Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals  

dt_node_impl.c

Go to the documentation of this file.
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 ); /* not looping around... */
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       /* Ensure that memory is available for new entry. */
00354       /*  WARN: recompute 'pos' from offset in case the buffer is reallocated */
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 

Generated on Sun Jun 1 16:35:38 2003 for datatree by doxygen 1.3.1