autoc 1.4 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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