Login
Check-in [ea62cfc2ec]
Login

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: ea62cfc2ec20fe91fe5ff09941248f84731e4426
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
Unified Diff Ignore Whitespace Patch
Changes to bindings/s2/Makefile.
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: CPPFLAGS+=-DS2_ENABLE_ZLIB=1 -DHAVE_CONFIG_H
s2_amalgamation.o: config.h

# end bins and libs
########################################################################

########################################
# Set up file-specific CPPFLAGS/LDFLAGS.







|







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
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
  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_lsize_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 {

    /**





       Linked list of key/value pairs held by this object.
    */
    cwal_kvp * kvp;

    /**
       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. */




#define cwal_obase_empty_m { NULL/*kvp*/, NULL/*prototype*/, CWAL_F_NONE/*flags*/, 0/*containerFlags*/, 0/*clientFlags*/, 0/*reservedPadding*/ }








/** @internal

   Concrete value type for Arrays (type CWAL_TYPE_ARRAY).
*/
struct cwal_array {
    /**







|
















>
|
>
>
>
>
>
|
|
|
>
|
|
|
|
|
|

|
|
|
|
|

|
|
|
|

|
|
|
|
|
|
|
|
|
|
|

|
|
|
|

|



|
>
>
>
>
|
>
>
>
>
>
>
>







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
9425
9426
9427
9428
9429
9430
9431
9432
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







<







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
9587


9588
9589
9590
9591
9592
9593
9594
       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 enum.


    */
    int (*rescope_children)( cwal_value * v );

    /**
       TODOs???:

       // Using JS semantics for true/value







|
>
>







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
10169
10170
10171
10172
10173
10174
10175
10176
10177
10178
10179
10180
    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 or it is and was flagged as now
    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.








|
|
|
|
|







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
10278
10279

10280
10281
10282
10283
10284
10285
10286
10287
10288
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;
  cwal_hash_t ndx;
  cwal_list const * li;

#endif
  cwal_kvp const * current;
};
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.







>


<

>

<







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
11276

11277
11278
11279
11280
11281
11282
11283
11284
#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: You don't have that much memory. */

#  define CWAL_STRLEN_MASK    ((cwal_size_t)0x1FFFFFFFFFFFFFFFU)
#  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

/*







|
>
|







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
11329
11330
11331
11332
11333
11334
11335
11336
11337
11338
11339
11340
11341
*/
#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_size_t)((S)->length & (cwal_size_t)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_size_t)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)

/**







|

|


|







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
12025
12026
12027
12028
12029
12030
12031
12032
  }
  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]", cwal_string_cstr(s) );
      }
    }else{
      fprintf( out, " (STILL INITIALIZING?)" );
    }
  }
  else if(cwal_value_is_integer(v)){
    fprintf( out, " int=%"CWAL_INT_T_PFMT,







|







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
12474
12475
12476
12477
12478
12479
12480
12481
12482
12483
12484
12485
12486
12487
12488
12489
12490
  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

    Searchs 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_size_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 ){







>


|








|







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
12576
12577
12578
12579
12580
12581
12582
12583

/**
   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_size_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;







|







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
12627
12628
12629
12630
12631
12632
12633
12634
12635
      *list = kvp->right;
    }
    kvp->right = NULL;
    cwal_kvp_free( e, kvp, 1 );
    return 0;
  }
}


    
/**
   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 ){







|
<







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
14356
14357
14358
14359
14360
14361
14362
14363
14364
      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. */







<
|







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
14380
14381
14382
14383
14384
14385
14386
14387
14388
        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 * pv = s->props;
    cwal_obase * 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?");
    /*







|
|







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
15448
15449
15450
15451
15452
15453
15454
15455
15456


15457
15458
15459
15460
15461
15462
15463
  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_V(e,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.


    */
    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);







|




|
|
|
|
>
>







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
15731
15732
15733
15734

15735
15736
15737
15738
15739
15740
15741
15742

15743
15744
15745
15746
15747
15748
15749

15750
15751
15752
15753
15754
15755

15756
15757
15758
15759
15760
15761
15762
15763
15764
15765
15766
15767
15768


15769
15770
15771
15772
15773
15774
15775
  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 * vScope = v->scope;
      CWAL_TR_V(e,v);
      if(CWAL_RCFLAG_HAS(v, CWAL_RCF_IS_GC_QUEUED)){
        assert(!v->scope);

        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_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_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_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,"NULL scope???");
        assert(v->scope && "this is always true now. That was not always the case.");


      }
      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







|



>








>







>






>











|
|
>
>







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
15804
15805

15806
15807
15808
15809
15810
15811
15812
        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.

      */
      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







|
|
>







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
16530
16531
16532
16533
16534
16535
16536
16537
   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_lsize_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;







|







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
16559



16560
16561
16562
16563
16564
16565
16566
/**
   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, char unrefProto ){



  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







|
>
>
>







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
16596
16597

16598
16599
16600

16601
16602
16603
16604
16605
16606
16607
      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,
                              cwal_lsize_t hashSize ){
  if(table->hashSize){

    assert(table->hashSize >= hashSize);
    return 0;
  }else{

    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;
    }







>















|
|
>



>







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
16627
16628
16629
16630
16631
16632
16633
16634
16635
16636
16637
    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_lsize_t * tableIndex,
                                             cwal_kvp ** left ){
  if(!htable->hashSize) return NULL;
  cwal_lsize_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];







|


|







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
16668
16669
16670
16671
16672
16673
16674
16675
16676
}

/**
   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_size_t keyLen,
                                                cwal_lsize_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;







|
|







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
16725
16726
16727
16728
16729
16730
16731
16732
16733
16734
16735
16736
16737
16738
16739
16740
16741
16742
16743
16744
/**
   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_lsize_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_lsize_t i;
  //cwal_lsize_t const oldSize = table->hashSize;
#ifdef DEBUG
  cwal_lsize_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;
  }







|








|
|

|







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
16802


16803
16804
16805
16806

16807
16808
16809
16810
16811
16812
16813
16814
16815
16816
16817
16818
16819
16820
16821
16822
16823
16824
16825
16826
16827
16828
16829
16830
16831
16832
16833
16834
16835
16836
16837
16838
16839
16840
16841
16842
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

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;


  int rc = 0;
  assert(hashSize);
#if 0
  /* arguable. If someone wants loads of 5.0, let him. */

  if(load >= 0.95) load = 0.95; else
#endif
  if(load < 0.50) load = 0.5;
  if((entryCount / hashSize) > load){
    cwal_lsize_t const newSize =
      cwal_next_prime((cwal_lsize_t)(entryCount + (entryCount * (1.0-load))));
    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_lsize_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_CONTAINER_DISALLOW_PROP_SET & base->flags){
    /* FIXME: this is a wrong mix of semantics. It's currently
       required/relied upon by s2, but we need a different flag
       for a hash-disallow-insert flag. */
    return CWAL_RC_DISALLOW_PROP_SET;
  }
  else if(!cwal_prop_key_can(key)) return CWAL_RC_TYPE;


  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->hashSize){
    rc = cwal_htable_alloc(CWAL_VENGINE(container), table, 0);

  }else{
    rc = cwal_htable_grow_if_loaded(container, table, -1.0);
  }

  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){







|
>
>



|
>
|

<

|
|












|




















<
<
<
<
<
<

>
>






|

>



>







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
16942

16943
16944

16945
16946
16947
16948
16949
16950
16951
16952
16953
16954
16955
16956
16957
16958
16959
16960
16961
16962
16963
16964
16965
16966
16967
16968
16969
16970
16971
16972
16973
16974
16975




16976
16977
16978
16979
16980
16981
16982
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
}

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;
  else if(CWAL_RCFLAG_HAS(vSelf,CWAL_RCF_IS_DESTRUCTING)) return CWAL_RC_DESTRUCTION_RUNNING;

#if 0
  // To be checked by higher-level containers...

  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
  else{
    cwal_lsize_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;
    }
  }
}
#if 0
static int cwal_htable_remove_impl_cstr( cwal_value * const vSelf,
                                         cwal_htable * const htable,
                                         char const * const key,
                                         cwal_size_t keyLen ){
  if(!vSelf || !key) return CWAL_RC_MISUSE;
  else if(!htable->hashSize || !htable->list.count) return CWAL_RC_NOT_FOUND;




  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;
  else{
    cwal_lsize_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;
    }
  }
}
#endif

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);







|
>


>



<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<



|


>
>
>
>



|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
<







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
17813
17814
17815
17816
17817
17818
17819
17820
          ? (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_size_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);







|







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
17859
17860
17861
17862
17863
17864
17865
17866
17867
17868
17869
17870
17871
17872
17873
17874
17875
17876
17877
17878
17879
17880
17881
17882
17883
17884
17885
17886
17887
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_size_t cwal_string_length_bytes( cwal_string const * str ){
  return str
    ? CWAL_STRLEN(str)
    : 0U;
}


cwal_size_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_size_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);







|






|













|







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
17908
17909
17910
17911
17912
17913
17914
17915
  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_size_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;
  }







|







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
17994

17995
17996
17997
17998
17999
18000
18001
        }
      }
    }
    return s;
  }
}

cwal_string * cwal_new_xstring(cwal_engine * e, char const * str, cwal_size_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







|
>







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
18031

18032
18033
18034
18035
18036
18037
18038
18039
18040
18041
18042
18043
      *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_size_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_size_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){







|
>




|







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
18091
18092
18093
18094
18095
18096
18097
18098
      /* 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_size_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;







|







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
18590
18591
18592
18593
18594
18595
18596





18597
18598
18599
18600
18601
18602
18603
18604




18605
18606
18607
18608
18609
18610
18611
*/
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 ){
  cwal_obase * b = CWAL_VOBASE(v);
  cwal_obase_kvp_iter iter;
  cwal_kvp const * kvp = cwal_obase_kvp_iter_init(v, &iter);
  int rc = CWAL_RC_OK;
  assert(b);
  assert(CWAL_V_IS_RESCOPING(v));
  assert(v->scope);





  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 );
    }
  }




  return rc;
}

int cwal_rescope_children_native( cwal_value * v ){
  int rc;
  cwal_native * n = cwal_value_get_native(v);
  assert(v->scope);








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|
<
<




>
>
>
>
>








>
>
>
>







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
19299
19300
19301
19302
19303
19304
19305
19306
19307
19308




19309

19310
19311
19312
19313
19314
19315
19316
    : CWAL_RC_MISUSE;
}

/**
   The C-string equivalent of cwal_obase_search_v().
*/
static cwal_value * cwal_obase_search( cwal_obase const * base,
                                       char searchProto,
                                       char const * const key,
                                       cwal_size_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;




      kvp = cwal_kvp_search( base->kvp, key, keyLen, prev );

      if(kvp) {
        rc = kvp->value;
        break;
      }
      else base = searchProto ? CWAL_VOBASE(base->prototype) : 0;
    }
    return rc;







|

|







>
>
>
>

>







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
19359
19360
19361
19362
19363
19364
19365
19366
19367



19368

19369
19370
19371
19372
19373
19374
19375
19376
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
19407
19408
19409
19410
19411
19412
19413
19414
19415
19416
19417
19418
19419
19420
19421
19422
19423
19424
19425
19426
19427
19428
19429
19430

19431
19432
19433
19434
19435
19436
19437
19438
19439
19440
19441
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
   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,
                                         char 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;



      kvp = cwal_kvp_search_v( base->kvp, key, prev );

      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_size_t keyLen,
                    char searchPrototype ) {
  cwal_obase * base = CWAL_VOBASE(v);
  if(!base || !key || !*key) return 0;
  else{
    return (searchPrototype
            ? (void const *)cwal_obase_search(base, 1, key, keyLen, NULL )
            : (void const *)cwal_kvp_search(base->kvp, key, keyLen, NULL)
            ) ? 1 : 0;
  }
}

bool cwal_prop_has_v( cwal_value const * v,
                      cwal_value const * key,
                      char searchPrototype ){
  cwal_obase const * base = CWAL_VOBASE(v);
  return (!base || !key)
    ? 0
    : ((searchPrototype
        ? (void const *)cwal_obase_search_v(base, 1, key, NULL )
        : (void const *)cwal_kvp_search_v(base->kvp, key, NULL)
        ) ? 1 : 0)
    ;
}

cwal_value * cwal_prop_get( cwal_value const * v,
                            char const * key, cwal_size_t keyLen ) {
  cwal_obase const * base = CWAL_VOBASE(v);
  if(!base || !key || !*key) return NULL;
  else{
    return cwal_obase_search( base, 1,
                              key, keyLen, NULL );
  }
}


cwal_value * cwal_prop_get_v( cwal_value const * c,
                              cwal_value const * key ) {
  cwal_obase const * base = CWAL_VOBASE(c);
  if(!base || !key) return NULL;
  else{
    return cwal_obase_search_v( base, 1, key, NULL );

  }
}


cwal_kvp * cwal_prop_get_kvp( cwal_value * c, char const * key,
                              cwal_size_t keyLen, char searchProtos,
                              cwal_value ** foundIn ){
  cwal_obase * b = CWAL_VOBASE(c);
  if(!key || !*key || !b) return 0;
  else{
    cwal_kvp * rc = 0;
    while(b){




      rc = cwal_kvp_search(b->kvp, key, keyLen, NULL);

      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,
                                char searchProtos,
                                cwal_value ** foundIn ){
  cwal_obase * b = CWAL_VOBASE(c);
  if(!key || !b) return 0;
  else{
    cwal_kvp * rc = 0;
    while(b){



      rc = cwal_kvp_search_v(b->kvp, key, NULL);

      if(rc){
        if(foundIn) *foundIn = c;
        break;
      }else if(searchProtos
               && (c = b->prototype)
               && (b = CWAL_VOBASE(c))){
        continue;







|








>
>
>

>




















|
|
|
<
<
|
|
<
|
<




|

|
<
<
|
<
|
<



|
|
|
<
|
|
<






|
<
|
>
|
|
<
<

|






>
>
>
>

>















|






>
>
>

>







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
19548
19549
19550
19551
19552
19553
19554
19555
19556
19557
  }else if(rv){
    *rv = maybeFunc;
  }
  return rc;
}

int cwal_prop_getX( cwal_value * c,
                    char processInterceptors,
                    char const * key,
                    cwal_size_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;







|

|







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
19572
19573
19574
19575
19576
19577
19578
19579
      rc = 0;
    }
    return rc;
  }
}

int cwal_prop_getX_v( cwal_value * c,
                      char 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 );







|







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
19596
19597
19598
19599

19600






19601

19602
19603
19604
19605
19606
19607

19608




19609

19610
19611
19612
19613
19614
19615
19616
19617
19618
19619
    }
    return rc;
  }
}


int cwal_prop_unset( cwal_value * const c,
                     char const * key, cwal_size_t keyLen ) {
  cwal_obase * b = CWAL_VOBASE(c);
  cwal_engine * e = b ? CWAL_VENGINE(c) : NULL;
  if(!e) return CWAL_RC_MISUSE;

  else if(CWAL_V_IS_VISITING(c)) return CWAL_RC_IS_VISITING;






  return cwal_kvp_unset( e, &b->kvp, key, keyLen );

}

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_V_IS_VISITING(c)) return CWAL_RC_IS_VISITING;




  return cwal_kvp_unset_v( e, &b->kvp, key );

}


/**
   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.







|
|
|

>

>
>
>
>
>
>

>






>

>
>
>
>

>


|







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
19648
19649
19650
19651
19652
19653
19654
19655
19656
19657
19658
19659
19660
19661
19662
19663
19664
19665
19666
19667
19668
19669
19670
19671
19672
19673
19674
19675

   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;
    char iAlloccedKvp = 0;
    cwal_obase * ob = CWAL_VOBASE(listOwner);
    cwal_kvp ** list = ob ? &ob->kvp : 0;
    assert(ob);
    assert(ob->kvp == *list
           && "just checking - we can factor out the list param.");
    if(CWAL_CONTAINER_DISALLOW_PROP_SET & ob->flags){
      return CWAL_RC_DISALLOW_PROP_SET;
    }
    kvp =
      cwal_kvp_search_v( *list, 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;
      }                 







<









|
|
<

<
<



<
|







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
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
19725
19726
19727
19728
19729
19730
19731
19732
19733
19734
19735
19736
19737
19738
19739
19740
19741
19742
19743

19744
19745
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
19776
19777
19778



19779
19780

19781
19782
19783
19784
19785
19786
19787
19788
19789
19790
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
    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.
    */
    i = 0;
    for( ; 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 || *list==kvp);
    }
    else if(left){
      /* kvp compares > left, so insert it here. */
      cwal_kvp * r = left->right;
      assert(!kvp->right);
      left->right = kvp;
      kvp->right = r;
    }
    else {
      assert(!left);
      /* Make kvp the head of the list */
      assert(*list != kvp);

      assert(!kvp->right);
      kvp->right = *list;
      *list = kvp;
    }
    return CWAL_RC_OK;
  }
}



#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 * b = CWAL_VOBASE(c);
  cwal_engine * e = CWAL_VENGINE(c);
  assert(v ? (!!e || CWAL_MEM_IS_BUILTIN(v)) : 1);
  if( !e || !key ) return CWAL_RC_MISUSE;
  else if(!cwal_prop_key_can(key)) return CWAL_RC_TYPE;
  else if(!b) return CWAL_RC_TYPE;
  else if(CWAL_RCFLAG_HAS(c,CWAL_RCF_IS_DESTRUCTING)) return CWAL_RC_DESTRUCTION_RUNNING;
  else if(CWAL_RCFLAG_HAS(c, CWAL_RCF_IS_VISITING)) return CWAL_RC_IS_VISITING;
  else if(CWAL_CONTAINER_DISALLOW_PROP_SET & b->flags){
    return CWAL_RC_DISALLOW_PROP_SET;
  }



  else if( NULL == v ) {
    return cwal_prop_unset_v( c, key );

  }
  return cwal_kvp_set_v( e, c, key, v, flags );
}

int cwal_prop_setX_with_flags_v( cwal_value * c,
                                 char 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_size_t keyLen, cwal_value * v,
                                uint16_t flags ) {
  cwal_obase * b = CWAL_VOBASE(c);
  cwal_engine * 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 );
  else {
    cwal_value * vkey;
    vkey = cwal_new_string_value(e, key, keyLen);
    if(!vkey) return CWAL_RC_OOM;
    else {
      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,
                               char processInterceptors,
                               char const * key, cwal_size_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_size_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_size_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 * b = CWAL_VOBASE(c);
  cwal_engine * e = CWAL_VENGINE(c);
  assert(c ? !!e : 1);
  if( !e || !b || !e || !key || !*key || !b->kvp) return NULL;
  else if(CWAL_V_IS_VISITING(c)) return NULL;





  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 * left = 0;
    cwal_value * rc = NULL;






    cwal_kvp * kvp = cwal_kvp_search( b->kvp, key,
                                      cwal_strlen(key), &left );

    if( ! kvp ) return NULL;
    rc = kvp->value;
    if(left){

      left->right = kvp->right;
    }else{






      assert(b->kvp == kvp);
      b->kvp = kvp->right /* ? kvp->right : NULL */;

    }



    kvp->right = NULL;
    assert( rc );
    cwal_value_unref2(e, kvp->key);
    kvp->key = 0;
    kvp->value = 0;
    cwal_kvp_free( e, kvp, 1 );
    if(!CWAL_MEM_IS_BUILTIN(rc)){
      assert( (CWAL_REFCOUNT(rc) > 0) && "Should still have kvp's reference!" );
      cwal_value_unhand(rc);
    }
    return rc;
  }
}

cwal_value * cwal_prop_take_v( cwal_value * c, cwal_value * key,
                               cwal_value ** takeKeyAsWell ){
  cwal_obase * b = CWAL_VOBASE(c);
  cwal_engine * e = CWAL_VENGINE(c);
  assert(c ? !!e : 1);




  if( !e || !b || !e || !key || !b->kvp) return NULL;

  else if(CWAL_V_IS_VISITING(c)) return NULL;
  else {
    cwal_kvp * left = 0;
    cwal_value * rc = 0;





    cwal_kvp * kvp = cwal_kvp_search_v( b->kvp, key, &left );

    if( ! kvp ) return NULL;
    rc = kvp->value;
    if(left){

      left->right = kvp->right;
    }else{






      assert(b->kvp == kvp);
      b->kvp = kvp->right;

    }



    kvp->right = NULL;
    assert( rc );

    if(takeKeyAsWell){
      *takeKeyAsWell = kvp->key;
    }else{
      cwal_value_unref2(e, kvp->key);
    }
    kvp->key = 0;
    kvp->value = 0;
    cwal_kvp_free( e, kvp, 1 );
    if(takeKeyAsWell && !CWAL_MEM_IS_BUILTIN(*takeKeyAsWell)){
      assert( (CWAL_REFCOUNT(*takeKeyAsWell) > 0) && "Should still have our reference!" );
#if 1
      cwal_value_unhand(*takeKeyAsWell);
#else
      if(0==CWAL_RCDECR(*takeKeyAsWell)){
        cwal_value_reprobate(1 ? (*takeKeyAsWell)->scope
                             : (*takeKeyAsWell)->scope->e->current /*?*/, vk);
      }
#endif
    }

    if(!CWAL_MEM_IS_BUILTIN(rc)){
      assert( (CWAL_REFCOUNT(rc) > 0) && "Should still have our reference!" );
      cwal_value_unhand(rc);
    }
    return rc;
  }

}

/**
   "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.








<
|










|
<



















|
<
|

|



<
|
<

|
>

|
|




>
>

















|
|

|
|
<

|



>
>
>
|
|
>

|



|

















|

|
|





>
|
>
>

<
<
|
|
<
|
|
|
|
|
<
<



|
|






|






|




|
|

<
|
>
>
>
>
>









>

|
>
>
>
>
>
>
|
|
>
|
|

>


>
>
>
>
>
>
|
|
>

>
>
>

|


|

|
|
|

|





|
|

>
>
>
>
|
>

|

|
>
>
>
>
>
|
>
|
|

>


>
>
>
>
>
>
|
|
>

>
>
>

<
>


<
<
<
|
<
<
<
<
<

<
<
<
<
|
<
<
>
|
|
|

|

<







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
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
  }
}

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(!e || !c) return CWAL_RC_MISUSE;
  else if(!b) return CWAL_RC_TYPE;
  else if(CWAL_CONTAINER_DISALLOW_PROP_SET
          &b->flags){
    return CWAL_RC_DISALLOW_PROP_SET;
  }
  else {
    /**
       We need a mechanism for clearing properties stored in other
       places in higher-level types, e.g. we might need to add a
       public API which simply calls c->vtab->cleanup(c). For arrays,
       however, that would end badly.
    */
    cwal_cleanup_obase( e, b, 0 );
    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;




  else{
    return cwal_kvp_set_v( e, dest, kvp->key, kvp->value,
                           /* We have to keep the property
                              flags intact... */
                           kvp->flags );
  }

}

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;*/
  else 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);



  return b && b->kvp ? 1 : 0;

}

cwal_size_t cwal_props_count( cwal_value const * c ){
  cwal_obase const * b = CWAL_VOBASE(c);

  if(!b) return 0;
  else{
    cwal_size_t rc = 0;
    cwal_kvp const * kvp = b->kvp;
    for( ; kvp ; ++rc, kvp = kvp->right ){}
    return rc;

  }
}


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;







<
|
|
<

<
|
<
<
<
<
<
<
|



<







>
>
>
>
|
|
<
<
<
<
>









|




>
>
>

>


|

>
|
|
|
|
|
|
>
|
<
<







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
20109
20110

20111
20112
20113
20114
20115
20116
20117
20118
20119
20120
20121
20122

20123
20124
20125
20126
20127
20128
20129

bool cwal_value_may_iterate( cwal_value const * const c ){
  if(!c) return 0;
  else if(CWAL_MEM_IS_BUILTIN(c)){
    return 0;
  }
  else{
    cwal_obase const * const ob = CWAL_VOBASE(c);
#if 0

    /* 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 ob ? 1 : 0;
#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){







<

>




|







>







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
20153
20154
20155
20156
20157

20158
20159
20160
20161
20162
20163
20164
20165
    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 = b->kvp;
         kvp && (0==rc);
         kvp = cwal_obase_kvp_iter_next(&iter) ){
      if(!(CWAL_VAR_F_HIDDEN & kvp->flags)){
        /* to support modification during traversal, we'll need

           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);







<
|


<
>
|







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
20673
20674
20675
20676
20677
20678
20679
20680
20681
20682
20683
20684
20685
20686
20687
20688
20689
20690
20691
20692
20693
20694
20695
20696
20697
20698
20699
20700
20701
20702
20703
20704
20705
20706
20707
20708
20709
20710
20711
20712
20713
20714
20715
20716
20717
20718
20719
20720
20721
20722
20723
20724
20725
20726
20727
20728
20729
    ? 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;
  if(!e) return;
  else{
    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;
}

static int cwal_rescope_children_hash( cwal_value * v ){
  cwal_hash * h = CWAL_HASH(v);
  cwal_scope * sc = v->scope;
  cwal_kvp * kvp;
  cwal_size_t i;
  int rc;
  assert(sc && h && v);
  assert(CWAL_V_IS_RESCOPING(v));
  rc = cwal_rescope_children_obase(v);
  if(rc){
    assert(!"This should not be possible.");
  }
  /* cwal_dump_v(nv,"Re-scoping hashtable children..."); */
  for( i = 0; !rc && (i < h->htable.hashSize); ++i ){
    kvp = (cwal_kvp*)h->htable.list.list[i];
    if(kvp){
      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"); */
      }
    }
  }
  return rc;
}

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);







<
|
|
|
|
|
|
<
<










|


<
<
<


|
<
<
<

<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|







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
20763
20764
20765
20766
20767
20768
20769
20770
20771
20772
20773
20774
20775
20776
}

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_size_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_size_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 ){







|





|







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
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
20830
20831
20832
20833
20834
20835


20836
20837
20838
20839
20840
20841
20842
20843
20844
20845
20846
20847
20848
20849
20850
20851
20852
20853
20854

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_size_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_size_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_size_t keyLen ){
  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_remove_v(h, vKey);
  cwal_value_unref(vKey);
  return rc;
}

cwal_lsize_t cwal_hash_entry_count(cwal_hash const *h){
  return h->htable.list.count;
}

cwal_lsize_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 {







|














|








|




|
|
<
<
|
>
>
|
<
<
<
|


|



|







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
20929
20930
20931
20932
20933
20934
20935
20936
20937
20938
20939
20940
20941
20942
20943
  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);
}

/**
   Returns the "next higher" prime number starting at (n+1), where "next"
   is really the next one in a list of rather arbitrary prime numbers.
   If n is larger than some value which we internally (and almost
   arbitrarily) define in this code, a value smaller than n will be
   returned.
*/
cwal_hash_t cwal_next_prime( cwal_hash_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];







<
<
<
<
<
<
<
|







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
20981
20982
20983





20984
20985
20986
20987
20988
20989
20990

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 ){





  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
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
21357
21358
21359
21360
21361
21362
21363
21364
21365
21366
21367
21368
21369
21370
21371
21372
21373
21374
   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,
                                char 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).  FIXME: add a
       setter which accounts for this stuff in one go. We need an
       internal cwal_var_get_kvp() which gives us the cwal_kvp
       associated with the var.
    */
    cwal_scope * foundIn = 0;
    int rc = 0;
    /* cwal_value * got = 0; */
    cwal_scope * origin = s;
    cwal_hash * h;
    cwal_kvp * kvp = 0;







|






|
<
<
<







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
21418
21419
21420
21421
21422
21423
21424
21425
21426
21427
21428
21429
21430
21431
21432
21433
21434
21435
21436
21437
21438
21439
21440
21441

21442
21443
21444



21445





21446
21447

21448


21449
21450
21451
21452
21453
21454
21455
    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;
    }
    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);
      return rc;
    }else{

      cwal_obase * b = CWAL_VOBASE(foundIn->props);
      return v
        ? cwal_kvp_set_v( e, foundIn->props,



                          key, v, flags )





        : cwal_kvp_unset_v( e, &b->kvp, key )
        ;

    }


  }
}
    
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 );







>













>
>

>
>
>
>
>












|
















<



|
<

>
|
|
|
>
>
>
|
>
>
>
>
>
|
<
>

>
>







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
21513
21514
21515
21516
21517
21518
21519
21520
21521
21522
21523
21524
      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







<
|
<
|
<







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
21545
21546
21547
21548
21549
21550
21551
21552
  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_size_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 ){







|







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
21577
21578
21579
21580
21581
21582
21583
21584
    }
    return kvp;
  }
}

cwal_value * cwal_scope_search( cwal_scope * s, int upToDepth,
                                char const * key,
                                cwal_size_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,







|







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
21653
21654
21655
21656
21657
21658
21659
21660
21661
21662
21663
21664
21665
21666
21667
21668
21669
21670
21671
21672
21673
21674
21675

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_size_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_size_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,







|














|







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
21694
21695
21696
21697
21698
21699
21700
21701
            : 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_size_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);







|







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
22951
22952
22953
22954
22955
22956
22957
22958
  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 ev ){
  switch(ev){
#define CASE(X) case CWAL_TRACE_##X: return #X
    CASE(NONE);
    CASE(ALL);

    CASE(GROUP_MASK);
        







|







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
23042
23043
23044
23045
23046
23047
23048
23049
               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_SIZE_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{







|







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
23863
23864
23865
23866
23867
23868
23869
23870
23871

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_size_t cwal_strlen( char const * str ){
  return str ? (cwal_size_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);
}







|
|







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
24382
24383
24384
24385
24386
24387
24388
24389
24390
24391
24392
24393

24394
24395
24396
24397
24398
24399
24400
#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.");
#endif
#ifdef DEBUG
  assert(CWAL_VOBASE(v) && "Invalid use of cwal_visit_props_end()");
#endif
  assert(v);
  assert(visitOpaqueMarkerYes==opaque || visitOpaqueMarkerNo==opaque);
  if(visitOpaqueMarkerYes==opaque){
    CWAL_RCFLAG_OFF(v,CWAL_RCF_IS_VISITING);
#if CWAL_OBASE_ISA_HASH
    ob->hprops.list.isVisiting = false;
#endif

  }
}

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);







|
<
|





<



>







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
24688
24689
24690
24691
24692
24693
24694
24695
24696
24697
24698
24699
24700
24701

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.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_lsize_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;







|





|







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
28742
28743
28744
28745
28746
28747
28748
28749
        || (c&0xFFFFF800)==0xD800
        || (c&0xFFFFFFFE)==0xFFFE ){  c = 0xFFFD; }
  }
  return c;

}

cwal_size_t cwal_strlen_utf8( char const * str, cwal_size_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.







|







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
28904
28905
28906
28907
28908
28909
28910
28911
28912
    }
  }


  int cwal_string_case_fold( cwal_engine * e,
                             cwal_string const * str,
                             cwal_value **rv,
                             char doUpper ){
    cwal_size_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







|
|







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
28936
28937
28938
28939
28940
28941
28942
28943
28944
28945
    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_size_t len,
                                     cwal_buffer *buf,
                                     char 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 ||







|

|







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
28997
28998
28999
29000
29001
29002
29003
29004
29005
29006
    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_size_t len,
                           cwal_value **rv,
                           char 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;
    }







|

|







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
34567
34568
34569
34570
34571
34572
34573
34574

   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_size_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)){







|







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
48226
48227
48228
48229
48230
48231
48232
48233
   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_size_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;







|







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
49672
49673
49674




49675
49676
49677
49678
49679
49680
49681
    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_size_t nameLen, cwal_value * v){
  int rc;
  cwal_value * const k = cwal_new_string_value(se->e, name, nameLen);




  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);
  }







|

|
>
>
>
>







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
57007
57008
57009
57010
57011
57012
57013
57014
57015
57016
57017
57018
57019
57020
57021
57022
57023
57024
57025
57026
57027
57028
    ? (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_size_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_size_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])







|













|







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
57119
57120
57121
57122
57123
57124
57125
57126
                       "Expecting a non-empty string argument.");
  }else if(!needleLen){
    *rv = args->self;
    return 0;
  }else{
    int rc = 0;
    cwal_int_t matchCount = 0;
    cwal_size_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







|







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
57211
57212
57213
57214
57215
57216
57217
57218
    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_size_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;
      }







|







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
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 5e0ce36380232ca65276e76e4486da278e6247b5 2021-07-10 22:22:18 built 2021-07-11 08:10"
#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 -Wimplicit-fallthrough=5  -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: */







|








|







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
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_lsize_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 and hashtables). The "l" is for "list".
*/

/** @typedef some_signed_integer cwal_int_t

    This is the type of integer value used by the library.

*/

/** @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, and thus may need
    to be larger than cwal_size_t).
*/

/** @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... */







|



|




|
>






|
<




|







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
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
#  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

/* Set up CWAL_LSIZE_... */
#if CWAL_SIZE_T_BITS == 16
    typedef uint16_t cwal_lsize_t;
#  define CWAL_LSIZE_T_PFMT CWAL_SIZE_T_PFMT
#  define CWAL_LSIZE_T_PFMTx CWAL_SIZE_T_PFMTx
#  define CWAL_LSIZE_T_PFMTX CWAL_SIZE_T_PFMTX
#  define CWAL_LSIZE_T_PFMTo CWAL_SIZE_T_PFMTo
#  define CWAL_LSIZE_T_SFMT CWAL_SIZE_T_SFMT
#  define CWAL_LSIZE_T_SFMTX CWAL_SIZE_T_SFMTX
#  define CWAL_LSIZE_T_MAX CWAL_SIZE_T_MAX
#else
    typedef uint32_t cwal_lsize_t;
#  define CWAL_LSIZE_T_PFMT PRIu32
#  define CWAL_LSIZE_T_PFMTx PRIx32
#  define CWAL_LSIZE_T_PFMTX PRIX32
#  define CWAL_LSIZE_T_PFMTo PRIo32
#  define CWAL_LSIZE_T_SFMT SCNu32
#  define CWAL_LSIZE_T_SFMTX SCNx32
#  define CWAL_LSIZE_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







>

















|

|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|







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

637
638


639
640
641
642
643
644
645
   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. */


#  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 */







>
|
|
>
>







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
1389
1390
1391
1392
1393
1394
1395
1396

   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 {

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),







|







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
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
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 values except CWAL_TRACE_NONE.
*/
CWAL_TRACE_ALL = 0x7FFFFFFF/*1..31*/

};
/**
   Convenience typedef.
*/
typedef enum cwal_trace_flags cwal_trace_flags;

    
#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 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;







|







|









|







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
1554
1555
1556
1557
1558
1559
1560
1561
1562
   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 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,







|
|







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
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
/**
   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 wrapped by the
    call()'d Function.
*/
struct cwal_callback_args{
  /**
     The engine object making the call.
  */
  cwal_engine * engine;
  /**







|
|
|
|
|
|







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
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
   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 implements 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 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).



   
   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.

   This interface is the heart of client-side cwal bindings, and any
   non-trivial binding will likely have many functions of this type.
*/
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







|
|



|




>
>
>








<
<
<







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
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
     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_lsize_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_lsize_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.
  */







|






|







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
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

   @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_size_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_size_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,







|




















|







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
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
                                       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_size_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_size_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.








|










|







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
4648
4649
4650
4651
4652
4653
4654
4655
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_size_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.








|







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
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

/**
   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_size_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_size_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







|
>




















|







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
5642
5643
5644
5645
5646
5647
5648
5649
5650
5651
   - 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_size_t cstrLen,
                         cwal_value **rv,
                         char 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







|

|







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
5675
5676
5677
5678
5679
5680
5681
5682
5683
   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_size_t len, cwal_buffer *buf,
                                   char 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.







|
|







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
5718

5719
5720
5721
5722
5723
5724
5725
5726
5727
5728
5729
5730

5731
5732
5733
5734
5735
5736
5737
5738
5739
                              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.


   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_utf8.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,

                           char 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







|
>






|




|
>
|
<







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
5784

5785
5786
5787
5788
5789
5790
5791
   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_size_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







|
>







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
5846

5847
5848
5849
5850
5851
5852

5853
5854
5855
5856
5857
5858
5859

   - 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_size_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_size_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,







|
>





|
>







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
5924

5925
5926
5927
5928
5929
5930

5931
5932
5933
5934
5935
5936
5937
   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_size_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_size_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.







|
>





|
>







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
6086
6087
6088
6089
6090
6091
6092
6093
6094
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
*/
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_size_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_size_t cwal_strlen_utf8( char const * str, cwal_size_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_size_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_size_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.








|









|






|











|







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
7054

7055
7056
7057
7058
7059
7060
7061

   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







|
>







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
7361

7362
7363
7364
7365
7366
7367
7368
7369
7370
7371
7372
7373
7374
7375
7376
7377
7378
7379
7380
7381

7382
7383
7384
7385
7386
7387
7388
   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_size_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_size_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").








|
>



















|
>







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
7414
7415
7416
7417
7418
7419
7420
7421
7422
7423
7424
7425
7426
7427
7428
7429
7430
   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, char processInterceptors,
                    char const * key, cwal_size_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, char 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).







|
|







|







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
7446
7447
7448
7449
7450
7451
7452
7453

   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_size_t keyLen, char 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







|







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
7482
7483
7484
7485
7486
7487
7488
7489
   @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,
                                char 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







|







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
7642
7643
7644
7645
7646
7647
7648
7649
7650
7651
7652
7653
7654
7655
7656
7657

7658
7659
7660
7661
7662
7663
7664
7665
7666
7667
7668
7669
7670
7671
   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_size_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_size_t keyLen, cwal_value * v );

/**
   UNTESTED! EXPERIMENTAL! DO NOT USE!
*/
int cwal_prop_setX_with_flags( cwal_value * c,
                               char processInterceptors,
                               char const * key,

                               cwal_size_t keyLen, cwal_value * v,
                               uint16_t flags );

/**
   UNTESTED! EXPERIMENTAL! DO NOT USE!
*/
int cwal_prop_setX_with_flags_v( cwal_value * c, char 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).








|







|





|

>
|





|







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
7708
7709
7710
7711
7712
7713
7714
7715
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_size_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







|







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
7751

7752
7753
7754
7755
7756
7757
7758
7759
7760
7761
7762
7763
7764
7765
7766
7767
7768
   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_size_t keyLen,

                    char 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,
                      char searchPrototype );
    
/**
   Returns the virtual type of v, or CWAL_TYPE_UNDEF if !v.
*/
cwal_type_id cwal_value_type_id( cwal_value const * v );

/**







|
>
|








|







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
8692

8693
8694
8695
8696
8697
8698
8699
8700
8701
8702
8703
8704
8705
8706
8707

8708
8709
8710
8711
8712
8713
8714

   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_size_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_size_t keyLen );


/**
   Returns true (non-0) if v is of the concrete type cwal_hash.
*/
bool cwal_value_is_hash( cwal_value const * v );

/**







|
>














|
>







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
8808

8809
8810
8811
8812
8813
8814
8815
8816
8817
8818
8819
8820
8821
8822
8823
/**
   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_size_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_size_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







|
>







|







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
8848
8849
8850
8851
8852
8853
8854
8855
8856
8857
8858
8859
8860
8861
8862
8863
8864
8865
8866
/**
   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_size_t keyLen );

/**
   Returns the number of entries in the given hash,
   or 0 if !h. This is an O(1) operation.
*/
cwal_lsize_t cwal_hash_entry_count(cwal_hash const * h);

/**
   Returns the table size of h, or 0 if !h.
*/
cwal_lsize_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).







|





|




|







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
8924
8925
8926
8927
8928
8929
8930
8931
8932
8933
8934
8935
8936
8937
8938
8939
8940
8941
8942
8943
8944



8945
8946
8947
8948
8949
8950
8951
8952
8953
8954
8955
8956
8957
8958
8959
8960
8961
8962
8963
   (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_hash_t cwal_next_prime( cwal_hash_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_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







|
<



















>
>
>










<
<







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
10004
10005
10006
10007
10008
10009
10010
10011
10012
10013
10014
*/
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 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







|
|
|
|







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
19184
19185


19186
19187
19188
19189
19190
19191
19192
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. Its bytes are
   copied, so it need not have a well-defined lifetime.



   "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







|
|
>
>







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
19235
19236
19237
19238
19239
19240
19241
19242
   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_size_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







|







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
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
  return 0;
}
#endif

static int s2sh_setup_s2_global( s2_engine * se ){
  int rc = 0;
  cwal_value * v = 0;
  cwal_engine * 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




  /*
    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", v);
    assert(CWAL_RC_ACCESS==rc);
    rc = s2_define_ukwd(se, "print", v);
    RC;
    rc = s2_define_ukwd(se, "print", v);
    assert(CWAL_RC_ALREADY_EXISTS==rc);
    rc = 0;
  }else
#endif
  {
    rc = cwal_var_decl(e, 0, "print", 5, v, 0);
    RC;







|




>
>
>












|

|

|







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

9
10
11
12
13
14
15
16

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 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);








>
|







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
51
52
53
54


55
56
57
58

59
60
61
62
63
64
65

scope {
  assert o.mayIterate();
}

scope {
    o.a = 3, o.b = 7, o.c = 42.24, o.d = [1,2,3], o.1 = -1;
    var json = o.toJSONString(' ');
    var o2 = eval -> json;
    assert typename o === typename o2;
    assert o2.d[1] === o.d[1];


    assert o2.toJSONString(1) === json;
    var 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');







|
|


>
>
|
|
|
|
>







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

142
143
144

145
146
147
148
149
150
151
             // 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 */;

    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







>
|
|
|
>







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
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! */;
}

scope { /* takeProperties() */

    var src, h;
    const reset = proc(){
        src = {a:1, b:-1, c:0};
        h = s2.Hash.new(5);
    };
    reset();







|







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();
}