summaryrefslogtreecommitdiff
path: root/src/config/repo.c
blob: bf847f1da4d9654a4f3970d72d79b087461f901e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/* ISC license. */

#include <stdint.h>
#include <string.h>

#include <skalibs/diuint32.h>
#include <skalibs/stralloc.h>
#include <skalibs/genalloc.h>
#include <skalibs/avltree.h>
#include <skalibs/cdbmake.h>

#include "shibari-cache-config-internal.h"

static void *node_dtok (uint32_t d, void *aux)
{
  repo *rp = aux ;
  return &genalloc_s(node, &rp->list)[d].key ;
}

static int node_cmp (void const *a, void const *b, void *aux)
{
  repo *rp = aux ;
  diuint32 const *ka = a ;
  diuint32 const *kb = b ;
  if (ka->right < kb->right) return -1 ;
  if (ka->right > kb->right) return 1 ;
  return memcmp(rp->storage.s + ka->left, rp->storage.s + kb->left, ka->right) ;
}

void repo_init (repo *rp)
{
  avltree_init(&rp->tree, 32, 3, 8, &node_dtok, &node_cmp, rp) ;
}

node *repo_search (repo *rp, char const *key, uint32_t keylen)
{
  diuint32 ukey = { .left = rp->storage.len, .right = keylen } ;
  uint32_t i ;
  if (!stralloc_catb(&rp->storage, key, keylen)) dienomem() ;
  rp->storage.len = ukey.left ;
  return avltree_search(&rp->tree, &ukey, &i) ? genalloc_s(node, &rp->list) + i : 0 ;
}

static int checkunique (memcmp_func_ref f, char const *ar, size_t arlen, char const *ele, size_t elelen)
{
  while (arlen >= elelen)
  {
    if (!(*f)(ar, ele, elelen)) return 0 ;
    ar += elelen ;
    arlen -= elelen ;
  }
  return 1 ;
}

void repo_add_new (repo *rp, char const *key, uint32_t keylen, char const *data, size_t datalen, uint32_t line, int accu)
{
  node *nod ;
  uint32_t n = genalloc_len(node, &rp->list) ;
  if (!genalloc_readyplus(node, &rp->list, 1)) dienomem() ;
  nod = genalloc_s(node, &rp->list) + n ;
  nod->key.left = rp->storage.len ;
  nod->key.right = keylen ;
  if (!stralloc_catb(&rp->storage, key, keylen)) dienomem() ;
  nod->line = line ;
  nod->data = stralloc_zero ;
  if (accu)
  {
    if (!stralloc_catb(&nod->data, data, datalen)) dienomem() ;
  }
  else
  {
    nod->data.a = rp->storage.len ;
    nod->data.len = datalen ;
    if (rp->storage.len + datalen > UINT32_MAX) diestorage() ;
    if (!stralloc_catb(&rp->storage, data, datalen)) dienomem() ;
  }
  genalloc_setlen(node, &rp->list, n + 1) ;
  if (!avltree_insert(&rp->tree, n)) dienomem() ;
}

uint32_t repo_add (repo *rp, char const *key, uint32_t keylen, char const *data, size_t datalen, uint32_t line, int accu, memcmp_func_ref f)
{
  node *nod ;
  if (keylen > UINT32_MAX || datalen > UINT32_MAX) diestorage() ;
  nod = repo_search(rp, key, keylen) ;
  if (nod)
  {
    if (!nod->data.s || !accu) return nod->line ;
    if (f && !checkunique(f, nod->data.s, nod->data.len, data, datalen)) return nod->line ;
    if (nod->data.len + datalen > UINT32_MAX) diestorage() ;
    if (!stralloc_catb(&nod->data, data, datalen)) dienomem() ;
  }
  else repo_add_new(rp, key, keylen, data, datalen, line, accu) ;
  return 0 ;
}

static int node_write (cdbmaker *cm, node *nod, char const *s)
{
  return cdbmake_add(cm, s + nod->key.left, nod->key.right, nod->data.s ? nod->data.s : s + nod->data.a, nod->data.len) ;
}

int repo_write (cdbmaker *cm, repo const *rp)
{
  for (size_t i = 0 ; i < genalloc_len(node, &rp->list) ; i++)
    if (!node_write(cm, genalloc_s(node, &rp->list) + i, rp->storage.s))
      return 0 ;
  return 1 ;
}

#if 0
static void node_free (node *nod)
{
  if (nod->data.s) stralloc_free(&nod->data) ;
}

void repo_free (repo *rp)
{
  avltree_free(&rp->tree) ;
  genalloc_deepfree(node, &rp->list, &node_free) ;
  stralloc_free(&rp->storage) ;
}
#endif