OpenGATE Contents | GATE development concepts: Arrays

Problem description

Arrays are individually typed compound structures. We talk about “array of int”, “array of string”, “array of some-struct” and so on. There is no generic C-style array that can cover all variants of them.

How are arrays terminated?
How can we iterate over them?
How can we add or remove values?

There are a lot of open questions regarding how arrays need to be designed before they can be transferred between different library layers.

Solution

The GATE framework differs between

Dynamically created arrays are created as and array list where all required content can be added and modified.
When all modifications are completed, an array list can be converted into a fixed-size array (array range) that can be accessed similar like plain C pointers to single array entries.

While primitive types do not need special treatment within an array (they are just mem-copied), complex types might need special handling when one entry is added, moved or destroyed.
Therefore GATE arrays can utilize copy-constructor and destructor function callbacks to apply type-specific behavior with the generic array structure.

The GATE C++ layer uses this feature to inject its copy-constructor and destructor methods into native C code, which makes the plain C-array C++ aware.
Foreign codes can take ownership of GATE C arrays without knowing how to manage its contained types, the array object itself manages lifetimes based on reference counting.

C Example

 1#include <gate/arrays.h>
 2#include <gate/strings.h>
 3
 4static void consume_int_array(gate_array_t* arr)
 5{
 6  /* iterate by array index */
 7  gate_size_t count = gate_array_length(arr);
 8  gate_size_t index;
 9  for(index = 0; index != count; ++index)
10  {
11    int const* ptr_entry = gate_array_get(arr, index);
12  } 
13}
14
15static void consume_string_array(gate_array_t* arr)
16{
17  /* iterate by enumerator interface */
18  gate_enumerator_t e;
19  gate_string_t const* ptr_entry;
20  gate_array_enumerate(arr, &e);
21  while(gate_enumerator_valid(&e))
22  {
23    ptr_entry = (gate_string_t const*)gate_enumerator_get(&e);
24    gate_enumerator_next(&e);
25  }
26}
27
28static void dynamic_int_array()
29{
30  gate_array_t final_array;
31  /* create arraylist for plain data type */
32  gate_arraylist_t list = gate_arraylist_create(sizeof(int), NULL, 0, NULL, NULL);
33  
34  int a = 42;
35  int b = 24;
36  gate_arraylist_add(list, &a);
37  gate_arraylist_add(list, &b);
38  
39  /* turn array list into immutable array */
40  gate_array_create(&final_array, list);
41  gate_arraylist_release(list);
42
43  consume_int_array(&arr);
44  gate_array_release(&final_array);
45}
46
47static void dynamic_string_array()
48{
49  gate_array_t final_array;
50  /* create list of strings using string copy-ctor and dtor */
51  gate_arraylist_t list = gate_arraylist_create(
52      sizeof(gate_string_t), NULL, 0, 
53      &gate_string_copy_constructor, &gate_string_destructor);
54  
55  gate_string_t a = GATE_STRING_INIT_STATIC("Hello");
56  gate_string_t b = GATE_STRING_INIT_STATIC("World");
57  gate_arraylist_add(list, &a);
58  gate_arraylist_add(list, &b);
59
60  /* turn array list into immutable array */
61  gate_array_create(&final_array, list);
62  gate_arraylist_release(list);
63
64  consume_string_array(&arr);
65  gate_array_release(&final_array);
66}
67
68int global_data[] = { 1, 2, 3, 4, 5 };
69
70int main()
71{
72  /* create array from static data */
73  gate_array_t data;
74  gate_array_create_static(&data, 
75    &global_data[0], /* first element */
76    sizeof(global_data[0]), /* size of element */
77    sizeof(global_data) / sizeof(global_data[0]) /* element count */
78    );
79  consume_int_array(&data);
80  gate_array_release(&data);
81
82  /* create array with dynamic data */
83  dynamic_int_array();
84  dynamic_string_array();
85
86  return 0;
87}

C++ Example

 1#include "gate/arrays.hpp"
 2#include "gate/strings.hpp"
 3
 4void consume_c_int_array(gate_array_t* arr)
 5{
 6  /* see C code above */
 7}
 8
 9void consumeCppIntArray(gate::Array<int> const& arr)
10{
11  // iterate by STL-like iterator access
12  for(gate::Array<int>::const_iterator i = arr.begin(); i != arr.end(); ++i)
13  {
14      int const& entry = *i;
15  }
16}
17
18void consumeCppStringArray(gate::Array<gate::String> const& arr)
19{
20  // iterate by GATE enumerator interface
21  for(gate::Array<gate::String>::enumerator_t e = arr.enumerate(); e.valid(); e.next())
22  {
23      gate::String const& entry = *e;
24  }
25}
26
27int main()
28{
29  /* static arrays */
30  static int const globalData[] = { 1, 2, 3, 4, 5 };
31  gate::Array<int> staticArray = gate::Array<int>::createStatic(globalData);
32  consume_c_int_array(staticArray.c_impl());
33  consumeCppIntArray(staticArray);
34
35  /* dynamically allocated arrays */
36  gate::ArrayList<int> intList;
37  intList << 42 << 24;
38  gate::Array<int> intArray = intList.toArray();
39  consume_c_int_array(intArray.c_impl());
40  consumeCppIntArray(intArray);
41
42  gate::ArrayList<String> strList;
43  strList << "Hello" << "World";
44  gate::Array<String> strArray = strList.toArray();
45  consumeCppStringArray(intArray);
46
47  return 0;
48}