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

        Fleece on GitHub | Using Fleece | Fleece Header File

      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

      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

      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.

      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

      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.

      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

      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.

      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.

      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.

      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>.

      Append values to array
      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.

      Parse JSON data to Fleece
      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);

      Generating JSON

      Use FLValue_ToJSON to convert FLValue into JSON string

      Convert to JSON
      FLDict props = CBLDocument_Properties(doc);
      FLStringResult jsonString = FLValue_ToJSON((FLValue) props);
      doSomethingWith(jsonString);
      FLSliceResult_Release(jsonString);

      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.