Commit 8db567fe authored by Robert Izzard's avatar Robert Izzard
Browse files

update readme and Merge branch 'master' into finterface

parents 4dbd3394 558d3f1d
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -14,3 +14,5 @@

29/04/2022 : V1.27 Rebranded as libcdict, added some build options,
             released under the GPL.

26/07/2022 : V1.29 Many (mostly small) bug fixes, improved much code, new set of unit tests for the API functions (macro and non-macro calls). Added JOSS paper.
+9 −0
Original line number Diff line number Diff line
@@ -74,5 +74,14 @@ ninja install

~~~

To build a version suitable for use with valgrind (this disables some gcc features that are incompatible with the current latest valgrind).

~~~bash

meson --prefix=$HOME --libdir=lib --buildtype=debug -Dvalgrind=TRUE builddir
cd builddir
ninja install

~~~

Further meson instructions can be found at https://mesonbuild.com/
 No newline at end of file
+1 −2
Original line number Diff line number Diff line
libcdict is copyright (c) Robert Izzard 2022

libcdict is a C library to use, output and load associated arrays, also know as dictionaries, e.g. in Python, or hashes, e.g. in Perl.
It is not perfect: if you spot a bug or deve
libcdict is a C library to use, output and load associated arrays, also known as dictionaries, e.g. in Python, or hashes, e.g. in Perl.

------------------------------------------------------------
    libcdict is free software: you can redistribute it and/or modify
+84 −47
Original line number Diff line number Diff line
Libcdict
========

Libcdict is a C library that provides a set functions to 
*Libcdict* is a C library that provides a set functions to 
allow native-C construction of associative arrays, known in Perl
as hashes or in Python as dictionaries. Input and output as JSON 
is included. Libcdict is designed to be fast and included most of 
is included. *Libcdict* is designed to be fast and included most of 
the features you would expect in Perl or Python.

Copyright 2022 Robert Izzard.
@@ -15,13 +15,13 @@ mirrored at
https://gitlab.com/robizzard/libcdict

Please see the file LICENCE for licensing conditions, currently 
libcdict is released under the GPL.
*libcdict* is released under the GPL.

Please cite the libcdict academic paper(s) and feel free to
donate cash to the Shepreth Hedgehog Hospital as a contribution 
( http://www.swccharity.org/hedgehog-hospital/ ).

libcdict uses code from:
*libcdict* uses code from:

* uthash at:
https://github.com/troydhanson/uthash
@@ -36,7 +36,7 @@ https://github.com/zserge/jsmn
https://github.com/lemire/fast_double_parser

These codes are provided under open-source licences
that are compatible with libcdict's GPL.
that are compatible with *libcdict*'s GPL.

Many thanks to the authors of those amazing codes!

@@ -56,13 +56,13 @@ pip3 install ninja
~~~


Then, use git to clone libcdict from its repository, e.g.
Then, use git to clone *libcdict* from its repository, e.g.

~~~bash
git clone https://gitlab.surrey.ac.uk/ri0005/libcdict.git
~~~

and then, from the libcdict directory, run:
and then, from the *libcdict* directory, run:

~~~bash
meson --prefix=$HOME --buildtype=release builddir
@@ -72,10 +72,10 @@ ninja install

which assumes your installation directories are in $HOME (e.g. $HOME/bin, $HOME/lib, etc.).

libcdict has been tested with modern versions of gcc (V7.5+) and clang (V9+).
*libcdict* has been tested with modern versions of gcc (V7.5+) and clang (V9+).

If you use another compiler, you will doubtless run into
difficulties because libcdict uses some gcc extensions.
difficulties because *libcdict* uses some gcc extensions.
Fortunately, gcc is available to all from https://gcc.gnu.org/ and clang is at https://clang.llvm.org/

Please note:
@@ -100,8 +100,7 @@ To make a cdict called `c`, use:
    CDict_new(c);
```

You can also make a new cdict with another cdict as its "parent",
which is sometimes useful.
You can also make a new cdict with another cdict as its "parent". The child cdict will inherit the parent's settings such as its error handler and cache use. This is useful when putting one cdict inside another (e.g. see `CDict_nest` below).

```c
    CDict_new(new_cdict,parent_cdict);
@@ -128,7 +127,7 @@ which is sometimes useful.
```
where the function should expect a `struct cdict_entry_t *` to be passed to it corresponding to each entry in `c`.

3. Setting scalars, arrays and pointers (including others cdict structs) in the cdict struct.
3. Setting scalars, arrays and pointers, including other cdicts, in your cdict struct.

  You can set entries containing scalars, pointers and arrays into the cdict with the `CDict_set()` function. This guesses the types of the key and value you try to set as well as array sizes.

@@ -174,8 +173,7 @@ You can set non-static (allocated memory) in the metadata too.
              CDict_string("League winners only 1950–51 and 1960–61"));
```

You can use a four-argument version of `CDict_set()` to give a reference a function
that is called to free any allocated memory.
You can use a four-argument version of `CDict_set()` to give a reference a function that is called to free any allocated memory.

```c

@@ -229,7 +227,7 @@ The `CDict_set` function can set scalars, pointers and arrays in the cdict with
  -  CDICT

note: if you want to explicitly use a `char*` pointer, call it a `VOID_POINTER`, i.e. `void*`, to avoid confusion with `STRING` types.
note: CDICT means a pointer to a libcdict entry (e.g. as created by a call to `CDict_new()`).
note: `CDICT` means a pointer to a `struct libcdict *`, e.g. as created by a call to `CDict_new()`.

   and the array types are:

@@ -343,7 +341,21 @@ Note that both "10" and 10 are valid keys, and they are different, and that the
               y);
```

Note that if you assign the strings with `CDict_string(...)`, they are automatically freed when freeing the cdict struct. Use the (libbsd) function `asprintf` directly if you do not want this useful feature.
Note that if you assign the strings with `CDict_string(...)`, they are automatically freed when freeing the `nestccdict` struct. Use the (libbsd) function `asprintf` directly if you do not want this useful feature.

Note that `CDict_nest`, and associated functions like `CDict_nest_set`, cannot handle `char *` types that are actual pointers to a char. You have two methods for handling `char *` types using the nest functions. 

* You chould treat them `as void *` types and manually cast them back to `char *`. 
* `CDict_nest` returns the new entry in the `cdict`, so you could set the type manually, e.g.

```c
    /* char * type: special case */
    struct cdict_entry_t * const e = CDict_nest("key",(char*)char_pointer,"nest","location");
    e->value.type = CDICT_DATA_TYPE_CHAR_POINTER;
    e->value.format = "%p";
```

The reason for this is that the compiler cannot distinguish between strings (`char[]`) and `char *` automatically, so we assume a string always. Given that you will almost always *actually* be using strings, and that there is a workaround for `char*` types, this is not a problem.

You can manually add pointers to a cdict's "tofree list" with:

@@ -380,15 +392,23 @@ Static strings are likely to be more efficiently stored in memory.

If no data is stored at the requested location available, `entry` will be `NULL`.

You can access a pointer to the the data in an entry by setting up a variable of the appropriate type. If there is an error, e.g. if the data does not exist at the required location, this returns NULL.
You can access a pointer to the the data in an entry by setting up a variable of the appropriate type. If there is an error, e.g. if the data does not exist at the required location, this pointer will be `NULL`.

```c
    double x;
    &x = CDict_nest_get_data_pointer(nestcdict,
                                      x,

    double * x = CDict_nest_get_data_pointer(nestcdict,
                                             "nested",
                                             "location", 
                                      ...);
                                             "of",
                                             "scalar double");
```
If you want access to something that's already a pointer, e.g. a cdict nested in a cdict, you have to be a little more careful because you have to cast the `void*` pointer returned by `CDict_nest_get_data_pointer` to `struct cdict_t **`, as shown below.

```c
    struct cdict_t * nested_cdict = 
               *(struct cdict_t **) CDict_nest_get_data_pointer(parent_cdict,
                                                                "nested",
                                                                "location");
```

More usefully, you can access the data itself (probably only works for scalar types):
@@ -401,7 +421,7 @@ More usefully, you can access the data itself (probably only works for scalar ty
                                  "location", 
                                  ...);
```
If the data does not exist, and error is raised.
If the data does not exist, an error is raised.

7.  You can loop over the keys in a cdict, access the entries' keys and values, with code like

@@ -429,7 +449,7 @@ If the data does not exist, and error is raised.
    }
```

If you do not care to sort the keys, use `CDict_loop(...)` instead.
If you do not care to sort the keys, use `CDict_loop(...)` instead of `CDict_sorted_loop(...)`.

You can access the cdict entry's value and key individually as strings from an entry using calls to `CDict_key_to_string()` and `CDict_value_to_string()`, e.g.

@@ -493,18 +513,18 @@ If you wish to compress the output so it uses less memory, use this call to `CDi
                    CDICT_JSON_NO_SORT);
```

libcdict has limited capability to load JSON data. Most of the limitation is that C arrays have a constant type, i.e. an array of ints, or floats, but not an array of some ints and some floats.
*libcdict* has limited capability to load JSON data. Most of the limitation is that C arrays must be of a constant type, i.e. an array of ints, or floats, but not an array of some ints and some floats. If you find this is truly a limitation for your work, you could store arrays of `void*` pointers to your data: these can point to anything.
   
   You can set a JSON string into a cdict:

```c
    CDict_JSON_buffer_to_Cdict(buffer,cdict);
    CDict_JSON_buffer_to_CDict(buffer,cdict);
```

   You can also load from a file into a cdict:

```c
    CDict_JSON_file_to_Cdict(cdict,filename);
    CDict_JSON_file_to_CDict(cdict,filename);
```

9.  Output formatting of keys and values is done automatically, but you can set the desired 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)`.
@@ -522,10 +542,22 @@ libcdict has limited capability to load JSON data. Most of the limitation is tha

```

10. Delete a single cdict entry with
10. 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);
```

Delete a cdict entry but do not delete its contents with this.

```c
    CDict_del_and_contents(cdict,entry,TRUE);
```

Delete a reference to a cdict entry with a call like this, but beware this does *not* delete the entry contents so will, unless you free the entry manually, lead to memory leaks. 

```c
    Cdict(cdict,key);
    CDict_del(cdict,entry);
```

11. 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.
@@ -582,7 +614,7 @@ You can also use your own sort function,

where the `sortfunc` should be defined as for the C standard-library `qsort` function.

14. A word on some internal functionality. Because libcdict automatically handles floating-point numbers, it has to make some choices. These come down to:
14. 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.

@@ -707,7 +739,7 @@ To set and get metadata from a cdict entry, use

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

```bash

@@ -739,15 +771,15 @@ Then, e.g.,
```bash

$ cdict-config --version
libcdict 1.27 : git 115:20220429:3ae3434 git@gitlab.surrey.ac.uk:ri0005/libcdict.git
libcdict 1.28 : git 129:20220718:c5a4d70 git@gitlab.surrey.ac.uk:ri0005/libcdict.git

```

which gives you the version number, git revision and git URL (which will probably be different to those shown above).

Running `cdict-config --tests` shows you the results of the test code in *cdict_tests.c*. Many of the above examples are in this code, as are many more.
Running `cdict-config --tests` shows you the results of the test code in *cdict_tests.c*. 

The `--libs` and `--cflags` are useful if you want to embed libcdict in your project (as it is in *binary_c*, see e.g. https://gitlab.surrey.ac.uk/ri0005/binary_c or https://gitlab.com/binary_c .
The `--libs` and `--cflags` are useful if you want to embed *libcdict* in your project (as it is in *binary_c*, see e.g. https://gitlab.surrey.ac.uk/ri0005/binary_c or https://gitlab.com/binary_c .

Note that the "--" are optional.

@@ -755,11 +787,16 @@ Note that the "--" are optional.

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.

The error handler function will be sent the data pointer, error number and a format statement and subsequent arguments so you can recreate the error string that libcdict uses by default.
The error handler function will be sent the data pointer, error number and a format statement and subsequent arguments so you can recreate the error string that *libcdict* uses by default.

*libcdict*'s action after the error handler is called depends on its return value. 

- If it returns >=0, or no error handler is set, then the error string is shown. If it returns <0 then the error string is not shown.
- If it returns >0, or no error handler is set, *libcdict* exits. If it turns <0 *libcdict* does not exit (this is for testing purposes).

```c
    void cdict_error_handler_function(void * p,
                                      int error_number,
    int cdict_error_handler_function(void * p,
                                     const int error_number,
                                     char * format,
                                     va_list args)
    {
@@ -809,20 +846,20 @@ Both `parent` and `ancestor` are `NULL` when the single-argument form of `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.

```c
    Cdict(cdict);
    CDict_new(cdict);
    CDict_new(cdict_copy);
    CDict_copy(cdict,cdict_copy);
```

18. Debugging

You have access to libcdict's debugging API. For example, to assert that x is true, use:
You have access to *libcdict*'s debugging API. For example, to assert that x is true, use:

```c
    CDict_assert(x);
```

which will exit through libcdict's `cdict_error()` when `x` is `false`.
which will exit through *libcdict*'s `cdict_error()` when `x` is `false`.

You can output cdict statistics with:

@@ -837,7 +874,7 @@ You can turn on debugging statements using:

19. Thread safety

libcdict is not designed to be explicitly thread safe: you'll need to implement some kind of asyncrhonous thread-locking 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). 
*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). 

20. Speed vs memory: the force_maps boolean

@@ -850,7 +887,7 @@ You should just choose which is most important to you: RAM or speed.

21. Use with external languages, e.g. *Perl* and *Python*.

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_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.
    
```python
    # read from a string 
@@ -1229,7 +1266,7 @@ Of libcdict, Robert Izzard.
Daniel Nemergut very kindly contributed the FORTRAN interface.
David Hendriks helped test the code and documentation.

External code from and probably modified in libcdict:
External code from and probably modified in *libcdict*:
* uthash by Troy Hanson 
* ryu by Ulf Adams 
* jsmn by Serge Zaitsev
@@ -1240,24 +1277,24 @@ You have no guarantee that any part of this code works and the author (Robert Iz
Originally part of the binary_c project https://gitlab.surrey.ac.uk/ri0005/binary_c .


libcdict uses uthash, (c) 2003-2018, Troy D. Hanson
*libcdict* uses uthash, (c) 2003-2018, Troy D. Hanson
http://troydhanson.github.com/uthash/
Please see its usage licence in uthash.h.


libcdict uses the code from ryu, (c) Ulf Adams
*libcdict* uses the code from ryu, (c) Ulf Adams
https://github.com/ulfjack/ryu
This is licenced under the Boost licence, see
ryu/LICENSE-Boost
(ryu is also released under the Apache2 licence ryu/LICENSE-Apache2)
Read their paper at https://dl.acm.org/doi/10.1145/3296979.3192369

libcdict uses jsmn, by Serge Zaitsev, distributed under an MIT LICENCE
*libcdict* uses jsmn, by Serge Zaitsev, distributed under an MIT LICENCE
https://github.com/zserge/jsmn https://zserge.com/jsmn/

libcdict uses code from the fast double parser (c) Daniel Lemire
*libcdict* uses code from the fast double parser (c) Daniel Lemire
https://github.com/lemire/fast_double_parser
which is released under the Apache licence

Many thanks to the authors of these codes, without you
libcdict would not be what it is.
*libcdict* would not be what it is.
+985 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading