autoc 1.4 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES.md +3 -0
  3. data/README.md +149 -0
  4. data/cmake/AutoC.cmake +39 -0
  5. data/lib/autoc/allocators.rb +51 -0
  6. data/lib/autoc/association.rb +126 -0
  7. data/lib/autoc/box.rb +311 -0
  8. data/lib/autoc/cmake.rb +54 -0
  9. data/lib/autoc/collection.rb +83 -110
  10. data/lib/autoc/composite.rb +333 -0
  11. data/lib/autoc/cstring.rb +263 -0
  12. data/lib/autoc/function.rb +247 -0
  13. data/lib/autoc/hash_map.rb +328 -0
  14. data/lib/autoc/hash_set.rb +339 -0
  15. data/lib/autoc/hashers.rb +102 -0
  16. data/lib/autoc/list.rb +444 -0
  17. data/lib/autoc/module.rb +434 -0
  18. data/lib/autoc/openmp.rb +15 -0
  19. data/lib/autoc/primitive.rb +27 -0
  20. data/lib/autoc/ranges.rb +707 -0
  21. data/lib/autoc/record.rb +247 -0
  22. data/lib/autoc/scaffold/docs.rb +117 -0
  23. data/lib/autoc/scaffold/generic_value.rb +86 -0
  24. data/lib/autoc/scaffold/project.rb +75 -0
  25. data/lib/autoc/scaffold/test_cstring.rb +113 -0
  26. data/lib/autoc/scaffold/test_cstring_hash_set.rb +35 -0
  27. data/lib/autoc/scaffold/test_int_box.rb +22 -0
  28. data/lib/autoc/scaffold/test_int_hash_set.rb +448 -0
  29. data/lib/autoc/scaffold/test_int_list.rb +106 -0
  30. data/lib/autoc/scaffold/test_int_vector.rb +83 -0
  31. data/lib/autoc/scaffold/test_v2v_hash_map.rb +83 -0
  32. data/lib/autoc/scaffold/test_value_hash_set.rb +60 -0
  33. data/lib/autoc/scaffold/test_value_vector.rb +146 -0
  34. data/{test/test.rb → lib/autoc/scaffold/tests.rb} +179 -158
  35. data/lib/autoc/scaffold.rb +12 -0
  36. data/lib/autoc/sequential.rb +99 -0
  37. data/lib/autoc/set.rb +331 -0
  38. data/lib/autoc/std.rb +149 -0
  39. data/lib/autoc/type.rb +93 -531
  40. data/lib/autoc/vector.rb +290 -0
  41. data/lib/autoc.rb +4 -35
  42. metadata +55 -85
  43. data/.yardopts +0 -4
  44. data/CHANGES +0 -23
  45. data/README +0 -28
  46. data/doc/AutoC/Code.html +0 -523
  47. data/doc/AutoC/Collection.html +0 -1214
  48. data/doc/AutoC/HashMap.html +0 -1441
  49. data/doc/AutoC/HashSet.html +0 -916
  50. data/doc/AutoC/Iterators/Bidirectional.html +0 -204
  51. data/doc/AutoC/Iterators/Unidirectional.html +0 -200
  52. data/doc/AutoC/Iterators.html +0 -126
  53. data/doc/AutoC/List.html +0 -1039
  54. data/doc/AutoC/Maps.html +0 -290
  55. data/doc/AutoC/Module/File.html +0 -415
  56. data/doc/AutoC/Module/Header.html +0 -437
  57. data/doc/AutoC/Module/Source.html +0 -707
  58. data/doc/AutoC/Module.html +0 -948
  59. data/doc/AutoC/Priority.html +0 -138
  60. data/doc/AutoC/Queue.html +0 -1172
  61. data/doc/AutoC/Reference.html +0 -735
  62. data/doc/AutoC/Sets.html +0 -520
  63. data/doc/AutoC/String.html +0 -1394
  64. data/doc/AutoC/TreeMap.html +0 -1565
  65. data/doc/AutoC/TreeSet.html +0 -1447
  66. data/doc/AutoC/Type.html +0 -2148
  67. data/doc/AutoC/UserDefinedType.html +0 -1047
  68. data/doc/AutoC/Vector.html +0 -987
  69. data/doc/AutoC.html +0 -331
  70. data/doc/_index.html +0 -388
  71. data/doc/class_list.html +0 -51
  72. data/doc/css/common.css +0 -1
  73. data/doc/css/full_list.css +0 -58
  74. data/doc/css/style.css +0 -481
  75. data/doc/file.CHANGES.html +0 -117
  76. data/doc/file.README.html +0 -116
  77. data/doc/file_list.html +0 -61
  78. data/doc/frames.html +0 -17
  79. data/doc/index.html +0 -116
  80. data/doc/js/app.js +0 -243
  81. data/doc/js/full_list.js +0 -216
  82. data/doc/js/jquery.js +0 -4
  83. data/doc/method_list.html +0 -1307
  84. data/doc/top-level-namespace.html +0 -112
  85. data/lib/autoc/code.rb +0 -237
  86. data/lib/autoc/collection/hash_map.rb +0 -385
  87. data/lib/autoc/collection/hash_set.rb +0 -337
  88. data/lib/autoc/collection/iterator.rb +0 -39
  89. data/lib/autoc/collection/list.rb +0 -429
  90. data/lib/autoc/collection/map.rb +0 -41
  91. data/lib/autoc/collection/queue.rb +0 -517
  92. data/lib/autoc/collection/set.rb +0 -134
  93. data/lib/autoc/collection/tree_map.rb +0 -464
  94. data/lib/autoc/collection/tree_set.rb +0 -611
  95. data/lib/autoc/collection/vector.rb +0 -336
  96. data/lib/autoc/string.rb +0 -492
  97. data/test/test_auto.c +0 -7141
  98. data/test/test_auto.h +0 -753
  99. data/test/test_char_string.rb +0 -270
  100. data/test/test_int_list.rb +0 -35
  101. data/test/test_int_tree_set.rb +0 -111
  102. data/test/test_int_vector.rb +0 -34
  103. data/test/test_value_hash_map.rb +0 -162
  104. data/test/test_value_hash_set.rb +0 -173
  105. data/test/test_value_list.rb +0 -193
  106. data/test/test_value_queue.rb +0 -275
  107. data/test/test_value_tree_map.rb +0 -176
  108. data/test/test_value_tree_set.rb +0 -173
  109. data/test/test_value_vector.rb +0 -155
  110. data/test/value.rb +0 -80
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: cc85e9cdc08a443fcc50ad0c86c681b205b47057
4
- data.tar.gz: d0a444d8b827b87478e1d26dbb70a2b3c27c09be
2
+ SHA256:
3
+ metadata.gz: a598879205b51d5bf574b70b370ef805efe3681e0ea4ad8b6347e45296cc304b
4
+ data.tar.gz: d5c3290746c096a666627ff544903afe2b1f31e61b7706cf5a5e531c410191ea
5
5
  SHA512:
6
- metadata.gz: f39cbdc42cb01f0fda4878fb755c9db3d9276976dfaa4822fa27b5bff02febb3e07a38d27a398beac07341de1de4f851e9bb42157fef8542fe8586bb1bb94ee1
7
- data.tar.gz: 7934c79a433127ed3396ee6170bbfd30a3a47579180fd0eb9d52a93f6d4a125b0e59b7d4d5552c68ec4d685c83c3b27fffa4a4e34db50ba394a5b190797d0cb4
6
+ metadata.gz: cb81338f80898d88975a0bc204b5245c6fe4e0deb931c91ff007bff5dca026f4f99fe5702d56033fa0387786cb20b03445dbb662c07ebcf7f8ba81f993848520
7
+ data.tar.gz: da094ff14cf393a2c7178fb45083d18b3513d686e29a693895dd4cea51bbcf406776fe26de0d550605102f7f5976170a3715fedc1d9520e1f4c1944c034b56d1
data/CHANGES.md ADDED
@@ -0,0 +1,3 @@
1
+ # 2.0.0
2
+
3
+ A complete package overhaul.
data/README.md ADDED
@@ -0,0 +1,149 @@
1
+ # Reinvention of the C wheel, automatized
2
+
3
+ The project AutoC ships a collection of [Ruby](https://www.ruby-lang.org) classes related to automagic
4
+ C source code generation.
5
+
6
+ Specifically, it provides a means of generating strongly-typed general purpose C data containers
7
+ (vectors, lists, maps etc.) similar to those provided by
8
+ the C++'s [STL template containers](https://en.cppreference.com/w/cpp/container)
9
+ but implemented in ***pure ANSI C language***.
10
+
11
+ Unlike similar attempts to introduce type-generic data containers to the C language which
12
+ are typically the macro libraries, the AutoC is an ***explicit source code generator***
13
+ with 100% of provided functionality is implemented as (inline or extern) C functions
14
+ making the code explicit, browseable and debuggable.
15
+
16
+ ## Qickstart
17
+
18
+ Install the `autoc` Ruby package from [RubyGems](https://rubygems.org)
19
+
20
+ ```shell
21
+ gem install autoc
22
+ ```
23
+
24
+ ### Extract sample documentation
25
+
26
+ Generate a documentation header `auto.h` with reference of what can be provided by the AutoC
27
+
28
+ ```shell
29
+ ruby -r autoc/scaffold -e docs
30
+ ```
31
+
32
+ Extract the documentation with [Doxygen](https://www.doxygen.nl)
33
+
34
+ ```shell
35
+ doxygen .
36
+ ```
37
+
38
+ Explore the rendered HTML documentation starting at `html/index.html`
39
+
40
+ ### Build & run sample project
41
+
42
+ Create auto code descriptor in Ruby `sample.rb`
43
+
44
+ ```ruby
45
+ require 'autoc/module'
46
+ require 'autoc/hash_set'
47
+ AutoC::Module.render(:sample) do |m|
48
+ m << AutoC::HashSet.new(:IntSet, :int)
49
+ end
50
+ ```
51
+
52
+ Generate C code into `sample_auto.[ch]`
53
+
54
+ ```shell
55
+ ruby sample.rb
56
+ ```
57
+
58
+ Create sample C code `sample.c`
59
+
60
+ ```c
61
+ #include <stdio.h>
62
+ #include "sample_auto.h"
63
+ int main(int argc, char** argv) {
64
+ IntSet set;
65
+ IntSetCreate(&set);
66
+ IntSetPut(&set, 1);
67
+ IntSetPut(&set, 0);
68
+ IntSetPut(&set, 1);
69
+ IntSetPut(&set, -1);
70
+ printf("size = %d\\n", IntSetSize(&set));
71
+ for(IntSetRange r = IntSetRangeNew(&set); !IntSetRangeEmpty(&r); IntSetRangePopFront(&r)) {
72
+ printf("%d\\n", IntSetRangeTakeFront(&r));
73
+ }
74
+ IntSetDestroy(&set);
75
+ }
76
+ ```
77
+
78
+ Build sample program
79
+
80
+ ```shell
81
+ cc -g -o sample sample.c sample_auto.c
82
+ ```
83
+
84
+ Test sample with [Valgrind](https://valgrind.org)
85
+
86
+ ```shell
87
+ valgrind sample
88
+ ```
89
+
90
+ ### Build & run test suite
91
+
92
+ Generate C test suite into `tests_auto.[ch]`
93
+
94
+ ```shell
95
+ ruby -r autoc/scaffold -e tests
96
+ ```
97
+
98
+ Build test suite
99
+
100
+ ```shell
101
+ cc -g -o tests tests_auto.c
102
+ ```
103
+
104
+ Witness the test suite run time correctness
105
+
106
+ ```shell
107
+ valgrind tests
108
+ ```
109
+
110
+ ### Create CMake project from template
111
+
112
+ Create CMake-powered skeleton project named `runme` in the current directory
113
+
114
+ ```shell
115
+ ruby -r autoc/scaffold -e project runme
116
+ ```
117
+
118
+ Configure the generated project
119
+
120
+ ```shell
121
+ cmake .
122
+ ```
123
+
124
+ Build the generated project
125
+
126
+ ```shell
127
+ cmake --build .
128
+ ```
129
+
130
+ ## Licensing & availability
131
+
132
+ This code is distributed under terms of the 2-clause BSD {file:LICENSE}.
133
+
134
+ The project's home page is [GitHub](https://github.com/okhlybov/autoc).
135
+
136
+ The released ruby gems are published in [RubyGems](https://rubygems.org/gems/autoc).
137
+
138
+ The condensed description of the changes is in the {file:CHANGES.md}.
139
+
140
+
141
+ ## Assorted related stuff
142
+
143
+ - [STC](https://github.com/tylov/STC)
144
+
145
+ ---
146
+
147
+ _Cheers && happy coding!_
148
+
149
+ Oleg A. Khlybov <fougas@mail.ru>
data/cmake/AutoC.cmake ADDED
@@ -0,0 +1,39 @@
1
+ cmake_minimum_required(VERSION 3.15)
2
+
3
+ find_package(Ruby 3.2)
4
+
5
+ if(NOT Ruby_FOUND)
6
+ message(STATUS "Attempting to locate default Ruby executable")
7
+ find_program(Ruby ruby REQUIRED)
8
+ endif()
9
+
10
+ function(add_autoc_module module)
11
+ set(args DIRECTORY MAIN_DEPENDENCY)
12
+ set(listArgs COMMAND DEPENDS)
13
+ cmake_parse_arguments(key "${flags}" "${args}" "${listArgs}" ${ARGN})
14
+ if(NOT key_DIRECTORY)
15
+ set(key_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
16
+ endif()
17
+ if(NOT key_MAIN_DEPENDENCY)
18
+ set(key_MAIN_DEPENDENCY ${key_DIRECTORY}/${module}.rb)
19
+ endif()
20
+ set(module_state ${key_DIRECTORY}/${module}.state)
21
+ set(module_cmake ${key_DIRECTORY}/${module}.cmake)
22
+ set(module_target ${module}-generate)
23
+ if(NOT EXISTS ${module_state} OR NOT EXISTS ${module_cmake})
24
+ message(CHECK_START "Bootstrapping AutoC module " ${module})
25
+ execute_process(WORKING_DIRECTORY ${key_DIRECTORY} COMMAND ${key_COMMAND} VERBATIM)
26
+ endif()
27
+ include(${module_cmake})
28
+ add_custom_command(
29
+ OUTPUT ${module_state}
30
+ BYPRODUCTS ${module_cmake}
31
+ MAIN_DEPENDENCY ${key_MAIN_DEPENDENCY}
32
+ DEPENDS ${key_DEPENDS}
33
+ WORKING_DIRECTORY ${key_DIRECTORY}
34
+ COMMAND ${key_COMMAND}
35
+ VERBATIM
36
+ )
37
+ add_custom_target(${module_target} DEPENDS ${module_state})
38
+ add_dependencies(${module} ${module_target})
39
+ endfunction()
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+
4
+ require 'singleton'
5
+ require 'autoc/std'
6
+ require 'autoc/type'
7
+ require 'autoc/module'
8
+
9
+
10
+ module AutoC
11
+
12
+
13
+ # Standard C malloc()-based dynamic memory handler
14
+ class Allocator
15
+
16
+ include STD
17
+
18
+ include Singleton
19
+
20
+ include Entity
21
+
22
+ def initialize = dependencies << STDLIB_H
23
+
24
+ def allocate(type, count = 1, zero: false, **kws)
25
+ zero ? "(#{type}*)calloc(#{count}, sizeof(#{type}))" : "(#{type}*)malloc((#{count})*sizeof(#{type}))"
26
+ end
27
+
28
+ def free(pointer) = "free(#{pointer})"
29
+
30
+ end # Allocator
31
+
32
+
33
+ # Boehm-Demers-Weiser garbage-collecting memory handler https://www.hboehm.info/gc/
34
+ class BDWAllocator
35
+
36
+ include Singleton
37
+
38
+ include Entity
39
+
40
+ def initialize = dependencies << SystemHeader.new('gc.h')
41
+
42
+ def allocate(type, count = 1, atomic: false, **kws)
43
+ atomic ? "(#{type}*)GC_malloc_atomic((#{count})*sizeof(#{type}))" : "(#{type}*)GC_malloc((#{count})*sizeof(#{type}))"
44
+ end
45
+
46
+ def free(pointer) = nil
47
+
48
+ end # Allocator
49
+
50
+
51
+ end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+
4
+ require 'autoc/std'
5
+ require 'autoc/collection'
6
+
7
+
8
+ module AutoC
9
+
10
+
11
+ using STD::Coercions
12
+
13
+
14
+ # @abstract
15
+ # Generator for C types for direct access using index of specific type (hash/tree maps, string, vector etc.)
16
+ class Association < Collection
17
+
18
+ attr_reader :index
19
+
20
+ def initialize(type, element, index, **kws)
21
+ super(type, element, **kws)
22
+ dependencies << (@index = index.to_type)
23
+ end
24
+
25
+ # For associative container to be copyable both hashable element and index types are required
26
+ def copyable? = super && index.copyable?
27
+
28
+ # For associative container to be comparable both hashable element and index types are required
29
+ def comparable? = super && index.comparable?
30
+
31
+ # For associative container to be orderable both hashable element and index types are required
32
+ def orderable? = super && index.orderable?
33
+
34
+ # The associative destructible element and index types mandates creation of the container's destructor
35
+ def destructible? = super || index.destructible?
36
+
37
+ # For associative container to be hashable both hashable element and index types are required
38
+ def hashable? = super && index.hashable?
39
+
40
+ def type_tag = "#{signature}<#{element},#{index}>"
41
+
42
+ private
43
+
44
+ def configure
45
+ super
46
+ method(:int, :check, { target: const_rvalue, index: index.const_rvalue } ).configure do
47
+ header %{
48
+ @brief Validate specified index
49
+
50
+ @param[in] target container to query
51
+ @param[in] index index to verify
52
+ @return non-zero value if there is an element associated with specified index and zero value otherwise
53
+
54
+ This function performs the index validity check.
55
+ For the contiguous containers (vector, string etc.) the yields non-zero value if the index passes the boundaries check.
56
+ For the mappings (hash/tree maps) this yields non-zero value if there exists a index->element association.
57
+
58
+ In any case, this function should be used for the index validation prior getting direct access to contained elements
59
+ as the container functions do not normally do it themselves for performance reasons.
60
+
61
+ @since 2.0
62
+ }
63
+ end
64
+ method(element.const_lvalue, :view, { target: const_rvalue, index: index.const_rvalue } ).configure do
65
+ header %{
66
+ @brief Get a view of the element
67
+
68
+ @param[in] target container
69
+ @param[in] index lookup index
70
+ @return a view of contained element
71
+
72
+ This function returns a constant view of the contained element associated with specified index in the form constant C pointer to the storage.
73
+ It is generally not wise to modify the value pointed to (especially in the case of mapping).
74
+
75
+ It is the caller's responsibility to check for the index validity prior calling this function (see @ref #{check}).
76
+
77
+ @since 2.0
78
+ }
79
+ end
80
+ method(element, :get, { target: const_rvalue, index: index.const_rvalue }, inline: true, constraint:-> { element.copyable? } ).configure do
81
+ dependencies << check << view
82
+ header %{
83
+ @brief Get specific element
84
+
85
+ @param[in] target container
86
+ @param[in] index lookup index
87
+ @return a copy of contained element
88
+
89
+ This function returns an independent copy of the contained element associated with specified index.
90
+
91
+ It is the caller's responsibility to check for the index validity prior calling this function (see @ref #{check}).
92
+
93
+ @since 2.0
94
+ }
95
+ inline_code %{
96
+ #{result} r;
97
+ #{element.const_lvalue} e;
98
+ assert(target);
99
+ assert(#{check.(target, index)});
100
+ e = #{view.(target, index)};
101
+ #{element.copy.(:r, '*e')};
102
+ return r;
103
+ }
104
+ end
105
+ method(:void, :set, { target: rvalue, index: index.const_rvalue, value: element.const_rvalue }, constraint:-> { index.copyable? && element.copyable? } ).configure do
106
+ header %{
107
+ @brief Set specific element
108
+
109
+ @param[in] target container
110
+ @param[in] index lookup index
111
+ @param[in] value source value
112
+
113
+ This function unconditionally sets the element at specified index to a copy of the source value.
114
+ A previous element (if any) is destroyed with specific destructor.
115
+
116
+ It is the caller's responsibility to check for the index validity prior calling this function (see @ref #{check}).
117
+
118
+ @since 2.0
119
+ }
120
+ end
121
+ end
122
+
123
+ end # Association
124
+
125
+
126
+ end
data/lib/autoc/box.rb ADDED
@@ -0,0 +1,311 @@
1
+ # frozen_string_literal: true
2
+
3
+
4
+ require 'autoc/std'
5
+ require 'autoc/composite'
6
+
7
+
8
+ module AutoC
9
+
10
+
11
+ using STD::Coercions
12
+
13
+
14
+ # C union wrapper with managed fields
15
+ class Box < Composite
16
+
17
+ attr_reader :variants
18
+
19
+ attr_reader :tag_
20
+
21
+ def default_constructible? = true
22
+ def custom_constructible? = false
23
+ def destructible? = variants.values.any? { |t| t.destructible? }
24
+ def comparable? = variants.values.all? { |t| t.comparable? }
25
+ def orderable? = variants.values.all? { |t| t.orderable? }
26
+ def copyable? = variants.values.all? { |t| t.copyable? }
27
+ def hashable? = variants.values.all? { |t| t.hashable? }
28
+
29
+ def initialize(type, variants, visibility: :public)
30
+ super(type, visibility:)
31
+ setup_variants(variants)
32
+ @tag_ = "#{signature}_";
33
+ @default = 'abort();'
34
+ end
35
+
36
+ def render_interface(stream)
37
+ if public?
38
+ stream << %{
39
+ /**
40
+ #{defgroup}
41
+ @brief Value type wrapper of the C union
42
+ */
43
+ }
44
+ stream << %{
45
+ /**
46
+ #{ingroup}
47
+
48
+ @brief Box tag set
49
+
50
+ Use @ref #{identifier(:tag)} to query current box contents. Empty box is always tagged as 0.
51
+
52
+ @since 2.0
53
+ */
54
+ }
55
+ else
56
+ stream << PRIVATE
57
+ end
58
+ stream << 'typedef enum {'
59
+ i = 0; stream << (variants.collect { |name, type| "#{identifier(name)} = #{i+=1}" }).join(',')
60
+ stream << "} #{tag_};"
61
+ if public?
62
+ stream << %{
63
+ /**
64
+ #{ingroup}
65
+
66
+ @brief Opaque struct holding state of the box
67
+
68
+ @since 2.0
69
+ */
70
+ }
71
+ else
72
+ stream << PRIVATE
73
+ end
74
+ stream << 'typedef struct {union {'
75
+ variants.each { |name, type| stream << field_declaration(type, name) }
76
+ stream << "} variant; /**< @private */ #{tag_} tag; /**< @private */} #{signature};"
77
+ end
78
+
79
+ def type_tag = "#{signature}<#{variants.values.join(',')}>"
80
+
81
+ private
82
+
83
+ # @private
84
+ def setup_variants(variants)
85
+ @variants = variants.transform_values { |type| type.to_type }
86
+ self.variants.each_value { |type| dependencies << type }
87
+ end
88
+
89
+ # @private
90
+ def field_variable(opt)
91
+ if opt.is_a?(::Hash)
92
+ obj, name = opt.first
93
+ "#{obj}->#{name}"
94
+ else
95
+ opt
96
+ end
97
+ end
98
+
99
+ # @private
100
+ def field_declaration(type, name)
101
+ s = "#{type} #{field_variable(name)};"
102
+ s += '/**< @private */' if @opaque
103
+ s
104
+ end
105
+
106
+ def configure
107
+ super
108
+ default_create.configure do
109
+ inline_code %{
110
+ assert(target);
111
+ target->tag = (#{tag_})0;
112
+ }
113
+ end
114
+ method(tag_, :tag, { target: const_rvalue }).configure do
115
+ inline_code %{
116
+ assert(target);
117
+ return target->tag;
118
+ }
119
+ header %{
120
+ @brief Get type of contained element
121
+
122
+ @param[in] target box to query
123
+ @return tag of currently contained element
124
+
125
+ This function returns a tag of currently contained element (@ref #{tag_}) or zero value if the box is empty (i.e. contains nothing).
126
+
127
+ @since 2.0
128
+ }
129
+ end
130
+ method(:void, :purge, { target: rvalue }).configure do
131
+ code %{
132
+ assert(target);
133
+ #{destroy.(target) if destructible?};
134
+ #{default_create.(target)};
135
+ }
136
+ header %{
137
+ @brief Reset box
138
+
139
+ @param[in] target box to purge
140
+
141
+ This function resets the box by destroying containing element (if any).
142
+ The box is left empty.
143
+
144
+ @since 2.0
145
+ }
146
+ end
147
+ ### destroy
148
+ _code = %$
149
+ assert(target);
150
+ if(target->tag) switch(target->tag) {
151
+ $
152
+ variants.each do |name, type|
153
+ _code += "case #{identifier(name)}:"
154
+ _code += type.destroy.("target->variant.#{name}") if type.destructible?
155
+ _code += ';break;'
156
+ end
157
+ _code += %{
158
+ default: #{@default}
159
+ }
160
+ _code += '}'
161
+ destroy.configure { code _code }
162
+ ### copy
163
+ _code = %$
164
+ assert(target);
165
+ assert(source);
166
+ if(source->tag) switch(source->tag) {
167
+ $
168
+ variants.each do |name, type|
169
+ _code += "case #{identifier(name)}:"
170
+ _code += type.copy.("target->variant.#{name}", "source->variant.#{name}")
171
+ _code += ';break;'
172
+ end
173
+ _code += %{
174
+ default: #{@default}
175
+ }
176
+ _code += '} target->tag = source->tag;'
177
+ copy.configure { code _code }
178
+ ### equal
179
+ _code = %$
180
+ assert(left);
181
+ assert(right);
182
+ if(left->tag != right->tag) return 0;
183
+ if(!left->tag) return 1;
184
+ switch(left->tag) {
185
+ $
186
+ variants.each do |name, type|
187
+ _code += "case #{identifier(name)}:"
188
+ _code += 'return '
189
+ _code += type.equal.("left->variant.#{name}", "right->variant.#{name}")
190
+ _code += ';'
191
+ end
192
+ _code += %{
193
+ default: #{@default}
194
+ }
195
+ _code += '}'
196
+ equal.configure { code _code }
197
+ ### compare
198
+ _code = %$
199
+ assert(left);
200
+ assert(right);
201
+ assert(left->tag == right->tag);
202
+ if(!left->tag) return 0;
203
+ switch(left->tag) {
204
+ $
205
+ variants.each do |name, type|
206
+ _code += "case #{identifier(name)}: return "
207
+ _code += type.compare.("left->variant.#{name}", "right->variant.#{name}")
208
+ _code += ';'
209
+ end
210
+ _code += %{
211
+ default: #{@default}
212
+ }
213
+ _code += '}'
214
+ compare.configure { code _code }
215
+ ### hash_code
216
+ _code = %$
217
+ assert(target);
218
+ if(!target->tag) return AUTOC_HASHER_SEED;
219
+ switch(target->tag) {
220
+ $
221
+ variants.each do |name, type|
222
+ _code += "case #{identifier(name)}: return "
223
+ _code += type.hash_code.("target->variant.#{name}")
224
+ _code += ';'
225
+ end
226
+ _code += %{
227
+ default: #{@default}
228
+ }
229
+ _code += '}'
230
+ hash_code.configure { code _code }
231
+ ### typed accessors
232
+ _type = self
233
+ variants.each do |name, type|
234
+ method(type.const_lvalue, "view_#{name}", { target: const_rvalue }).configure do
235
+ code %{
236
+ assert(target);
237
+ assert(target->tag == #{identifier(name)});
238
+ return &target->variant.#{name};
239
+ }
240
+ header %{
241
+ @brief Get a view of contained value of type #{type}
242
+
243
+ @param[in] target box to query
244
+ @return a view of the value of type #{type}
245
+
246
+ This function is used to get a constant reference (in form of the C pointer) to value contained in `target`.
247
+
248
+ It is the caller's responsibility to check the type of currently contained value.
249
+ Consider using guard `if(#{identifier(:tag)}(...) == #{identifier(name)}) ...`
250
+
251
+ @see @ref #{tag}
252
+
253
+ @since 2.0
254
+ }
255
+ end
256
+ if type.copyable?
257
+ method(type, "get_#{name}", { target: const_rvalue }).configure do
258
+ code %{
259
+ #{type} result;
260
+ assert(target);
261
+ assert(target->tag == #{identifier(name)});
262
+ #{type.copy.(:result, "target->variant.#{name}")};
263
+ return result;
264
+ }
265
+ header %{
266
+ @brief Get a copy of contained value of type #{type}
267
+
268
+ @param[in] target box to query
269
+ @return a copy of the value of type #{type}
270
+
271
+ This function is used to get a copy of the value contained in `target`.
272
+
273
+ It is the caller's responsibility to check the type of currently contained value.
274
+ Consider using guard `if(#{identifier(:tag)}(...) == #{identifier(name)}) ...`
275
+
276
+ @see @ref #{tag}
277
+
278
+ @since 2.0
279
+ }
280
+ end
281
+ method(:void, "put_#{name}", { target: rvalue, value: type.const_rvalue }).configure do
282
+ code %{
283
+ assert(target);
284
+ #{destroy.(target) if destructible?};
285
+ #{type.copy.("target->variant.#{name}", value)};
286
+ target->tag = #{identifier(name)};
287
+ }
288
+ header %{
289
+ @brief Put value of type #{type} into box
290
+
291
+ @param[in] target box to set
292
+ @param[in] value value of type #{type} to put
293
+
294
+ This function is used to put a copy of the value into the box.
295
+ Previously contained value is destroyed with respective destructor.
296
+
297
+ After call to this function the value type may be obtained with @ref #{identifier(:tag)}.
298
+
299
+ @see @ref #{tag}
300
+
301
+ @since 2.0
302
+ }
303
+ end
304
+ end
305
+ end
306
+ end
307
+
308
+ end # Box
309
+
310
+
311
+ end