Skip to main content
Commonmark migration
Source Link

##Usage

Usage

##Questions

Questions

##Code

Code

##Usage

##Questions

##Code

Usage

Questions

Code

added 108 characters in body
Source Link
Dagg
  • 4.5k
  • 1
  • 24
  • 41

Use kvs_create and kvs_createkvs_destroy to create stores and clean them up later:

I'd like to make the length and pairs fields in KVSstore read-only with const (because any attempt to alter these would amount to user error under the use cases I have in mind for this), but I need some way to make them mutable internally. Casting back and forth between KVSstore and something like KVSmutablestore gets old really fast, and makes the code more difficult to follow. I'm trying to figure out a cleaner way to handle that.

Use kvs_create and kvs_create to create stores and clean them up later:

I'd like to make the length and pairs fields in KVSstore read-only with const, but I need some way to make them mutable internally. Casting back and forth between KVSstore and something like KVSmutablestore gets old really fast, and makes the code more difficult to follow. I'm trying to figure out a cleaner way to handle that.

Use kvs_create and kvs_destroy to create stores and clean them up later:

I'd like to make the length and pairs fields in KVSstore read-only with const (because any attempt to alter these would amount to user error under the use cases I have in mind for this), but I need some way to make them mutable internally. Casting back and forth between KVSstore and something like KVSmutablestore gets old really fast, and makes the code more difficult to follow. I'm trying to figure out a cleaner way to handle that.

Source Link
Dagg
  • 4.5k
  • 1
  • 24
  • 41

Simple key-value store in C

I needed a simple key-value store. Here's what I came up with.

##Usage

Use kvs_create and kvs_create to create stores and clean them up later:

KVSstore *store = kvs_create();
...
kvs_destroy(store);

Of course you can also create a store on the stack:

KVSstore s = {0};
KVSstore *store = &s;

Add values to the store or update existing values with kvs_put:

const char *nameKey = "name";
const char *jobKey = "job";

kvs_put(store, nameKey, "Bob"); // store->length is now 1
kvs_put(store, jobKey, "Janitor"); // store->length is now 2

Get values from the store with kvs_get:

const char *name = kvs_get(store, nameKey); // "Bob"
const char *job = kvs_get(store, jobKey); // "Janitor"

If the key isn't found, kvs_get returns NULL. Setting a value to NULL with kvs_put will remove the key-value pair from the store if the key was found.

kvs_put(store, jobKey, NULL); // store->length is now 1

These examples use strings, but keys and values are really opaque data pointers (void *). Care should be taken with string keys, since two otherwise identical strings existing at different memory locations are two different keys.

##Questions

I'd like to make the length and pairs fields in KVSstore read-only with const, but I need some way to make them mutable internally. Casting back and forth between KVSstore and something like KVSmutablestore gets old really fast, and makes the code more difficult to follow. I'm trying to figure out a cleaner way to handle that.

Other than that, I'm just looking for a general review.

##Code

kvs.h

#ifndef __KVS_H__
#define __KVS_H__

#ifdef __cplusplus
extern "C" {
#endif

#include <stdlib.h>

typedef struct {
    const void *key;
    void *value;
} KVSpair;

typedef struct {
    KVSpair *pairs;
    size_t length;
} KVSstore;

KVSstore *kvs_create(void);

void kvs_destroy(KVSstore *store);

void kvs_put(KVSstore *store, const void *key, void *value);

void *kvs_get(KVSstore *store, const void *key);

#ifdef __cplusplus
}
#endif

#endif /* #define __KVS_H__ */

kvs.c

#include "kvs.h"

static const size_t kvs_pair_size = sizeof(KVSpair);

static const size_t kvs_store_size = sizeof(KVSstore);

static int kvs_sort_compare(const void *a, const void *b) {
    const KVSpair *pairA = a;
    const KVSpair *pairB = b;
    if (pairA->key > pairB->key) {
        return -1;
    }
    if (pairA->key < pairB->key) {
        return 1;
    }
    return 0;
}

static int kvs_search_compare(const void *key, const void *element) {
    const KVSpair *pair = element;
    if (key > pair->key) {
        return -1;
    }
    if (key < pair->key) {
        return 1;
    }
    return 0;
}

static KVSpair *kvs_get_pair(KVSstore *store, const void *key) {
    if ((!store) || (!store->pairs)) {
        return NULL;
    }
    return bsearch(key, store->pairs, store->length, kvs_pair_size,
                    kvs_search_compare);
}

static void kvs_sort_pairs(KVSstore *store) {
    if ((!store) || (!store->pairs)) {
        return;
    }
    qsort(store->pairs, store->length, kvs_pair_size, kvs_sort_compare);
}

static void kvs_resize_pairs(KVSstore *store) {
    if (!store) {
        return;
    }
    store->pairs = realloc(store->pairs, kvs_pair_size * store->length);
}

static void kvs_create_pair(KVSstore *store, const void *key, void *value) {
    KVSpair *pair;
    if (!store) {
        return;
    }
    ++store->length;
    kvs_resize_pairs(store);
    pair = &store->pairs[store->length - 1];
    pair->key = key;
    pair->value = value;
    kvs_sort_pairs(store);
}

static void kvs_remove_pair(KVSstore *store, KVSpair *pair) {
    if ((!store) || (!pair)) {
        return;
    }
    pair->key = NULL;
    kvs_sort_pairs(store);
    --store->length;
    kvs_resize_pairs(store);
}

KVSstore *kvs_create(void) {
    KVSstore *store = malloc(kvs_store_size);
    store->pairs = NULL;
    store->length = 0;
    return store;
}

void kvs_destroy(KVSstore *store) {
    if (!store) {
        return;
    }
    if (store->pairs) {
        free(store->pairs);
    }
    free(store);
}

void kvs_put(KVSstore *store, const void *key, void *value) {
    KVSpair *pair = kvs_get_pair(store, key);
    if (pair) {
        if (value) {
            pair->value = value;
        } else {
            kvs_remove_pair(store, pair);
        }
    } else if (value) {
        kvs_create_pair(store, key, value);
    }
}

void *kvs_get(KVSstore *store, const void *key) {
    KVSpair *pair = kvs_get_pair(store, key);
    return pair ? pair->value : NULL;
}