back to index

Introduction

An array is a sequential field (indexed by integers) of ints, floats, Objects or dynamically typed elements. Arrays are the most frequently used type of data container in programming. Other container classes include Pools, Lists, Trees and HashTables.

Most arrays can be used like "lists", i.e. you can add(), insert() and delete() elements. Usually this is quite expensive in terms of CPU time since preceeding/succeeding elements have to be copied. Please use the List class if you need real lists.

C++ array classes

From a technical point of view, an array is also an instance of a C++ API class, i.e. there are dedicated array classes for different element types:

int           -> IntArray 
float         -> FloatArray
String        -> StringArray
Pointer       -> PointerArray 
<c++class>    -> ObjectArray
<scriptclass> -> ClassArray
var           -> ValueArray

The [] operator

Each of these array classes supports the [] operator which is used to read or modify elements.

Example:

int ia[10]; // create IntArray with 10 elements
ia[2]=3; // set an array element
print ia[2]; // print an array element

The array size initialisation may be omitted since version 0.9.0.6. Example:

IntArray ia; // create empty IntArray object
ia[2]=3;     // set an array element, resize/alloc array elements
print ia[2]; // print an array element

Resizing arrays

The alloc(), realloc() and free() methods are used to determine or change the size of an array resp. free its elements.

If an array is resized using the realloc() method, its old content is preserved if possible. If the new array size is smaller than the number of previously used elements, (oldNumElements-newMaxElements) will be discarded.

There are hardcoded limits for the number of elements in arrays which are by default set to

#define TKS_MAX_INTARRAYALLOCSIZE (1024*1024*128)
#define TKS_MAX_FLOATARRAYALLOCSIZE (1024*1024*128)
#define TKS_MAX_ARRAYALLOCSIZE (1024*1024*4) // objects

Since version 0.9.0.6 tkscript automatically resizes your array if writing to an index >= maxElements. This behaviour can be turned off with the commandline option "-nra, --noarrayautoresize".

Example:

IntArray ia; ia.alloc(10); // create IntArray with 10 elements
ia[5]=42;       // set the 6. array element, also changes numElements
ia.realloc(20); // resize array
print ia[5];    // read an element

Element tracking and buffered arrays

Each array keeps track of the number of elements actually in use (numElements) as well as the maximum number of elements available (maxElements). Upon creation of an array, the maxElements property is initialized with the value passed to the alloc() method, numElements will be set to 0, though.

The empty() method is used to reset numElements without actually discarding the elements.

Array lists

Single elements can be added resp. removed by using the add(), insert() and delete() methods. This mode of operation resembles lists, hence the term array list. In contrary to real lists, the maximum list length is limited by the number of allocated elements, though.

Please use the List class if you need real lists.

Example:

float fa[100];
loop(fa.maxElements)
   fa.add( rnd(1.0) );

fa.realloc(200);
loop(fa.MaxElements-fa.numElements)
   fa.add( rnd(1.0) );

print "fa.numElements=" + fa.numElements;
fa.empty();
print "empty()";
print "fa.numElements =" + fa.numElements + " fa.maxElements =" + fa.maxElements;



Associative Arrays (Hashtables)

Unlike regular arrays, Hashtables are not indexed sequentially. Instead, named keys (Strings) are used to calculate the actual (internal) index using a so called hash function.

Furthermore, each HashTable element may have its individual type which is determined by the expression result being assigned to it. If this result value represents an unbound pointer, no explicite pointer assignment is required to bind that pointer to a HashTable element slot.

Also see here.

Example:

HashTable ht;
ht["myint"]=42;              // store an int value
ht["myfloat"]=1.23;          // store a float value
ht["mystr"]="hello, world."; // bind constant pointer
ht["myobj"]=new IntArray;    // bind r/w pointer to HashTable slot
if ht.exists("myobj")        // test if hash entry exists
    print "found slot \"myobj\"";
else
    stderr "d'oh.";

ht.delete("myobj");



Example:

int n=150; // http://www.bagley.org/~doug/shootout/bench/hash2
HashTable hash1; hash1.alloc(10000);
HashTable hash2; hash2.alloc(10000);
int i=0;
for(i=0; i<10000; i++)
   hash1["foo_" + i] = i;
String k;
loop(n)
   foreach k in hash1
      hash2[k] += hash1[k];


Array initializers

The values of array elements may be set by either assigning single values or by using the following array initializer expressions:

Example:

StringArray str <= [ "one", "two", "three" ];
FloatArray  flt <= [ 1.1, 2.2, 3.3 ];
IntArray    ia  <= [ 1, 2, 3 ];
HashTable   ht  <=#["myint"=42, "myfloat"=1.23, "mystr"="hello, world.", "myobj"=new IntArray];

The first element of an array initializer determines the type of array to be created. HashTable initializers are preceeded by the # char.

Note: The return value (i.e. an array object) of an array initializer is constant, i.e. read-only!

Nevertheless, when the initialization expression is called more than once, the expression lists are evaluated again and the elements of the array are updated.

Multidimensional arrays

A multidimensional array is constructed by using an array of pointers that point to IntArrays, FloatArrays, StringArrays or PointerArrays:

Example:

int i;
PointerArray mda <= [ [1,2,3], [4,5,6], [7,8,9] ];

IntArray ia <= mda[0];
i=ia[2];
print "ia[2]=mda[0][2]="+i;

i=mda[2][1];
print "mda[2][1]="+i;

Hash of hashes

The HashTable class can store arbitrary datatypes (including pointers) therefore the declaration and handling of multidimensional hash tables is fairly straight forward:

Example:

HashTable mht <= #[
   "ht1"=#["one"=1, "two"=2.2],
   "ht2"=#["three"=3, "four"=4.4]
];

HashTable ht <= mht["ht2"];

print mht["ht1"]["two"];

Note: Similar to array initializers, the #[] hash table initializer returns constant objects. Nevertheless, when an initialization expression is called more than once, the expression lists are evaluated again and the elements of the hash table are updated.

Pools

A Pool is a container for uniform objects which are not accessed sequentially but rather using so called name-IDs.

The main advantage rests with the fast qAlloc() and qFree() methods; a linear search for free elements is not required even after many nested alloc/free calls.

Example:

Pool p; p.template=String; p.alloc(10);
int nameid;
loop(10) {
   nameid=p.qAlloc();
   p[nameid]="test"+rnd(1024);
}
foreach nameid in p 
   print "p["+nameid+"]="+p[nameid];


Example:

class MyPoolEntry {
   String name;
}

function main() {
   Pool pool;
   int i;
   int id;
   MyPoolEntry ce;
   String s;

   pool.template=MyPoolEntry;
   pool.alloc(32);
   loop(10)
   {
      id=pool.qAlloc();
      ce<=pool[id];
      ce.name="poolentry_"+id;
   }

   i=0;
   foreach id in pool
   {
      trace("foreach qFree i=="+i);
      if(++i<5)
      {
         // detach entry, does not affect iterated list
         pool.qFree(id);
      }
      else
         break; // end foreach
   }
   
   foreach id in pool
   {
      ce<=pool[id];
      s<=ce.name;
      trace("foreach entry \""+s+"\"\n");
   }

   pool.free();
}

Lists

Lists are used to store an arbitrary number of dynamically typed, double-linked elements. A list is composed of ListNodes which can also be created on-the-fly using the list expression.

Examples:

ListNode l;

l =  {1,2,new String};        // copy list (grab objects)
l <= {1,2}+{3,4,new String};  // concat lists (reference objects)
l <= {1,2}^{3,4,new String};  // concat lists (grab objects)    

Also see list.tks, tgclso_lists.tks

Trees

A tree is basically a special form of a double-linked list and consists of TreeNodes which are linked to their predecessor (parent), to nodes on the same hierarchy level ("left") resp. to branching off sub-trees ("right"). Each TreeNode may furthermore store an object pointer to reference abitrary user data.

Example: (requires input.xml)

String s;

if(!s.loadLocal("input.xml", 1))
   die "cannot load input file.";

TreeNode troot<=s.parseXML();
if(troot)
{
    trace "tree has "+troot.numNodes+" nodes.";
    HashTable ht;
    troot.writeToHashTable(ht);
    String key; foreach key in ht {
       print "ht[\""+key+"\"]="+ht[key];
    }
}
else
   die "parseXML failed.";

JIT compiled arrays

The TkScript JIT compiler has special support for int and float arrays. The following things should be kept in mind when using the JIT:

Examples: see IntArray, juliaattractor.tks


back to index

TkScript and the TkScript documentation are (c) Copyright 2001-2004 by Bastian Spiegel.