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