Version 3 of Array enumeration

Updated 2016-11-24 19:26:23 by AMG

AMG: Tcl arrays are enumerated via the [array names] or [array get] commands or by the (virtually obsolete) combination of [array startsearch], [array nextelement], [array anymore], and [array donesearch]. At present, they cannot be enumerated via the Tcl C API. The FlightAware Tcl bounty program [L1 ] seeks to address this and other Tcl shortcomings.

I intend to implement a Tcl C API for enumerating array elements. I am patterning my API on Tcl API listed above and on the C API for accessing variables. The implementation will be obtained by rearranging existing code as much as possible to minimize the inadvertent introduction of new bugs. The above-listed [array] commands will be reimplemented as calls into the new C API so that it can be tested by the existing Tcl test suite.

This will be my first TIP and my first case of Tcl core programming. Outside of random bug and documentation fixes, my Tcl C experience is writing proprietary Tcl extensions over the last 10-15 years, and my Tcl scripting experience goes back to 1999.


Code

http://core.tcl.tk/tcl/timeline?t=amg-array-enum-c-api


API

Here is my working API design. Please share any comments or questions you may have. I welcome opinions about the alternatives and wishes I outline below, and please feel free to add your own ideas.

/* Tcl_ArraySearch is an opaque pointer to struct ArraySearch which has
 * the search internals.  The term "search" is reused for the C API even
 * though it's actually a full enumeration. */
typedef struct ArraySearch *Tcl_ArraySearch;

/* Common argument definitions.  See Tcl_SetVar(3) for details. */
Tcl_Interp *interp (in)
Tcl_Obj *varNamePtr (in)
int *objcPtr (out)
Tcl_Obj ***objvPtr (out)
Tcl_ArraySearch search (in): obtained from Tcl_ArraySearchStart()
int flags (in): TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY | TCL_LEAVE_ERR_MSG

/* Returns array size or -1 on error.  For compatibility with [array
 * size], 0 is returned if the variable is a scalar or does not exist.
 *
 * Alternative: Take an intPtr argument and return TCL_OK or TCL_ERROR.
 * This approach matches Tcl_ListObjLength(). */
int
Tcl_ArraySize(interp, varNamePtr, flags)

/* Returns a Tcl_ArraySearch on success or NULL on error.
 *
 * Wish: Optional glob filter to match [array names]. */
Tcl_ArraySearch
Tcl_ArraySearchStart(interp, varNamePtr, flags)

/* Returns name of next element or NULL if finished. */
Tcl_Obj *
Tcl_ArraySearchNext(search)

/* Cleans up array search internals.
 *
 * Alternative name: Tcl_ArraySearchStop(). */
void
Tcl_ArraySearchDone(search)

/* Gets a list of all array element names.  Call ckfree() on objvPtr
 * when done.
 *
 * Alternative: Give caller the option to manage objvPtr memory
 * directly.  Only automatically allocate if *objvPtr is NULL, otherwise
 * assume it points to a block of memory big enough for Tcl_ArraySize()
 * Tcl_Obj pointers.
 *
 * Alternative: Hybrid approach.  If *objvPtr is not NULL and *objcPtr
 * is at least Tcl_ArraySize(), use it directly as described above.  If
 * *objvPtr is not NULL but *objcPtr is insufficient, attemptckrealloc()
 * *objvPtr to the minimum required size.  This way, Tcl_ArrayGetNames()
 * can be used many times in a row without allocating and freeing memory
 * more than needed.  Changes objcPtr and objvPtr to be (in/out).  Even
 * if glob filter wish is implemented, would still allocate to match the
 * array size just in case the filter ends up matching everything.
 *
 * Alternative name: Tcl_ArrayGetNames().
 *
 * Wish: Optional glob filter to match [array names]. */
int
Tcl_ArrayNames(interp, varNamePtr, objcPtr, objvPtr, flags)

Progress

20 November 2016
Began work, implemented Tcl_ArraySize().
24 November 2016
Published commits, fixed [array size] reporting of trace errors.