C/C++ code preprocessor generating code of containers. Generated code is based on marks found in processed code.
Following container types are supported:
struct- Simple structure composed from contained elements.array- Array of contained elements.queue- One direction queue of contained elements.list- List of contained elements.rb_tree- Red-black tree of contained elements.
Data of contained elements are stored in continuous block of memory. Memory block is resized when its size is not sufficient for requested count of elements. Copying of memory block while resizing is performed by realloc, no knowledge of objects structure other than its size is required.
Elements inside containers are identified by indexes (unsigned int) which are persistent and cannot be invalidated by any operation other than removal of this particular element. This allows usage of element indexes as members in other structures related to container, rather than pointers.
C++ Constructors and destructors are not used by generated structures.
Methods init and clear are instead used for object initialization and
clear.
init - After creation of object (allocation on heap, or on stack) it must be
initialized by method init or related metods (init_size).
clear - Clears object content, release allocated resources and reset object
state to initialized state. Object is not invalidated by clear method.
Containers code is generated to .cc file. Generated code can be read, modified,
or copied and used in another projects.
cont is self-hosting: it preprocesses its own source files. A two-pass bootstrap is required on first build.
# First pass — build cont without preprocessing
mkdir -p build && cd build
cmake ..
make
sudo make install
# Second pass — cont now preprocesses its own source
rm -rf *
cmake ..
make
sudo make installmkdir -p build && cd build
cmake ..
make
sudo make installCMake finds cont in PATH automatically via find_program. Use -DPROCESS_BIN=/path/to/cont only to override with a specific binary.
Declare a struct with typed fields inside @begin/@end markup, and add custom
inline methods via an additions block.
struct.h
@begin
include "base.h"
@end
// -- record_s --
@begin
struct
<
unsigned:index
unsigned:value
>
additions
{
inline unsigned get_index();
inline unsigned get_value();
}
record_s;
@end
@begin
inlines record_s
@end
inline unsigned record_s::get_index()
{
return index;
}
inline unsigned record_s::get_value()
{
return value;
}struct.cc (usage)
record_s rec0, rec1;
rec0.init();
rec1.init();
rec0.set(1, 2);
rec1.set(3, 4);
printf("rec0: {%u,%u}\n", rec0.index, rec0.value);
printf("rec1: {%u,%u}\n", rec1.index, rec1.value);
printf("rec0 == rec1: %s\n", rec0 == rec1 ? "TRUE" : "FALSE");
rec1 = rec0;
printf("rec0 == rec1: %s\n", rec0 == rec1 ? "TRUE" : "FALSE");
rec0.clear();
rec1.clear();Wrap a user-defined struct in an array — supports push, pop, operator[],
and iteration over contiguous memory.
array.h
@begin
include "struct.h"
@end
// -- rec_array_s --
@begin
array<record_s> rec_array_s;
@end
@begin
inlines rec_array_s
@endarray.cc (usage)
record_s rec;
rec.init();
rec.set(1, 2);
rec_array_s array0;
array0.init();
// push elements
array0.push(rec);
array0.push(rec);
array0.push(rec);
// modify via operator[]
array0[1].value = 42;
// iterate over contiguous data
record_s *r_ptr = array0.data;
record_s *r_ptr_end = r_ptr + array0.used;
while (r_ptr < r_ptr_end)
{
printf("{%u,%u}", r_ptr->index, r_ptr->value);
++r_ptr;
}
array0.clear();
rec.clear();Compose struct + rb_tree to build a key-value map sorted by key.
Provide a custom __compare_value to define ordering.
int_str_map.h
// -- int_string_s --
@begin
struct
<
int:index
string_s:value
>
int_string_s;
@end
// -- int_string_map_s --
@begin
rb_tree<int_string_s> int_string_map_s;
@end
@begin
inlines int_string_map_s
@end
inline int int_string_map_s::__compare_value(int_string_s &a_first,int_string_s &a_second)
{
int &fi = a_first.index;
int &si = a_second.index;
return fi < si ? -1 : fi > si ? 1 : 0;
}int_str_map.cc (usage)
int_string_map_s map;
map.init();
// insert key-value pairs
int_string_s pair;
pair.init();
pair.index = 3;
pair.value.setf("hello");
map.swap_insert(pair);
pair.index = 1;
pair.value.setf("world");
map.swap_insert(pair);
// iterate in sorted order (1, 3)
unsigned stack[map.get_descent_stack_size()];
unsigned *stack_ptr = stack;
unsigned idx = map.get_stack_min_value_idx(map.root_idx, &stack_ptr);
do
{
int_string_s &p = map[idx];
printf("%d -> %s\n", p.index, p.value.data);
idx = map.get_stack_next_idx(idx, &stack_ptr, stack);
}
while (idx != c_idx_not_exist);
pair.clear();
map.clear();Full working examples are in directory: cont/examples.