Skip to content

Commit d7607c9

Browse files
committed
docs + minorities
1 parent 87707fc commit d7607c9

File tree

3 files changed

+338
-15
lines changed

3 files changed

+338
-15
lines changed

docs/_SOURCE/0.8.x/fio-stl.md

Lines changed: 321 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3219,14 +3219,16 @@ The JSON parsing should stop with an error.
32193219

32203220
The facil.io library includes a dynamic type system that makes it a easy to handle mixed-type tasks, such as JSON object construction.
32213221

3222-
This dynamic type system is based on the core types and API provided by the core STL library.
3222+
This soft type system included in the facil.io STL is based on the Core types mentioned above and shares their API (Dynamic Strings, Dynamic Arrays, and Hash Maps).
32233223

32243224
The `FIOBJ` type API is divided by it's inner types (tested using `FIOBJ_TYPE(obj)` or `FIOBJ_TYPE_IS(obj, type)`).
32253225

32263226
In addition, some `FIOBJ` functions can be called for any `FIOBJ` object, regardless of their type.
32273227

32283228
The documentation regarding the `FIOBJ` soft-type system is divided as follows:
32293229

3230+
* [`FIOBJ` General Considerations](#fiobj-general-considerations)
3231+
32303232
* [`FIOBJ` Core Type Identification](#fiobj-core-type-identification)
32313233

32323234
* [`FIOBJ` Core Memory Management](#fiobj-core-memory-management)
@@ -3245,14 +3247,39 @@ The documentation regarding the `FIOBJ` soft-type system is divided as follows:
32453247

32463248
* [Hash Maps](#fiobj-hash-maps)
32473249

3248-
* [JSON](#fiobj-json-helpers)
3250+
* [JSON Helpers](#fiobj-json-helpers)
3251+
3252+
* [How to Extend the `FIOBJ` Type System](#how-to-extend-the-fiobj-type-system)
32493253

32503254
In the facil.io web application framework, there are extensions to the core `FIOBJ` primitives, including:
32513255

32523256
* [IO storage](fiobj_io)
32533257

32543258
* [Mustache](fiobj_mustache)
32553259

3260+
3261+
### `FIOBJ` General Considerations
3262+
3263+
1. To use the `FIOBJ` soft types, define the `FIO_FIOBJ` macro and then include the facil.io STL header.
3264+
3265+
2. To include declarations as globally available symbols (allowing the functions to be called from multiple C files), define `FIOBJ_EXTERN` _before_ including the STL header.
3266+
3267+
This also requires that _only_ a single C file (translation unit) define `FIOBJ_EXTERN_COMPLETE` _before_ including the header with the `FIOBJ_EXTERN` directive.
3268+
3269+
3. The `FIOBJ` types use pointer tagging and require that the memory allocator provide allocations on 64 bit memory alignment boundaries.
3270+
3271+
If the system allocator doesn't provide (at least) 64 bit allocation boundaries, use the facil.io memory allocator provided (`fio_malloc`).
3272+
3273+
4. The `FIOBJ` soft type system uses an "ownership" memory model.
3274+
3275+
This means that Arrays "own" their members and Hash Maps "own" their values (but **not** the keys).
3276+
3277+
Freeing an Array will free all the objects within the Array. Freeing a Hash Map will free all the values within the Hash Map (but none of the keys).
3278+
3279+
Ownership is only transferred if the object is removed from it's container.
3280+
3281+
i.e., `fiobj_array_get` does **not** transfer ownership (it's just a short temporary "loan"). Whereas, `fiobj_array_remove` **does** revoke ownership - either freeing the object or moving the ownership to the pointer provided to hold the `old` value.
3282+
32563283
### `FIOBJ` Core Type Identification
32573284

32583285
`FIOBJ` objects can contain any number of possible types, including user defined types.
@@ -3883,3 +3910,295 @@ Returns a FIOBJ object matching the JSON valid C string `str`.
38833910
If the parsing failed (no complete valid JSON data) `FIOBJ_INVALID` is returned.
38843911

38853912
`fiobj_json_parse2` is a helper macro, it calls `fiobj_json_parse` with the provided string information.
3913+
3914+
### How to Extend the `FIOBJ` Type System
3915+
3916+
The `FIOBJ` source code includes two extensions for the `Float` and `Number` types.
3917+
3918+
In many cases, numbers and floats can be used without memory allocations. However, when memory allocation is required to store the data, the `FIOBJ_T_NUMBER` and `FIOBJ_T_FLOAT` types are extended using the same techniques described here.
3919+
3920+
#### `FIOBJ` Extension Requirements
3921+
3922+
To extend the `FIOBJ` soft type system, there are a number of requirements:
3923+
3924+
1. A **unique** type ID must be computed.
3925+
3926+
Type IDs are `size_t` bits in length. Values under 100 are reserved. Values under 40 are illegal (might break implementation).
3927+
3928+
2. A static virtual function table object (`FIOBJ_class_vtable_s`) must be fully populated (`NULL` values may break cause a segmentation fault).
3929+
3930+
3. The unique type construct / destructor must be wrapped using the facil.io reference counting wrapper (using `FIO_REF_NAME`).
3931+
3932+
The `FIO_REF_METADATA` should be set to a `FIOBJ_class_vtable_s` pointer and initialized for every object.
3933+
3934+
4. The unique type wrapper must use pointer tagging as described bellow (`FIO_PTR_TAG`).
3935+
3936+
5. A public API should be presented.
3937+
3938+
#### `FIOBJ` Pointer Tagging
3939+
3940+
The `FIOBJ` types is often identified by th a bit "tag" added to the pointer.
3941+
3942+
The facil.io memory allocator (`fio_malloc`), as well as most system allocators, promise a 64 bit allocation alignment.
3943+
3944+
The `FIOBJ` types leverage this behavior by utilizing the least significant 3 bits that are always zero.
3945+
3946+
The following macros should be defined for tagging an extension `FIOBJ` type, allowing the `FIO_REF_NAME` constructor / destructor to manage pointer tagging.
3947+
3948+
```c
3949+
#define FIO_PTR_TAG(p) ((uintptr_t)p | FIOBJ_T_OTHER)
3950+
#define FIO_PTR_UNTAG(p) FIOBJ_PTR_UNTAG(p)
3951+
#define FIO_PTR_TAG_TYPE FIOBJ
3952+
```
3953+
3954+
#### `FIOBJ` Virtual Function Tables
3955+
3956+
`FIOBJ` extensions use a virtual function table that is shared by all the objects of that type/class.
3957+
3958+
Basically, the virtual function table is a `struct` with the Type ID and function pointers.
3959+
3960+
All function pointers must be populated (where `each1` is only called if `count` returns a non-zero value).
3961+
3962+
This is the structure of the virtual table:
3963+
3964+
```c
3965+
/** FIOBJ types can be extended using virtual function tables. */
3966+
typedef struct {
3967+
/** A unique number to identify object type. */
3968+
size_t type_id;
3969+
/** Test for equality between two objects with the same `type_id` */
3970+
unsigned char (*is_eq)(FIOBJ a, FIOBJ b);
3971+
/** Converts an object to a String */
3972+
fio_str_info_s (*to_s)(FIOBJ o);
3973+
/** Converts an object to an integer */
3974+
intptr_t (*to_i)(FIOBJ o);
3975+
/** Converts an object to a double */
3976+
double (*to_f)(FIOBJ o);
3977+
/** Returns the number of exposed elements held by the object, if any. */
3978+
uint32_t (*count)(FIOBJ o);
3979+
/** Iterates the exposed elements held by the object. See `fiobj_each1`. */
3980+
uint32_t (*each1)(FIOBJ o, int32_t start_at,
3981+
int (*task)(FIOBJ child, void *arg), void *arg);
3982+
/**
3983+
* Decreases the reference count and/or frees the object, calling `free2` for
3984+
* any nested objects.
3985+
*
3986+
* Returns 0 if the object is still alive or 1 if the object was freed. The
3987+
* return value is currently ignored, but this might change in the future.
3988+
*/
3989+
int (*free2)(FIOBJ o);
3990+
} FIOBJ_class_vtable_s;
3991+
```
3992+
3993+
#### `FIOBJ` Extension Example
3994+
3995+
For our example, let us implement a static string extension type.
3996+
3997+
The API for this type and the header might look something like this:
3998+
3999+
```c
4000+
/* *****************************************************************************
4001+
FIOBJ Static String Extension Header Example
4002+
4003+
Copyright: Boaz Segev, 2019
4004+
License: ISC / MIT (choose your license)
4005+
4006+
Feel free to copy, use and enjoy according to the license provided.
4007+
***************************************************************************** */
4008+
#ifndef FIO_STAT_STRING_HEADER_H
4009+
#define FIO_STAT_STRING_HEADER_H
4010+
/* *****************************************************************************
4011+
Perliminaries - include the FIOBJ extension, but not it's implementation
4012+
***************************************************************************** */
4013+
#define FIO_EXTERN 1
4014+
#define FIOBJ_EXTERN 1
4015+
#define FIO_FIOBJ
4016+
#include "fio-stl.h"
4017+
4018+
/* *****************************************************************************
4019+
Defining the Type ID and the API
4020+
***************************************************************************** */
4021+
4022+
/** The Static String Type ID */
4023+
#define FIOBJ_T_STATIC_STRING 101UL
4024+
4025+
/** Returns a new static string object. The string is considered immutable. */
4026+
FIOBJ fiobj_static_new(const char *str, size_t len);
4027+
4028+
/** Returns a pointer to the static string. */
4029+
const char *fiobj_static2ptr(FIOBJ s);
4030+
4031+
/** Returns the static strings length. */
4032+
size_t fiobj_static_len(FIOBJ s);
4033+
4034+
#endif
4035+
```
4036+
4037+
**Note**: The header assumes that _somewhere_ there's a C implementation file that includes the `FIOBJ` implementation. That C file defines the `FIOBJ_EXTERN_COMPLETE` macro.
4038+
4039+
The implementation may look like this.
4040+
4041+
```c
4042+
/* *****************************************************************************
4043+
FIOBJ Static String Extension Implementation Example
4044+
4045+
Copyright: Boaz Segev, 2019
4046+
License: ISC / MIT (choose your license)
4047+
4048+
Feel free to copy, use and enjoy according to the license provided.
4049+
***************************************************************************** */
4050+
#include <fiobj_static.h> // include the header file here, whatever it's called
4051+
4052+
/* *****************************************************************************
4053+
The Virtual Function Table (definitions and table)
4054+
***************************************************************************** */
4055+
4056+
/** Test for equality between two objects with the same `type_id` */
4057+
static unsigned char static_string_is_eq(FIOBJ a, FIOBJ b);
4058+
/** Converts an object to a String */
4059+
static fio_str_info_s static_string_to_s(FIOBJ o);
4060+
/** Converts an object to an integer */
4061+
static intptr_t static_string_to_i(FIOBJ o);
4062+
/** Converts an object to a double */
4063+
static double static_string_to_f(FIOBJ o);
4064+
/** Returns the number of exposed elements held by the object, if any. */
4065+
static uint32_t static_string_count(FIOBJ o);
4066+
/** Iterates the exposed elements held by the object. See `fiobj_each1`. */
4067+
static uint32_t static_string_each1(FIOBJ o, int32_t start_at,
4068+
int (*task)(FIOBJ, void *), void *arg);
4069+
/**
4070+
* Decreases the reference count and/or frees the object, calling `free2` for
4071+
* any nested objects (which we don't have for this type).
4072+
*
4073+
* Returns 0 if the object is still alive or 1 if the object was freed. The
4074+
* return value is currently ignored, but this might change in the future.
4075+
*/
4076+
static int static_string_free2(FIOBJ o);
4077+
/** The virtual function table object. */
4078+
static const FIOBJ_class_vtable_s FIOBJ___STATIC_STRING_VTABLE = {
4079+
.type_id = FIOBJ_T_STATIC_STRING,
4080+
.is_eq = static_string_is_eq,
4081+
.to_s = static_string_to_s,
4082+
.to_i = static_string_to_i,
4083+
.to_f = static_string_to_f,
4084+
.count = static_string_count,
4085+
.each1 = static_string_each1,
4086+
.free2 = static_string_free2,
4087+
};
4088+
4089+
/* *****************************************************************************
4090+
The Static String Type (internal implementation)
4091+
***************************************************************************** */
4092+
4093+
/* in this example, all functions defined by fio-stl.h will be static (local) */
4094+
#undef FIO_EXTERN
4095+
#undef FIOBJ_EXTERN
4096+
/* leverage the small-string type to hold static string data */
4097+
#define FIO_SMALL_STR_NAME fiobj_static_string
4098+
/* add required pointer tagging */
4099+
#define FIO_PTR_TAG(p) ((uintptr_t)p | FIOBJ_T_OTHER)
4100+
#define FIO_PTR_UNTAG(p) FIOBJ_PTR_UNTAG(p)
4101+
#define FIO_PTR_TAG_TYPE FIOBJ
4102+
/* add required reference counter / wrapper type */
4103+
#define FIO_REF_CONSTRUCTOR_ONLY 1
4104+
#define FIO_REF_NAME fiobj_static_string
4105+
/* initialization - for demonstration purposes, we don't use it here. */
4106+
#define FIO_REF_INIT(o) \
4107+
do { \
4108+
o = (fiobj_static_string_s){.aligned = NULL}; \
4109+
FIOBJ_MARK_MEMORY_ALLOC(); /* mark memory allocation for debugging */ \
4110+
} while (0)
4111+
/* cleanup - destroy the object data when the reference count reaches zero. */
4112+
#define FIO_REF_DESTROY(o) \
4113+
do { \
4114+
fiobj_static_string_destroy((FIOBJ)&o); \
4115+
FIOBJ_MARK_MEMORY_FREE(); /* mark memory deallocation for debugging */ \
4116+
} while (0)
4117+
/* metadata (vtable) definition and initialization. */
4118+
#define FIO_REF_METADATA const FIOBJ_class_vtable_s *
4119+
/* metadata initialization - required to initialize the vtable. */
4120+
#define FIO_REF_METADATA_INIT(m) \
4121+
do { \
4122+
m = &FIOBJ___STATIC_STRING_VTABLE; \
4123+
} while (0)
4124+
#include <fio-stl.h>
4125+
4126+
/* *****************************************************************************
4127+
The Public API
4128+
***************************************************************************** */
4129+
4130+
/** Returns a new static string object. The string is considered immutable. */
4131+
FIOBJ fiobj_static_new(const char *str, size_t len) {
4132+
FIOBJ o = fiobj_static_string_new();
4133+
FIO_ASSERT_ALLOC(FIOBJ_PTR_UNTAG(o));
4134+
fiobj_static_string_set_const(o, str, len);
4135+
return o;
4136+
}
4137+
4138+
/** Returns a pointer to the static string. */
4139+
const char *fiobj_static2ptr(FIOBJ o) { return fiobj_static_string2ptr(o); }
4140+
4141+
/** Returns the static strings length. */
4142+
size_t fiobj_static_len(FIOBJ o) { return fiobj_static_string_len(o); }
4143+
4144+
/* *****************************************************************************
4145+
Virtual Function Table Implementation
4146+
***************************************************************************** */
4147+
4148+
/** Test for equality between two objects with the same `type_id` */
4149+
static unsigned char static_string_is_eq(FIOBJ a, FIOBJ b) {
4150+
fio_str_info_s ai, bi;
4151+
ai = fiobj_static_string_info(a);
4152+
bi = fiobj_static_string_info(b);
4153+
return (ai.len == bi.len && !memcmp(ai.buf, bi.buf, ai.len));
4154+
}
4155+
/** Converts an object to a String */
4156+
static fio_str_info_s static_string_to_s(FIOBJ o) {
4157+
return fiobj_static_string_info(o);
4158+
}
4159+
/** Converts an object to an integer */
4160+
static intptr_t static_string_to_i(FIOBJ o) {
4161+
fio_str_info_s s = fiobj_static_string_info(o);
4162+
if (s.len)
4163+
return fio_atol(&s.buf);
4164+
return 0;
4165+
}
4166+
/** Converts an object to a double */
4167+
static double static_string_to_f(FIOBJ o) {
4168+
fio_str_info_s s = fiobj_static_string_info(o);
4169+
if (s.len)
4170+
return fio_atof(&s.buf);
4171+
return 0;
4172+
}
4173+
/** Returns the number of exposed elements held by the object, if any. */
4174+
static uint32_t static_string_count(FIOBJ o) {
4175+
return 0;
4176+
(void)o;
4177+
}
4178+
/** Iterates the exposed elements held by the object. See `fiobj_each1`. */
4179+
static uint32_t static_string_each1(FIOBJ o, int32_t start_at,
4180+
int (*task)(FIOBJ, void *), void *arg) {
4181+
return 0;
4182+
(void)o; (void)start_at; (void)task; (void)arg;
4183+
}
4184+
/** Decreases the reference count and/or frees the object. */
4185+
static int static_string_free2(FIOBJ o) { return fiobj_static_string_free(o); }
4186+
```
4187+
4188+
Example usage:
4189+
4190+
```c
4191+
#include "fiobj_static.h" // include FIOBJ extension type
4192+
int main(void) {
4193+
FIOBJ o = fiobj_static_new("my static string", 16);
4194+
/* example test of virtual table redirection */
4195+
FIO_ASSERT(fiobj2cstr(o).buf == fiobj_static2ptr(o) &&
4196+
fiobj2cstr(o).len == fiobj_static_len(o),
4197+
"vtable redirection error.");
4198+
fprintf(stderr, "allocated: %s\n", fiobj_static2ptr(o));
4199+
fprintf(stderr, "it's %zu byte long\n", fiobj_static_len(o));
4200+
fprintf(stderr, "object type: %zu\n", FIOBJ_TYPE(o));
4201+
fiobj_free(o);
4202+
FIOBJ_MARK_MEMORY_PRINT(); /* only in DEBUG mode */
4203+
}
4204+
```

docs/_SOURCE/assets/styles/_railscasts.scss

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ Railscasts-like style (c) Visoft, Inc. (Damien White)
199199
.highlight .p { color: #fee } /* Punctuation */
200200
.highlight .ch { color: #babadd } /* Comment.Hashbang */
201201
.highlight .cm { color: #babadd } /* Comment.Multiline */
202-
.highlight .cp { color: #babadd } /* Comment.Preproc */
202+
.highlight .cp { color: #febadd } /* Comment.Preproc */
203203
.highlight .cpf { color: #babadd } /* Comment.PreprocFile */
204204
.highlight .c1 { color: #babadd } /* Comment.Single */
205205
.highlight .cs { color: #babadd } /* Comment.Special */
@@ -257,4 +257,4 @@ Railscasts-like style (c) Visoft, Inc. (Damien White)
257257
.highlight .vg { color: #fee } /* Name.Variable.Global */
258258
.highlight .vi { color: #fee } /* Name.Variable.Instance */
259259
.highlight .vm { color: #fee } /* Name.Variable.Magic */
260-
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
260+
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */

0 commit comments

Comments
 (0)