00001
00004 #include "dt_node.h"
00005
00006 #include "dt_node_impl.h"
00007
00008 #include <assert.h>
00009 #include <stdlib.h>
00010 #include <string.h>
00011
00012
00013 #ifndef NDEBUG
00014
00015 unsigned dt_node_instance_count = 0;
00016 #endif
00017
00018
00019
00020 dt_bool dt_node_is_valid( dt_node const* node )
00021 {
00022 if( ! node ) return 0;
00023
00024 if( node->refs <= 0 )
00025 return 0;
00026
00027 switch( node->kind )
00028 {
00029 default: return 0;
00030 case dt_leaf_node: break;
00031 case dt_arr_node: {
00032 if( (node->buf.strEnd - node->buf.begin)%sizeof(arr_item) ) return 0;
00033 break;
00034 }
00035 case dt_rec_node: {
00036 if( (node->buf.strEnd - node->buf.begin)%sizeof(rec_item) ) return 0;
00037 break;
00038 }
00039 }
00040 return 1;
00041 }
00042
00043
00044 dt_node* dt_make_leaf( dt_byte const* begin, size_t len )
00045 {
00046 dt_node* ans = (dt_node*)malloc(sizeof(dt_node));
00047 if( !! ans )
00048 {
00049 ans->kind = dt_leaf_node;
00050 ans->refs = 1;
00051 if( dt_buf_init_data( & ans->buf, begin, len ) )
00052 {
00053 #ifndef NDEBUG
00054 ++ dt_node_instance_count;
00055 #endif
00056 return ans;
00057 }
00058 free(ans);
00059 }
00060 return 00;
00061 }
00062
00063 dt_node* dt_make_rec()
00064 {
00065 dt_node* ans = (dt_node*)malloc(sizeof(dt_node));
00066 if( !! ans )
00067 {
00068 ans->kind = dt_rec_node;
00069 ans->refs = 1;
00070 if( dt_buf_init( & ans->buf ) )
00071 {
00072 #ifndef NDEBUG
00073 ++ dt_node_instance_count;
00074 #endif
00075 return ans;
00076 }
00077 free(ans);
00078 }
00079 return 00;
00080 }
00081
00082 dt_node* dt_make_arr()
00083 {
00084 dt_node* ans = (dt_node*)malloc(sizeof(dt_node));
00085 if( !! ans )
00086 {
00087 ans->kind = dt_arr_node;
00088 ans->refs = 1;
00089 if( dt_buf_init( & ans->buf ) )
00090 {
00091 #ifndef NDEBUG
00092 ++ dt_node_instance_count;
00093 #endif
00094 return ans;
00095 }
00096 free(ans);
00097 }
00098 return 00;
00099 }
00100
00101
00102 void dt_node_addref( dt_node* node )
00103 {
00104 if( ! node ) return;
00105
00106 assert( dt_node_is_valid(node) );
00107 ++ node->refs;
00108 assert( node->refs != 0 );
00109 }
00110
00111 void dt_node_release( dt_node* node )
00112 {
00113 if( ! node ) return;
00114
00115 assert( dt_node_is_valid(node) );
00116
00117 if( 0 < --node->refs )
00118 return;
00119 switch( node->kind )
00120 {
00121 default: assert( 00 ); return;
00122 case dt_leaf_node: break;
00123 case dt_arr_node: {
00124 arr_item *scan, *end;
00125 assert( (node->buf.strEnd - node->buf.begin)%sizeof(arr_item) == 0 );
00126 scan = (arr_item*)node->buf.begin;
00127 end = (arr_item*)node->buf.strEnd;
00128 for( ; scan != end ; ++scan )
00129 dt_node_release( *scan );
00130 }
00131 break;
00132 case dt_rec_node: {
00133 rec_item *scan, *end;
00134 assert( (node->buf.strEnd - node->buf.begin)%sizeof(rec_item) == 0 );
00135 scan = (rec_item*)node->buf.begin;
00136 end = (rec_item*)node->buf.strEnd;
00137 for( ; scan != end ; ++scan )
00138 {
00139 free( scan->key );
00140 dt_node_release( scan->node );
00141 }
00142 }
00143 break;
00144 }
00145 dt_buf_free( & node->buf );
00146 free( node );
00147 #ifndef NDEBUG
00148 -- dt_node_instance_count;
00149 #endif
00150 }
00151
00152 enum dt_node_kind dt_node_get_kind( dt_node* node )
00153 {
00154 assert( dt_node_is_valid(node) );
00155 return node->kind;
00156 }
00157
00158
00159 dt_bool dt_leaf_get_data( dt_node const* node, dt_byte const** begin, size_t* len )
00160 {
00161 if( ! node ) return 0;
00162
00163 assert( dt_node_is_valid(node) );
00164
00165 if( node->kind != dt_leaf_node )
00166 return 0;
00167 *begin = node->buf.begin;
00168 *len = node->buf.strEnd - *begin;
00169 return 1;
00170 }
00171
00172
00173 size_t dt_arr_get_size( dt_node const* arr )
00174 {
00175 if( ! arr || arr->kind != dt_arr_node )
00176 return 0;
00177
00178 assert( dt_node_is_valid(arr) );
00179
00180 return (arr->buf.strEnd - arr->buf.begin) / sizeof(arr_item);
00181 }
00182
00183 dt_node* dt_arr_get( dt_node const* arr, unsigned ind )
00184 {
00185 if( ! arr ) return 00;
00186
00187 assert( dt_node_is_valid(arr) );
00188
00189 if( arr->kind != dt_arr_node
00190 || ind >= (arr->buf.strEnd - arr->buf.begin)/sizeof(arr_item)
00191 ) return 00;
00192 return ((arr_item*)arr->buf.begin)[ind];
00193 }
00194
00195 dt_bool dt_arr_put( dt_node* arr, unsigned ind, dt_node* item )
00196 {
00197 arr_item* pos;
00198
00199 if( ! item )
00200 return 0;
00201
00202 assert( !arr || dt_node_is_valid(arr) );
00203 assert( dt_node_is_valid(item) );
00204
00205 if( ! arr
00206 || arr->kind != dt_arr_node
00207 || ind >= (arr->buf.strEnd - arr->buf.begin)/sizeof(arr_item)
00208 )
00209 {
00210 dt_node_release(item);
00211 return 0;
00212 }
00213 pos = ((arr_item*)arr->buf.begin) + ind;
00214 dt_node_release( *pos );
00215 *pos = item;
00216 return 1;
00217 }
00218
00219 dt_bool dt_arr_append( dt_node* arr, dt_node* item )
00220 {
00221 if( ! item ) return 0;
00222
00223 assert( !arr || dt_node_is_valid(arr) );
00224 assert( dt_node_is_valid(item) );
00225
00226 if( !! arr && arr->kind == dt_arr_node
00227 && dt_buf_append_data( & arr->buf, &item, sizeof(item) )
00228 ) return 1;
00229
00230 dt_node_release( item );
00231 return 0;
00232 }
00233
00234
00235 size_t dt_rec_get_size( dt_node const* node )
00236 {
00237 if( !node || node->kind != dt_rec_node )
00238 return 0;
00239 assert( dt_node_is_valid(node) );
00240 return (node->buf.strEnd - node->buf.begin) / sizeof(rec_item);
00241 }
00242
00248 static
00249 int rec_key_cmp(dt_byte const* a, size_t la, dt_byte const* b, size_t lb)
00250 {
00251 size_t l = (la<lb) ? la : lb;
00252 for( ; l-- ; ++a, ++b )
00253 if( *a != *b )
00254 return (*a<*b) ? -1 : +1;
00255
00256 if( la!=lb ) return (la<lb) ? -1 : +1;
00257 return 0;
00258 }
00259
00271 static
00272 dt_bool rec_bsearch( rec_item* base, rec_item* end
00273 , dt_byte const* key, size_t key_len
00274 , rec_item** pos )
00275 {
00276 size_t n = end-base;
00277 while( n > 0 )
00278 {
00279 size_t m = n/2;
00280 rec_item* mid = base+m;
00281 int cmp = rec_key_cmp( key,key_len, mid->key, mid->key_len );
00282 if( cmp==0 )
00283 {
00284 *pos = mid;
00285 return 1;
00286 }
00287 if( cmp<0 )
00288 {
00289 n = m;
00290 }
00291 else
00292 {
00293 ++m;
00294 base += m;
00295 n -= m;
00296 }
00297 }
00298 *pos = base;
00299 return 0;
00300 }
00301
00302
00303 dt_node* dt_rec_get( dt_node const* rec, dt_byte const* key, size_t key_len )
00304 {
00305 rec_item* pos;
00306
00307 assert( !rec || dt_node_is_valid(rec) );
00308
00309 if( !! rec
00310 && ( !! key || ! key_len )
00311 && rec->kind == dt_rec_node
00312 && rec_bsearch( (rec_item*)rec->buf.begin, (rec_item*)rec->buf.strEnd, key, key_len, &pos )
00313 )
00314 return pos->node;
00315
00316 return 00;
00317 }
00318
00319
00320 dt_node* dt_rec_sget( dt_node const* rec, char const* key )
00321 {
00322 if( ! key )
00323 return 00;
00324
00325 return dt_rec_get( rec, (dt_byte const*)key, strlen(key) );
00326 }
00327
00328
00329
00330 dt_bool dt_rec_put( dt_node* rec
00331 , dt_byte const* key, size_t key_len
00332 , dt_node* item
00333 )
00334 {
00335 rec_item* pos;
00336 if( ! item ) return 0;
00337 if( ! rec
00338 || ( !key && !!key_len )
00339 || rec->kind != dt_rec_node
00340 ) goto FAIL;
00341
00342 assert( dt_node_is_valid(rec) );
00343 assert( dt_node_is_valid(item) );
00344
00345 if( rec_bsearch( (rec_item*)rec->buf.begin, (rec_item*)rec->buf.strEnd, key, key_len, &pos ) )
00346 {
00347 dt_node_release( pos->node );
00348 }
00349 else
00350 {
00351 void* alloc_key;
00352
00353
00354
00355 size_t rec_offs = pos - (rec_item*)rec->buf.begin;
00356 if( ! dt_buf_growth_reserve( & rec->buf, sizeof( rec_item ) ) )
00357 goto FAIL;
00358 pos = (rec_item*)rec->buf.begin + rec_offs;
00359
00360 alloc_key = malloc(key_len);
00361 if( ! alloc_key )
00362 goto FAIL;
00363
00364 memcpy( alloc_key, key, key_len );
00365 memmove( pos+1, pos, rec->buf.strEnd-(dt_byte*)pos );
00366 rec->buf.strEnd += sizeof(*pos);
00367 pos->key = alloc_key;
00368 pos->key_len = key_len;
00369 }
00370 pos->node = item;
00371 return 1;
00372
00373 FAIL:
00374 dt_node_release( item );
00375 return 0;
00376 }
00377
00378
00379 dt_bool dt_rec_sput( dt_node* rec, char const* key, dt_node* item )
00380 {
00381 return dt_rec_put( rec, (dt_byte const*)key, !key ? 1 : strlen(key), item );
00382 }
00383
00384
00385
00386 dt_node* dt_rec_get_nth( dt_node* rec, unsigned ind
00387 , dt_byte const** key, size_t* key_len
00388 )
00389 {
00390 rec_item* pos;
00391 assert( !rec || dt_node_is_valid(rec) );
00392
00393 if( ! rec
00394 || rec->kind != dt_rec_node
00395 || ind >= (rec->buf.strEnd - rec->buf.begin)/sizeof(rec_item)
00396 ) return 00;
00397
00398 pos = (rec_item*)rec->buf.begin + ind;
00399 if( key ) *key = pos->key;
00400 if( key_len ) *key_len = pos->key_len;
00401 return pos->node;
00402 }
00403