github.com/moontrade/nogc@v0.1.7/collections/wormhole/kv.c (about)

     1  /*
     2   * Copyright (c) 2016--2021  Wu, Xingbo <wuxb45@gmail.com>
     3   *
     4   * All rights reserved. No warranty, explicit or implicit, provided.
     5   */
     6  #define _GNU_SOURCE
     7  
     8  // headers {{{
     9  #include <assert.h> // static_assert
    10  #include <ctype.h>
    11  #include "lib.h"
    12  #include "ctypes.h"
    13  #include "kv.h"
    14  // }}} headers
    15  
    16  // crc32c {{{
    17    inline u32
    18  kv_crc32c(const void * const ptr, u32 len)
    19  {
    20    return crc32c_inc((const u8 *)ptr, len, KV_CRC32C_SEED);
    21  }
    22  
    23    inline u64
    24  kv_crc32c_extend(const u32 lo)
    25  {
    26    const u64 hi = (u64)(~lo);
    27    return (hi << 32) | ((u64)lo);
    28  }
    29  // }}} crc32c
    30  
    31  // kv {{{
    32  
    33  // size {{{
    34    inline size_t
    35  kv_size(const struct kv * const kv)
    36  {
    37    return sizeof(*kv) + kv->klen + kv->vlen;
    38  }
    39  
    40    inline size_t
    41  kv_size_align(const struct kv * const kv, const u64 align)
    42  {
    43    debug_assert(align && ((align & (align - 1)) == 0));
    44    return (sizeof(*kv) + kv->klen + kv->vlen + (align - 1)) & (~(align - 1));
    45  }
    46  
    47    inline size_t
    48  key_size(const struct kv *const key)
    49  {
    50    return sizeof(*key) + key->klen;
    51  }
    52  
    53    inline size_t
    54  key_size_align(const struct kv *const key, const u64 align)
    55  {
    56    debug_assert(align && ((align & (align - 1)) == 0));
    57    return (sizeof(*key) + key->klen + (align - 1)) & (~(align - 1));
    58  }
    59  // }}} size
    60  
    61  // construct {{{
    62    inline void
    63  kv_update_hash(struct kv * const kv)
    64  {
    65    const u32 lo = kv_crc32c((const void *)kv->kv, kv->klen);
    66    kv->hash = kv_crc32c_extend(lo);
    67  }
    68  
    69    inline void
    70  kv_refill_value(struct kv * const kv, const void * const value, const u32 vlen)
    71  {
    72    debug_assert((vlen == 0) || value);
    73    memcpy(&(kv->kv[kv->klen]), value, vlen);
    74    kv->vlen = vlen;
    75  }
    76  
    77    inline void
    78  kv_refill(struct kv * const kv, const void * const key, const u32 klen,
    79      const void * const value, const u32 vlen)
    80  {
    81    debug_assert(kv);
    82    kv->klen = klen;
    83    memcpy(&(kv->kv[0]), key, klen);
    84    kv_refill_value(kv, value, vlen);
    85    kv_update_hash(kv);
    86  }
    87  
    88    inline void
    89  kv_refill_str(struct kv * const kv, const char * const key,
    90      const void * const value, const u32 vlen)
    91  {
    92    kv_refill(kv, key, (u32)strlen(key), value, vlen);
    93  }
    94  
    95    inline void
    96  kv_refill_str_str(struct kv * const kv, const char * const key,
    97      const char * const value)
    98  {
    99    kv_refill(kv, key, (u32)strlen(key), value, (u32)strlen(value));
   100  }
   101  
   102  // the u64 key is filled in big-endian byte order for correct ordering
   103    inline void
   104  kv_refill_u64(struct kv * const kv, const u64 key, const void * const value, const u32 vlen)
   105  {
   106    kv->klen = sizeof(u64);
   107    *(u64 *)(kv->kv) = __builtin_bswap64(key); // bswap on little endian
   108    kv_refill_value(kv, value, vlen);
   109    kv_update_hash(kv);
   110  }
   111  
   112    inline void
   113  kv_refill_hex32(struct kv * const kv, const u32 hex, const void * const value, const u32 vlen)
   114  {
   115    kv->klen = 8;
   116    strhex_32(kv->kv, hex);
   117    kv_refill_value(kv, value, vlen);
   118    kv_update_hash(kv);
   119  }
   120  
   121    inline void
   122  kv_refill_hex64(struct kv * const kv, const u64 hex, const void * const value, const u32 vlen)
   123  {
   124    kv->klen = 16;
   125    strhex_64(kv->kv, hex);
   126    kv_refill_value(kv, value, vlen);
   127    kv_update_hash(kv);
   128  }
   129  
   130    inline void
   131  kv_refill_hex64_klen(struct kv * const kv, const u64 hex,
   132      const u32 klen, const void * const value, const u32 vlen)
   133  {
   134    strhex_64(kv->kv, hex);
   135    if (klen > 16) {
   136      kv->klen = klen;
   137      memset(kv->kv + 16, '!', klen - 16);
   138    } else {
   139      kv->klen = 16;
   140    }
   141    kv_refill_value(kv, value, vlen);
   142    kv_update_hash(kv);
   143  }
   144  
   145    inline void
   146  kv_refill_kref(struct kv * const kv, const struct kref * const kref)
   147  {
   148    kv->klen = kref->len;
   149    kv->vlen = 0;
   150    kv->hash = kv_crc32c_extend(kref->hash32);
   151    memmove(kv->kv, kref->ptr, kref->len);
   152  }
   153  
   154    inline void
   155  kv_refill_kref_v(struct kv * const kv, const struct kref * const kref,
   156      const void * const value, const u32 vlen)
   157  {
   158    kv->klen = kref->len;
   159    kv->vlen = vlen;
   160    kv->hash = kv_crc32c_extend(kref->hash32);
   161    memmove(kv->kv, kref->ptr, kref->len);
   162    memcpy(kv->kv + kv->klen, value, vlen);
   163  }
   164  
   165    inline struct kref
   166  kv_kref(const struct kv * const key)
   167  {
   168    return (struct kref){.ptr = key->kv, .len = key->klen, .hash32 = key->hashlo};
   169  }
   170  
   171    inline struct kv *
   172  kv_create(const void * const key, const u32 klen, const void * const value, const u32 vlen)
   173  {
   174    struct kv * const kv = malloc(sizeof(*kv) + klen + vlen);
   175    if (kv)
   176      kv_refill(kv, key, klen, value, vlen);
   177    return kv;
   178  }
   179  
   180    inline struct kv *
   181  kv_create_str(const char * const key, const void * const value, const u32 vlen)
   182  {
   183    return kv_create(key, (u32)strlen(key), value, vlen);
   184  }
   185  
   186    inline struct kv *
   187  kv_create_str_str(const char * const key, const char * const value)
   188  {
   189    return kv_create(key, (u32)strlen(key), value, (u32)strlen(value));
   190  }
   191  
   192    inline struct kv *
   193  kv_create_kref(const struct kref * const kref, const void * const value, const u32 vlen)
   194  {
   195    return kv_create(kref->ptr, kref->len, value, vlen);
   196  }
   197  
   198  static struct kv __kv_null = {};
   199  
   200  __attribute__((constructor))
   201    static void
   202  kv_null_init(void)
   203  {
   204    kv_update_hash(&__kv_null);
   205  }
   206  
   207    inline const struct kv *
   208  kv_null(void)
   209  {
   210    return &__kv_null;
   211  }
   212  // }}} construct
   213  
   214  // dup {{{
   215    inline struct kv *
   216  kv_dup(const struct kv * const kv)
   217  {
   218    if (kv == NULL)
   219      return NULL;
   220  
   221    const size_t sz = kv_size(kv);
   222    struct kv * const new = malloc(sz);
   223    if (new)
   224      memcpy(new, kv, sz);
   225    return new;
   226  }
   227  
   228    inline struct kv *
   229  kv_dup_key(const struct kv * const kv)
   230  {
   231    if (kv == NULL)
   232      return NULL;
   233  
   234    const size_t sz = key_size(kv);
   235    struct kv * const new = malloc(sz);
   236    if (new) {
   237      memcpy(new, kv, sz);
   238      new->vlen = 0;
   239    }
   240    return new;
   241  }
   242  
   243    inline struct kv *
   244  kv_dup2(const struct kv * const from, struct kv * const to)
   245  {
   246    if (from == NULL)
   247      return NULL;
   248    const size_t sz = kv_size(from);
   249    struct kv * const new = to ? to : malloc(sz);
   250    if (new)
   251      memcpy(new, from, sz);
   252    return new;
   253  }
   254  
   255    inline struct kv *
   256  kv_dup2_key(const struct kv * const from, struct kv * const to)
   257  {
   258    if (from == NULL)
   259      return NULL;
   260    const size_t sz = key_size(from);
   261    struct kv * const new = to ? to : malloc(sz);
   262    if (new) {
   263      memcpy(new, from, sz);
   264      new->vlen = 0;
   265    }
   266    return new;
   267  }
   268  
   269    inline struct kv *
   270  kv_dup2_key_prefix(const struct kv * const from, struct kv * const to, const u32 plen)
   271  {
   272    if (from == NULL)
   273      return NULL;
   274    debug_assert(plen <= from->klen);
   275    const size_t sz = key_size(from) - from->klen + plen;
   276    struct kv * const new = to ? to : malloc(sz);
   277    if (new) {
   278      new->klen = plen;
   279      memcpy(new->kv, from->kv, plen);
   280      new->vlen = 0;
   281      kv_update_hash(new);
   282    }
   283    return new;
   284  }
   285  // }}} dup
   286  
   287  // compare {{{
   288    static inline int
   289  klen_compare(const u32 len1, const u32 len2)
   290  {
   291    if (len1 < len2)
   292      return -1;
   293    else if (len1 > len2)
   294      return 1;
   295    else
   296      return 0;
   297  }
   298  
   299  // compare whether the two keys are identical
   300  // optimistic: do not check hash
   301    inline bool
   302  kv_match(const struct kv * const key1, const struct kv * const key2)
   303  {
   304    //cpu_prefetch0(((u8 *)key2) + 64);
   305    //return (key1->hash == key2->hash)
   306    //  && (key1->klen == key2->klen)
   307    //  && (!memcmp(key1->kv, key2->kv, key1->klen));
   308    return (key1->klen == key2->klen) && (!memcmp(key1->kv, key2->kv, key1->klen));
   309  }
   310  
   311  // compare whether the two keys are identical
   312  // check hash first
   313  // pessimistic: return false quickly if their hashes mismatch
   314    inline bool
   315  kv_match_hash(const struct kv * const key1, const struct kv * const key2)
   316  {
   317    return (key1->hash == key2->hash)
   318      && (key1->klen == key2->klen)
   319      && (!memcmp(key1->kv, key2->kv, key1->klen));
   320  }
   321  
   322    inline bool
   323  kv_match_full(const struct kv * const kv1, const struct kv * const kv2)
   324  {
   325    return (kv1->kvlen == kv2->kvlen)
   326      && (!memcmp(kv1, kv2, sizeof(*kv1) + kv1->klen + kv1->vlen));
   327  }
   328  
   329    bool
   330  kv_match_kv128(const struct kv * const sk, const u8 * const kv128)
   331  {
   332    debug_assert(sk);
   333    debug_assert(kv128);
   334  
   335    u32 klen128 = 0;
   336    u32 vlen128 = 0;
   337    const u8 * const pdata = vi128_decode_u32(vi128_decode_u32(kv128, &klen128), &vlen128);
   338    (void)vlen128;
   339    return (sk->klen == klen128) && (!memcmp(sk->kv, pdata, klen128));
   340  }
   341  
   342    inline int
   343  kv_compare(const struct kv * const kv1, const struct kv * const kv2)
   344  {
   345    const u32 len = kv1->klen < kv2->klen ? kv1->klen : kv2->klen;
   346    const int cmp = memcmp(kv1->kv, kv2->kv, (size_t)len);
   347    return cmp ? cmp : klen_compare(kv1->klen, kv2->klen);
   348  }
   349  
   350  // for qsort and bsearch
   351    static int
   352  kv_compare_ptrs(const void * const p1, const void * const p2)
   353  {
   354    const struct kv * const * const pp1 = (typeof(pp1))p1;
   355    const struct kv * const * const pp2 = (typeof(pp2))p2;
   356    return kv_compare(*pp1, *pp2);
   357  }
   358  
   359    int
   360  kv_k128_compare(const struct kv * const sk, const u8 * const k128)
   361  {
   362    debug_assert(sk);
   363    const u32 klen1 = sk->klen;
   364    u32 klen2 = 0;
   365    const u8 * const ptr2 = vi128_decode_u32(k128, &klen2);
   366    debug_assert(ptr2);
   367    const u32 len = (klen1 < klen2) ? klen1 : klen2;
   368    const int cmp = memcmp(sk->kv, ptr2, len);
   369    return cmp ? cmp : klen_compare(klen1, klen2);
   370  }
   371  
   372    int
   373  kv_kv128_compare(const struct kv * const sk, const u8 * const kv128)
   374  {
   375    debug_assert(sk);
   376    const u32 klen1 = sk->klen;
   377    u32 klen2 = 0;
   378    u32 vlen2 = 0;
   379    const u8 * const ptr2 = vi128_decode_u32(vi128_decode_u32(kv128, &klen2), &vlen2);
   380    const u32 len = (klen1 < klen2) ? klen1 : klen2;
   381    const int cmp = memcmp(sk->kv, ptr2, len);
   382    return cmp ? cmp : klen_compare(klen1, klen2);
   383  }
   384  
   385    inline void
   386  kv_qsort(struct kv ** const kvs, const size_t nr)
   387  {
   388    qsort(kvs, nr, sizeof(kvs[0]), kv_compare_ptrs);
   389  }
   390  
   391  // return the length of longest common prefix of the two keys
   392    inline u32
   393  kv_key_lcp(const struct kv * const key1, const struct kv * const key2)
   394  {
   395    const u32 max = (key1->klen < key2->klen) ? key1->klen : key2->klen;
   396    return memlcp(key1->kv, key2->kv, max);
   397  }
   398  
   399  // return the length of longest common prefix of the two keys with a known lcp0
   400    inline u32
   401  kv_key_lcp_skip(const struct kv * const key1, const struct kv * const key2, const u32 lcp0)
   402  {
   403    const u32 max = (key1->klen < key2->klen) ? key1->klen : key2->klen;
   404    debug_assert(max >= lcp0);
   405    return lcp0 + memlcp(key1->kv+lcp0, key2->kv+lcp0, max-lcp0);
   406  }
   407  // }}}
   408  
   409  // psort {{{
   410    static inline void
   411  kv_psort_exchange(struct kv ** const kvs, const u64 i, const u64 j)
   412  {
   413    if (i != j) {
   414      struct kv * const tmp = kvs[i];
   415      kvs[i] = kvs[j];
   416      kvs[j] = tmp;
   417    }
   418  }
   419  
   420    static u64
   421  kv_psort_partition(struct kv ** const kvs, const u64 lo, const u64 hi)
   422  {
   423    if (lo >= hi)
   424      return lo;
   425  
   426    const u64 p = (lo+hi) >> 1;
   427    kv_psort_exchange(kvs, lo, p);
   428    u64 i = lo;
   429    u64 j = hi + 1;
   430    do {
   431      while (kv_compare(kvs[++i], kvs[lo]) < 0 && i < hi);
   432      while (kv_compare(kvs[--j], kvs[lo]) > 0);
   433      if (i >= j)
   434        break;
   435      kv_psort_exchange(kvs, i, j);
   436    } while (true);
   437    kv_psort_exchange(kvs, lo, j);
   438    return j;
   439  }
   440  
   441    static void
   442  kv_psort_rec(struct kv ** const kvs, const u64 lo, const u64 hi, const u64 tlo, const u64 thi)
   443  {
   444    if (lo >= hi)
   445      return;
   446    const u64 c = kv_psort_partition(kvs, lo, hi);
   447  
   448    if (c > tlo) // go left
   449      kv_psort_rec(kvs, lo, c-1, tlo, thi);
   450  
   451    if (c < thi) // go right
   452      kv_psort_rec(kvs, c+1, hi, tlo, thi);
   453  }
   454  
   455    inline void
   456  kv_psort(struct kv ** const kvs, const u64 nr, const u64 tlo, const u64 thi)
   457  {
   458    debug_assert(tlo <= thi);
   459    debug_assert(thi < nr);
   460    kv_psort_rec(kvs, 0, nr-1, tlo, thi);
   461  }
   462  // }}} psort
   463  
   464  // ptr {{{
   465    inline void *
   466  kv_vptr(struct kv * const kv)
   467  {
   468    return (void *)(&(kv->kv[kv->klen]));
   469  }
   470  
   471    inline void *
   472  kv_kptr(struct kv * const kv)
   473  {
   474    return (void *)(&(kv->kv[0]));
   475  }
   476  
   477    inline const void *
   478  kv_vptr_c(const struct kv * const kv)
   479  {
   480    return (const void *)(&(kv->kv[kv->klen]));
   481  }
   482  
   483    inline const void *
   484  kv_kptr_c(const struct kv * const kv)
   485  {
   486    return (const void *)(&(kv->kv[0]));
   487  }
   488  // }}} ptr
   489  
   490  // print {{{
   491  // cmd "KV" K and V can be 's': string, 'x': hex, 'd': dec, or else for not printing.
   492  // n for newline after kv
   493    void
   494  kv_print(const struct kv * const kv, const char * const cmd, FILE * const out)
   495  {
   496    debug_assert(cmd);
   497    const u32 klen = kv->klen;
   498    fprintf(out, "#%016lx k[%3u]", kv->hash, klen);
   499  
   500    switch(cmd[0]) {
   501    case 's': fprintf(out, " %.*s", klen, kv->kv); break;
   502    case 'x': str_print_hex(out, kv->kv, klen); break;
   503    case 'd': str_print_dec(out, kv->kv, klen); break;
   504    default: break;
   505    }
   506  
   507    const u32 vlen = kv->vlen;
   508    switch (cmd[1]) {
   509    case 's': fprintf(out, "  v[%4u] %.*s", vlen, vlen, kv->kv+klen); break;
   510    case 'x': fprintf(out, "  v[%4u]", vlen); str_print_hex(out, kv->kv+klen, vlen); break;
   511    case 'd': fprintf(out, "  v[%4u]", vlen); str_print_dec(out, kv->kv+klen, vlen); break;
   512    default: break;
   513    }
   514    if (strchr(cmd, 'n'))
   515      fprintf(out, "\n");
   516  }
   517  // }}} print
   518  
   519  // mm {{{
   520    struct kv *
   521  kvmap_mm_in_noop(struct kv * const kv, void * const priv)
   522  {
   523    (void)priv;
   524    return kv;
   525  }
   526  
   527  // copy-out
   528    struct kv *
   529  kvmap_mm_out_noop(struct kv * const kv, struct kv * const out)
   530  {
   531    (void)out;
   532    return kv;
   533  }
   534  
   535    void
   536  kvmap_mm_free_noop(struct kv * const kv, void * const priv)
   537  {
   538    (void)kv;
   539    (void)priv;
   540  }
   541  
   542  // copy-in
   543    struct kv *
   544  kvmap_mm_in_dup(struct kv * const kv, void * const priv)
   545  {
   546    (void)priv;
   547    return kv_dup(kv);
   548  }
   549  
   550  // copy-out
   551    struct kv *
   552  kvmap_mm_out_dup(struct kv * const kv, struct kv * const out)
   553  {
   554    return kv_dup2(kv, out);
   555  }
   556  
   557    void
   558  kvmap_mm_free_free(struct kv * const kv, void * const priv)
   559  {
   560    (void)priv;
   561    free(kv);
   562  }
   563  
   564  const struct kvmap_mm kvmap_mm_dup = {
   565    .in = kvmap_mm_in_dup,
   566    .out = kvmap_mm_out_dup,
   567    .free = kvmap_mm_free_free,
   568    .priv = NULL,
   569  };
   570  
   571  const struct kvmap_mm kvmap_mm_ndf = {
   572    .in = kvmap_mm_in_noop,
   573    .out = kvmap_mm_out_dup,
   574    .free = kvmap_mm_free_free,
   575    .priv = NULL,
   576  };
   577  
   578  // }}} mm
   579  
   580  // kref {{{
   581    inline void
   582  kref_ref_raw(struct kref * const kref, const u8 * const ptr, const u32 len)
   583  {
   584    kref->ptr = ptr;
   585    kref->len = len;
   586    kref->hash32 = 0;
   587  }
   588  
   589    inline void
   590  kref_ref_hash32(struct kref * const kref, const u8 * const ptr, const u32 len)
   591  {
   592    kref->ptr = ptr;
   593    kref->len = len;
   594    kref->hash32 = kv_crc32c(ptr, len);
   595  }
   596  
   597    inline void
   598  kref_update_hash32(struct kref * const kref)
   599  {
   600    kref->hash32 = kv_crc32c(kref->ptr, kref->len);
   601  }
   602  
   603    inline void
   604  kref_ref_kv(struct kref * const kref, const struct kv * const kv)
   605  {
   606    kref->ptr = kv->kv;
   607    kref->len = kv->klen;
   608    kref->hash32 = kv->hashlo;
   609  }
   610  
   611    inline void
   612  kref_ref_kv_hash32(struct kref * const kref, const struct kv * const kv)
   613  {
   614    kref->ptr = kv->kv;
   615    kref->len = kv->klen;
   616    kref->hash32 = kv_crc32c(kv->kv, kv->klen);
   617  }
   618  
   619    inline bool
   620  kref_match(const struct kref * const k1, const struct kref * const k2)
   621  {
   622    return (k1->len == k2->len) && (!memcmp(k1->ptr, k2->ptr, k1->len));
   623  }
   624  
   625  // match a kref and a key
   626    inline bool
   627  kref_kv_match(const struct kref * const kref, const struct kv * const k)
   628  {
   629    return (kref->len == k->klen) && (!memcmp(kref->ptr, k->kv, kref->len));
   630  }
   631  
   632    inline int
   633  kref_compare(const struct kref * const kref1, const struct kref * const kref2)
   634  {
   635    const u32 len = kref1->len < kref2->len ? kref1->len : kref2->len;
   636    const int cmp = memcmp(kref1->ptr, kref2->ptr, (size_t)len);
   637    return cmp ? cmp : klen_compare(kref1->len, kref2->len);
   638  }
   639  
   640  // compare a kref and a key
   641    inline int
   642  kref_kv_compare(const struct kref * const kref, const struct kv * const k)
   643  {
   644    debug_assert(kref);
   645    debug_assert(k);
   646    const u32 len = kref->len < k->klen ? kref->len : k->klen;
   647    const int cmp = memcmp(kref->ptr, k->kv, (size_t)len);
   648    return cmp ? cmp : klen_compare(kref->len, k->klen);
   649  }
   650  
   651    inline u32
   652  kref_lcp(const struct kref * const k1, const struct kref * const k2)
   653  {
   654    const u32 max = (k1->len < k2->len) ? k1->len : k2->len;
   655    return memlcp(k1->ptr, k2->ptr, max);
   656  }
   657  
   658    inline u32
   659  kref_kv_lcp(const struct kref * const kref, const struct kv * const kv)
   660  {
   661    const u32 max = (kref->len < kv->klen) ? kref->len : kv->klen;
   662    return memlcp(kref->ptr, kv->kv, max);
   663  }
   664  
   665  // klen, key, ...
   666    inline int
   667  kref_k128_compare(const struct kref * const sk, const u8 * const k128)
   668  {
   669    debug_assert(sk);
   670    const u32 klen1 = sk->len;
   671    u32 klen2 = 0;
   672    const u8 * const ptr2 = vi128_decode_u32(k128, &klen2);
   673    debug_assert(ptr2);
   674    const u32 len = (klen1 < klen2) ? klen1 : klen2;
   675    const int cmp = memcmp(sk->ptr, ptr2, len);
   676    return cmp ? cmp : klen_compare(klen1, klen2);
   677  }
   678  
   679  // klen, vlen, key, ...
   680    inline int
   681  kref_kv128_compare(const struct kref * const sk, const u8 * const kv128)
   682  {
   683    debug_assert(sk);
   684    const u32 klen1 = sk->len;
   685    u32 klen2 = 0;
   686    u32 vlen2 = 0;
   687    const u8 * const ptr2 = vi128_decode_u32(vi128_decode_u32(kv128, &klen2), &vlen2);
   688    const u32 len = (klen1 < klen2) ? klen1 : klen2;
   689    const int cmp = memcmp(sk->ptr, ptr2, len);
   690    return cmp ? cmp : klen_compare(klen1, klen2);
   691  }
   692  
   693  static struct kref __kref_null = {.hash32 = KV_CRC32C_SEED};
   694  
   695    inline const struct kref *
   696  kref_null(void)
   697  {
   698    return &__kref_null;
   699  }
   700  // }}} kref
   701  
   702  // kvref {{{
   703    inline void
   704  kvref_ref_kv(struct kvref * const ref, struct kv * const kv)
   705  {
   706    ref->kptr = kv->kv;
   707    ref->vptr = kv->kv + kv->klen;
   708    ref->hdr = *kv;
   709  }
   710  
   711    struct kv *
   712  kvref_dup2_kv(struct kvref * const ref, struct kv * const to)
   713  {
   714    if (ref == NULL)
   715      return NULL;
   716    const size_t sz = sizeof(*to) + ref->hdr.klen + ref->hdr.vlen;
   717    struct kv * const new = to ? to : malloc(sz);
   718    if (new == NULL)
   719      return NULL;
   720  
   721    *new = ref->hdr;
   722    memcpy(new->kv, ref->kptr, new->klen);
   723    memcpy(new->kv + new->klen, ref->vptr, new->vlen);
   724    return new;
   725  }
   726  
   727    struct kv *
   728  kvref_dup2_key(struct kvref * const ref, struct kv * const to)
   729  {
   730    if (ref == NULL)
   731      return NULL;
   732    const size_t sz = sizeof(*to) + ref->hdr.klen;
   733    struct kv * const new = to ? to : malloc(sz);
   734    if (new == NULL)
   735      return NULL;
   736  
   737    *new = ref->hdr;
   738    memcpy(new->kv, ref->kptr, new->klen);
   739    return new;
   740  }
   741  
   742    int
   743  kvref_kv_compare(const struct kvref * const ref, const struct kv * const kv)
   744  {
   745    const u32 len = ref->hdr.klen < kv->klen ? ref->hdr.klen : kv->klen;
   746    const int cmp = memcmp(ref->kptr, kv->kv, (size_t)len);
   747    return cmp ? cmp : klen_compare(ref->hdr.klen, kv->klen);
   748  }
   749  // }}} kvref
   750  
   751  // kv128 {{{
   752  // estimate the encoded size
   753    inline size_t
   754  kv128_estimate_kv(const struct kv * const kv)
   755  {
   756    return vi128_estimate_u32(kv->klen) + vi128_estimate_u32(kv->vlen) + kv->klen + kv->vlen;
   757  }
   758  
   759  // create a kv128 from kv
   760    u8 *
   761  kv128_encode_kv(const struct kv * const kv, u8 * const out, size_t * const pesize)
   762  {
   763    u8 * const ptr = out ? out : malloc(kv128_estimate_kv(kv));
   764    if (!ptr)
   765      return NULL;
   766  
   767    u8 * const pdata = vi128_encode_u32(vi128_encode_u32(ptr, kv->klen), kv->vlen);
   768    memcpy(pdata, kv->kv, kv->klen + kv->vlen);
   769  
   770    if (pesize)
   771      *pesize = (size_t)(pdata - ptr) + kv->klen + kv->vlen;
   772    return ptr; // return the head of the encoded kv128
   773  }
   774  
   775  // dup kv128 to a kv
   776    struct kv *
   777  kv128_decode_kv(const u8 * const ptr, struct kv * const out, size_t * const pesize)
   778  {
   779    u32 klen, vlen;
   780    const u8 * const pdata = vi128_decode_u32(vi128_decode_u32(ptr, &klen), &vlen);
   781    struct kv * const ret = out ? out : malloc(sizeof(struct kv) + klen + vlen);
   782    if (ret)
   783      kv_refill(ret, pdata, klen, pdata + klen, vlen);
   784  
   785    if (pesize)
   786      *pesize = (size_t)(pdata - ptr) + klen + vlen;
   787    return ret; // return the kv
   788  }
   789  
   790    inline size_t
   791  kv128_size(const u8 * const ptr)
   792  {
   793    u32 klen, vlen;
   794    const u8 * const pdata = vi128_decode_u32(vi128_decode_u32(ptr, &klen), &vlen);
   795    return ((size_t)(pdata - ptr)) + klen + vlen;
   796  }
   797  // }}} kv128
   798  
   799  // }}} kv
   800  
   801  // kvmap {{{
   802  
   803  // registry {{{
   804  // increase MAX if need more
   805  #define KVMAP_API_MAX ((32))
   806  static struct kvmap_api_reg kvmap_api_regs[KVMAP_API_MAX];
   807  static u64 kvmap_api_regs_nr = 0;
   808  
   809    void
   810  kvmap_api_register(const int nargs, const char * const name, const char * const args_msg,
   811      void * (*create)(const char *, const struct kvmap_mm *, char **), const struct kvmap_api * const api)
   812  {
   813    if (kvmap_api_regs_nr < KVMAP_API_MAX) {
   814      kvmap_api_regs[kvmap_api_regs_nr].nargs = nargs;
   815      kvmap_api_regs[kvmap_api_regs_nr].name = name;
   816      kvmap_api_regs[kvmap_api_regs_nr].args_msg = args_msg;
   817      kvmap_api_regs[kvmap_api_regs_nr].create = create;
   818      kvmap_api_regs[kvmap_api_regs_nr].api = api;
   819      kvmap_api_regs_nr++;
   820    } else {
   821      fprintf(stderr, "%s failed to register [%s]\n", __func__, name);
   822    }
   823  }
   824    void
   825  kvmap_api_helper_message(void)
   826  {
   827    fprintf(stderr, "%s Usage: api <map-type> <param1> ...\n", __func__);
   828    for (u64 i = 0; i < kvmap_api_regs_nr; i++) {
   829      fprintf(stderr, "%s example: api %s %s\n", __func__,
   830          kvmap_api_regs[i].name, kvmap_api_regs[i].args_msg);
   831    }
   832  }
   833  
   834    int
   835  kvmap_api_helper(int argc, char ** const argv, const struct kvmap_mm * const mm,
   836      const struct kvmap_api ** const api_out, void ** const map_out)
   837  {
   838    // "api" "name" "arg1", ...
   839    if (argc < 2 || strcmp(argv[0], "api") != 0)
   840      return -1;
   841  
   842    for (u64 i = 0; i < kvmap_api_regs_nr; i++) {
   843      const struct kvmap_api_reg * const reg = &kvmap_api_regs[i];
   844      if (0 != strcmp(argv[1], reg->name))
   845        continue;
   846  
   847      if ((argc - 2) < reg->nargs)
   848        return -1;
   849  
   850      void * const map = reg->create(argv[1], mm, argv + 2); // skip "api" "name"
   851      if (map) {
   852        *api_out = reg->api;
   853        *map_out = map;
   854        return 2 + reg->nargs;
   855      } else {
   856        return -1;
   857      }
   858    }
   859  
   860    // no match
   861    return -1;
   862  }
   863  // }}} registry
   864  
   865  // misc {{{
   866    void
   867  kvmap_inp_steal_kv(struct kv * const kv, void * const priv)
   868  {
   869    // steal the kv pointer out so we don't need a dangerous get_key_interanl()
   870    if (priv)
   871      *(struct kv **)priv = kv;
   872  }
   873  
   874    inline void *
   875  kvmap_ref(const struct kvmap_api * const api, void * const map)
   876  {
   877    return api->ref ? api->ref(map) : map;
   878  }
   879  
   880  // return the original map pointer; usually unused by caller
   881    inline void *
   882  kvmap_unref(const struct kvmap_api * const api, void * const ref)
   883  {
   884    return api->unref ? api->unref(ref) : ref;
   885  }
   886  // }}} misc
   887  
   888  // kvmap_kv_op {{{
   889    inline struct kv *
   890  kvmap_kv_get(const struct kvmap_api * const api, void * const ref,
   891      const struct kv * const key, struct kv * const out)
   892  {
   893    const struct kref kref = kv_kref(key);
   894    return api->get(ref, &kref, out);
   895  }
   896  
   897    inline bool
   898  kvmap_kv_probe(const struct kvmap_api * const api, void * const ref,
   899      const struct kv * const key)
   900  {
   901    const struct kref kref = kv_kref(key);
   902    return api->probe(ref, &kref);
   903  }
   904  
   905    inline bool
   906  kvmap_kv_put(const struct kvmap_api * const api, void * const ref,
   907      struct kv * const kv)
   908  {
   909    return api->put(ref, kv);
   910  }
   911  
   912    inline bool
   913  kvmap_kv_del(const struct kvmap_api * const api, void * const ref,
   914      const struct kv * const key)
   915  {
   916    const struct kref kref = kv_kref(key);
   917    return api->del(ref, &kref);
   918  }
   919  
   920    inline bool
   921  kvmap_kv_inpr(const struct kvmap_api * const api, void * const ref,
   922      const struct kv * const key, kv_inp_func uf, void * const priv)
   923  {
   924    const struct kref kref = kv_kref(key);
   925    return api->inpr(ref, &kref, uf, priv);
   926  }
   927  
   928    inline bool
   929  kvmap_kv_inpw(const struct kvmap_api * const api, void * const ref,
   930      const struct kv * const key, kv_inp_func uf, void * const priv)
   931  {
   932    const struct kref kref = kv_kref(key);
   933    return api->inpw(ref, &kref, uf, priv);
   934  }
   935  
   936    inline bool
   937  kvmap_kv_merge(const struct kvmap_api * const api, void * const ref,
   938      const struct kv * const key, kv_merge_func uf, void * const priv)
   939  {
   940    const struct kref kref = kv_kref(key);
   941    return api->merge(ref, &kref, uf, priv);
   942  }
   943  
   944    inline u64
   945  kvmap_kv_delr(const struct kvmap_api * const api, void * const ref,
   946      const struct kv * const start, const struct kv * const end)
   947  {
   948    const struct kref kref0 = kv_kref(start);
   949    if (end) {
   950      const struct kref krefz = kv_kref(end);
   951      return api->delr(ref, &kref0, &krefz);
   952    } else {
   953      return api->delr(ref, &kref0, NULL);
   954    }
   955  }
   956  
   957    inline void
   958  kvmap_kv_iter_seek(const struct kvmap_api * const api, void * const iter,
   959      const struct kv * const key)
   960  {
   961    const struct kref kref = kv_kref(key);
   962    api->iter_seek(iter, &kref);
   963  }
   964  // }}} kvmap_kv_op
   965  
   966  // kvmap_raw_op {{{
   967    inline struct kv *
   968  kvmap_raw_get(const struct kvmap_api * const api, void * const ref,
   969      const u32 len, const u8 * const ptr, struct kv * const out)
   970  {
   971    const struct kref kref = {.ptr = ptr, .len = len,
   972      .hash32 = api->hashkey ? kv_crc32c(ptr, len) : 0};
   973    return api->get(ref, &kref, out);
   974  }
   975  
   976    inline bool
   977  kvmap_raw_probe(const struct kvmap_api * const api, void * const ref,
   978      const u32 len, const u8 * const ptr)
   979  {
   980    const struct kref kref = {.ptr = ptr, .len = len,
   981      .hash32 = api->hashkey ? kv_crc32c(ptr, len) : 0};
   982    return api->probe(ref, &kref);
   983  }
   984  
   985    inline bool
   986  kvmap_raw_del(const struct kvmap_api * const api, void * const ref,
   987      const u32 len, const u8 * const ptr)
   988  {
   989    const struct kref kref = {.ptr = ptr, .len = len,
   990      .hash32 = api->hashkey ? kv_crc32c(ptr, len) : 0};
   991    return api->del(ref, &kref);
   992  }
   993  
   994    inline bool
   995  kvmap_raw_inpr(const struct kvmap_api * const api, void * const ref,
   996      const u32 len, const u8 * const ptr, kv_inp_func uf, void * const priv)
   997  {
   998    const struct kref kref = {.ptr = ptr, .len = len,
   999      .hash32 = api->hashkey ? kv_crc32c(ptr, len) : 0};
  1000    return api->inpr(ref, &kref, uf, priv);
  1001  }
  1002  
  1003    inline bool
  1004  kvmap_raw_inpw(const struct kvmap_api * const api, void * const ref,
  1005      const u32 len, const u8 * const ptr, kv_inp_func uf, void * const priv)
  1006  {
  1007    const struct kref kref = {.ptr = ptr, .len = len,
  1008      .hash32 = api->hashkey ? kv_crc32c(ptr, len) : 0};
  1009    return api->inpw(ref, &kref, uf, priv);
  1010  }
  1011  
  1012    inline void
  1013  kvmap_raw_iter_seek(const struct kvmap_api * const api, void * const iter,
  1014      const u32 len, const u8 * const ptr)
  1015  {
  1016    const struct kref kref = {.ptr = ptr, .len = len,
  1017      .hash32 = api->hashkey ? kv_crc32c(ptr, len) : 0};
  1018    api->iter_seek(iter, &kref);
  1019  }
  1020  // }}}} kvmap_raw_op
  1021  
  1022  // dump {{{
  1023    u64
  1024  kvmap_dump_keys(const struct kvmap_api * const api, void * const map, const int fd)
  1025  {
  1026    void * const ref = kvmap_ref(api, map);
  1027    void * const iter = api->iter_create(ref);
  1028    api->iter_seek(iter, kref_null());
  1029    u64 i = 0;
  1030    while (api->iter_valid(iter)) {
  1031      struct kvref kvref;
  1032      api->iter_kvref(iter, &kvref);
  1033      dprintf(fd, "%010lu [%3u] %.*s [%u]\n", i, kvref.hdr.klen, kvref.hdr.klen, kvref.kptr, kvref.hdr.vlen);
  1034      i++;
  1035      api->iter_skip1(iter);
  1036    }
  1037    api->iter_destroy(iter);
  1038    kvmap_unref(api, ref);
  1039    return i;
  1040  }
  1041  // }}} dump
  1042  
  1043  // }}} kvmap
  1044  
  1045  // vim:fdm=marker