maug
Quick and dirty C mini-augmentation library.
mdata.h
Go to the documentation of this file.
1
2#ifndef MDATA_H
3#define MDATA_H
4
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
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
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
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
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
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
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
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
265MERROR_RETVAL 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
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
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
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
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. */
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
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. */
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
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
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",
1152#endif /* MDATA_VECTOR_TRACE_LVL */
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 );
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 );
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
1258MERROR_RETVAL mdata_table_unlock( struct MDATA_TABLE* t ) {
1259 MERROR_RETVAL retval = MERROR_OK;
1260
1261 mdata_vector_unlock( &(t->data_cols[0]) );
1262 mdata_vector_unlock( &(t->data_cols[1]) );
1263
1264 if( MERROR_OK != retval ) {
1265 assert( mdata_vector_is_locked( &(t->data_cols[0]) ) );
1266 }
1267
1268 return retval;
1269}
1270
1271/* === */
1272
1273struct MDATA_TABLE_REPLACE_CADDY {
1274 struct MDATA_TABLE_KEY* key;
1275 void* data;
1276};
1277
1278/* === */
1279
1280ssize_t _mdata_table_hunt_index(
1281 const struct MDATA_TABLE* t,
1282 const char* key, uint32_t key_hash, size_t key_sz
1283) {
1284 struct MDATA_TABLE_KEY* key_iter = NULL;
1285 ssize_t i = -1;
1286
1287 if( 0 == mdata_table_ct( t ) ) {
1288 goto cleanup;
1289 }
1290
1291 assert( mdata_vector_is_locked( &(t->data_cols[0]) ) );
1292
1293 /* Hash the key to hunt for if provided. */
1294 if( NULL != key ) {
1295 key_sz = maug_strlen( key );
1296 if( MDATA_TABLE_KEY_SZ_MAX < key_sz ) {
1297 key_sz = MDATA_TABLE_KEY_SZ_MAX;
1298 }
1299 key_hash = mdata_hash( key, key_sz );
1300
1301#if MDATA_TABLE_TRACE_LVL > 0
1302 debug_printf( MDATA_TABLE_TRACE_LVL,
1303 "searching for key: %s (%u)", key, key_hash );
1304#endif /* MDATA_TABLE_TRACE_LVL */
1305 }
1306
1307 /* Compare the key to what we have. */
1308 /* TODO: Divide and conquer! */
1309 for( i = 0 ; mdata_vector_ct( &(t->data_cols[0]) ) > i ; i++ ) {
1310 key_iter = mdata_vector_get(
1311 &(t->data_cols[0]), i, struct MDATA_TABLE_KEY );
1312 assert( NULL != key );
1313 if(
1314 key_iter->hash == key_hash &&
1315 key_iter->string_sz == key_sz
1316 ) {
1317#if MDATA_TABLE_TRACE_LVL > 0
1318 debug_printf( MDATA_TABLE_TRACE_LVL, "found value for key: %s", key );
1319#endif /* MDATA_TABLE_TRACE_LVL */
1320 return i;
1321 }
1322 }
1323
1324cleanup:
1325
1326 return -1;
1327}
1328
1329/* === */
1330
1331static MERROR_RETVAL _mdata_table_replace(
1332 const struct MDATA_TABLE_KEY* key, void* data, size_t data_sz,
1333 void* cb_data, size_t cb_data_sz, size_t idx
1334) {
1335 MERROR_RETVAL retval = MERROR_OK;
1336 struct MDATA_TABLE_REPLACE_CADDY* caddy =
1337 (struct MDATA_TABLE_REPLACE_CADDY*)cb_data;
1338
1339 if(
1340 key->hash == caddy->key->hash && key->string_sz == caddy->key->string_sz
1341 ) {
1342#if MDATA_TABLE_TRACE_LVL > 0
1343 debug_printf( MDATA_TABLE_TRACE_LVL,
1344 "replacing table data for key %s (%u)...", key->string, key->hash );
1345#endif /* MDATA_TABLE_TRACE_LVL */
1346 memcpy( data, caddy->data, data_sz );
1347 retval = MERROR_FILE;
1348 }
1349
1350 return retval;
1351}
1352
1353/* === */
1354
1355MERROR_RETVAL mdata_table_iter(
1356 struct MDATA_TABLE* t,
1357 mdata_table_iter_t cb, void* cb_data, size_t cb_data_sz
1358) {
1359 MERROR_RETVAL retval = MERROR_OK;
1360 size_t i = 0;
1361 int autolock = 0;
1362 struct MDATA_TABLE_KEY* p_key = NULL;
1363 char* p_value = NULL;
1364
1365 if( 0 == mdata_table_ct( t ) ) {
1366 return MERROR_OK;
1367 }
1368
1369 if( !mdata_table_is_locked( t ) ) {
1370#if MDATA_LOCK_TRACE_LVL > 0
1371 debug_printf( MDATA_LOCK_TRACE_LVL, "engaging table autolock..." );
1372#endif /* MDATA_LOCK_TRACE_LVL */
1373 mdata_table_lock( t );
1374 autolock = 1;
1375 }
1376
1377 /* Execute the callback for every item. */
1378 for( i = 0 ; mdata_table_ct( t ) > i ; i++ ) {
1379 p_key = mdata_vector_get_void( &(t->data_cols[0]), i );
1380 assert( NULL != p_key );
1381 assert( 0 < p_key->string_sz );
1382 assert( p_key->string_sz == maug_strlen( p_key->string ) );
1383 p_value = mdata_vector_get_void( &(t->data_cols[1]), i );
1384 retval = cb(
1385 p_key, p_value, t->data_cols[1].item_sz, cb_data, cb_data_sz, i );
1386 maug_cleanup_if_not_ok();
1387 }
1388
1389cleanup:
1390
1391 if( autolock ) {
1392 mdata_table_unlock( t );
1393 }
1394
1395 return retval;
1396}
1397
1398/* === */
1399
1400MERROR_RETVAL mdata_table_set(
1401 struct MDATA_TABLE* t, const char* key,
1402 void* value, size_t value_sz
1403) {
1404 MERROR_RETVAL retval = MERROR_OK;
1405 ssize_t idx_key = -1;
1406 ssize_t idx_val = -1;
1407 struct MDATA_TABLE_KEY key_tmp;
1408 struct MDATA_TABLE_REPLACE_CADDY caddy;
1409
1410 assert( 0 < maug_strlen( key ) );
1411
1412 assert( !mdata_table_is_locked( t ) );
1413
1414 assert(
1415 mdata_vector_ct( &(t->data_cols[0]) ) ==
1416 mdata_vector_ct( &(t->data_cols[1]) ) );
1417
1418 /* Get key hash and properties. */
1419 maug_mzero( &key_tmp, sizeof( struct MDATA_TABLE_KEY ) );
1420 maug_strncpy( key_tmp.string, key, MDATA_TABLE_KEY_SZ_MAX );
1421 if( maug_strlen( key ) > MDATA_TABLE_KEY_SZ_MAX + 1 ) {
1422 error_printf(
1423 "key %s is longer than maximum key size! truncating to: %s",
1424 key, key_tmp.string );
1425 }
1426 key_tmp.string_sz = strlen( key_tmp.string );
1427 key_tmp.hash = mdata_hash( key_tmp.string, key_tmp.string_sz );
1428
1429#if MDATA_TABLE_TRACE_LVL > 0
1430 debug_printf( MDATA_TABLE_TRACE_LVL,
1431 "attempting to set key %s (%u) to " SIZE_T_FMT "-byte value...",
1432 key_tmp.string, key_tmp.hash, value_sz );
1433#endif /* MDATA_TABLE_TRACE_LVL */
1434
1435 caddy.key = &key_tmp;
1436 caddy.data = value;
1437
1438 /* Search for the hash. */
1439 /* TODO: Use quicker search. */
1440 retval = mdata_table_iter( t, _mdata_table_replace, &caddy,
1441 sizeof( struct MDATA_TABLE_REPLACE_CADDY ) );
1442 if( MERROR_FILE == retval ) {
1443 /* _mdata_table_replace returned that it replaced an item, so quit. */
1444 retval = MERROR_OK;
1445 goto cleanup;
1446 }
1447
1448 /* TODO: Insert in hash order. */
1449
1450 idx_key = mdata_vector_append(
1451 &(t->data_cols[0]), &key_tmp, sizeof( struct MDATA_TABLE_KEY ) );
1452 if( 0 > idx_key ) {
1453 error_printf( "error appending table key: %d", idx_key );
1454 retval = merror_sz_to_retval( idx_key );
1455 }
1456
1457 /* TODO: Atomicity: remove key if value fails! */
1458
1459 idx_val = mdata_vector_append( &(t->data_cols[1]), value, value_sz );
1460 assert( 0 <= idx_val );
1461 if( 0 > idx_val ) {
1462 error_printf( "error appending table value: %d", idx_val );
1463 retval = merror_sz_to_retval( idx_val );
1464 }
1465
1466cleanup:
1467
1468 /* TODO: Set retval! */
1469
1470 return retval;
1471}
1472
1473/* === */
1474
1475MERROR_RETVAL mdata_table_unset(
1476 struct MDATA_TABLE* t, const char* key
1477) {
1478 MERROR_RETVAL retval = MERROR_OK;
1479 int autolock = 0;
1480 ssize_t idx = 0;
1481
1482#if MDATA_TABLE_TRACE_LVL > 0
1483 debug_printf( MDATA_TABLE_TRACE_LVL, "unsetting table key: %s", key );
1484#endif /* MDATA_TABLE_TRACE_LVL */
1485
1486 /* Autolock is fine to have for unset, as there is no returned pointer to
1487 * preserve.
1488 */
1489 if( !mdata_table_is_locked( t ) ) {
1490#if MDATA_LOCK_TRACE_LVL > 0
1491 debug_printf( MDATA_LOCK_TRACE_LVL, "autolocking table vectors" );
1492#endif /* MDATA_LOCK_TRACE_LVL */
1493 assert( !mdata_vector_is_locked( &(t->data_cols[0]) ) );
1494 assert( !mdata_vector_is_locked( &(t->data_cols[1]) ) );
1495 mdata_table_lock( t );
1496 autolock = 1;
1497 }
1498
1499 idx = _mdata_table_hunt_index( t, key, 0, 0 );
1500 if( 0 > idx ) {
1501 goto cleanup;
1502 }
1503
1504 /* Remove the item. */
1505 mdata_table_unlock( t );
1506 mdata_vector_remove( &(t->data_cols[0]), idx );
1507 mdata_vector_remove( &(t->data_cols[1]), idx );
1508
1509cleanup:
1510
1511 if( autolock && mdata_table_is_locked( t ) ) {
1512 mdata_table_unlock( t );
1513 } else if( !autolock && !mdata_table_is_locked( t ) ) {
1514 mdata_table_lock( t );
1515 }
1516
1517 return retval;
1518}
1519
1520/* === */
1521
1522void* mdata_table_get_void( const struct MDATA_TABLE* t, const char* key ) {
1523 MERROR_RETVAL retval = MERROR_OK;
1524 void* value_out = NULL;
1525 ssize_t idx = 0;
1526
1527 assert( mdata_table_is_locked( t ) );
1528
1529 idx = _mdata_table_hunt_index( t, key, 0, 0 );
1530 if( 0 > idx ) {
1531 retval = MERROR_OVERFLOW;
1532 goto cleanup;
1533 }
1534
1535 value_out = mdata_vector_get_void( &(t->data_cols[1]), idx );
1536
1537cleanup:
1538
1539 if( MERROR_OK != retval ) {
1540 value_out = NULL;
1541 }
1542
1543 return value_out;
1544}
1545
1546/* === */
1547
1548void* mdata_table_hash_get_void(
1549 struct MDATA_TABLE* t, uint32_t key_hash, size_t key_sz
1550) {
1551 MERROR_RETVAL retval = MERROR_OK;
1552 void* value_out = NULL;
1553 ssize_t idx = 0;
1554
1555 assert( mdata_table_is_locked( t ) );
1556
1557#if MDATA_TABLE_TRACE_LVL > 0
1558 debug_printf( MDATA_TABLE_TRACE_LVL,
1559 "searching for hash %u (" SIZE_T_FMT ")", key_hash, key_sz );
1560#endif /* MDATA_TABLE_TRACE_LVL */
1561
1562 idx = _mdata_table_hunt_index( t, NULL, key_hash, key_sz );
1563 if( 0 > idx ) {
1564 retval = MERROR_OVERFLOW;
1565 goto cleanup;
1566 }
1567
1568 value_out = mdata_vector_get_void( &(t->data_cols[1]), idx );
1569
1570cleanup:
1571
1572 if( MERROR_OK != retval ) {
1573 value_out = NULL;
1574 }
1575
1576 return value_out;
1577}
1578
1579/* === */
1580
1581void mdata_table_free( struct MDATA_TABLE* t ) {
1582 mdata_vector_free( &(t->data_cols[0]) );
1583 mdata_vector_free( &(t->data_cols[1]) );
1584 maug_mzero( t, sizeof( struct MDATA_TABLE ) );
1585}
1586
1587#endif /* MDATA_C */
1588 /* maug_data */
1590
1591#endif /* MDATA_H */
1592
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
#define mdata_vector_lock(v)
Lock the vector. This should be done when items from the vector are actively being referenced,...
Definition: mdata.h:372
size_t ct_step
Number of items added when more space is needed.
Definition: mdata.h:119
#define mdata_vector_unlock(v)
Unlock the vector so items may be added and removed.
Definition: mdata.h:405
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
#define mdata_vector_ct(v)
Number of items of MDATA_VECTOR::item_sz bytes actively stored in this vector.
Definition: mdata.h:448
#define MDATA_VECTOR_INIT_STEP_SZ
Default initial value for MDATA_VECTOR::ct_step.
Definition: mdata.h:55
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