1 /*****************************************************************************
2 * This file is part of gfxprim library. *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
19 * Copyright (C) 2009-2015 Cyril Hrubis <metan@ucw.cz> *
21 *****************************************************************************/
27 #include "core/GP_Debug.h"
28 #include "core/GP_Common.h"
30 #include "GP_DataStorage.h"
38 struct GP_DataNode
*first
;
39 struct GP_DataNode
*last
;
42 #define BLOCK_SIZE 4096
51 struct GP_DataStorage
{
53 struct GP_DataNode root
;
54 struct GP_DataDict dict
;
58 struct block
*cur_block
;
61 /* Align to four bytes boundary */
62 static size_t align(size_t size
)
66 return (size
+ mask
) & ~mask
;
69 static struct block
*new_block(GP_DataStorage
*self
, size_t size
)
71 struct block
*new = malloc(size
);
73 GP_DEBUG(3, "Allocating new block for %zu bytes", size
);
78 new->size
= size
- sizeof(*new);
80 new->next
= self
->blocks
;
86 static void *storage_alloc(GP_DataStorage
*self
, size_t size
)
91 GP_DEBUG(3, "Allocating %zu bytes", size
);
93 if (size
>= BLOCK_MAX
) {
94 new = new_block(self
, sizeof(*new) + size
);
102 if (self
->cur_block
->size
< size
) {
103 new = new_block(self
, BLOCK_SIZE
);
108 self
->cur_block
= new;
111 ret
= self
->cur_block
->data
+ BLOCK_SIZE
- self
->cur_block
->size
;
112 self
->cur_block
->size
-= size
;
117 static struct record
*new_record(GP_DataStorage
*self
, GP_DataNode
*node
)
119 size_t id_len
= align(strlen(node
->id
) + 1);
120 size_t payload_len
= 0;
124 switch (node
->type
) {
126 payload_len
= align(strlen(node
->value
.str
) + 1);
129 payload_len
= sizeof(struct GP_DataDict
);
135 new = storage_alloc(self
, sizeof(*new) + id_len
+ payload_len
);
140 strcpy(new->id
, node
->id
);
141 new->node
.id
= new->id
;
142 new->node
.type
= node
->type
;
143 new->node
.value
= node
->value
;
144 new->node
.next
= NULL
;
146 payload
= ((void*)new) + sizeof(*new) + id_len
;
148 switch (node
->type
) {
150 strcpy(payload
, node
->value
.str
);
151 new->node
.value
.str
= payload
;
154 new->node
.value
.dict
= payload
;
155 new->node
.value
.dict
->first
= NULL
;
156 new->node
.value
.dict
->last
= NULL
;
165 GP_DataStorage
*GP_DataStorageCreate(void)
167 GP_DataStorage
*storage
= malloc(sizeof(*storage
));
169 GP_DEBUG(1, "Creating data storage (%p)", storage
);
174 storage
->root
.type
= GP_DATA_DICT
;
175 storage
->root
.value
.dict
= &storage
->dict
;
176 storage
->dict
.first
= NULL
;
177 storage
->dict
.last
= NULL
;
179 storage
->blocks
= NULL
;
180 storage
->cur_block
= new_block(storage
, BLOCK_SIZE
);
182 if (!storage
->cur_block
) {
190 void GP_DataStorageDestroy(GP_DataStorage
*self
)
197 GP_DEBUG(1, "Destroying data storage");
199 for (i
= self
->blocks
; i
; ) {
208 void GP_DataStorageClear(GP_DataStorage
*self
)
212 GP_DEBUG(1, "Clearing all data in storage");
214 /* Clear all but first block */
215 for (i
= self
->blocks
->next
; i
;) {
221 /* Rest first block */
222 self
->cur_block
= self
->blocks
;
223 self
->cur_block
->next
= NULL
;
224 //TODO: Store block size!!
225 self
->cur_block
->size
= BLOCK_SIZE
- sizeof(struct block
);
227 /* Reset root dict */
228 self
->dict
.first
= NULL
;
229 self
->dict
.last
= NULL
;
232 GP_DataNode
*GP_DataStorageRoot(GP_DataStorage
*self
)
237 GP_DataNode
*GP_DataDictFirst(GP_DataNode
*node
)
239 return node
->value
.dict
->first
;
242 static void dict_add(GP_DataDict
*dict
, GP_DataNode
*node
)
248 dict
->last
->next
= node
;
253 GP_DataNode
*GP_DataStorageAdd(GP_DataStorage
*self
,
254 GP_DataNode
*node
, GP_DataNode
*data
)
257 struct GP_DataNode
*dup
;
259 GP_DEBUG(2, "Adding '%s' to storage (%p)", data
->id
, self
);
261 if (node
&& node
->type
!= GP_DATA_DICT
) {
262 GP_WARN("Trying to insert data into %s",
263 GP_DataTypeName(node
->type
));
267 dup
= GP_DataStorageGet(self
, node
, data
->id
);
270 GP_WARN("Trying to insert allready existing node '%s'",
275 rec
= new_record(self
, data
);
281 node
= GP_DataStorageRoot(self
);
283 dict_add(node
->value
.dict
, &rec
->node
);
288 GP_DataNode
*GP_DataStorageGet(GP_DataStorage
*self
,
292 struct GP_DataNode
*i
;
295 node
= GP_DataStorageRoot(self
);
297 for (i
= GP_DataDictFirst(node
); i
; i
= i
->next
) {
298 if (!strcmp(i
->id
, id
))
305 static struct GP_DataNode
*lookup(GP_DataNode
*node
, const char *id
,
308 struct GP_DataNode
*i
;
313 for (i
= GP_DataDictFirst(node
); i
; i
= i
->next
) {
314 if (!strncmp(i
->id
, id
, id_len
))
321 static struct GP_DataNode
*get_by_path(GP_DataNode
*node
, const char *path
)
325 for (i
= 0; path
[i
] && path
[i
] != '/'; i
++);
330 node
= lookup(node
, path
, i
);
335 GP_DEBUG(3, "Lookup has node '%s'", node
->id
);
342 return get_by_path(node
, path
);
345 GP_DataNode
*GP_DataStorageGetByPath(GP_DataStorage
*self
, GP_DataNode
*node
,
348 GP_DEBUG(3, "Looking for '%s' in %p", path
, node
);
350 if (path
[0] == '/') {
355 node
= GP_DataStorageRoot(self
);
359 return get_by_path(node
, path
);
363 static void padd_printf(size_t padd
, const char *id
, size_t id_padd
,
364 const char *fmt
, ...)
365 __attribute__ ((format (printf
, 4, 5)));
367 static void padd_printf(size_t padd
, const char *id
, size_t id_padd
,
368 const char *fmt
, ...)
379 id_padd
-= strlen(id
);
389 /* Must be called on data dict only */
390 static size_t max_id_len(const GP_DataNode
*node
)
395 for (i
= node
->value
.dict
->first
; i
; i
= i
->next
)
396 max
= GP_MAX(max
, strlen(i
->id
));
401 static void data_print(const GP_DataNode
*node
,
402 unsigned int padd
, size_t id_padd
)
407 padd_printf(padd
, NULL
, 0, "(Empty)\n");
411 switch (node
->type
) {
413 padd_printf(padd
, node
->id
, id_padd
, " : %li\n", node
->value
.i
);
416 padd_printf(padd
, node
->id
, id_padd
, " : %lf\n", node
->value
.d
);
418 case GP_DATA_RATIONAL
:
419 padd_printf(padd
, node
->id
, id_padd
, " : %li/%li\n",
420 node
->value
.rat
.num
, node
->value
.rat
.den
);
423 padd_printf(padd
, node
->id
, id_padd
, " : '%s'\n", node
->value
.str
);
426 padd_printf(padd
, node
->id
? node
->id
: "Data Root", 0, " = {\n");
428 for (i
= node
->value
.dict
->first
; i
; i
= i
->next
)
429 data_print(i
, padd
+ 1, max_id_len(node
));
431 padd_printf(padd
, NULL
, 0, "}\n");
436 void GP_DataPrint(const GP_DataNode
*node
)
438 data_print(node
, 0, node
->id
? strlen(node
->id
) : 0);
441 const char *GP_DataTypeName(enum GP_DataType type
)
448 case GP_DATA_RATIONAL
:
459 GP_DataNode
*GP_DataStorageAddInt(GP_DataStorage
*self
, GP_DataNode
*node
,
460 const char *id
, long i
)
468 return GP_DataStorageAdd(self
, node
, &data
);
471 GP_DataNode
*GP_DataStorageAddString(GP_DataStorage
*self
, GP_DataNode
*node
,
472 const char *id
, const char *str
)
475 .type
= GP_DATA_STRING
,
480 return GP_DataStorageAdd(self
, node
, &data
);
483 GP_DataNode
*GP_DataStorageAddDouble(GP_DataStorage
*self
, GP_DataNode
*node
,
484 const char *id
, double d
)
487 .type
= GP_DATA_DOUBLE
,
492 return GP_DataStorageAdd(self
, node
, &data
);
495 GP_DataNode
*GP_DataStorageAddRational(GP_DataStorage
*self
, GP_DataNode
*node
,
496 const char *id
, long num
, long den
)
499 .type
= GP_DATA_RATIONAL
,
501 .value
.rat
= {.num
= num
, .den
= den
},
504 return GP_DataStorageAdd(self
, node
, &data
);
507 GP_DataNode
*GP_DataStorageAddDict(GP_DataStorage
*self
, GP_DataNode
*node
,
511 .type
= GP_DATA_DICT
,
515 return GP_DataStorageAdd(self
, node
, &data
);