Fleece C API
Description — Introducing the key concepts of the Fleece C API
Introduction
Couchbase Lite for C makes extensive use of the Fleece C API for accessing document data. This content introduces some basic Fleece API concepts and examples.
Fleece is a binary encoding for semi-structured data. Its data model is a superset of JSON, adding support for binary data (blobs) to give seven data types: null, boolean, numbers, strings, data, arrays, and dictionaries. Arrays can contain any data types. Dictionary keys are strings, with values of any data type.
Fleece is designed to be:
-
Very fast to read:
No parsing is needed, and the data can be navigated and read without any heap allocation. Fleece objects are internal pointers into the raw data. Arrays and dictionaries can be random-accessed. Performance on real-world-scale data has been clocked at 20x that of JSON. -
Compact:
Simple values will be about the same size as JSON. Complex ones may be much smaller, since repeated values, especially strings, only need to be stored once. -
Efficient to convert into native objects:
Numbers are binary, strings are raw UTF-8 without quoting, binary data is not base64-encoded. Storing repeated values once means they only need to be converted into native objects once. -
Appendable:
Fleece is what’s known as a persistent data structure. A Fleece document can be mutated by appending data to it. The mutation is in effect a delta, so it’s usually much smaller than the original document. And the original document is unchanged, which is great for concurrency as well as (simple) version control.- For more information, see
Values
Fleece’s data types are almost identical to those of JSON, with the notable addition of binary data types.
Basically Fleece provides seven data types: null, boolean, numbers, strings, arrays, dictionaries, and data. Arrays can contain any data type and dictionaries have strings as keys, with values of any data type.
The basic Fleece data type is FLValue, an opaque pointer reference to a value of any type.
Use the FLValue_GetType API to check the value’s actual type and FLValue_As<Type Name> to get the actual value as shown in Use FLValue
FLDict props = CBLDocument_Properties(doc);
FLValue value = FLDict_Get(props, FLSTR("name”));
FLValueType type = FLValue_GetType(value); (1)
if (type == kFLString) {
FLString name = FLValue_AsString(value);
doSomethingWith(name); (2)
}
1 | Find the values data type |
2 | Cast to appropriate type |
See: Fleece Header File for more details.
Slices and Strings
FLSlice
Another basic Fleece data type, FLSlice a simple struct consisting of a pointer and a length. It points to a block of memory, without implying ownership of that memory. FLSlice is used to represent both binary data and strings.
FLString
FLString is a typedef of FLSlice, which explicitly represents a string value. Use the FLSTR(“Some String”) macro to create an FLString from a string literal — see: Create an FLString
CBLDatabase* db = CBLDatabase_Open( (FLSTR("my-database"), NULL, &err); (1)
1 | FLSTR("My-database") creates the FLString from the given string literal. |
FLSliceResult/FLStringResult
FLSlice doesn’t imply an ownership of memory.
However, FLSliceResult/FLStringResult is an FLSlice type which does own memory and is reference-counted.
In general, whenever an FLSliceResult/FLStringResult is returned from an API call, you are responsible for calling FLSliceResult_Release when you are done using it.
For an example of FLSliceResult
in use, see: Using FLStringResult.
FLStringResult path = CBLDatabase_Path(db);
doSomethingWith(path);
FLSliceResult_Release(path); (1)
1 | You are responsible for calling FLSliceResult_Release when you are done using it. |
FLSlice and FLSliceResult have utility functions such as:
-
FLSlice_Equal
— compares two slices for equality. -
FLSlice_Compare
— a 3-way comparison, like strcmp(). -
FLSlice_Copy
-
FLSliceResult_New
-
FLSliceResults_Release
Null Slices
The null slice {NULL, 0} is represented by the constant kFLSliceNull
.
You test a slice for null by comparing its pointer (buf) with NULL — see: Test for null slice
FLValue value = FLDict_Get(props, FLSTR("name”));
FLString name = FLValue_AsString(value);
if (name.buf != NULL) {
doSomethingWith(name);
}
See: FLSlice.h for more details on data slices.
Dictionaries
Immutable
FLDict represents an immutable dictionary type in Fleece.
To access a value with a string key from a dictionary, use FLDict_Get — as shown in: Get dictionary value.
FLDict props = CBLDocument_Properties(doc);
FLValue value = FLDict_Get(props, FLSTR("name”));
doSomethingWith(value);
To iterate through each key-value pair in the dictionary, use FLDictIterator, as shown in: Iterate key-value pairs in dictionary
FLDictIterator iter;
FLDictIterator_Begin(myDict, &iter);
FLValue value;
while (NULL != (value = FLDictIterator_GetValue(&iter))) {
FLString key = FLDictIterator_GetKeyString(&iter);
doSomethingWith(key, value);
FLDictIterator_Next(&iter);
}
Mutable
FLMutableDictionary is a mutable dictionary type that allows editing.
To create a new mutable dictionary, use FLMutableDict_New() — see: Set dictionary value.
FLMutableDict myDict = FLMutableDict_New()
FLMutableDict_SetString(myDict, FLSTR(“name”), FLSTR(“John Doe”));
doSomethingWith(myDict);
FLMutableDict_Release(myDict); (1)
1 | don’t forget to release resources once you have finished with them |
Arrays
Immutable
FLArray represents an immutable array type in Fleece.
use FLArray_Count and FLArray_Get respectively, to get the numbers of values in an array and to get a value using with an index — as shown in Use arrays.
int count = FLArray_Count(myArray);
if (count > 0) {
FLValue value = FLArray_Get(myArray, 0);
doSomethingWith(value);
}
Use FLArrayIterator to iterate through arrays, as shown in : Array iteration.
FLArrayIterator iter;
FLArrayIterator_Begin(myArray, &iter);
FLValue value;
while (NULL != (value = FLArrayIterator_GetValue(&iter))) {
doSomethingWith(value);
FLArrayIterator_Next(&iter);
}
Mutable
FLMutableArray is a mutable array type that allows editing.
To create a new mutable array, use FLMutableArray_New.
To append a value into the array, use FLMutableArray_Append<Type Name>.
FLMutableArray myArray = FLMutableArray_New();
FLMutableArray_AppendString(myArray, FLSTR(“String 1”));
FLMutableArray_AppendString(myArray, FLSTR(“String 2”)); (1)
doSomethingWith(myArray);
FLMutableArray_Release(myArray)
1 | To set a value at a specific array index, use FLMutableArraySet<Type Name>. |
JSON Support
Fleece provides a JSON utility that allows you to parse JSON string into Fleece or generate JSON from Fleece.
Parsing JSON
Use FLDoc_FromJSON to convert JSON Dictionary or Array into Fleece Dictionary or Array.
FLError error;
FLDoc doc = FLDoc_FromJSON(jsonString, &error);
if (doc) {
FLValue value = FLDoc_GetRoot(doc);
FLDict dict = FLValue_AsDict(value);
doSomethingWith(dict);
}
FLDoc_Release(doc);
Memory Management
In general, Mutable objects are reference counted: with MutableArray and Mutable Dictionary each having retain and release functions.
The lifespan of Immutable objects is the same as that of the memory block from which they are parsed.
They cannot be individually released or retained.
For more see:
Fleece Mememory Management |
Advanced Fleece Mememory Management