Previous: Intrinsic Integer Data Type, Up: Simple Referable Data Type Examples [Index]
Consider a data type describing string data. For the interpreted languages such type would be an opaque application defined type. Consider now that it would be desirable to have multiple references to data of such type.
The application data of such type may be represented, for an instance, as a pointer integer pair, with the pointer indicating a memory address where the string bytes are stored and the integer counting the bytes.
struct this_type { char *data; unsigned size; };
Adding a reference counter transforms to:
struct this_type { char *data; unsigned call, size; };
The interpreters will require a struct x1f4_datatype_type
definition
to allow declarations of data of such type.
See struct x1f4_datatype_type.
struct x1f4_datatype_type data_type = { "data", flat_data, lead_data, line_data, link_data, flat_data, slip_data, HERE_DATA, 4, NULL };
The definition specifies a 4 characters long ‘data’ name and a
HERE_DATA
id for the data type (there is a ‘data’ data type
provided by the libaime libraries, but this is not it, it is just an
example). HERE_DATA
is an integral
value, better greater than X1f4_E4_LAST
.
See Symbolic Types.
The preinitializing routine (preinitializing helps with early program execution termination) does little:
int link_data(void *subtext, void **address) { *address = NULL; return 0; }
See Execution Completion Cleanup.
The initializing routine allocates some data of the string representation
struct this_type
type and sets it to a sensible value (the reference
counter to 1, the actual string data to an empty string).
int line_data(void *subtext, void **address) { int status; struct this_type *this_data; allocate memory for data, set status to operation success if (status) { } else { this_data->call = 1; this_data->length = 0; this_data->string = (char *) x1f4_c1_empty_string; *address = (void *) this_data; } return status; }
See x1f4_c1_empty_string.
See Of The Intrinsic String Type.
Define a routine that actually destroys data:
int side_data(void *subtext, void *data) { int status; struct this_type *this_data; this_data = data; if (!this_data) { status = 0; } else { free actual string data if necessary, free data, set status to operation success } return status; }
and the routine that accounts for references being removed:
int flat_data(void *subtext, void **address) { int status; struct this_type *this_data; this_data = *address; if (this_data) { unsigned call; call = this_data->call; call--; if (call) { this_data->call = call; *address = NULL; status = 0; } else { status = side_data(subtext, this_data); if (status) { } else { *address = NULL; } } } else { status = 0; } return status; }
Expectedly, the routine decrements the reference count, and when reaching 0 it
destroys data. It also sets data to the preinitialized NULL
value.
The new variable held reference acknowledging routine increments the reference count:
int lead_data(void *subtext, void **address) { struct this_type *this_data; this_data = *address; this_data->call++; return 0; }
The removed variable held reference acknowledging routine decrements the reference count:
int slip_data(void *subtext, void **address) { int status; struct this_type *this_data; unsigned call; this_data = *address; call = this_data->call; call--; if (call) { this_data->call = call; status = 0; } else { status = side_data(subtext, this_data); } return status; }
The referable object data types definition:
See struct x1f4_nodetype_type.
struct x1f4_nodetype_type node_type = { "data", NULL, HERE_DATA, copy_data, NULL, free_data, NULL, lead_data, NULL, NULL, node_data, NULL, push_data, slip_data, X1f4_LX_LINK_ACCESS, 4, NULL };
The definition restates the 4 characters long ‘data’ name and the
HERE_DATA
id for the data type.
The X1f4_LX_LINK_ACCESS
indicates that the node
field is set
(here to some node_data
routine) and to be used.
The reference removing routine much resembles the one in the struct
x1f4_datatype_type
definition, it is only simpler.
int free_data(void *subtext, void *data, struct x1f4_nodelink_type **nodelink, const struct x1f4_nodelink_type *nodelink_data) { int status; struct this_type *this_data; unsigned call; this_data = data; call = this_data->call; call--; if (call) { this_data->call = call; status = 0; } else { status = side_data(subtext, data); } return status; }
The reference registering routine increments the reference count and copies the data pointer (as the new reference).
int node_data(void *subtext, void **copy, void *data, const struct x1f4_nodelink_type *nodelink_data) { struct this_type *this_data; this_data = data; *copy = data; this_data->call++; return 0; }
The routine transfering a reference hold by a object to a variable will copy a pointer (to data for which the reference is transferred). No reference counter for this later object needs modified. Still, the variable to which the reference is transferred is already referring some object. The reference count for this object needs decremented and if reaching 0, the object needs freed.
Stating this again: say reference to object ‘A’ hold by object ‘C’ needs transferred to variable ‘V’. The actual transfer is just a pointer copy. Yet, variable ‘V’ is (must be) referring something, some object, call it object ‘B’. Once the reference transfer for object ‘A’ is completed, ‘V’ no longer will refer ‘B’, hence ‘B’ will have one less reference.
int push_data(void *subtext, void **copy, void *data, const struct x1f4_nodelink_type *nodelink_data) { int status; struct this_type *this_data; unsigned call; this_data = *copy; call = this_data->call; call--; if (call) { this_data->call = call; *copy = data; status = 0; } else { status = side_data(subtext, this_data); if (status) { } else { *copy = data; } } return status; }
The object copying routine reserves memory for the copy being made, copies data and sets the reference count for the new object (to 1).
int copy_data(void *subtext, void *tracker, void **copy, const void *data, const struct x1f4_nodelink_type *nodelink_data) { int status; struct this_type *this_data; allocate memory for data, set status to operation success if (status) { } else { unsigned length; length = ((struct this_type *) data)->length; if (!length) { this_data->length = 0; this_data->string = (char *) x1f4_c1_empty_string; this_data->call = 1; *copy = (void *) this_data; } else { allocate memory for actual string data, set status to operation success if (status) { free memory allocated for data } else { copy string data, set `length' and `string' fields in the `this_data' record this_data->call = 1; *copy = (void *) this_data; } } } return status; }
Previous: Intrinsic Integer Data Type, Up: Simple Referable Data Type Examples [Index]