Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Latest upstream s2, configured to use hashtables for property storage. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
ea62cfc2ec20fe91fe5ff09941248f84 |
User & Date: | stephan 2021-07-12 03:08:30.773 |
Context
2021-07-12
| ||
14:24 | Latest upstream s2 with some minor build-time, doc, and unit test tweaks. check-in: a08eb62a66 user: stephan tags: trunk | |
03:08 | Latest upstream s2, configured to use hashtables for property storage. check-in: ea62cfc2ec user: stephan tags: trunk | |
2021-07-11
| ||
09:16 | Latest upstream s2, for testing purposes. check-in: 9e2a6e3934 user: stephan tags: trunk | |
Changes
Changes to bindings/s2/Makefile.
︙ | ︙ | |||
86 87 88 89 90 91 92 | f-s2sh.BIN.LDFLAGS := $(S2_CLIENT_LDFLAGS) $(LDFLAGS_READLINE) $(eval $(call ShakeNMake.CALL.RULES.BINS,f-s2sh)) all: $(f-s2sh.BIN) # s2's inclusion of miniz breaks its policy of building with # the (-pedantic -std=c89) flags, and requires that we be less # stringent with compilation flags :(... s2_amalgamation.o: CFLAGS=-Wall -Werror -Wsign-compare -g -UNDEBUG -DDEBUG=1 | | | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | f-s2sh.BIN.LDFLAGS := $(S2_CLIENT_LDFLAGS) $(LDFLAGS_READLINE) $(eval $(call ShakeNMake.CALL.RULES.BINS,f-s2sh)) all: $(f-s2sh.BIN) # s2's inclusion of miniz breaks its policy of building with # the (-pedantic -std=c89) flags, and requires that we be less # stringent with compilation flags :(... s2_amalgamation.o: CFLAGS=-Wall -Werror -Wsign-compare -g -UNDEBUG -DDEBUG=1 s2_amalgamation.o shell2.o shell_extend.o: CPPFLAGS+=-DS2_ENABLE_ZLIB=1 -DHAVE_CONFIG_H s2_amalgamation.o: config.h # end bins and libs ######################################################################## ######################################## # Set up file-specific CPPFLAGS/LDFLAGS. |
︙ | ︙ |
Changes to bindings/s2/config.h.
1 2 3 4 | #define S2_OS_UNIX 1 #define S2_HAVE_REALPATH 1 #define S2_HAVE_STAT 1 #define S2_HAVE_CHDIR 1 | > | 1 2 3 4 5 | #define S2_OS_UNIX 1 #define S2_HAVE_REALPATH 1 #define S2_HAVE_STAT 1 #define S2_HAVE_CHDIR 1 #define CWAL_OBASE_ISA_HASH 1 |
Changes to bindings/s2/s2_amalgamation.c.
︙ | ︙ | |||
9158 9159 9160 9161 9162 9163 9164 | cwal_list list; /** Side effect of the chunk recycler: we need to be able to differentiate between the hashtable size and the amount of memory allocated for it (which might be larger). This value be less than or equal to this->list.alloced. */ | | > | > > > > > | | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > | > > > > > > > | 9158 9159 9160 9161 9162 9163 9164 9165 9166 9167 9168 9169 9170 9171 9172 9173 9174 9175 9176 9177 9178 9179 9180 9181 9182 9183 9184 9185 9186 9187 9188 9189 9190 9191 9192 9193 9194 9195 9196 9197 9198 9199 9200 9201 9202 9203 9204 9205 9206 9207 9208 9209 9210 9211 9212 9213 9214 9215 9216 9217 9218 9219 9220 9221 9222 9223 9224 9225 9226 9227 9228 9229 9230 9231 9232 9233 9234 9235 9236 9237 9238 9239 9240 9241 9242 9243 9244 9245 9246 9247 9248 9249 9250 9251 | cwal_list list; /** Side effect of the chunk recycler: we need to be able to differentiate between the hashtable size and the amount of memory allocated for it (which might be larger). This value be less than or equal to this->list.alloced. */ cwal_midsize_t hashSize; }; /** A clean cwal_htable instance for cost-copy initialization. */ #define cwal_htable_empty_m {cwal_list_empty_m,0} /** @internal Convenience typedef. */ typedef struct cwal_obase cwal_obase; /** @internal "Base" type for types which contain other values (which means they are subject to cycles). An instance of this struct must be embedded at the FIRST MEMBER of any such class, and any type-specific members must come after that. See cwal_array and cwal_object for examples. */ struct cwal_obase { #if CWAL_OBASE_ISA_HASH /** Hashtable of object-level properties. */ cwal_htable hprops; #else /** Linked list of key/value pairs held by this object. */ cwal_kvp * kvp; #endif /** The "prototype" (analog to a parent class). */ cwal_value * prototype; /** Internal flags. Maintenance note: due to struct padding, this can be either 16 or 32-bits with no real change in struct size on 64-bit, but increasing either flags field on 32-bit increases the sizeof (4 bytes if we increase both fields to 32 bits). Internally we currently need 16 bits for flags. As of 20141205, we are using the top few bits of these via cwal_container_flags, exposing/modifying the upper byte of these flags via cwal_container_flags_set() and cwal_container_flags_get(). As of 20191212, we desperately need more room for flags, but cannot do so without increasing the sizeof by up to 4 on 32-bit builds, from 12 to 16. We may just have to eat that cost :/. On 64-bit builds that change wouldn't change the sizeof(). */ cwal_flags16_t flags; /** Engine-internal flags specifically for container-type-specific behaviour. */ cwal_flags16_t containerFlags; /** Holds client-specified flags. */ cwal_flags16_t clientFlags; cwal_flags16_t reservedPadding; }; /** @internal Empty-initialized cwal_obase object. */ #if CWAL_OBASE_ISA_HASH # define cwal_obase_empty_m {\ cwal_htable_empty_m/*hprops*/, NULL/*prototype*/,CWAL_F_NONE/*flags*/,\ 0/*containerFlags*/, 0/*clientFlags*/, 0/*reservedPadding*/\ } #else # define cwal_obase_empty_m { \ NULL/*kvp*/, NULL/*prototype*/, CWAL_F_NONE/*flags*/,\ 0/*containerFlags*/, 0/*clientFlags*/, 0/*reservedPadding*/\ } #endif /** @internal Concrete value type for Arrays (type CWAL_TYPE_ARRAY). */ struct cwal_array { /** |
︙ | ︙ | |||
9418 9419 9420 9421 9422 9423 9424 | typedef cwal_hash_t (*cwal_value_hash_f)( cwal_value const * v ); /** Returns v's hash value, as computed by v's vtab. Returns 0 if !v. */ cwal_hash_t cwal_value_hash( cwal_value const * const v ); | < | 9436 9437 9438 9439 9440 9441 9442 9443 9444 9445 9446 9447 9448 9449 | typedef cwal_hash_t (*cwal_value_hash_f)( cwal_value const * v ); /** Returns v's hash value, as computed by v's vtab. Returns 0 if !v. */ cwal_hash_t cwal_value_hash( cwal_value const * const v ); /** Typedef for cwal_value comparison functions. Has memcmp() semantics. Ordering of mismatched types (e.g. comparing an array to an object) is type-dependent, possibly undefined. Implementations of this function are type-specific and require that the lhs (left-hand-side) argument be of their specific type (and are |
︙ | ︙ | |||
9580 9581 9582 9583 9584 9585 9586 | hold other values _must_ implement it (properly!). Must return 0 on success and "truly shouldn't fail" because all it does it pass each child on to cwal_value_rescope(), which cannot fail if all arguments are in order and the internal state of the values seems okay (the engine does a good deal of extra checking and assert()ing). However, if it fails it should | | > > | 9597 9598 9599 9600 9601 9602 9603 9604 9605 9606 9607 9608 9609 9610 9611 9612 9613 | hold other values _must_ implement it (properly!). Must return 0 on success and "truly shouldn't fail" because all it does it pass each child on to cwal_value_rescope(), which cannot fail if all arguments are in order and the internal state of the values seems okay (the engine does a good deal of extra checking and assert()ing). However, if it fails it should return an appropriate value from the cwal_rc_e enum. Returning non-0 will be treated as fatal, possibly assert()ing in debug builds. */ int (*rescope_children)( cwal_value * v ); /** TODOs???: // Using JS semantics for true/value |
︙ | ︙ | |||
10162 10163 10164 10165 10166 10167 10168 | An internal helper for routines (specifically JSON) to traverse an object tree and detect cycles. Passed the object which is about to be traversed and a pointer to an opaque state value. If this function returns 0, the value is either not capable of | | | | | | | 10181 10182 10183 10184 10185 10186 10187 10188 10189 10190 10191 10192 10193 10194 10195 10196 10197 10198 10199 | An internal helper for routines (specifically JSON) to traverse an object tree and detect cycles. Passed the object which is about to be traversed and a pointer to an opaque state value. If this function returns 0, the value is either not capable of participating in acyclic traversal (cannot form cyles) or it is and was flagged as not being in an acyclic traversal. If non-0 is returned, the value was already flagged as being in an acylic traversal and was traversed again (by this function), indicating a cyclic case (i.e. an error). If it returns CWAL_RC_CYCLES_DETECTED: the value is already in the process of acyclic traversal. The caller should fail the operation with the result code returned by this function (CWAL_RC_CYCLES_DETECTED) or a semantic equivalent for the given operation. |
︙ | ︙ | |||
10216 10217 10218 10219 10220 10221 10222 10223 10224 10225 10226 10227 10228 10229 10230 10231 | Calling this obliges the caller to pass the value of *opaque to cwal_visit_props_end() when visitation is complete. The API guarantees that this routine will set *opaque to a non-0 value, so that callers may use 0 for their own purposes (e.g. determining whether or not they need to call cwal_visit_props_end()). @see cwal_visit_props_end() */ void cwal_visit_props_begin( cwal_value * const v, int * const opaque ); /** @internal If, and only if, cwal_visit_props_begin() was passed v, the resulting integer value from that call MUST be passed to this | > > > > > > > > > > > > > > | 10235 10236 10237 10238 10239 10240 10241 10242 10243 10244 10245 10246 10247 10248 10249 10250 10251 10252 10253 10254 10255 10256 10257 10258 10259 10260 10261 10262 10263 10264 | Calling this obliges the caller to pass the value of *opaque to cwal_visit_props_end() when visitation is complete. The API guarantees that this routine will set *opaque to a non-0 value, so that callers may use 0 for their own purposes (e.g. determining whether or not they need to call cwal_visit_props_end()). This function may set the CWAL_RCF_IS_VISITING flag on v, and records in the 2nd argument whether or not it did so. When cwal_visit_props_end() is called, if its second argument records that it set the flag then that call unsets that flag. This allows properties to be visited multiple times concurrently, with only the top-most visitation toggling that flag. That flag, in turn, is checked by routines which would invalidate such iteration, causing such routines to return an error code rather than invalidating the in-progress iteration. e.g. trying to set a property value while the properties are being iterated over will trigger such a case because the underlying data model does not support modification during traversal. @see cwal_visit_props_end() @see cwal_visit_acyclic_begin() */ void cwal_visit_props_begin( cwal_value * const v, int * const opaque ); /** @internal If, and only if, cwal_visit_props_begin() was passed v, the resulting integer value from that call MUST be passed to this |
︙ | ︙ | |||
10269 10270 10271 10272 10273 10274 10275 10276 10277 | void cwal_visit_list_end( cwal_value * const v, int opaque ); /** Internal helper for iterating over cwal_obase properties. */ struct cwal_obase_kvp_iter { cwal_value * v; #if CWAL_OBASE_ISA_HASH cwal_obase * base; | > < > < | 10302 10303 10304 10305 10306 10307 10308 10309 10310 10311 10312 10313 10314 10315 10316 10317 10318 10319 10320 10321 | void cwal_visit_list_end( cwal_value * const v, int opaque ); /** Internal helper for iterating over cwal_obase properties. */ struct cwal_obase_kvp_iter { cwal_value * v; cwal_kvp const * current; #if CWAL_OBASE_ISA_HASH cwal_obase * base; cwal_list const * li; cwal_midsize_t ndx; #endif }; typedef struct cwal_obase_kvp_iter cwal_obase_kvp_iter; /** @internal Initializes oks for iteration over v's properties and returns the first property. Returns NULL if v has no properties. |
︙ | ︙ | |||
11269 11270 11271 11272 11273 11274 11275 | #if 0 /* Portability: stick with 32-bit lengths. */ # define CWAL_STRLEN_MASK ((cwal_size_t)0x1FFFFFFFU) # define CWAL_STR_XMASK ((cwal_size_t)0x80000000U) # define CWAL_STR_ZMASK ((cwal_size_t)0x40000000U) # define CWAL_STR_ASCII_MASK ((cwal_size_t)0x20000000U) #else | | > | | 11302 11303 11304 11305 11306 11307 11308 11309 11310 11311 11312 11313 11314 11315 11316 11317 11318 | #if 0 /* Portability: stick with 32-bit lengths. */ # define CWAL_STRLEN_MASK ((cwal_size_t)0x1FFFFFFFU) # define CWAL_STR_XMASK ((cwal_size_t)0x80000000U) # define CWAL_STR_ZMASK ((cwal_size_t)0x40000000U) # define CWAL_STR_ASCII_MASK ((cwal_size_t)0x20000000U) #else /* Max string length: 32-bits so that we can use cwal_midsize_t for all string lengths. */ # define CWAL_STRLEN_MASK ((cwal_size_t)0x1FFFFFFFU) # define CWAL_STR_XMASK ((cwal_size_t)0x8000000000000000U) # define CWAL_STR_ZMASK ((cwal_size_t)0x4000000000000000U) # define CWAL_STR_ASCII_MASK ((cwal_size_t)0x2000000000000000U) #endif #endif /* |
︙ | ︙ | |||
11322 11323 11324 11325 11326 11327 11328 | */ #define CWAL_STR_ISASCII(S) ((CWAL_STR_ASCII_MASK & (S)->length) ? 1 : 0) /** Evaluates to the absolute value of S->length, in bytes, where S must be a non-NULL (cwal_string [const]*). This is required instead direct access to S->length because we encode non-size info in the | | | | | 11356 11357 11358 11359 11360 11361 11362 11363 11364 11365 11366 11367 11368 11369 11370 11371 11372 11373 11374 11375 | */ #define CWAL_STR_ISASCII(S) ((CWAL_STR_ASCII_MASK & (S)->length) ? 1 : 0) /** Evaluates to the absolute value of S->length, in bytes, where S must be a non-NULL (cwal_string [const]*). This is required instead direct access to S->length because we encode non-size info in the length field for X- and Z-strings, plus the is-ASCII flag. */ #define CWAL_STRLEN(S) ((cwal_midsize_t)((S)->length & CWAL_STRLEN_MASK)) /** Evaluates to non-0 if the cwal_size_t value LEN is too long for a string length. */ #define CWAL_STRLEN_TOO_LONG(LEN) (((cwal_size_t)(LEN)) & ~CWAL_STRLEN_MASK) /** CWAL_OBJ(V) casts CWAL_TYPE_OBJECT (cwal_value*) V to a (cwal_object*). */ #define CWAL_OBJ(V) (((V) && (V)->vtab && (CWAL_TYPE_OBJECT==(V)->vtab->typeID)) ? CWAL_VVPCAST(cwal_object,(V)) : 0) /** |
︙ | ︙ | |||
12018 12019 12020 12021 12022 12023 12024 | } if( cwal_value_is_string(v) ){ cwal_string const * s = cwal_value_get_string(v); if(s && CWAL_STRLEN(s)){ const cwal_size_t len = CWAL_STRLEN(s); fprintf( out, " strlen=%u", (unsigned)len); if( len <= 30 ){ | | | 12052 12053 12054 12055 12056 12057 12058 12059 12060 12061 12062 12063 12064 12065 12066 | } if( cwal_value_is_string(v) ){ cwal_string const * s = cwal_value_get_string(v); if(s && CWAL_STRLEN(s)){ const cwal_size_t len = CWAL_STRLEN(s); fprintf( out, " strlen=%u", (unsigned)len); if( len <= 30 ){ fprintf( out, " bytes=[%.*s]", (int)len, cwal_string_cstr(s) ); } }else{ fprintf( out, " (STILL INITIALIZING?)" ); } } else if(cwal_value_is_integer(v)){ fprintf( out, " int=%"CWAL_INT_T_PFMT, |
︙ | ︙ | |||
12465 12466 12467 12468 12469 12470 12471 12472 12473 | cwal_flags16_t const rc = (cwal_flags16_t)(CWAL_VAR_F_PRESERVE & kvp->flags); if(CWAL_VAR_F_PRESERVE != flags){ kvp->flags = flags; } return rc; } /** @internal | > | | | 12499 12500 12501 12502 12503 12504 12505 12506 12507 12508 12509 12510 12511 12512 12513 12514 12515 12516 12517 12518 12519 12520 12521 12522 12523 12524 12525 | cwal_flags16_t const rc = (cwal_flags16_t)(CWAL_VAR_F_PRESERVE & kvp->flags); if(CWAL_VAR_F_PRESERVE != flags){ kvp->flags = flags; } return rc; } #if !CWAL_OBASE_ISA_HASH /** @internal Searches for the given key in the given kvp list. Returns the found item if a match is found, NULL if not. If prev is not NULL then *prev is set to the returned value's left-hand-side kvp from the linked list (or the end of the list, if no match is found). A *prev value of NULL and return value of non-NULL indicates that the result kvp was found at the head of the list. */ static cwal_kvp * cwal_kvp_search( cwal_kvp * kvp, char const * key, cwal_midsize_t keyLen, cwal_kvp ** prev){ if(!kvp || !key ) return NULL; else{ cwal_kvp * left = 0; char const * cKey; cwal_size_t cLen; int cmp; for( left = 0; kvp; left = kvp, kvp = kvp->right ){ |
︙ | ︙ | |||
12569 12570 12571 12572 12573 12574 12575 | /** Functionally identical to cwal_kvp_unset_v() but takes its key in C-string form. */ static int cwal_kvp_unset( cwal_engine * e, /* cwal_scope * fromScope, */ cwal_kvp ** list, | | | 12604 12605 12606 12607 12608 12609 12610 12611 12612 12613 12614 12615 12616 12617 12618 | /** Functionally identical to cwal_kvp_unset_v() but takes its key in C-string form. */ static int cwal_kvp_unset( cwal_engine * e, /* cwal_scope * fromScope, */ cwal_kvp ** list, char const * key, cwal_midsize_t keyLen ) { /* assert(fromScope); */ assert(e); assert(key); if( !e || !key || !list ) return CWAL_RC_MISUSE; else if(!*list) return CWAL_RC_NOT_FOUND; else { cwal_kvp * left = 0; |
︙ | ︙ | |||
12620 12621 12622 12623 12624 12625 12626 | *list = kvp->right; } kvp->right = NULL; cwal_kvp_free( e, kvp, 1 ); return 0; } } | | < | 12655 12656 12657 12658 12659 12660 12661 12662 12663 12664 12665 12666 12667 12668 12669 | *list = kvp->right; } kvp->right = NULL; cwal_kvp_free( e, kvp, 1 ); return 0; } } #endif /* !CWAL_OBASE_ISA_HASH */ /** Returns the client-supplied hash table size "trimmed" to some "convenient" prime number (more or less arbitrarily chosen by this developer - feel free to change/extend this range). */ static uint16_t cwal_trim_hash_size( uint16_t hashSize ){ |
︙ | ︙ | |||
14349 14350 14351 14352 14353 14354 14355 | cwal_scope * parent = (s==e->current /* vacuum op */) ? s->parent : e->current; CWAL_TR_SV(e,s,vPropagate); CWAL_TR3(e,CWAL_TRACE_SCOPE_MASK,"Relocating vPropagate..."); if(!parent){ if(1==phase) cwal_exception_set(e, 0); else cwal_propagating_set(e, 0); assert((1==phase) ? 0==e->values.exception : 0==e->values.propagating); | < | | 14383 14384 14385 14386 14387 14388 14389 14390 14391 14392 14393 14394 14395 14396 14397 | cwal_scope * parent = (s==e->current /* vacuum op */) ? s->parent : e->current; CWAL_TR_SV(e,s,vPropagate); CWAL_TR3(e,CWAL_TRACE_SCOPE_MASK,"Relocating vPropagate..."); if(!parent){ if(1==phase) cwal_exception_set(e, 0); else cwal_propagating_set(e, 0); assert((1==phase) ? 0==e->values.exception : 0==e->values.propagating); }else{ rc = cwal_value_xscope( e, parent, vPropagate, NULL ); #if 0 /* we really should soldier on and clean up, but we'd be doing so on possibly corrupt memory! 20200111: that said, this operation has never failed in practice. */ |
︙ | ︙ | |||
14373 14374 14375 14376 14377 14378 14379 | CWAL_TR3(e,CWAL_TRACE_SCOPE_MASK,"Moved EXCEPTION/PROPAGATING to next scope up."); } } if(2==++phase) goto propagate_next; } if(s->props){ | | | | 14406 14407 14408 14409 14410 14411 14412 14413 14414 14415 14416 14417 14418 14419 14420 14421 | CWAL_TR3(e,CWAL_TRACE_SCOPE_MASK,"Moved EXCEPTION/PROPAGATING to next scope up."); } } if(2==++phase) goto propagate_next; } if(s->props){ cwal_value * const pv = s->props; cwal_obase * const obase = CWAL_VOBASE(pv); assert(pv); assert(obase); assert(pv->scope && "It's not possible to have no scope at this point."); assert((pv->scope==s || (pv->scope->level<s->level)) && "Scoping/lifetime precondition violation."); assert((CWAL_REFCOUNT(pv)>0) && "Who stole my properties ref?"); /* |
︙ | ︙ | |||
15441 15442 15443 15444 15445 15446 15447 | CWAL_TR3(e, CWAL_TRACE_MEM_TO_RECYCLER, "Placed string in recycling bin."); return 1; freeit: #if !CWAL_ENABLE_TRACE if(0){ assert(freeMsg && "Avoid unused var warning in non-trace builds."); } #endif | | | | | | > > | 15474 15475 15476 15477 15478 15479 15480 15481 15482 15483 15484 15485 15486 15487 15488 15489 15490 15491 15492 15493 15494 15495 15496 15497 15498 | CWAL_TR3(e, CWAL_TRACE_MEM_TO_RECYCLER, "Placed string in recycling bin."); return 1; freeit: #if !CWAL_ENABLE_TRACE if(0){ assert(freeMsg && "Avoid unused var warning in non-trace builds."); } #endif CWAL_TR_SV(e,e->current,v); CWAL_TR3(e,CWAL_TRACE_MEM_TO_RECYCLER, freeMsg); #if 1 { /** Pushing this memory to the chunk recycler can lower both allocs and peak marginally, but can also increase peak while lowering allocs, depending on the usage. Compare s2's UNIT.s2 vs UNIT-import.s2. They both run the same tests, but the former loads them as a single script and the latter imports one script at a time. */ cwal_size_t sz = sizeof(cwal_value)+sizeof(cwal_string) + slen + 1 /*NUL byte*/; /* Account for string size padding */ if(CwalConsts.StringPadSize){ if(slen<CwalConsts.StringPadSize) sz = sz - slen + CwalConsts.StringPadSize; else if(slen>CwalConsts.StringPadSize){ cwal_size_t const mod = (slen % CwalConsts.StringPadSize); |
︙ | ︙ | |||
15724 15725 15726 15727 15728 15729 15730 | CWAL_TR_SV(e,v->scope,v); if(CWAL_MEM_IS_BUILTIN(v)) return 0; else { cwal_obase * b; b = CWAL_VOBASE(v); CWAL_TR3(e,CWAL_TRACE_VALUE_REFCOUNT,"Unref'ing"); if(!CWAL_REFCOUNT(v) || !CWAL_RCDECR(v)){ | | > > > > | | > > | 15759 15760 15761 15762 15763 15764 15765 15766 15767 15768 15769 15770 15771 15772 15773 15774 15775 15776 15777 15778 15779 15780 15781 15782 15783 15784 15785 15786 15787 15788 15789 15790 15791 15792 15793 15794 15795 15796 15797 15798 15799 15800 15801 15802 15803 15804 15805 15806 15807 15808 15809 15810 15811 15812 15813 15814 15815 15816 | CWAL_TR_SV(e,v->scope,v); if(CWAL_MEM_IS_BUILTIN(v)) return 0; else { cwal_obase * b; b = CWAL_VOBASE(v); CWAL_TR3(e,CWAL_TRACE_VALUE_REFCOUNT,"Unref'ing"); if(!CWAL_REFCOUNT(v) || !CWAL_RCDECR(v)){ cwal_scope * const vScope = v->scope; CWAL_TR_V(e,v); if(CWAL_RCFLAG_HAS(v, CWAL_RCF_IS_GC_QUEUED)){ assert(!v->scope); CWAL_TR_S(e,vScope); CWAL_TR3(e,CWAL_TRACE_VALUE_CYCLE, "DESTRUCTION OF A GC-QUEUED OBJECT: SKIPPING"); /* Possible again since starting refcount at 0: assert(!"This is no longer possible."); */ return CWAL_RC_DESTRUCTION_RUNNING; } else if(CWAL_RCFLAG_HAS(v, CWAL_RCF_IS_RECYCLED)){ assert(!v->scope); CWAL_TR_S(e,vScope); CWAL_TR3(e,CWAL_TRACE_VALUE_CYCLE, "DESTRUCTION OF A RECYCLED OBJECT: SKIPPING"); /* Possible again since starting refcount at 0: assert(!"This is no longer possible."); */ return CWAL_RC_DESTRUCTION_RUNNING; } else if(CWAL_RCFLAG_HAS(v, CWAL_RCF_IS_DESTRUCTING)) { CWAL_TR_S(e,vScope); CWAL_TR3(e,CWAL_TRACE_VALUE_CYCLE, "ENTERING DESTRUCTION A 2ND TIME (or more): SKIPPING"); /* Possible again since starting refcount at 0: assert(!"This is no longer possible."); */ return CWAL_RC_DESTRUCTION_RUNNING; } CWAL_TR_S(e,vScope); CWAL_TR3(e,CWAL_TRACE_VALUE_CLEAN_START, "Starting finalization..."); if(e->values.exception == v){ e->values.exception = 0; } if(e->values.propagating == v){ e->values.propagating = 0; } if(!v->scope){ dump_val(v,"Value with NULL scope???"); assert(v->scope && "this is always true now. " "That was not always the case."); return e->fatalCode = CWAL_RC_ASSERT; } cwal_value_take(e, v) /*ignoring rc! take() cannot fail any more under these conditions.*/; if(b && (CWAL_F_IS_PROP_STORAGE & b->flags)){ /* reminder to self: it's potentially possible for clients to move this value into a place where |
︙ | ︙ | |||
15797 15798 15799 15800 15801 15802 15803 | for( ; sc ; sc = sc->parent ){ if(sc->props == v){ sc->props = 0; break; } } } | | | > | 15838 15839 15840 15841 15842 15843 15844 15845 15846 15847 15848 15849 15850 15851 15852 15853 15854 | for( ; sc ; sc = sc->parent ){ if(sc->props == v){ sc->props = 0; break; } } } /* The left/right assertions help ensure we're not now traversing through the recycle list, which is an easy thing to do when memory has been mismanaged. */ if(v->left || v->right){ /* This is case checked above in a different manner. If this check fails, then memory corruption is what's going on and we need to stop that... the only way we reasonably can. Alternately, we may at some |
︙ | ︙ | |||
16523 16524 16525 16526 16527 16528 16529 | is true then it also frees up htable->list.list. */ static void cwal_cleanup_htable( cwal_engine * const e, cwal_htable * const htable, bool freeList){ cwal_kvp * kvp = 0; cwal_kvp * next = 0; | | | 16565 16566 16567 16568 16569 16570 16571 16572 16573 16574 16575 16576 16577 16578 16579 | is true then it also frees up htable->list.list. */ static void cwal_cleanup_htable( cwal_engine * const e, cwal_htable * const htable, bool freeList){ cwal_kvp * kvp = 0; cwal_kvp * next = 0; for( cwal_midsize_t i = 0; htable->list.count && (i < htable->hashSize); ++i ){ kvp = (cwal_kvp*)htable->list.list[i]; htable->list.list[i] = next = NULL; for(; kvp; kvp = next){ assert(htable->list.count>0); next = kvp->right; |
︙ | ︙ | |||
16552 16553 16554 16555 16556 16557 16558 | /** Cleanup routine for the cwal_obase part of classes which use that. Cleans up the contents of b->kvp and sets b->kvp to NULL. Also, if unrefProto is true, clears the CWAL_CONTAINER_DISALLOW_PROTOTYPE_SET flag from b->flags and unrefs/NULLs b->prototype. */ | | > > > | 16594 16595 16596 16597 16598 16599 16600 16601 16602 16603 16604 16605 16606 16607 16608 16609 16610 16611 | /** Cleanup routine for the cwal_obase part of classes which use that. Cleans up the contents of b->kvp and sets b->kvp to NULL. Also, if unrefProto is true, clears the CWAL_CONTAINER_DISALLOW_PROTOTYPE_SET flag from b->flags and unrefs/NULLs b->prototype. */ static void cwal_cleanup_obase( cwal_engine * e, cwal_obase * b, bool unrefProto ){ #if CWAL_OBASE_ISA_HASH cwal_cleanup_htable(e, &b->hprops, true); #else while(b->kvp){ cwal_kvp * kvp = b->kvp; cwal_kvp * next = 0; b->kvp = 0; /* In theory the is-visiting flag is not needed here because b->kvp=0 means we cannot possibly traverse the property list as a side-effect of this cleanup. Well, we cannot |
︙ | ︙ | |||
16574 16575 16576 16577 16578 16579 16580 16581 16582 16583 16584 16585 16586 16587 16588 16589 16590 16591 16592 16593 16594 16595 | kvp->right = 0; /* if(kvp->key==bv) kvp->key = 0; */ /* if(kvp->value==bv) kvp->value = 0; */ cwal_kvp_free( e/* , bv->scope */, kvp, 1 ); } /* b->flags &= ~CWAL_F_IS_VISITING; */ } if( unrefProto ){ b->flags &= ~CWAL_CONTAINER_DISALLOW_PROTOTYPE_SET; if( b->prototype ){ cwal_value_prototype_set( CWAL_VALPART(b), NULL ); } } } /** If table->hashSize is 0, initialize the table for hashSize elements, or CwalConsts.ScopePropsHashSize if hashSize==0. Use this only to initialize an empty table. Returns 0 on success, CWAL_RC_OOM on error. */ static int cwal_htable_alloc( cwal_engine * const e, cwal_htable * const table, | > | | > > | 16619 16620 16621 16622 16623 16624 16625 16626 16627 16628 16629 16630 16631 16632 16633 16634 16635 16636 16637 16638 16639 16640 16641 16642 16643 16644 16645 16646 16647 16648 16649 16650 16651 16652 16653 16654 16655 | kvp->right = 0; /* if(kvp->key==bv) kvp->key = 0; */ /* if(kvp->value==bv) kvp->value = 0; */ cwal_kvp_free( e/* , bv->scope */, kvp, 1 ); } /* b->flags &= ~CWAL_F_IS_VISITING; */ } #endif if( unrefProto ){ b->flags &= ~CWAL_CONTAINER_DISALLOW_PROTOTYPE_SET; if( b->prototype ){ cwal_value_prototype_set( CWAL_VALPART(b), NULL ); } } } /** If table->hashSize is 0, initialize the table for hashSize elements, or CwalConsts.ScopePropsHashSize if hashSize==0. Use this only to initialize an empty table. Returns 0 on success, CWAL_RC_OOM on error. */ static int cwal_htable_alloc( cwal_engine * const e, cwal_htable * const table, cwal_midsize_t hashSize ){ if(table->hashSize && table->list.alloced){ assert(table->list.alloced >= table->hashSize); assert(table->hashSize >= hashSize); return 0; }else{ assert(!table->list.alloced); if(!hashSize) hashSize = CwalConsts.DefaultHashtableSize; int rc = 0; if(hashSize > cwal_list_reserve(e, &table->list, hashSize)){ rc = CWAL_RC_OOM; }else{ table->hashSize = hashSize; } |
︙ | ︙ | |||
16620 16621 16622 16623 16624 16625 16626 | of the returned kvp in the hash table (required for re-linking collisions). This function is intollerant of NULLs for (table,key). */ static cwal_kvp * cwal_htable_search_impl_v( cwal_htable const * htable, cwal_value const * key, | | | | 16668 16669 16670 16671 16672 16673 16674 16675 16676 16677 16678 16679 16680 16681 16682 16683 16684 16685 | of the returned kvp in the hash table (required for re-linking collisions). This function is intollerant of NULLs for (table,key). */ static cwal_kvp * cwal_htable_search_impl_v( cwal_htable const * htable, cwal_value const * key, cwal_midsize_t * tableIndex, cwal_kvp ** left ){ if(!htable->hashSize) return NULL; cwal_midsize_t const ndx = cwal_value_hash( key ) % htable->hashSize; if(!htable->list.count){ if(left) *left = 0; if(tableIndex) *tableIndex = ndx; return NULL; } cwal_type_id const kType = key->vtab->typeID /*cwal_value_type_id(key)*/; cwal_kvp * kvp = (cwal_kvp*)htable->list.list[ndx]; |
︙ | ︙ | |||
16661 16662 16663 16664 16665 16666 16667 | } /** C-string conterpart of cwal_htable_search_impl_v(). */ static cwal_kvp * cwal_htable_search_impl_cstr( cwal_htable const * htable, char const * key, | | | | 16709 16710 16711 16712 16713 16714 16715 16716 16717 16718 16719 16720 16721 16722 16723 16724 | } /** C-string conterpart of cwal_htable_search_impl_v(). */ static cwal_kvp * cwal_htable_search_impl_cstr( cwal_htable const * htable, char const * key, cwal_midsize_t keyLen, cwal_midsize_t * tableIndex, cwal_kvp ** left ){ if(!htable->hashSize) return NULL; cwal_hash_t const ndx = cwal_hash_bytes( key, keyLen ) % htable->hashSize; if(!htable->list.count){ if(left) *left = 0; if(tableIndex) *tableIndex = ndx; |
︙ | ︙ | |||
16718 16719 16720 16721 16722 16723 16724 | /** Assumes table is used as a hashtable for the value hv. The table is, if needed, resized to toSize. Returns 0 on success, CWAL_RC_OOM on OOM. */ static int cwal_htable_resize( cwal_value * const hv, cwal_htable * const table, | | | | | | 16766 16767 16768 16769 16770 16771 16772 16773 16774 16775 16776 16777 16778 16779 16780 16781 16782 16783 16784 16785 16786 16787 16788 16789 16790 16791 16792 | /** Assumes table is used as a hashtable for the value hv. The table is, if needed, resized to toSize. Returns 0 on success, CWAL_RC_OOM on OOM. */ static int cwal_htable_resize( cwal_value * const hv, cwal_htable * const table, cwal_midsize_t toSize ){ if(!hv) return CWAL_RC_MISUSE; else if(!toSize) return CWAL_RC_RANGE; //else if(CWAL_V_IS_VISITING_LIST(hv)) return CWAL_RC_IS_VISITING_LIST; else if(toSize==table->hashSize) return 0; /* highly arguable: toSize = cwal_trim_hash_size( toSize ); */ cwal_list li = cwal_list_empty; int rc = 0; cwal_engine * e = hv->scope->e; cwal_midsize_t i; //cwal_midsize_t const oldSize = table->hashSize; #ifdef DEBUG cwal_midsize_t const oldCount = table->list.count; #endif //MARKER(("Resizing htable @%p from %d to %d\n", (void *)table, (int)table->list.count, (int)toSize)); //dump_val(hv, "hv htable holder"); if(toSize > cwal_list_reserve(e, &li, toSize)){ assert(!li.list); return CWAL_RC_OOM; } |
︙ | ︙ | |||
16795 16796 16797 16798 16799 16800 16801 | static int cwal_htable_grow_if_loaded( cwal_value * const container, cwal_htable * htable, double load ){ if(!htable->list.count) return 0; else if(load<=0) load = CwalConsts.PreferredHashLoad; else if(load<0.5) load = 0.5/*kinda arbitrary*/; double const hashSize = (double)htable->hashSize; | | > > | > | < | | | < < < < < < > > | > > | 16843 16844 16845 16846 16847 16848 16849 16850 16851 16852 16853 16854 16855 16856 16857 16858 16859 16860 16861 16862 16863 16864 16865 16866 16867 16868 16869 16870 16871 16872 16873 16874 16875 16876 16877 16878 16879 16880 16881 16882 16883 16884 16885 16886 16887 16888 16889 16890 16891 16892 16893 16894 16895 16896 16897 16898 16899 16900 16901 16902 16903 16904 16905 16906 16907 16908 16909 16910 16911 16912 16913 16914 16915 16916 16917 16918 | static int cwal_htable_grow_if_loaded( cwal_value * const container, cwal_htable * htable, double load ){ if(!htable->list.count) return 0; else if(load<=0) load = CwalConsts.PreferredHashLoad; else if(load<0.5) load = 0.5/*kinda arbitrary*/; double const hashSize = (double)htable->hashSize; double const entryCount = (double)(htable->list.count ? htable->list.count : CwalConsts.DefaultHashtableSize); int rc = 0; assert(hashSize); #if 0 /* arguable. If someone wants loads of 5.0, let him. OTOH, values approaching or surpassing 1.0 break an upcoming calculation... */ if(load >= 0.95) load = 0.95; #endif if((entryCount / hashSize) > load){ cwal_midsize_t const newSize = (cwal_midsize_t)cwal_next_prime((cwal_midsize_t)(entryCount * 3 / 2)); assert(newSize > entryCount); /*MARKER(("Resizing hash: old size=%f, count=%f, Going for load %f, size=%d\n", hashSize, entryCount, load, (int)newSize));*/ rc = cwal_htable_resize(container, htable, newSize); } return rc; } int cwal_htable_insert_impl_v( cwal_value * const container, cwal_htable * const table, cwal_value * const key, cwal_value * const v, bool allowOverwrite, uint16_t kvpFlags ){ cwal_midsize_t ndx = 0; cwal_kvp * left = 0; cwal_kvp * kvp; cwal_obase * const base = CWAL_VOBASE(container); cwal_scope * const sc = container->scope; if(!key || !v) return CWAL_RC_MISUSE; else if(CWAL_V_IS_IN_CLEANUP(container)) return CWAL_RC_DESTRUCTION_RUNNING; #if 0 // These need to be checked in the higher-level containers which // call this else if((h = CWAL_HASH(container)) && table==&h->htable && CWAL_V_IS_VISITING_LIST(container)){ /* Genuine hashtable entries */ return CWAL_RC_IS_VISITING_LIST; } else if(CWAL_V_IS_VISITING(container)){ /* base->hprops properties */ return CWAL_RC_IS_VISITING; } #endif else if(!cwal_prop_key_can(key)) return CWAL_RC_TYPE; assert(!(CWAL_CONTAINER_DISALLOW_PROP_SET & base->flags) && "Expecting this to be checked before this is called."); int rc = 0; /* Maintenance reminder: we need to init/resize the table before searching so that the calculated hash index is valid. There's a corner case here where we'll grow even if the entry is already in the hashtable (so no new space would be needed), but that's not too tragic. */ if(!table->list.alloced){ rc = cwal_htable_alloc(CWAL_VENGINE(container), table, 0); //MARKER(("alloced=%d, hashSize=%d\n", (int)table->list.alloced, (int)table->hashSize)); }else{ rc = cwal_htable_grow_if_loaded(container, table, -1.0); } assert(table->list.alloced>=table->hashSize); if(rc) return rc; //dump_val(key,"cwal_htable_insert_impl_v() key adding to htable"); //MARKER(("At ndx=%d (%d?)\n", (int)ndx, // (int)(cwal_value_hash(key) % table->hashSize))); kvp = cwal_htable_search_impl_v( table, key, &ndx, &left ); //dump_val(key,"cwal_htable_insert_impl_v() key"); if(kvp){ |
︙ | ︙ | |||
16935 16936 16937 16938 16939 16940 16941 | } static int cwal_htable_remove_impl_v( cwal_value * const vSelf, cwal_htable * const htable, cwal_value * const key ){ if(!htable || !key) return CWAL_RC_MISUSE; else if(!htable->hashSize || !htable->list.count) return CWAL_RC_NOT_FOUND; | | > > < | | | | | | | | | | | | | | | | | | | | < | > > > > | | | | | | | | | | | | | | | | | | | | < < | 16983 16984 16985 16986 16987 16988 16989 16990 16991 16992 16993 16994 16995 16996 16997 16998 16999 17000 17001 17002 17003 17004 17005 17006 17007 17008 17009 17010 17011 17012 17013 17014 17015 17016 17017 17018 17019 17020 17021 17022 17023 17024 17025 17026 17027 17028 17029 17030 17031 17032 17033 17034 17035 17036 17037 17038 17039 17040 17041 17042 17043 17044 17045 17046 17047 17048 17049 17050 17051 17052 17053 17054 17055 17056 17057 | } static int cwal_htable_remove_impl_v( cwal_value * const vSelf, cwal_htable * const htable, cwal_value * const key ){ if(!htable || !key) return CWAL_RC_MISUSE; else if(!htable->hashSize || !htable->list.count) return CWAL_RC_NOT_FOUND; assert(!(CWAL_RCFLAG_HAS(vSelf,CWAL_RCF_IS_DESTRUCTING)) && "Expecting this to be checked upstream."); #if 0 // To be checked by higher-level containers... if(CWAL_RCFLAG_HAS(vSelf,CWAL_RCF_IS_DESTRUCTING)) return CWAL_RC_DESTRUCTION_RUNNING; else if(CWAL_CONTAINER_DISALLOW_PROP_SET & CWAL_VOBASE(vSelf)->flags) return CWAL_RC_DISALLOW_PROP_SET; else if(CWAL_V_IS_VISITING_LIST(vSelf)) return CWAL_RC_IS_VISITING_LIST; #endif cwal_midsize_t ndx = 0; cwal_kvp * left = 0; cwal_kvp * const kvp = cwal_htable_search_impl_v( htable, key, &ndx, &left ); cwal_engine * const e = vSelf->scope->e; if(!kvp) return CWAL_RC_NOT_FOUND; else{ assert(htable->list.count>0); if(left){ left->right = kvp->right; }else{ htable->list.list[ndx] = kvp->right; } kvp->right = NULL; --htable->list.count; cwal_kvp_free(e, kvp, 1); return 0; } } static int cwal_htable_remove_impl_cstr( cwal_value * const vSelf, cwal_htable * const htable, char const * const key, cwal_midsize_t keyLen ){ if(!vSelf || !key) return CWAL_RC_MISUSE; else if(!htable->hashSize || !htable->list.count) return CWAL_RC_NOT_FOUND; assert(!(CWAL_RCFLAG_HAS(vSelf,CWAL_RCF_IS_DESTRUCTING)) && "Expecting this to be checked upstream."); #if 0 // To be checked by higher-level containers... else if(CWAL_RCFLAG_HAS(vSelf,CWAL_RCF_IS_DESTRUCTING)) return CWAL_RC_DESTRUCTION_RUNNING; else if(CWAL_CONTAINER_DISALLOW_PROP_SET & CWAL_VOBASE(vSelf)->flags) return CWAL_RC_DISALLOW_PROP_SET; else if(CWAL_V_IS_VISITING_LIST(vSelf)) return CWAL_RC_IS_VISITING_LIST; #endif cwal_midsize_t ndx = 0; cwal_kvp * left = 0; cwal_kvp * kvp; cwal_engine * const e = vSelf->scope->e; kvp = cwal_htable_search_impl_cstr( htable, key, keyLen, &ndx, &left ); if(!kvp) return CWAL_RC_NOT_FOUND; else{ assert(htable->list.count>0); if(left){ left->right = kvp->right; }else{ htable->list.list[ndx] = kvp->right; } kvp->right = NULL; --htable->list.count; cwal_kvp_free(e, kvp, 1); return 0; } } void cwal_list_to_recycler( cwal_engine * e, cwal_list * li ){ if(li->list){ cwal_memchunk_add(e, li->list, li->alloced * sizeof(void*)); *li = cwal_list_empty; }else{ assert(!li->count); |
︙ | ︙ | |||
17806 17807 17808 17809 17810 17811 17812 | ? (char const *) *((unsigned char const **)(v+1)) : (char const *) ((unsigned char const *)(v+1))) : ""); #endif } | | | 17856 17857 17858 17859 17860 17861 17862 17863 17864 17865 17866 17867 17868 17869 17870 | ? (char const *) *((unsigned char const **)(v+1)) : (char const *) ((unsigned char const *)(v+1))) : ""); #endif } char const * cwal_string_cstr2(cwal_string const *v, cwal_midsize_t * len){ if(v && len) *len = CWAL_STRLEN(v); return cwal_string_cstr(v); } void cwal_value_cleanup_string( cwal_engine * e, void * V ){ cwal_value * v = (cwal_value*)V; cwal_string * s = cwal_value_get_string(v); |
︙ | ︙ | |||
17852 17853 17854 17855 17856 17857 17858 | int cwal_string_unref(cwal_string * s){ cwal_value * v = cwal_string_value(s); return v ? cwal_value_unref2( cwal_value_engine(v), v ) : CWAL_RC_MISUSE; } | | | | | 17902 17903 17904 17905 17906 17907 17908 17909 17910 17911 17912 17913 17914 17915 17916 17917 17918 17919 17920 17921 17922 17923 17924 17925 17926 17927 17928 17929 17930 17931 17932 17933 17934 17935 17936 17937 | int cwal_string_unref(cwal_string * s){ cwal_value * v = cwal_string_value(s); return v ? cwal_value_unref2( cwal_value_engine(v), v ) : CWAL_RC_MISUSE; } cwal_midsize_t cwal_string_length_bytes( cwal_string const * str ){ return str ? CWAL_STRLEN(str) : 0U; } cwal_midsize_t cwal_string_length_utf8( cwal_string const * str ){ return str ? (CWAL_STR_ISASCII(str) ? CWAL_STRLEN(str) : cwal_strlen_utf8( cwal_string_cstr(str), CWAL_STRLEN(str) ) ) : 0U; } bool cwal_string_is_ascii( cwal_string const * str ){ return str ? CWAL_STR_ISASCII(str) : 0; } cwal_value * cwal_new_string_value(cwal_engine * e, char const * str, cwal_midsize_t len){ return cwal_string_value( cwal_new_string(e, str, len) ); } bool cwal_cstr_internable_predicate_f_default( void * state, char const * str, cwal_size_t len ){ if(state || str){/*avoid unused param warning*/} return !CwalConsts.MaxInternedStringSize || (len <= CwalConsts.MaxInternedStringSize); |
︙ | ︙ | |||
17901 17902 17903 17904 17905 17906 17907 | assert(ndx>=0 && ndx<=127); v = (cwal_value *)CWAL_BUILTIN_VALS.memAsciiPrintable[ndx]; assert(CWAL_STR(v)); return CWAL_STR(v); } #endif | | | 17951 17952 17953 17954 17955 17956 17957 17958 17959 17960 17961 17962 17963 17964 17965 | assert(ndx>=0 && ndx<=127); v = (cwal_value *)CWAL_BUILTIN_VALS.memAsciiPrintable[ndx]; assert(CWAL_STR(v)); return CWAL_STR(v); } #endif cwal_string * cwal_new_string(cwal_engine * e, char const * str, cwal_midsize_t len){ if(!e || CWAL_STRLEN_TOO_LONG(len)){ return NULL ; } else if( !str || !len ){ METRICS_REQ_INCR(e,CWAL_TYPE_STRING); return CWAL_BUILTIN_VALS.sEmptyString; } |
︙ | ︙ | |||
17987 17988 17989 17990 17991 17992 17993 | } } } return s; } } | | > | 18037 18038 18039 18040 18041 18042 18043 18044 18045 18046 18047 18048 18049 18050 18051 18052 | } } } return s; } } cwal_string * cwal_new_xstring(cwal_engine * e, char const * str, cwal_midsize_t len){ if(!e || (len & ~((cwal_size_t)CWAL_STRLEN_MASK) /* too big */)){ return NULL; }else if( !len ){ METRICS_REQ_INCR(e,CWAL_TYPE_XSTRING); return CWAL_BUILTIN_VALS.sEmptyString; } #if CWAL_ENABLE_BUILTIN_LEN1_ASCII_STRINGS |
︙ | ︙ | |||
18024 18025 18026 18027 18028 18029 18030 | *dest = (unsigned char const *)str; cwal_string_check_for_ascii( s ); } return s; } } | | > | | 18075 18076 18077 18078 18079 18080 18081 18082 18083 18084 18085 18086 18087 18088 18089 18090 18091 18092 18093 18094 18095 | *dest = (unsigned char const *)str; cwal_string_check_for_ascii( s ); } return s; } } cwal_value * cwal_new_xstring_value(cwal_engine * e, char const * str, cwal_midsize_t len){ cwal_string * s = cwal_new_xstring(e, str, len); return s ? cwal_string_value(s) : NULL; } cwal_string * cwal_new_zstring(cwal_engine * e, char * str, cwal_midsize_t len){ if(!e || (len & ~((cwal_size_t)CWAL_STRLEN_MASK) /* too big */)){ return NULL; }else if(!str){ METRICS_REQ_INCR(e,CWAL_TYPE_ZSTRING); return CWAL_BUILTIN_VALS.sEmptyString; } else if(!len){ |
︙ | ︙ | |||
18084 18085 18086 18087 18088 18089 18090 | /* See the API docs for why we do this. */ cwal_free2( e, str, len/*+1 would be safe, until it wasn't.*/ ); } return s; } } | | | 18136 18137 18138 18139 18140 18141 18142 18143 18144 18145 18146 18147 18148 18149 18150 | /* See the API docs for why we do this. */ cwal_free2( e, str, len/*+1 would be safe, until it wasn't.*/ ); } return s; } } cwal_value * cwal_new_zstring_value(cwal_engine * e, char * str, cwal_midsize_t len){ cwal_string * s = cwal_new_zstring(e, str, len); return s ? cwal_string_value(s) : NULL; } int cwal_buffer_reset( cwal_buffer * b ){ if(!b) return CWAL_RC_MISUSE; |
︙ | ︙ | |||
18581 18582 18583 18584 18585 18586 18587 18588 18589 | */ static int cwal_xscope_visitor_children_array( void * V, void * VParent ){ cwal_value * par = (cwal_value*)VParent; cwal_value * child = (cwal_value*)V; assert(par && par->scope); return cwal_value_xscope( par->scope->e, par->scope, child, 0 ); } int cwal_rescope_children_obase( cwal_value * v ){ | > > > > > > > > > > > > > > > > > > > > > > > > > > | < < > > > > > > > > > | 18633 18634 18635 18636 18637 18638 18639 18640 18641 18642 18643 18644 18645 18646 18647 18648 18649 18650 18651 18652 18653 18654 18655 18656 18657 18658 18659 18660 18661 18662 18663 18664 18665 18666 18667 18668 18669 18670 18671 18672 18673 18674 18675 18676 18677 18678 18679 18680 18681 18682 18683 18684 18685 18686 18687 18688 18689 18690 18691 18692 18693 18694 18695 18696 | */ static int cwal_xscope_visitor_children_array( void * V, void * VParent ){ cwal_value * par = (cwal_value*)VParent; cwal_value * child = (cwal_value*)V; assert(par && par->scope); return cwal_value_xscope( par->scope->e, par->scope, child, 0 ); } static void cwal_htable_rescope(cwal_scope * const sc, cwal_htable * const h){ /* cwal_dump_v(nv,"Re-scoping cwal_htable children..."); */ int rc = 0; cwal_midsize_t const max = h->list.alloced>=h->hashSize ? h->hashSize : h->list.alloced; for( cwal_midsize_t i = 0; !rc && (i < max); ++i ){ cwal_kvp * kvp = (cwal_kvp*)h->list.list[i]; if(!kvp) continue; cwal_kvp * next = NULL; for( ; !rc && kvp; kvp = next){ next = kvp->right; assert(kvp->key); assert(kvp->value); rc = cwal_value_xscope(sc->e, sc, kvp->key, 0); if(!rc && kvp->key != kvp->value){ rc = cwal_value_xscope(sc->e, sc, kvp->value, 0); } /* cwal_dump_v(kvp->key,"Re-scoped key"); */ /* cwal_dump_v(kvp->value,"Re-scoped value"); */ } assert(!rc && "Rescoping failure is no longer be possible " "except in the case of memory corruption."); } } int cwal_rescope_children_obase( cwal_value * v ){ cwal_obase * const b = CWAL_VOBASE(v); int rc = CWAL_RC_OK; assert(b); assert(CWAL_V_IS_RESCOPING(v)); assert(v->scope); #if CWAL_OBASE_ISA_HASH cwal_htable_rescope(v->scope, &b->hprops); #else cwal_obase_kvp_iter iter; cwal_kvp const * kvp = cwal_obase_kvp_iter_init(v, &iter); for( ; kvp && (0==rc); kvp = cwal_obase_kvp_iter_next(&iter) ){ if(kvp->key){ rc = cwal_value_xscope( v->scope->e, v->scope, kvp->key, 0 ); } if((0==rc) && kvp->value){ rc = cwal_value_xscope( v->scope->e, v->scope, kvp->value, 0 ); } } if(rc){ assert(!"Rescoping failure should no longer be possible."); } #endif return rc; } int cwal_rescope_children_native( cwal_value * v ){ int rc; cwal_native * n = cwal_value_get_native(v); assert(v->scope); |
︙ | ︙ | |||
19292 19293 19294 19295 19296 19297 19298 | : CWAL_RC_MISUSE; } /** The C-string equivalent of cwal_obase_search_v(). */ static cwal_value * cwal_obase_search( cwal_obase const * base, | | | > > > > > | 19377 19378 19379 19380 19381 19382 19383 19384 19385 19386 19387 19388 19389 19390 19391 19392 19393 19394 19395 19396 19397 19398 19399 19400 19401 19402 19403 19404 19405 19406 | : CWAL_RC_MISUSE; } /** The C-string equivalent of cwal_obase_search_v(). */ static cwal_value * cwal_obase_search( cwal_obase const * base, bool searchProto, char const * const key, cwal_midsize_t keyLen, cwal_kvp ** prev){ if(!base || !key) return NULL; else { cwal_kvp * kvp; cwal_value * rc = NULL; while(base){ if(CWAL_F_LOCKED & base->flags) break; #if CWAL_OBASE_ISA_HASH kvp = cwal_htable_search_impl_cstr(&base->hprops, key, keyLen, NULL, prev); #else kvp = cwal_kvp_search( base->kvp, key, keyLen, prev ); #endif if(kvp) { rc = kvp->value; break; } else base = searchProto ? CWAL_VOBASE(base->prototype) : 0; } return rc; |
︙ | ︙ | |||
19352 19353 19354 19355 19356 19357 19358 | prototypes) while searching, NULL is returned. It does not simply skip over the locked member because the search results could then arguably be inconsistent, depending on whether the locked member actually overrides the property from a prototype further up the chain. */ static cwal_value * cwal_obase_search_v( cwal_obase const * base, | | > > > > | | | < < | | < | < | | < < | < | < | | | < | | < | < | > | | < < | > > > > > | > > > > | 19442 19443 19444 19445 19446 19447 19448 19449 19450 19451 19452 19453 19454 19455 19456 19457 19458 19459 19460 19461 19462 19463 19464 19465 19466 19467 19468 19469 19470 19471 19472 19473 19474 19475 19476 19477 19478 19479 19480 19481 19482 19483 19484 19485 19486 19487 19488 19489 19490 19491 19492 19493 19494 19495 19496 19497 19498 19499 19500 19501 19502 19503 19504 19505 19506 19507 19508 19509 19510 19511 19512 19513 19514 19515 19516 19517 19518 19519 19520 19521 19522 19523 19524 19525 19526 19527 19528 19529 19530 19531 19532 19533 19534 19535 19536 19537 19538 19539 19540 19541 19542 19543 19544 19545 19546 19547 19548 19549 19550 19551 19552 19553 19554 19555 19556 19557 19558 19559 19560 19561 19562 19563 19564 | prototypes) while searching, NULL is returned. It does not simply skip over the locked member because the search results could then arguably be inconsistent, depending on whether the locked member actually overrides the property from a prototype further up the chain. */ static cwal_value * cwal_obase_search_v( cwal_obase const * base, bool searchProto, cwal_value const * key, cwal_kvp ** prev){ if(!base || !key) return NULL; else { cwal_kvp * kvp; cwal_value * rc = NULL; while(base){ if(CWAL_F_LOCKED & base->flags) break; #if CWAL_OBASE_ISA_HASH kvp = cwal_htable_search_impl_v(&base->hprops, key, NULL, prev); #else kvp = cwal_kvp_search_v( base->kvp, key, prev ); #endif if(kvp) { rc = kvp->value; /* Here is where we would check if kvp->value is a function with the CWAL_CONTAINER_PROP_GETTER container flag. If so, we would return the call to that function, passing it (key). */ break; } else { base = searchProto ? CWAL_VOBASE(base->prototype) : 0; } } return rc; } } bool cwal_prop_has( cwal_value const * v, char const * key, cwal_midsize_t keyLen, bool searchPrototype ) { cwal_obase const * const base = CWAL_VOBASE(v); return (base && key) ? !!cwal_obase_search(base, searchPrototype, key, keyLen, NULL) : false; } bool cwal_prop_has_v( cwal_value const * v, cwal_value const * key, bool searchPrototype ){ cwal_obase const * base = CWAL_VOBASE(v); return (base && key) ? !!cwal_obase_search_v(base, searchPrototype, key, NULL ) : false; } cwal_value * cwal_prop_get( cwal_value const * v, char const * key, cwal_midsize_t keyLen ) { cwal_obase const * const base = CWAL_VOBASE(v); return (base && key) ? cwal_obase_search( base, true, key, keyLen, NULL ) : NULL; } cwal_value * cwal_prop_get_v( cwal_value const * c, cwal_value const * key ) { cwal_obase const * base = CWAL_VOBASE(c); return (base && key) ? cwal_obase_search_v( base, true, key, NULL ) : NULL; } cwal_kvp * cwal_prop_get_kvp( cwal_value * c, char const * key, cwal_midsize_t keyLen, bool searchProtos, cwal_value ** foundIn ){ cwal_obase * b = CWAL_VOBASE(c); if(!key || !*key || !b) return 0; else{ cwal_kvp * rc = 0; while(b){ #if CWAL_OBASE_ISA_HASH rc = cwal_htable_search_impl_cstr(&b->hprops, key, keyLen, NULL, NULL); #else rc = cwal_kvp_search(b->kvp, key, keyLen, NULL); #endif if(rc){ if(foundIn) *foundIn = c; break; }else if(searchProtos && (c = b->prototype) && (b = CWAL_VOBASE(c))){ continue; } b = 0; }while(0); return rc; } } cwal_kvp * cwal_prop_get_kvp_v( cwal_value * c, cwal_value const * key, bool searchProtos, cwal_value ** foundIn ){ cwal_obase * b = CWAL_VOBASE(c); if(!key || !b) return 0; else{ cwal_kvp * rc = 0; while(b){ #if CWAL_OBASE_ISA_HASH rc = cwal_htable_search_impl_v(&b->hprops, key, NULL, NULL); #else rc = cwal_kvp_search_v(b->kvp, key, NULL); #endif if(rc){ if(foundIn) *foundIn = c; break; }else if(searchProtos && (c = b->prototype) && (b = CWAL_VOBASE(c))){ continue; |
︙ | ︙ | |||
19541 19542 19543 19544 19545 19546 19547 | }else if(rv){ *rv = maybeFunc; } return rc; } int cwal_prop_getX( cwal_value * c, | | | | 19632 19633 19634 19635 19636 19637 19638 19639 19640 19641 19642 19643 19644 19645 19646 19647 19648 | }else if(rv){ *rv = maybeFunc; } return rc; } int cwal_prop_getX( cwal_value * c, bool processInterceptors, char const * key, cwal_midsize_t keyLen, cwal_value ** rv ){ cwal_obase const * base = CWAL_VOBASE(c); if(!base || !key) return CWAL_RC_MISUSE; else{ cwal_value * foundIn = 0; cwal_kvp * kvp = cwal_prop_get_kvp( c, key, keyLen, 1, &foundIn ); int rc; |
︙ | ︙ | |||
19565 19566 19567 19568 19569 19570 19571 | rc = 0; } return rc; } } int cwal_prop_getX_v( cwal_value * c, | | | 19656 19657 19658 19659 19660 19661 19662 19663 19664 19665 19666 19667 19668 19669 19670 | rc = 0; } return rc; } } int cwal_prop_getX_v( cwal_value * c, bool processInterceptors, cwal_value const * key, cwal_value ** rv ){ cwal_obase const * base = CWAL_VOBASE(c); if(!base || !key) return CWAL_RC_MISUSE; else{ cwal_value * foundIn = 0; cwal_kvp * kvp = cwal_prop_get_kvp_v( c, key, 1, &foundIn ); |
︙ | ︙ | |||
19589 19590 19591 19592 19593 19594 19595 | } return rc; } } int cwal_prop_unset( cwal_value * const c, | | | | > > > > > > > > > > > > > > | | 19680 19681 19682 19683 19684 19685 19686 19687 19688 19689 19690 19691 19692 19693 19694 19695 19696 19697 19698 19699 19700 19701 19702 19703 19704 19705 19706 19707 19708 19709 19710 19711 19712 19713 19714 19715 19716 19717 19718 19719 19720 19721 19722 19723 19724 | } return rc; } } int cwal_prop_unset( cwal_value * const c, char const * key, cwal_midsize_t keyLen ) { cwal_obase * const b = CWAL_VOBASE(c); cwal_engine * const e = b ? CWAL_VENGINE(c) : NULL; if(!e) return CWAL_RC_MISUSE; else if(CWAL_RCFLAG_HAS(c,CWAL_RCF_IS_DESTRUCTING)) return CWAL_RC_DESTRUCTION_RUNNING; else if(CWAL_V_IS_VISITING(c)) return CWAL_RC_IS_VISITING; else if(CWAL_CONTAINER_DISALLOW_PROP_SET & b->flags){ return CWAL_RC_DISALLOW_PROP_SET; } #if CWAL_OBASE_ISA_HASH return cwal_htable_remove_impl_cstr(c, &b->hprops, key, keyLen); #else return cwal_kvp_unset( e, &b->kvp, key, keyLen ); #endif } int cwal_prop_unset_v( cwal_value * c, cwal_value * key ) { cwal_obase * b = CWAL_VOBASE(c); cwal_engine * e = b ? CWAL_VENGINE(c) : NULL; if(!e) return CWAL_RC_MISUSE; else if(CWAL_RCFLAG_HAS(c,CWAL_RCF_IS_DESTRUCTING)) return CWAL_RC_DESTRUCTION_RUNNING; else if(CWAL_V_IS_VISITING(c)) return CWAL_RC_IS_VISITING; else if(CWAL_CONTAINER_DISALLOW_PROP_SET & b->flags) return CWAL_RC_DISALLOW_PROP_SET; #if CWAL_OBASE_ISA_HASH return cwal_htable_remove_impl_v(c, &b->hprops, key); #else return cwal_kvp_unset_v( e, &b->kvp, key ); #endif } #if !CWAL_OBASE_ISA_HASH /** Adds an entry or updates an existing one in the given kvp list. listOwner must be the value which owns/manages list. key is the key to search for and value is the value to set it to. key->vtab->compare() is used to test for equivalence. On success listOwner->kvp may be modified. |
︙ | ︙ | |||
19641 19642 19643 19644 19645 19646 19647 | Returns CWAL_RC_DISALLOW_NEW_PROPERTIES if listOwner is flagged with the CWAL_CONTAINER_DISALLOW_NEW_PROPERTIES flag _AND_ key refers to a new property. If flags!=CWAL_VAR_F_PRESERVE then the flags of the kvp are set to the given value (but the CONST check trumps this). | < | | < < < < | | 19746 19747 19748 19749 19750 19751 19752 19753 19754 19755 19756 19757 19758 19759 19760 19761 19762 19763 19764 19765 19766 19767 19768 19769 19770 19771 19772 19773 19774 19775 | Returns CWAL_RC_DISALLOW_NEW_PROPERTIES if listOwner is flagged with the CWAL_CONTAINER_DISALLOW_NEW_PROPERTIES flag _AND_ key refers to a new property. If flags!=CWAL_VAR_F_PRESERVE then the flags of the kvp are set to the given value (but the CONST check trumps this). */ static int cwal_kvp_set_v( cwal_engine * e, cwal_value * listOwner, cwal_value * key, cwal_value * v, uint32_t flags ){ if( !e || !key || !listOwner || !v ) return CWAL_RC_MISUSE; else { int rc; cwal_kvp * kvp = 0; cwal_kvp * left = 0; char i = 0; bool iAlloccedKvp = 0; cwal_obase * const ob = CWAL_VOBASE(listOwner); assert(ob); if(CWAL_CONTAINER_DISALLOW_PROP_SET & ob->flags){ return CWAL_RC_DISALLOW_PROP_SET; } kvp = cwal_kvp_search_v( ob->kvp, key, &left ); if( !kvp ){ if(CWAL_CONTAINER_DISALLOW_NEW_PROPERTIES & ob->flags){ return CWAL_RC_DISALLOW_NEW_PROPERTIES; } else if(!v){ return CWAL_RC_NOT_FOUND; } |
︙ | ︙ | |||
19691 19692 19693 19694 19695 19696 19697 | if(CWAL_VAR_F_PRESERVE!=flags) kvp->flags = flags; /* Reminder: we have to increase the refcount of the key even if it's the same pointer as a key we have or the same as v. Remember that interning guarantees that we'll eventually see the same key instances. */ | < | | < | < | | < | < | > | | > > | | | | < | > > > | | > | | | | | > | > > < < | | < | | | | | < < | | | | | | < | > > > > > > | > > > > > > | | > | | > > > > > > > | | > > > > | | | | | | | | > > > > | > | | > > > > > | > | | > > > > > > > | | > > > > < > < < < | < < < < < < < < < | < < > | | | | < | 19791 19792 19793 19794 19795 19796 19797 19798 19799 19800 19801 19802 19803 19804 19805 19806 19807 19808 19809 19810 19811 19812 19813 19814 19815 19816 19817 19818 19819 19820 19821 19822 19823 19824 19825 19826 19827 19828 19829 19830 19831 19832 19833 19834 19835 19836 19837 19838 19839 19840 19841 19842 19843 19844 19845 19846 19847 19848 19849 19850 19851 19852 19853 19854 19855 19856 19857 19858 19859 19860 19861 19862 19863 19864 19865 19866 19867 19868 19869 19870 19871 19872 19873 19874 19875 19876 19877 19878 19879 19880 19881 19882 19883 19884 19885 19886 19887 19888 19889 19890 19891 19892 19893 19894 19895 19896 19897 19898 19899 19900 19901 19902 19903 19904 19905 19906 19907 19908 19909 19910 19911 19912 19913 19914 19915 19916 19917 19918 19919 19920 19921 19922 19923 19924 19925 19926 19927 19928 19929 19930 19931 19932 19933 19934 19935 19936 19937 19938 19939 19940 19941 19942 19943 19944 19945 19946 19947 19948 19949 19950 19951 19952 19953 19954 19955 19956 19957 19958 19959 19960 19961 19962 19963 19964 19965 19966 19967 19968 19969 19970 19971 19972 19973 19974 19975 19976 19977 19978 19979 19980 19981 19982 19983 19984 19985 19986 19987 19988 19989 19990 19991 19992 19993 19994 19995 19996 19997 19998 19999 20000 20001 20002 20003 20004 20005 20006 20007 20008 20009 20010 20011 20012 20013 20014 20015 20016 20017 20018 20019 20020 20021 20022 20023 20024 20025 20026 20027 20028 20029 20030 20031 20032 20033 20034 20035 20036 20037 20038 20039 20040 20041 20042 20043 20044 20045 20046 20047 20048 20049 20050 20051 20052 20053 20054 20055 20056 20057 20058 20059 20060 20061 20062 20063 20064 20065 20066 20067 20068 20069 20070 20071 20072 20073 | if(CWAL_VAR_F_PRESERVE!=flags) kvp->flags = flags; /* Reminder: we have to increase the refcount of the key even if it's the same pointer as a key we have or the same as v. Remember that interning guarantees that we'll eventually see the same key instances. */ for( i = 0; i < 2; ++i ){ /* 0==key, 1==value */ cwal_value * vv = 0==i ? key : v; rc = cwal_value_xscope( e, listOwner->scope, vv, 0 ); if(rc){ if(iAlloccedKvp){ cwal_kvp_free( e/* , listOwner->scope */, kvp, 1 ); } assert(!"This cannot fail since the transition from arrays to linked lists."); return rc; } /* The ref/unref order is important in case key==kvp->key or... in case v==kvp->value, key, or listOwner. */ cwal_value_ref2( e, vv ); if(0==i) { /* KEY part... */ if(kvp->key){ cwal_value_unref2( e, kvp->key ); } kvp->key = vv; }else{ /* VALUE part... */ if(kvp->value){ cwal_value_unref2( e, kvp->value ); } kvp->value = vv; break; } } assert(1 == i); assert(kvp->key != 0); assert(kvp->value != 0); if(!iAlloccedKvp){ /* kvp is already in *list */ assert(left || ob->kvp==kvp); }else if(left){ /* kvp compares > left, so insert it here. */ cwal_kvp * const r = left->right; assert(!kvp->right); left->right = kvp; kvp->right = r; }else{ /* Make kvp the head of the list */ assert(!left); assert(ob->kvp != kvp); assert(!kvp->right); kvp->right = ob->kvp; ob->kvp = kvp; } return CWAL_RC_OK; } } #endif /* !CWAL_OBASE_ISA_HASH */ #if 0 /** qsort(3) comparison func for a C-style (not cwal-style) array of (cwal_kvp const *). */ static int cwal_props_cmp(void const *l, void const *r){ cwal_kvp const * lhs = *((cwal_kvp const **)l); cwal_kvp const * rhs = *((cwal_kvp const **)r); return cwal_value_compare( lhs ? lhs->key : NULL, rhs ? rhs->key : NULL ); } #endif static int cwal_prop_setX_impl_v( cwal_value * c, CWAL_UNUSED_VAR bool processInterceptors, cwal_value * key, cwal_value * v, uint16_t flags ) { cwal_obase * const b = CWAL_VOBASE(c); cwal_engine * const e = CWAL_VENGINE(c); assert(v ? (!!e || CWAL_MEM_IS_BUILTIN(v)) : 1); if(!e || !key) return CWAL_RC_MISUSE; else if(!b || !cwal_prop_key_can(key)) return CWAL_RC_TYPE; else if(CWAL_RCFLAG_HAS(c,CWAL_RCF_IS_DESTRUCTING)) return CWAL_RC_DESTRUCTION_RUNNING; else if(CWAL_V_IS_VISITING(c)) return CWAL_RC_IS_VISITING; else if(CWAL_CONTAINER_DISALLOW_PROP_SET & b->flags){ return CWAL_RC_DISALLOW_PROP_SET; } if(v){ #if CWAL_OBASE_ISA_HASH return cwal_htable_insert_impl_v(c, &b->hprops, key, v, true, flags); #else return cwal_kvp_set_v( e, c, key, v, flags ); #endif } return cwal_prop_unset_v( c, key ); } int cwal_prop_setX_with_flags_v( cwal_value * c, bool processInterceptors, cwal_value * key, cwal_value * v, uint16_t flags ) { return cwal_prop_setX_impl_v( c, processInterceptors, key, v, flags ); } int cwal_prop_set_with_flags_v( cwal_value * c, cwal_value * key, cwal_value * v, uint16_t flags ) { return cwal_prop_setX_impl_v( c, 0, key, v, flags ); } int cwal_prop_set_v( cwal_value * c, cwal_value * key, cwal_value * v ) { return cwal_prop_set_with_flags_v( c, key, v, CWAL_VAR_F_PRESERVE ); } static int cwal_prop_setX_impl( cwal_value * c, bool processInterceptors, char const * key, cwal_midsize_t keyLen, cwal_value * v, uint16_t flags ) { cwal_obase * const b = CWAL_VOBASE(c); cwal_engine * const e = b ? CWAL_VENGINE(c) : 0; if( !e || !key ) return CWAL_RC_MISUSE; else if(!b) return CWAL_RC_TYPE; else if(CWAL_V_IS_VISITING(c)) return CWAL_RC_IS_VISITING; else if(CWAL_CONTAINER_DISALLOW_PROP_SET & b->flags){ return CWAL_RC_DISALLOW_PROP_SET; } else if(CWAL_RCFLAG_HAS(c,CWAL_RCF_IS_DESTRUCTING)){ return CWAL_RC_DESTRUCTION_RUNNING; } else if( NULL == v ) return cwal_prop_unset( c, key, keyLen ); cwal_value * const vkey = cwal_new_string_value(e, key, keyLen); if(!vkey) return CWAL_RC_OOM; int rc; cwal_value_ref(vkey); rc = cwal_prop_setX_impl_v( c, processInterceptors, vkey, v, flags); cwal_value_unref2(e, vkey); return rc; } int cwal_prop_setX_with_flags( cwal_value * c, bool processInterceptors, char const * key, cwal_midsize_t keyLen, cwal_value * v, uint16_t flags ) { return cwal_prop_setX_impl( c, processInterceptors, key, keyLen, v, flags ); } int cwal_prop_set_with_flags( cwal_value * c, char const * key, cwal_midsize_t keyLen, cwal_value * v, uint16_t flags ) { return cwal_prop_setX_impl( c, 0, key, keyLen, v, flags ); } int cwal_prop_set( cwal_value * c, char const * key, cwal_midsize_t keyLen, cwal_value * v ) { return cwal_prop_set_with_flags( c, key, keyLen, v, CWAL_VAR_F_PRESERVE ); } cwal_value * cwal_prop_take( cwal_value * c, char const * key ){ cwal_obase * const b = CWAL_VOBASE(c); cwal_engine * const e = CWAL_VENGINE(c); assert(c ? !!e : 1); if( !e || !b || !key || CWAL_V_IS_VISITING(c)) return NULL; #if CWAL_OBASE_ISA_HASH else if(!b->hprops.list.count) return NULL; #else else if(!b->kvp) return NULL; #endif else { /* FIXME: this is 90% identical to cwal_kvp_unset(), only with different refcount handling. Consolidate them. FIXME #2: instead of keeping our reference, drop the reference and reprobate the value if needed. */ cwal_kvp * kvp; cwal_kvp * left = 0; cwal_value * rv = NULL; #if CWAL_OBASE_ISA_HASH cwal_midsize_t ndx = 0; kvp = cwal_htable_search_impl_cstr(&b->hprops, key, cwal_strlen(key), &ndx, &left); #else kvp = cwal_kvp_search( b->kvp, key, cwal_strlen(key), &left ); #endif if( !kvp ) return NULL; rv = kvp->value; if(left){ assert(kvp==left->right); left->right = kvp->right; }else{ #if CWAL_OBASE_ISA_HASH /* kvp is the only entry at ndx or the left-most entry in a hash collision */ assert(b->hprops.list.list[ndx] == kvp); b->hprops.list.list[ndx] = kvp->right; #else assert(b->kvp == kvp && "kvp is the head of b->kvp"); b->kvp = kvp->right; #endif } #if CWAL_OBASE_ISA_HASH --b->hprops.list.count; #endif kvp->right = NULL; assert(rv); cwal_value_unref2(e, kvp->key); kvp->key = 0; kvp->value = NULL/*steal its ref point*/; cwal_kvp_free( e, kvp, 1 ); if(!CWAL_MEM_IS_BUILTIN(rv)){ assert( (CWAL_REFCOUNT(rv) > 0) && "Should still have kvp's reference!" ); cwal_value_unhand(rv); } return rv; } } cwal_value * cwal_prop_take_v( cwal_value * c, cwal_value * key, cwal_value ** takeKeyAsWell ){ cwal_obase * const b = CWAL_VOBASE(c); cwal_engine * const e = CWAL_VENGINE(c); assert(c ? !!e : 1); if( !e || !b || !key) return NULL; #if CWAL_OBASE_ISA_HASH else if(!b->hprops.list.count) return NULL; #else else if(!b->kvp) return NULL; #endif else if(CWAL_V_IS_VISITING(c)) return NULL; else{ cwal_kvp * left = 0; cwal_value * rv = 0; cwal_kvp * kvp; #if CWAL_OBASE_ISA_HASH cwal_midsize_t ndx = 0; kvp = cwal_htable_search_impl_v(&b->hprops, key, &ndx, &left); #else kvp = cwal_kvp_search_v( b->kvp, key, &left ); #endif if(!kvp) return NULL; rv = cwal_kvp_value(kvp); if(left){ assert(kvp==left->right); left->right = kvp->right; }else{ #if CWAL_OBASE_ISA_HASH /* kvp is only entry at ndx or the left-most entry in a hash collision */ assert(b->hprops.list.list[ndx] == kvp); b->hprops.list.list[ndx] = kvp->right; #else assert(b->kvp == kvp && "kvp is the head b->kvp"); b->kvp = kvp->right /* ? kvp->right : NULL */; #endif } #if CWAL_OBASE_ISA_HASH --b->hprops.list.count; #endif kvp->right = NULL; kvp->value = NULL/*steal its ref point*/; if(takeKeyAsWell){ *takeKeyAsWell = kvp->key; kvp->key = NULL; cwal_value_unhand(*takeKeyAsWell); } cwal_kvp_free(e, kvp, 1); if(!CWAL_MEM_IS_BUILTIN(rv)){ assert( (CWAL_REFCOUNT(rv) > 0) && "Should still have kvp's reference!" ); cwal_value_unhand(rv); } return rv; } } /** "Visits" one member of a key/value pair. If mode is 0 then the key is visited, and 1 means to visit the value. Any other value is illegal. |
︙ | ︙ | |||
19992 19993 19994 19995 19996 19997 19998 | } } int cwal_props_clear( cwal_value * c ){ cwal_obase * b = CWAL_VOBASE(c); cwal_engine * e = CWAL_VENGINE(c); /* dump_val(c,"props_clear"); */ | < | | < < | < < < < < < | < > > > > | | < < < < > | > > > > | > | | | | | | > | < < | 20122 20123 20124 20125 20126 20127 20128 20129 20130 20131 20132 20133 20134 20135 20136 20137 20138 20139 20140 20141 20142 20143 20144 20145 20146 20147 20148 20149 20150 20151 20152 20153 20154 20155 20156 20157 20158 20159 20160 20161 20162 20163 20164 20165 20166 20167 20168 20169 20170 20171 20172 20173 20174 20175 20176 20177 20178 20179 20180 20181 20182 20183 20184 20185 20186 20187 20188 20189 | } } int cwal_props_clear( cwal_value * c ){ cwal_obase * b = CWAL_VOBASE(c); cwal_engine * e = CWAL_VENGINE(c); /* dump_val(c,"props_clear"); */ if(!b) return CWAL_RC_TYPE; else if(CWAL_CONTAINER_DISALLOW_PROP_SET & b->flags){ return CWAL_RC_DISALLOW_PROP_SET; }else{ cwal_cleanup_obase( e, b, false ); return CWAL_RC_OK; } } static int cwal_kvp_visitor_props_copy( cwal_kvp const * kvp, void * state ){ cwal_value * const dest = (cwal_value*)state; cwal_obase * const b = CWAL_VOBASE(dest); cwal_engine * const e = CWAL_VENGINE(dest); if( !e || !b ) return CWAL_RC_MISUSE; /* Reminder: we have to keep the property flags intact. */ #if CWAL_OBASE_ISA_HASH return cwal_htable_insert_impl_v(dest, &b->hprops, kvp->key, kvp->value, true, kvp->flags); #else return cwal_kvp_set_v( e, dest, kvp->key, kvp->value, kvp->flags ); #endif } int cwal_props_copy( cwal_value * src, cwal_value * dest ){ cwal_obase const * const bSrc = CWAL_VOBASE(src); cwal_obase const * const bDest = CWAL_VOBASE(dest); if(!src || !dest) return CWAL_RC_MISUSE; else if(!bSrc || !bDest) return CWAL_RC_TYPE; else if(CWAL_V_IS_VISITING(dest)) return CWAL_RC_IS_VISITING; /*else if(CWAL_OB_IS_LOCKED(bSrc) || CWAL_OB_IS_LOCKED(bDest)) return CWAL_RC_LOCKED;*/ return cwal_props_visit_kvp( src, cwal_kvp_visitor_props_copy, dest ); } bool cwal_props_has_any( cwal_value const * c ){ cwal_obase const * b = CWAL_VOBASE(c); #if CWAL_OBASE_ISA_HASH return 0 < b->hprops.list.count; #else return b && b->kvp ? 1 : 0; #endif } cwal_midsize_t cwal_props_count( cwal_value const * c ){ cwal_obase const * b = CWAL_VOBASE(c); #if CWAL_OBASE_ISA_HASH return b->hprops.list.count; #else cwal_size_t rc = 0; cwal_kvp const * kvp = b->kvp; for( ; kvp ; ++rc, kvp = kvp->right ){} return rc; #endif } int cwal_props_visit_values( cwal_value * c, cwal_value_visitor_f f, void * state ){ cwal_obase * b = CWAL_VOBASE(c); if(!c || !f) return CWAL_RC_MISUSE; else if(!b) return CWAL_RC_TYPE; else { int rc = 0; |
︙ | ︙ | |||
20102 20103 20104 20105 20106 20107 20108 | bool cwal_value_may_iterate( cwal_value const * const c ){ if(!c) return 0; else if(CWAL_MEM_IS_BUILTIN(c)){ return 0; } else{ | < > | > | 20227 20228 20229 20230 20231 20232 20233 20234 20235 20236 20237 20238 20239 20240 20241 20242 20243 20244 20245 20246 20247 20248 20249 20250 20251 20252 20253 20254 20255 | bool cwal_value_may_iterate( cwal_value const * const c ){ if(!c) return 0; else if(CWAL_MEM_IS_BUILTIN(c)){ return 0; } else{ #if 0 cwal_obase const * const ob = CWAL_VOBASE(c); /* No... this will disable iteration even when array indexes (but not properties) are locked... */ return ob ? ((CWAL_F_LOCKED & ob->flags) ? 0 : 1) : 0; #else return !!CWAL_VOBASE(c); #endif } } bool cwal_value_is_iterating_list( cwal_value const * const c ){ return c ? CWAL_V_IS_VISITING_LIST(c) : 0; } bool cwal_value_is_iterating_props( cwal_value const * const c ){ return c ? CWAL_V_IS_VISITING(c) : 0; } bool cwal_value_may_iterate_list( cwal_value const * const c ){ if(!c) return 0; switch(c->vtab->typeID){ |
︙ | ︙ | |||
20146 20147 20148 20149 20150 20151 20152 | int opaque; cwal_obase_kvp_iter iter; cwal_kvp const * kvp; cwal_visit_props_begin(c, &opaque); kvp = cwal_obase_kvp_iter_init(c, &iter); assert( CWAL_RCFLAG_HAS(c, CWAL_RCF_IS_VISITING) ); cwal_value_ref(c); | < | < > | | 20272 20273 20274 20275 20276 20277 20278 20279 20280 20281 20282 20283 20284 20285 20286 20287 20288 20289 20290 | int opaque; cwal_obase_kvp_iter iter; cwal_kvp const * kvp; cwal_visit_props_begin(c, &opaque); kvp = cwal_obase_kvp_iter_init(c, &iter); assert( CWAL_RCFLAG_HAS(c, CWAL_RCF_IS_VISITING) ); cwal_value_ref(c); for( ; kvp && (0==rc); kvp = cwal_obase_kvp_iter_next(&iter) ){ if(!(CWAL_VAR_F_HIDDEN & kvp->flags)){ /* In case the callback does something untowards with the kvp, we'll hold a couple new refs... */ cwal_value * const lhs = kvp->key; cwal_value * const rhs = kvp->value; cwal_value_ref(lhs); cwal_value_ref(rhs); rc = f( kvp, state ); cwal_value_unref(lhs); cwal_value_unref(rhs); |
︙ | ︙ | |||
20666 20667 20668 20669 20670 20671 20672 | ? cwal_cstr_to_double( cwal_string_cstr(s), CWAL_STRLEN(s), dest ) : CWAL_RC_MISUSE; } void cwal_hash_clear( cwal_hash * h, bool freeProps ){ cwal_scope * const sc = h ? CWAL_VALPART(h)->scope : 0; cwal_engine * const e = sc ? sc->e : 0; | < | | | | | | < < | < < < | < < < < | < < < < < < < < < < < < < < < | | 20791 20792 20793 20794 20795 20796 20797 20798 20799 20800 20801 20802 20803 20804 20805 20806 20807 20808 20809 20810 20811 20812 20813 20814 20815 20816 20817 20818 20819 20820 20821 20822 20823 20824 20825 20826 20827 20828 20829 | ? cwal_cstr_to_double( cwal_string_cstr(s), CWAL_STRLEN(s), dest ) : CWAL_RC_MISUSE; } void cwal_hash_clear( cwal_hash * h, bool freeProps ){ cwal_scope * const sc = h ? CWAL_VALPART(h)->scope : 0; cwal_engine * const e = sc ? sc->e : 0; assert(e && "Else invalid cwal_hash reference."); cwal_cleanup_htable(e, &h->htable, false); if(freeProps){ cwal_cleanup_obase(e, &h->base, false); } } void cwal_value_cleanup_hash( cwal_engine * e, void * V ){ cwal_value * vSelf = (cwal_value *)V; cwal_hash * h = CWAL_HASH(vSelf); /* MARKER("Freeing hash @%p\n", (void const *)h); */ cwal_hash_clear( h, 1 ); cwal_cleanup_htable(e, &h->htable, true); *h = cwal_hash_empty; } int cwal_rescope_children_hash( cwal_value * v ){ cwal_hash * h = CWAL_HASH(v); cwal_scope * sc = v->scope; assert(sc && h && v); assert(CWAL_V_IS_RESCOPING(v)); cwal_rescope_children_obase(v); /* cwal_dump_v(nv,"Re-scoping hashtable children..."); */ cwal_htable_rescope(sc, &h->htable); return 0; } cwal_value * cwal_new_hash_value( cwal_engine * e, cwal_size_t hashSize){ if(!e || !hashSize) return NULL; else { cwal_value * v = cwal_value_new(e, e->current, CWAL_TYPE_HASH, 0); |
︙ | ︙ | |||
20756 20757 20758 20759 20760 20761 20762 | } cwal_value * cwal_hash_value( cwal_hash * h ){ return CWAL_VALPART(h); } cwal_kvp * cwal_hash_search_kvp( cwal_hash * h, char const * key, | | | | 20856 20857 20858 20859 20860 20861 20862 20863 20864 20865 20866 20867 20868 20869 20870 20871 20872 20873 20874 20875 20876 | } cwal_value * cwal_hash_value( cwal_hash * h ){ return CWAL_VALPART(h); } cwal_kvp * cwal_hash_search_kvp( cwal_hash * h, char const * key, cwal_midsize_t keyLen ){ return cwal_htable_search_impl_cstr(&h->htable, key, keyLen, NULL, NULL); } cwal_value * cwal_hash_search( cwal_hash * h, char const * key, cwal_midsize_t keyLen ){ cwal_kvp const * const kvp = cwal_htable_search_impl_cstr(&h->htable, key, keyLen, NULL, NULL); return kvp ? kvp->value : 0; } cwal_value * cwal_hash_search_v( cwal_hash * h, cwal_value const * key ){ |
︙ | ︙ | |||
20795 20796 20797 20798 20799 20800 20801 | int cwal_hash_insert_v( cwal_hash * h, cwal_value * key, cwal_value * v, bool allowOverwrite ){ return cwal_hash_insert_with_flags_v(h, key, v, allowOverwrite, CWAL_VAR_F_PRESERVE); } | | | | | | < < | > > | < < < | | | | 20895 20896 20897 20898 20899 20900 20901 20902 20903 20904 20905 20906 20907 20908 20909 20910 20911 20912 20913 20914 20915 20916 20917 20918 20919 20920 20921 20922 20923 20924 20925 20926 20927 20928 20929 20930 20931 20932 20933 20934 20935 20936 20937 20938 20939 20940 20941 20942 20943 20944 20945 20946 20947 20948 20949 20950 20951 | int cwal_hash_insert_v( cwal_hash * h, cwal_value * key, cwal_value * v, bool allowOverwrite ){ return cwal_hash_insert_with_flags_v(h, key, v, allowOverwrite, CWAL_VAR_F_PRESERVE); } int cwal_hash_insert_with_flags( cwal_hash * h, char const * key, cwal_midsize_t keyLen, cwal_value * v, bool allowOverwrite, cwal_flags16_t kvpFlags ){ cwal_value * const hv = CWAL_VALPART(h); cwal_engine * const e = hv->scope->e; cwal_value * const vKey = cwal_new_string_value(e, key, keyLen); if(!vKey) return CWAL_RC_OOM; int rc; cwal_value_ref(vKey); rc = cwal_hash_insert_with_flags_v(h, vKey, v, allowOverwrite, kvpFlags); cwal_value_unref(vKey); return rc; } int cwal_hash_insert( cwal_hash * h, char const * key, cwal_midsize_t keyLen, cwal_value * v, bool allowOverwrite ){ return cwal_hash_insert_with_flags( h, key, keyLen, v, allowOverwrite, CWAL_VAR_F_PRESERVE ); } int cwal_hash_remove_v( cwal_hash * h, cwal_value * key ){ cwal_value * const vSelf = CWAL_VALPART(h); if(!h || !vSelf || !key) return CWAL_RC_MISUSE; else if(CWAL_RCFLAG_HAS(vSelf,CWAL_RCF_IS_DESTRUCTING)) return CWAL_RC_DESTRUCTION_RUNNING; //else if(CWAL_CONTAINER_DISALLOW_PROP_SET & h->base.flags) return CWAL_RC_DISALLOW_PROP_SET; else if(CWAL_V_IS_VISITING_LIST(vSelf)) return CWAL_RC_IS_VISITING_LIST; return cwal_htable_remove_impl_v(vSelf, &h->htable, key); } int cwal_hash_remove( cwal_hash * h, char const * key, cwal_midsize_t keyLen ){ cwal_value * const vSelf = CWAL_VALPART(h); if(!h || !vSelf || !key) return CWAL_RC_MISUSE; else if(CWAL_RCFLAG_HAS(vSelf,CWAL_RCF_IS_DESTRUCTING)) return CWAL_RC_DESTRUCTION_RUNNING; //else if(CWAL_CONTAINER_DISALLOW_PROP_SET & h->base.flags) return CWAL_RC_DISALLOW_PROP_SET; else if(CWAL_V_IS_VISITING_LIST(vSelf)) return CWAL_RC_IS_VISITING_LIST; return cwal_htable_remove_impl_cstr(vSelf, &h->htable, key, keyLen); } cwal_midsize_t cwal_hash_entry_count(cwal_hash const *h){ return h->htable.list.count; } cwal_midsize_t cwal_hash_size( cwal_hash const * h ){ return h->htable.hashSize; } int cwal_hash_visit_kvp( cwal_hash * h, cwal_kvp_visitor_f f, void * state ){ cwal_value * const hv = (h && f) ? CWAL_VALPART(h) : NULL; if(!hv || !f) return CWAL_RC_MISUSE; else { |
︙ | ︙ | |||
20922 20923 20924 20925 20926 20927 20928 | cwal_value * const hv = CWAL_VALPART(h); if(!h || !hv) return CWAL_RC_MISUSE; else if(CWAL_V_IS_VISITING_LIST(hv)) return CWAL_RC_IS_VISITING_LIST; /* highly arguable: newSize = cwal_trim_hash_size( newSize ); */ return cwal_htable_resize(hv, &h->htable, newSize); } | < < < < < < < | | 21019 21020 21021 21022 21023 21024 21025 21026 21027 21028 21029 21030 21031 21032 21033 | cwal_value * const hv = CWAL_VALPART(h); if(!h || !hv) return CWAL_RC_MISUSE; else if(CWAL_V_IS_VISITING_LIST(hv)) return CWAL_RC_IS_VISITING_LIST; /* highly arguable: newSize = cwal_trim_hash_size( newSize ); */ return cwal_htable_resize(hv, &h->htable, newSize); } cwal_midsize_t cwal_next_prime( cwal_midsize_t n ){ #if 1 int const * p = cwal_first_1000_primes(); int const last = 999; int i = 0; if((int)n >= p[last]) return (cwal_hash_t)p[last]; for( ; i < last; ++i){ if(p[i] > (int)n) return (cwal_hash_t)p[i]; |
︙ | ︙ | |||
20974 20975 20976 20977 20978 20979 20980 | int cwal_hash_grow_if_loaded( cwal_hash * h, double load ){ cwal_value * const hv = CWAL_VALPART(h); if(CWAL_V_IS_VISITING_LIST(hv)) return CWAL_RC_IS_VISITING_LIST; return cwal_htable_grow_if_loaded(hv, &h->htable, load); } | < > > > > > | 21064 21065 21066 21067 21068 21069 21070 21071 21072 21073 21074 21075 21076 21077 21078 21079 21080 21081 21082 21083 21084 | int cwal_hash_grow_if_loaded( cwal_hash * h, double load ){ cwal_value * const hv = CWAL_VALPART(h); if(CWAL_V_IS_VISITING_LIST(hv)) return CWAL_RC_IS_VISITING_LIST; return cwal_htable_grow_if_loaded(hv, &h->htable, load); } int cwal_hash_take_props( cwal_hash * h, cwal_value * src, int overwritePolicy ){ #if CWAL_OBASE_ISA_HASH (void)overwritePolicy; (void)h; (void)src; //assert(!"FIXME: cwal_hash_take_props() has to be reimpl'd for this case!"); return CWAL_RC_UNSUPPORTED; #else cwal_obase * srcBase; cwal_value * const hv = CWAL_VALPART(h); if(!src || !h || !hv) return CWAL_RC_MISUSE; else if(CWAL_V_IS_VISITING_LIST(hv)) return CWAL_RC_IS_VISITING_LIST; else if(CWAL_V_IS_VISITING(src)) return CWAL_RC_IS_VISITING; else if(!(srcBase = CWAL_VOBASE(src))) return CWAL_RC_TYPE; else{ |
︙ | ︙ | |||
21064 21065 21066 21067 21068 21069 21070 21071 21072 21073 21074 21075 21076 21077 | assert(CWAL_REFCOUNT(toKeepTail->value) || CWAL_MEM_IS_BUILTIN(toKeepTail->value)); toKeepTail->right = srcBase->kvp; srcBase->kvp = keepThese; } /* nope cwal_value_set_visiting_list(hv, 0); */ return rc; } } void cwal_value_cleanup_native( cwal_engine * e, void * V ){ cwal_value * v = (cwal_value *)V; cwal_native * n = v ? CWAL_V2NATIVE(v) : 0; assert(v && n); | > | 21158 21159 21160 21161 21162 21163 21164 21165 21166 21167 21168 21169 21170 21171 21172 | assert(CWAL_REFCOUNT(toKeepTail->value) || CWAL_MEM_IS_BUILTIN(toKeepTail->value)); toKeepTail->right = srcBase->kvp; srcBase->kvp = keepThese; } /* nope cwal_value_set_visiting_list(hv, 0); */ return rc; } #endif } void cwal_value_cleanup_native( cwal_engine * e, void * V ){ cwal_value * v = (cwal_value *)V; cwal_native * n = v ? CWAL_V2NATIVE(v) : 0; assert(v && n); |
︙ | ︙ | |||
21350 21351 21352 21353 21354 21355 21356 | arguments for the cwal_var_xxx() family of functions. */ #define SETUP_VAR_E_S if(!e) e=s?s->e:0; if(!s)s=e?e->current:0; \ if(!s && !e) return CWAL_RC_MISUSE static int cwal_var_set_v_impl( cwal_engine * e, cwal_scope * s, cwal_value * key, cwal_value * v, | | | < < < | 21445 21446 21447 21448 21449 21450 21451 21452 21453 21454 21455 21456 21457 21458 21459 21460 21461 21462 21463 21464 21465 21466 | arguments for the cwal_var_xxx() family of functions. */ #define SETUP_VAR_E_S if(!e) e=s?s->e:0; if(!s)s=e?e->current:0; \ if(!s && !e) return CWAL_RC_MISUSE static int cwal_var_set_v_impl( cwal_engine * e, cwal_scope * s, cwal_value * key, cwal_value * v, bool searchParents, uint16_t flags ){ if(!e || !key) return CWAL_RC_MISUSE; SETUP_VAR_E_S; else{ /* We need to take parent scopes into account when assigning a variable. This causes duplicate lookup of the var via cwal_kvp_set_v() (which also has to search). */ cwal_scope * foundIn = 0; int rc = 0; /* cwal_value * got = 0; */ cwal_scope * origin = s; cwal_hash * h; cwal_kvp * kvp = 0; |
︙ | ︙ | |||
21385 21386 21387 21388 21389 21390 21391 21392 21393 21394 21395 21396 21397 21398 21399 21400 21401 21402 21403 21404 21405 21406 21407 21408 21409 21410 21411 21412 21413 21414 21415 21416 21417 | if(kvp){ MARKER(("var set v impl kvp flags=0x%04x, new flags=0x%04x\n", (int)kvp->flags, flags)); dump_val(kvp->key,"key"); dump_val(kvp->value,"val"); } #endif if(kvp){ /*MARKER(("kvp found. flags=0x%04d\n", (int)kvp->flags));*/ /* dump_val(kvp->key,"key"); */ assert(s == foundIn); assert(foundIn->props); if(CWAL_VAR_F_CONST & kvp->flags){ return CWAL_RC_CONST_VIOLATION; } else if(v){ rc = cwal_kvp_value_set2(kvp, v); if(!rc) cwal_value_rescope(foundIn, v); return rc; } } if(!foundIn){ if(!v) return CWAL_RC_NOT_FOUND; foundIn = origin; } if(!foundIn->props){ rc = cwal_scope_init_props(foundIn); }else if(CWAL_V_IS_VISITING(foundIn->props)){ rc = CWAL_RC_IS_VISITING; }else if(CWAL_HASH(foundIn->props) && CWAL_V_IS_VISITING_LIST(foundIn->props)){ rc = CWAL_RC_IS_VISITING_LIST; } | > > > > > > > > | < | < > | | | > > > | > > > > > | < > > > | 21477 21478 21479 21480 21481 21482 21483 21484 21485 21486 21487 21488 21489 21490 21491 21492 21493 21494 21495 21496 21497 21498 21499 21500 21501 21502 21503 21504 21505 21506 21507 21508 21509 21510 21511 21512 21513 21514 21515 21516 21517 21518 21519 21520 21521 21522 21523 21524 21525 21526 21527 21528 21529 21530 21531 21532 21533 21534 21535 21536 21537 21538 21539 21540 21541 21542 21543 21544 21545 21546 21547 21548 21549 21550 21551 21552 21553 21554 21555 21556 21557 21558 21559 21560 21561 21562 21563 21564 | if(kvp){ MARKER(("var set v impl kvp flags=0x%04x, new flags=0x%04x\n", (int)kvp->flags, flags)); dump_val(kvp->key,"key"); dump_val(kvp->value,"val"); } #endif if(kvp){ /* Found a match. */ /*MARKER(("kvp found. flags=0x%04d\n", (int)kvp->flags));*/ /* dump_val(kvp->key,"key"); */ assert(s == foundIn); assert(foundIn->props); if(CWAL_VAR_F_CONST & kvp->flags){ return CWAL_RC_CONST_VIOLATION; } else if(v){ rc = cwal_kvp_value_set2(kvp, v); if(!rc) cwal_value_rescope(foundIn, v); return rc; } } /* Below here, we did not find a match, so we need to insert one, OR we found a match but are about to do an UNSET. FIXME (2021-07-110: This is currently less efficient than it could be. We now have enough infrastructure to be able to do this without a second property lookup imposed by the upcoming set/unset operations. */ if(!foundIn){ if(!v) return CWAL_RC_NOT_FOUND; foundIn = origin; } if(!foundIn->props){ rc = cwal_scope_init_props(foundIn); }else if(CWAL_V_IS_VISITING(foundIn->props)){ rc = CWAL_RC_IS_VISITING; }else if(CWAL_HASH(foundIn->props) && CWAL_V_IS_VISITING_LIST(foundIn->props)){ rc = CWAL_RC_IS_VISITING_LIST; } if(rc) return rc; assert(foundIn && foundIn->props); #if 0 MARKER(("Setting [opaque key type] in scope#%d via scope#%d.\n", (int)foundIn->level, (int)origin->level)); #endif if((h = CWAL_HASH(foundIn->props))){ #if 0 dump_val(key,"setting this key in hash"); dump_val(foundIn->props,"in this container"); MARKER(("var set v impl new kvp flags=0x%04x\n", flags)); if(kvp){ MARKER(("var set v impl kvp flags=0x%04x, new flags=0x%04x\n", (int)kvp->flags, flags)); dump_val(kvp->key,"key"); dump_val(kvp->value,"val"); } #endif rc = v ? cwal_hash_insert_with_flags_v( h, key, v, 1, flags ) : cwal_hash_remove_v(h, key); //if(v && !rc) rc = cwal_scope_adjust_prop_size(foundIn); }else{ /* Object-type scope properties... */ cwal_obase * const b = CWAL_VOBASE(foundIn->props); assert(b); assert(foundIn->props); #if CWAL_OBASE_ISA_HASH rc = v ? cwal_htable_insert_impl_v(foundIn->props, &b->hprops, key, v, true, flags) : cwal_htable_remove_impl_v(foundIn->props, &b->hprops, key); #else rc = v ? cwal_kvp_set_v( e, foundIn->props, key, v, flags ) : cwal_kvp_unset_v( e, &b->kvp, key ); #endif } return rc; } } static int cwal_kvp_visitor_scope_import_props( cwal_kvp const * kvp, void * state ){ cwal_scope * dest = (cwal_scope*)state; return cwal_var_set_v_impl( dest->e, dest, kvp->key, kvp->value, 0, kvp->flags ); |
︙ | ︙ | |||
21506 21507 21508 21509 21510 21511 21512 | assert(s->level); upToDepth = (int)(s->level-1); } for( os = s; os && (upToDepth>=0); --upToDepth ){ cwal_hash * const h = CWAL_HASH(os->props); | < | < | < | 21615 21616 21617 21618 21619 21620 21621 21622 21623 21624 21625 21626 21627 21628 21629 21630 | assert(s->level); upToDepth = (int)(s->level-1); } for( os = s; os && (upToDepth>=0); --upToDepth ){ cwal_hash * const h = CWAL_HASH(os->props); if(h) kvp = cwal_hash_search_kvp_v(h, key); else if(os->props) kvp = cwal_prop_get_kvp_v( os->props, key, 0, NULL ); if(kvp){ if(foundIn) *foundIn = os; break; } else os = os->parent; } #if 0 |
︙ | ︙ | |||
21538 21539 21540 21541 21542 21543 21544 | cwal_kvp * kvp = cwal_scope_search_kvp_v(s, upToDepth, key, foundIn); return kvp ? kvp->value : NULL; } cwal_kvp * cwal_scope_search_kvp( cwal_scope * s, int upToDepth, char const * key, | | | 21644 21645 21646 21647 21648 21649 21650 21651 21652 21653 21654 21655 21656 21657 21658 | cwal_kvp * kvp = cwal_scope_search_kvp_v(s, upToDepth, key, foundIn); return kvp ? kvp->value : NULL; } cwal_kvp * cwal_scope_search_kvp( cwal_scope * s, int upToDepth, char const * key, cwal_midsize_t keyLen, cwal_scope ** foundIn ){ if(!s || !key) return NULL; else if(!s->props && !upToDepth) return NULL; else { cwal_scope * os; cwal_kvp * kvp = 0; if( upToDepth<0 ){ |
︙ | ︙ | |||
21570 21571 21572 21573 21574 21575 21576 | } return kvp; } } cwal_value * cwal_scope_search( cwal_scope * s, int upToDepth, char const * key, | | | 21676 21677 21678 21679 21680 21681 21682 21683 21684 21685 21686 21687 21688 21689 21690 | } return kvp; } } cwal_value * cwal_scope_search( cwal_scope * s, int upToDepth, char const * key, cwal_midsize_t keyLen, cwal_scope ** foundIn ){ cwal_kvp * kvp = cwal_scope_search_kvp(s, upToDepth, key, keyLen, foundIn); return kvp ? kvp->value : NULL; } int cwal_scope_chain_set_with_flags_v( cwal_scope * s, int upToDepth, |
︙ | ︙ | |||
21646 21647 21648 21649 21650 21651 21652 | int cwal_scope_chain_set_v( cwal_scope * s, int upToDepth, cwal_value * k, cwal_value * v ){ return cwal_scope_chain_set_with_flags_v(s, upToDepth, k, v, CWAL_VAR_F_PRESERVE); } int cwal_scope_chain_set_with_flags( cwal_scope * s, int upToDepth, | | | | 21752 21753 21754 21755 21756 21757 21758 21759 21760 21761 21762 21763 21764 21765 21766 21767 21768 21769 21770 21771 21772 21773 21774 21775 21776 21777 21778 21779 21780 21781 | int cwal_scope_chain_set_v( cwal_scope * s, int upToDepth, cwal_value * k, cwal_value * v ){ return cwal_scope_chain_set_with_flags_v(s, upToDepth, k, v, CWAL_VAR_F_PRESERVE); } int cwal_scope_chain_set_with_flags( cwal_scope * s, int upToDepth, char const * k, cwal_midsize_t keyLen, cwal_value * v, uint16_t flags ){ if(!s || !k) return CWAL_RC_MISUSE; else { int rc; cwal_value * kv = cwal_new_string_value(s->e, k, keyLen); if(!v) return CWAL_RC_OOM; cwal_value_ref(kv); rc = cwal_scope_chain_set_with_flags_v( s, upToDepth, kv, v, flags ); cwal_value_unref(kv); return rc; } } int cwal_scope_chain_set( cwal_scope * s, int upToDepth, char const * k, cwal_midsize_t keyLen, cwal_value * v ){ return cwal_scope_chain_set_with_flags( s, upToDepth, k, keyLen, v, CWAL_VAR_F_PRESERVE ); } int cwal_var_decl_v( cwal_engine * e, cwal_scope * s, cwal_value * key, cwal_value * v, |
︙ | ︙ | |||
21687 21688 21689 21690 21691 21692 21693 | : cwal_var_set_v_impl( e, s, key, v ? v : cwal_value_undefined(), 0, flags)); } } int cwal_var_decl( cwal_engine * e, cwal_scope * s, char const * key, | | | 21793 21794 21795 21796 21797 21798 21799 21800 21801 21802 21803 21804 21805 21806 21807 | : cwal_var_set_v_impl( e, s, key, v ? v : cwal_value_undefined(), 0, flags)); } } int cwal_var_decl( cwal_engine * e, cwal_scope * s, char const * key, cwal_midsize_t keyLen, cwal_value * v, uint16_t flags ){ if(!e || !key || !*key) return CWAL_RC_MISUSE; SETUP_VAR_E_S; else { int rc; cwal_value * k = cwal_new_string_value(e, key, keyLen); if(!k) return CWAL_RC_OOM; cwal_value_ref(k); |
︙ | ︙ | |||
22944 22945 22946 22947 22948 22949 22950 | FILE * f = (FILE*)filePtr; if(f && (f!=stdout) && (f!=stderr) && (f!=stdin)){ fclose(f); } } #if CWAL_ENABLE_TRACE | | | 23050 23051 23052 23053 23054 23055 23056 23057 23058 23059 23060 23061 23062 23063 23064 | FILE * f = (FILE*)filePtr; if(f && (f!=stdout) && (f!=stderr) && (f!=stdin)){ fclose(f); } } #if CWAL_ENABLE_TRACE static char const * cwal_tr_cstr( cwal_trace_flags_e ev ){ switch(ev){ #define CASE(X) case CWAL_TRACE_##X: return #X CASE(NONE); CASE(ALL); CASE(GROUP_MASK); |
︙ | ︙ | |||
23035 23036 23037 23038 23039 23040 23041 | b->list.count ); #endif } if( cwal_value_is_string(v) ){ const cwal_size_t truncLen = 16; cwal_string const * s = cwal_value_get_string(v); if(s && CWAL_STRLEN(s)){ | | | 23141 23142 23143 23144 23145 23146 23147 23148 23149 23150 23151 23152 23153 23154 23155 | b->list.count ); #endif } if( cwal_value_is_string(v) ){ const cwal_size_t truncLen = 16; cwal_string const * s = cwal_value_get_string(v); if(s && CWAL_STRLEN(s)){ fprintf( f, " strlen=%"CWAL_MIDSIZE_T_PFMT, CWAL_STRLEN(s) ); if( CWAL_STRLEN(s) <= truncLen ){ fprintf( f, " bytes=[%s]", cwal_string_cstr(s) ); }else{ fprintf( f, " bytes=[%.*s...] (truncated)", (int)truncLen, cwal_string_cstr(s) ); /*fprintf( f, " bytes=[%s]", cwal_string_cstr(s) );*/ } }else{ |
︙ | ︙ | |||
23856 23857 23858 23859 23860 23861 23862 | int cwal_callback_hook_set(cwal_engine * e, cwal_callback_hook const * h ){ if(!e) return CWAL_RC_MISUSE; e->cbHook = h ? *h : cwal_callback_hook_empty; return 0; } | | | | 23962 23963 23964 23965 23966 23967 23968 23969 23970 23971 23972 23973 23974 23975 23976 23977 | int cwal_callback_hook_set(cwal_engine * e, cwal_callback_hook const * h ){ if(!e) return CWAL_RC_MISUSE; e->cbHook = h ? *h : cwal_callback_hook_empty; return 0; } cwal_midsize_t cwal_strlen( char const * str ){ return str ? (cwal_midsize_t)strlen(str) : 0U; } bool cwal_value_is_vacuum_proof( cwal_value const * v ){ return v->scope ? CWAL_V_IS_VACUUM_SAFE(v) : CWAL_MEM_IS_BUILTIN(v); } |
︙ | ︙ | |||
24375 24376 24377 24378 24379 24380 24381 | #endif } } void cwal_visit_props_end( cwal_value * const v, int opaque ){ #if CWAL_OBASE_ISA_HASH cwal_obase * const ob = CWAL_VOBASE(v); | | < | < > | 24481 24482 24483 24484 24485 24486 24487 24488 24489 24490 24491 24492 24493 24494 24495 24496 24497 24498 24499 24500 24501 24502 24503 24504 24505 | #endif } } void cwal_visit_props_end( cwal_value * const v, int opaque ){ #if CWAL_OBASE_ISA_HASH cwal_obase * const ob = CWAL_VOBASE(v); assert(ob->hprops.list.isVisiting && "Else internal API misuse."); #elif defined(DEBUG) assert(CWAL_VOBASE(v) && "Invalid use of cwal_visit_props_end()"); #endif assert(v); assert(visitOpaqueMarkerYes==opaque || visitOpaqueMarkerNo==opaque); if(visitOpaqueMarkerYes==opaque){ #if CWAL_OBASE_ISA_HASH ob->hprops.list.isVisiting = false; #endif CWAL_RCFLAG_OFF(v,CWAL_RCF_IS_VISITING); } } void cwal_visit_list_begin( cwal_value * const v, int * const opaque ){ cwal_hash * const h = CWAL_HASH(v); cwal_array * const a = h ? NULL : CWAL_ARRAY(v); assert(v); |
︙ | ︙ | |||
24681 24682 24683 24684 24685 24686 24687 | cwal_kvp const * cwal_obase_kvp_iter_next( cwal_obase_kvp_iter * const oks ){ assert(CWAL_V_IS_VISITING(oks->v) || CWAL_V_IS_VISITING_LIST(oks->v) || CWAL_V_IS_RESCOPING(oks->v)); #if CWAL_OBASE_ISA_HASH //assert(CWAL_V_IS_VISITING(CWAL_VALPART(oks->base))); | | | | 24786 24787 24788 24789 24790 24791 24792 24793 24794 24795 24796 24797 24798 24799 24800 24801 24802 24803 24804 24805 24806 | cwal_kvp const * cwal_obase_kvp_iter_next( cwal_obase_kvp_iter * const oks ){ assert(CWAL_V_IS_VISITING(oks->v) || CWAL_V_IS_VISITING_LIST(oks->v) || CWAL_V_IS_RESCOPING(oks->v)); #if CWAL_OBASE_ISA_HASH //assert(CWAL_V_IS_VISITING(CWAL_VALPART(oks->base))); assert(oks->base->hprops.list.isVisiting); if(oks->ndx>=oks->base->hprops.hashSize){ return NULL; }else if(oks->current && oks->current->right){ return oks->current = oks->current->right; } for(cwal_midsize_t i = oks->ndx; i < oks->base->hprops.hashSize; ++i){ if(oks->li->list[i]){ oks->current = (cwal_kvp const *)oks->li->list[i]; oks->ndx = i+1; return oks->current; } } oks->ndx = oks->base->hprops.hashSize; |
︙ | ︙ | |||
28735 28736 28737 28738 28739 28740 28741 | || (c&0xFFFFF800)==0xD800 || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } } return c; } | | | 28840 28841 28842 28843 28844 28845 28846 28847 28848 28849 28850 28851 28852 28853 28854 | || (c&0xFFFFF800)==0xD800 || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } } return c; } cwal_midsize_t cwal_strlen_utf8( char const * str, cwal_midsize_t len ){ if( !str || !len ) return 0; else{ char unsigned const * x = (char unsigned const *)str; char unsigned const * end = x + len; cwal_size_t rc = 0; /* profiling shows that cwal_utf8_read_char() is, by leaps and bounds, the most oft-called func in the whole s2 constellation. |
︙ | ︙ | |||
28897 28898 28899 28900 28901 28902 28903 | } } int cwal_string_case_fold( cwal_engine * e, cwal_string const * str, cwal_value **rv, | | | | 29002 29003 29004 29005 29006 29007 29008 29009 29010 29011 29012 29013 29014 29015 29016 29017 | } } int cwal_string_case_fold( cwal_engine * e, cwal_string const * str, cwal_value **rv, bool doUpper ){ cwal_midsize_t len = 0; char const * cs = cwal_string_cstr2(str, &len); if(!e) return CWAL_RC_MISUSE; else if(!len){ *rv = cwal_string_value(str); return 0; }else{ #if 0 |
︙ | ︙ | |||
28929 28930 28931 28932 28933 28934 28935 | else if(ch<=0x7FF) return 2; else if(ch<=0xffff) return 3; else return 4; } #endif int cwal_utf8_case_fold_to_buffer( cwal_engine * e, char const * cstr, | | | | 29034 29035 29036 29037 29038 29039 29040 29041 29042 29043 29044 29045 29046 29047 29048 29049 29050 | else if(ch<=0x7FF) return 2; else if(ch<=0xffff) return 3; else return 4; } #endif int cwal_utf8_case_fold_to_buffer( cwal_engine * e, char const * cstr, cwal_midsize_t len, cwal_buffer *buf, bool doUpper ){ int rc = 0; unsigned char const * cs = (unsigned char const *)cstr; unsigned char const * csEnd = cs+len; int ch; int clen; unsigned char cbuf[5] = {0,0,0,0,0}; if(!e || !cstr || !buf || |
︙ | ︙ | |||
28990 28991 28992 28993 28994 28995 28996 | if(!rc){ assert(0==buf->mem[buf->used] && "performed by/via cwal_buffer_append()"); } return rc; } int cwal_utf8_case_fold( cwal_engine * e, char const * cstr, | | | | 29095 29096 29097 29098 29099 29100 29101 29102 29103 29104 29105 29106 29107 29108 29109 29110 29111 | if(!rc){ assert(0==buf->mem[buf->used] && "performed by/via cwal_buffer_append()"); } return rc; } int cwal_utf8_case_fold( cwal_engine * e, char const * cstr, cwal_midsize_t len, cwal_value **rv, bool doUpper ){ cwal_buffer buf = cwal_buffer_empty; int rc = 0; if(!e || !cstr || !rv) return CWAL_RC_MISUSE; else if(!len){ *rv = cwal_new_string_value(e, "", 0) /* does not allocate */; return 0; } |
︙ | ︙ | |||
34560 34561 34562 34563 34564 34565 34566 | TODO: negative values to count from the end, but then we'll also need to go patch string.charAt() for that. */ cwal_value * s2_charat_by_index( s2_engine *se, cwal_string const * str, cwal_int_t n ){ | | | 34665 34666 34667 34668 34669 34670 34671 34672 34673 34674 34675 34676 34677 34678 34679 | TODO: negative values to count from the end, but then we'll also need to go patch string.charAt() for that. */ cwal_value * s2_charat_by_index( s2_engine *se, cwal_string const * str, cwal_int_t n ){ cwal_midsize_t slen = 0; unsigned char const * cstr = (unsigned char const * )cwal_string_cstr2(str, &slen); unsigned int cp = 0; assert(cstr); if(n < 0 || (cwal_size_t)n >= cwal_string_length_bytes(str)){ return cwal_value_undefined(); }else if(cwal_string_is_ascii(str)){ |
︙ | ︙ | |||
48219 48220 48221 48222 48223 48224 48225 | because that approach has to (for non-ASCII strings) re-traverse the whole string to find the i'th character. Returns 0 on success. */ static int s2_foreach_string_char( cwal_value * vStr, s2_foreach_state * fst ){ int rc = 0; | | | 48324 48325 48326 48327 48328 48329 48330 48331 48332 48333 48334 48335 48336 48337 48338 | because that approach has to (for non-ASCII strings) re-traverse the whole string to find the i'th character. Returns 0 on success. */ static int s2_foreach_string_char( cwal_value * vStr, s2_foreach_state * fst ){ int rc = 0; cwal_midsize_t slen = 0; cwal_string * str = cwal_value_get_string(vStr); char unsigned const * cstr = (char unsigned const *)cwal_string_cstr2( str, &slen ); char unsigned const * pos = cstr; char const isAscii = cwal_string_is_ascii(str); cwal_engine * const e = fst->se->e; cwal_value * vIndex = 0; cwal_value * vVal = 0; |
︙ | ︙ | |||
49665 49666 49667 49668 49669 49670 49671 | qsort( uk->list, uk->count, sizeof(s2_keyword), cmp_ukwd_kw ); cwal_hash_grow_if_loaded(uk->h, 0.7)/*ignore error - not fatal*/; return 0; } } int s2_define_ukwd(s2_engine * se, char const * name, | | | > > > > | 49770 49771 49772 49773 49774 49775 49776 49777 49778 49779 49780 49781 49782 49783 49784 49785 49786 49787 49788 49789 49790 | qsort( uk->list, uk->count, sizeof(s2_keyword), cmp_ukwd_kw ); cwal_hash_grow_if_loaded(uk->h, 0.7)/*ignore error - not fatal*/; return 0; } } int s2_define_ukwd(s2_engine * se, char const * name, cwal_int_t nameLen, cwal_value * v){ int rc; cwal_value * const k = cwal_new_string_value(se->e, name, nameLen>0 ? (cwal_midsize_t)nameLen : cwal_strlen(name)); if(k){ cwal_value_ref(k); rc = s2_define_ukwd_v(se, k, v); cwal_value_unref(k); }else{ rc = s2_engine_err_set(se, CWAL_RC_OOM, 0); } |
︙ | ︙ | |||
57000 57001 57002 57003 57004 57005 57006 | ? (unsigned char const *)cwal_value_get_cstr(args->argv[0], &sepLen) : NULL; if(!sep){ return s2_throw( se, CWAL_RC_MISUSE, "Expecting a non-empty string argument."); }else if(!sepLen){ /* Split into individual characters */ | | | | 57109 57110 57111 57112 57113 57114 57115 57116 57117 57118 57119 57120 57121 57122 57123 57124 57125 57126 57127 57128 57129 57130 57131 57132 57133 57134 57135 57136 57137 | ? (unsigned char const *)cwal_value_get_cstr(args->argv[0], &sepLen) : NULL; if(!sep){ return s2_throw( se, CWAL_RC_MISUSE, "Expecting a non-empty string argument."); }else if(!sepLen){ /* Split into individual characters */ cwal_midsize_t slen = 0; unsigned char const * pos = (unsigned char const *)cwal_string_cstr2(self, &slen); cwal_int_t limit; assert(pos); limit = (args->argc>1) ? cwal_value_get_integer(args->argv[1]) : 0; return s2_cb_str_split_chars(args, rv, pos, slen, limit); }else{ int rc = 0; cwal_int_t count = 0; cwal_int_t limit; cwal_array * ar = NULL; cwal_midsize_t slen = 0; unsigned char const * pos = (unsigned char const *)cwal_string_cstr2(self, &slen); unsigned char const * eof = pos + slen; unsigned char const * start = pos; cwal_value * v; limit = (args->argc>1) ? cwal_value_get_integer(args->argv[1]) |
︙ | ︙ | |||
57112 57113 57114 57115 57116 57117 57118 | "Expecting a non-empty string argument."); }else if(!needleLen){ *rv = args->self; return 0; }else{ int rc = 0; cwal_int_t matchCount = 0; | | | 57221 57222 57223 57224 57225 57226 57227 57228 57229 57230 57231 57232 57233 57234 57235 | "Expecting a non-empty string argument."); }else if(!needleLen){ *rv = args->self; return 0; }else{ int rc = 0; cwal_int_t matchCount = 0; cwal_midsize_t slen = 0; unsigned char const * pos = (unsigned char const *)cwal_string_cstr2(self, &slen); unsigned char const * eof = pos + slen; unsigned char const * start = pos; cwal_buffer * buf = &se->buffer; cwal_size_t const oldUsed = buf->used; cwal_int_t const limit = args->argc>2 |
︙ | ︙ | |||
57204 57205 57206 57207 57208 57209 57210 | arg = cwal_value_get_cstr(args->argv[0], &aLen); if(!arg) goto misuse; else if(!aLen){ *rv = cwal_new_integer(args->engine, -1); return 0; } else{ | | | 57313 57314 57315 57316 57317 57318 57319 57320 57321 57322 57323 57324 57325 57326 57327 | arg = cwal_value_get_cstr(args->argv[0], &aLen); if(!arg) goto misuse; else if(!aLen){ *rv = cwal_new_integer(args->engine, -1); return 0; } else{ cwal_midsize_t sLen = 0; char const * myStr = cwal_string_cstr2(self, &sLen); cwal_int_t i = 0; cwal_int_t offset; if(aLen>sLen){ *rv = cwal_new_integer(args->engine, -1); return 0; } |
︙ | ︙ | |||
61626 61627 61628 61629 61630 61631 61632 61633 61634 61635 61636 61637 61638 61639 | *rv = cwal_new_integer(args->engine, it); } return *rv ? 0 : CWAL_RC_OOM; } int s2_cb_mstime( cwal_callback_args const * args, cwal_value **rv ){ #if !S2_ENABLE_CLOCK_GETTIME return cwal_exception_setf(args->engine, CWAL_RC_UNSUPPORTED, "mstime() is not implemented in this build."); #else /* Per https://upvoid.com/devblog/2014/05/linux-timers/ CLOCK_REALTIME_COARSE has a resolution of within 1ms, which is fine for what we're doing. | > | 61735 61736 61737 61738 61739 61740 61741 61742 61743 61744 61745 61746 61747 61748 61749 | *rv = cwal_new_integer(args->engine, it); } return *rv ? 0 : CWAL_RC_OOM; } int s2_cb_mstime( cwal_callback_args const * args, cwal_value **rv ){ #if !S2_ENABLE_CLOCK_GETTIME (void)rv; return cwal_exception_setf(args->engine, CWAL_RC_UNSUPPORTED, "mstime() is not implemented in this build."); #else /* Per https://upvoid.com/devblog/2014/05/linux-timers/ CLOCK_REALTIME_COARSE has a resolution of within 1ms, which is fine for what we're doing. |
︙ | ︙ |
Changes to bindings/s2/s2_amalgamation.h.
︙ | ︙ | |||
18 19 20 21 22 23 24 | # define _DEFAULT_SOURCE # endif #endif /* start of file /home/stephan/fossil/cwal/cwal_amalgamation.h */ #if !defined(WANDERINGHORSE_NET_CWAL_AMALGAMATION_H_INCLUDED) #define WANDERINGHORSE_NET_CWAL_AMALGAMATION_H_INCLUDED #if !defined(CWAL_VERSION_STRING) | | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | # define _DEFAULT_SOURCE # endif #endif /* start of file /home/stephan/fossil/cwal/cwal_amalgamation.h */ #if !defined(WANDERINGHORSE_NET_CWAL_AMALGAMATION_H_INCLUDED) #define WANDERINGHORSE_NET_CWAL_AMALGAMATION_H_INCLUDED #if !defined(CWAL_VERSION_STRING) # define CWAL_VERSION_STRING "cwal e0d28b94d683305402278480902fff5a23b6b450 2021-07-11 18:27:06 built 2021-07-12 02:43" #endif #if defined(__cplusplus) && !defined(__STDC_FORMAT_MACROS) /* required for PRIi32 and friends.*/ # define __STDC_FORMAT_MACROS #endif #if !defined(CWAL_CPPFLAGS) # define CWAL_CPPFLAGS "-I/home/stephan/include -I. -I/home/stephan/fossil/cwal/include -I/home/stephan/include -DDEBUG=1" #endif #if !defined(CWAL_CFLAGS) # define CWAL_CFLAGS "-Werror -Wall -Wextra -Wsign-compare -fPIC -std=c99 -g -Wpedantic -O0" #endif #if !defined(CWAL_CXXFLAGS) # define CWAL_CXXFLAGS "-g -O2 -fPIC -O0" #endif /* start of file include/wh/cwal/cwal_config.h */ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=4 et sw=2 tw=80: */ |
︙ | ︙ | |||
404 405 406 407 408 409 410 | For cwal's intended purposes uint16_t is "almost certainly" fine, but those who are concerned about 64kb limitations on certain contexts might want to set this to uint32_t. */ | | | | > | < | | 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 | For cwal's intended purposes uint16_t is "almost certainly" fine, but those who are concerned about 64kb limitations on certain contexts might want to set this to uint32_t. */ /** typedef some_unsigned_int_type cwal_midsize_t A cwal_size_t counterpart which is intended to be capped at 32 bits and used in contexts for which 64 bits is simply a massive waste (e.g. arrays, strings, and hashtables). */ /** @typedef some_signed_integer cwal_int_t This is the type of integer value used by the library for its "script-visible" integers. */ /** @typedef some_unsigned_integer cwal_refcount_t This is the type of integer value used by the library to keep track of both reference counts and their embedded flags (which reduce the useful range of the reference count). */ /** @def CWAL_REFCOUNT_T_BITS @internal MUST be equal to (sizeof(cwal_refcount_t) * 8), but must be a constant usable by the preprocessor. */ /* Set up CWAL_SIZE_T... */ |
︙ | ︙ | |||
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 | # define CWAL_SIZE_T_PFMTX PRIX32 # define CWAL_SIZE_T_PFMTo PRIo32 # define CWAL_SIZE_T_SFMT SCNu32 # define CWAL_SIZE_T_SFMTX SCNx32 # define CWAL_SIZE_T_MAX 4294967295U typedef uint32_t cwal_size_t; typedef uint32_t cwal_refcount_t; #elif CWAL_SIZE_T_BITS == 64 # define CWAL_SIZE_T_PFMT PRIu64 # define CWAL_SIZE_T_PFMTx PRIx64 # define CWAL_SIZE_T_PFMTX PRIX64 # define CWAL_SIZE_T_PFMTo PRIo64 # define CWAL_SIZE_T_SFMT SCNu64 # define CWAL_SIZE_T_SFMTX SCNx64 # define CWAL_SIZE_T_MAX 18446744073709551615U typedef uint64_t cwal_size_t; typedef uint64_t cwal_refcount_t /*32 bits "should be" fine, but using 64 doesn't (because of padding) actually change the sizeof of cwal_value */; # define CWAL_REFCOUNT_T_BITS 64 #else # error "CWAL_SIZE_T_BITS must be one of: 16, 32, 64" #endif | > | | | | | | | | | | | | | | | | | | 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 | # define CWAL_SIZE_T_PFMTX PRIX32 # define CWAL_SIZE_T_PFMTo PRIo32 # define CWAL_SIZE_T_SFMT SCNu32 # define CWAL_SIZE_T_SFMTX SCNx32 # define CWAL_SIZE_T_MAX 4294967295U typedef uint32_t cwal_size_t; typedef uint32_t cwal_refcount_t; # define CWAL_REFCOUNT_T_BITS 32 #elif CWAL_SIZE_T_BITS == 64 # define CWAL_SIZE_T_PFMT PRIu64 # define CWAL_SIZE_T_PFMTx PRIx64 # define CWAL_SIZE_T_PFMTX PRIX64 # define CWAL_SIZE_T_PFMTo PRIo64 # define CWAL_SIZE_T_SFMT SCNu64 # define CWAL_SIZE_T_SFMTX SCNx64 # define CWAL_SIZE_T_MAX 18446744073709551615U typedef uint64_t cwal_size_t; typedef uint64_t cwal_refcount_t /*32 bits "should be" fine, but using 64 doesn't (because of padding) actually change the sizeof of cwal_value */; # define CWAL_REFCOUNT_T_BITS 64 #else # error "CWAL_SIZE_T_BITS must be one of: 16, 32, 64" #endif /* Set up CWAL_MIDSIZE_... */ #if CWAL_SIZE_T_BITS == 16 typedef uint16_t cwal_midsize_t; # define CWAL_MIDSIZE_T_PFMT CWAL_SIZE_T_PFMT # define CWAL_MIDSIZE_T_PFMTx CWAL_SIZE_T_PFMTx # define CWAL_MIDSIZE_T_PFMTX CWAL_SIZE_T_PFMTX # define CWAL_MIDSIZE_T_PFMTo CWAL_SIZE_T_PFMTo # define CWAL_MIDSIZE_T_SFMT CWAL_SIZE_T_SFMT # define CWAL_MIDSIZE_T_SFMTX CWAL_SIZE_T_SFMTX # define CWAL_MIDSIZE_T_MAX CWAL_SIZE_T_MAX #else typedef uint32_t cwal_midsize_t; # define CWAL_MIDSIZE_T_PFMT PRIu32 # define CWAL_MIDSIZE_T_PFMTx PRIx32 # define CWAL_MIDSIZE_T_PFMTX PRIX32 # define CWAL_MIDSIZE_T_PFMTo PRIo32 # define CWAL_MIDSIZE_T_SFMT SCNu32 # define CWAL_MIDSIZE_T_SFMTX SCNx32 # define CWAL_MIDSIZE_T_MAX 4294967295U #endif /* Set up CWAL_INT_... */ #if CWAL_INT_T_BITS == 16 # define CWAL_INT_T_PFMT PRIi16 # define CWAL_INT_T_PFMTx PRIx16 # define CWAL_INT_T_PFMTX PRIX16 |
︙ | ︙ | |||
630 631 632 633 634 635 636 | that it be left off unless needed. */ # define CWAL_ENABLE_TRACE 1 #endif #if !defined(CWAL_OBASE_ISA_HASH) | > | | > > | 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 | that it be left off unless needed. */ # define CWAL_ENABLE_TRACE 1 #endif #if !defined(CWAL_OBASE_ISA_HASH) /* Leave this off for the time being: it's an experimenal work in progress. If it's enabled then cwal_obase will use a hashtable, instead of a sorted list, for its property management. */ # define CWAL_OBASE_ISA_HASH 0 #endif #endif /* WANDERINGHORSE_NET_CWAL_CONFIG_H_INCLUDED */ /* end of file include/wh/cwal/cwal_config.h */ /* start of file include/wh/cwal/cwal.h */ |
︙ | ︙ | |||
1382 1383 1384 1385 1386 1387 1388 | By an unfortunate fluke of mis-design, entries which are themselves not group masks (groups are named xxxx_MASK) cannot be effecitvely mixed together via bitmasking. The end effect is that only the MASK, NONE, or ALL entries can be usefully/predictibly applied. i'll see about fixing that. */ | | | 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 | By an unfortunate fluke of mis-design, entries which are themselves not group masks (groups are named xxxx_MASK) cannot be effecitvely mixed together via bitmasking. The end effect is that only the MASK, NONE, or ALL entries can be usefully/predictibly applied. i'll see about fixing that. */ enum cwal_trace_flags_e { CWAL_TRACE_NONE = 0, CWAL_TRACE_GROUP_MASK = 0x7F000000, CWAL_TRACE_MEM_MASK = 0x01000000, CWAL_TRACE_MEM_MALLOC = CWAL_TRACE_MEM_MASK | (1 << 0), CWAL_TRACE_MEM_REALLOC = CWAL_TRACE_MEM_MASK | (1 << 1), |
︙ | ︙ | |||
1427 1428 1429 1430 1431 1432 1433 | CWAL_TRACE_FYI_MASK = 0x10000000, CWAL_TRACE_MESSAGE = CWAL_TRACE_FYI_MASK | (1<<1), CWAL_TRACE_ERROR_MASK = 0x20000000, CWAL_TRACE_ERROR = CWAL_TRACE_ERROR_MASK | (1<<0), /** | | | | | 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 | CWAL_TRACE_FYI_MASK = 0x10000000, CWAL_TRACE_MESSAGE = CWAL_TRACE_FYI_MASK | (1<<1), CWAL_TRACE_ERROR_MASK = 0x20000000, CWAL_TRACE_ERROR = CWAL_TRACE_ERROR_MASK | (1<<0), /** Contains all cwal_trace_flags_e values except CWAL_TRACE_NONE. */ CWAL_TRACE_ALL = 0x7FFFFFFF/*1..31*/ }; /** Convenience typedef. */ typedef enum cwal_trace_flags_e cwal_trace_flags_e; #if CWAL_ENABLE_TRACE typedef struct cwal_trace_state cwal_trace_state; /** State which gets passed to a cwal_engine_tracer_f() callback when cwal_engine tracing is enabled. */ struct cwal_trace_state { cwal_trace_flags_e event; int32_t mask; cwal_rc code_NYI; cwal_engine const * e; cwal_value const * value; cwal_scope const * scope; void const * memory; cwal_size_t memorySize; |
︙ | ︙ | |||
1547 1548 1549 1550 1551 1552 1553 | JavaScript/JSON-compatible types, plus some extensions. These are primarily in the public API to allow O(1) client-side dispatching based on cwal_value types, as opposed to using O(N) if/else if/else. Note that the integer values assigned here are not guaranteed to | | | | 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 | JavaScript/JSON-compatible types, plus some extensions. These are primarily in the public API to allow O(1) client-side dispatching based on cwal_value types, as opposed to using O(N) if/else if/else. Note that the integer values assigned here are not guaranteed to stay stable: they are intended only to assist human-level debug work in the cwal code. */ enum cwal_type_id { /** GCC likes to make enums unsigned at times, which breaks strict comparison of integers with enums. Soooo... */ CWAL_TYPE_FORCE_SIGNED_ENUM = -1, |
︙ | ︙ | |||
1677 1678 1679 1680 1681 1682 1683 | /** Convenience typedef. */ typedef struct cwal_function cwal_function; /** @struct cwal_callback_args | | | | | | | | 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 | /** Convenience typedef. */ typedef struct cwal_function cwal_function; /** @struct cwal_callback_args A type holding arguments generated from "script" code which call()s a Function value. Instances of this type are created only by the cwal_function_call() family of functions, never by client code. The populated state is, via cwal_function_call() and friends, passed to the cwal_callback_f() implementation which is wrapped by the call()'d Function. */ struct cwal_callback_args{ /** The engine object making the call. */ cwal_engine * engine; /** |
︙ | ︙ | |||
1765 1766 1767 1768 1769 1770 1771 | Callback function interface for cwal "script" functions. args contains various state information related to the call. The callback returns a value to the framework by assigning *rv to it (assigning it to NULL is equivalent to assigning it to cwal_value_undefined()). Implementations can rely on rv being non-NULL but must not rely on any previous contents of *rv. In practice, callbacks are passed a pointer to an initially-NULL | | | | > > > < < < | 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 | Callback function interface for cwal "script" functions. args contains various state information related to the call. The callback returns a value to the framework by assigning *rv to it (assigning it to NULL is equivalent to assigning it to cwal_value_undefined()). Implementations can rely on rv being non-NULL but must not rely on any previous contents of *rv. In practice, callbacks are passed a pointer to an initially-NULL value, and callback implementations will, on success, set *rv to the result value. Callbacks must return 0 on success, CWAL_RC_EXCEPTION if they set the cwal exception state, or (preferably) one of the other relevant CWAL_RC values on a genuine error. Practice strongly suggests that implementations should assign a new value to *rv only if they "succeed" (for a client-dependent definition of "succeed"), and "really shouldn't" assign it a new value if they "fail" (again, where "fail" sometimes has as client-specific meaning). This interface is the heart of client-side cwal bindings, and any non-trivial binding will likely have many functions of this type. ACHTUNG: it is critical that implementations return CWAL_RC_xxx values, as the framework relies on several specific values to report information to the framework and to scripting engines built on it. e.g. CWAL_RC_RETURN, CWAL_RC_OOM, CWAL_RC_BREAK, and CWAL_RC_EXCEPTION are often treated specially. If clients return non-cwal result codes from this function, cwal may get confused and downstream behaviour is undefined. */ typedef int (*cwal_callback_f)( cwal_callback_args const * args, cwal_value ** rv ); /** Framework-wide interface for finalizer functions for memory managed by/within a cwal_engine instance. Generally speaking it must semantically behave like free(3), but if the implementor knows what |
︙ | ︙ | |||
1841 1842 1843 1844 1845 1846 1847 | Number of "used" entries in the list. Reminder to self: we could reasonably use a 32-bit size type even in 64-bit builds, and that would save 8 bytes per array. It would require many changes to list-related API signatures which take cwal_size_t (which may be larger than 32-bits). */ | | | | 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 | Number of "used" entries in the list. Reminder to self: we could reasonably use a 32-bit size type even in 64-bit builds, and that would save 8 bytes per array. It would require many changes to list-related API signatures which take cwal_size_t (which may be larger than 32-bits). */ cwal_midsize_t count; /** Number of slots allocated in this->list. Use cwal_list_reserve() to modify this. Doing so might move the this->list pointer but the values it points to will stay stable. */ cwal_midsize_t alloced; /** An internal consistency/misuse marker to let us know that this list is currently undergoing iteration/visitation and must therefore not be modified. Do not use this from client-level code. */ |
︙ | ︙ | |||
4526 4527 4528 4529 4530 4531 4532 | @see cwal_scope_search_kvp_v() @see cwal_scope_search() */ cwal_kvp * cwal_scope_search_kvp( cwal_scope * s, int upToDepth, char const * key, | | | | 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 | @see cwal_scope_search_kvp_v() @see cwal_scope_search() */ cwal_kvp * cwal_scope_search_kvp( cwal_scope * s, int upToDepth, char const * key, cwal_midsize_t keyLen, cwal_scope ** foundIn ); /** Functionally equivalent to cwal_scope_search_v() except that it takes a C-string key and can only match String-typed keys. The first keyLen bytes of key are used as the search key. Returns as described for cwal_scope_search_v(), and also returns NULL if (!key). See cwal_prop_get() for details about the lookup key comparison. @see cwal_scope_search_kvp_v() @see cwal_scope_search_kvp() */ cwal_value * cwal_scope_search( cwal_scope * s, int maxDepth, char const * key, cwal_midsize_t keyLen, cwal_scope ** foundIn ); /** Identical to cwal_scope_chain_set_with_flags_v(), passing CWAL_VAR_F_PRESERVE as the final parameter. */ int cwal_scope_chain_set_v( cwal_scope * s, int upToDepth, |
︙ | ︙ | |||
4585 4586 4587 4588 4589 4590 4591 | uint16_t flags ); /** Identical to cwal_scope_chain_set_with_flags(), passing CWAL_VAR_F_PRESERVE as the final parameter. */ int cwal_scope_chain_set( cwal_scope * s, int upToDepth, | | | | 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 | uint16_t flags ); /** Identical to cwal_scope_chain_set_with_flags(), passing CWAL_VAR_F_PRESERVE as the final parameter. */ int cwal_scope_chain_set( cwal_scope * s, int upToDepth, char const * k, cwal_midsize_t keyLen, cwal_value * v ); /** The C-string form of cwal_scope_chain_set_v(), except that only the first keyLen bytes of k are considered as the search key. See cwal_prop_get() for details about the lookup key comparison. */ int cwal_scope_chain_set_with_flags( cwal_scope * s, int upToDepth, char const * k, cwal_midsize_t keyLen, cwal_value * v, uint16_t flags ); /** Copies properties from src to dest, retaining any flags set for those properties. If src is-a hashtable, its hash entries are used, otherwise if src is a container, those properties are used. |
︙ | ︙ | |||
4641 4642 4643 4644 4645 4646 4647 | int cwal_var_decl_v( cwal_engine * e, cwal_scope * s, cwal_value * key, cwal_value * v, uint16_t flags ); /** Functionally identical to cwal_var_decl_v(), but takes a C-style string (key) which must be keyLen bytes long. */ int cwal_var_decl( cwal_engine * e, cwal_scope * s, char const * key, | | | 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 | int cwal_var_decl_v( cwal_engine * e, cwal_scope * s, cwal_value * key, cwal_value * v, uint16_t flags ); /** Functionally identical to cwal_var_decl_v(), but takes a C-style string (key) which must be keyLen bytes long. */ int cwal_var_decl( cwal_engine * e, cwal_scope * s, char const * key, cwal_midsize_t keyLen, cwal_value * v, uint16_t flags ); /** cwal_value_unref() is THE function clients must use for destroying values allocated via this framework. It decrements the reference count of a cwal_value, cleaning up if needed. |
︙ | ︙ | |||
5585 5586 5587 5588 5589 5590 5591 | /** Equivalent to cwal_string_value( cwal_new_string(e,str,len) ). @see cwal_new_string() @see cwal_new_VALUE() */ | | > | | 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 | /** Equivalent to cwal_string_value( cwal_new_string(e,str,len) ). @see cwal_new_string() @see cwal_new_VALUE() */ cwal_value * cwal_new_string_value(cwal_engine * e, char const * str, cwal_midsize_t len); /** Returns a pointer to the NULL-terminated string bytes of str. The bytes are owned by string and will be invalided when it is cleaned up. If str is NULL then NULL is returned. If the string has a length of 0 then "" is returned. @see cwal_string_length_bytes() @see cwal_value_get_string() @see cwal_string_cstr2() */ char const * cwal_string_cstr(cwal_string const *v); /** Equivalent to cwal_string_cstr(), but if the 2nd argument is not NULL, *len is set to the string's length, in bytes. @see cwal_string_cstr() */ char const * cwal_string_cstr2(cwal_string const *v, cwal_midsize_t * len); /** Case-folds a UTF-8 C-string, placing the result in a new cwal_string instance. cstr must point to at least cstrLen bytes of valid UTF-8 text. This function converts the case of each character to upper or lower (as |
︙ | ︙ | |||
5635 5636 5637 5638 5639 5640 5641 | - CWAL_RC_OOM on allocation error or if the 3rd parameter exceeds cwal's string-length limits. In such cases, *rv may be set to 0 (or may be unmodified). @see cwal_string_case_fold() */ int cwal_utf8_case_fold( cwal_engine * e, char const * cstr, | | | | 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 | - CWAL_RC_OOM on allocation error or if the 3rd parameter exceeds cwal's string-length limits. In such cases, *rv may be set to 0 (or may be unmodified). @see cwal_string_case_fold() */ int cwal_utf8_case_fold( cwal_engine * e, char const * cstr, cwal_midsize_t cstrLen, cwal_value **rv, bool doUpper ); /** Works just like cwal_utf8_case_fold() with the following differences: - Case-folded output is appended to buf, which may cause buf->mem to get reallocated (and thus any prior pointer to it |
︙ | ︙ | |||
5668 5669 5670 5671 5672 5673 5674 | at buf->mem[buf->used].) Returns CWAL_RC_MISUSE if !e, !cstr, !buf, or if cstr is part of buf's current memory range. Otherwise it returns as documented for cwal_utf8_case_fold(). */ int cwal_utf8_case_fold_to_buffer( cwal_engine * e, char const * cstr, | | | | 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 | at buf->mem[buf->used].) Returns CWAL_RC_MISUSE if !e, !cstr, !buf, or if cstr is part of buf's current memory range. Otherwise it returns as documented for cwal_utf8_case_fold(). */ int cwal_utf8_case_fold_to_buffer( cwal_engine * e, char const * cstr, cwal_midsize_t len, cwal_buffer *buf, bool doUpper ); /** Searches for the given "needle" in the given "haystack". The 1st and 2nd parameters delimit the area to search. The 4th and 5th specify the thing to look for. |
︙ | ︙ | |||
5711 5712 5713 5714 5715 5716 5717 | char returnAsByteOffset ); /** Identical to cwal_utf8_case_fold() except that it takes its input in the form of a cwal_string. As a special case, if str is an empty string (length of 0), | | > | | > | < | 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 | char returnAsByteOffset ); /** Identical to cwal_utf8_case_fold() except that it takes its input in the form of a cwal_string. As a special case, if str is an empty string (length of 0), *rv is set to its value part. i.e. the output will be the input, but in its alternate type pointer. On 20180515 a (cwal_engine*) parameter was added because this function otherwise fails when used on built-in static strings (length-1 ASCII might, depending on build options, be compiled in). We don't internally special-case that because special-casing is ugly and because that corner case is a compile-time option which cwal_utf.c doesn't know about. @see cwal_utf8_case_fold() */ int cwal_string_case_fold( cwal_engine * e, cwal_string const * str, cwal_value **rv, bool doUpper ); /** This creates a new cwal string Value which copies the first n bytes of str. The new string will be NUL-terminated after n bytes, regardless of whether the input string is. ACHTUNG: prior to 20171005, n=0 meant that this function should use |
︙ | ︙ | |||
5777 5778 5779 5780 5781 5782 5783 | cwal_new_string_value() is a more convenient choice. @see cwal_string_value() @see cwal_new_string_value() @see cwal_string_cstr() @see cwal_string_cstr2() */ | | > | 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 | cwal_new_string_value() is a more convenient choice. @see cwal_string_value() @see cwal_new_string_value() @see cwal_string_cstr() @see cwal_string_cstr2() */ cwal_string * cwal_new_string(cwal_engine * e, char const * str, cwal_midsize_t len); /** printf-like form of cwal_new_string(). See cwal_printf() for the formatting specifiers. */ cwal_string * cwal_new_stringf(cwal_engine * e, char const * fmt, ...); /** printf-like form of cwal_new_string(). See cwal_printfv() for |
︙ | ︙ | |||
5839 5840 5841 5842 5843 5844 5845 | - X-strings DO partake in the length-0-string optimization, so cwal_new_string(e,"",0) and cwal_new_xstring(e,"",0) will return the same value (but that's an implementation detail clients should not make code-level decisions based on). */ | | > | > | 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 | - X-strings DO partake in the length-0-string optimization, so cwal_new_string(e,"",0) and cwal_new_xstring(e,"",0) will return the same value (but that's an implementation detail clients should not make code-level decisions based on). */ cwal_string * cwal_new_xstring(cwal_engine * e, char const * str, cwal_midsize_t len); /** Equivalent to passing the return value of cwal_new_xstring(e,str,len) to cwal_string_value(). */ cwal_value * cwal_new_xstring_value(cwal_engine * e, char const * str, cwal_midsize_t len); /** A "z-string" is closely related to an "x-string" (see cwal_new_xstring()) in that the caller allocates the string, but (different from x-strings), the caller gives its memory over to a new cwal_string value. This can avoid extra copies in some cases, |
︙ | ︙ | |||
5917 5918 5919 5920 5921 5922 5923 | source tree (not this one) where pointers to strings for which the client owns the memory are named with a "z" prefix, e.g. zMyString. @see cwal_new_zstring_value() @see cwal_new_string() @see cwal_new_xstring() */ | | > | > | 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 | source tree (not this one) where pointers to strings for which the client owns the memory are named with a "z" prefix, e.g. zMyString. @see cwal_new_zstring_value() @see cwal_new_string() @see cwal_new_xstring() */ cwal_string * cwal_new_zstring(cwal_engine * e, char * str, cwal_midsize_t len); /** Equivalent to passing the result value of cwal_new_zstring(e,str,len) to cwal_string_value(). */ cwal_value * cwal_new_zstring_value(cwal_engine * e, char * str, cwal_midsize_t len); /** Creates a new cwal_string value by concatenating two string values. Returns NULL if either argument is NULL or if allocation of the new string fails. |
︙ | ︙ | |||
5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 | hashes are much faster at property lookups when a scope contains many variables. Historically, objects have suited this purpose just fine. Changing this flag at runtime only affects future property storage creation, and does not affect scope which have already allocated their scope properties (which they do lazily, only when needed). */ CWAL_FEATURE_SCOPE_STORAGE_HASH = 0x0400 }; /** Sets the current set of feature flags and returns the old flags. Pass a negative flags value to have it return the current flags | > > > > > | 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 | hashes are much faster at property lookups when a scope contains many variables. Historically, objects have suited this purpose just fine. Changing this flag at runtime only affects future property storage creation, and does not affect scope which have already allocated their scope properties (which they do lazily, only when needed). When the library is compiled with the CWAL_OBASE_ISA_HASH configuration option then scopes will use a hash either way, but the actual concrete type of the storage will differ: it will be cwal_object without this flag and cwal_hash with it. */ CWAL_FEATURE_SCOPE_STORAGE_HASH = 0x0400 }; /** Sets the current set of feature flags and returns the old flags. Pass a negative flags value to have it return the current flags |
︙ | ︙ | |||
6079 6080 6081 6082 6083 6084 6085 | */ cwal_value * cwal_string_value(cwal_string const * s); /** Returns the length of str in bytes, or 0 if !str. This is an O(1) operation. */ | | | | | | 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 | */ cwal_value * cwal_string_value(cwal_string const * s); /** Returns the length of str in bytes, or 0 if !str. This is an O(1) operation. */ cwal_midsize_t cwal_string_length_bytes( cwal_string const * str ); /** Returns the length of the first n bytes of str in UTF8 characters, or 0 if !str. Results are undefined if str is not legal UTF8. This is an O(N) operation. Note that an embedded NUL byte before (str+n) is counted as a byte! */ cwal_midsize_t cwal_strlen_utf8( char const * str, cwal_midsize_t n ); /** Functionally equivalent to strlen(3) except that if !str it returns 0 instead of crashing, and it returns cwal_size_t, which very well may not be the same size as size_t. */ cwal_midsize_t cwal_strlen( char const * str ); /** Equivalent to: cwal_strlen_utf8(cwal_string_cstr(str),cwal_string_length_bytes(str)) Unless str is known to be an ASCII string, in which case it is an O(1) operation. Returns 0 if !str. */ cwal_midsize_t cwal_string_length_utf8( cwal_string const * str ); /** If str is composed solely of ASCII characters (in the range (0,127), this returns true, else false. While normally of little significance, some common algorithms can be sped up notably if their input is guaranteed to have only 1 byte per character. |
︙ | ︙ | |||
7047 7048 7049 7050 7051 7052 7053 | TODO: change last parameter to an int to support non-ASCII separators. s2's string.split() code is close to what we need here. @see cwal_prop_get_sub() @see cwal_prop_get_sub2() */ | | > | 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 | TODO: change last parameter to an int to support non-ASCII separators. s2's string.split() code is close to what we need here. @see cwal_prop_get_sub() @see cwal_prop_get_sub2() */ int cwal_prop_fetch_sub( cwal_value * obj, cwal_value ** tgt, char const * path, char separator ); /** Similar to cwal_prop_fetch_sub(), but derives the path separator character from the first byte of the path argument. e.g. the following arg equivalent: @code |
︙ | ︙ | |||
7354 7355 7356 7357 7358 7359 7360 | Fails with CWAL_RC_IS_VISITING if c is currently being iterated over. This is functionally equivalent calling cwal_prop_set(obj,key,keyLen,NULL). */ | | > | > | 7371 7372 7373 7374 7375 7376 7377 7378 7379 7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 | Fails with CWAL_RC_IS_VISITING if c is currently being iterated over. This is functionally equivalent calling cwal_prop_set(obj,key,keyLen,NULL). */ int cwal_prop_unset( cwal_value * c, char const * key, cwal_midsize_t keyLen ); /** Searches the given container value for a string-keyed property matching the first keyLen bytes of the given key. If found, it is returned. If no match is found, or any arguments are NULL, NULL is returned. The returned object is owned by c, and may be invalidated by ANY operations which change c's property list (i.e. add or remove properties). This routine will only ever match property keys for which cwal_value_get_cstr() returns non-NULL (i.e. property keys of type cwal_string or cwal_buffer). It never compares the key to non-string property keys (even though they might compare equivalent if the search key was a "real" cwal_string). @see cwal_prop_get_kvp() @see cwal_prop_get_v() @see cwal_prop_get_kvp_v() */ cwal_value * cwal_prop_get( cwal_value const * c, char const * key, cwal_midsize_t keyLen ); /** Similar to cwal_prop_get() but takes a cwal_value key and may compare keys of different types for equivalence. e.g. the lookup key (integer 1) will match a property with a key of (double 1) or (string "1"). |
︙ | ︙ | |||
7407 7408 7409 7410 7411 7412 7413 | modified. Achtung: if/when property interceptors are added to the cwal core, this function will support them (whereas cwal_prop_get() and friends will not). Thus a non-0 return value may hypothetically come from a property interceptor function. */ | | | | | 7426 7427 7428 7429 7430 7431 7432 7433 7434 7435 7436 7437 7438 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 | modified. Achtung: if/when property interceptors are added to the cwal core, this function will support them (whereas cwal_prop_get() and friends will not). Thus a non-0 return value may hypothetically come from a property interceptor function. */ int cwal_prop_getX( cwal_value * c, bool processInterceptors, char const * key, cwal_midsize_t keyLen, cwal_value ** rv); /** UNTESTED! EXPERIMENTAL! DO NOT USE! Like cwal_prop_getX() but takes a cwal_value key. */ int cwal_prop_getX_v( cwal_value * c, bool processInterceptors, cwal_value const * key, cwal_value ** rv ); /** cwal_prop_get_kvp() is similar to cwal_prop_get(), but returns its result in a more complex form (useful mostly in interpreter-level code so that it can get at their flags to check for constness and such). |
︙ | ︙ | |||
7439 7440 7441 7442 7443 7444 7445 | ACHTUNG: the returned object is owned by c (or *foundIn) and may be invalidated on any modification (or cleanup) of c (or *foundIn). Returns 0 if no match is found, !c, or !key. */ cwal_kvp * cwal_prop_get_kvp( cwal_value * c, char const * key, | | | 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 7470 7471 7472 | ACHTUNG: the returned object is owned by c (or *foundIn) and may be invalidated on any modification (or cleanup) of c (or *foundIn). Returns 0 if no match is found, !c, or !key. */ cwal_kvp * cwal_prop_get_kvp( cwal_value * c, char const * key, cwal_midsize_t keyLen, bool searchProtos, cwal_value ** foundIn ); /** cwal_prop_get_kvp_v() works identically to cwal_prop_get_kvp(), but takes its key in the form of a cwal_value. Except in the case of a boolean lookup key or property key (see below), it performs a |
︙ | ︙ | |||
7475 7476 7477 7478 7479 7480 7481 | @see cwal_prop_get() @see cwal_prop_get_v() @see cwal_prop_get_kvp() @see cwal_prop_take() @see cwal_prop_take_v() */ cwal_kvp * cwal_prop_get_kvp_v( cwal_value * c, cwal_value const * key, | | | 7494 7495 7496 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506 7507 7508 | @see cwal_prop_get() @see cwal_prop_get_v() @see cwal_prop_get_kvp() @see cwal_prop_take() @see cwal_prop_take_v() */ cwal_kvp * cwal_prop_get_kvp_v( cwal_value * c, cwal_value const * key, bool searchProtos, cwal_value ** foundIn ); /** Similar to cwal_prop_get(), but removes the value from the parent container's ownership. This removes the owning container's reference point but does not destroy the value if its refcount reaches 0. If no item is found then NULL is returned, else the |
︙ | ︙ | |||
7635 7636 7637 7638 7639 7640 7641 | key comparisons. @see cwal_prop_set() @see cwal_prop_set_v() @see cwal_prop_set_with_flags_v() */ int cwal_prop_set_with_flags( cwal_value * c, char const * key, | | | | > | | | 7654 7655 7656 7657 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 7683 7684 7685 7686 7687 7688 7689 7690 7691 | key comparisons. @see cwal_prop_set() @see cwal_prop_set_v() @see cwal_prop_set_with_flags_v() */ int cwal_prop_set_with_flags( cwal_value * c, char const * key, cwal_midsize_t keyLen, cwal_value * v, uint16_t flags ); /** Equivalent to calling cwal_prop_set_with_flags() using the same parameters, and a flags value of CWAL_VAR_F_PRESERVE. */ int cwal_prop_set( cwal_value * c, char const * key, cwal_midsize_t keyLen, cwal_value * v ); /** UNTESTED! EXPERIMENTAL! DO NOT USE! */ int cwal_prop_setX_with_flags( cwal_value * c, bool processInterceptors, char const * key, cwal_midsize_t keyLen, cwal_value * v, uint16_t flags ); /** UNTESTED! EXPERIMENTAL! DO NOT USE! */ int cwal_prop_setX_with_flags_v( cwal_value * c, bool processInterceptors, cwal_value * key, cwal_value * v, uint16_t flags ); /** Returns non-0 (true) if c is of a type capable of containing per-instance properties, else 0 (false). |
︙ | ︙ | |||
7701 7702 7703 7704 7705 7706 7707 | bool cwal_prop_key_can( cwal_value const * c ); /** Returns the number of properties in c (not including prototypes), or 0 if c is not a properties-capable type. This is an O(N) operation. */ | | | 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730 7731 7732 7733 7734 7735 | bool cwal_prop_key_can( cwal_value const * c ); /** Returns the number of properties in c (not including prototypes), or 0 if c is not a properties-capable type. This is an O(N) operation. */ cwal_midsize_t cwal_props_count( cwal_value const * c ); /** Like cwal_prop_set_with_flags() but takes a cwal_value key. Note that this routine does a type-loose comparison for the lookup key and property keys, with the exception of boolean-type keys (which only compare type-strictly: see cwal_prop_get_kvp_v() for |
︙ | ︙ | |||
7744 7745 7746 7747 7748 7749 7750 | property key. If searchPrototype is true then the search continues up the prototype chain if the property is not found, otherwise only v is checked. See cwal_prop_get_kvp_v() for details about the lookup/property key comparisons. */ | | > | | | 7764 7765 7766 7767 7768 7769 7770 7771 7772 7773 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785 7786 7787 7788 7789 | property key. If searchPrototype is true then the search continues up the prototype chain if the property is not found, otherwise only v is checked. See cwal_prop_get_kvp_v() for details about the lookup/property key comparisons. */ bool cwal_prop_has( cwal_value const * v, char const * key, cwal_midsize_t keyLen, bool searchPrototype ); /** Like cwal_prop_has() but takes a cwal_value key. See cwal_prop_get_kvp_v() for details about the lookup/property key comparisons. */ bool cwal_prop_has_v( cwal_value const * v, cwal_value const * key, bool searchPrototype ); /** Returns the virtual type of v, or CWAL_TYPE_UNDEF if !v. */ cwal_type_id cwal_value_type_id( cwal_value const * v ); /** |
︙ | ︙ | |||
8685 8686 8687 8688 8689 8690 8691 | Returns NULL if !h or !key. If keyLen is 0 and *key is not then the equivalent of strlen(key) is used to find its length. @see cwal_hash_search_v() @see cwal_hash_search_kvp() */ | | > | > | 8706 8707 8708 8709 8710 8711 8712 8713 8714 8715 8716 8717 8718 8719 8720 8721 8722 8723 8724 8725 8726 8727 8728 8729 8730 8731 8732 8733 8734 8735 8736 8737 | Returns NULL if !h or !key. If keyLen is 0 and *key is not then the equivalent of strlen(key) is used to find its length. @see cwal_hash_search_v() @see cwal_hash_search_kvp() */ cwal_value * cwal_hash_search( cwal_hash * h, char const * key, cwal_midsize_t keyLen ); /** Equivalent to cwal_hash_search() but returns (on a match) a cwal_kvp holding the key/value pair, using the first keyLen bytes of key as the search key. It only matches String-typed keys. The returned object is owned by h and might be invalidated or modified on any change to h, so clients must not hold returned kvp wrapper for long. NEVER, EVER change the internals of the returned cwal_kvp value, e.g. changing the key or value instances, as that Will Break Things. @see cwal_hash_search() */ cwal_kvp * cwal_hash_search_kvp( cwal_hash * h, char const * key, cwal_midsize_t keyLen ); /** Returns true (non-0) if v is of the concrete type cwal_hash. */ bool cwal_value_is_hash( cwal_value const * v ); /** |
︙ | ︙ | |||
8801 8802 8803 8804 8805 8806 8807 | /** Like cwal_hash_insert_with_flags_v() but takes its key in the form of the first keyLen bytes of the given key. This routine allocates a new String value for the key (just in case there was any doubt about that). */ | | > | | 8824 8825 8826 8827 8828 8829 8830 8831 8832 8833 8834 8835 8836 8837 8838 8839 8840 8841 8842 8843 8844 8845 8846 8847 | /** Like cwal_hash_insert_with_flags_v() but takes its key in the form of the first keyLen bytes of the given key. This routine allocates a new String value for the key (just in case there was any doubt about that). */ int cwal_hash_insert_with_flags( cwal_hash * h, char const * key, cwal_midsize_t keyLen, cwal_value * v, bool allowOverwrite, cwal_flags16_t kvpFlags ); /** Equivalent to calling cwal_hash_insert_with_flags() with the same arguments, passing CWAL_VAR_F_PRESERVE as the final argument. */ int cwal_hash_insert( cwal_hash * h, char const * key, cwal_midsize_t keyLen, cwal_value * v, bool allowOverwrite ); /** Removes the given key from the given hashtable, potentially freeing the value (and possibly even the passed-in key, depening on ownership conditions). Returns 0 on success, CWAL_RC_MISUSE if either argument is |
︙ | ︙ | |||
8841 8842 8843 8844 8845 8846 8847 | /** Like cwal_hash_remove_v(), with the same result codes, but takes its key in the form of the first keyLen bytes of the given key. It can only match String-type keys, not non-String-type keys which might happen to have similar representations. e.g. passing "1" as a key will not match an Integer-typed key with the numeric value 1. */ | | | | | 8865 8866 8867 8868 8869 8870 8871 8872 8873 8874 8875 8876 8877 8878 8879 8880 8881 8882 8883 8884 8885 8886 8887 8888 8889 8890 | /** Like cwal_hash_remove_v(), with the same result codes, but takes its key in the form of the first keyLen bytes of the given key. It can only match String-type keys, not non-String-type keys which might happen to have similar representations. e.g. passing "1" as a key will not match an Integer-typed key with the numeric value 1. */ int cwal_hash_remove( cwal_hash * h, char const * key, cwal_midsize_t keyLen ); /** Returns the number of entries in the given hash, or 0 if !h. This is an O(1) operation. */ cwal_midsize_t cwal_hash_entry_count(cwal_hash const * h); /** Returns the table size of h, or 0 if !h. */ cwal_midsize_t cwal_hash_size( cwal_hash const * h ); /** Resizes the table used by h for key/value storage to the new size (which most definitely should be a prime number!). On success it returns 0 and cwal_hash_size() will return the size passed here. This is a no-op (returning 0) if newSize == cwal_hash_size(h). |
︙ | ︙ | |||
8917 8918 8919 8920 8921 8922 8923 | (and almost arbitrarily) define in this code, a value smaller than n will be returned. That maximum value is guaranteed to be at least as large as the 1000th prime number (7919 resp. cwal_first_1000_primes()[999]). This function makes no performance guarantees. */ | | < > > > < < | 8941 8942 8943 8944 8945 8946 8947 8948 8949 8950 8951 8952 8953 8954 8955 8956 8957 8958 8959 8960 8961 8962 8963 8964 8965 8966 8967 8968 8969 8970 8971 8972 8973 8974 8975 8976 8977 8978 8979 8980 8981 8982 8983 8984 8985 8986 8987 | (and almost arbitrarily) define in this code, a value smaller than n will be returned. That maximum value is guaranteed to be at least as large as the 1000th prime number (7919 resp. cwal_first_1000_primes()[999]). This function makes no performance guarantees. */ cwal_midsize_t cwal_next_prime( cwal_midsize_t n ); /** _Moves_ properties from the containter-type value src to the hash table dest in such a way that does not require new allocations. overwritePolicy determines how to handle keys which dest already contains: overwritePolicy<0: keep existing entry overwritePolicy0: error on key collision overwritePolicy>0: overwrite any keys already existing in the hash. If a given property, due to the overwrite policy, is not taken then it is kept in src, so src need not be empty when this returns unless overwritePolicy>0. Returns 0 on success or: - CWAL_RC_UNSUPPORTED if built with CWAL_OBASE_ISA_HASH, as this operation hasn't been re-done for that case yet. - CWAL_RC_MISUSE if !src or !dest - CWAL_RC_TYPE if src is not a container type. - CWAL_RC_IS_VISITING if either src is currently being visited (the model does not support modification during visitation). - CWAL_RC_IS_VISITING_LIST if dest is currently being visited (the model does not support modification during visitation). (This case was reported as CWAL_RC_IS_VISITING prior to 20191211.) */ int cwal_hash_take_props( cwal_hash * dest, cwal_value * src, int overwritePolicy ); /** Similar to cwal_props_visit_kvp() except that it operates on the hash table entries of h. See cwal_props_visit_kvp() for the |
︙ | ︙ | |||
9997 9998 9999 10000 10001 10002 10003 | */ int cwal_json_parse_cstr( cwal_engine * e, char const * src, cwal_size_t len, cwal_value ** tgt, cwal_json_parse_info * pInfo ); /** Sets the current trace mask and returns the old mask. mask is | | | | | | 10021 10022 10023 10024 10025 10026 10027 10028 10029 10030 10031 10032 10033 10034 10035 10036 10037 10038 | */ int cwal_json_parse_cstr( cwal_engine * e, char const * src, cwal_size_t len, cwal_value ** tgt, cwal_json_parse_info * pInfo ); /** Sets the current trace mask and returns the old mask. mask is interpreted as a bitmask of cwal_trace_flags_e values. If mask == -1 then it returns the current mask without setting it, otherwise it sets the trace mask to the given value and returns the previous value. If !e or tracing is disabled at built-time, returns -1. */ int32_t cwal_engine_trace_flags( cwal_engine * e, int32_t mask ); /** Sets v's prototype value. Both v and prototype must be |
︙ | ︙ | |||
19177 19178 19179 19180 19181 19182 19183 | char const * s2_home_get(s2_engine * se, cwal_size_t * len); /** Installs a user-defined pseudo-keyword into the given engine, granting fast acess to the value and a lifetime as long as the engine is running. | | | > > | 19201 19202 19203 19204 19205 19206 19207 19208 19209 19210 19211 19212 19213 19214 19215 19216 19217 19218 | char const * s2_home_get(s2_engine * se, cwal_size_t * len); /** Installs a user-defined pseudo-keyword into the given engine, granting fast acess to the value and a lifetime as long as the engine is running. The given string must be a legal s2 identifier with a length equal to the 3rd argument. Its bytes are copied, so it need not have a well-defined lifetime. If the given length is negative, cwal_strlen() is used to calculate the key's length. "User Keywords," or UKWDs, as they're colloquially known, use s2's keyword infrastructure for their lookups, meaning that they bypass all scope-level lookups and have an amortized faster search time than var/const symbols. The determination of whether a given symbol is a UKWD an average O(log n) operation (n=number of UKWDs), and then finding the associated value for that requires a hashtable |
︙ | ︙ | |||
19228 19229 19230 19231 19232 19233 19234 | much, but keyword lookups happen *all the time* internally (every time an identifier is seen), so it adds up. 2) They cannot be re-set or uninstalled once they have been installed. */ int s2_define_ukwd(s2_engine * se, char const * name, | | | 19254 19255 19256 19257 19258 19259 19260 19261 19262 19263 19264 19265 19266 19267 19268 | much, but keyword lookups happen *all the time* internally (every time an identifier is seen), so it adds up. 2) They cannot be re-set or uninstalled once they have been installed. */ int s2_define_ukwd(s2_engine * se, char const * name, cwal_int_t nameLen, cwal_value * v); /** A set of *advisory* flags for features which well-behaved s2 APIs should honor. The flag names listed for each entry are for use with s2_disable_set_cstr(). This is generally only intended to apply to script-side APIs, not |
︙ | ︙ |
Changes to bindings/s2/shell_common.c.
︙ | ︙ | |||
1118 1119 1120 1121 1122 1123 1124 | return 0; } #endif static int s2sh_setup_s2_global( s2_engine * se ){ int rc = 0; cwal_value * v = 0; | | > > > | | | | 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 | return 0; } #endif static int s2sh_setup_s2_global( s2_engine * se ){ int rc = 0; cwal_value * v = 0; cwal_engine * const e = se->e; cwal_value * s2 = 0; #define VCHECK if(!v){rc = CWAL_RC_OOM; goto end;} (void)0 #define RC if(rc) goto end rc = s2_define_ukwd(se, "CWAL_OBASE_ISA_HASH", -1, cwal_new_bool(CWAL_OBASE_ISA_HASH)); RC; /* Reminder to self: we're not "leaking" anything on error here - it will be cleaned up by the scope when it pops during cleanup right after the error code is returned. */ v = cwal_new_function_value( e, s2_cb_print, 0, 0, 0 ); VCHECK; /*s2_dump_val(App.s2Global, "App.s2Global");*/ cwal_value_ref(v); #if 0 if(2==S2SH_VERSION){ rc = s2_define_ukwd(se, "if", 2, v); assert(CWAL_RC_ACCESS==rc); rc = s2_define_ukwd(se, "print", 5, v); RC; rc = s2_define_ukwd(se, "print", 5, v); assert(CWAL_RC_ALREADY_EXISTS==rc); rc = 0; }else #endif { rc = cwal_var_decl(e, 0, "print", 5, v, 0); RC; |
︙ | ︙ |
Changes to bindings/s2/unit/040-000-objects.s2.
︙ | ︙ | |||
233 234 235 236 237 238 239 240 241 242 243 244 245 | assert 'CWAL_RC_TYPE' === catch{ /* The "problem" with enums is that they can use either object or hash storage internally, so we would need to differentiate between the two in the @ expansion. We don't currently do that, but maybe someday will. */ {@enum {a,b,c}} }.codeString(); } o /* propagate top-most o out for lifetime checks */; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 | assert 'CWAL_RC_TYPE' === catch{ /* The "problem" with enums is that they can use either object or hash storage internally, so we would need to differentiate between the two in the @ expansion. We don't currently do that, but maybe someday will. ^^^^ that's outdated. enums now always use hashes. */ {@enum {a,b,c}} }.codeString(); } scope { /* 2021-06-24: ensure that vars declared in property access [] or () are not leaked into the current scope. e.g. var o = {}; o[var x = 'hi'] = 1; assert 'hi'===x; */ var o = {}; o[var xx = 'a']; assert !typeinfo(isdeclared xx); o.(var xx = 'b'); assert !typeinfo(isdeclared xx); /* But we want standalone (...) to run in the current scope. */ 1 && (var xx = 'y'); assert 'y' === xx; } scope { /* 2021-07-09: Ensure that cwal_prop_key_can() prohibits certain property key types... */ const o = {}; assert 'CWAL_RC_TYPE' === catch{ o[new s2.Buffer()] = 1; }.codeString(); assert 'CWAL_RC_TYPE' === catch{ o[[#]] = 1; }.codeString(); } o /* propagate top-most o out for lifetime checks */; |
Changes to bindings/s2/unit/100-000-object-methods.s2.
1 2 3 4 5 6 7 8 | var o = {a:1, 2:'two', __typename:'Fred'}; scope { assert 'Fred' === typename o; assert o.hasOwnProperty('a'); assert !o.hasOwnProperty('hasOwnProperty'); assert o.prototype.hasOwnProperty('hasOwnProperty'); assert o.hasOwnProperty(2); | > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | var o = {a:1, 2:'two', __typename:'Fred'}; scope { assert 'Fred' === typename o; assert o.hasOwnProperty('a'); assert !o.hasOwnProperty('hasOwnProperty'); assert o.prototype.hasOwnProperty('hasOwnProperty'); assert o.hasOwnProperty(2); assert CWAL_OBASE_ISA_HASH ? !o.hasOwnProperty('2') : o.hasOwnProperty('2'); unset o.2; assert !o.hasOwnProperty(2); assert 0 != o.compare({}); assert 0 === o.compare(print,print); assert 0 === o.compare(o); assert 0 === o.compare(o,o); assert 0 === o.compare(1,1); |
︙ | ︙ | |||
44 45 46 47 48 49 50 | scope { assert o.mayIterate(); } scope { o.a = 3, o.b = 7, o.c = 42.24, o.d = [1,2,3], o.1 = -1; | | | > > | | | | > | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | scope { assert o.mayIterate(); } scope { o.a = 3, o.b = 7, o.c = 42.24, o.d = [1,2,3], o.1 = -1; const json = o.toJSONString(' '); const o2 = eval -> json; assert typename o === typename o2; assert o2.d[1] === o.d[1]; if(!CWAL_OBASE_ISA_HASH){ /*only works if !CWAL_OBASE_ISA_HASH, else order is undefined*/ assert o2.toJSONString(1) === json; const abc = o.toJSONString('abc'); assert abc.indexOf('abc')>0; assert abc.toLower() === o2.toJSONString('ABC').toLower(); } } scope { o.x = -1; assert -1 === o.get('x'); o.set('x',1); assert 1 === o.get('x'); |
︙ | ︙ |
Changes to bindings/s2/unit/500-000-array.s2.
︙ | ︙ | |||
135 136 137 138 139 140 141 | // on whether it gets set before or after this object // extends the array class... prototype:[1,2] }; x.0 = -1 /* sets array index */; assert -1 === x.0 /* array index */; assert -1 === x.prototype.0 /* array index */; | > | | | > | 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | // on whether it gets set before or after this object // extends the array class... prototype:[1,2] }; x.0 = -1 /* sets array index */; assert -1 === x.0 /* array index */; assert -1 === x.prototype.0 /* array index */; if(!CWAL_OBASE_ISA_HASH){ assert 0 === x.'0' /* string type bypasses array index check, so this is an object property access.*/; x.'0' = 1 /* also object property, not array index */; } assert -1 === x.0 /* string key '0' did not overwrite this */; x[] = 3; assert 3 === x.length(); assert 3 === x.2; /* Minor descrepancy vis-a-vis objects: objects never (via |
︙ | ︙ |
Changes to bindings/s2/unit/600-000-hash.s2.
︙ | ︙ | |||
94 95 96 97 98 99 100 | const rch = s2.getResultCodeHash(); assert rch.entryCount() > 90 /* === 102 as of this writing */; assert rch === s2.getResultCodeHash() /* result is cached */; assert 'integer' === typename rch # 'CWAL_RC_OOM'; assert 'string' === typename rch # 0 /* the only code with a well-defined value! */; } | | | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | const rch = s2.getResultCodeHash(); assert rch.entryCount() > 90 /* === 102 as of this writing */; assert rch === s2.getResultCodeHash() /* result is cached */; assert 'integer' === typename rch # 'CWAL_RC_OOM'; assert 'string' === typename rch # 0 /* the only code with a well-defined value! */; } if(!CWAL_OBASE_ISA_HASH){ /* takeProperties() */ var src, h; const reset = proc(){ src = {a:1, b:-1, c:0}; h = s2.Hash.new(5); }; reset(); |
︙ | ︙ | |||
171 172 173 174 175 176 177 | potential semantic ambiguities in handling of hash vs. object properties. */ const ex = catch{ {#@{a:1}} }; assert 'CWAL_RC_TYPE' === ex.codeString(); assert ex.message.indexOf('hash literal') > 0; } | > > > > > > > > > > > > | 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | potential semantic ambiguities in handling of hash vs. object properties. */ const ex = catch{ {#@{a:1}} }; assert 'CWAL_RC_TYPE' === ex.codeString(); assert ex.message.indexOf('hash literal') > 0; } scope { /* 2021-07-09: Ensure that cwal_prop_key_can() prohibits certain property key types... */ const h = {#}; assert 'CWAL_RC_TYPE' === catch{ h.insert(new s2.Buffer(),1); }.codeString(); assert 'CWAL_RC_TYPE' === catch{ h.insert([#], 1); }.codeString(); } |