Please see the INSTALL file for full installation details.
@@ -127,24 +86,23 @@ Fortunately, gcc is available to all from https://gcc.gnu.org/ and clang is at h
Please note:
If you use gcc version >=10 or clang >= 9, you should include the compiler flag `-Wno-sizeof-pointer-div` to prevent spurious warnings. This is done by default.
0.<aid="cdict_headers"></a>Include the cdict header file in your C source code.
Include the cdict header file in your C source code.
```c
#include<cdict/cdict.h>
```
1.<aid="make_cdict"></a>Make a new cdict struct
## 1. Make a new cdict struct
To make a cdict called `c`, use:
@@ -158,7 +116,7 @@ Usage
CDict_new(new_cdict,parent_cdict);
```
2.<aid="free_cdict"></a>Free the memory associated with a cdict struct, and any nested cdict structs,
## 2. Free the memory associated with a cdict struct, and any nested cdict structs,
- If you just want to free the cdict `c` and any associated metadata (if set)
@@ -181,7 +139,7 @@ Usage
Please note: if a `cdict` is freed which is pointed to as the ancestor of another `cdict` this will probaly cause an error. You should thus free cdicts in the reverse order they are accessed, or just free the ancestor (which will free its children).
3.<aid="setting_data_implicitly"></a>Setting scalars, arrays and pointers, including other cdicts, in your cdict struct, with implicit type guessing.
## 3. Setting scalars, arrays and pointers, including other cdicts, in your cdict, with implicit type guessing.
You can set entries containing scalars, pointers and arrays into the cdict with the `CDict_set()` function. This implicitly guesses the types of the key and value you try to set as well as array sizes.
@@ -246,7 +204,7 @@ Note: Such metadata is not output as JSON.
free_metadata_function);
```
4. <a id="setting_data_explicitly"></a> Setting scalars and pointers, and arrays, in the cdict - the explicit way.
## 4. Setting scalars and pointers, and arrays, in your cdict, with explicit types.
You can set scalars, pointers and arrays in the cdict with the functions `CDict_set_with_types(cdict,key,keytype,value,valuetype)` and `CDict_set_with_types_and_metadata(cdict,key,keytype,value,valuetype,metadata,metadata_free_function)`. These are different to `CDict_set()` in that they do not guess the data's C type, instead you must set this manually.
@@ -330,7 +288,9 @@ Note: Such metadata is not output as JSON.
Note that all elements in the array must be of the same type (as in C). This is not a limitation, it is a design choice: when you want to have many elements of different types, you can use a cdict instead (see above).
5.<aid="set_nested_data"></a>Setting nested variables in the cdict can be done either using the above function calls, or the `CDict_nest(cdict,key,value,...)` function, where "..." is a list of keys which define the nested location (usually statically, i.e. not with `malloc` or `calloc`, allocated scalar types, e.g. numbers or strings). This is a powerful method for setting, or appending to, complicated nested cdicts quickly. Note that if a cdict entry already exists at the nested location, it will be appended if possible. In the case of numbers this means adding them, strings and arrays are concatenated, Booleans are ANDed, while pointers are incremented by casting the appending value to a ptrdiff_t and then adding it. Note that you cannot append a cdict on a cdict: such cases should be prevented using `CDict_contains(cdict,key)` or `CDict_nest_get_entry(cdict,...)`.
## 5. Set nested variables
Setting nested variables in the cdict can be done either using the above function calls, or the `CDict_nest(cdict,key,value,...)` function, where "..." is a list of keys which define the nested location (usually statically, i.e. not with `malloc` or `calloc`, allocated scalar types, e.g. numbers or strings). This is a powerful method for setting, or appending to, complicated nested cdicts quickly. Note that if a cdict entry already exists at the nested location, it will be appended if possible. In the case of numbers this means adding them, strings and arrays are concatenated, Booleans are ANDed, while pointers are incremented by casting the appending value to a ptrdiff_t and then adding it. Note that you cannot append a cdict on a cdict: such cases should be prevented using `CDict_contains(cdict,key)` or `CDict_nest_get_entry(cdict,...)`.
```c
/*
@@ -439,7 +399,9 @@ Note: Such metadata is not output as JSON.
Static strings are likely to be more efficiently stored in memory.
6.<aid="access_nested_data"></a>Accessing nested cdict data is relatively simple. To access an entry, simply call
## 6. Accessing nested cdict data
Accessing nested cdict data is relatively simple. To access an entry, simply call
```c
struct cdict_entry_t * entry =
@@ -482,7 +444,9 @@ Note: Such metadata is not output as JSON.
```
If the data does not exist, an error is raised.
7.<aid="access_entries_by_loop"></a>You can loop over the keys in a cdict, access the entries' keys and values, with code like
## 7. Access cdict entries by looping over its keys
You can loop over the keys in a cdict, access the entries' keys and values, with code like
```c
/* Loop over cdict stored in cdict */
@@ -525,7 +489,9 @@ Note: Such metadata is not output as JSON.
Note that these key/value to string functions return the number of bytes put in the string (the value string in the case they are both set), or a negative number in case of an error.
8.<aid="cdict_to_JSON"></a><ANAME="CDict_print_JSON"></A> You can easily output a cdict's contents to a JSON buffer using. If you just want to output to stdout (the usual case), use `CDict_print_JSON()`. This takes the cdict itself as the first argument, and the second argument chooses whether to sort the cdict or not, it should be either `CDICT_JSON_SORT` or `CDICT_JSON_NO_SORT`. (It is slower to sort the cdict hence you have the option.)
## 8. cdict to JSON
You can easily output a cdict's contents to a JSON buffer using. If you just want to output to stdout (the usual case), use `CDict_print_JSON()`. This takes the cdict itself as the first argument, and the second argument chooses whether to sort the cdict or not, it should be either `CDICT_JSON_SORT` or `CDICT_JSON_NO_SORT`. (It is slower to sort the cdict hence you have the option.)
```c
/*
@@ -586,7 +552,9 @@ Note: Such metadata is not output as JSON.
CDict_JSON_file_to_CDict(cdict,filename);
```
9.<aid="cdict_custom_formatting"></a>Output formatting of keys and values is done automatically, but you can set a custom format at the same time as setting your data in place. For example, the following sets a double as a key and an int as a value, with the format strings `"%.15e"` and `"%d"` respectively. You can use `CDict_set_with_types_and_formats(cdict,key,keytype,keyformat,value,valuetype,valueformat)` and `CDict_set_with_types_formats_and_metadata(cdict,key,keytype,keyformat,value,valuetype,valueformat,metadata,metadata_free_function)`.
## 9. Custom output formatting
Output formatting of keys and values is done automatically, but you can set a custom format at the same time as setting your data in place. For example, the following sets a double as a key and an int as a value, with the format strings `"%.15e"` and `"%d"` respectively. You can use `CDict_set_with_types_and_formats(cdict,key,keytype,keyformat,value,valuetype,valueformat)` and `CDict_set_with_types_formats_and_metadata(cdict,key,keytype,keyformat,value,valuetype,valueformat,metadata,metadata_free_function)`.
```c
double r1 = 10.0;
@@ -601,7 +569,9 @@ Note: Such metadata is not output as JSON.
```
10.<aid="delete_cdict_entry"></a>Delete a cdict entry and its value's contents, if appropriate (e.g. if they are a pointer) with the following.
## 10. Delete cdict entry
Delete a cdict entry and its value's contents, if appropriate (e.g. if they are a pointer) with the following.
```c
CDict_del_and_contents(cdict,entry,TRUE);
@@ -619,7 +589,9 @@ Note: Such metadata is not output as JSON.
CDict_del(cdict,entry);
```
11.<aid="append_cdict_entry"></a>Append to a cdict entry, with given key, by value, with the following code. As with `CDict_set()` the key and value types are guessed automatically.
## 11. Append cdict entry
Append to a cdict entry, with given key, by value, with the following code. As with `CDict_set()` the key and value types are guessed automatically.
```c
CDict_append(cdict,key,value);
@@ -629,7 +601,9 @@ Note: Such metadata is not output as JSON.
You can also use `CDict_append_with_types(cdict,key,keytype,value,valuetype)` and `CDict_append_with_types_and_metadata(cdict,key,keytype,value,valuetype,metadata,metadata_free_function)` should you require more control.
12.<aid="locate_cdict_entry"></a>Find out if the cdict contains an entry with
## 12. Locate an entry
Find out if the cdict contains an entry with
```c
/*
@@ -644,7 +618,9 @@ Note: Such metadata is not output as JSON.
```
13.<aid="sort_cdict"></a>Sort a cdict, e.g. prior to looping (this is implicitly done if you use `CDict_sorted_loop()`).
## 13. Sort a cdict
Sort a cdict, e.g. prior to looping (this is implicitly done if you use `CDict_sorted_loop()`).
```c
/*
@@ -673,7 +649,9 @@ Note: Such metadata is not output as JSON.
where the `sortfunc` should be defined as for the Gnu C standard-library `qsort` function.
14.<aid="internal_functionality"></a>A word on some internal functionality. Because *libcdict* automatically handles floating-point numbers, it has to make some choices. These come down to:
## 14. Internal functionality
A word on some internal functionality. Because *libcdict* automatically handles floating-point numbers, it has to make some choices. These come down to:
- Choosing how to put floats and doubles into hash buckets, i.e. how to "hash" them. We currently do this by truncating the precision of the float or double to the leading `n` bytes, where you can set `n` as shown below. This algorithm is not perfect [^1], but works enough of the time for reasonable choice of `n`. If you have a very large number of hash items, it makes sense to have a larger `n` so there are more buckets. If you choose `n` to be very small (< 3) there will possibly be few buckets so your hash lookups will be slow.
@@ -692,7 +670,9 @@ Note: Such metadata is not output as JSON.
By default, we set `abseps=releps=2.0*DBL_EPSILON`, `nbytes_double=4` and `nbytes_float=3`. You may well need to use different tolerances in your projects.
15.<aid="metadata"></a>You can set metadata into cdict entries. This data can be used for anything you like, but most often it is used as a label for some kind of internal processing. Metadata is not output as JSON.
## 15. Metadata
You can set metadata into cdict entries. This data can be used for anything you like, but most often it is used as a label for some kind of internal processing. Metadata is not output as JSON.
To set metadata when setting an item in the cdict, to set a metadata label string do something like this:
@@ -796,7 +776,8 @@ Note: Such metadata is not output as JSON.
```
16.<aid="config_and_testing"></a>Configuration information and testing
## 16. Configuration information and testing
If you want to acquire information on the configuration of cdict, after running `ninja install`, and assuming your `$PATH` is set to point to wherever you decided to install *libcdict*, run the following in your terminal:
In case of an error, you can set a function pointer as an error handler and set a custom data pointer for it. This means you can pass whatever you like in this pointer to the handler function, and hence deal with the error in any way you like.
Both `parent` and `ancestor` are `NULL` when the single-argument form of `CDict_new()` is used.
19.<aid="copy_cdict"></a>Copying a cdict
## 19. Copying a cdict
You can use `CDict_copy()` to copy a cdict. The new cdict has its array content (e.g. strings and arrays of scalars) copied so you can delete the original cdict, if required.
*libcdict* is not designed to be explicitly thread safe: you'll need to implement some kind of asyncrhonous thread-locking, e.g. with libpthread mutexes, should you wish to use a single cdict struct in multiple threads. That said, as long as you do this, it should just work: there are no problems with global variables (the only global variables are the floating-point epsilons which you will probably never change).
22.<aid="speed_vs_memory"></a>Speed vs memory: the force_maps boolean
## 22. Speed vs memory: the force_maps boolean
When comparing cdict keys to determine whether a path exists in a cdict, often the only way, e.g. when the keys are of different type, is to convert the keys to strings. By default these strings are stored so that further comparisons are as fast as possible. This costs RAM, however. You can change this behaviour with the cdict->force_maps boolean.
You should just choose which is most important to you: RAM or speed.
23.<aid="external_languages"></a>Use with external languages, e.g. *Perl* and *Python*, via JSON.
## 23. External languages via JSON
You can export *libcdict* JSON data (see [point 8 above](#CDict_print_JSON)) to a file or buffer which can easily be imported into *Perl* or *Python*, both of which have JSON modules to do this. For example, in Python try something like this.
You can export *libcdict* JSON data (see [point 8 above](#cdict-to-JSON)) to a file or buffer which can easily be imported into *Perl* or *Python*, both of which have JSON modules to do this. For example, in Python try something like this.
```python
# read from a string
@@ -1007,8 +988,7 @@ data = keys_to_floats(data)
print('keys converted to floats:',data.keys())
```
FORTRAN
=======
# FORTRAN
The FORTRAN module for libcdict is a set of FORTRAN interfaces that directly call the C API.
It supports the same general functionality defined above with a few limitations, namely:
@@ -1022,9 +1002,6 @@ It supports the same general functionality defined above with a few limitations,
The module requires FORTRAN 90 or higher to use iso_c_binding.
FORTRAN Usage
=============
The following functions are currently supported in the FORTRAN API:
1. CDict_new
2. CDict_copy
@@ -1036,7 +1013,9 @@ The following functions are currently supported in the FORTRAN API:
Most of the above documentation is applicable to the FORTRAN API for these methods, so please read that first. The following is a brief summary of how to call the FORTRAN subroutines and a short example of a complete program that uses libcdict in FORTRAN.
0. <a id="fortran_cdict_module"></a>Include the cdict module file (cdict_fortran_interface.f90) in your FORTRAN source code.
## 0. Fortran cdict module
Include the cdict module file (cdict_fortran_interface.f90) in your FORTRAN source code.
First, cdict must be installed in the project directory using the above instructions. This allows `cdict_fortran_interface.f90`,`cdict_fortran_api.h`, and `libcdict.so` to be available. The module file (cdict_fortran_interface.f90) must be compiled with your FORTRAN source code and the cdict library (libcdict.so) must be linked. See the full example below to see how to do this with a Makefile.
@@ -1048,7 +1027,7 @@ Most of the above documentation is applicable to the FORTRAN API for these metho
implicit none
```
1. <a id="fortran_make_cdict"></a>CDict_new
## 1. New Fortran cdict
To make a cdict:
@@ -1066,7 +1045,7 @@ Most of the above documentation is applicable to the FORTRAN API for these metho
c = CDict_new(p)
```
2.<aid="fortran_free_cdict"></a>CDict_free
## 2. Free Fortran cdict
To free a cdict and any associated metadata (if set):
@@ -1077,7 +1056,7 @@ Most of the above documentation is applicable to the FORTRAN API for these metho
call CDict_free(c)
```
3.<aid="fortran_cdict_set"></a>CDict_set
## 3. Set data in Fortrancdict
To set entries into a cdict:
@@ -1115,7 +1094,7 @@ Most of the above documentation is applicable to the FORTRAN API for these metho
@@ -1132,7 +1111,7 @@ To set nested variables in a cdict:
Note that `CDict_nest` currently has a maximum nesting depth of 2. To achieve a deeper nesting level, set a cdict inside a cdict with repeated calls to `CDict_nest`. If you know how to achieve deeper nesting in FORTRAN, please let us know!
5.<aid="#fortran_cdict_copy"></a>CDict_copy
## 5. Copy Fortrancdict
To copy a cdict `c` into a new cdict `c_copy`, you must first make the new cdict with `CDict_new()` and then call `CDict_copy`:
@@ -1146,7 +1125,7 @@ To set nested variables in a cdict: