Fossil SCM

latest cson_amalgamation. Fixes an obscure ref-counting discrepancy and cuts memory cost of cloning.

stephan 2012-03-04 14:45 trunk
Commit 7830e2cc0f175cfc248d9e6aed82900dc1bf0adb
--- src/cson_amalgamation.c
+++ src/cson_amalgamation.c
@@ -1427,11 +1427,11 @@
14271427
/**
14281428
Type IDs corresponding to JavaScript/JSON types.
14291429
*/
14301430
enum cson_type_id {
14311431
/**
1432
- The special "null" value constant.
1432
+ The special "undefined" value constant.
14331433
14341434
Its value must be 0 for internal reasons.
14351435
*/
14361436
CSON_TYPE_UNDEF = 0,
14371437
/**
@@ -1597,10 +1597,18 @@
15971597
static const cson_value cson_value_double_empty = { &cson_value_api_double, NULL, 0 };
15981598
static const cson_value cson_value_string_empty = { &cson_value_api_string, NULL, 0 };
15991599
static const cson_value cson_value_array_empty = { &cson_value_api_array, NULL, 0 };
16001600
static const cson_value cson_value_object_empty = { &cson_value_api_object, NULL, 0 };
16011601
1602
+/**
1603
+ Strings are allocated as an instances of this class with N+1
1604
+ trailing bytes, where N is the length of the string being
1605
+ allocated. To convert a cson_string to c-string we simply increment
1606
+ the cson_string pointer. To do the opposite we use (cstr -
1607
+ sizeof(cson_string)). Zero-length strings are a special case
1608
+ handled by a couple of the cson_string functions.
1609
+*/
16021610
struct cson_string
16031611
{
16041612
unsigned int length;
16051613
};
16061614
#define cson_string_empty_m {0/*length*/}
@@ -1668,11 +1676,11 @@
16681676
{ &cson_value_api_bool, &CSON_EMPTY_HOLDER.trueValue, 0 }, /* TRUE */
16691677
{ &cson_value_api_bool, NULL, 0 }, /* FALSE */
16701678
{ &cson_value_api_integer, NULL, 0 }, /* INT_0 */
16711679
{ &cson_value_api_double, NULL, 0 }, /* DBL_0 */
16721680
{ &cson_value_api_string, &CSON_EMPTY_HOLDER.stringValue, 0 }, /* STR_EMPTY */
1673
-{ 0, NULL, 0 }
1681
+{ NULL, NULL, 0 }
16741682
};
16751683
16761684
16771685
/**
16781686
Returns non-0 (true) if m is one of our special
@@ -1916,11 +1924,11 @@
19161924
19171925
cson_strings are supposed to be immutable, but this form provides
19181926
access to the immutable bits, which are v->length bytes long. A
19191927
length-0 string is returned as NULL from here, as opposed to
19201928
"". (This is a side-effect of the string allocation mechanism.)
1921
- Returns NULL if !v.
1929
+ Returns NULL if !v or if v is the internal empty-string singleton.
19221930
*/
19231931
static char * cson_string_str(cson_string *v)
19241932
{
19251933
/*
19261934
See http://groups.google.com/group/comp.lang.c.moderated/browse_thread/thread/2e0c0df5e8a0cd6a
@@ -1948,11 +1956,14 @@
19481956
See http://groups.google.com/group/comp.lang.c.moderated/browse_thread/thread/2e0c0df5e8a0cd6a
19491957
*/
19501958
#if 1
19511959
if( ! v ) return NULL;
19521960
else if( v == &CSON_EMPTY_HOLDER.stringValue ) return "";
1953
- else return (char *)((unsigned char *)(v+1));
1961
+ else {
1962
+ assert((0 < v->length) && "How do we have a non-singleton empty string?");
1963
+ return (char *)((unsigned char *)(v+1));
1964
+ }
19541965
#else
19551966
return (NULL == v)
19561967
? NULL
19571968
: (v->length
19581969
? (char const *) ((unsigned char const *)(v+1))
@@ -2222,13 +2233,11 @@
22222233
@see cson_value_new_integer()
22232234
@see cson_value_new_double()
22242235
@see cson_value_new_bool()
22252236
@see cson_value_free()
22262237
*/
2227
-static cson_value * cson_value_new(cson_type_id t, size_t extra);
2228
-
2229
-cson_value * cson_value_new(cson_type_id t, size_t extra)
2238
+static cson_value * cson_value_new(cson_type_id t, size_t extra)
22302239
{
22312240
static const size_t vsz = sizeof(cson_value);
22322241
const size_t sz = vsz + extra;
22332242
size_t tx = 0;
22342243
cson_value def = cson_value_undef;
@@ -3142,11 +3151,11 @@
31423151
kvp->value = v;
31433152
}
31443153
return 0;
31453154
}
31463155
if( !obj->kvp.alloced || (obj->kvp.count == obj->kvp.alloced-1))
3147
- {
3156
+ { /* reserve space */
31483157
unsigned int const n = obj->kvp.count ? (obj->kvp.count*2) : 6;
31493158
if( n > cson_kvp_list_reserve( &obj->kvp, n ) )
31503159
{
31513160
return cson_rc.AllocError;
31523161
}
@@ -3281,10 +3290,12 @@
32813290
{
32823291
cson_value_free(val);
32833292
return cson_rc.AllocError;
32843293
}
32853294
kvp->key = cson_string_value(p->ckey)/*transfer ownership*/;
3295
+ assert(0 == kvp->key->refcount);
3296
+ cson_refcount_incr(kvp->key);
32863297
p->ckey = NULL;
32873298
kvp->value = val;
32883299
cson_refcount_incr( val );
32893300
rc = cson_kvp_list_append( &obj->kvp, kvp );
32903301
if( 0 != rc )
@@ -3361,11 +3372,11 @@
33613372
? cson_value_new_array()
33623373
: cson_value_new_object();
33633374
if( ! obja )
33643375
{
33653376
p->errNo = cson_rc.AllocError;
3366
- return 0;
3377
+ break;
33673378
}
33683379
if( 0 != rc ) break;
33693380
if( ! p->root )
33703381
{
33713382
p->root = p->node = obja;
@@ -3384,12 +3395,16 @@
33843395
}
33853396
}
33863397
else
33873398
{
33883399
rc = cson_array_append( &p->stack, obja );
3389
- if( 0 == rc ) rc = cson_parser_push_value( p, obja );
3390
- if( 0 == rc ) p->node = obja;
3400
+ if(rc) cson_value_free( obja );
3401
+ else
3402
+ {
3403
+ rc = cson_parser_push_value( p, obja );
3404
+ if( 0 == rc ) p->node = obja;
3405
+ }
33913406
}
33923407
break;
33933408
}
33943409
case JSON_T_ARRAY_END:
33953410
case JSON_T_OBJECT_END: {
@@ -4578,10 +4593,39 @@
45784593
cson_value * v = NULL;
45794594
cson_object_fetch_sub2( obj, &v, path );
45804595
return v;
45814596
}
45824597
4598
+
4599
+/**
4600
+ If v is-a Object or Array then this function returns a deep
4601
+ clone, otherwise it returns v. In either case, the refcount
4602
+ of the returned value is increased by 1.
4603
+*/
4604
+static cson_value * cson_value_clone_shared( cson_value * v )
4605
+{
4606
+ cson_value * rc = NULL;
4607
+#define TRY_SHARING 1
4608
+#if TRY_SHARING
4609
+ if(!v ) return rc;
4610
+ else if( cson_value_is_object(v)
4611
+ || cson_value_is_array(v))
4612
+ {
4613
+ rc = cson_value_clone( v );
4614
+ }
4615
+ else
4616
+ {
4617
+ rc = v;
4618
+ }
4619
+#else
4620
+ rc = cson_value_clone(v);
4621
+#endif
4622
+#undef TRY_SHARING
4623
+ cson_value_add_reference(rc);
4624
+ return rc;
4625
+}
4626
+
45834627
static cson_value * cson_value_clone_array( cson_value const * orig )
45844628
{
45854629
unsigned int i = 0;
45864630
cson_array const * asrc = cson_value_get_array( orig );
45874631
unsigned int alen = cson_array_length_get( asrc );
@@ -4600,11 +4644,11 @@
46004644
for( ; i < alen; ++i )
46014645
{
46024646
cson_value * ch = cson_array_get( asrc, i );
46034647
if( NULL != ch )
46044648
{
4605
- cson_value * cl = cson_value_clone( ch );
4649
+ cson_value * cl = cson_value_clone_shared( ch );
46064650
if( NULL == cl )
46074651
{
46084652
cson_value_free( destV );
46094653
return NULL;
46104654
}
@@ -4612,15 +4656,16 @@
46124656
{
46134657
cson_value_free( cl );
46144658
cson_value_free( destV );
46154659
return NULL;
46164660
}
4661
+ cson_value_free(cl)/*remove our artificial reference */;
46174662
}
46184663
}
46194664
return destV;
46204665
}
4621
-
4666
+
46224667
static cson_value * cson_value_clone_object( cson_value const * orig )
46234668
{
46244669
cson_object const * src = cson_value_get_object( orig );
46254670
cson_value * destV = NULL;
46264671
cson_object * dest = NULL;
@@ -4639,32 +4684,33 @@
46394684
cson_value_free( destV );
46404685
return NULL;
46414686
}
46424687
while( (kvp = cson_object_iter_next( &iter )) )
46434688
{
4644
- /*
4645
- FIXME: refcount the keys! We first need a setter which takes
4646
- a cson_string or cson_value key type.
4647
- */
46484689
cson_value * key = NULL;
46494690
cson_value * val = NULL;
4650
- key = cson_value_clone(kvp->key);
4651
- val = key ? cson_value_clone( kvp->value ) : NULL;
4691
+ assert( kvp->key && (kvp->key->refcount>0) );
4692
+ key = cson_value_clone_shared(kvp->key);
4693
+ val = key ? cson_value_clone_shared(kvp->value) : NULL;
46524694
if( ! key || !val ){
4653
- cson_value_free(key);
4654
- cson_value_free(val);
4655
- cson_value_free(destV);
4656
- return NULL;
4695
+ goto error;
46574696
}
46584697
assert( CSON_STR(key) );
46594698
if( 0 != cson_object_set_s( dest, CSON_STR(key), val ) )
46604699
{
4661
- cson_value_free(key);
4662
- cson_value_free(val);
4663
- cson_value_free(destV);
4664
- return NULL;
4700
+ goto error;
46654701
}
4702
+ /* remove our references */
4703
+ cson_value_free(key);
4704
+ cson_value_free(val);
4705
+ continue;
4706
+ error:
4707
+ cson_value_free(key);
4708
+ cson_value_free(val);
4709
+ cson_value_free(destV);
4710
+ destV = NULL;
4711
+ break;
46664712
}
46674713
return destV;
46684714
}
46694715
46704716
cson_value * cson_value_clone( cson_value const * orig )
@@ -4733,17 +4779,17 @@
47334779
void cson_free_array(cson_array *x)
47344780
{
47354781
if(x) cson_value_free(cson_array_value(x));
47364782
}
47374783
4738
-void cson_free_string(cson_string const *x)
4784
+void cson_free_string(cson_string *x)
47394785
{
47404786
if(x) cson_value_free(cson_string_value(x));
47414787
}
47424788
void cson_free_value(cson_value *x)
47434789
{
4744
- cson_value_free(x);
4790
+ if(x) cson_value_free(x);
47454791
}
47464792
47474793
47484794
#if 0
47494795
/* i'm not happy with this... */
@@ -4907,11 +4953,11 @@
49074953
assert( 0 && "Should have been caught by is-builtin check!" );
49084954
break;
49094955
default:
49104956
assert(0 && "Invalid typeID!");
49114957
return 0;
4912
-
4958
+#undef RCCHECK
49134959
}
49144960
return rc;
49154961
}
49164962
}
49174963
49184964
--- src/cson_amalgamation.c
+++ src/cson_amalgamation.c
@@ -1427,11 +1427,11 @@
1427 /**
1428 Type IDs corresponding to JavaScript/JSON types.
1429 */
1430 enum cson_type_id {
1431 /**
1432 The special "null" value constant.
1433
1434 Its value must be 0 for internal reasons.
1435 */
1436 CSON_TYPE_UNDEF = 0,
1437 /**
@@ -1597,10 +1597,18 @@
1597 static const cson_value cson_value_double_empty = { &cson_value_api_double, NULL, 0 };
1598 static const cson_value cson_value_string_empty = { &cson_value_api_string, NULL, 0 };
1599 static const cson_value cson_value_array_empty = { &cson_value_api_array, NULL, 0 };
1600 static const cson_value cson_value_object_empty = { &cson_value_api_object, NULL, 0 };
1601
 
 
 
 
 
 
 
 
1602 struct cson_string
1603 {
1604 unsigned int length;
1605 };
1606 #define cson_string_empty_m {0/*length*/}
@@ -1668,11 +1676,11 @@
1668 { &cson_value_api_bool, &CSON_EMPTY_HOLDER.trueValue, 0 }, /* TRUE */
1669 { &cson_value_api_bool, NULL, 0 }, /* FALSE */
1670 { &cson_value_api_integer, NULL, 0 }, /* INT_0 */
1671 { &cson_value_api_double, NULL, 0 }, /* DBL_0 */
1672 { &cson_value_api_string, &CSON_EMPTY_HOLDER.stringValue, 0 }, /* STR_EMPTY */
1673 { 0, NULL, 0 }
1674 };
1675
1676
1677 /**
1678 Returns non-0 (true) if m is one of our special
@@ -1916,11 +1924,11 @@
1916
1917 cson_strings are supposed to be immutable, but this form provides
1918 access to the immutable bits, which are v->length bytes long. A
1919 length-0 string is returned as NULL from here, as opposed to
1920 "". (This is a side-effect of the string allocation mechanism.)
1921 Returns NULL if !v.
1922 */
1923 static char * cson_string_str(cson_string *v)
1924 {
1925 /*
1926 See http://groups.google.com/group/comp.lang.c.moderated/browse_thread/thread/2e0c0df5e8a0cd6a
@@ -1948,11 +1956,14 @@
1948 See http://groups.google.com/group/comp.lang.c.moderated/browse_thread/thread/2e0c0df5e8a0cd6a
1949 */
1950 #if 1
1951 if( ! v ) return NULL;
1952 else if( v == &CSON_EMPTY_HOLDER.stringValue ) return "";
1953 else return (char *)((unsigned char *)(v+1));
 
 
 
1954 #else
1955 return (NULL == v)
1956 ? NULL
1957 : (v->length
1958 ? (char const *) ((unsigned char const *)(v+1))
@@ -2222,13 +2233,11 @@
2222 @see cson_value_new_integer()
2223 @see cson_value_new_double()
2224 @see cson_value_new_bool()
2225 @see cson_value_free()
2226 */
2227 static cson_value * cson_value_new(cson_type_id t, size_t extra);
2228
2229 cson_value * cson_value_new(cson_type_id t, size_t extra)
2230 {
2231 static const size_t vsz = sizeof(cson_value);
2232 const size_t sz = vsz + extra;
2233 size_t tx = 0;
2234 cson_value def = cson_value_undef;
@@ -3142,11 +3151,11 @@
3142 kvp->value = v;
3143 }
3144 return 0;
3145 }
3146 if( !obj->kvp.alloced || (obj->kvp.count == obj->kvp.alloced-1))
3147 {
3148 unsigned int const n = obj->kvp.count ? (obj->kvp.count*2) : 6;
3149 if( n > cson_kvp_list_reserve( &obj->kvp, n ) )
3150 {
3151 return cson_rc.AllocError;
3152 }
@@ -3281,10 +3290,12 @@
3281 {
3282 cson_value_free(val);
3283 return cson_rc.AllocError;
3284 }
3285 kvp->key = cson_string_value(p->ckey)/*transfer ownership*/;
 
 
3286 p->ckey = NULL;
3287 kvp->value = val;
3288 cson_refcount_incr( val );
3289 rc = cson_kvp_list_append( &obj->kvp, kvp );
3290 if( 0 != rc )
@@ -3361,11 +3372,11 @@
3361 ? cson_value_new_array()
3362 : cson_value_new_object();
3363 if( ! obja )
3364 {
3365 p->errNo = cson_rc.AllocError;
3366 return 0;
3367 }
3368 if( 0 != rc ) break;
3369 if( ! p->root )
3370 {
3371 p->root = p->node = obja;
@@ -3384,12 +3395,16 @@
3384 }
3385 }
3386 else
3387 {
3388 rc = cson_array_append( &p->stack, obja );
3389 if( 0 == rc ) rc = cson_parser_push_value( p, obja );
3390 if( 0 == rc ) p->node = obja;
 
 
 
 
3391 }
3392 break;
3393 }
3394 case JSON_T_ARRAY_END:
3395 case JSON_T_OBJECT_END: {
@@ -4578,10 +4593,39 @@
4578 cson_value * v = NULL;
4579 cson_object_fetch_sub2( obj, &v, path );
4580 return v;
4581 }
4582
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4583 static cson_value * cson_value_clone_array( cson_value const * orig )
4584 {
4585 unsigned int i = 0;
4586 cson_array const * asrc = cson_value_get_array( orig );
4587 unsigned int alen = cson_array_length_get( asrc );
@@ -4600,11 +4644,11 @@
4600 for( ; i < alen; ++i )
4601 {
4602 cson_value * ch = cson_array_get( asrc, i );
4603 if( NULL != ch )
4604 {
4605 cson_value * cl = cson_value_clone( ch );
4606 if( NULL == cl )
4607 {
4608 cson_value_free( destV );
4609 return NULL;
4610 }
@@ -4612,15 +4656,16 @@
4612 {
4613 cson_value_free( cl );
4614 cson_value_free( destV );
4615 return NULL;
4616 }
 
4617 }
4618 }
4619 return destV;
4620 }
4621
4622 static cson_value * cson_value_clone_object( cson_value const * orig )
4623 {
4624 cson_object const * src = cson_value_get_object( orig );
4625 cson_value * destV = NULL;
4626 cson_object * dest = NULL;
@@ -4639,32 +4684,33 @@
4639 cson_value_free( destV );
4640 return NULL;
4641 }
4642 while( (kvp = cson_object_iter_next( &iter )) )
4643 {
4644 /*
4645 FIXME: refcount the keys! We first need a setter which takes
4646 a cson_string or cson_value key type.
4647 */
4648 cson_value * key = NULL;
4649 cson_value * val = NULL;
4650 key = cson_value_clone(kvp->key);
4651 val = key ? cson_value_clone( kvp->value ) : NULL;
 
4652 if( ! key || !val ){
4653 cson_value_free(key);
4654 cson_value_free(val);
4655 cson_value_free(destV);
4656 return NULL;
4657 }
4658 assert( CSON_STR(key) );
4659 if( 0 != cson_object_set_s( dest, CSON_STR(key), val ) )
4660 {
4661 cson_value_free(key);
4662 cson_value_free(val);
4663 cson_value_free(destV);
4664 return NULL;
4665 }
 
 
 
 
 
 
 
 
 
 
4666 }
4667 return destV;
4668 }
4669
4670 cson_value * cson_value_clone( cson_value const * orig )
@@ -4733,17 +4779,17 @@
4733 void cson_free_array(cson_array *x)
4734 {
4735 if(x) cson_value_free(cson_array_value(x));
4736 }
4737
4738 void cson_free_string(cson_string const *x)
4739 {
4740 if(x) cson_value_free(cson_string_value(x));
4741 }
4742 void cson_free_value(cson_value *x)
4743 {
4744 cson_value_free(x);
4745 }
4746
4747
4748 #if 0
4749 /* i'm not happy with this... */
@@ -4907,11 +4953,11 @@
4907 assert( 0 && "Should have been caught by is-builtin check!" );
4908 break;
4909 default:
4910 assert(0 && "Invalid typeID!");
4911 return 0;
4912
4913 }
4914 return rc;
4915 }
4916 }
4917
4918
--- src/cson_amalgamation.c
+++ src/cson_amalgamation.c
@@ -1427,11 +1427,11 @@
1427 /**
1428 Type IDs corresponding to JavaScript/JSON types.
1429 */
1430 enum cson_type_id {
1431 /**
1432 The special "undefined" value constant.
1433
1434 Its value must be 0 for internal reasons.
1435 */
1436 CSON_TYPE_UNDEF = 0,
1437 /**
@@ -1597,10 +1597,18 @@
1597 static const cson_value cson_value_double_empty = { &cson_value_api_double, NULL, 0 };
1598 static const cson_value cson_value_string_empty = { &cson_value_api_string, NULL, 0 };
1599 static const cson_value cson_value_array_empty = { &cson_value_api_array, NULL, 0 };
1600 static const cson_value cson_value_object_empty = { &cson_value_api_object, NULL, 0 };
1601
1602 /**
1603 Strings are allocated as an instances of this class with N+1
1604 trailing bytes, where N is the length of the string being
1605 allocated. To convert a cson_string to c-string we simply increment
1606 the cson_string pointer. To do the opposite we use (cstr -
1607 sizeof(cson_string)). Zero-length strings are a special case
1608 handled by a couple of the cson_string functions.
1609 */
1610 struct cson_string
1611 {
1612 unsigned int length;
1613 };
1614 #define cson_string_empty_m {0/*length*/}
@@ -1668,11 +1676,11 @@
1676 { &cson_value_api_bool, &CSON_EMPTY_HOLDER.trueValue, 0 }, /* TRUE */
1677 { &cson_value_api_bool, NULL, 0 }, /* FALSE */
1678 { &cson_value_api_integer, NULL, 0 }, /* INT_0 */
1679 { &cson_value_api_double, NULL, 0 }, /* DBL_0 */
1680 { &cson_value_api_string, &CSON_EMPTY_HOLDER.stringValue, 0 }, /* STR_EMPTY */
1681 { NULL, NULL, 0 }
1682 };
1683
1684
1685 /**
1686 Returns non-0 (true) if m is one of our special
@@ -1916,11 +1924,11 @@
1924
1925 cson_strings are supposed to be immutable, but this form provides
1926 access to the immutable bits, which are v->length bytes long. A
1927 length-0 string is returned as NULL from here, as opposed to
1928 "". (This is a side-effect of the string allocation mechanism.)
1929 Returns NULL if !v or if v is the internal empty-string singleton.
1930 */
1931 static char * cson_string_str(cson_string *v)
1932 {
1933 /*
1934 See http://groups.google.com/group/comp.lang.c.moderated/browse_thread/thread/2e0c0df5e8a0cd6a
@@ -1948,11 +1956,14 @@
1956 See http://groups.google.com/group/comp.lang.c.moderated/browse_thread/thread/2e0c0df5e8a0cd6a
1957 */
1958 #if 1
1959 if( ! v ) return NULL;
1960 else if( v == &CSON_EMPTY_HOLDER.stringValue ) return "";
1961 else {
1962 assert((0 < v->length) && "How do we have a non-singleton empty string?");
1963 return (char *)((unsigned char *)(v+1));
1964 }
1965 #else
1966 return (NULL == v)
1967 ? NULL
1968 : (v->length
1969 ? (char const *) ((unsigned char const *)(v+1))
@@ -2222,13 +2233,11 @@
2233 @see cson_value_new_integer()
2234 @see cson_value_new_double()
2235 @see cson_value_new_bool()
2236 @see cson_value_free()
2237 */
2238 static cson_value * cson_value_new(cson_type_id t, size_t extra)
 
 
2239 {
2240 static const size_t vsz = sizeof(cson_value);
2241 const size_t sz = vsz + extra;
2242 size_t tx = 0;
2243 cson_value def = cson_value_undef;
@@ -3142,11 +3151,11 @@
3151 kvp->value = v;
3152 }
3153 return 0;
3154 }
3155 if( !obj->kvp.alloced || (obj->kvp.count == obj->kvp.alloced-1))
3156 { /* reserve space */
3157 unsigned int const n = obj->kvp.count ? (obj->kvp.count*2) : 6;
3158 if( n > cson_kvp_list_reserve( &obj->kvp, n ) )
3159 {
3160 return cson_rc.AllocError;
3161 }
@@ -3281,10 +3290,12 @@
3290 {
3291 cson_value_free(val);
3292 return cson_rc.AllocError;
3293 }
3294 kvp->key = cson_string_value(p->ckey)/*transfer ownership*/;
3295 assert(0 == kvp->key->refcount);
3296 cson_refcount_incr(kvp->key);
3297 p->ckey = NULL;
3298 kvp->value = val;
3299 cson_refcount_incr( val );
3300 rc = cson_kvp_list_append( &obj->kvp, kvp );
3301 if( 0 != rc )
@@ -3361,11 +3372,11 @@
3372 ? cson_value_new_array()
3373 : cson_value_new_object();
3374 if( ! obja )
3375 {
3376 p->errNo = cson_rc.AllocError;
3377 break;
3378 }
3379 if( 0 != rc ) break;
3380 if( ! p->root )
3381 {
3382 p->root = p->node = obja;
@@ -3384,12 +3395,16 @@
3395 }
3396 }
3397 else
3398 {
3399 rc = cson_array_append( &p->stack, obja );
3400 if(rc) cson_value_free( obja );
3401 else
3402 {
3403 rc = cson_parser_push_value( p, obja );
3404 if( 0 == rc ) p->node = obja;
3405 }
3406 }
3407 break;
3408 }
3409 case JSON_T_ARRAY_END:
3410 case JSON_T_OBJECT_END: {
@@ -4578,10 +4593,39 @@
4593 cson_value * v = NULL;
4594 cson_object_fetch_sub2( obj, &v, path );
4595 return v;
4596 }
4597
4598
4599 /**
4600 If v is-a Object or Array then this function returns a deep
4601 clone, otherwise it returns v. In either case, the refcount
4602 of the returned value is increased by 1.
4603 */
4604 static cson_value * cson_value_clone_shared( cson_value * v )
4605 {
4606 cson_value * rc = NULL;
4607 #define TRY_SHARING 1
4608 #if TRY_SHARING
4609 if(!v ) return rc;
4610 else if( cson_value_is_object(v)
4611 || cson_value_is_array(v))
4612 {
4613 rc = cson_value_clone( v );
4614 }
4615 else
4616 {
4617 rc = v;
4618 }
4619 #else
4620 rc = cson_value_clone(v);
4621 #endif
4622 #undef TRY_SHARING
4623 cson_value_add_reference(rc);
4624 return rc;
4625 }
4626
4627 static cson_value * cson_value_clone_array( cson_value const * orig )
4628 {
4629 unsigned int i = 0;
4630 cson_array const * asrc = cson_value_get_array( orig );
4631 unsigned int alen = cson_array_length_get( asrc );
@@ -4600,11 +4644,11 @@
4644 for( ; i < alen; ++i )
4645 {
4646 cson_value * ch = cson_array_get( asrc, i );
4647 if( NULL != ch )
4648 {
4649 cson_value * cl = cson_value_clone_shared( ch );
4650 if( NULL == cl )
4651 {
4652 cson_value_free( destV );
4653 return NULL;
4654 }
@@ -4612,15 +4656,16 @@
4656 {
4657 cson_value_free( cl );
4658 cson_value_free( destV );
4659 return NULL;
4660 }
4661 cson_value_free(cl)/*remove our artificial reference */;
4662 }
4663 }
4664 return destV;
4665 }
4666
4667 static cson_value * cson_value_clone_object( cson_value const * orig )
4668 {
4669 cson_object const * src = cson_value_get_object( orig );
4670 cson_value * destV = NULL;
4671 cson_object * dest = NULL;
@@ -4639,32 +4684,33 @@
4684 cson_value_free( destV );
4685 return NULL;
4686 }
4687 while( (kvp = cson_object_iter_next( &iter )) )
4688 {
 
 
 
 
4689 cson_value * key = NULL;
4690 cson_value * val = NULL;
4691 assert( kvp->key && (kvp->key->refcount>0) );
4692 key = cson_value_clone_shared(kvp->key);
4693 val = key ? cson_value_clone_shared(kvp->value) : NULL;
4694 if( ! key || !val ){
4695 goto error;
 
 
 
4696 }
4697 assert( CSON_STR(key) );
4698 if( 0 != cson_object_set_s( dest, CSON_STR(key), val ) )
4699 {
4700 goto error;
 
 
 
4701 }
4702 /* remove our references */
4703 cson_value_free(key);
4704 cson_value_free(val);
4705 continue;
4706 error:
4707 cson_value_free(key);
4708 cson_value_free(val);
4709 cson_value_free(destV);
4710 destV = NULL;
4711 break;
4712 }
4713 return destV;
4714 }
4715
4716 cson_value * cson_value_clone( cson_value const * orig )
@@ -4733,17 +4779,17 @@
4779 void cson_free_array(cson_array *x)
4780 {
4781 if(x) cson_value_free(cson_array_value(x));
4782 }
4783
4784 void cson_free_string(cson_string *x)
4785 {
4786 if(x) cson_value_free(cson_string_value(x));
4787 }
4788 void cson_free_value(cson_value *x)
4789 {
4790 if(x) cson_value_free(x);
4791 }
4792
4793
4794 #if 0
4795 /* i'm not happy with this... */
@@ -4907,11 +4953,11 @@
4953 assert( 0 && "Should have been caught by is-builtin check!" );
4954 break;
4955 default:
4956 assert(0 && "Invalid typeID!");
4957 return 0;
4958 #undef RCCHECK
4959 }
4960 return rc;
4961 }
4962 }
4963
4964
--- src/cson_amalgamation.h
+++ src/cson_amalgamation.h
@@ -928,11 +928,12 @@
928928
/**
929929
Returns a pointer to the NULL-terminated string bytes of str.
930930
The bytes are owned by string and will be invalided when it
931931
is cleaned up.
932932
933
- If str is NULL then NULL is returned.
933
+ If str is NULL then NULL is returned. If the string has a length
934
+ of 0 then "" is returned.
934935
935936
@see cson_string_length_bytes()
936937
@see cson_value_get_string()
937938
*/
938939
char const * cson_string_cstr( cson_string const * str );
@@ -1261,11 +1262,11 @@
12611262
void cson_free_array(cson_array *x);
12621263
12631264
/**
12641265
Equivalent to cson_value_free(cson_string_value(x)).
12651266
*/
1266
-void cson_free_string(cson_string const *x);
1267
+void cson_free_string(cson_string *x);
12671268
12681269
12691270
/**
12701271
Allocates a new "array" value and transfers ownership of it to the
12711272
caller. It must eventually be destroyed, by the caller or its
@@ -2037,14 +2038,14 @@
20372038
20382039
/**
20392040
Deeply copies a JSON value, be it an object/array or a "plain"
20402041
value (e.g. number/string/boolean). If cv is not NULL then this
20412042
function makes a deep clone of it and returns that clone. Ownership
2042
- of the clone is transfered to the caller, who must eventually free
2043
- the value using cson_value_free() or add it to a container
2044
- object/array to transfer ownership to the container. The returned
2045
- object will be of the same logical type as orig.
2043
+ of the clone is identical t transfered to the caller, who must
2044
+ eventually free the value using cson_value_free() or add it to a
2045
+ container object/array to transfer ownership to the container. The
2046
+ returned object will be of the same logical type as orig.
20462047
20472048
ACHTUNG: if orig contains any cyclic references at any depth level
20482049
this function will endlessly recurse. (Having _any_ cyclic
20492050
references violates this library's requirements.)
20502051
@@ -2051,10 +2052,36 @@
20512052
Returns NULL if orig is NULL or if cloning fails. Assuming that
20522053
orig is in a valid state, the only "likely" error case is that an
20532054
allocation fails while constructing the clone. In other words, if
20542055
cloning fails due to something other than an allocation error then
20552056
either orig is in an invalid state or there is a bug.
2057
+
2058
+ When this function clones Objects or Arrays it shares any immutable
2059
+ values (including object keys) between the parent and the
2060
+ clone. Mutable values (Objects and Arrays) are copied, however.
2061
+ For example, if we clone:
2062
+
2063
+ @code
2064
+ { a: 1, b: 2, c:["hi"] }
2065
+ @endcode
2066
+
2067
+ The cloned object and the array "c" would be a new Object/Array
2068
+ instances but the object keys (a,b,b) and the values of (a,b), as
2069
+ well as the string value within the "c" array, would be shared
2070
+ between the original and the clone. The "c" array itself would be
2071
+ deeply cloned, such that future changes to the clone are not
2072
+ visible to the parent, and vice versa, but immutable values within
2073
+ the array are shared (in this case the string "hi"). The
2074
+ justification for this heuristic is that immutable values can never
2075
+ be changed, so there is no harm in sharing them across
2076
+ clones. Additionally, such types can never contribute to cycles in
2077
+ a JSON tree, so they are safe to share this way. Objects and
2078
+ Arrays, on the other hand, can be modified later and can contribute
2079
+ to cycles, and thus the clone needs to be an independent instance.
2080
+ Note, however, that if this function directly passed a
2081
+ non-Object/Array, that value is deeply cloned. The sharing
2082
+ behaviour only applies when traversing Objects/Arrays.
20562083
*/
20572084
cson_value * cson_value_clone( cson_value const * orig );
20582085
20592086
/**
20602087
Returns the value handle associated with s. The handle itself owns
@@ -2062,11 +2089,12 @@
20622089
function. If the returned handle is part of a container, calling
20632090
cson_value_free() on the returned handle invoked undefined
20642091
behaviour (quite possibly downstream when the container tries to
20652092
use it).
20662093
2067
- This function only returns NULL if s. is NULL.
2094
+ This function only returns NULL if s is NULL. The length of the
2095
+ returned string is cson_string_length_bytes().
20682096
*/
20692097
cson_value * cson_string_value(cson_string const * s);
20702098
/**
20712099
The Object form of cson_string_value(). See that function
20722100
for full details.
@@ -2079,19 +2107,20 @@
20792107
*/
20802108
cson_value * cson_array_value(cson_array const * s);
20812109
20822110
20832111
/**
2084
- Calculates the in-memory-allocated size of v, recursively if it is
2085
- a container type, with the following caveats and limitations:
2086
-
2087
- If a given value is reference counted and multiple times within a
2088
- traversed container, each reference is counted at full cost. We
2089
- have no what of knowing if a given reference has been visited
2090
- already and whether it should or should not be counted, so we
2091
- pessimistically count them even though the _might_ not really count
2092
- for the given object tree (it depends on where the other open
2112
+ Calculates the approximate in-memory-allocated size of v,
2113
+ recursively if it is a container type, with the following caveats
2114
+ and limitations:
2115
+
2116
+ If a given value is reference counted then it is only and multiple
2117
+ times within a traversed container, each reference is counted at
2118
+ full cost. We have no way of knowing if a given reference has been
2119
+ visited already and whether it should or should not be counted, so
2120
+ we pessimistically count them even though the _might_ not really
2121
+ count for the given object tree (it depends on where the other open
20932122
references live).
20942123
20952124
This function returns 0 if any of the following are true:
20962125
20972126
- v is NULL
20982127
--- src/cson_amalgamation.h
+++ src/cson_amalgamation.h
@@ -928,11 +928,12 @@
928 /**
929 Returns a pointer to the NULL-terminated string bytes of str.
930 The bytes are owned by string and will be invalided when it
931 is cleaned up.
932
933 If str is NULL then NULL is returned.
 
934
935 @see cson_string_length_bytes()
936 @see cson_value_get_string()
937 */
938 char const * cson_string_cstr( cson_string const * str );
@@ -1261,11 +1262,11 @@
1261 void cson_free_array(cson_array *x);
1262
1263 /**
1264 Equivalent to cson_value_free(cson_string_value(x)).
1265 */
1266 void cson_free_string(cson_string const *x);
1267
1268
1269 /**
1270 Allocates a new "array" value and transfers ownership of it to the
1271 caller. It must eventually be destroyed, by the caller or its
@@ -2037,14 +2038,14 @@
2037
2038 /**
2039 Deeply copies a JSON value, be it an object/array or a "plain"
2040 value (e.g. number/string/boolean). If cv is not NULL then this
2041 function makes a deep clone of it and returns that clone. Ownership
2042 of the clone is transfered to the caller, who must eventually free
2043 the value using cson_value_free() or add it to a container
2044 object/array to transfer ownership to the container. The returned
2045 object will be of the same logical type as orig.
2046
2047 ACHTUNG: if orig contains any cyclic references at any depth level
2048 this function will endlessly recurse. (Having _any_ cyclic
2049 references violates this library's requirements.)
2050
@@ -2051,10 +2052,36 @@
2051 Returns NULL if orig is NULL or if cloning fails. Assuming that
2052 orig is in a valid state, the only "likely" error case is that an
2053 allocation fails while constructing the clone. In other words, if
2054 cloning fails due to something other than an allocation error then
2055 either orig is in an invalid state or there is a bug.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2056 */
2057 cson_value * cson_value_clone( cson_value const * orig );
2058
2059 /**
2060 Returns the value handle associated with s. The handle itself owns
@@ -2062,11 +2089,12 @@
2062 function. If the returned handle is part of a container, calling
2063 cson_value_free() on the returned handle invoked undefined
2064 behaviour (quite possibly downstream when the container tries to
2065 use it).
2066
2067 This function only returns NULL if s. is NULL.
 
2068 */
2069 cson_value * cson_string_value(cson_string const * s);
2070 /**
2071 The Object form of cson_string_value(). See that function
2072 for full details.
@@ -2079,19 +2107,20 @@
2079 */
2080 cson_value * cson_array_value(cson_array const * s);
2081
2082
2083 /**
2084 Calculates the in-memory-allocated size of v, recursively if it is
2085 a container type, with the following caveats and limitations:
2086
2087 If a given value is reference counted and multiple times within a
2088 traversed container, each reference is counted at full cost. We
2089 have no what of knowing if a given reference has been visited
2090 already and whether it should or should not be counted, so we
2091 pessimistically count them even though the _might_ not really count
2092 for the given object tree (it depends on where the other open
 
2093 references live).
2094
2095 This function returns 0 if any of the following are true:
2096
2097 - v is NULL
2098
--- src/cson_amalgamation.h
+++ src/cson_amalgamation.h
@@ -928,11 +928,12 @@
928 /**
929 Returns a pointer to the NULL-terminated string bytes of str.
930 The bytes are owned by string and will be invalided when it
931 is cleaned up.
932
933 If str is NULL then NULL is returned. If the string has a length
934 of 0 then "" is returned.
935
936 @see cson_string_length_bytes()
937 @see cson_value_get_string()
938 */
939 char const * cson_string_cstr( cson_string const * str );
@@ -1261,11 +1262,11 @@
1262 void cson_free_array(cson_array *x);
1263
1264 /**
1265 Equivalent to cson_value_free(cson_string_value(x)).
1266 */
1267 void cson_free_string(cson_string *x);
1268
1269
1270 /**
1271 Allocates a new "array" value and transfers ownership of it to the
1272 caller. It must eventually be destroyed, by the caller or its
@@ -2037,14 +2038,14 @@
2038
2039 /**
2040 Deeply copies a JSON value, be it an object/array or a "plain"
2041 value (e.g. number/string/boolean). If cv is not NULL then this
2042 function makes a deep clone of it and returns that clone. Ownership
2043 of the clone is identical t transfered to the caller, who must
2044 eventually free the value using cson_value_free() or add it to a
2045 container object/array to transfer ownership to the container. The
2046 returned object will be of the same logical type as orig.
2047
2048 ACHTUNG: if orig contains any cyclic references at any depth level
2049 this function will endlessly recurse. (Having _any_ cyclic
2050 references violates this library's requirements.)
2051
@@ -2051,10 +2052,36 @@
2052 Returns NULL if orig is NULL or if cloning fails. Assuming that
2053 orig is in a valid state, the only "likely" error case is that an
2054 allocation fails while constructing the clone. In other words, if
2055 cloning fails due to something other than an allocation error then
2056 either orig is in an invalid state or there is a bug.
2057
2058 When this function clones Objects or Arrays it shares any immutable
2059 values (including object keys) between the parent and the
2060 clone. Mutable values (Objects and Arrays) are copied, however.
2061 For example, if we clone:
2062
2063 @code
2064 { a: 1, b: 2, c:["hi"] }
2065 @endcode
2066
2067 The cloned object and the array "c" would be a new Object/Array
2068 instances but the object keys (a,b,b) and the values of (a,b), as
2069 well as the string value within the "c" array, would be shared
2070 between the original and the clone. The "c" array itself would be
2071 deeply cloned, such that future changes to the clone are not
2072 visible to the parent, and vice versa, but immutable values within
2073 the array are shared (in this case the string "hi"). The
2074 justification for this heuristic is that immutable values can never
2075 be changed, so there is no harm in sharing them across
2076 clones. Additionally, such types can never contribute to cycles in
2077 a JSON tree, so they are safe to share this way. Objects and
2078 Arrays, on the other hand, can be modified later and can contribute
2079 to cycles, and thus the clone needs to be an independent instance.
2080 Note, however, that if this function directly passed a
2081 non-Object/Array, that value is deeply cloned. The sharing
2082 behaviour only applies when traversing Objects/Arrays.
2083 */
2084 cson_value * cson_value_clone( cson_value const * orig );
2085
2086 /**
2087 Returns the value handle associated with s. The handle itself owns
@@ -2062,11 +2089,12 @@
2089 function. If the returned handle is part of a container, calling
2090 cson_value_free() on the returned handle invoked undefined
2091 behaviour (quite possibly downstream when the container tries to
2092 use it).
2093
2094 This function only returns NULL if s is NULL. The length of the
2095 returned string is cson_string_length_bytes().
2096 */
2097 cson_value * cson_string_value(cson_string const * s);
2098 /**
2099 The Object form of cson_string_value(). See that function
2100 for full details.
@@ -2079,19 +2107,20 @@
2107 */
2108 cson_value * cson_array_value(cson_array const * s);
2109
2110
2111 /**
2112 Calculates the approximate in-memory-allocated size of v,
2113 recursively if it is a container type, with the following caveats
2114 and limitations:
2115
2116 If a given value is reference counted then it is only and multiple
2117 times within a traversed container, each reference is counted at
2118 full cost. We have no way of knowing if a given reference has been
2119 visited already and whether it should or should not be counted, so
2120 we pessimistically count them even though the _might_ not really
2121 count for the given object tree (it depends on where the other open
2122 references live).
2123
2124 This function returns 0 if any of the following are true:
2125
2126 - v is NULL
2127

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button