Fossil SCM
Another round of cson memory optimizations. Object keys can now be cson_strings, which can be refcounted/shared.
Commit
3d252e87548f99713d93203d3ae00412497596a5
Parent
c75759d8d0cf9a3…
2 files changed
+206
-171
+82
-5
+206
-171
| --- src/cson_amalgamation.c | ||
| +++ src/cson_amalgamation.c | ||
| @@ -1873,41 +1873,10 @@ | ||
| 1873 | 1873 | return 0; |
| 1874 | 1874 | } |
| 1875 | 1875 | else return cv->refcount; |
| 1876 | 1876 | } |
| 1877 | 1877 | |
| 1878 | -/** | |
| 1879 | - Allocates a new cson_string object with enough space for | |
| 1880 | - the given number of bytes. A byte for a NUL terminator | |
| 1881 | - is added automatically. Use cson_string_str() to get | |
| 1882 | - access to the string bytes, which will be len bytes long. | |
| 1883 | - | |
| 1884 | - len may be 0, in which case the internal string is "", as opposed | |
| 1885 | - to null. This is because the string bytes and the cson_string are | |
| 1886 | - allocated in a single chunk of memory, and the cson_string object | |
| 1887 | - does not directly provide (or have) a pointer to the string bytes. | |
| 1888 | -*/ | |
| 1889 | -static cson_string * cson_string_alloc(unsigned int len) | |
| 1890 | -{ | |
| 1891 | - if( ! len ) return CSON_STR(&CSON_SPECIAL_VALUES[CSON_VAL_STR_EMPTY]); | |
| 1892 | - else | |
| 1893 | - { | |
| 1894 | - cson_string * s = NULL; | |
| 1895 | - const size_t msz = sizeof(cson_string) + len + 1 /*NUL*/; | |
| 1896 | - unsigned char * mem = NULL; | |
| 1897 | - if( msz < (sizeof(cson_string)+len) ) /*overflow*/ return NULL; | |
| 1898 | - mem = (unsigned char *)cson_malloc( msz, "cson_string_alloc" ); | |
| 1899 | - if( mem ) | |
| 1900 | - { | |
| 1901 | - memset( mem, 0, msz ); | |
| 1902 | - s = (cson_string *)mem; | |
| 1903 | - s->length = len; | |
| 1904 | - } | |
| 1905 | - return s; | |
| 1906 | - } | |
| 1907 | -} | |
| 1908 | - | |
| 1909 | 1878 | unsigned int cson_string_length_bytes( cson_string const * str ) |
| 1910 | 1879 | { |
| 1911 | 1880 | return str ? str->length : 0; |
| 1912 | 1881 | } |
| 1913 | 1882 | |
| @@ -1974,33 +1943,10 @@ | ||
| 1974 | 1943 | memset( rc, 0, n+1 ); |
| 1975 | 1944 | rc[n] = 0; |
| 1976 | 1945 | return strncpy( rc, src, n ); |
| 1977 | 1946 | } |
| 1978 | 1947 | #endif |
| 1979 | - | |
| 1980 | -/** | |
| 1981 | - Allocates a new cson_string() from the the first n bytes of src. | |
| 1982 | - Returns NULL on allocation error, else the caller owns the returned | |
| 1983 | - object and must eventually free() it. | |
| 1984 | -*/ | |
| 1985 | -static cson_string * cson_string_strdup( char const * src, size_t n ) | |
| 1986 | -{ | |
| 1987 | - cson_string * cs = cson_string_alloc(n); | |
| 1988 | - if( ! cs ) return NULL; | |
| 1989 | - else if( &CSON_EMPTY_HOLDER.stringValue == cs ) return cs; | |
| 1990 | - else | |
| 1991 | - { | |
| 1992 | - char * cstr = cson_string_str(cs); | |
| 1993 | - assert( cs->length == n ); | |
| 1994 | - if( cstr && n ) | |
| 1995 | - { | |
| 1996 | - strncpy( cstr, src, n ); | |
| 1997 | - } | |
| 1998 | - return cs; | |
| 1999 | - } | |
| 2000 | -} | |
| 2001 | - | |
| 2002 | 1948 | |
| 2003 | 1949 | int cson_string_cmp_cstr_n( cson_string const * str, char const * other, unsigned int otherLen ) |
| 2004 | 1950 | { |
| 2005 | 1951 | if( ! other && !str ) return 0; |
| 2006 | 1952 | else if( other && !str ) return 1; |
| @@ -2045,14 +1991,11 @@ | ||
| 2045 | 1991 | Each of these objects owns its key/value pointers, and they |
| 2046 | 1992 | are cleaned up by cson_kvp_clean(). |
| 2047 | 1993 | */ |
| 2048 | 1994 | struct cson_kvp |
| 2049 | 1995 | { |
| 2050 | - /* FIXME: switch to cson_value keys. Calling cson_string_value() | |
| 2051 | - on one of these guys will read invalid memory. | |
| 2052 | - */ | |
| 2053 | - cson_string * key; | |
| 1996 | + cson_value * key; | |
| 2054 | 1997 | cson_value * value; |
| 2055 | 1998 | }; |
| 2056 | 1999 | #define cson_kvp_empty_m {NULL,NULL} |
| 2057 | 2000 | static const cson_kvp cson_kvp_empty = cson_kvp_empty_m; |
| 2058 | 2001 | |
| @@ -2087,45 +2030,21 @@ | ||
| 2087 | 2030 | */ |
| 2088 | 2031 | #define CSON_OBJECT_PROPS_SORT_USE_LENGTH 0 |
| 2089 | 2032 | |
| 2090 | 2033 | #if CSON_OBJECT_PROPS_SORT |
| 2091 | 2034 | |
| 2092 | -#if 0 | |
| 2093 | -/* i would prefer case-insensitive sorting but keys need | |
| 2094 | - to be case-sensitive for search purposes. | |
| 2095 | - | |
| 2096 | - TODO? write a comparitor which reverses the default | |
| 2097 | - sort order of upper/lower-case. The current behaviour | |
| 2098 | - is a bit non-intuitive, where 'Z' < 'a'. | |
| 2099 | -*/ | |
| 2100 | -static int cson_kvp_strcmp( char const * l, char const * r ) | |
| 2101 | -{ | |
| 2102 | - char cl; | |
| 2103 | - char cr; | |
| 2104 | - for( ; *l && *r; ++l, ++r ) | |
| 2105 | - { | |
| 2106 | - cl = tolower(*l); | |
| 2107 | - cr = tolower(*r); | |
| 2108 | - if( cl < cr ) return -1; | |
| 2109 | - else if( cl > cr ) return 1; | |
| 2110 | - } | |
| 2111 | - if( !*l && !*r ) return 0; | |
| 2112 | - else return (*l) ? 1 : -1; | |
| 2113 | -} | |
| 2114 | -#endif | |
| 2115 | - | |
| 2116 | 2035 | /** |
| 2117 | 2036 | cson_kvp comparator for use with qsort(). ALMOST compares with |
| 2118 | 2037 | strcmp() semantics, but it uses the strings' lengths as a quicker |
| 2119 | 2038 | approach. This might give non-intuitive results, but it's faster. |
| 2120 | 2039 | */ |
| 2121 | 2040 | static int cson_kvp_cmp( void const * lhs, void const * rhs ) |
| 2122 | 2041 | { |
| 2123 | 2042 | cson_kvp const * lk = *((cson_kvp const * const*)lhs); |
| 2124 | 2043 | cson_kvp const * rk = *((cson_kvp const * const*)rhs); |
| 2125 | - cson_string const * l = lk->key; | |
| 2126 | - cson_string const * r = rk->key; | |
| 2044 | + cson_string const * l = cson_string_value(lk->key); | |
| 2045 | + cson_string const * r = cson_string_value(rk->key); | |
| 2127 | 2046 | #if CSON_OBJECT_PROPS_SORT_USE_LENGTH |
| 2128 | 2047 | if( l->length < r->length ) return -1; |
| 2129 | 2048 | else if( l->length > r->length ) return 1; |
| 2130 | 2049 | else return strcmp( cson_string_cstr( l ), cson_string_cstr( r ) ); |
| 2131 | 2050 | #else |
| @@ -2135,10 +2054,11 @@ | ||
| 2135 | 2054 | } |
| 2136 | 2055 | #endif /*CSON_OBJECT_PROPS_SORT*/ |
| 2137 | 2056 | |
| 2138 | 2057 | |
| 2139 | 2058 | #if CSON_OBJECT_PROPS_SORT |
| 2059 | +#error "Need to rework this for cson_string-to-cson_value refactoring" | |
| 2140 | 2060 | /** |
| 2141 | 2061 | A bsearch() comparison function which requires that lhs be a (char |
| 2142 | 2062 | const *) and rhs be-a (cson_kvp const * const *). It compares lhs |
| 2143 | 2063 | to rhs->key's value, using strcmp() semantics. |
| 2144 | 2064 | */ |
| @@ -2450,11 +2370,11 @@ | ||
| 2450 | 2370 | { |
| 2451 | 2371 | if( kvp ) |
| 2452 | 2372 | { |
| 2453 | 2373 | if(kvp->key) |
| 2454 | 2374 | { |
| 2455 | - cson_free(kvp->key,"cson_kvp::key"); | |
| 2375 | + cson_value_free(kvp->key); | |
| 2456 | 2376 | kvp->key = NULL; |
| 2457 | 2377 | } |
| 2458 | 2378 | if(kvp->value) |
| 2459 | 2379 | { |
| 2460 | 2380 | cson_value_free( kvp->value ); |
| @@ -2463,11 +2383,11 @@ | ||
| 2463 | 2383 | } |
| 2464 | 2384 | } |
| 2465 | 2385 | |
| 2466 | 2386 | cson_string const * cson_kvp_key( cson_kvp const * kvp ) |
| 2467 | 2387 | { |
| 2468 | - return kvp ? kvp->key : NULL; | |
| 2388 | + return kvp ? cson_value_get_string(kvp->key) : NULL; | |
| 2469 | 2389 | } |
| 2470 | 2390 | cson_value * cson_kvp_value( cson_kvp const * kvp ) |
| 2471 | 2391 | { |
| 2472 | 2392 | return kvp ? kvp->value : NULL; |
| 2473 | 2393 | } |
| @@ -2554,33 +2474,10 @@ | ||
| 2554 | 2474 | cson_array_clean( ar, 1 ); |
| 2555 | 2475 | *self = cson_value_undef; |
| 2556 | 2476 | } |
| 2557 | 2477 | } |
| 2558 | 2478 | |
| 2559 | - | |
| 2560 | -#if 0 | |
| 2561 | -static void cson_kvp_list_item_clean( void * kvp ); | |
| 2562 | -static void cson_value_list_item_clean( void * val ); | |
| 2563 | -void cson_value_list_item_clean( void * val_ ) | |
| 2564 | -{ | |
| 2565 | - cson_value * val = (cson_value*)val_; | |
| 2566 | - if( val ) | |
| 2567 | - { | |
| 2568 | - cson_value_clean(val); | |
| 2569 | - } | |
| 2570 | -} | |
| 2571 | -void cson_kvp_list_item_clean( void * val ) | |
| 2572 | -{ | |
| 2573 | - cson_kvp * kvp = (cson_kvp *)val; | |
| 2574 | - if( kvp ) | |
| 2575 | - { | |
| 2576 | - cson_free(kvp->key,"cson_kvp::key"); | |
| 2577 | - cson_value_clean( &kvp->value ); | |
| 2578 | - } | |
| 2579 | -} | |
| 2580 | -#endif | |
| 2581 | - | |
| 2582 | 2479 | int cson_buffer_fill_from( cson_buffer * dest, cson_data_source_f src, void * state ) |
| 2583 | 2480 | { |
| 2584 | 2481 | int rc; |
| 2585 | 2482 | enum { BufSize = 1024 * 4 }; |
| 2586 | 2483 | char rbuf[BufSize]; |
| @@ -2926,10 +2823,15 @@ | ||
| 2926 | 2823 | |
| 2927 | 2824 | cson_value * cson_value_null() |
| 2928 | 2825 | { |
| 2929 | 2826 | return &CSON_SPECIAL_VALUES[CSON_VAL_NULL]; |
| 2930 | 2827 | } |
| 2828 | + | |
| 2829 | +cson_value * cson_new_int( cson_int_t v ) | |
| 2830 | +{ | |
| 2831 | + return cson_value_new_integer(v); | |
| 2832 | +} | |
| 2931 | 2833 | |
| 2932 | 2834 | cson_value * cson_value_new_integer( cson_int_t v ) |
| 2933 | 2835 | { |
| 2934 | 2836 | if( 0 == v ) return &CSON_SPECIAL_VALUES[CSON_VAL_INT_0]; |
| 2935 | 2837 | else |
| @@ -2941,10 +2843,15 @@ | ||
| 2941 | 2843 | *CSON_INT(c) = v; |
| 2942 | 2844 | } |
| 2943 | 2845 | return c; |
| 2944 | 2846 | } |
| 2945 | 2847 | } |
| 2848 | + | |
| 2849 | +cson_value * cson_new_double( cson_double_t v ) | |
| 2850 | +{ | |
| 2851 | + return cson_value_new_double(v); | |
| 2852 | +} | |
| 2946 | 2853 | |
| 2947 | 2854 | cson_value * cson_value_new_double( cson_double_t v ) |
| 2948 | 2855 | { |
| 2949 | 2856 | if( 0.0 == v ) return &CSON_SPECIAL_VALUES[CSON_VAL_DBL_0]; |
| 2950 | 2857 | else |
| @@ -2956,11 +2863,11 @@ | ||
| 2956 | 2863 | } |
| 2957 | 2864 | return c; |
| 2958 | 2865 | } |
| 2959 | 2866 | } |
| 2960 | 2867 | |
| 2961 | -cson_string const * cson_new_string(char const * str, unsigned int len) | |
| 2868 | +cson_string * cson_new_string(char const * str, unsigned int len) | |
| 2962 | 2869 | { |
| 2963 | 2870 | if( !str || !*str || !len ) return &CSON_EMPTY_HOLDER.stringValue; |
| 2964 | 2871 | else |
| 2965 | 2872 | { |
| 2966 | 2873 | cson_value * c = cson_value_new(CSON_TYPE_STRING, len + 1/*NUL byte*/); |
| @@ -3100,14 +3007,17 @@ | ||
| 3100 | 3007 | unsigned int i = 0; |
| 3101 | 3008 | cson_kvp * kvp; |
| 3102 | 3009 | const unsigned int klen = strlen(key); |
| 3103 | 3010 | for( ; i < li->count; ++i ) |
| 3104 | 3011 | { |
| 3012 | + cson_string const * sKey; | |
| 3105 | 3013 | kvp = li->list[i]; |
| 3106 | 3014 | assert( kvp && kvp->key ); |
| 3107 | - if( kvp->key->length != klen ) continue; | |
| 3108 | - else if(0==strcmp(key,cson_string_cstr(kvp->key))) | |
| 3015 | + sKey = cson_value_get_string(kvp->key); | |
| 3016 | + assert(sKey); | |
| 3017 | + if( sKey->length != klen ) continue; | |
| 3018 | + else if(0==strcmp(key,cson_string_cstr(sKey))) | |
| 3109 | 3019 | { |
| 3110 | 3020 | if(ndx) *ndx = i; |
| 3111 | 3021 | return kvp; |
| 3112 | 3022 | } |
| 3113 | 3023 | } |
| @@ -3166,67 +3076,91 @@ | ||
| 3166 | 3076 | #endif |
| 3167 | 3077 | return 0; |
| 3168 | 3078 | } |
| 3169 | 3079 | } |
| 3170 | 3080 | |
| 3081 | +int cson_object_set_s( cson_object * obj, cson_string * key, cson_value * v ) | |
| 3082 | +{ | |
| 3083 | + if( !obj || !key ) return cson_rc.ArgError; | |
| 3084 | + else if( NULL == v ) return cson_object_unset( obj, cson_string_cstr(key) ); | |
| 3085 | + else | |
| 3086 | + { | |
| 3087 | + char const * cKey; | |
| 3088 | + cson_value * vKey; | |
| 3089 | + cson_kvp * kvp; | |
| 3090 | + vKey = cson_string_value(key); | |
| 3091 | + assert(vKey && (key==CSON_STR(vKey))); | |
| 3092 | + if( vKey == CSON_VCAST(obj) ){ | |
| 3093 | + return cson_rc.ArgError; | |
| 3094 | + } | |
| 3095 | + cKey = cson_string_cstr(key); | |
| 3096 | + kvp = cson_object_search_impl( obj, cKey, NULL ); | |
| 3097 | + if( kvp ) | |
| 3098 | + { /* "I told 'em we've already got one!" */ | |
| 3099 | + if( kvp->key != vKey ){ | |
| 3100 | + cson_value_free( kvp->key ); | |
| 3101 | + cson_refcount_incr(vKey); | |
| 3102 | + kvp->key = vKey; | |
| 3103 | + } | |
| 3104 | + if(kvp->value != v){ | |
| 3105 | + cson_value_free( kvp->value ); | |
| 3106 | + cson_refcount_incr( v ); | |
| 3107 | + kvp->value = v; | |
| 3108 | + } | |
| 3109 | + return 0; | |
| 3110 | + } | |
| 3111 | + if( !obj->kvp.alloced || (obj->kvp.count == obj->kvp.alloced-1)) | |
| 3112 | + { | |
| 3113 | + unsigned int const n = obj->kvp.count ? (obj->kvp.count*2) : 6; | |
| 3114 | + if( n > cson_kvp_list_reserve( &obj->kvp, n ) ) | |
| 3115 | + { | |
| 3116 | + return cson_rc.AllocError; | |
| 3117 | + } | |
| 3118 | + } | |
| 3119 | + { /* insert new item... */ | |
| 3120 | + int rc = 0; | |
| 3121 | + kvp = cson_kvp_alloc(); | |
| 3122 | + if( ! kvp ) | |
| 3123 | + { | |
| 3124 | + return cson_rc.AllocError; | |
| 3125 | + } | |
| 3126 | + rc = cson_kvp_list_append( &obj->kvp, kvp ); | |
| 3127 | + if( 0 != rc ) | |
| 3128 | + { | |
| 3129 | + cson_kvp_free(kvp); | |
| 3130 | + } | |
| 3131 | + else | |
| 3132 | + { | |
| 3133 | + cson_refcount_incr(vKey); | |
| 3134 | + cson_refcount_incr(v); | |
| 3135 | + kvp->key = vKey; | |
| 3136 | + kvp->value = v; | |
| 3137 | +#if CSON_OBJECT_PROPS_SORT | |
| 3138 | + cson_object_sort_props( obj ); | |
| 3139 | +#endif | |
| 3140 | + } | |
| 3141 | + return rc; | |
| 3142 | + } | |
| 3143 | + } | |
| 3144 | + | |
| 3145 | +} | |
| 3171 | 3146 | int cson_object_set( cson_object * obj, char const * key, cson_value * v ) |
| 3172 | 3147 | { |
| 3173 | 3148 | if( ! obj || !key || !*key ) return cson_rc.ArgError; |
| 3174 | 3149 | else if( NULL == v ) |
| 3175 | 3150 | { |
| 3176 | 3151 | return cson_object_unset( obj, key ); |
| 3177 | 3152 | } |
| 3178 | 3153 | else |
| 3179 | 3154 | { |
| 3180 | - cson_kvp * kvp = cson_object_search_impl( obj, key, NULL ); | |
| 3181 | - if( kvp ) | |
| 3182 | - { /* "I told 'em we've already got one!" */ | |
| 3183 | - if( v == kvp->value ) return 0 /* actually a usage error */; | |
| 3184 | - else | |
| 3185 | - { | |
| 3186 | - cson_value_free( kvp->value ); | |
| 3187 | - cson_refcount_incr( v ); | |
| 3188 | - kvp->value = v; | |
| 3189 | - return 0; | |
| 3190 | - } | |
| 3191 | - } | |
| 3192 | - if( !obj->kvp.alloced || (obj->kvp.count == obj->kvp.alloced-1)) | |
| 3193 | - { | |
| 3194 | - unsigned int const n = obj->kvp.count ? (obj->kvp.count*2) : 7; | |
| 3195 | - if( n > cson_kvp_list_reserve( &obj->kvp, n ) ) | |
| 3196 | - { | |
| 3197 | - return cson_rc.AllocError; | |
| 3198 | - } | |
| 3199 | - } | |
| 3200 | - { /* insert new item... */ | |
| 3201 | - int rc = 0; | |
| 3202 | - cson_string * keycp = cson_string_strdup(key, strlen(key)); | |
| 3203 | - if( ! keycp ) | |
| 3204 | - { | |
| 3205 | - return cson_rc.AllocError; | |
| 3206 | - } | |
| 3207 | - kvp = cson_kvp_alloc(); | |
| 3208 | - if( ! kvp ) | |
| 3209 | - { | |
| 3210 | - cson_free(keycp,"cson_parser::key"); | |
| 3211 | - return cson_rc.AllocError; | |
| 3212 | - } | |
| 3213 | - kvp->key = keycp /* transfer ownership */; | |
| 3214 | - rc = cson_kvp_list_append( &obj->kvp, kvp ); | |
| 3215 | - if( 0 != rc ) | |
| 3216 | - { | |
| 3217 | - cson_kvp_free(kvp); | |
| 3218 | - } | |
| 3219 | - else | |
| 3220 | - { | |
| 3221 | - cson_refcount_incr( v ); | |
| 3222 | - kvp->value = v /* transfer ownership */; | |
| 3223 | -#if CSON_OBJECT_PROPS_SORT | |
| 3224 | - cson_object_sort_props( obj ); | |
| 3225 | -#endif | |
| 3226 | - } | |
| 3227 | - return 0; | |
| 3155 | + cson_string * cs = cson_new_string(key,strlen(key)); | |
| 3156 | + if(!cs) return cson_rc.AllocError; | |
| 3157 | + else | |
| 3158 | + { | |
| 3159 | + int const rc = cson_object_set_s(obj, cs, v); | |
| 3160 | + if(rc) cson_value_free(cson_string_value(cs)); | |
| 3161 | + return rc; | |
| 3228 | 3162 | } |
| 3229 | 3163 | } |
| 3230 | 3164 | } |
| 3231 | 3165 | |
| 3232 | 3166 | cson_value * cson_object_take( cson_object * obj, char const * key ) |
| @@ -3311,11 +3245,11 @@ | ||
| 3311 | 3245 | if( ! kvp ) |
| 3312 | 3246 | { |
| 3313 | 3247 | cson_value_free(val); |
| 3314 | 3248 | return cson_rc.AllocError; |
| 3315 | 3249 | } |
| 3316 | - kvp->key = p->ckey/*transfer ownership*/; | |
| 3250 | + kvp->key = cson_string_value(p->ckey)/*transfer ownership*/; | |
| 3317 | 3251 | p->ckey = NULL; |
| 3318 | 3252 | kvp->value = val; |
| 3319 | 3253 | cson_refcount_incr( val ); |
| 3320 | 3254 | rc = cson_kvp_list_append( &obj->kvp, kvp ); |
| 3321 | 3255 | if( 0 != rc ) |
| @@ -3507,11 +3441,11 @@ | ||
| 3507 | 3441 | rc = cson_parser_push_value( p, cson_value_false() ); |
| 3508 | 3442 | break; |
| 3509 | 3443 | } |
| 3510 | 3444 | case JSON_T_KEY: { |
| 3511 | 3445 | assert(!p->ckey); |
| 3512 | - p->ckey = cson_string_strdup( value->vu.str.value, value->vu.str.length ); | |
| 3446 | + p->ckey = cson_new_string( value->vu.str.value, value->vu.str.length ); | |
| 3513 | 3447 | if( ! p->ckey ) |
| 3514 | 3448 | { |
| 3515 | 3449 | rc = cson_rc.AllocError; |
| 3516 | 3450 | break; |
| 3517 | 3451 | } |
| @@ -3580,11 +3514,13 @@ | ||
| 3580 | 3514 | if( p->p ) |
| 3581 | 3515 | { |
| 3582 | 3516 | delete_JSON_parser(p->p); |
| 3583 | 3517 | p->p = NULL; |
| 3584 | 3518 | } |
| 3585 | - cson_free( p->ckey, "cson_parser::key" ); | |
| 3519 | + if( p->ckey ){ | |
| 3520 | + cson_value_free(cson_string_value(p->ckey)); | |
| 3521 | + } | |
| 3586 | 3522 | cson_array_clean( &p->stack, 1 ); |
| 3587 | 3523 | if( p->root ) |
| 3588 | 3524 | { |
| 3589 | 3525 | cson_value_free( p->root ); |
| 3590 | 3526 | } |
| @@ -4192,11 +4128,13 @@ | ||
| 4192 | 4128 | for( i = 0; (i < obj->kvp.count) && (0 == rc); ++i ) |
| 4193 | 4129 | { |
| 4194 | 4130 | kvp = obj->kvp.list[i]; |
| 4195 | 4131 | if( kvp && kvp->key ) |
| 4196 | 4132 | { |
| 4197 | - rc = cson_str_to_json(cson_string_cstr(kvp->key), kvp->key->length, | |
| 4133 | + cson_string const * sKey = cson_value_get_string(kvp->key); | |
| 4134 | + char const * cKey = cson_string_cstr(sKey); | |
| 4135 | + rc = cson_str_to_json(cKey, sKey->length, | |
| 4198 | 4136 | fmt->escapeForwardSlashes, f, state); |
| 4199 | 4137 | if( 0 == rc ) |
| 4200 | 4138 | { |
| 4201 | 4139 | rc = fmt->addSpaceAfterColon |
| 4202 | 4140 | ? f(state, ": ", 2 ) |
| @@ -4638,26 +4576,42 @@ | ||
| 4638 | 4576 | cson_kvp const * kvp = NULL; |
| 4639 | 4577 | cson_object_iterator iter = cson_object_iterator_empty; |
| 4640 | 4578 | assert( orig && src ); |
| 4641 | 4579 | if( 0 != cson_object_iter_init( src, &iter ) ) |
| 4642 | 4580 | { |
| 4643 | - cson_value_free( destV ); | |
| 4644 | 4581 | return NULL; |
| 4645 | 4582 | } |
| 4646 | 4583 | destV = cson_value_new_object(); |
| 4647 | 4584 | if( NULL == destV ) return NULL; |
| 4648 | 4585 | dest = cson_value_get_object( destV ); |
| 4649 | 4586 | assert( dest ); |
| 4587 | + if( src->kvp.count > cson_kvp_list_reserve( &dest->kvp, src->kvp.count ) ){ | |
| 4588 | + cson_value_free( destV ); | |
| 4589 | + return NULL; | |
| 4590 | + } | |
| 4650 | 4591 | while( (kvp = cson_object_iter_next( &iter )) ) |
| 4651 | 4592 | { |
| 4652 | - cson_string const * key = cson_kvp_key( kvp ); | |
| 4653 | - cson_value const * val = cson_kvp_value( kvp ); | |
| 4654 | - if( 0 != cson_object_set( dest, | |
| 4655 | - cson_string_cstr( key ), | |
| 4656 | - cson_value_clone( val ) ) ) | |
| 4593 | + /* | |
| 4594 | + FIXME: refcount the keys! We first need a setter which takes | |
| 4595 | + a cson_string or cson_value key type. | |
| 4596 | + */ | |
| 4597 | + cson_value * key = NULL; | |
| 4598 | + cson_value * val = NULL; | |
| 4599 | + key = cson_value_clone(kvp->key); | |
| 4600 | + val = key ? cson_value_clone( kvp->value ) : NULL; | |
| 4601 | + if( ! key || !val ){ | |
| 4602 | + cson_value_free(key); | |
| 4603 | + cson_value_free(val); | |
| 4604 | + cson_value_free(destV); | |
| 4605 | + return NULL; | |
| 4606 | + } | |
| 4607 | + assert( CSON_STR(key) ); | |
| 4608 | + if( 0 != cson_object_set_s( dest, CSON_STR(key), val ) ) | |
| 4657 | 4609 | { |
| 4658 | - cson_value_free( destV ); | |
| 4610 | + cson_value_free(key); | |
| 4611 | + cson_value_free(val); | |
| 4612 | + cson_value_free(destV); | |
| 4659 | 4613 | return NULL; |
| 4660 | 4614 | } |
| 4661 | 4615 | } |
| 4662 | 4616 | return destV; |
| 4663 | 4617 | } |
| @@ -4719,10 +4673,27 @@ | ||
| 4719 | 4673 | return s |
| 4720 | 4674 | ? CSON_VCAST(s) |
| 4721 | 4675 | : NULL; |
| 4722 | 4676 | } |
| 4723 | 4677 | |
| 4678 | +void cson_free_object(cson_object *x) | |
| 4679 | +{ | |
| 4680 | + if(x) cson_value_free(cson_object_value(x)); | |
| 4681 | +} | |
| 4682 | +void cson_free_array(cson_array *x) | |
| 4683 | +{ | |
| 4684 | + if(x) cson_value_free(cson_array_value(x)); | |
| 4685 | +} | |
| 4686 | + | |
| 4687 | +void cson_free_string(cson_string const *x) | |
| 4688 | +{ | |
| 4689 | + if(x) cson_value_free(cson_string_value(x)); | |
| 4690 | +} | |
| 4691 | +void cson_free_value(cson_value *x) | |
| 4692 | +{ | |
| 4693 | + cson_value_free(x); | |
| 4694 | +} | |
| 4724 | 4695 | |
| 4725 | 4696 | |
| 4726 | 4697 | #if 0 |
| 4727 | 4698 | /* i'm not happy with this... */ |
| 4728 | 4699 | char * cson_pod_to_string( cson_value const * orig ) |
| @@ -4826,10 +4797,74 @@ | ||
| 4826 | 4797 | } |
| 4827 | 4798 | return v; |
| 4828 | 4799 | } |
| 4829 | 4800 | } |
| 4830 | 4801 | #endif |
| 4802 | + | |
| 4803 | +unsigned int cson_value_msize(cson_value const * v) | |
| 4804 | +{ | |
| 4805 | + if(!v) return 0; | |
| 4806 | + else if( cson_value_is_builtin(v) ) return 0; | |
| 4807 | + else { | |
| 4808 | + unsigned int rc = sizeof(cson_value); | |
| 4809 | + assert(NULL != v->api); | |
| 4810 | + switch(v->api->typeID){ | |
| 4811 | + case CSON_TYPE_INTEGER: | |
| 4812 | + assert( v != &CSON_SPECIAL_VALUES[CSON_VAL_INT_0]); | |
| 4813 | + rc += sizeof(cson_int_t); | |
| 4814 | + break; | |
| 4815 | + case CSON_TYPE_DOUBLE: | |
| 4816 | + assert( v != &CSON_SPECIAL_VALUES[CSON_VAL_DBL_0]); | |
| 4817 | + rc += sizeof(cson_double_t); | |
| 4818 | + break; | |
| 4819 | + case CSON_TYPE_STRING: | |
| 4820 | + rc += sizeof(cson_string) | |
| 4821 | + + CSON_STR(v)->length + 1/*NUL*/; | |
| 4822 | + break; | |
| 4823 | + case CSON_TYPE_ARRAY:{ | |
| 4824 | + cson_array const * ar = CSON_ARRAY(v); | |
| 4825 | + cson_value_list const * li; | |
| 4826 | + unsigned int i = 0; | |
| 4827 | + assert( NULL != ar ); | |
| 4828 | + li = &ar->list; | |
| 4829 | + rc += sizeof(cson_array) | |
| 4830 | + + (li->alloced * sizeof(cson_value *)); | |
| 4831 | + for( ; i < li->count; ++i ){ | |
| 4832 | + cson_value const * e = ar->list.list[i]; | |
| 4833 | + if( e ) rc += cson_value_msize( e ); | |
| 4834 | + } | |
| 4835 | + break; | |
| 4836 | + } | |
| 4837 | + case CSON_TYPE_OBJECT:{ | |
| 4838 | + cson_object const * obj = CSON_OBJ(v); | |
| 4839 | + unsigned int i = 0; | |
| 4840 | + cson_kvp_list const * kl; | |
| 4841 | + assert(NULL != obj); | |
| 4842 | + kl = &obj->kvp; | |
| 4843 | + rc += sizeof(cson_object) | |
| 4844 | + + (kl->alloced * sizeof(cson_kvp*)); | |
| 4845 | + for( ; i < kl->count; ++i ){ | |
| 4846 | + cson_kvp const * kvp = kl->list[i]; | |
| 4847 | + assert(NULL != kvp); | |
| 4848 | + rc += cson_value_msize(kvp->key); | |
| 4849 | + rc += cson_value_msize(kvp->value); | |
| 4850 | + } | |
| 4851 | + break; | |
| 4852 | + } | |
| 4853 | + case CSON_TYPE_UNDEF: | |
| 4854 | + case CSON_TYPE_NULL: | |
| 4855 | + case CSON_TYPE_BOOL: | |
| 4856 | + assert( 0 && "Should have been caught by is-builtin check!" ); | |
| 4857 | + break; | |
| 4858 | + default: | |
| 4859 | + assert(0 && "Invalid typeID!"); | |
| 4860 | + return 0; | |
| 4861 | + | |
| 4862 | + } | |
| 4863 | + return rc; | |
| 4864 | + } | |
| 4865 | +} | |
| 4831 | 4866 | |
| 4832 | 4867 | #if defined(__cplusplus) |
| 4833 | 4868 | } /*extern "C"*/ |
| 4834 | 4869 | #endif |
| 4835 | 4870 | |
| 4836 | 4871 |
| --- src/cson_amalgamation.c | |
| +++ src/cson_amalgamation.c | |
| @@ -1873,41 +1873,10 @@ | |
| 1873 | return 0; |
| 1874 | } |
| 1875 | else return cv->refcount; |
| 1876 | } |
| 1877 | |
| 1878 | /** |
| 1879 | Allocates a new cson_string object with enough space for |
| 1880 | the given number of bytes. A byte for a NUL terminator |
| 1881 | is added automatically. Use cson_string_str() to get |
| 1882 | access to the string bytes, which will be len bytes long. |
| 1883 | |
| 1884 | len may be 0, in which case the internal string is "", as opposed |
| 1885 | to null. This is because the string bytes and the cson_string are |
| 1886 | allocated in a single chunk of memory, and the cson_string object |
| 1887 | does not directly provide (or have) a pointer to the string bytes. |
| 1888 | */ |
| 1889 | static cson_string * cson_string_alloc(unsigned int len) |
| 1890 | { |
| 1891 | if( ! len ) return CSON_STR(&CSON_SPECIAL_VALUES[CSON_VAL_STR_EMPTY]); |
| 1892 | else |
| 1893 | { |
| 1894 | cson_string * s = NULL; |
| 1895 | const size_t msz = sizeof(cson_string) + len + 1 /*NUL*/; |
| 1896 | unsigned char * mem = NULL; |
| 1897 | if( msz < (sizeof(cson_string)+len) ) /*overflow*/ return NULL; |
| 1898 | mem = (unsigned char *)cson_malloc( msz, "cson_string_alloc" ); |
| 1899 | if( mem ) |
| 1900 | { |
| 1901 | memset( mem, 0, msz ); |
| 1902 | s = (cson_string *)mem; |
| 1903 | s->length = len; |
| 1904 | } |
| 1905 | return s; |
| 1906 | } |
| 1907 | } |
| 1908 | |
| 1909 | unsigned int cson_string_length_bytes( cson_string const * str ) |
| 1910 | { |
| 1911 | return str ? str->length : 0; |
| 1912 | } |
| 1913 | |
| @@ -1974,33 +1943,10 @@ | |
| 1974 | memset( rc, 0, n+1 ); |
| 1975 | rc[n] = 0; |
| 1976 | return strncpy( rc, src, n ); |
| 1977 | } |
| 1978 | #endif |
| 1979 | |
| 1980 | /** |
| 1981 | Allocates a new cson_string() from the the first n bytes of src. |
| 1982 | Returns NULL on allocation error, else the caller owns the returned |
| 1983 | object and must eventually free() it. |
| 1984 | */ |
| 1985 | static cson_string * cson_string_strdup( char const * src, size_t n ) |
| 1986 | { |
| 1987 | cson_string * cs = cson_string_alloc(n); |
| 1988 | if( ! cs ) return NULL; |
| 1989 | else if( &CSON_EMPTY_HOLDER.stringValue == cs ) return cs; |
| 1990 | else |
| 1991 | { |
| 1992 | char * cstr = cson_string_str(cs); |
| 1993 | assert( cs->length == n ); |
| 1994 | if( cstr && n ) |
| 1995 | { |
| 1996 | strncpy( cstr, src, n ); |
| 1997 | } |
| 1998 | return cs; |
| 1999 | } |
| 2000 | } |
| 2001 | |
| 2002 | |
| 2003 | int cson_string_cmp_cstr_n( cson_string const * str, char const * other, unsigned int otherLen ) |
| 2004 | { |
| 2005 | if( ! other && !str ) return 0; |
| 2006 | else if( other && !str ) return 1; |
| @@ -2045,14 +1991,11 @@ | |
| 2045 | Each of these objects owns its key/value pointers, and they |
| 2046 | are cleaned up by cson_kvp_clean(). |
| 2047 | */ |
| 2048 | struct cson_kvp |
| 2049 | { |
| 2050 | /* FIXME: switch to cson_value keys. Calling cson_string_value() |
| 2051 | on one of these guys will read invalid memory. |
| 2052 | */ |
| 2053 | cson_string * key; |
| 2054 | cson_value * value; |
| 2055 | }; |
| 2056 | #define cson_kvp_empty_m {NULL,NULL} |
| 2057 | static const cson_kvp cson_kvp_empty = cson_kvp_empty_m; |
| 2058 | |
| @@ -2087,45 +2030,21 @@ | |
| 2087 | */ |
| 2088 | #define CSON_OBJECT_PROPS_SORT_USE_LENGTH 0 |
| 2089 | |
| 2090 | #if CSON_OBJECT_PROPS_SORT |
| 2091 | |
| 2092 | #if 0 |
| 2093 | /* i would prefer case-insensitive sorting but keys need |
| 2094 | to be case-sensitive for search purposes. |
| 2095 | |
| 2096 | TODO? write a comparitor which reverses the default |
| 2097 | sort order of upper/lower-case. The current behaviour |
| 2098 | is a bit non-intuitive, where 'Z' < 'a'. |
| 2099 | */ |
| 2100 | static int cson_kvp_strcmp( char const * l, char const * r ) |
| 2101 | { |
| 2102 | char cl; |
| 2103 | char cr; |
| 2104 | for( ; *l && *r; ++l, ++r ) |
| 2105 | { |
| 2106 | cl = tolower(*l); |
| 2107 | cr = tolower(*r); |
| 2108 | if( cl < cr ) return -1; |
| 2109 | else if( cl > cr ) return 1; |
| 2110 | } |
| 2111 | if( !*l && !*r ) return 0; |
| 2112 | else return (*l) ? 1 : -1; |
| 2113 | } |
| 2114 | #endif |
| 2115 | |
| 2116 | /** |
| 2117 | cson_kvp comparator for use with qsort(). ALMOST compares with |
| 2118 | strcmp() semantics, but it uses the strings' lengths as a quicker |
| 2119 | approach. This might give non-intuitive results, but it's faster. |
| 2120 | */ |
| 2121 | static int cson_kvp_cmp( void const * lhs, void const * rhs ) |
| 2122 | { |
| 2123 | cson_kvp const * lk = *((cson_kvp const * const*)lhs); |
| 2124 | cson_kvp const * rk = *((cson_kvp const * const*)rhs); |
| 2125 | cson_string const * l = lk->key; |
| 2126 | cson_string const * r = rk->key; |
| 2127 | #if CSON_OBJECT_PROPS_SORT_USE_LENGTH |
| 2128 | if( l->length < r->length ) return -1; |
| 2129 | else if( l->length > r->length ) return 1; |
| 2130 | else return strcmp( cson_string_cstr( l ), cson_string_cstr( r ) ); |
| 2131 | #else |
| @@ -2135,10 +2054,11 @@ | |
| 2135 | } |
| 2136 | #endif /*CSON_OBJECT_PROPS_SORT*/ |
| 2137 | |
| 2138 | |
| 2139 | #if CSON_OBJECT_PROPS_SORT |
| 2140 | /** |
| 2141 | A bsearch() comparison function which requires that lhs be a (char |
| 2142 | const *) and rhs be-a (cson_kvp const * const *). It compares lhs |
| 2143 | to rhs->key's value, using strcmp() semantics. |
| 2144 | */ |
| @@ -2450,11 +2370,11 @@ | |
| 2450 | { |
| 2451 | if( kvp ) |
| 2452 | { |
| 2453 | if(kvp->key) |
| 2454 | { |
| 2455 | cson_free(kvp->key,"cson_kvp::key"); |
| 2456 | kvp->key = NULL; |
| 2457 | } |
| 2458 | if(kvp->value) |
| 2459 | { |
| 2460 | cson_value_free( kvp->value ); |
| @@ -2463,11 +2383,11 @@ | |
| 2463 | } |
| 2464 | } |
| 2465 | |
| 2466 | cson_string const * cson_kvp_key( cson_kvp const * kvp ) |
| 2467 | { |
| 2468 | return kvp ? kvp->key : NULL; |
| 2469 | } |
| 2470 | cson_value * cson_kvp_value( cson_kvp const * kvp ) |
| 2471 | { |
| 2472 | return kvp ? kvp->value : NULL; |
| 2473 | } |
| @@ -2554,33 +2474,10 @@ | |
| 2554 | cson_array_clean( ar, 1 ); |
| 2555 | *self = cson_value_undef; |
| 2556 | } |
| 2557 | } |
| 2558 | |
| 2559 | |
| 2560 | #if 0 |
| 2561 | static void cson_kvp_list_item_clean( void * kvp ); |
| 2562 | static void cson_value_list_item_clean( void * val ); |
| 2563 | void cson_value_list_item_clean( void * val_ ) |
| 2564 | { |
| 2565 | cson_value * val = (cson_value*)val_; |
| 2566 | if( val ) |
| 2567 | { |
| 2568 | cson_value_clean(val); |
| 2569 | } |
| 2570 | } |
| 2571 | void cson_kvp_list_item_clean( void * val ) |
| 2572 | { |
| 2573 | cson_kvp * kvp = (cson_kvp *)val; |
| 2574 | if( kvp ) |
| 2575 | { |
| 2576 | cson_free(kvp->key,"cson_kvp::key"); |
| 2577 | cson_value_clean( &kvp->value ); |
| 2578 | } |
| 2579 | } |
| 2580 | #endif |
| 2581 | |
| 2582 | int cson_buffer_fill_from( cson_buffer * dest, cson_data_source_f src, void * state ) |
| 2583 | { |
| 2584 | int rc; |
| 2585 | enum { BufSize = 1024 * 4 }; |
| 2586 | char rbuf[BufSize]; |
| @@ -2926,10 +2823,15 @@ | |
| 2926 | |
| 2927 | cson_value * cson_value_null() |
| 2928 | { |
| 2929 | return &CSON_SPECIAL_VALUES[CSON_VAL_NULL]; |
| 2930 | } |
| 2931 | |
| 2932 | cson_value * cson_value_new_integer( cson_int_t v ) |
| 2933 | { |
| 2934 | if( 0 == v ) return &CSON_SPECIAL_VALUES[CSON_VAL_INT_0]; |
| 2935 | else |
| @@ -2941,10 +2843,15 @@ | |
| 2941 | *CSON_INT(c) = v; |
| 2942 | } |
| 2943 | return c; |
| 2944 | } |
| 2945 | } |
| 2946 | |
| 2947 | cson_value * cson_value_new_double( cson_double_t v ) |
| 2948 | { |
| 2949 | if( 0.0 == v ) return &CSON_SPECIAL_VALUES[CSON_VAL_DBL_0]; |
| 2950 | else |
| @@ -2956,11 +2863,11 @@ | |
| 2956 | } |
| 2957 | return c; |
| 2958 | } |
| 2959 | } |
| 2960 | |
| 2961 | cson_string const * cson_new_string(char const * str, unsigned int len) |
| 2962 | { |
| 2963 | if( !str || !*str || !len ) return &CSON_EMPTY_HOLDER.stringValue; |
| 2964 | else |
| 2965 | { |
| 2966 | cson_value * c = cson_value_new(CSON_TYPE_STRING, len + 1/*NUL byte*/); |
| @@ -3100,14 +3007,17 @@ | |
| 3100 | unsigned int i = 0; |
| 3101 | cson_kvp * kvp; |
| 3102 | const unsigned int klen = strlen(key); |
| 3103 | for( ; i < li->count; ++i ) |
| 3104 | { |
| 3105 | kvp = li->list[i]; |
| 3106 | assert( kvp && kvp->key ); |
| 3107 | if( kvp->key->length != klen ) continue; |
| 3108 | else if(0==strcmp(key,cson_string_cstr(kvp->key))) |
| 3109 | { |
| 3110 | if(ndx) *ndx = i; |
| 3111 | return kvp; |
| 3112 | } |
| 3113 | } |
| @@ -3166,67 +3076,91 @@ | |
| 3166 | #endif |
| 3167 | return 0; |
| 3168 | } |
| 3169 | } |
| 3170 | |
| 3171 | int cson_object_set( cson_object * obj, char const * key, cson_value * v ) |
| 3172 | { |
| 3173 | if( ! obj || !key || !*key ) return cson_rc.ArgError; |
| 3174 | else if( NULL == v ) |
| 3175 | { |
| 3176 | return cson_object_unset( obj, key ); |
| 3177 | } |
| 3178 | else |
| 3179 | { |
| 3180 | cson_kvp * kvp = cson_object_search_impl( obj, key, NULL ); |
| 3181 | if( kvp ) |
| 3182 | { /* "I told 'em we've already got one!" */ |
| 3183 | if( v == kvp->value ) return 0 /* actually a usage error */; |
| 3184 | else |
| 3185 | { |
| 3186 | cson_value_free( kvp->value ); |
| 3187 | cson_refcount_incr( v ); |
| 3188 | kvp->value = v; |
| 3189 | return 0; |
| 3190 | } |
| 3191 | } |
| 3192 | if( !obj->kvp.alloced || (obj->kvp.count == obj->kvp.alloced-1)) |
| 3193 | { |
| 3194 | unsigned int const n = obj->kvp.count ? (obj->kvp.count*2) : 7; |
| 3195 | if( n > cson_kvp_list_reserve( &obj->kvp, n ) ) |
| 3196 | { |
| 3197 | return cson_rc.AllocError; |
| 3198 | } |
| 3199 | } |
| 3200 | { /* insert new item... */ |
| 3201 | int rc = 0; |
| 3202 | cson_string * keycp = cson_string_strdup(key, strlen(key)); |
| 3203 | if( ! keycp ) |
| 3204 | { |
| 3205 | return cson_rc.AllocError; |
| 3206 | } |
| 3207 | kvp = cson_kvp_alloc(); |
| 3208 | if( ! kvp ) |
| 3209 | { |
| 3210 | cson_free(keycp,"cson_parser::key"); |
| 3211 | return cson_rc.AllocError; |
| 3212 | } |
| 3213 | kvp->key = keycp /* transfer ownership */; |
| 3214 | rc = cson_kvp_list_append( &obj->kvp, kvp ); |
| 3215 | if( 0 != rc ) |
| 3216 | { |
| 3217 | cson_kvp_free(kvp); |
| 3218 | } |
| 3219 | else |
| 3220 | { |
| 3221 | cson_refcount_incr( v ); |
| 3222 | kvp->value = v /* transfer ownership */; |
| 3223 | #if CSON_OBJECT_PROPS_SORT |
| 3224 | cson_object_sort_props( obj ); |
| 3225 | #endif |
| 3226 | } |
| 3227 | return 0; |
| 3228 | } |
| 3229 | } |
| 3230 | } |
| 3231 | |
| 3232 | cson_value * cson_object_take( cson_object * obj, char const * key ) |
| @@ -3311,11 +3245,11 @@ | |
| 3311 | if( ! kvp ) |
| 3312 | { |
| 3313 | cson_value_free(val); |
| 3314 | return cson_rc.AllocError; |
| 3315 | } |
| 3316 | kvp->key = p->ckey/*transfer ownership*/; |
| 3317 | p->ckey = NULL; |
| 3318 | kvp->value = val; |
| 3319 | cson_refcount_incr( val ); |
| 3320 | rc = cson_kvp_list_append( &obj->kvp, kvp ); |
| 3321 | if( 0 != rc ) |
| @@ -3507,11 +3441,11 @@ | |
| 3507 | rc = cson_parser_push_value( p, cson_value_false() ); |
| 3508 | break; |
| 3509 | } |
| 3510 | case JSON_T_KEY: { |
| 3511 | assert(!p->ckey); |
| 3512 | p->ckey = cson_string_strdup( value->vu.str.value, value->vu.str.length ); |
| 3513 | if( ! p->ckey ) |
| 3514 | { |
| 3515 | rc = cson_rc.AllocError; |
| 3516 | break; |
| 3517 | } |
| @@ -3580,11 +3514,13 @@ | |
| 3580 | if( p->p ) |
| 3581 | { |
| 3582 | delete_JSON_parser(p->p); |
| 3583 | p->p = NULL; |
| 3584 | } |
| 3585 | cson_free( p->ckey, "cson_parser::key" ); |
| 3586 | cson_array_clean( &p->stack, 1 ); |
| 3587 | if( p->root ) |
| 3588 | { |
| 3589 | cson_value_free( p->root ); |
| 3590 | } |
| @@ -4192,11 +4128,13 @@ | |
| 4192 | for( i = 0; (i < obj->kvp.count) && (0 == rc); ++i ) |
| 4193 | { |
| 4194 | kvp = obj->kvp.list[i]; |
| 4195 | if( kvp && kvp->key ) |
| 4196 | { |
| 4197 | rc = cson_str_to_json(cson_string_cstr(kvp->key), kvp->key->length, |
| 4198 | fmt->escapeForwardSlashes, f, state); |
| 4199 | if( 0 == rc ) |
| 4200 | { |
| 4201 | rc = fmt->addSpaceAfterColon |
| 4202 | ? f(state, ": ", 2 ) |
| @@ -4638,26 +4576,42 @@ | |
| 4638 | cson_kvp const * kvp = NULL; |
| 4639 | cson_object_iterator iter = cson_object_iterator_empty; |
| 4640 | assert( orig && src ); |
| 4641 | if( 0 != cson_object_iter_init( src, &iter ) ) |
| 4642 | { |
| 4643 | cson_value_free( destV ); |
| 4644 | return NULL; |
| 4645 | } |
| 4646 | destV = cson_value_new_object(); |
| 4647 | if( NULL == destV ) return NULL; |
| 4648 | dest = cson_value_get_object( destV ); |
| 4649 | assert( dest ); |
| 4650 | while( (kvp = cson_object_iter_next( &iter )) ) |
| 4651 | { |
| 4652 | cson_string const * key = cson_kvp_key( kvp ); |
| 4653 | cson_value const * val = cson_kvp_value( kvp ); |
| 4654 | if( 0 != cson_object_set( dest, |
| 4655 | cson_string_cstr( key ), |
| 4656 | cson_value_clone( val ) ) ) |
| 4657 | { |
| 4658 | cson_value_free( destV ); |
| 4659 | return NULL; |
| 4660 | } |
| 4661 | } |
| 4662 | return destV; |
| 4663 | } |
| @@ -4719,10 +4673,27 @@ | |
| 4719 | return s |
| 4720 | ? CSON_VCAST(s) |
| 4721 | : NULL; |
| 4722 | } |
| 4723 | |
| 4724 | |
| 4725 | |
| 4726 | #if 0 |
| 4727 | /* i'm not happy with this... */ |
| 4728 | char * cson_pod_to_string( cson_value const * orig ) |
| @@ -4826,10 +4797,74 @@ | |
| 4826 | } |
| 4827 | return v; |
| 4828 | } |
| 4829 | } |
| 4830 | #endif |
| 4831 | |
| 4832 | #if defined(__cplusplus) |
| 4833 | } /*extern "C"*/ |
| 4834 | #endif |
| 4835 | |
| 4836 |
| --- src/cson_amalgamation.c | |
| +++ src/cson_amalgamation.c | |
| @@ -1873,41 +1873,10 @@ | |
| 1873 | return 0; |
| 1874 | } |
| 1875 | else return cv->refcount; |
| 1876 | } |
| 1877 | |
| 1878 | unsigned int cson_string_length_bytes( cson_string const * str ) |
| 1879 | { |
| 1880 | return str ? str->length : 0; |
| 1881 | } |
| 1882 | |
| @@ -1974,33 +1943,10 @@ | |
| 1943 | memset( rc, 0, n+1 ); |
| 1944 | rc[n] = 0; |
| 1945 | return strncpy( rc, src, n ); |
| 1946 | } |
| 1947 | #endif |
| 1948 | |
| 1949 | int cson_string_cmp_cstr_n( cson_string const * str, char const * other, unsigned int otherLen ) |
| 1950 | { |
| 1951 | if( ! other && !str ) return 0; |
| 1952 | else if( other && !str ) return 1; |
| @@ -2045,14 +1991,11 @@ | |
| 1991 | Each of these objects owns its key/value pointers, and they |
| 1992 | are cleaned up by cson_kvp_clean(). |
| 1993 | */ |
| 1994 | struct cson_kvp |
| 1995 | { |
| 1996 | cson_value * key; |
| 1997 | cson_value * value; |
| 1998 | }; |
| 1999 | #define cson_kvp_empty_m {NULL,NULL} |
| 2000 | static const cson_kvp cson_kvp_empty = cson_kvp_empty_m; |
| 2001 | |
| @@ -2087,45 +2030,21 @@ | |
| 2030 | */ |
| 2031 | #define CSON_OBJECT_PROPS_SORT_USE_LENGTH 0 |
| 2032 | |
| 2033 | #if CSON_OBJECT_PROPS_SORT |
| 2034 | |
| 2035 | /** |
| 2036 | cson_kvp comparator for use with qsort(). ALMOST compares with |
| 2037 | strcmp() semantics, but it uses the strings' lengths as a quicker |
| 2038 | approach. This might give non-intuitive results, but it's faster. |
| 2039 | */ |
| 2040 | static int cson_kvp_cmp( void const * lhs, void const * rhs ) |
| 2041 | { |
| 2042 | cson_kvp const * lk = *((cson_kvp const * const*)lhs); |
| 2043 | cson_kvp const * rk = *((cson_kvp const * const*)rhs); |
| 2044 | cson_string const * l = cson_string_value(lk->key); |
| 2045 | cson_string const * r = cson_string_value(rk->key); |
| 2046 | #if CSON_OBJECT_PROPS_SORT_USE_LENGTH |
| 2047 | if( l->length < r->length ) return -1; |
| 2048 | else if( l->length > r->length ) return 1; |
| 2049 | else return strcmp( cson_string_cstr( l ), cson_string_cstr( r ) ); |
| 2050 | #else |
| @@ -2135,10 +2054,11 @@ | |
| 2054 | } |
| 2055 | #endif /*CSON_OBJECT_PROPS_SORT*/ |
| 2056 | |
| 2057 | |
| 2058 | #if CSON_OBJECT_PROPS_SORT |
| 2059 | #error "Need to rework this for cson_string-to-cson_value refactoring" |
| 2060 | /** |
| 2061 | A bsearch() comparison function which requires that lhs be a (char |
| 2062 | const *) and rhs be-a (cson_kvp const * const *). It compares lhs |
| 2063 | to rhs->key's value, using strcmp() semantics. |
| 2064 | */ |
| @@ -2450,11 +2370,11 @@ | |
| 2370 | { |
| 2371 | if( kvp ) |
| 2372 | { |
| 2373 | if(kvp->key) |
| 2374 | { |
| 2375 | cson_value_free(kvp->key); |
| 2376 | kvp->key = NULL; |
| 2377 | } |
| 2378 | if(kvp->value) |
| 2379 | { |
| 2380 | cson_value_free( kvp->value ); |
| @@ -2463,11 +2383,11 @@ | |
| 2383 | } |
| 2384 | } |
| 2385 | |
| 2386 | cson_string const * cson_kvp_key( cson_kvp const * kvp ) |
| 2387 | { |
| 2388 | return kvp ? cson_value_get_string(kvp->key) : NULL; |
| 2389 | } |
| 2390 | cson_value * cson_kvp_value( cson_kvp const * kvp ) |
| 2391 | { |
| 2392 | return kvp ? kvp->value : NULL; |
| 2393 | } |
| @@ -2554,33 +2474,10 @@ | |
| 2474 | cson_array_clean( ar, 1 ); |
| 2475 | *self = cson_value_undef; |
| 2476 | } |
| 2477 | } |
| 2478 | |
| 2479 | int cson_buffer_fill_from( cson_buffer * dest, cson_data_source_f src, void * state ) |
| 2480 | { |
| 2481 | int rc; |
| 2482 | enum { BufSize = 1024 * 4 }; |
| 2483 | char rbuf[BufSize]; |
| @@ -2926,10 +2823,15 @@ | |
| 2823 | |
| 2824 | cson_value * cson_value_null() |
| 2825 | { |
| 2826 | return &CSON_SPECIAL_VALUES[CSON_VAL_NULL]; |
| 2827 | } |
| 2828 | |
| 2829 | cson_value * cson_new_int( cson_int_t v ) |
| 2830 | { |
| 2831 | return cson_value_new_integer(v); |
| 2832 | } |
| 2833 | |
| 2834 | cson_value * cson_value_new_integer( cson_int_t v ) |
| 2835 | { |
| 2836 | if( 0 == v ) return &CSON_SPECIAL_VALUES[CSON_VAL_INT_0]; |
| 2837 | else |
| @@ -2941,10 +2843,15 @@ | |
| 2843 | *CSON_INT(c) = v; |
| 2844 | } |
| 2845 | return c; |
| 2846 | } |
| 2847 | } |
| 2848 | |
| 2849 | cson_value * cson_new_double( cson_double_t v ) |
| 2850 | { |
| 2851 | return cson_value_new_double(v); |
| 2852 | } |
| 2853 | |
| 2854 | cson_value * cson_value_new_double( cson_double_t v ) |
| 2855 | { |
| 2856 | if( 0.0 == v ) return &CSON_SPECIAL_VALUES[CSON_VAL_DBL_0]; |
| 2857 | else |
| @@ -2956,11 +2863,11 @@ | |
| 2863 | } |
| 2864 | return c; |
| 2865 | } |
| 2866 | } |
| 2867 | |
| 2868 | cson_string * cson_new_string(char const * str, unsigned int len) |
| 2869 | { |
| 2870 | if( !str || !*str || !len ) return &CSON_EMPTY_HOLDER.stringValue; |
| 2871 | else |
| 2872 | { |
| 2873 | cson_value * c = cson_value_new(CSON_TYPE_STRING, len + 1/*NUL byte*/); |
| @@ -3100,14 +3007,17 @@ | |
| 3007 | unsigned int i = 0; |
| 3008 | cson_kvp * kvp; |
| 3009 | const unsigned int klen = strlen(key); |
| 3010 | for( ; i < li->count; ++i ) |
| 3011 | { |
| 3012 | cson_string const * sKey; |
| 3013 | kvp = li->list[i]; |
| 3014 | assert( kvp && kvp->key ); |
| 3015 | sKey = cson_value_get_string(kvp->key); |
| 3016 | assert(sKey); |
| 3017 | if( sKey->length != klen ) continue; |
| 3018 | else if(0==strcmp(key,cson_string_cstr(sKey))) |
| 3019 | { |
| 3020 | if(ndx) *ndx = i; |
| 3021 | return kvp; |
| 3022 | } |
| 3023 | } |
| @@ -3166,67 +3076,91 @@ | |
| 3076 | #endif |
| 3077 | return 0; |
| 3078 | } |
| 3079 | } |
| 3080 | |
| 3081 | int cson_object_set_s( cson_object * obj, cson_string * key, cson_value * v ) |
| 3082 | { |
| 3083 | if( !obj || !key ) return cson_rc.ArgError; |
| 3084 | else if( NULL == v ) return cson_object_unset( obj, cson_string_cstr(key) ); |
| 3085 | else |
| 3086 | { |
| 3087 | char const * cKey; |
| 3088 | cson_value * vKey; |
| 3089 | cson_kvp * kvp; |
| 3090 | vKey = cson_string_value(key); |
| 3091 | assert(vKey && (key==CSON_STR(vKey))); |
| 3092 | if( vKey == CSON_VCAST(obj) ){ |
| 3093 | return cson_rc.ArgError; |
| 3094 | } |
| 3095 | cKey = cson_string_cstr(key); |
| 3096 | kvp = cson_object_search_impl( obj, cKey, NULL ); |
| 3097 | if( kvp ) |
| 3098 | { /* "I told 'em we've already got one!" */ |
| 3099 | if( kvp->key != vKey ){ |
| 3100 | cson_value_free( kvp->key ); |
| 3101 | cson_refcount_incr(vKey); |
| 3102 | kvp->key = vKey; |
| 3103 | } |
| 3104 | if(kvp->value != v){ |
| 3105 | cson_value_free( kvp->value ); |
| 3106 | cson_refcount_incr( v ); |
| 3107 | kvp->value = v; |
| 3108 | } |
| 3109 | return 0; |
| 3110 | } |
| 3111 | if( !obj->kvp.alloced || (obj->kvp.count == obj->kvp.alloced-1)) |
| 3112 | { |
| 3113 | unsigned int const n = obj->kvp.count ? (obj->kvp.count*2) : 6; |
| 3114 | if( n > cson_kvp_list_reserve( &obj->kvp, n ) ) |
| 3115 | { |
| 3116 | return cson_rc.AllocError; |
| 3117 | } |
| 3118 | } |
| 3119 | { /* insert new item... */ |
| 3120 | int rc = 0; |
| 3121 | kvp = cson_kvp_alloc(); |
| 3122 | if( ! kvp ) |
| 3123 | { |
| 3124 | return cson_rc.AllocError; |
| 3125 | } |
| 3126 | rc = cson_kvp_list_append( &obj->kvp, kvp ); |
| 3127 | if( 0 != rc ) |
| 3128 | { |
| 3129 | cson_kvp_free(kvp); |
| 3130 | } |
| 3131 | else |
| 3132 | { |
| 3133 | cson_refcount_incr(vKey); |
| 3134 | cson_refcount_incr(v); |
| 3135 | kvp->key = vKey; |
| 3136 | kvp->value = v; |
| 3137 | #if CSON_OBJECT_PROPS_SORT |
| 3138 | cson_object_sort_props( obj ); |
| 3139 | #endif |
| 3140 | } |
| 3141 | return rc; |
| 3142 | } |
| 3143 | } |
| 3144 | |
| 3145 | } |
| 3146 | int cson_object_set( cson_object * obj, char const * key, cson_value * v ) |
| 3147 | { |
| 3148 | if( ! obj || !key || !*key ) return cson_rc.ArgError; |
| 3149 | else if( NULL == v ) |
| 3150 | { |
| 3151 | return cson_object_unset( obj, key ); |
| 3152 | } |
| 3153 | else |
| 3154 | { |
| 3155 | cson_string * cs = cson_new_string(key,strlen(key)); |
| 3156 | if(!cs) return cson_rc.AllocError; |
| 3157 | else |
| 3158 | { |
| 3159 | int const rc = cson_object_set_s(obj, cs, v); |
| 3160 | if(rc) cson_value_free(cson_string_value(cs)); |
| 3161 | return rc; |
| 3162 | } |
| 3163 | } |
| 3164 | } |
| 3165 | |
| 3166 | cson_value * cson_object_take( cson_object * obj, char const * key ) |
| @@ -3311,11 +3245,11 @@ | |
| 3245 | if( ! kvp ) |
| 3246 | { |
| 3247 | cson_value_free(val); |
| 3248 | return cson_rc.AllocError; |
| 3249 | } |
| 3250 | kvp->key = cson_string_value(p->ckey)/*transfer ownership*/; |
| 3251 | p->ckey = NULL; |
| 3252 | kvp->value = val; |
| 3253 | cson_refcount_incr( val ); |
| 3254 | rc = cson_kvp_list_append( &obj->kvp, kvp ); |
| 3255 | if( 0 != rc ) |
| @@ -3507,11 +3441,11 @@ | |
| 3441 | rc = cson_parser_push_value( p, cson_value_false() ); |
| 3442 | break; |
| 3443 | } |
| 3444 | case JSON_T_KEY: { |
| 3445 | assert(!p->ckey); |
| 3446 | p->ckey = cson_new_string( value->vu.str.value, value->vu.str.length ); |
| 3447 | if( ! p->ckey ) |
| 3448 | { |
| 3449 | rc = cson_rc.AllocError; |
| 3450 | break; |
| 3451 | } |
| @@ -3580,11 +3514,13 @@ | |
| 3514 | if( p->p ) |
| 3515 | { |
| 3516 | delete_JSON_parser(p->p); |
| 3517 | p->p = NULL; |
| 3518 | } |
| 3519 | if( p->ckey ){ |
| 3520 | cson_value_free(cson_string_value(p->ckey)); |
| 3521 | } |
| 3522 | cson_array_clean( &p->stack, 1 ); |
| 3523 | if( p->root ) |
| 3524 | { |
| 3525 | cson_value_free( p->root ); |
| 3526 | } |
| @@ -4192,11 +4128,13 @@ | |
| 4128 | for( i = 0; (i < obj->kvp.count) && (0 == rc); ++i ) |
| 4129 | { |
| 4130 | kvp = obj->kvp.list[i]; |
| 4131 | if( kvp && kvp->key ) |
| 4132 | { |
| 4133 | cson_string const * sKey = cson_value_get_string(kvp->key); |
| 4134 | char const * cKey = cson_string_cstr(sKey); |
| 4135 | rc = cson_str_to_json(cKey, sKey->length, |
| 4136 | fmt->escapeForwardSlashes, f, state); |
| 4137 | if( 0 == rc ) |
| 4138 | { |
| 4139 | rc = fmt->addSpaceAfterColon |
| 4140 | ? f(state, ": ", 2 ) |
| @@ -4638,26 +4576,42 @@ | |
| 4576 | cson_kvp const * kvp = NULL; |
| 4577 | cson_object_iterator iter = cson_object_iterator_empty; |
| 4578 | assert( orig && src ); |
| 4579 | if( 0 != cson_object_iter_init( src, &iter ) ) |
| 4580 | { |
| 4581 | return NULL; |
| 4582 | } |
| 4583 | destV = cson_value_new_object(); |
| 4584 | if( NULL == destV ) return NULL; |
| 4585 | dest = cson_value_get_object( destV ); |
| 4586 | assert( dest ); |
| 4587 | if( src->kvp.count > cson_kvp_list_reserve( &dest->kvp, src->kvp.count ) ){ |
| 4588 | cson_value_free( destV ); |
| 4589 | return NULL; |
| 4590 | } |
| 4591 | while( (kvp = cson_object_iter_next( &iter )) ) |
| 4592 | { |
| 4593 | /* |
| 4594 | FIXME: refcount the keys! We first need a setter which takes |
| 4595 | a cson_string or cson_value key type. |
| 4596 | */ |
| 4597 | cson_value * key = NULL; |
| 4598 | cson_value * val = NULL; |
| 4599 | key = cson_value_clone(kvp->key); |
| 4600 | val = key ? cson_value_clone( kvp->value ) : NULL; |
| 4601 | if( ! key || !val ){ |
| 4602 | cson_value_free(key); |
| 4603 | cson_value_free(val); |
| 4604 | cson_value_free(destV); |
| 4605 | return NULL; |
| 4606 | } |
| 4607 | assert( CSON_STR(key) ); |
| 4608 | if( 0 != cson_object_set_s( dest, CSON_STR(key), val ) ) |
| 4609 | { |
| 4610 | cson_value_free(key); |
| 4611 | cson_value_free(val); |
| 4612 | cson_value_free(destV); |
| 4613 | return NULL; |
| 4614 | } |
| 4615 | } |
| 4616 | return destV; |
| 4617 | } |
| @@ -4719,10 +4673,27 @@ | |
| 4673 | return s |
| 4674 | ? CSON_VCAST(s) |
| 4675 | : NULL; |
| 4676 | } |
| 4677 | |
| 4678 | void cson_free_object(cson_object *x) |
| 4679 | { |
| 4680 | if(x) cson_value_free(cson_object_value(x)); |
| 4681 | } |
| 4682 | void cson_free_array(cson_array *x) |
| 4683 | { |
| 4684 | if(x) cson_value_free(cson_array_value(x)); |
| 4685 | } |
| 4686 | |
| 4687 | void cson_free_string(cson_string const *x) |
| 4688 | { |
| 4689 | if(x) cson_value_free(cson_string_value(x)); |
| 4690 | } |
| 4691 | void cson_free_value(cson_value *x) |
| 4692 | { |
| 4693 | cson_value_free(x); |
| 4694 | } |
| 4695 | |
| 4696 | |
| 4697 | #if 0 |
| 4698 | /* i'm not happy with this... */ |
| 4699 | char * cson_pod_to_string( cson_value const * orig ) |
| @@ -4826,10 +4797,74 @@ | |
| 4797 | } |
| 4798 | return v; |
| 4799 | } |
| 4800 | } |
| 4801 | #endif |
| 4802 | |
| 4803 | unsigned int cson_value_msize(cson_value const * v) |
| 4804 | { |
| 4805 | if(!v) return 0; |
| 4806 | else if( cson_value_is_builtin(v) ) return 0; |
| 4807 | else { |
| 4808 | unsigned int rc = sizeof(cson_value); |
| 4809 | assert(NULL != v->api); |
| 4810 | switch(v->api->typeID){ |
| 4811 | case CSON_TYPE_INTEGER: |
| 4812 | assert( v != &CSON_SPECIAL_VALUES[CSON_VAL_INT_0]); |
| 4813 | rc += sizeof(cson_int_t); |
| 4814 | break; |
| 4815 | case CSON_TYPE_DOUBLE: |
| 4816 | assert( v != &CSON_SPECIAL_VALUES[CSON_VAL_DBL_0]); |
| 4817 | rc += sizeof(cson_double_t); |
| 4818 | break; |
| 4819 | case CSON_TYPE_STRING: |
| 4820 | rc += sizeof(cson_string) |
| 4821 | + CSON_STR(v)->length + 1/*NUL*/; |
| 4822 | break; |
| 4823 | case CSON_TYPE_ARRAY:{ |
| 4824 | cson_array const * ar = CSON_ARRAY(v); |
| 4825 | cson_value_list const * li; |
| 4826 | unsigned int i = 0; |
| 4827 | assert( NULL != ar ); |
| 4828 | li = &ar->list; |
| 4829 | rc += sizeof(cson_array) |
| 4830 | + (li->alloced * sizeof(cson_value *)); |
| 4831 | for( ; i < li->count; ++i ){ |
| 4832 | cson_value const * e = ar->list.list[i]; |
| 4833 | if( e ) rc += cson_value_msize( e ); |
| 4834 | } |
| 4835 | break; |
| 4836 | } |
| 4837 | case CSON_TYPE_OBJECT:{ |
| 4838 | cson_object const * obj = CSON_OBJ(v); |
| 4839 | unsigned int i = 0; |
| 4840 | cson_kvp_list const * kl; |
| 4841 | assert(NULL != obj); |
| 4842 | kl = &obj->kvp; |
| 4843 | rc += sizeof(cson_object) |
| 4844 | + (kl->alloced * sizeof(cson_kvp*)); |
| 4845 | for( ; i < kl->count; ++i ){ |
| 4846 | cson_kvp const * kvp = kl->list[i]; |
| 4847 | assert(NULL != kvp); |
| 4848 | rc += cson_value_msize(kvp->key); |
| 4849 | rc += cson_value_msize(kvp->value); |
| 4850 | } |
| 4851 | break; |
| 4852 | } |
| 4853 | case CSON_TYPE_UNDEF: |
| 4854 | case CSON_TYPE_NULL: |
| 4855 | case CSON_TYPE_BOOL: |
| 4856 | assert( 0 && "Should have been caught by is-builtin check!" ); |
| 4857 | break; |
| 4858 | default: |
| 4859 | assert(0 && "Invalid typeID!"); |
| 4860 | return 0; |
| 4861 | |
| 4862 | } |
| 4863 | return rc; |
| 4864 | } |
| 4865 | } |
| 4866 | |
| 4867 | #if defined(__cplusplus) |
| 4868 | } /*extern "C"*/ |
| 4869 | #endif |
| 4870 | |
| 4871 |
+82
-5
| --- src/cson_amalgamation.h | ||
| +++ src/cson_amalgamation.h | ||
| @@ -1147,10 +1147,15 @@ | ||
| 1147 | 1147 | Returns NULL on allocation error. |
| 1148 | 1148 | */ |
| 1149 | 1149 | cson_value * cson_value_new_bool( char v ); |
| 1150 | 1150 | |
| 1151 | 1151 | |
| 1152 | +/** | |
| 1153 | + Alias for cson_value_new_bool(v). | |
| 1154 | +*/ | |
| 1155 | +cson_value * cson_new_bool(char v); | |
| 1156 | + | |
| 1152 | 1157 | /** |
| 1153 | 1158 | Returns the special JSON "null" value. When outputing JSON, |
| 1154 | 1159 | its string representation is "null" (without the quotes). |
| 1155 | 1160 | |
| 1156 | 1161 | See cson_value_new_bool() for notes regarding the returned |
| @@ -1171,15 +1176,25 @@ | ||
| 1171 | 1176 | /** |
| 1172 | 1177 | Semantically the same as cson_value_new_bool(), but for integers. |
| 1173 | 1178 | */ |
| 1174 | 1179 | cson_value * cson_value_new_integer( cson_int_t v ); |
| 1175 | 1180 | |
| 1181 | +/** | |
| 1182 | + Alias for cson_value_new_integer(v). | |
| 1183 | +*/ | |
| 1184 | +cson_value * cson_new_int(cson_int_t v); | |
| 1185 | + | |
| 1176 | 1186 | /** |
| 1177 | 1187 | Semantically the same as cson_value_new_bool(), but for doubles. |
| 1178 | 1188 | */ |
| 1179 | 1189 | cson_value * cson_value_new_double( cson_double_t v ); |
| 1180 | 1190 | |
| 1191 | +/** | |
| 1192 | + Alias for cson_value_new_double(v). | |
| 1193 | +*/ | |
| 1194 | +cson_value * cson_new_double(cson_double_t v); | |
| 1195 | + | |
| 1181 | 1196 | /** |
| 1182 | 1197 | Semantically the same as cson_value_new_bool(), but for strings. |
| 1183 | 1198 | This creates a JSON value which copies the first n bytes of str. |
| 1184 | 1199 | The string will automatically be NUL-terminated. |
| 1185 | 1200 | |
| @@ -1229,17 +1244,28 @@ | ||
| 1229 | 1244 | cson_array * cson_new_array(); |
| 1230 | 1245 | |
| 1231 | 1246 | /** |
| 1232 | 1247 | Identical to cson_new_object() except that it creates |
| 1233 | 1248 | a String. |
| 1249 | +*/ | |
| 1250 | +cson_string * cson_new_string(char const * val, unsigned int len); | |
| 1234 | 1251 | |
| 1235 | - ACHTUNG: this function returns a const pointer but the ownership of | |
| 1236 | - the memory belongs to the caller! Use cson_string_value() to fetch | |
| 1237 | - the Value handle, and then cson_value_free() that handle or insert | |
| 1238 | - it into a container to transfer ownership. | |
| 1252 | +/** | |
| 1253 | + Equivalent to cson_value_free(cson_object_value(x)). | |
| 1254 | +*/ | |
| 1255 | +void cson_free_object(cson_object *x); | |
| 1256 | + | |
| 1257 | +/** | |
| 1258 | + Equivalent to cson_value_free(cson_array_value(x)). | |
| 1259 | +*/ | |
| 1260 | +void cson_free_array(cson_array *x); | |
| 1261 | + | |
| 1262 | +/** | |
| 1263 | + Equivalent to cson_value_free(cson_string_value(x)). | |
| 1239 | 1264 | */ |
| 1240 | -cson_string const * cson_new_string(char const * val, unsigned int len); | |
| 1265 | +void cson_free_string(cson_string const *x); | |
| 1266 | + | |
| 1241 | 1267 | |
| 1242 | 1268 | /** |
| 1243 | 1269 | Allocates a new "array" value and transfers ownership of it to the |
| 1244 | 1270 | caller. It must eventually be destroyed, by the caller or its |
| 1245 | 1271 | owning container, by passing it to cson_value_free(). |
| @@ -1271,10 +1297,16 @@ | ||
| 1271 | 1297 | @see cson_value_new_object() |
| 1272 | 1298 | @see cson_value_new_array() |
| 1273 | 1299 | @see cson_value_add_reference() |
| 1274 | 1300 | */ |
| 1275 | 1301 | void cson_value_free(cson_value * v); |
| 1302 | + | |
| 1303 | +/** | |
| 1304 | + Alias for cson_value_free(). | |
| 1305 | +*/ | |
| 1306 | +void cson_free_value(cson_value * v); | |
| 1307 | + | |
| 1276 | 1308 | |
| 1277 | 1309 | /** |
| 1278 | 1310 | Functionally similar to cson_array_set(), but uses a string key |
| 1279 | 1311 | as an index. Like arrays, if a value already exists for the given key, |
| 1280 | 1312 | it is destroyed by this function before inserting the new value. |
| @@ -1322,10 +1354,24 @@ | ||
| 1322 | 1354 | value types to strings. We could simply to-JSON them and use those |
| 1323 | 1355 | as keys. |
| 1324 | 1356 | */ |
| 1325 | 1357 | int cson_object_set( cson_object * obj, char const * key, cson_value * v ); |
| 1326 | 1358 | |
| 1359 | +/** | |
| 1360 | + Functionaly equivalent to cson_object_set(), but takes a | |
| 1361 | + cson_string() as its KEY type. The string will be reference-counted | |
| 1362 | + like any other values, and the key may legally be used within this | |
| 1363 | + same container (as a value) or others (as a key or value) at the | |
| 1364 | + same time. | |
| 1365 | + | |
| 1366 | + Returns 0 on success. On error, ownership (i.e. refcounts) of key | |
| 1367 | + and value are not modified. On success key and value will get | |
| 1368 | + increased refcounts unless they are replacing themselves (which is | |
| 1369 | + a harmless no-op). | |
| 1370 | +*/ | |
| 1371 | +int cson_object_set_s( cson_object * obj, cson_string * key, cson_value * v ); | |
| 1372 | + | |
| 1327 | 1373 | /** |
| 1328 | 1374 | Removes a property from an object. |
| 1329 | 1375 | |
| 1330 | 1376 | If obj contains the given key, it is removed and 0 is returned. If |
| 1331 | 1377 | it is not found, cson_rc.NotFoundError is returned (which can |
| @@ -1965,10 +2011,41 @@ | ||
| 1965 | 2011 | for full details. |
| 1966 | 2012 | */ |
| 1967 | 2013 | cson_value * cson_array_value(cson_array const * s); |
| 1968 | 2014 | |
| 1969 | 2015 | |
| 2016 | +/** | |
| 2017 | + Calculates the in-memory-allocated size of v, recursively if it is | |
| 2018 | + a container type, with the following caveats and limitations: | |
| 2019 | + | |
| 2020 | + If a given value is reference counted and multiple times within a | |
| 2021 | + traversed container, each reference is counted at full cost. We | |
| 2022 | + have no what of knowing if a given reference has been visited | |
| 2023 | + already and whether it should or should not be counted, so we | |
| 2024 | + pessimistically count them even though the _might_ not really count | |
| 2025 | + for the given object tree (it depends on where the other open | |
| 2026 | + references live). | |
| 2027 | + | |
| 2028 | + This function returns 0 if any of the following are true: | |
| 2029 | + | |
| 2030 | + - v is NULL | |
| 2031 | + | |
| 2032 | + - v is one of the special singleton values (null, bools, empty | |
| 2033 | + string, int 0, double 0.0) | |
| 2034 | + | |
| 2035 | + All other values require an allocation, and this will return their | |
| 2036 | + total memory cost, including the cson-specific internals and the | |
| 2037 | + native value(s). | |
| 2038 | + | |
| 2039 | + Note that because arrays and objects might have more internal slots | |
| 2040 | + allocated than used, the alloced size of a container does not | |
| 2041 | + necessarily increase when a new item is inserted into it. An interesting | |
| 2042 | + side-effect of this is that when cson_clone()ing an array or object, the | |
| 2043 | + size of the clone can actually be less than the original. | |
| 2044 | +*/ | |
| 2045 | +unsigned int cson_value_msize(cson_value const * v); | |
| 2046 | + | |
| 1970 | 2047 | /* LICENSE |
| 1971 | 2048 | |
| 1972 | 2049 | This software's source code, including accompanying documentation and |
| 1973 | 2050 | demonstration applications, are licensed under the following |
| 1974 | 2051 | conditions... |
| 1975 | 2052 |
| --- src/cson_amalgamation.h | |
| +++ src/cson_amalgamation.h | |
| @@ -1147,10 +1147,15 @@ | |
| 1147 | Returns NULL on allocation error. |
| 1148 | */ |
| 1149 | cson_value * cson_value_new_bool( char v ); |
| 1150 | |
| 1151 | |
| 1152 | /** |
| 1153 | Returns the special JSON "null" value. When outputing JSON, |
| 1154 | its string representation is "null" (without the quotes). |
| 1155 | |
| 1156 | See cson_value_new_bool() for notes regarding the returned |
| @@ -1171,15 +1176,25 @@ | |
| 1171 | /** |
| 1172 | Semantically the same as cson_value_new_bool(), but for integers. |
| 1173 | */ |
| 1174 | cson_value * cson_value_new_integer( cson_int_t v ); |
| 1175 | |
| 1176 | /** |
| 1177 | Semantically the same as cson_value_new_bool(), but for doubles. |
| 1178 | */ |
| 1179 | cson_value * cson_value_new_double( cson_double_t v ); |
| 1180 | |
| 1181 | /** |
| 1182 | Semantically the same as cson_value_new_bool(), but for strings. |
| 1183 | This creates a JSON value which copies the first n bytes of str. |
| 1184 | The string will automatically be NUL-terminated. |
| 1185 | |
| @@ -1229,17 +1244,28 @@ | |
| 1229 | cson_array * cson_new_array(); |
| 1230 | |
| 1231 | /** |
| 1232 | Identical to cson_new_object() except that it creates |
| 1233 | a String. |
| 1234 | |
| 1235 | ACHTUNG: this function returns a const pointer but the ownership of |
| 1236 | the memory belongs to the caller! Use cson_string_value() to fetch |
| 1237 | the Value handle, and then cson_value_free() that handle or insert |
| 1238 | it into a container to transfer ownership. |
| 1239 | */ |
| 1240 | cson_string const * cson_new_string(char const * val, unsigned int len); |
| 1241 | |
| 1242 | /** |
| 1243 | Allocates a new "array" value and transfers ownership of it to the |
| 1244 | caller. It must eventually be destroyed, by the caller or its |
| 1245 | owning container, by passing it to cson_value_free(). |
| @@ -1271,10 +1297,16 @@ | |
| 1271 | @see cson_value_new_object() |
| 1272 | @see cson_value_new_array() |
| 1273 | @see cson_value_add_reference() |
| 1274 | */ |
| 1275 | void cson_value_free(cson_value * v); |
| 1276 | |
| 1277 | /** |
| 1278 | Functionally similar to cson_array_set(), but uses a string key |
| 1279 | as an index. Like arrays, if a value already exists for the given key, |
| 1280 | it is destroyed by this function before inserting the new value. |
| @@ -1322,10 +1354,24 @@ | |
| 1322 | value types to strings. We could simply to-JSON them and use those |
| 1323 | as keys. |
| 1324 | */ |
| 1325 | int cson_object_set( cson_object * obj, char const * key, cson_value * v ); |
| 1326 | |
| 1327 | /** |
| 1328 | Removes a property from an object. |
| 1329 | |
| 1330 | If obj contains the given key, it is removed and 0 is returned. If |
| 1331 | it is not found, cson_rc.NotFoundError is returned (which can |
| @@ -1965,10 +2011,41 @@ | |
| 1965 | for full details. |
| 1966 | */ |
| 1967 | cson_value * cson_array_value(cson_array const * s); |
| 1968 | |
| 1969 | |
| 1970 | /* LICENSE |
| 1971 | |
| 1972 | This software's source code, including accompanying documentation and |
| 1973 | demonstration applications, are licensed under the following |
| 1974 | conditions... |
| 1975 |
| --- src/cson_amalgamation.h | |
| +++ src/cson_amalgamation.h | |
| @@ -1147,10 +1147,15 @@ | |
| 1147 | Returns NULL on allocation error. |
| 1148 | */ |
| 1149 | cson_value * cson_value_new_bool( char v ); |
| 1150 | |
| 1151 | |
| 1152 | /** |
| 1153 | Alias for cson_value_new_bool(v). |
| 1154 | */ |
| 1155 | cson_value * cson_new_bool(char v); |
| 1156 | |
| 1157 | /** |
| 1158 | Returns the special JSON "null" value. When outputing JSON, |
| 1159 | its string representation is "null" (without the quotes). |
| 1160 | |
| 1161 | See cson_value_new_bool() for notes regarding the returned |
| @@ -1171,15 +1176,25 @@ | |
| 1176 | /** |
| 1177 | Semantically the same as cson_value_new_bool(), but for integers. |
| 1178 | */ |
| 1179 | cson_value * cson_value_new_integer( cson_int_t v ); |
| 1180 | |
| 1181 | /** |
| 1182 | Alias for cson_value_new_integer(v). |
| 1183 | */ |
| 1184 | cson_value * cson_new_int(cson_int_t v); |
| 1185 | |
| 1186 | /** |
| 1187 | Semantically the same as cson_value_new_bool(), but for doubles. |
| 1188 | */ |
| 1189 | cson_value * cson_value_new_double( cson_double_t v ); |
| 1190 | |
| 1191 | /** |
| 1192 | Alias for cson_value_new_double(v). |
| 1193 | */ |
| 1194 | cson_value * cson_new_double(cson_double_t v); |
| 1195 | |
| 1196 | /** |
| 1197 | Semantically the same as cson_value_new_bool(), but for strings. |
| 1198 | This creates a JSON value which copies the first n bytes of str. |
| 1199 | The string will automatically be NUL-terminated. |
| 1200 | |
| @@ -1229,17 +1244,28 @@ | |
| 1244 | cson_array * cson_new_array(); |
| 1245 | |
| 1246 | /** |
| 1247 | Identical to cson_new_object() except that it creates |
| 1248 | a String. |
| 1249 | */ |
| 1250 | cson_string * cson_new_string(char const * val, unsigned int len); |
| 1251 | |
| 1252 | /** |
| 1253 | Equivalent to cson_value_free(cson_object_value(x)). |
| 1254 | */ |
| 1255 | void cson_free_object(cson_object *x); |
| 1256 | |
| 1257 | /** |
| 1258 | Equivalent to cson_value_free(cson_array_value(x)). |
| 1259 | */ |
| 1260 | void cson_free_array(cson_array *x); |
| 1261 | |
| 1262 | /** |
| 1263 | Equivalent to cson_value_free(cson_string_value(x)). |
| 1264 | */ |
| 1265 | void cson_free_string(cson_string const *x); |
| 1266 | |
| 1267 | |
| 1268 | /** |
| 1269 | Allocates a new "array" value and transfers ownership of it to the |
| 1270 | caller. It must eventually be destroyed, by the caller or its |
| 1271 | owning container, by passing it to cson_value_free(). |
| @@ -1271,10 +1297,16 @@ | |
| 1297 | @see cson_value_new_object() |
| 1298 | @see cson_value_new_array() |
| 1299 | @see cson_value_add_reference() |
| 1300 | */ |
| 1301 | void cson_value_free(cson_value * v); |
| 1302 | |
| 1303 | /** |
| 1304 | Alias for cson_value_free(). |
| 1305 | */ |
| 1306 | void cson_free_value(cson_value * v); |
| 1307 | |
| 1308 | |
| 1309 | /** |
| 1310 | Functionally similar to cson_array_set(), but uses a string key |
| 1311 | as an index. Like arrays, if a value already exists for the given key, |
| 1312 | it is destroyed by this function before inserting the new value. |
| @@ -1322,10 +1354,24 @@ | |
| 1354 | value types to strings. We could simply to-JSON them and use those |
| 1355 | as keys. |
| 1356 | */ |
| 1357 | int cson_object_set( cson_object * obj, char const * key, cson_value * v ); |
| 1358 | |
| 1359 | /** |
| 1360 | Functionaly equivalent to cson_object_set(), but takes a |
| 1361 | cson_string() as its KEY type. The string will be reference-counted |
| 1362 | like any other values, and the key may legally be used within this |
| 1363 | same container (as a value) or others (as a key or value) at the |
| 1364 | same time. |
| 1365 | |
| 1366 | Returns 0 on success. On error, ownership (i.e. refcounts) of key |
| 1367 | and value are not modified. On success key and value will get |
| 1368 | increased refcounts unless they are replacing themselves (which is |
| 1369 | a harmless no-op). |
| 1370 | */ |
| 1371 | int cson_object_set_s( cson_object * obj, cson_string * key, cson_value * v ); |
| 1372 | |
| 1373 | /** |
| 1374 | Removes a property from an object. |
| 1375 | |
| 1376 | If obj contains the given key, it is removed and 0 is returned. If |
| 1377 | it is not found, cson_rc.NotFoundError is returned (which can |
| @@ -1965,10 +2011,41 @@ | |
| 2011 | for full details. |
| 2012 | */ |
| 2013 | cson_value * cson_array_value(cson_array const * s); |
| 2014 | |
| 2015 | |
| 2016 | /** |
| 2017 | Calculates the in-memory-allocated size of v, recursively if it is |
| 2018 | a container type, with the following caveats and limitations: |
| 2019 | |
| 2020 | If a given value is reference counted and multiple times within a |
| 2021 | traversed container, each reference is counted at full cost. We |
| 2022 | have no what of knowing if a given reference has been visited |
| 2023 | already and whether it should or should not be counted, so we |
| 2024 | pessimistically count them even though the _might_ not really count |
| 2025 | for the given object tree (it depends on where the other open |
| 2026 | references live). |
| 2027 | |
| 2028 | This function returns 0 if any of the following are true: |
| 2029 | |
| 2030 | - v is NULL |
| 2031 | |
| 2032 | - v is one of the special singleton values (null, bools, empty |
| 2033 | string, int 0, double 0.0) |
| 2034 | |
| 2035 | All other values require an allocation, and this will return their |
| 2036 | total memory cost, including the cson-specific internals and the |
| 2037 | native value(s). |
| 2038 | |
| 2039 | Note that because arrays and objects might have more internal slots |
| 2040 | allocated than used, the alloced size of a container does not |
| 2041 | necessarily increase when a new item is inserted into it. An interesting |
| 2042 | side-effect of this is that when cson_clone()ing an array or object, the |
| 2043 | size of the clone can actually be less than the original. |
| 2044 | */ |
| 2045 | unsigned int cson_value_msize(cson_value const * v); |
| 2046 | |
| 2047 | /* LICENSE |
| 2048 | |
| 2049 | This software's source code, including accompanying documentation and |
| 2050 | demonstration applications, are licensed under the following |
| 2051 | conditions... |
| 2052 |