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