From 43badf5e2668aadfa2da16fd9cab5fabf03703bc Mon Sep 17 00:00:00 2001 From: Jerome Kelleher Date: Thu, 28 Mar 2019 11:58:15 +0000 Subject: [PATCH 1/6] Added 'contains' operation. Closes #76. --- c/kastore.c | 22 ++++++++++++++++++++++ c/kastore.h | 40 ++++++++++++++++++++++++++++++++++++++++ c/tests.c | 36 ++++++++++++++++++++++++++++++++++++ docs/c-api.rst | 10 ++++++++++ 4 files changed, 108 insertions(+) diff --git a/c/kastore.c b/c/kastore.c index 12cf326..6b1cfe0 100644 --- a/c/kastore.c +++ b/c/kastore.c @@ -602,6 +602,28 @@ kastore_close(kastore_t *self) return ret; } +int KAS_WARN_UNUSED +kastore_contains(kastore_t *self, const char *key, size_t key_len) +{ + void *array; + size_t array_len; + int type; + int ret = kastore_get(self, key, key_len, &array, &array_len, &type); + + if (ret == 0) { + ret = 1; + } else if (ret == KAS_ERR_KEY_NOT_FOUND) { + ret = 0; + } + return ret; +} + +int KAS_WARN_UNUSED +kastore_containss(kastore_t *self, const char *key) +{ + return kastore_contains(self, key, strlen(key)); +} + int KAS_WARN_UNUSED kastore_get(kastore_t *self, const char *key, size_t key_len, void **array, size_t *array_len, int *type) diff --git a/c/kastore.h b/c/kastore.h index 39a9baa..ea9bedf 100644 --- a/c/kastore.h +++ b/c/kastore.h @@ -228,6 +228,46 @@ call ``kastore_close`` multiple times on the same object, but */ int kastore_close(kastore_t *self); +/** +@brief Return 1 if the store contains the specified key and 0 if it does not. + +@rst +Queries the store for the specified key and returns 1 if it exists. If the +key does not exist, 0 is returned. If an error occurs (for example, if querying +the store while it is in write-mode), a negative value is returned. + +For keys that are standard NULL terminated strings, the :c:func:`kastore_containss` +function may be more convenient. +@endrst + +@param self A pointer to a kastore object. +@param key The key. +@param key_len The length of the key. +@return Return 1 if the key is present and 0 if it does not. If an error occurs, + return a negative value. +*/ +int kastore_contains(kastore_t *self, const char *key, size_t key_len); + +/** +@brief Return 1 if the store contains the specified NULL terminated key +and 0 if it does not. + +@rst +Queries the store for the specified key, which must be a NULL terminated string, +and returns 1 if it exists. If the +key does not exist, 0 is returned. If an error occurs (for example, if querying +the store while it is in write-mode), a negative value is returned. +the array in the specified destination pointers. +@endrst + +@param self A pointer to a kastore object. +@param key The key. +@return Return 1 if the key is present and 0 if it does not. If an error occurs, + return a negative value. +*/ +int kastore_containss(kastore_t *self, const char *key); + + /** @brief Get the array for the specified key. diff --git a/c/tests.c b/c/tests.c index 3d5c4a4..d2dc25b 100644 --- a/c/tests.c +++ b/c/tests.c @@ -421,6 +421,35 @@ test_get_write_mode(void) CU_ASSERT_EQUAL_FATAL(ret, 0); } +static void +test_contains(void) +{ + int ret; + kastore_t store; + const uint32_t array[] = {1, 2, 3, 4}; + + ret = kastore_open(&store, _tmp_file_name, "w", 0); + CU_ASSERT_EQUAL_FATAL(ret, 0); + ret = kastore_puts(&store, "abc", array, 4, KAS_UINT32, 0); + CU_ASSERT_EQUAL_FATAL(ret, 0); + /* It's an error to query a store in write mode */ + CU_ASSERT_EQUAL(kastore_containss(&store, "abc"), KAS_ERR_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL(kastore_containss(&store, "xyz"), KAS_ERR_ILLEGAL_OPERATION); + ret = kastore_close(&store); + CU_ASSERT_EQUAL_FATAL(ret, 0); + + ret = kastore_open(&store, _tmp_file_name, "r", 0); + CU_ASSERT_EQUAL_FATAL(ret, 0); + CU_ASSERT_EQUAL_FATAL(kastore_containss(&store, "abc"), 1); + CU_ASSERT_EQUAL_FATAL(kastore_contains(&store, "abc", 3), 1); + CU_ASSERT_EQUAL_FATAL(kastore_contains(&store, "abc", 2), 0); + CU_ASSERT_EQUAL_FATAL(kastore_containss(&store, "ab"), 0); + CU_ASSERT_EQUAL_FATAL(kastore_containss(&store, "xyz"), 0); + + ret = kastore_close(&store); + CU_ASSERT_EQUAL_FATAL(ret, 0); +} + static void test_missing_key(void) { @@ -450,6 +479,9 @@ test_missing_key(void) CU_ASSERT_EQUAL_FATAL(ret, KAS_ERR_KEY_NOT_FOUND); ret = kastore_gets(&store, "defgh", (void **) &a, &array_len, &type); CU_ASSERT_EQUAL_FATAL(ret, KAS_ERR_KEY_NOT_FOUND); + CU_ASSERT_EQUAL_FATAL(kastore_containss(&store, "xyz"), 0); + CU_ASSERT_EQUAL_FATAL(kastore_containss(&store, "a"), 0); + CU_ASSERT_EQUAL_FATAL(kastore_containss(&store, "defgh"), 0); ret = kastore_close(&store); CU_ASSERT_EQUAL_FATAL(ret, 0); @@ -621,6 +653,7 @@ test_simple_round_trip_append(void) CU_ASSERT_EQUAL(type, KAS_UINT32); CU_ASSERT_EQUAL(array_len, 1); CU_ASSERT_EQUAL(a[0], 1); + CU_ASSERT_TRUE(kastore_containss(&store, "a")); ret = kastore_gets(&store, "b", (void **) &a, &array_len, &type); CU_ASSERT_EQUAL_FATAL(ret, 0); @@ -628,6 +661,7 @@ test_simple_round_trip_append(void) CU_ASSERT_EQUAL(array_len, 2); CU_ASSERT_EQUAL(a[0], 1); CU_ASSERT_EQUAL(a[1], 2); + CU_ASSERT_TRUE(kastore_containss(&store, "b")); ret = kastore_gets(&store, "c", (void **) &a, &array_len, &type); CU_ASSERT_EQUAL_FATAL(ret, 0); @@ -637,6 +671,7 @@ test_simple_round_trip_append(void) CU_ASSERT_EQUAL(a[1], 2); CU_ASSERT_EQUAL(a[2], 3); CU_ASSERT_EQUAL(a[3], 4); + CU_ASSERT_TRUE(kastore_containss(&store, "c")); ret = kastore_close(&store); CU_ASSERT_EQUAL_FATAL(ret, 0); @@ -1388,6 +1423,7 @@ main(int argc, char **argv) {"test_duplicate_key", test_duplicate_key}, {"test_duplicate_key_own_put", test_duplicate_key_own_put}, {"test_missing_key", test_missing_key}, + {"test_contains", test_contains}, {"test_bad_types", test_bad_types}, {"test_simple_round_trip", test_simple_round_trip}, {"test_simple_round_trip_own_put_buffers", test_simple_round_trip_own_put_buffers}, diff --git a/docs/c-api.rst b/docs/c-api.rst index 99862cf..efeee16 100644 --- a/docs/c-api.rst +++ b/docs/c-api.rst @@ -40,6 +40,16 @@ Top level .. _sec_c_api_get: + +****************** +Contains functions +****************** + +Contains functions provide a way to determine if a given key is in the store. + +.. doxygenfunction:: kastore_contains +.. doxygenfunction:: kastore_containss + ************* Get functions ************* From 41469a70a6675e33e2973ff320e9a60f945656e6 Mon Sep 17 00:00:00 2001 From: Jerome Kelleher Date: Thu, 28 Mar 2019 12:14:03 +0000 Subject: [PATCH 2/6] Change own_put to oput. --- c/kastore.c | 48 ++++++++++++++++++++++++------------------------ c/kastore.h | 26 +++++++++++++------------- c/tests.c | 48 ++++++++++++++++++++++++------------------------ docs/c-api.rst | 29 +++++++++++++++++++++++++++++ 4 files changed, 90 insertions(+), 61 deletions(-) diff --git a/c/kastore.c b/c/kastore.c index 6b1cfe0..2899382 100644 --- a/c/kastore.c +++ b/c/kastore.c @@ -767,7 +767,7 @@ kastore_put(kastore_t *self, const char *key, size_t key_len, } memcpy(array_copy, array, array_size); - ret = kastore_own_put(self, key, key_len, array_copy, array_len, type, flags); + ret = kastore_oput(self, key, key_len, array_copy, array_len, type, flags); if (ret == 0) { /* Kastore has taken ownership of the array, so we don't need to free it */ array_copy = NULL; @@ -778,7 +778,7 @@ kastore_put(kastore_t *self, const char *key, size_t key_len, } int KAS_WARN_UNUSED -kastore_own_put(kastore_t *self, const char *key, size_t key_len, +kastore_oput(kastore_t *self, const char *key, size_t key_len, void *array, size_t array_len, int type, int KAS_UNUSED(flags)) { int ret = 0; @@ -920,80 +920,80 @@ kastore_puts_float64(kastore_t *self, const char *key, const double *array, size } int KAS_WARN_UNUSED -kastore_own_puts(kastore_t *self, const char *key, +kastore_oputs(kastore_t *self, const char *key, void *array, size_t array_len, int type, int flags) { - return kastore_own_put(self, key, strlen(key), array, array_len, type, flags); + return kastore_oput(self, key, strlen(key), array, array_len, type, flags); } int KAS_WARN_UNUSED -kastore_own_puts_int8(kastore_t *self, const char *key, int8_t *array, size_t array_len, +kastore_oputs_int8(kastore_t *self, const char *key, int8_t *array, size_t array_len, int flags) { - return kastore_own_puts(self, key, (void *) array, array_len, KAS_INT8, flags); + return kastore_oputs(self, key, (void *) array, array_len, KAS_INT8, flags); } int KAS_WARN_UNUSED -kastore_own_puts_uint8(kastore_t *self, const char *key, uint8_t *array, size_t array_len, +kastore_oputs_uint8(kastore_t *self, const char *key, uint8_t *array, size_t array_len, int flags) { - return kastore_own_puts(self, key, (void *) array, array_len, KAS_UINT8, flags); + return kastore_oputs(self, key, (void *) array, array_len, KAS_UINT8, flags); } int KAS_WARN_UNUSED -kastore_own_puts_int16(kastore_t *self, const char *key, int16_t *array, size_t array_len, +kastore_oputs_int16(kastore_t *self, const char *key, int16_t *array, size_t array_len, int flags) { - return kastore_own_puts(self, key, (void *) array, array_len, KAS_INT16, flags); + return kastore_oputs(self, key, (void *) array, array_len, KAS_INT16, flags); } int KAS_WARN_UNUSED -kastore_own_puts_uint16(kastore_t *self, const char *key, uint16_t *array, size_t array_len, +kastore_oputs_uint16(kastore_t *self, const char *key, uint16_t *array, size_t array_len, int flags) { - return kastore_own_puts(self, key, (void *) array, array_len, KAS_UINT16, flags); + return kastore_oputs(self, key, (void *) array, array_len, KAS_UINT16, flags); } int KAS_WARN_UNUSED -kastore_own_puts_int32(kastore_t *self, const char *key, int32_t *array, size_t array_len, +kastore_oputs_int32(kastore_t *self, const char *key, int32_t *array, size_t array_len, int flags) { - return kastore_own_puts(self, key, (void *) array, array_len, KAS_INT32, flags); + return kastore_oputs(self, key, (void *) array, array_len, KAS_INT32, flags); } int KAS_WARN_UNUSED -kastore_own_puts_uint32(kastore_t *self, const char *key, uint32_t *array, size_t array_len, +kastore_oputs_uint32(kastore_t *self, const char *key, uint32_t *array, size_t array_len, int flags) { - return kastore_own_puts(self, key, (void *) array, array_len, KAS_UINT32, flags); + return kastore_oputs(self, key, (void *) array, array_len, KAS_UINT32, flags); } int KAS_WARN_UNUSED -kastore_own_puts_int64(kastore_t *self, const char *key, int64_t *array, size_t array_len, +kastore_oputs_int64(kastore_t *self, const char *key, int64_t *array, size_t array_len, int flags) { - return kastore_own_puts(self, key, (void *) array, array_len, KAS_INT64, flags); + return kastore_oputs(self, key, (void *) array, array_len, KAS_INT64, flags); } int KAS_WARN_UNUSED -kastore_own_puts_uint64(kastore_t *self, const char *key, uint64_t *array, size_t array_len, +kastore_oputs_uint64(kastore_t *self, const char *key, uint64_t *array, size_t array_len, int flags) { - return kastore_own_puts(self, key, (void *) array, array_len, KAS_UINT64, flags); + return kastore_oputs(self, key, (void *) array, array_len, KAS_UINT64, flags); } int KAS_WARN_UNUSED -kastore_own_puts_float32(kastore_t *self, const char *key, float *array, size_t array_len, +kastore_oputs_float32(kastore_t *self, const char *key, float *array, size_t array_len, int flags) { - return kastore_own_puts(self, key, (void *) array, array_len, KAS_FLOAT32, flags); + return kastore_oputs(self, key, (void *) array, array_len, KAS_FLOAT32, flags); } int KAS_WARN_UNUSED -kastore_own_puts_float64(kastore_t *self, const char *key, double *array, size_t array_len, +kastore_oputs_float64(kastore_t *self, const char *key, double *array, size_t array_len, int flags) { - return kastore_own_puts(self, key, (void *) array, array_len, KAS_FLOAT64, flags); + return kastore_oputs(self, key, (void *) array, array_len, KAS_FLOAT64, flags); } void diff --git a/c/kastore.h b/c/kastore.h index ea9bedf..102da24 100644 --- a/c/kastore.h +++ b/c/kastore.h @@ -428,13 +428,13 @@ function are identical to :c:func:`kastore_put`. @param flags The insertion flags. Currently unused. @return Return 0 on success or a negative value on failure. */ -int kastore_own_put(kastore_t *self, const char *key, size_t key_len, +int kastore_oput(kastore_t *self, const char *key, size_t key_len, void *array, size_t array_len, int type, int flags); /** @brief Insert the specified null terminated key and array pair into the store. @rst -As for :c:func:`kastore_own_put` except the key must be NULL-terminated C string. +As for :c:func:`kastore_oput` except the key must be NULL-terminated C string. @endrst @param self A pointer to a kastore object. @@ -445,7 +445,7 @@ As for :c:func:`kastore_own_put` except the key must be NULL-terminated C string @param flags The insertion flags. Currently unused. @return Return 0 on success or a negative value on failure. */ -int kastore_own_puts(kastore_t *self, const char *key, void *array, size_t array_len, +int kastore_oputs(kastore_t *self, const char *key, void *array, size_t array_len, int type, int flags); /** @@ -453,25 +453,25 @@ int kastore_own_puts(kastore_t *self, const char *key, void *array, size_t array @{ */ -int kastore_own_puts_int8(kastore_t *self, const char *key, int8_t *array, +int kastore_oputs_int8(kastore_t *self, const char *key, int8_t *array, size_t array_len, int flags); -int kastore_own_puts_uint8(kastore_t *self, const char *key, uint8_t *array, +int kastore_oputs_uint8(kastore_t *self, const char *key, uint8_t *array, size_t array_len, int flags); -int kastore_own_puts_int16(kastore_t *self, const char *key, int16_t *array, +int kastore_oputs_int16(kastore_t *self, const char *key, int16_t *array, size_t array_len, int flags); -int kastore_own_puts_uint16(kastore_t *self, const char *key, uint16_t *array, +int kastore_oputs_uint16(kastore_t *self, const char *key, uint16_t *array, size_t array_len, int flags); -int kastore_own_puts_int32(kastore_t *self, const char *key, int32_t *array, +int kastore_oputs_int32(kastore_t *self, const char *key, int32_t *array, size_t array_len, int flags); -int kastore_own_puts_uint32(kastore_t *self, const char *key, uint32_t *array, +int kastore_oputs_uint32(kastore_t *self, const char *key, uint32_t *array, size_t array_len, int flags); -int kastore_own_puts_int64(kastore_t *self, const char *key, int64_t *array, +int kastore_oputs_int64(kastore_t *self, const char *key, int64_t *array, size_t array_len, int flags); -int kastore_own_puts_uint64(kastore_t *self, const char *key, uint64_t *array, +int kastore_oputs_uint64(kastore_t *self, const char *key, uint64_t *array, size_t array_len, int flags); -int kastore_own_puts_float32(kastore_t *self, const char *key, float *array, +int kastore_oputs_float32(kastore_t *self, const char *key, float *array, size_t array_len, int flags); -int kastore_own_puts_float64(kastore_t *self, const char *key, double *array, +int kastore_oputs_float64(kastore_t *self, const char *key, double *array, size_t array_len, int flags); /** @} */ diff --git a/c/tests.c b/c/tests.c index d2dc25b..b510eca 100644 --- a/c/tests.c +++ b/c/tests.c @@ -176,13 +176,13 @@ test_bad_types(void) ret = kastore_puts(&store, "a", array, 1, KAS_NUM_TYPES + 1, 0); CU_ASSERT_EQUAL_FATAL(ret, KAS_ERR_BAD_TYPE); - ret = kastore_own_puts(&store, "a", NULL, 1, -1, 0); + ret = kastore_oputs(&store, "a", NULL, 1, -1, 0); CU_ASSERT_EQUAL_FATAL(ret, KAS_ERR_BAD_TYPE); - ret = kastore_own_puts(&store, "a", NULL, 1, -2, 0); + ret = kastore_oputs(&store, "a", NULL, 1, -2, 0); CU_ASSERT_EQUAL_FATAL(ret, KAS_ERR_BAD_TYPE); - ret = kastore_own_puts(&store, "a", NULL, 1, KAS_NUM_TYPES, 0); + ret = kastore_oputs(&store, "a", NULL, 1, KAS_NUM_TYPES, 0); CU_ASSERT_EQUAL_FATAL(ret, KAS_ERR_BAD_TYPE); - ret = kastore_own_puts(&store, "a", NULL, 1, KAS_NUM_TYPES + 1, 0); + ret = kastore_oputs(&store, "a", NULL, 1, KAS_NUM_TYPES + 1, 0); CU_ASSERT_EQUAL_FATAL(ret, KAS_ERR_BAD_TYPE); ret = kastore_close(&store); @@ -325,7 +325,7 @@ test_duplicate_key(void) } static void -test_duplicate_key_own_put(void) +test_duplicate_key_oput(void) { int ret; kastore_t store; @@ -338,11 +338,11 @@ test_duplicate_key_own_put(void) ret = kastore_open(&store, _tmp_file_name, "w", 0); CU_ASSERT_EQUAL_FATAL(ret, 0); - ret = kastore_own_put(&store, "a", 1, a, 1, KAS_UINT32, 0); + ret = kastore_oput(&store, "a", 1, a, 1, KAS_UINT32, 0); CU_ASSERT_EQUAL_FATAL(ret, 0); - ret = kastore_own_put(&store, "b", 1, b, 1, KAS_UINT32, 0); + ret = kastore_oput(&store, "b", 1, b, 1, KAS_UINT32, 0); CU_ASSERT_EQUAL_FATAL(ret, 0); - ret = kastore_own_put(&store, "a", 1, c, 1, KAS_UINT32, 0); + ret = kastore_oput(&store, "a", 1, c, 1, KAS_UINT32, 0); CU_ASSERT_EQUAL_FATAL(ret, KAS_ERR_DUPLICATE_KEY); CU_ASSERT_EQUAL_FATAL(store.num_items, 2); @@ -545,7 +545,7 @@ test_simple_round_trip(void) } static void -test_simple_round_trip_own_put_buffers(void) +test_simple_round_trip_oput_buffers(void) { int ret; kastore_t store; @@ -569,11 +569,11 @@ test_simple_round_trip_own_put_buffers(void) ret = kastore_open(&store, _tmp_file_name, "w", 0); CU_ASSERT_EQUAL_FATAL(ret, 0); - ret = kastore_own_puts_uint32(&store, "c", array_c, 4, 0); + ret = kastore_oputs_uint32(&store, "c", array_c, 4, 0); CU_ASSERT_EQUAL_FATAL(ret, 0); - ret = kastore_own_puts_uint32(&store, "b", array_b, 2, 0); + ret = kastore_oputs_uint32(&store, "b", array_b, 2, 0); CU_ASSERT_EQUAL_FATAL(ret, 0); - ret = kastore_own_puts_uint32(&store, "a", array_a, 1, 0); + ret = kastore_oputs_uint32(&store, "a", array_a, 1, 0); CU_ASSERT_EQUAL_FATAL(ret, 0); ret = kastore_close(&store); @@ -732,7 +732,7 @@ test_round_trip_int8(void) CU_ASSERT_EQUAL_FATAL(ret, 0); ret = kastore_puts_int8(&store, "max", &max, 1, 0); CU_ASSERT_EQUAL_FATAL(ret, 0); - ret = kastore_own_puts_int8(&store, "zero", zero, 1, 0); + ret = kastore_oputs_int8(&store, "zero", zero, 1, 0); CU_ASSERT_EQUAL_FATAL(ret, 0); ret = kastore_close(&store); CU_ASSERT_EQUAL_FATAL(ret, 0); @@ -773,7 +773,7 @@ test_round_trip_uint8(void) CU_ASSERT_EQUAL_FATAL(ret, 0); ret = kastore_puts_uint8(&store, "max", &max, 1, 0); CU_ASSERT_EQUAL_FATAL(ret, 0); - ret = kastore_own_puts_uint8(&store, "zero", zero, 1, 0); + ret = kastore_oputs_uint8(&store, "zero", zero, 1, 0); CU_ASSERT_EQUAL_FATAL(ret, 0); ret = kastore_close(&store); CU_ASSERT_EQUAL_FATAL(ret, 0); @@ -814,7 +814,7 @@ test_round_trip_int16(void) CU_ASSERT_EQUAL_FATAL(ret, 0); ret = kastore_puts_int16(&store, "max", &max, 1, 0); CU_ASSERT_EQUAL_FATAL(ret, 0); - ret = kastore_own_puts_int16(&store, "zero", zero, 1, 0); + ret = kastore_oputs_int16(&store, "zero", zero, 1, 0); CU_ASSERT_EQUAL_FATAL(ret, 0); ret = kastore_close(&store); CU_ASSERT_EQUAL_FATAL(ret, 0); @@ -855,7 +855,7 @@ test_round_trip_uint16(void) CU_ASSERT_EQUAL_FATAL(ret, 0); ret = kastore_puts_uint16(&store, "max", &max, 1, 0); CU_ASSERT_EQUAL_FATAL(ret, 0); - ret = kastore_own_puts_uint16(&store, "zero", zero, 1, 0); + ret = kastore_oputs_uint16(&store, "zero", zero, 1, 0); CU_ASSERT_EQUAL_FATAL(ret, 0); ret = kastore_close(&store); CU_ASSERT_EQUAL_FATAL(ret, 0); @@ -896,7 +896,7 @@ test_round_trip_int32(void) CU_ASSERT_EQUAL_FATAL(ret, 0); ret = kastore_puts_int32(&store, "max", &max, 1, 0); CU_ASSERT_EQUAL_FATAL(ret, 0); - ret = kastore_own_puts_int32(&store, "zero", zero, 1, 0); + ret = kastore_oputs_int32(&store, "zero", zero, 1, 0); CU_ASSERT_EQUAL_FATAL(ret, 0); ret = kastore_close(&store); CU_ASSERT_EQUAL_FATAL(ret, 0); @@ -937,7 +937,7 @@ test_round_trip_uint32(void) CU_ASSERT_EQUAL_FATAL(ret, 0); ret = kastore_puts_uint32(&store, "max", &max, 1, 0); CU_ASSERT_EQUAL_FATAL(ret, 0); - ret = kastore_own_puts_uint32(&store, "zero", zero, 1, 0); + ret = kastore_oputs_uint32(&store, "zero", zero, 1, 0); CU_ASSERT_EQUAL_FATAL(ret, 0); ret = kastore_close(&store); CU_ASSERT_EQUAL_FATAL(ret, 0); @@ -979,7 +979,7 @@ test_round_trip_int64(void) CU_ASSERT_EQUAL_FATAL(ret, 0); ret = kastore_puts_int64(&store, "max", &max, 1, 0); CU_ASSERT_EQUAL_FATAL(ret, 0); - ret = kastore_own_puts_int64(&store, "zero", zero, 1, 0); + ret = kastore_oputs_int64(&store, "zero", zero, 1, 0); CU_ASSERT_EQUAL_FATAL(ret, 0); ret = kastore_close(&store); CU_ASSERT_EQUAL_FATAL(ret, 0); @@ -1020,7 +1020,7 @@ test_round_trip_uint64(void) CU_ASSERT_EQUAL_FATAL(ret, 0); ret = kastore_puts_uint64(&store, "max", &max, 1, 0); CU_ASSERT_EQUAL_FATAL(ret, 0); - ret = kastore_own_puts_uint64(&store, "zero", zero, 1, 0); + ret = kastore_oputs_uint64(&store, "zero", zero, 1, 0); CU_ASSERT_EQUAL_FATAL(ret, 0); ret = kastore_close(&store); CU_ASSERT_EQUAL_FATAL(ret, 0); @@ -1061,7 +1061,7 @@ test_round_trip_float32(void) CU_ASSERT_EQUAL_FATAL(ret, 0); ret = kastore_puts_float32(&store, "max", &max, 1, 0); CU_ASSERT_EQUAL_FATAL(ret, 0); - ret = kastore_own_puts_float32(&store, "zero", zero, 1, 0); + ret = kastore_oputs_float32(&store, "zero", zero, 1, 0); CU_ASSERT_EQUAL_FATAL(ret, 0); ret = kastore_close(&store); CU_ASSERT_EQUAL_FATAL(ret, 0); @@ -1102,7 +1102,7 @@ test_round_trip_float64(void) CU_ASSERT_EQUAL_FATAL(ret, 0); ret = kastore_puts_float64(&store, "max", &max, 1, 0); CU_ASSERT_EQUAL_FATAL(ret, 0); - ret = kastore_own_puts_float64(&store, "zero", zero, 1, 0); + ret = kastore_oputs_float64(&store, "zero", zero, 1, 0); CU_ASSERT_EQUAL_FATAL(ret, 0); ret = kastore_close(&store); CU_ASSERT_EQUAL_FATAL(ret, 0); @@ -1421,12 +1421,12 @@ main(int argc, char **argv) {"test_mixed_keys", test_mixed_keys}, {"test_put_copy_array", test_put_copy_array}, {"test_duplicate_key", test_duplicate_key}, - {"test_duplicate_key_own_put", test_duplicate_key_own_put}, + {"test_duplicate_key_oput", test_duplicate_key_oput}, {"test_missing_key", test_missing_key}, {"test_contains", test_contains}, {"test_bad_types", test_bad_types}, {"test_simple_round_trip", test_simple_round_trip}, - {"test_simple_round_trip_own_put_buffers", test_simple_round_trip_own_put_buffers}, + {"test_simple_round_trip_oput_buffers", test_simple_round_trip_oput_buffers}, {"test_simple_round_trip_append", test_simple_round_trip_append}, {"test_gets_type_errors", test_gets_type_errors}, {"test_round_trip_int8", test_round_trip_int8}, diff --git a/docs/c-api.rst b/docs/c-api.rst index efeee16..02d4782 100644 --- a/docs/c-api.rst +++ b/docs/c-api.rst @@ -102,6 +102,35 @@ type of the array is known in advance. :content-only: +.. _sec_c_api_oput: + +************* +Put functions +************* + +Put functions provide the interface for inserting data into store. The most +general interface is :c:func:`kastore_put` which allows keys to be arbitrary +bytes, but it is usually more convenient to use one of the :ref:`typed put +functions `. + +.. doxygenfunction:: kastore_put +.. doxygenfunction:: kastore_puts + +.. _sec_c_api_typed_put: + +---------- +Typed puts +---------- + +The functions listed here provide a convenient short-cut for inserting +key-array pairs where the key is a standard NULL terminated C string and the +type of the array is known in advance. + +.. doxygengroup:: TYPED_PUTS_GROUP + :content-only: + + + ********* Constants ********* From f41002d3f74ca23b64f7f1d04010cdf59a755c4d Mon Sep 17 00:00:00 2001 From: Jerome Kelleher Date: Thu, 28 Mar 2019 13:18:34 +0000 Subject: [PATCH 3/6] Add example program to documentation. --- c/example.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++ c/kastore.h | 20 ++++++----- c/meson.build | 1 + c/tests.c | 19 ++++++++++ docs/c-api.rst | 44 ++++++++++++----------- 5 files changed, 151 insertions(+), 29 deletions(-) create mode 100644 c/example.c diff --git a/c/example.c b/c/example.c new file mode 100644 index 0000000..ec7ee7d --- /dev/null +++ b/c/example.c @@ -0,0 +1,96 @@ +/* This is a simple program to illustrate the kastore C API. With + * no arguments it writes a file 'example.kas'. If called with + * a single command line argument, reads this file in and prints. + */ +#include +#include +#include + +#include + +static void +handle_kas_error(int line, int retval) +{ + errx(1, "Error at line %d: %s", line, kas_strerror(retval)); +} + +static void +write_example(const char *path) +{ + int ret; + kastore_t store; + const uint32_t a[] = {1, 2, 3, 4}; + size_t b_length = 10; + uint32_t *b = calloc(b_length, sizeof(*b)); + + if (b == NULL) { + err(1, "Out of memory"); + } + + ret = kastore_open(&store, path, "w", 0); + if (ret != 0) { + handle_kas_error(__LINE__, ret); + } + /* This is the standard 'put' where the library takes a copy of the array. + * This is the recommended approach unless working with very large arrays. */ + ret = kastore_puts_uint32(&store, "a", a, 4, 0); + if (ret != 0) { + handle_kas_error(__LINE__, ret); + } + /* This is the own-put variant, where the array is inserted into the store + * and ownership of the buffer (which must be a pointer returned from + * malloc/calloc) is passed to the store. The buffer will be freed by the + * library when 'close' is called. */ + ret = kastore_oputs_uint32(&store, "b", b, b_length, 0); + if (ret != 0) { + /* The store only takes ownership of the buffer if oputs succeeds, so + * we must free b here to avoid leaking memory in error conditions */ + free(b); + handle_kas_error(__LINE__, ret); + } + + ret = kastore_close(&store); + if (ret != 0) { + handle_kas_error(__LINE__, ret); + } +} + +static void +read_example(const char *path) +{ + int ret; + kastore_t store; + uint32_t *array; + size_t j, k, array_len; + const char *keys[] = {"a", "b"}; + + ret = kastore_open(&store, path, "r", 0); + if (ret != 0) { + handle_kas_error(__LINE__, ret); + } + for (j = 0; j < sizeof(keys) / sizeof(*keys); j++) { + ret = kastore_gets_uint32(&store, keys[j], &array, &array_len); + if (ret != 0) { + handle_kas_error(__LINE__, ret); + } + printf("key: %s = [", keys[j]); + for (k = 0; k < array_len; k++) { + printf("%d%s", array[k], k == array_len - 1 ? "]\n": ", "); + } + } + ret = kastore_close(&store); + if (ret != 0) { + handle_kas_error(__LINE__, ret); + } +} + +int +main(int argc, char **argv) +{ + if (argc == 1) { + write_example("example.kas"); + } else { + read_example(argv[1]); + } + return 0; +} diff --git a/c/kastore.h b/c/kastore.h index 102da24..fdbb691 100644 --- a/c/kastore.h +++ b/c/kastore.h @@ -359,7 +359,7 @@ strings, it is usually more convenient to use the :ref:`typed variants int kastore_put(kastore_t *self, const char *key, size_t key_len, const void *array, size_t array_len, int type, int flags); /** -@brief Insert the specified null terminated key and array pair into the store. +@brief Insert the specified NULL terminated key and array pair into the store. @rst As for :c:func:`kastore_put` except the key must be NULL-terminated C string. @@ -405,15 +405,16 @@ int kastore_puts_float64(kastore_t *self, const char *key, const double *array, /** @} */ /** -@brief Insert the specified key-array pair into the store, taking ownership -of the array buffer (own-put). +@brief Insert the specified key-array pair into the store, transferring ownership +of the malloced array buffer to the store (own-put). @rst A key with the specified length is inserted into the store and associated with an array of the specified type and number of elements. The contents of the -specified key is copied, but the array buffer is 'taken' and freed when -the store is closed. The array buffer must be a pointer returned by ``malloc``. -Ownership of the buffer is not taken unless the function returns successfully. +specified key is copied, but the array buffer is taken directly and freed when +the store is closed. The array buffer must be a pointer returned by ``malloc`` +or ``calloc``. Ownership of the buffer is not taken unless the function returns +successfully. Apart from taking ownership of the array buffer, the semantics of this function are identical to :c:func:`kastore_put`. @@ -422,7 +423,7 @@ function are identical to :c:func:`kastore_put`. @param self A pointer to a kastore object. @param key The key. @param key_len The length of the key. -@param array The array. Must be a pointer returned by malloc. +@param array The array. Must be a pointer returned by malloc/calloc. @param array_len The number of elements in the array. @param type The type of the array. @param flags The insertion flags. Currently unused. @@ -431,7 +432,8 @@ function are identical to :c:func:`kastore_put`. int kastore_oput(kastore_t *self, const char *key, size_t key_len, void *array, size_t array_len, int type, int flags); /** -@brief Insert the specified null terminated key and array pair into the store. +@brief Insert the specified NULL terminated key and array pair into the store, +transferring ownership of the malloced array buffer to the store (own-put). @rst As for :c:func:`kastore_oput` except the key must be NULL-terminated C string. @@ -439,7 +441,7 @@ As for :c:func:`kastore_oput` except the key must be NULL-terminated C string. @param self A pointer to a kastore object. @param key The key. -@param array The array. Must be a pointer returned by malloc. +@param array The array. Must be a pointer returned by malloc/calloc. @param array_len The number of elements in the array. @param type The type of the array. @param flags The insertion flags. Currently unused. diff --git a/c/meson.build b/c/meson.build index fe22554..14f40ba 100644 --- a/c/meson.build +++ b/c/meson.build @@ -19,6 +19,7 @@ if not meson.is_subproject() # The shared library can be installed into the system. install_headers('kastore.h') shared_library('kastore', 'kastore.c', install: true) + executable('example', ['example.c'], link_with: kastore) cunit_dep = dependency('cunit') executable('tests', ['tests.c', 'kastore.c'], dependencies: cunit_dep) diff --git a/c/tests.c b/c/tests.c index b510eca..8705db2 100644 --- a/c/tests.c +++ b/c/tests.c @@ -12,6 +12,24 @@ char * _tmp_file_name; FILE * _devnull; +static void +test_oputs_example(void) +{ + int ret; + kastore_t store; + size_t num_elements = 100; + uint32_t *array = calloc(num_elements, sizeof(*array)); + + ret = kastore_open(&store, _tmp_file_name, "w", 0); + CU_ASSERT_EQUAL_FATAL(ret, 0); + + ret = kastore_oputs_uint32(&store, "big_array", array, num_elements, 0); + CU_ASSERT_EQUAL_FATAL(ret, 0); + + ret = kastore_close(&store); + CU_ASSERT_EQUAL_FATAL(ret, 0); +} + static void test_bad_open_mode(void) { @@ -1408,6 +1426,7 @@ main(int argc, char **argv) CU_pTest test; CU_pSuite suite; CU_TestInfo tests[] = { + {"test_oputs_example", test_oputs_example}, {"test_bad_open_mode", test_bad_open_mode}, {"test_open_io_errors", test_open_io_errors}, {"test_append_empty_file", test_append_empty_file}, diff --git a/docs/c-api.rst b/docs/c-api.rst index 02d4782..e7e15bf 100644 --- a/docs/c-api.rst +++ b/docs/c-api.rst @@ -6,8 +6,14 @@ C API Documentation This is the C API documentation for kastore. -.. todo:: Give a short example program. +.. _sec_c_api_example: +*************** +Example program +*************** + +.. literalinclude:: ../c/example.c + :language: c ****************** General principles @@ -104,33 +110,31 @@ type of the array is known in advance. .. _sec_c_api_oput: -************* -Put functions -************* - -Put functions provide the interface for inserting data into store. The most -general interface is :c:func:`kastore_put` which allows keys to be arbitrary -bytes, but it is usually more convenient to use one of the :ref:`typed put -functions `. +***************** +Own-put functions +***************** -.. doxygenfunction:: kastore_put -.. doxygenfunction:: kastore_puts +The 'own-put' functions are almost identical to the standard 'put' functions, +but transfer ownership of the array buffer from the caller to the store. This +is useful, for example, when client code wishes to write a large array to the +store and wants of avoid the overhead of keeping a separate copy of this buffer +in the store. By calling :c:func:`kastore_oput`, the user can put the key-array +pair into the store and transfer responsibility for freeing the malloced +array buffer to the store. See the :ref:`sec_c_api_example` for an illustration. -.. _sec_c_api_typed_put: +.. doxygenfunction:: kastore_oput +.. doxygenfunction:: kastore_oputs ----------- -Typed puts ----------- +.. _sec_c_api_typed_oput: -The functions listed here provide a convenient short-cut for inserting -key-array pairs where the key is a standard NULL terminated C string and the -type of the array is known in advance. +----------- +Typed oputs +----------- -.. doxygengroup:: TYPED_PUTS_GROUP +.. doxygengroup:: TYPED_OPUTS_GROUP :content-only: - ********* Constants ********* From 0ef332f10c905c0a258c6544a33f9e0ce03fe2bd Mon Sep 17 00:00:00 2001 From: Jerome Kelleher Date: Thu, 28 Mar 2019 13:28:14 +0000 Subject: [PATCH 4/6] Document READ_ALL flag. Closes #61. --- c/kastore.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/c/kastore.h b/c/kastore.h index fdbb691..084f7ab 100644 --- a/c/kastore.h +++ b/c/kastore.h @@ -204,7 +204,18 @@ After :c:func:`kastore_open` has been called on a particular store, :c:func:`kastore_close` must be called to avoid leaking memory. This must also be done when :c:func:`kastore_open` returns an error. -.. todo:: Document open flags. +When opened in read-mode, the default is to read key/array values from file +on demand. This is useful when a subset of the data is required and we don't +wish to read the entire file. If the entire file is to be read, the +``KAS_READ_ALL`` flag may be specified to improve performance. + +**Flags** + +KAS_READ_ALL + If this option is specified, read the entire file at + open time. This will give slightly better performance as the file can + be read sequentially in a single pass. + @endrst @param self A pointer to a kastore object. From bcc17f095d5a84098dfd5078173314149e56ecb2 Mon Sep 17 00:00:00 2001 From: Jerome Kelleher Date: Thu, 28 Mar 2019 13:29:20 +0000 Subject: [PATCH 5/6] Bumped C API version to 1.1.0. --- c/kastore.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/c/kastore.h b/c/kastore.h index 084f7ab..604a144 100644 --- a/c/kastore.h +++ b/c/kastore.h @@ -140,12 +140,12 @@ sizes and types of externally visible structs. The library major version. Incremented when non-breaking backward-compatible changes to the API or ABI are introduced, i.e., the addition of a new function. */ -#define KAS_VERSION_MINOR 0 +#define KAS_VERSION_MINOR 1 /** The library patch version. Incremented when any changes not relevant to the to the API or ABI are introduced, i.e., internal refactors of bugfixes. */ -#define KAS_VERSION_PATCH 1 +#define KAS_VERSION_PATCH 0 /** @} */ #define KAS_HEADER_SIZE 64 From 3123c857c20a69c5b63cc91490f0a0988bcb22e4 Mon Sep 17 00:00:00 2001 From: Jerome Kelleher Date: Thu, 28 Mar 2019 13:32:51 +0000 Subject: [PATCH 6/6] Update changelog. --- c/CHANGELOG.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/c/CHANGELOG.rst b/c/CHANGELOG.rst index 16e3e49..99a1eab 100644 --- a/c/CHANGELOG.rst +++ b/c/CHANGELOG.rst @@ -1,3 +1,11 @@ +-------------------- +[1.1.0] - 2019-03-19 +-------------------- + +- Add `contains` function +- Add `oput` variants that transfer ownership of buffer. +- Various documentation updates. + -------------------- [1.0.1] - 2019-01-24 --------------------