gwenhywfar 5.10.1
simpleptrlist.c
Go to the documentation of this file.
1/***************************************************************************
2 begin : Fri Dec 06 2019
3 copyright : (C) 2019 by Martin Preuss
4 email : martin@libchipcard.de
5
6 ***************************************************************************
7 * *
8 * This library is free software; you can redistribute it and/or *
9 * modify it under the terms of the GNU Lesser General Public *
10 * License as published by the Free Software Foundation; either *
11 * version 2.1 of the License, or (at your option) any later version. *
12 * *
13 * This library is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16 * Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public *
19 * License along with this library; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21 * MA 02111-1307 USA *
22 * *
23 ***************************************************************************/
24
25#ifdef HAVE_CONFIG_H
26# include <config.h>
27#endif
28
29#define DISABLE_DEBUGLOG
30
31
32#include "simpleptrlist_p.h"
33#include <gwenhywfar/debug.h>
34
35
36#include <stdlib.h>
37#include <assert.h>
38#include <string.h>
39
40
41
42/* ------------------------------------------------------------------------------------------------
43 * forward declarations
44 * ------------------------------------------------------------------------------------------------
45 */
46
47static void _attachToObject(GWEN_SIMPLEPTRLIST *pl, void *p);
48static void _detachFromObject(GWEN_SIMPLEPTRLIST *pl, void *p);
51
52static INTERNAL_PTRLIST *_mallocPtrList(uint64_t totalEntries);
53static void _attachToPtrList(INTERNAL_PTRLIST *entries);
54static void _freePtrList(INTERNAL_PTRLIST *entries);
55static INTERNAL_PTRLIST *_reallocPtrList(INTERNAL_PTRLIST *oldEntries, uint64_t totalEntries);
56static INTERNAL_PTRLIST *_copyPtrList(const INTERNAL_PTRLIST *oldEntries, uint64_t totalEntries);
57
58
59
60/* ------------------------------------------------------------------------------------------------
61 * implementations
62 * ------------------------------------------------------------------------------------------------
63 */
64
65
67
68
69
70
71GWEN_SIMPLEPTRLIST *GWEN_SimplePtrList_new(uint64_t startEntries, uint64_t steps)
72{
74
76 pl->refCount=1;
78
79 pl->entryList=_mallocPtrList(startEntries);
80 pl->maxEntries=startEntries;
81 pl->steps=steps;
82 pl->usedEntries=0;
83 return pl;
84}
85
86
87
89{
91
93 pl->refCount=1;
95
96 pl->entryList=oldList->entryList;
97 _attachToPtrList(pl->entryList);
98
99 pl->maxEntries=oldList->maxEntries;
100 pl->steps=oldList->steps;
101 pl->usedEntries=oldList->usedEntries;
102 pl->attachObjectFn=oldList->attachObjectFn;
103 pl->freeObjectFn=oldList->freeObjectFn;
104 pl->userIntData=oldList->userIntData;
105 pl->flags=oldList->flags | GWEN_SIMPLEPTRLIST_FLAGS_COPYONWRITE;
106 /* set copyOnWrite flag also on old list to keep lists separate even when changes to old lists are made */
107 oldList->flags|=GWEN_SIMPLEPTRLIST_FLAGS_COPYONWRITE;
108 return pl;
109}
110
111
112
114{
115 assert(pl);
116 assert(pl->refCount);
117 pl->refCount++;
118}
119
120
121
123{
124 if (pl) {
125 assert(pl->refCount);
126 if (pl->refCount==1) {
128 if (pl->flags & GWEN_SIMPLEPTRLIST_FLAGS_DETACHFROMOBJECTS && pl->entryList->refCounter==1) {
129 DBG_VERBOUS(GWEN_LOGDOMAIN, "Entries no longer needed, detaching from its objects");
131 }
132 _freePtrList(pl->entryList);
133 pl->entryList=NULL;
134 pl->maxEntries=0;
135 pl->refCount--;
137 }
138 else
139 pl->refCount--;
140 }
141}
142
143
144
146{
147 uint64_t i;
148 void **ptr;
149
150 assert(pl);
151 assert(pl->refCount);
152
155
156 ptr=pl->entryList->entries;
157 for (i=0; i<pl->usedEntries; i++)
158 *(ptr++)=NULL;
159}
160
161
162
164{
165 assert(pl);
166 assert(pl->refCount);
167 return pl->userIntData;
168}
169
170
171
173{
174 assert(pl);
175 assert(pl->refCount);
176 pl->userIntData=i;
177}
178
179
180
182{
183 assert(pl);
184 assert(pl->refCount);
185 pl->userCounter=i;
186}
187
188
189
191{
192 assert(pl);
193 assert(pl->refCount);
194 return pl->userCounter;
195}
196
197
198
200{
201 assert(pl);
202 assert(pl->refCount);
203 pl->userCounter++;
204}
205
206
207
209{
210 assert(pl);
211 assert(pl->refCount);
212 if (pl->userCounter) {
213 pl->userCounter--;
214 return 0;
215 }
216 else
217 return GWEN_ERROR_INVALID; /* counter already is 0 */
218}
219
220
221
222
223
224
226{
227 assert(pl);
228 assert(pl->refCount);
229 if (idx<pl->usedEntries) {
230 return pl->entryList->entries[idx];
231 }
232 else {
234 "Index outside boundaries (%lu >= %lu)",
235 (unsigned long) idx,
236 (unsigned long)(pl->usedEntries));
237 }
238 return NULL;
239}
240
241
242
243int GWEN_SimplePtrList_SetPtrAt(GWEN_SIMPLEPTRLIST *pl, uint64_t idx, void *p)
244{
245 assert(pl);
246 assert(pl->refCount);
247
248 if (idx<pl->usedEntries) {
249 int rv;
250 void *oldPtr;
251
252 /* copy on write, if needed */
254 if (rv<0) {
255 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
256 return rv;
257 }
258
259 oldPtr=pl->entryList->entries[idx];
260 pl->entryList->entries[idx]=p;
261 if (p && (pl->flags & GWEN_SIMPLEPTRLIST_FLAGS_ATTACHTOOBJECTS))
262 _attachToObject(pl, p);
263 if (oldPtr && (pl->flags & GWEN_SIMPLEPTRLIST_FLAGS_DETACHFROMOBJECTS))
264 _detachFromObject(pl, oldPtr);
265 }
266 else {
267 DBG_ERROR(GWEN_LOGDOMAIN, "Bad index");
269 }
270
271 return 0;
272}
273
274
275
277{
278 int rv;
279
280 assert(pl);
281 assert(pl->refCount);
282
284 if (rv<0) {
285 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
286 return rv;
287 }
288
289 if (pl->usedEntries >= pl->maxEntries) {
290 uint64_t num;
291
292 num=pl->maxEntries+pl->steps;
293 if (num>pl->maxEntries) {
294 INTERNAL_PTRLIST *entryList;
295
296 /* resize current list */
297 entryList=_reallocPtrList(pl->entryList, num);
298 if (entryList==NULL) {
299 DBG_ERROR(GWEN_LOGDOMAIN, "Memory full.");
301 }
302 pl->entryList=entryList;
303 pl->maxEntries=num;
304 }
305 else {
306 DBG_ERROR(GWEN_LOGDOMAIN, "Table full (step size==0).");
308 }
309 }
310
311 /* add entry */
312 pl->entryList->entries[pl->usedEntries]=p;
313 if (p && (pl->flags & GWEN_SIMPLEPTRLIST_FLAGS_ATTACHTOOBJECTS))
314 _attachToObject(pl, p);
315 pl->usedEntries++;
316 return pl->usedEntries-1;
317}
318
319
320
322{
323 assert(pl);
324 assert(pl->refCount);
325 return pl->steps;
326}
327
328
329
331{
332 assert(pl);
333 assert(pl->refCount);
334 pl->steps=steps;
335}
336
337
338
340{
341 assert(pl);
342 assert(pl->refCount);
343 return pl->maxEntries;
344}
345
346
347
349{
350 assert(pl);
351 assert(pl->refCount);
352 return pl->usedEntries;
353}
354
355
356
358{
359 assert(pl);
360 assert(pl->refCount);
361 return pl->entryList->entries;
362}
363
364
365
367{
368 assert(pl);
369 assert(pl->refCount);
370 return pl->flags;
371}
372
373
374
376{
377 assert(pl);
378 assert(pl->refCount);
379 pl->flags=f;
380}
381
382
383
385{
386 assert(pl);
387 assert(pl->refCount);
388 pl->flags|=f;
389}
390
391
392
394{
395 assert(pl);
396 assert(pl->refCount);
397 pl->flags&=~f;
398}
399
400
401
404{
406
407 assert(pl);
408 assert(pl->refCount);
409
410 oldFn=pl->attachObjectFn;
411 pl->attachObjectFn=fn;
412 return oldFn;
413}
414
415
416
419{
421
422 assert(pl);
423 assert(pl->refCount);
424
425 oldFn=pl->freeObjectFn;
426 pl->freeObjectFn=fn;
427 return oldFn;
428}
429
430
431
433{
434 if (pl->attachObjectFn)
435 pl->attachObjectFn(pl, p);
436}
437
438
439
441{
442 if (pl->freeObjectFn)
443 pl->freeObjectFn(pl, p);
444}
445
446
447
449{
450 if (pl->attachObjectFn) {
451 uint64_t i;
452 void **ptr;
453
454 DBG_VERBOUS(GWEN_LOGDOMAIN, "Attaching to objects");
455 ptr=pl->entryList->entries;
456 for (i=0; i<pl->usedEntries; i++) {
457 if (*ptr!=NULL)
458 _attachToObject(pl, *ptr);
459 ptr++;
460 }
461 }
462 else {
463 DBG_ERROR(GWEN_LOGDOMAIN, "No attachObjectFn set");
464 }
465}
466
467
468
470{
471 if (pl->freeObjectFn) {
472 uint64_t i;
473 void **ptr;
474
475 DBG_VERBOUS(GWEN_LOGDOMAIN, "Detaching from objects");
476 ptr=pl->entryList->entries;
477 for (i=0; i<pl->usedEntries; i++) {
478 if (*ptr!=NULL)
479 _detachFromObject(pl, *ptr);
480 ptr++;
481 }
482 }
483 else {
484 DBG_ERROR(GWEN_LOGDOMAIN, "No attachObjectFn set");
485 }
486}
487
488
489
490
491
492
493INTERNAL_PTRLIST *_mallocPtrList(uint64_t totalEntries)
494{
495 INTERNAL_PTRLIST *entries;
496 size_t objectSize;
497
498 DBG_VERBOUS(GWEN_LOGDOMAIN, "Malloc entries");
499 objectSize=sizeof(INTERNAL_PTRLIST) + (totalEntries*sizeof(void *));
500 entries=(INTERNAL_PTRLIST *) malloc(objectSize);
501 if (entries==NULL) {
502 DBG_ERROR(GWEN_LOGDOMAIN, "Memory full.");
503 return NULL;
504 }
505 memset((void *)entries, 0, objectSize);
506 entries->refCounter=1;
507 entries->storedEntries=totalEntries;
508 return entries;
509}
510
511
512
513void _attachToPtrList(INTERNAL_PTRLIST *entries)
514{
515 assert(entries && entries->refCounter>0);
516 if (entries && entries->refCounter>0) {
517 DBG_VERBOUS(GWEN_LOGDOMAIN, "Attaching to entries");
518 entries->refCounter++;
519 }
520 else {
521 DBG_ERROR(GWEN_LOGDOMAIN, "Null pointer or already freed");
522 }
523}
524
525
526
527void _freePtrList(INTERNAL_PTRLIST *entries)
528{
529 if (entries && entries->refCounter>0) {
530 if (entries->refCounter==1) {
531 DBG_VERBOUS(GWEN_LOGDOMAIN, "Freeing entries");
532 entries->refCounter=0;
533 free(entries);
534 }
535 else {
536 entries->refCounter--;
537 }
538 }
539}
540
541
542
543INTERNAL_PTRLIST *_reallocPtrList(INTERNAL_PTRLIST *entries, uint64_t totalEntries)
544{
545 assert(entries && entries->refCounter>0);
546 if (entries && entries->refCounter>0) {
547 size_t newSize;
548 uint64_t diffEntries;
549
550 DBG_VERBOUS(GWEN_LOGDOMAIN, "Resizing entries");
551 if (totalEntries<entries->storedEntries) {
552 DBG_INFO(GWEN_LOGDOMAIN, "Will not decrease size (for now)");
553 return entries;
554 }
555
556 diffEntries=totalEntries-(entries->storedEntries);
557 newSize=sizeof(INTERNAL_PTRLIST)+totalEntries*sizeof(void *);
558
559 entries=(INTERNAL_PTRLIST *) realloc(entries, newSize);
560 if (entries==NULL) {
561 DBG_ERROR(GWEN_LOGDOMAIN, "Memory full.");
562 return NULL;
563 }
564
565 /* preset new entries */
566 if (diffEntries)
567 memset((void *) &(entries->entries[entries->storedEntries]), 0, diffEntries*sizeof(void *));
568 entries->storedEntries=totalEntries;
569 return entries;
570 }
571 else {
572 DBG_ERROR(GWEN_LOGDOMAIN, "Null pointer or already freed");
573 return NULL;
574 }
575}
576
577
578
579INTERNAL_PTRLIST *_copyPtrList(const INTERNAL_PTRLIST *oldEntries, uint64_t totalEntries)
580{
581 assert(oldEntries && oldEntries->refCounter>0);
582 if (oldEntries && oldEntries->refCounter>0) {
583 INTERNAL_PTRLIST *entries;
584 size_t oldSize;
585 size_t newSize;
586 uint64_t diffEntries;
587
588 DBG_VERBOUS(GWEN_LOGDOMAIN, "Copying entries");
589 if (totalEntries<oldEntries->storedEntries)
590 totalEntries=oldEntries->storedEntries;
591
592 diffEntries=totalEntries-(oldEntries->storedEntries);
593 oldSize=sizeof(INTERNAL_PTRLIST)+((oldEntries->storedEntries)*sizeof(void *));
594 newSize=sizeof(INTERNAL_PTRLIST)+totalEntries*sizeof(void *);
595
596 entries=(INTERNAL_PTRLIST *) malloc(newSize);
597 if (entries==NULL) {
598 DBG_ERROR(GWEN_LOGDOMAIN, "Memory full.");
599 return NULL;
600 }
601
602 /* copy old struct */
603 memmove(entries, oldEntries, oldSize);
604
605 /* preset new entries */
606 if (diffEntries)
607 memset((void *) &(entries->entries[entries->storedEntries]), 0, diffEntries*sizeof(void *));
608
609 /* setup rest of the fields */
610 entries->refCounter=1;
611 entries->storedEntries=totalEntries;
612 return entries;
613 }
614 else {
615 DBG_ERROR(GWEN_LOGDOMAIN, "Null pointer or already freed");
616 return NULL;
617 }
618}
619
620
621
623{
624 assert(pl && pl->refCount);
625
626 if (pl->flags & GWEN_SIMPLEPTRLIST_FLAGS_COPYONWRITE) {
627 INTERNAL_PTRLIST *entryList;
628 uint64_t num;
629
630 num=pl->maxEntries+pl->steps;
631
632 DBG_VERBOUS(GWEN_LOGDOMAIN, "Copying entries");
633
634 /* make new entries pointer a copy of the old one */
635 entryList=_copyPtrList(pl->entryList, num);
636 if (entryList==NULL) {
637 DBG_ERROR(GWEN_LOGDOMAIN, "Memory full.");
639 }
640
641 _freePtrList(pl->entryList);
642 pl->entryList=entryList;
643 pl->maxEntries=num;
644 /* this is a copy, attach to objs */
646 DBG_VERBOUS(GWEN_LOGDOMAIN, "Attaching to objects");
648 }
649 /* clear copy-on-write flag */
650 pl->flags&=~GWEN_SIMPLEPTRLIST_FLAGS_COPYONWRITE;
651 }
652
653 return 0;
654}
655
656
657
658/* include tests */
659#include "simpleptrlist-t.c"
660
#define NULL
Definition: binreloc.c:300
#define DBG_VERBOUS(dbg_logger, format, args...)
Definition: debug.h:224
#define DBG_INFO(dbg_logger, format, args...)
Definition: debug.h:181
#define DBG_ERROR(dbg_logger, format, args...)
Definition: debug.h:97
#define GWEN_ERROR_MEMORY_FULL
Definition: error.h:77
#define GWEN_ERROR_INVALID
Definition: error.h:67
#define GWEN_ERROR_BUFFER_OVERFLOW
Definition: error.h:79
#define GWEN_INHERIT_FUNCTIONS(t)
Definition: inherit.h:163
#define GWEN_INHERIT_INIT(t, element)
Definition: inherit.h:223
#define GWEN_INHERIT_FINI(t, element)
Definition: inherit.h:238
#define GWEN_LOGDOMAIN
Definition: logger.h:35
#define GWEN_FREE_OBJECT(varname)
Definition: memory.h:61
#define GWEN_NEW_OBJECT(typ, varname)
Definition: memory.h:55
static void _freePtrList(INTERNAL_PTRLIST *entries)
uint64_t GWEN_SimplePtrList_GetUsedEntries(const GWEN_SIMPLEPTRLIST *pl)
uint32_t GWEN_SimplePtrList_GetFlags(const GWEN_SIMPLEPTRLIST *pl)
uint64_t GWEN_SimplePtrList_GetSteps(const GWEN_SIMPLEPTRLIST *pl)
GWEN_SIMPLEPTRLIST_ATTACHOBJECT_FN GWEN_SimplePtrList_SetAttachObjectFn(GWEN_SIMPLEPTRLIST *pl, GWEN_SIMPLEPTRLIST_ATTACHOBJECT_FN fn)
void GWEN_SimplePtrList_SetFlags(GWEN_SIMPLEPTRLIST *pl, uint32_t f)
static void _detachFromObject(GWEN_SIMPLEPTRLIST *pl, void *p)
int GWEN_SimplePtrList_GetUserIntData(const GWEN_SIMPLEPTRLIST *pl)
void * GWEN_SimplePtrList_GetEntries(const GWEN_SIMPLEPTRLIST *pl)
int GWEN_SimplePtrList_EnsureWritability(GWEN_SIMPLEPTRLIST *pl)
void GWEN_SimplePtrList_Attach(GWEN_SIMPLEPTRLIST *pl)
void GWEN_SimplePtrList_SubFlags(GWEN_SIMPLEPTRLIST *pl, uint32_t f)
void GWEN_SimplePtrList_SetUserIntData(GWEN_SIMPLEPTRLIST *pl, int i)
static void _attachToPtrList(INTERNAL_PTRLIST *entries)
int GWEN_SimplePtrList_DecUserCounter(GWEN_SIMPLEPTRLIST *pl)
void GWEN_SimplePtrList_free(GWEN_SIMPLEPTRLIST *pl)
void GWEN_SimplePtrList_SetSteps(GWEN_SIMPLEPTRLIST *pl, uint64_t steps)
int64_t GWEN_SimplePtrList_AddPtr(GWEN_SIMPLEPTRLIST *pl, void *p)
GWEN_SIMPLEPTRLIST_FREEOBJECT_FN GWEN_SimplePtrList_SetFreeObjectFn(GWEN_SIMPLEPTRLIST *pl, GWEN_SIMPLEPTRLIST_FREEOBJECT_FN fn)
static INTERNAL_PTRLIST * _reallocPtrList(INTERNAL_PTRLIST *oldEntries, uint64_t totalEntries)
uint64_t GWEN_SimplePtrList_GetUserCounter(const GWEN_SIMPLEPTRLIST *pl)
int GWEN_SimplePtrList_SetPtrAt(GWEN_SIMPLEPTRLIST *pl, uint64_t idx, void *p)
void GWEN_SimplePtrList_AddFlags(GWEN_SIMPLEPTRLIST *pl, uint32_t f)
void GWEN_SimplePtrList_SetUserCounter(GWEN_SIMPLEPTRLIST *pl, uint64_t i)
static INTERNAL_PTRLIST * _mallocPtrList(uint64_t totalEntries)
static INTERNAL_PTRLIST * _copyPtrList(const INTERNAL_PTRLIST *oldEntries, uint64_t totalEntries)
void GWEN_SimplePtrList_Clear(GWEN_SIMPLEPTRLIST *pl)
GWEN_SIMPLEPTRLIST * GWEN_SimplePtrList_LazyCopy(GWEN_SIMPLEPTRLIST *oldList)
Definition: simpleptrlist.c:88
uint64_t GWEN_SimplePtrList_GetMaxEntries(const GWEN_SIMPLEPTRLIST *pl)
static void _detachFromAllObjects(GWEN_SIMPLEPTRLIST *pl)
static void _attachToAllObjects(GWEN_SIMPLEPTRLIST *pl)
static void _attachToObject(GWEN_SIMPLEPTRLIST *pl, void *p)
GWEN_SIMPLEPTRLIST * GWEN_SimplePtrList_new(uint64_t startEntries, uint64_t steps)
Definition: simpleptrlist.c:71
void * GWEN_SimplePtrList_GetPtrAt(const GWEN_SIMPLEPTRLIST *pl, uint64_t idx)
void GWEN_SimplePtrList_IncUserCounter(GWEN_SIMPLEPTRLIST *pl)
GWENHYWFAR_CB void(* GWEN_SIMPLEPTRLIST_ATTACHOBJECT_FN)(GWEN_SIMPLEPTRLIST *pl, void *p)
Definition: simpleptrlist.h:43
struct GWEN_SIMPLEPTRLIST GWEN_SIMPLEPTRLIST
Definition: simpleptrlist.h:38
#define GWEN_SIMPLEPTRLIST_FLAGS_ATTACHTOOBJECTS
Definition: simpleptrlist.h:33
GWENHYWFAR_CB void(* GWEN_SIMPLEPTRLIST_FREEOBJECT_FN)(GWEN_SIMPLEPTRLIST *pl, void *p)
Definition: simpleptrlist.h:44
#define GWEN_SIMPLEPTRLIST_FLAGS_DETACHFROMOBJECTS
Definition: simpleptrlist.h:34