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
- Mutable array lists
This C object manages the contents of an array from allocation to its destruction. Lists can import new entries by copying them into the array’s memory block and it is possible to attach construction and destruction functions to manage the native behavior of an entry. - Immutable array ranges
This “final” array type just contains a pointer to the first element of an array and the total amount of elements in a sequential memory block. The size of an entry is stored too, to access a specific entry by its index with one generic interface.
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}