maug
Quick and dirty C mini-augmentation library.
Loading...
Searching...
No Matches
mdata.h
Go to the documentation of this file.
1
2#ifndef MDATA_H
3#define MDATA_H
4
12
13#ifndef MDATA_LOCK_TRACE_LVL
14# define MDATA_LOCK_TRACE_LVL 0
15#endif /* !MDATA_LOCK_TRACE_LVL */
16
17#ifndef MDATA_STRPOOL_TRACE_LVL
18# define MDATA_STRPOOL_TRACE_LVL 0
19#endif /* !MDATA_STRPOOL_TRACE_LVL */
20
21#ifndef MDATA_VECTOR_TRACE_LVL
22# define MDATA_VECTOR_TRACE_LVL 0
23#endif /* !MDATA_VECTOR_TRACE_LVL */
24
25#ifndef MDATA_TABLE_TRACE_LVL
26# define MDATA_TABLE_TRACE_LVL 0
27#endif /* !MDATA_TABLE_TRACE_LVL */
28
29#ifndef MDATA_TABLE_KEY_SZ_MAX
30# define MDATA_TABLE_KEY_SZ_MAX 8
31#endif /* !MDATA_TABLE_KEY_SZ_MAX */
32
37
46#define MDATA_VECTOR_FLAG_REFCOUNT 0x01
47
48#define MDATA_VECTOR_FLAG_IS_LOCKED 0x02
49
50#ifndef MDATA_VECTOR_INIT_STEP_SZ
55# define MDATA_VECTOR_INIT_STEP_SZ 10
56#endif /* !MDATA_VECTOR_INIT_STEP_SZ */
57
59
66
67#define MDATA_STRPOOL_FLAG_IS_LOCKED 0x01
68
69#define MDATA_STRPOOL_FLAG_DEDUPE 0x02
70
71typedef size_t mdata_strpool_idx_t;
72
81 uint8_t flags;
82 MAUG_MHANDLE str_h;
83 char* str_p;
84 size_t str_sz;
85 size_t str_sz_max;
86};
87 /* mdata_strpool */
89
95
106 uint8_t flags;
108 MAUG_MHANDLE data_h;
110 uint8_t* data_bytes;
112 size_t ct_max;
114 size_t ct;
116 size_t ct_step;
121 size_t item_sz;
123 ssize_t locks;
124};
125 /* mdata_vector */
127
132
134 char string[MDATA_TABLE_KEY_SZ_MAX + 1];
135 size_t string_sz;
136 uint32_t hash;
137};
138
140 volatile uint16_t flags;
141 struct MDATA_VECTOR data_cols[2];
142 size_t key_sz;
143};
144
146
151
156 struct MDATA_STRPOOL* sp, mdata_strpool_idx_t idx );
157
158mdata_strpool_idx_t mdata_strpool_find(
159 struct MDATA_STRPOOL* sp, const char* str, size_t str_sz );
160
166 struct MDATA_STRPOOL* sp, mdata_strpool_idx_t idx );
167
168mdata_strpool_idx_t mdata_strpool_append(
169 struct MDATA_STRPOOL* sp, const char* str, size_t str_sz, uint8_t flags );
170
171MERROR_RETVAL mdata_strpool_remove(
172 struct MDATA_STRPOOL* sp, mdata_strpool_idx_t idx );
173
174MERROR_RETVAL mdata_strpool_alloc(
175 struct MDATA_STRPOOL* sp, size_t alloc_sz );
176
177void mdata_strpool_free( struct MDATA_STRPOOL* sp );
178
180
185
200 struct MDATA_VECTOR* v, const void* item, size_t item_sz );
201
202ssize_t mdata_vector_insert(
203 struct MDATA_VECTOR* v, const void* item, ssize_t idx, size_t item_sz );
204
211
220void* mdata_vector_get_void( const struct MDATA_VECTOR* v, size_t idx );
221
222MERROR_RETVAL mdata_vector_copy(
223 struct MDATA_VECTOR* v_dest, struct MDATA_VECTOR* v_src );
224
230 struct MDATA_VECTOR* v, size_t item_sz, size_t item_ct_init );
231
232void mdata_vector_free( struct MDATA_VECTOR* v );
233 /* mdata_vector */
235
236uint32_t mdata_hash( const char* token, size_t token_sz );
237
242
243typedef MERROR_RETVAL (*mdata_table_iter_t)(
244 const struct MDATA_TABLE_KEY* key, void* data, size_t data_sz,
245 void* cb_data, size_t cb_data_sz, size_t idx );
246
247MERROR_RETVAL mdata_table_lock( struct MDATA_TABLE* t );
248
249MERROR_RETVAL mdata_table_unlock( struct MDATA_TABLE* t );
250
251MERROR_RETVAL mdata_table_iter(
252 struct MDATA_TABLE* t,
253 mdata_table_iter_t cb, void* cb_data, size_t cb_data_sz );
254
255MERROR_RETVAL mdata_table_set(
256 struct MDATA_TABLE* t, const char* key,
257 void* value, size_t value_sz );
258
259MERROR_RETVAL mdata_table_unset(
260 struct MDATA_TABLE* t, const char* key );
261
262void* mdata_table_get_void( const struct MDATA_TABLE* t, const char* key );
263
264void* mdata_table_hash_get_void(
265 struct MDATA_TABLE* t, uint32_t key_hash, size_t key_sz );
266
267void mdata_table_free( struct MDATA_TABLE* t );
268
270
271#if MDATA_LOCK_TRACE_LVL > 0
272# define mdata_debug_lock_printf( fmt, ... ) \
273 debug_printf( MDATA_LOCK_TRACE_LVL, fmt, __VA_ARGS__ );
274#else
275# define mdata_debug_lock_printf( fmt, ... )
276#endif /* MDATA_LOCK_TRACE_LVL */
277
282
283#define mdata_strpool_sz( sp ) ((sp)->str_sz_max)
284
285#define mdata_strpool_is_locked( sp ) \
286 (MDATA_STRPOOL_FLAG_IS_LOCKED == \
287 (MDATA_STRPOOL_FLAG_IS_LOCKED & (sp)->flags))
288
289#define mdata_strpool_lock( sp ) \
290 mdata_debug_lock_printf( "locking strpool %p...", sp ); \
291 if( NULL != (sp)->str_p ) { \
292 error_printf( "str_p not null! double lock?" ); \
293 retval = MERROR_ALLOC; \
294 goto cleanup; \
295 } \
296 maug_mlock( (sp)->str_h, (sp)->str_p ); \
297 maug_cleanup_if_null_lock( char*, (sp)->str_p ); \
298 (sp)->flags |= MDATA_STRPOOL_FLAG_IS_LOCKED;
299
300#define mdata_strpool_unlock( sp ) \
301 mdata_debug_lock_printf( "unlocking strpool %p...", sp ); \
302 if( NULL != (sp)->str_p ) { \
303 maug_munlock( (sp)->str_h, (sp)->str_p ); \
304 (sp)->flags &= ~MDATA_STRPOOL_FLAG_IS_LOCKED; \
305 }
306
307#define mdata_strpool_get( sp, idx ) \
308 ((idx >= 1 && idx < (sp)->str_sz) ? &((sp)->str_p[idx]) : NULL)
309
310#define mdata_strpool_get_sz( sp, idx ) \
311 ((idx >= sizeof( size_t ) && idx < (sp)->str_sz) ? \
312 (size_t)(*(&((sp)->str_p[idx - sizeof( size_t )]))) : 0)
313
314#define mdata_strpool_padding( str_sz ) \
315 (sizeof( size_t ) - ((str_sz + 1 /* NULL */) % sizeof( size_t )))
316 /* mdata_strpool */
318
323
332#define mdata_vector_lock( v ) \
333 if( (MAUG_MHANDLE)NULL == (v)->data_h && NULL == (v)->data_bytes ) { \
334 mdata_debug_lock_printf( "locking empty vector..." ); \
335 (v)->flags |= MDATA_VECTOR_FLAG_IS_LOCKED; \
336 } else if( \
337 mdata_vector_get_flag( v, MDATA_VECTOR_FLAG_REFCOUNT ) && \
338 0 < (v)->locks \
339 ) { \
340 (v)->locks++; \
341 mdata_debug_lock_printf( "vector " #v " locks: " SSIZE_T_FMT, (v)->locks ); \
342 } else { \
343 /* assert( !mdata_vector_is_locked( v ) ); */ \
344 if( mdata_vector_is_locked( v ) ) { \
345 error_printf( "attempting to double-lock vector!" ); \
346 retval = MERROR_OVERFLOW; \
347 goto cleanup; \
348 } \
349 if( (MAUG_MHANDLE)NULL == (v)->data_h ) { \
350 error_printf( "invalid data handle!" ); \
351 retval = MERROR_ALLOC; \
352 goto cleanup; \
353 } \
354 maug_mlock( (v)->data_h, (v)->data_bytes ); \
355 maug_cleanup_if_null_lock( uint8_t*, (v)->data_bytes ); \
356 (v)->flags |= MDATA_VECTOR_FLAG_IS_LOCKED; \
357 mdata_debug_lock_printf( "locked vector " #v ); \
358 }
359
365#define mdata_vector_unlock( v ) \
366 if( (MAUG_MHANDLE)NULL == (v)->data_h && NULL == (v)->data_bytes ) { \
367 mdata_debug_lock_printf( "locking empty vector..." ); \
368 (v)->flags &= ~MDATA_VECTOR_FLAG_IS_LOCKED; \
369 } else { \
370 if( \
371 mdata_vector_get_flag( v, MDATA_VECTOR_FLAG_REFCOUNT ) && \
372 0 < (v)->locks \
373 ) { \
374 (v)->locks--; \
375 mdata_debug_lock_printf( "vector " #v " locks: " SSIZE_T_FMT, \
376 (v)->locks ); \
377 } \
378 if( 0 == (v)->locks && NULL != (v)->data_bytes ) { \
379 assert( mdata_vector_is_locked( v ) ); \
380 maug_munlock( (v)->data_h, (v)->data_bytes ); \
381 (v)->flags &= ~MDATA_VECTOR_FLAG_IS_LOCKED; \
382 mdata_debug_lock_printf( "unlocked vector " #v ); \
383 } \
384 }
385
386#define mdata_vector_get( v, idx, type ) \
387 ((type*)mdata_vector_get_void( v, idx ))
388
389#define mdata_vector_get_last( v, type ) \
390 (0 < mdata_vector_ct( v ) ? \
391 ((type*)mdata_vector_get_void( v, \
392 mdata_vector_ct( v ) - 1 )) : NULL)
393
394#define mdata_vector_remove_last( v ) \
395 (0 < mdata_vector_ct( v ) ? \
396 (mdata_vector_remove( v, mdata_vector_ct( v ) - 1 )) : MERROR_OVERFLOW)
397
398#define mdata_vector_set_ct_step( v, step ) \
399 (v)->ct_step = step;
400
408#define mdata_vector_ct( v ) ((v)->ct)
409
414#define mdata_vector_sz( v ) (((v)->ct_max) * ((v)->item_sz))
415
420#define mdata_vector_fill( v, ct_new, sz ) \
421 retval = mdata_vector_alloc( v, sz, ct_new ); \
422 maug_cleanup_if_not_ok(); \
423 (v)->ct = (ct_new);
424
425#define mdata_vector_is_locked( v ) \
426 (MDATA_VECTOR_FLAG_IS_LOCKED == \
427 (MDATA_VECTOR_FLAG_IS_LOCKED & (v)->flags))
428
429/* TODO: Implement insert sorting. */
430#define mdata_vector_insert_sort( v, i, t, field )
431
432/* TODO: Implement sorting. */
433#define mdata_vector_sort( v, t, field )
434
435#define _mdata_vector_item_ptr( v, idx ) \
436 (&((v)->data_bytes[((idx) * ((v)->item_sz))]))
437
438#define mdata_vector_set_flag( v, flag ) (v)->flags |= (flag)
439
440#define mdata_vector_get_flag( v, flag ) ((flag) == ((v)->flags & (flag)))
441 /* mdata_vector */
443
448
449#define mdata_table_is_locked( t ) \
450 (mdata_vector_is_locked( &((t)->data_cols[0]) ))
451
452#define mdata_table_get( t, key, type ) \
453 ((type*)mdata_table_get_void( t, key ))
454
455#define mdata_table_hash_get( t, hash, sz, type ) \
456 ((type*)mdata_table_hash_get_void( t, hash, sz ))
457
458#define mdata_table_ct( t ) ((t)->data_cols[0].ct)
459
460#define mdata_table_sz( t ) \
461 mdata_vector_sz( &((t)->data_cols[0]) ) + \
462 mdata_vector_sz( &((t)->data_cols[1]) )
463 /* mdata_table */
465
466#define mdata_retval( idx ) (0 > idx ? ((idx) * -1) : MERROR_OK)
467
468#ifdef MDATA_C
469
471 struct MDATA_STRPOOL* sp, mdata_strpool_idx_t idx
472) {
473 MERROR_RETVAL retval = MERROR_OVERFLOW;
474 mdata_strpool_idx_t i = 0;
475 int autolock = 0;
476
477 if( !mdata_strpool_is_locked( sp ) ) {
478 mdata_strpool_lock( sp );
479 autolock = 1;
480 }
481
482 for( i = 0 ; sp->str_sz > i ; i += (size_t)*(&(sp->str_p[i])) ) {
483 if( idx == i ) {
484 retval = MERROR_OK;
485 goto cleanup;
486 }
487 }
488
489cleanup:
490
491 if( autolock ) {
492 mdata_strpool_unlock( sp );
493 }
494
495 return retval;
496}
497
498/* === */
499
500void mdata_strpool_dump( struct MDATA_STRPOOL* sp ) {
501 size_t i = 0;
502 char* strpool_p = NULL;
503
504 maug_mlock( sp->str_h, strpool_p );
505
506 for( i = 0 ; mdata_strpool_sz( sp ) > i ; i++ ) {
507 printf( "0x%02x ", strpool_p[i] );
508 }
509 printf( "\n" );
510
511 if( NULL != strpool_p ) {
512 maug_munlock( sp->str_h, strpool_p );
513 }
514}
515
516/* === */
517
518mdata_strpool_idx_t mdata_strpool_find(
519 struct MDATA_STRPOOL* strpool, const char* str, size_t str_sz
520) {
521 MERROR_RETVAL retval = MERROR_OK;
522 mdata_strpool_idx_t i = 0;
523 char* strpool_p = NULL;
524 size_t* p_str_iter_sz = NULL;
525
526 if( (MAUG_MHANDLE)NULL == strpool->str_h ) {
527 error_printf( "strpool not allocated!" );
528 i = 0;
529 goto cleanup;
530 }
531
532 maug_mlock( strpool->str_h, strpool_p );
533
534 while( i < strpool->str_sz ) {
535 p_str_iter_sz = (size_t*)&(strpool_p[i]);
536 if(
537 0 == maug_strncmp(
538 &(strpool_p[i + sizeof( size_t )]), str, str_sz + 1 )
539 ) {
540 /* String found. Advance past the size before returning. */
541 i += sizeof( size_t );
542#if MDATA_STRPOOL_TRACE_LVL > 0
543 debug_printf( MDATA_STRPOOL_TRACE_LVL,
544 "found strpool_idx: " SIZE_T_FMT " (" SIZE_T_FMT " bytes): \"%s\" "
545 "to match " SIZE_T_FMT "-byte token: %s",
546 i, *p_str_iter_sz, &(strpool_p[i]),
547 str_sz, str );
548#endif /* MDATA_STRPOOL_TRACE_LVL */
549
550 goto cleanup;
551#if MDATA_STRPOOL_TRACE_LVL > 0
552 } else {
553 debug_printf( MDATA_STRPOOL_TRACE_LVL,
554 "skipping strpool_idx: " SIZE_T_FMT " (" SIZE_T_FMT
555 " bytes): \"%s\"",
556 i + sizeof( size_t ), *p_str_iter_sz,
557 &(strpool_p[i + sizeof( size_t )]) );
558#endif /* MDATA_STRPOOL_TRACE_LVL */
559 }
560 i += *p_str_iter_sz;
561 }
562
563 /* String not found. */
564 i = 0;
565
566cleanup:
567
568 if( MERROR_OK != retval ) {
569 i = 0;
570 }
571
572 if( NULL != strpool_p ) {
573 maug_munlock( strpool->str_h, strpool_p );
574 }
575
576 return i;
577}
578
579/* === */
580
581MAUG_MHANDLE mdata_strpool_extract(
582 struct MDATA_STRPOOL* sp, mdata_strpool_idx_t idx
583) {
584 MERROR_RETVAL retval = MERROR_OK;
585 MAUG_MHANDLE out_h = (MAUG_MHANDLE)NULL;
586 size_t str_sz = 0;
587 char* out_tmp = NULL;
588 int autolock = 0;
589 char* str_src = NULL;
590
591 if( !mdata_strpool_is_locked( sp ) ) {
592 mdata_strpool_lock( sp );
593 autolock = 1;
594 }
595
596 str_src = mdata_strpool_get( sp, idx );
597 if( NULL == str_src ) {
598 error_printf( "invalid strpool index: " SSIZE_T_FMT, idx );
599 retval = MERROR_OVERFLOW;
600 goto cleanup;
601 }
602
603 str_sz = maug_strlen( str_src );
604
605 out_h = maug_malloc( str_sz + 1, 1 );
606 maug_cleanup_if_null_alloc( MAUG_MHANDLE, out_h );
607
608 maug_mlock( out_h, out_tmp );
609 maug_cleanup_if_null_lock( char*, out_tmp );
610
611 maug_mzero( out_tmp, str_sz + 1 );
612
613 /* memcpy is faster, here, since we know the allocated size was succesful.
614 */
615 memcpy( out_tmp, str_src, str_sz );
616
617cleanup:
618
619 if( NULL != out_tmp ) {
620 maug_munlock( out_h, out_tmp );
621 }
622
623 if( MERROR_OK != retval && (MAUG_MHANDLE)NULL != out_h ) {
624 maug_mfree( out_h );
625 }
626
627 if( autolock ) {
628 mdata_strpool_unlock( sp );
629 }
630
631 return out_h;
632}
633
634/* === */
635
636mdata_strpool_idx_t mdata_strpool_append(
637 struct MDATA_STRPOOL* strpool, const char* str, size_t str_sz, uint8_t flags
638) {
639 mdata_strpool_idx_t idx_p_out = 0;
640 char* strpool_p = NULL;
641 MERROR_RETVAL retval = MERROR_OK;
642 size_t* p_str_sz = NULL;
643 size_t alloc_sz = 0;
644
645 if( 0 == str_sz ) {
646 error_printf( "attempted to add zero-length string!" );
647 retval = MERROR_OVERFLOW;
648 goto cleanup;
649 }
650
651 if(
652 0 < strpool->str_sz &&
653 MDATA_STRPOOL_FLAG_DEDUPE == (MDATA_STRPOOL_FLAG_DEDUPE & flags)
654 ) {
655 /* Search the str_stable for an identical string and return that index.
656 */
657 idx_p_out = mdata_strpool_find( strpool, str, str_sz );
658 if( 0 < idx_p_out ) {
659 /* Found, or error returned. */
660#if MDATA_STRPOOL_TRACE_LVL > 0
661 debug_printf( MDATA_STRPOOL_TRACE_LVL,
662 "found duplicate string for add at index: " SSIZE_T_FMT,
663 idx_p_out );
664#endif /* MDATA_STRPOOL_TRACE_LVL */
665 goto cleanup;
666 }
667 }
668
669 /* Pad out allocated space so size_t is always aligned. */
670 alloc_sz = sizeof( size_t ) + str_sz + 1 /* NULL */ +
671 mdata_strpool_padding( str_sz );
672 assert( 0 == alloc_sz % sizeof( size_t ) );
673
674#if MDATA_STRPOOL_TRACE_LVL > 0
675 debug_printf( MDATA_STRPOOL_TRACE_LVL,
676 "adding size_t (" SIZE_T_FMT " bytes) + string %s (" SIZE_T_FMT
677 " bytes) + 1 NULL + " SIZE_T_FMT " bytes padding to strpool...",
678 sizeof( size_t ), str, str_sz, mdata_strpool_padding( str_sz ) );
679#endif /* MDATA_STRPOOL_TRACE_LVL */
680
681 retval = mdata_strpool_alloc( strpool, alloc_sz );
682 maug_cleanup_if_not_ok();
683
684 maug_mlock( strpool->str_h, strpool_p );
685 maug_cleanup_if_null_alloc( char*, strpool_p );
686
687#if MDATA_LOCK_TRACE_LVL > 0
688 debug_printf( MDATA_LOCK_TRACE_LVL,
689 "strpool (" SIZE_T_FMT " bytes) locked to: %p",
690 strpool->str_sz, strpool_p );
691#endif /* MDATA_LOCK_TRACE_LVL */
692
693 /* Add this string at the end of the string pool. */
694 maug_strncpy(
695 &(strpool_p[strpool->str_sz + sizeof( size_t )]), str, str_sz );
696 strpool_p[strpool->str_sz + sizeof( size_t ) + str_sz] = '\0';
697
698 /* Add the size of the string to the strpool. */
699 assert( 0 == strpool->str_sz % sizeof( size_t ) );
700 p_str_sz = (size_t*)&(strpool_p[strpool->str_sz]);
701 *p_str_sz = alloc_sz;
702
703 idx_p_out = strpool->str_sz + sizeof( size_t );
704
705#if MDATA_STRPOOL_TRACE_LVL > 0
706 debug_printf( MDATA_STRPOOL_TRACE_LVL,
707 "set strpool_idx: " SIZE_T_FMT ": \"%s\"",
708 strpool->str_sz, &(strpool_p[idx_p_out]) );
709#endif /* MDATA_STRPOOL_TRACE_LVL */
710
711 /* Set the string pool cursor to the next available spot. */
712 strpool->str_sz += alloc_sz;
713
714cleanup:
715
716 if( MERROR_OK != retval ) {
717 idx_p_out = 0;
718 }
719
720 if( NULL != strpool_p ) {
721 maug_munlock( strpool->str_h, strpool_p );
722 }
723
724 return idx_p_out;
725}
726
727/* === */
728
729MERROR_RETVAL mdata_strpool_alloc(
730 struct MDATA_STRPOOL* strpool, size_t alloc_sz
731) {
732 MERROR_RETVAL retval = MERROR_OK;
733 MAUG_MHANDLE str_h_new = (MAUG_MHANDLE)NULL;
734
735 if( (MAUG_MHANDLE)NULL == strpool->str_h ) {
736#if MDATA_STRPOOL_TRACE_LVL > 0
737 debug_printf(
738 MDATA_STRPOOL_TRACE_LVL,
739 "creating string pool of " SIZE_T_FMT " chars...",
740 alloc_sz );
741#endif /* MDATA_STRPOOL_TRACE_LVL */
742 assert( (MAUG_MHANDLE)NULL == strpool->str_h );
743 strpool->str_h = maug_malloc( alloc_sz, 1 );
744 maug_cleanup_if_null_alloc( MAUG_MHANDLE, strpool->str_h );
745 strpool->str_sz_max = alloc_sz;
746
747 } else if( strpool->str_sz_max <= strpool->str_sz + alloc_sz ) {
748 while( strpool->str_sz_max <= strpool->str_sz + alloc_sz ) {
749#if MDATA_STRPOOL_TRACE_LVL > 0
750 debug_printf(
751 MDATA_STRPOOL_TRACE_LVL,
752 "enlarging string pool to " SIZE_T_FMT "...",
753 strpool->str_sz_max * 2 );
754#endif /* MDATA_STRPOOL_TRACE_LVL */
755 maug_mrealloc_test(
756 str_h_new, strpool->str_h, strpool->str_sz_max, (size_t)2 );
757 strpool->str_sz_max *= 2;
758 }
759 }
760
761cleanup:
762 return retval;
763}
764
765/* === */
766
767void mdata_strpool_free( struct MDATA_STRPOOL* strpool ) {
768 if( (MAUG_MHANDLE)NULL != strpool->str_h ) {
769 maug_mfree( strpool->str_h );
770 }
771}
772
773/* === */
774
775ssize_t mdata_vector_append(
776 struct MDATA_VECTOR* v, const void* item, size_t item_sz
777) {
778 MERROR_RETVAL retval = MERROR_OK;
779 ssize_t idx_out = -1;
780
781 if( 0 < v->item_sz && item_sz != v->item_sz ) {
782 error_printf( "attempting to add item of " SIZE_T_FMT " bytes to vector, "
783 "but vector is already sized for " SIZE_T_FMT "-byte items!",
784 item_sz, v->item_sz );
785 retval = MERROR_OVERFLOW;
786 goto cleanup;
787 }
788
789 mdata_vector_alloc( v, item_sz, v->ct_step );
790
791 /* Lock the vector to work in it a bit. */
792 mdata_vector_lock( v );
793
794 idx_out = v->ct;
795
796 if( NULL != item ) {
797 /* Copy provided item. */
798#if MDATA_VECTOR_TRACE_LVL > 0
799 debug_printf(
800 MDATA_VECTOR_TRACE_LVL, "inserting into vector at index: " SIZE_T_FMT,
801 idx_out );
802#endif /* MDATA_VECTOR_TRACE_LVL */
803
804 memcpy( _mdata_vector_item_ptr( v, idx_out ), item, item_sz );
805 }
806
807 v->ct++;
808
809cleanup:
810
811 if( MERROR_OK != retval ) {
812 error_printf( "error adding to vector: %d", retval );
813 idx_out = retval * -1;
814 assert( 0 > idx_out );
815 }
816
817 mdata_vector_unlock( v );
818
819 return idx_out;
820}
821
822/* === */
823
824ssize_t mdata_vector_insert(
825 struct MDATA_VECTOR* v, const void* item, ssize_t idx, size_t item_sz
826) {
827 MERROR_RETVAL retval = MERROR_OK;
828 ssize_t i = 0;
829
830 assert( 0 <= idx );
831
832 if( 0 < v->item_sz && item_sz != v->item_sz ) {
833 error_printf( "attempting to add item of " SIZE_T_FMT " bytes to vector, "
834 "but vector is already sized for " SIZE_T_FMT "-byte items!",
835 item_sz, v->item_sz );
836 retval = MERROR_OVERFLOW;
837 goto cleanup;
838 }
839
840 if( idx > v->ct ) {
841 error_printf( "attempting to insert beyond end of vector!" );
842 retval = MERROR_OVERFLOW;
843 goto cleanup;
844 }
845
846 mdata_vector_alloc( v, item_sz, v->ct_step );
847
848 /* Lock the vector to work in it a bit. */
849 mdata_vector_lock( v );
850
851 for( i = v->ct ; idx < i ; i-- ) {
852#if MDATA_VECTOR_TRACE_LVL > 0
853 debug_printf( MDATA_VECTOR_TRACE_LVL,
854 "copying vector item " SSIZE_T_FMT " to " SSIZE_T_FMT "...",
855 i - 1, i );
856#endif /* MDATA_VECTOR_TRACE_LVL */
857 memcpy(
858 _mdata_vector_item_ptr( v, i ),
859 _mdata_vector_item_ptr( v, i - 1),
860 item_sz );
861 }
862
863#if MDATA_VECTOR_TRACE_LVL > 0
864 debug_printf(
865 MDATA_VECTOR_TRACE_LVL,
866 "inserting into vector at index: " SIZE_T_FMT, idx );
867#endif /* MDATA_VECTOR_TRACE_LVL */
868 if( NULL != item ) {
869 /* Copy provided item. */
870 memcpy( _mdata_vector_item_ptr( v, idx ), item, item_sz );
871 } else {
872 /* Just blank the given index. */
873 maug_mzero( _mdata_vector_item_ptr( v, idx ), item_sz );
874 }
875
876 v->ct++;
877
878cleanup:
879
880 if( MERROR_OK != retval ) {
881 error_printf( "error adding to vector: %d", retval );
882 idx = retval * -1;
883 assert( 0 > idx );
884 }
885
886 mdata_vector_unlock( v );
887
888 return idx;
889}
890
891/* === */
892
893MERROR_RETVAL mdata_vector_remove( struct MDATA_VECTOR* v, size_t idx ) {
894 MERROR_RETVAL retval = MERROR_OK;
895 size_t i = 0;
896
897 if( mdata_vector_is_locked( v ) ) {
898 error_printf( "vector cannot be resized while locked!" );
899 retval = MERROR_ALLOC;
900 goto cleanup;
901 }
902
903 if( v->ct <= idx ) {
904 error_printf( "index out of range!" );
905 retval = MERROR_OVERFLOW;
906 goto cleanup;
907 }
908
909#if MDATA_VECTOR_TRACE_LVL > 0
910 debug_printf( MDATA_VECTOR_TRACE_LVL,
911 "removing vector item: " SIZE_T_FMT, idx );
912#endif /* MDATA_VECTOR_TRACE_LVL */
913
914 assert( 0 < v->item_sz );
915
916 mdata_vector_lock( v );
917
918 for( i = idx ; v->ct > i + 1 ; i++ ) {
919#if MDATA_VECTOR_TRACE_LVL > 0
920 debug_printf( MDATA_VECTOR_TRACE_LVL,
921 "shifting " SIZE_T_FMT "-byte vector item " SIZE_T_FMT " up by 1...",
922 v->item_sz, i );
923#endif /* MDATA_VECTOR_TRACE_LVL */
924 memcpy(
925 &(v->data_bytes[i * v->item_sz]),
926 &(v->data_bytes[(i + 1) * v->item_sz]),
927 v->item_sz );
928 }
929
930 v->ct--;
931
932cleanup:
933
934 mdata_vector_unlock( v );
935
936 return retval;
937}
938
939/* === */
940
941void* mdata_vector_get_void( const struct MDATA_VECTOR* v, size_t idx ) {
942
943#if MDATA_VECTOR_TRACE_LVL > 0
944 debug_printf( MDATA_VECTOR_TRACE_LVL,
945 "getting vector item " SIZE_T_FMT " (of " SIZE_T_FMT ")...",
946 idx, v->ct );
947#endif /* MDATA_VECTOR_TRACE_LVL */
948
949 assert( 0 == v->ct || NULL != v->data_bytes );
950
951 if( idx >= v->ct ) {
952 return NULL;
953 } else {
954 return _mdata_vector_item_ptr( v, idx );
955 }
956}
957
958/* === */
959
960MERROR_RETVAL mdata_vector_copy(
961 struct MDATA_VECTOR* v_dest, struct MDATA_VECTOR* v_src
962) {
963 MERROR_RETVAL retval = MERROR_OK;
964
965 if( NULL != v_src->data_bytes ) {
966 error_printf( "vector cannot be copied while locked!" );
967 retval = MERROR_ALLOC;
968 goto cleanup;
969 }
970
971 assert( 0 < v_src->item_sz );
972 assert( 0 < v_src->ct_max );
973
974 v_dest->ct_max = v_src->ct_max;
975 v_dest->ct = v_src->ct;
976 v_dest->item_sz = v_src->item_sz;
977#if MDATA_VECTOR_TRACE_LVL > 0
978 debug_printf( MDATA_VECTOR_TRACE_LVL,
979 "copying " SIZE_T_FMT " vector of " SIZE_T_FMT "-byte nodes...",
980 v_src->ct_max, v_src->item_sz );
981#endif /* MDATA_VECTOR_TRACE_LVL */
982 assert( (MAUG_MHANDLE)NULL == v_dest->data_h );
983 v_dest->data_h = maug_malloc( v_src->ct_max, v_src->item_sz );
984 maug_cleanup_if_null_alloc( MAUG_MHANDLE, v_dest->data_h );
985
986 mdata_vector_lock( v_dest );
987 mdata_vector_lock( v_src );
988
989 memcpy( v_dest->data_bytes, v_src->data_bytes,
990 v_src->ct_max * v_src->item_sz );
991
992cleanup:
993
994 mdata_vector_unlock( v_src );
995 mdata_vector_unlock( v_dest );
996
997 return retval;
998}
999
1000/* === */
1001
1003 struct MDATA_VECTOR* v, size_t item_sz, size_t item_ct_init
1004) {
1005 MERROR_RETVAL retval = MERROR_OK;
1006 MAUG_MHANDLE data_h_new = (MAUG_MHANDLE)NULL;
1007 size_t new_ct = item_ct_init,
1008 new_bytes_start = 0,
1009 new_bytes_sz = 0;
1010
1011 if( NULL != v->data_bytes ) {
1012 error_printf( "vector cannot be resized while locked!" );
1013 retval = MERROR_ALLOC;
1014 goto cleanup;
1015 }
1016
1017 /* Make sure there are free nodes. */
1018 if( (MAUG_MHANDLE)NULL == v->data_h ) {
1019 assert( 0 == v->ct_max );
1020
1021 if( 0 < item_ct_init ) {
1022#if MDATA_VECTOR_TRACE_LVL > 0
1023 debug_printf( MDATA_VECTOR_TRACE_LVL, "setting step sz: " SIZE_T_FMT,
1024 item_ct_init );
1025#endif /* MDATA_VECTOR_TRACE_LVL */
1026 v->ct_step = item_ct_init;
1027 } else if( 0 == v->ct_step ) {
1028#if MDATA_VECTOR_TRACE_LVL > 0
1029 debug_printf( MDATA_VECTOR_TRACE_LVL, "setting step sz: %d",
1030 MDATA_VECTOR_INIT_STEP_SZ );
1031#endif /* MDATA_VECTOR_TRACE_LVL */
1032 v->ct_step = MDATA_VECTOR_INIT_STEP_SZ;
1033 }
1034 v->ct_max = v->ct_step;
1035#if MDATA_VECTOR_TRACE_LVL > 0
1036 debug_printf( MDATA_VECTOR_TRACE_LVL,
1037 "creating " SIZE_T_FMT " vector of " SIZE_T_FMT "-byte nodes...",
1038 v->ct_max, item_sz );
1039#endif /* MDATA_VECTOR_TRACE_LVL */
1040 assert( (MAUG_MHANDLE)NULL == v->data_h );
1041 v->data_h = maug_malloc( v->ct_max, item_sz );
1042 assert( 0 < item_sz );
1043 v->item_sz = item_sz;
1044 maug_cleanup_if_null_alloc( MAUG_MHANDLE, v->data_h );
1045
1046 /* Zero out the new space. */
1047 mdata_vector_lock( v );
1048 maug_mzero( v->data_bytes, v->ct_max * item_sz );
1049 mdata_vector_unlock( v );
1050
1051 } else if( v->ct_max <= v->ct + 1 || v->ct_max <= item_ct_init ) {
1052 assert( item_sz == v->item_sz );
1053
1054 /* Use ct * 2 or ct_init... whichever is larger! */
1055 if( item_ct_init < v->ct_max + v->ct_step ) {
1056 assert( v->ct_max + v->ct_step > v->ct_max );
1057 new_ct = v->ct_max + v->ct_step;
1058 }
1059
1060 /* Perform the resize. */
1061#if MDATA_VECTOR_TRACE_LVL > 0
1062 debug_printf( MDATA_VECTOR_TRACE_LVL,
1063 "enlarging vector to " SIZE_T_FMT "...",
1064 new_ct );
1065#endif /* MDATA_VECTOR_TRACE_LVL */
1066 maug_mrealloc_test( data_h_new, v->data_h, new_ct, item_sz );
1067
1068 /* Zero out the new space. */
1069 new_bytes_start = v->ct_max * v->item_sz;
1070 assert( new_bytes_start >= v->ct_max );
1071 new_bytes_sz = (new_ct * v->item_sz) - new_bytes_start;
1072 assert( new_bytes_sz >= v->item_sz );
1073 mdata_vector_lock( v );
1074 maug_mzero( &(v->data_bytes[new_bytes_start]), new_bytes_sz );
1075 mdata_vector_unlock( v );
1076
1077 v->ct_max = new_ct;
1078 }
1079
1080cleanup:
1081
1082 return retval;
1083}
1084
1085/* === */
1086
1087void mdata_vector_free( struct MDATA_VECTOR* v ) {
1088 if( 0 < v->ct_max ) {
1089 maug_mfree( v->data_h );
1090 }
1091 v->ct = 0;
1092 v->ct_max = 0;
1093 v->item_sz = 0;
1094}
1095
1096/* === */
1097
1098uint32_t mdata_hash( const char* token, size_t token_sz ) {
1099 uint32_t hash_out = 2166136261u; /* Arbitrary fixed prime. */
1100 size_t i = 0;
1101 char c = 0;
1102
1103 for( i = 0 ; token_sz > i ; i++ ) {
1104 c = token[i];
1105
1106 /* Case-insensitive. */
1107 if( 'A' <= c && 'Z' >= c ) {
1108 c += 32;
1109 }
1110
1111 hash_out ^= c;
1112 hash_out *= 16777619u;
1113 }
1114
1115 return hash_out;
1116}
1117
1118/* === */
1119
1120MERROR_RETVAL mdata_table_lock( struct MDATA_TABLE* t ) {
1121 MERROR_RETVAL retval = MERROR_OK;
1122
1123 mdata_vector_lock( &(t->data_cols[0]) );
1124 mdata_vector_lock( &(t->data_cols[1]) );
1125
1126cleanup:
1127
1128 /*
1129 if( MERROR_OK != retval ) {
1130 assert( !mdata_vector_is_locked( &(t->data_cols[0]) ) );
1131 }
1132 */
1133
1134 return retval;
1135}
1136
1137/* === */
1138
1139MERROR_RETVAL mdata_table_unlock( struct MDATA_TABLE* t ) {
1140 MERROR_RETVAL retval = MERROR_OK;
1141
1142 mdata_vector_unlock( &(t->data_cols[0]) );
1143 mdata_vector_unlock( &(t->data_cols[1]) );
1144
1145 if( MERROR_OK != retval ) {
1146 assert( mdata_vector_is_locked( &(t->data_cols[0]) ) );
1147 }
1148
1149 return retval;
1150}
1151
1152/* === */
1153
1154struct MDATA_TABLE_REPLACE_CADDY {
1155 struct MDATA_TABLE_KEY* key;
1156 void* data;
1157};
1158
1159/* === */
1160
1161ssize_t _mdata_table_hunt_index(
1162 const struct MDATA_TABLE* t,
1163 const char* key, uint32_t key_hash, size_t key_sz
1164) {
1165 struct MDATA_TABLE_KEY* key_iter = NULL;
1166 ssize_t i = -1;
1167
1168 if( 0 == mdata_table_ct( t ) ) {
1169 goto cleanup;
1170 }
1171
1172 assert( mdata_vector_is_locked( &(t->data_cols[0]) ) );
1173
1174 /* Hash the key to hunt for if provided. */
1175 if( NULL != key ) {
1176 key_sz = maug_strlen( key );
1177 if( MDATA_TABLE_KEY_SZ_MAX < key_sz ) {
1178 key_sz = MDATA_TABLE_KEY_SZ_MAX;
1179 }
1180 key_hash = mdata_hash( key, key_sz );
1181
1182#if MDATA_TABLE_TRACE_LVL > 0
1183 debug_printf( MDATA_TABLE_TRACE_LVL,
1184 "searching for key: %s (%u)", key, key_hash );
1185#endif /* MDATA_TABLE_TRACE_LVL */
1186 }
1187
1188 /* Compare the key to what we have. */
1189 /* TODO: Divide and conquer! */
1190 for( i = 0 ; mdata_vector_ct( &(t->data_cols[0]) ) > i ; i++ ) {
1191 key_iter = mdata_vector_get(
1192 &(t->data_cols[0]), i, struct MDATA_TABLE_KEY );
1193 assert( NULL != key );
1194 if(
1195 key_iter->hash == key_hash &&
1196 key_iter->string_sz == key_sz
1197 ) {
1198#if MDATA_TABLE_TRACE_LVL > 0
1199 debug_printf( MDATA_TABLE_TRACE_LVL, "found value for key: %s", key );
1200#endif /* MDATA_TABLE_TRACE_LVL */
1201 return i;
1202 }
1203 }
1204
1205cleanup:
1206
1207 return -1;
1208}
1209
1210/* === */
1211
1212static MERROR_RETVAL _mdata_table_replace(
1213 const struct MDATA_TABLE_KEY* key, void* data, size_t data_sz,
1214 void* cb_data, size_t cb_data_sz, size_t idx
1215) {
1216 MERROR_RETVAL retval = MERROR_OK;
1217 struct MDATA_TABLE_REPLACE_CADDY* caddy =
1218 (struct MDATA_TABLE_REPLACE_CADDY*)cb_data;
1219
1220 if(
1221 key->hash == caddy->key->hash && key->string_sz == caddy->key->string_sz
1222 ) {
1223#if MDATA_TABLE_TRACE_LVL > 0
1224 debug_printf( MDATA_TABLE_TRACE_LVL,
1225 "replacing table data for key %s (%u)...", key->string, key->hash );
1226#endif /* MDATA_TABLE_TRACE_LVL */
1227 memcpy( data, caddy->data, data_sz );
1228 retval = MERROR_FILE;
1229 }
1230
1231 return retval;
1232}
1233
1234/* === */
1235
1236MERROR_RETVAL mdata_table_iter(
1237 struct MDATA_TABLE* t,
1238 mdata_table_iter_t cb, void* cb_data, size_t cb_data_sz
1239) {
1240 MERROR_RETVAL retval = MERROR_OK;
1241 size_t i = 0;
1242 int autolock = 0;
1243 struct MDATA_TABLE_KEY* p_key = NULL;
1244 char* p_value = NULL;
1245
1246 if( 0 == mdata_table_ct( t ) ) {
1247 return MERROR_OK;
1248 }
1249
1250 if( !mdata_table_is_locked( t ) ) {
1251#if MDATA_LOCK_TRACE_LVL > 0
1252 debug_printf( MDATA_LOCK_TRACE_LVL, "engaging table autolock..." );
1253#endif /* MDATA_LOCK_TRACE_LVL */
1254 mdata_table_lock( t );
1255 autolock = 1;
1256 }
1257
1258 /* Execute the callback for every item. */
1259 for( i = 0 ; mdata_table_ct( t ) > i ; i++ ) {
1260 p_key = mdata_vector_get_void( &(t->data_cols[0]), i );
1261 assert( NULL != p_key );
1262 assert( 0 < p_key->string_sz );
1263 assert( p_key->string_sz == maug_strlen( p_key->string ) );
1264 p_value = mdata_vector_get_void( &(t->data_cols[1]), i );
1265 retval = cb(
1266 p_key, p_value, t->data_cols[1].item_sz, cb_data, cb_data_sz, i );
1267 maug_cleanup_if_not_ok();
1268 }
1269
1270cleanup:
1271
1272 if( autolock ) {
1273 mdata_table_unlock( t );
1274 }
1275
1276 return retval;
1277}
1278
1279/* === */
1280
1281MERROR_RETVAL mdata_table_set(
1282 struct MDATA_TABLE* t, const char* key,
1283 void* value, size_t value_sz
1284) {
1285 MERROR_RETVAL retval = MERROR_OK;
1286 ssize_t idx_key = -1;
1287 ssize_t idx_val = -1;
1288 struct MDATA_TABLE_KEY key_tmp;
1289 struct MDATA_TABLE_REPLACE_CADDY caddy;
1290
1291 assert( 0 < maug_strlen( key ) );
1292
1293 assert( !mdata_table_is_locked( t ) );
1294
1295 assert(
1296 mdata_vector_ct( &(t->data_cols[0]) ) ==
1297 mdata_vector_ct( &(t->data_cols[1]) ) );
1298
1299 /* Get key hash and properties. */
1300 maug_mzero( &key_tmp, sizeof( struct MDATA_TABLE_KEY ) );
1301 maug_strncpy( key_tmp.string, key, MDATA_TABLE_KEY_SZ_MAX );
1302 if( maug_strlen( key ) > MDATA_TABLE_KEY_SZ_MAX + 1 ) {
1303 error_printf(
1304 "key %s is longer than maximum key size! truncating to: %s",
1305 key, key_tmp.string );
1306 }
1307 key_tmp.string_sz = strlen( key_tmp.string );
1308 key_tmp.hash = mdata_hash( key_tmp.string, key_tmp.string_sz );
1309
1310#if MDATA_TABLE_TRACE_LVL > 0
1311 debug_printf( MDATA_TABLE_TRACE_LVL,
1312 "attempting to set key %s (%u) to " SIZE_T_FMT "-byte value...",
1313 key_tmp.string, key_tmp.hash, value_sz );
1314#endif /* MDATA_TABLE_TRACE_LVL */
1315
1316 caddy.key = &key_tmp;
1317 caddy.data = value;
1318
1319 /* Search for the hash. */
1320 /* TODO: Use quicker search. */
1321 retval = mdata_table_iter( t, _mdata_table_replace, &caddy,
1322 sizeof( struct MDATA_TABLE_REPLACE_CADDY ) );
1323 if( MERROR_FILE == retval ) {
1324 /* _mdata_table_replace returned that it replaced an item, so quit. */
1325 retval = MERROR_OK;
1326 goto cleanup;
1327 }
1328
1329 /* TODO: Insert in hash order. */
1330
1331 idx_key = mdata_vector_append(
1332 &(t->data_cols[0]), &key_tmp, sizeof( struct MDATA_TABLE_KEY ) );
1333 if( 0 > idx_key ) {
1334 error_printf( "error appending table key: %d", idx_key );
1335 retval = merror_sz_to_retval( idx_key );
1336 }
1337
1338 /* TODO: Atomicity: remove key if value fails! */
1339
1340 idx_val = mdata_vector_append( &(t->data_cols[1]), value, value_sz );
1341 assert( 0 <= idx_val );
1342 if( 0 > idx_val ) {
1343 error_printf( "error appending table value: %d", idx_val );
1344 retval = merror_sz_to_retval( idx_val );
1345 }
1346
1347cleanup:
1348
1349 /* TODO: Set retval! */
1350
1351 return retval;
1352}
1353
1354/* === */
1355
1356MERROR_RETVAL mdata_table_unset(
1357 struct MDATA_TABLE* t, const char* key
1358) {
1359 MERROR_RETVAL retval = MERROR_OK;
1360 int autolock = 0;
1361 ssize_t idx = 0;
1362
1363#if MDATA_TABLE_TRACE_LVL > 0
1364 debug_printf( MDATA_TABLE_TRACE_LVL, "unsetting table key: %s", key );
1365#endif /* MDATA_TABLE_TRACE_LVL */
1366
1367 /* Autolock is fine to have for unset, as there is no returned pointer to
1368 * preserve.
1369 */
1370 if( !mdata_table_is_locked( t ) ) {
1371#if MDATA_LOCK_TRACE_LVL > 0
1372 debug_printf( MDATA_LOCK_TRACE_LVL, "autolocking table vectors" );
1373#endif /* MDATA_LOCK_TRACE_LVL */
1374 assert( !mdata_vector_is_locked( &(t->data_cols[0]) ) );
1375 assert( !mdata_vector_is_locked( &(t->data_cols[1]) ) );
1376 mdata_table_lock( t );
1377 autolock = 1;
1378 }
1379
1380 idx = _mdata_table_hunt_index( t, key, 0, 0 );
1381 if( 0 > idx ) {
1382 goto cleanup;
1383 }
1384
1385 /* Remove the item. */
1386 mdata_table_unlock( t );
1387 mdata_vector_remove( &(t->data_cols[0]), idx );
1388 mdata_vector_remove( &(t->data_cols[1]), idx );
1389
1390cleanup:
1391
1392 if( autolock && mdata_table_is_locked( t ) ) {
1393 mdata_table_unlock( t );
1394 } else if( !autolock && !mdata_table_is_locked( t ) ) {
1395 mdata_table_lock( t );
1396 }
1397
1398 return retval;
1399}
1400
1401/* === */
1402
1403void* mdata_table_get_void( const struct MDATA_TABLE* t, const char* key ) {
1404 MERROR_RETVAL retval = MERROR_OK;
1405 void* value_out = NULL;
1406 ssize_t idx = 0;
1407
1408 assert( mdata_table_is_locked( t ) );
1409
1410 idx = _mdata_table_hunt_index( t, key, 0, 0 );
1411 if( 0 > idx ) {
1412 retval = MERROR_OVERFLOW;
1413 goto cleanup;
1414 }
1415
1416 value_out = mdata_vector_get_void( &(t->data_cols[1]), idx );
1417
1418cleanup:
1419
1420 if( MERROR_OK != retval ) {
1421 value_out = NULL;
1422 }
1423
1424 return value_out;
1425}
1426
1427/* === */
1428
1429void* mdata_table_hash_get_void(
1430 struct MDATA_TABLE* t, uint32_t key_hash, size_t key_sz
1431) {
1432 MERROR_RETVAL retval = MERROR_OK;
1433 void* value_out = NULL;
1434 ssize_t idx = 0;
1435
1436 assert( mdata_table_is_locked( t ) );
1437
1438#if MDATA_TABLE_TRACE_LVL > 0
1439 debug_printf( MDATA_TABLE_TRACE_LVL,
1440 "searching for hash %u (" SIZE_T_FMT ")", key_hash, key_sz );
1441#endif /* MDATA_TABLE_TRACE_LVL */
1442
1443 idx = _mdata_table_hunt_index( t, NULL, key_hash, key_sz );
1444 if( 0 > idx ) {
1445 retval = MERROR_OVERFLOW;
1446 goto cleanup;
1447 }
1448
1449 value_out = mdata_vector_get_void( &(t->data_cols[1]), idx );
1450
1451cleanup:
1452
1453 if( MERROR_OK != retval ) {
1454 value_out = NULL;
1455 }
1456
1457 return value_out;
1458}
1459
1460/* === */
1461
1462void mdata_table_free( struct MDATA_TABLE* t ) {
1463 mdata_vector_free( &(t->data_cols[0]) );
1464 mdata_vector_free( &(t->data_cols[1]) );
1465 maug_mzero( t, sizeof( struct MDATA_TABLE ) );
1466}
1467
1468#endif /* MDATA_C */
1469 /* maug_data */
1471
1472#endif /* MDATA_H */
1473
uint16_t MERROR_RETVAL
Return type indicating function returns a value from this list.
Definition merror.h:28
MAUG_MHANDLE mdata_strpool_extract(struct MDATA_STRPOOL *sp, mdata_strpool_idx_t idx)
Return a dynamically-allocated memory handle containing the contents of the string at the given index...
MERROR_RETVAL mdata_strpool_check_idx(struct MDATA_STRPOOL *sp, mdata_strpool_idx_t idx)
Verify if the given mdata_strpool_idx_t is valid in the given strpool.
ssize_t mdata_vector_append(struct MDATA_VECTOR *v, const void *item, size_t item_sz)
Append an item to the specified vector.
MERROR_RETVAL mdata_vector_remove(struct MDATA_VECTOR *v, size_t idx)
Remove item at the given index, shifting subsequent items up by 1.
void * mdata_vector_get_void(const struct MDATA_VECTOR *v, size_t idx)
Get a generic pointer to an item in the MDATA_VECTOR.
MERROR_RETVAL mdata_vector_alloc(struct MDATA_VECTOR *v, size_t item_sz, size_t item_ct_init)
A pool of immutable text strings. Deduplicates strings to save memory.
Definition mdata.h:80
Definition mdata.h:133
Definition mdata.h:139
A vector of uniformly-sized objects, stored contiguously.
Definition mdata.h:105
size_t ct_step
Number of items added when more space is needed.
Definition mdata.h:116
MAUG_MHANDLE data_h
Handle for allocated items (unlocked).
Definition mdata.h:108
size_t item_sz
Size, in bytes, of each item.
Definition mdata.h:121
size_t ct
Maximum number of items actually used.
Definition mdata.h:114
uint8_t * data_bytes
Handle for allocated items (locked).
Definition mdata.h:110
size_t ct_max
Maximum number of items currently allocated for.
Definition mdata.h:112
ssize_t locks
Lock count, if MDATA_VECTOR_FLAG_REFCOUNT is enabled.
Definition mdata.h:123