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
@@ -0,0 +1,328 @@
1
+ # frozen_string_literal: true
2
+
3
+
4
+ require 'autoc/record'
5
+ require 'autoc/hash_set'
6
+ require 'autoc/association'
7
+
8
+
9
+ module AutoC
10
+
11
+
12
+ using STD::Coercions
13
+
14
+
15
+ class HashMap < Association
16
+
17
+ def _range_class = Range
18
+
19
+ def _node_class = Record
20
+
21
+ def _set_class = HashMap::HashSet
22
+
23
+ def range = @range ||= _range_class.new(self, visibility: visibility)
24
+
25
+ def _node = @_node ||= _node_class.new(identifier(:_node, abbreviate: true), { index: index, element: element }, _master: self, visibility: :internal)
26
+
27
+ def _set = @_set ||= _set_class.new(identifier(:_set, set_operations: false, abbreviate: true), _node, _master: self, visibility: :internal)
28
+
29
+ def orderable? = _set.orderable?
30
+
31
+ def initialize(*args, **kws)
32
+ super
33
+ dependencies << _set
34
+ end
35
+
36
+ def render_interface(stream)
37
+ if public?
38
+ stream << %{
39
+ /**
40
+ #{defgroup}
41
+
42
+ @brief Unordered collection of elements of type #{element} associated with unique index of type #{index}.
43
+
44
+ For iteration over the set elements refer to @ref #{range}.
45
+
46
+ @see C++ [std::unordered_map<K,T>](https://en.cppreference.com/w/cpp/container/unordered_map)
47
+
48
+ @since 2.0
49
+ */
50
+ /**
51
+ #{ingroup}
52
+ @brief Opaque structure holding state of the hash map
53
+ @since 2.0
54
+ */
55
+ }
56
+ else
57
+ stream << PRIVATE
58
+ end
59
+ stream << %{
60
+ typedef struct {
61
+ #{_set} set; /**< @private */
62
+ } #{signature};
63
+ }
64
+ end
65
+
66
+ private
67
+
68
+ def configure
69
+ super
70
+ method(:int, :remove, { target: rvalue, index: index.const_rvalue }, constraint:-> { index.comparable? }).configure do
71
+ code %{
72
+ assert(target);
73
+ return #{_set._remove_index_node.('target->set', index)};
74
+ }
75
+ header %{
76
+ @brief Remove element associated with index
77
+
78
+ @param[in] target map to process
79
+ @param[in] index index to look for
80
+ @return non-zero value on successful removal and zero value otherwise
81
+
82
+ This function removes and destroys index and associated element if any.
83
+ The function returns zero value if `target` contains no such association.
84
+
85
+ @since 2.0
86
+ }
87
+ end
88
+ default_create.configure do
89
+ code %{
90
+ assert(target);
91
+ #{_set.default_create.('target->set')};
92
+ }
93
+ end
94
+ set.configure do
95
+ code %{
96
+ #{_node.lvalue} node;
97
+ assert(target);
98
+ assert(target);
99
+ node = #{_set._find_index_node.('target->set', index)};
100
+ if(node) {
101
+ #{_node.destroy.('*node') if _node.destructible?};
102
+ #{_node.custom_create.('*node', index, value)}; /* override node's contents in-place */
103
+ } else {
104
+ #{_node} node;
105
+ #{_set._slot.lvalue} s = (#{_set._slot.lvalue})#{_set._find_index_slot.('target->set', index)};
106
+ /* construct temporary node as POD value; actual copying will be performed by the list itself */
107
+ node.index = index;
108
+ node.element = value;
109
+ #{_set._slot.push_front.('*s', :node)};
110
+ ++target->set.size; /* bypassing set's element manipulation functions incurs manual size management */
111
+ }
112
+ }
113
+ end
114
+ destroy.configure do
115
+ code %{
116
+ assert(target);
117
+ #{_set.destroy.('target->set')};
118
+ }
119
+ end
120
+ copy.configure do
121
+ code %{
122
+ assert(target);
123
+ assert(source);
124
+ #{_set.copy.('target->set', 'source->set')};
125
+ }
126
+ end
127
+ equal.configure do
128
+ code %{
129
+ assert(left);
130
+ assert(right);
131
+ return #{_set.equal.('left->set', 'right->set')};
132
+ }
133
+ end
134
+ hash_code.configure do
135
+ code %{
136
+ assert(target);
137
+ return #{_set.hash_code.('target->set')};
138
+ }
139
+ end
140
+ empty.configure do
141
+ code %{
142
+ assert(target);
143
+ return #{_set.empty.('target->set')};
144
+ }
145
+ end
146
+ size.configure do
147
+ code %{
148
+ assert(target);
149
+ return #{_set.size.('target->set')};
150
+ }
151
+ end
152
+ contains.configure do
153
+ code %{
154
+ assert(target);
155
+ return #{find_first.(target, value)} != NULL;
156
+ }
157
+ end
158
+ check.configure do
159
+ code %{
160
+ assert(target);
161
+ return #{_set._find_index_node.('target->set', index)} != NULL;
162
+ }
163
+ end
164
+ view.configure do
165
+ code %{
166
+ #{_node.lvalue} node;
167
+ assert(target);
168
+ node = #{_set._find_index_node.('target->set', index)};
169
+ return node ? &node->element : NULL;
170
+ }
171
+ end
172
+ find_first.configure do
173
+ code %{
174
+ #{range} r;
175
+ assert(target);
176
+ for(r = #{range.new.(target)}; !#{range.empty.(:r)}; #{range.pop_front.(:r)}) {
177
+ #{element.const_lvalue} e = #{range.view_front.(:r)};
178
+ if(#{element.equal.('*e', value)}) return e;
179
+ }
180
+ return NULL;
181
+ }
182
+ end
183
+ end
184
+
185
+ end # HashMap
186
+
187
+
188
+ class HashMap::HashSet < HashSet
189
+
190
+ def _slot_class = HashMap::List
191
+
192
+ attr_reader :_index
193
+
194
+ def initialize(*args, **kws)
195
+ super
196
+ _map = _master # this set is a subcomponent of the map
197
+ @_index = _map.index
198
+ end
199
+
200
+ private
201
+
202
+ def configure
203
+ super
204
+ method(_slot.const_lvalue, :_find_index_slot, { target: const_rvalue, index: _index.const_rvalue }, visibility: :internal).configure do
205
+ # Find slot based on the index hash code only bypassing element
206
+ dependencies << _find_slot
207
+ inline_code _find_slot_hash(_index.hash_code.(index))
208
+ end
209
+ method(element.lvalue, :_find_index_node, { target: const_rvalue, index: _index.const_rvalue }, visibility: :internal).configure do
210
+ code %{
211
+ #{_slot._node_p} curr;
212
+ #{_slot._node_p} prev;
213
+ #{_slot.const_lvalue} s = #{_find_index_slot.(target, index)};
214
+ return #{_slot._find_index_node.('*s', index, :prev, :curr)} ? &curr->element : NULL;
215
+ }
216
+ end
217
+ method(:int, :_remove_index_node, { target: rvalue, index: _index.const_rvalue }, visibility: :internal).configure do
218
+ code %{
219
+ int c;
220
+ #{_slot.lvalue} s = (#{_slot.lvalue})#{_find_index_slot.(target, index)};
221
+ c = #{_slot._remove_index_node.('*s', index)};
222
+ if(c) --target->size;
223
+ return c;
224
+ }
225
+ end
226
+ end
227
+
228
+ end # HashSet
229
+
230
+
231
+ class HashMap::List < List
232
+
233
+ attr_reader :_index
234
+
235
+ def initialize(*args, **kws)
236
+ super
237
+ _map = _master._master # this list is a subcomponent of a set which is in turn a subcomponent of the map
238
+ @_index = _map.index
239
+ end
240
+
241
+ private
242
+
243
+ def configure
244
+ super
245
+ method(:int, :_find_index_node, { target: const_rvalue, index: _index.const_rvalue, prev_p: _node_pp, curr_p: _node_pp }, constraint:-> { _index.comparable? }).configure do
246
+ # Locate node satisfying default element equality condition, return this and previous nodes
247
+ code _locate_node_equal(_index.equal.('curr->element.index', index))
248
+ end
249
+ method(:int, :_remove_index_node, { target: rvalue, index: _index.const_rvalue }, constraint:-> { _index.comparable? }).configure do
250
+ code _remove_first(_find_index_node.(target, index, :prev, :curr))
251
+ end
252
+ end
253
+
254
+ end # List
255
+
256
+
257
+ class HashMap::Range < AssociativeRange
258
+
259
+ def render_interface(stream)
260
+ if public?
261
+ render_type_description(stream)
262
+ stream << %{
263
+ /**
264
+ #{ingroup}
265
+ @brief Opaque structure holding state of the hash map's range
266
+ @since 2.0
267
+ */
268
+ }
269
+ else
270
+ stream << PRIVATE
271
+ end
272
+ stream << %{
273
+ typedef struct {
274
+ #{_range} set; /**< @private */
275
+ } #{signature};
276
+ }
277
+ end
278
+
279
+ # @private
280
+ def _range = _iterable._set.range
281
+
282
+ private
283
+
284
+ def configure
285
+ super
286
+ method(iterable._node.const_lvalue, :_view_node, { range: const_rvalue }, inline: true, visibility: :internal).configure do
287
+ code %{
288
+ assert(!#{empty.(range)});
289
+ return #{_range.view_front.('range->set')};
290
+ }
291
+ end
292
+ custom_create.configure do
293
+ code %{
294
+ assert(range);
295
+ assert(iterable);
296
+ #{_range.default_create.('range->set', '&iterable->set')};
297
+ }
298
+ end
299
+ empty.configure do
300
+ code %{
301
+ assert(range);
302
+ return #{_range.empty.('range->set')};
303
+ }
304
+ end
305
+ pop_front.configure do
306
+ code %{
307
+ assert(range);
308
+ #{_range.pop_front.('range->set')};
309
+ }
310
+ end
311
+ view_front.configure do
312
+ code %{
313
+ assert(range);
314
+ return &#{_view_node.(range)}->element;
315
+ }
316
+ end
317
+ view_index_front.configure do
318
+ code %{
319
+ assert(range);
320
+ return &#{_view_node.(range)}->index;
321
+ }
322
+ end
323
+ end
324
+
325
+ end # Range
326
+
327
+
328
+ end
@@ -0,0 +1,339 @@
1
+ # frozen_string_literal: true
2
+
3
+
4
+ require 'autoc/vector'
5
+ require 'autoc/list'
6
+ require 'autoc/set'
7
+
8
+
9
+ module AutoC
10
+
11
+
12
+ using STD::Coercions
13
+
14
+
15
+ class HashSet < Set
16
+
17
+ def _slot_class = List
18
+
19
+ def _bin_class = Vector
20
+
21
+ def range = @range ||= Range.new(self, visibility: visibility)
22
+
23
+ def _slot = @_slot ||= _slot_class.new(identifier(:_list, abbreviate: true), element, _master: self, maintain_size: false, visibility: :internal)
24
+
25
+ def _bin = @_bin ||= _bin_class.new(identifier(:_vector, abbreviate: true), _slot, _master: self, visibility: :internal)
26
+
27
+ def initialize(*args, **kws)
28
+ super
29
+ dependencies << _bin
30
+ end
31
+
32
+ def render_interface(stream)
33
+ if public?
34
+ stream << %{
35
+ /**
36
+ #{defgroup}
37
+
38
+ @brief Unordered collection of unique elements of type #{element}
39
+
40
+ For iteration over the set elements refer to @ref #{range}.
41
+
42
+ @see C++ [std::unordered_set<T>](https://en.cppreference.com/w/cpp/container/unordered_set)
43
+
44
+ @since 2.0
45
+ */
46
+ /**
47
+ #{ingroup}
48
+ @brief Opaque structure holding state of the hash set
49
+ @since 2.0
50
+ */
51
+ }
52
+ else
53
+ stream << PRIVATE
54
+ end
55
+ stream << %{
56
+ typedef struct {
57
+ #{_bin} bin; /**< @private */
58
+ size_t size; /**< @private */
59
+ size_t hash_mask; /**< @private */
60
+ } #{signature};
61
+ }
62
+ end
63
+
64
+ private
65
+
66
+ def configure
67
+ super
68
+ method(:void, :create_capacity, { target: lvalue, capacity: :size_t.rvalue }).configure do
69
+ code %{
70
+ unsigned char bits = 0;
71
+ assert(target);
72
+ target->size = 0;
73
+ /* fix capacity to become the ceiling to the nearest power of two */
74
+ if(capacity % 2 == 0) --capacity;
75
+ while(capacity >>= 1) ++bits;
76
+ capacity = (size_t)1 << (bits+1); assert(capacity > 0);
77
+ target->hash_mask = capacity-1; /* fast slot location for value: hash_code(value) & hash_mask */
78
+ #{_bin.custom_create.('target->bin', capacity)};
79
+ assert(#{_bin.size.('target->bin')} % 2 == 0);
80
+ }
81
+ header %{
82
+ @brief Create set with specified capacity
83
+
84
+ @param[out] target set to create
85
+ @param[in] capacity initial capacity of the set
86
+
87
+ This function creates a new set which should be suffice to contain specific number of elements.
88
+
89
+ While the input capacity may be arbitrary the resulting one will be rounded up to the nearest power of two.
90
+
91
+ This function may be useful when the (approximate) number of elements this set is about to contain is known in advance
92
+ in order to avoid expensive storage reallocation & elements rehashing operations during the set's lifetime.
93
+
94
+ @since 2.0
95
+ }
96
+ end
97
+ def _find_slot_hash(hash)
98
+ %{
99
+ assert(target);
100
+ return #{_bin.view.('target->bin', "#{hash} & target->hash_mask")};
101
+ }
102
+ end
103
+ method(_slot.const_lvalue, :_find_slot, { target: const_rvalue, value: element.const_rvalue }, visibility: :internal).configure do
104
+ # Find slot based on the value hash code
105
+ dependencies << _bin.view
106
+ inline_code _find_slot_hash(element.hash_code.(value))
107
+ end
108
+ method(:void, :_expand, { target: lvalue, force: :int.const_rvalue }, visibility: :internal).configure do
109
+ code %{
110
+ #{type} set;
111
+ #{_bin.range} r;
112
+ assert(target);
113
+ /* capacity threshold == 1.0 */
114
+ if(force || target->size >= #{_bin.size.('target->bin')}) {
115
+ #{create_capacity.(:set, _bin.size.('target->bin') + '*2')};
116
+ /* move elements to newly allocated set */
117
+ for(r = #{_bin.range.new.('target->bin')}; !#{_bin.range.empty.(:r)}; #{_bin.range.pop_front.(:r)}) {
118
+ #{_slot.lvalue} src = (#{_slot.lvalue})#{_bin.range.view_front.(:r)};
119
+ while(!#{_slot.empty.('*src')}) {
120
+ /* direct node relocation from original to new list bypassing node reallocation & payload copying */
121
+ #{_slot._node_p} node = #{_slot._pull_node.('*src')};
122
+ #{_slot.lvalue} dst = (#{_slot.lvalue})#{_find_slot.(target, 'node->element')};
123
+ #{_slot._push_node.('*dst', '*node')};
124
+ }
125
+ }
126
+ set.size = target->size; /* assume all elements have been moved into new set */
127
+ #{destroy.(target)};
128
+ *target = set;
129
+ }
130
+ }
131
+ end
132
+ subset.configure do
133
+ code %{
134
+ #{range} r;
135
+ assert(target);
136
+ assert(other);
137
+ if(#{size.(target)} > #{size.(other)}) return 0; /* larger set can't be a subset of a smaller one */
138
+ for(r = #{range.new.(target)}; !#{range.empty.(:r)}; #{range.pop_front.(:r)}) {
139
+ #{element.const_lvalue} e = #{range.view_front.(:r)};
140
+ if(!#{contains.(other, '*e')}) return 0;
141
+ }
142
+ return 1;
143
+ }
144
+ end
145
+ remove.configure do
146
+ code %{
147
+ int c;
148
+ #{_slot.lvalue} s;
149
+ assert(target);
150
+ s = (#{_slot.lvalue})#{_find_slot.(target, value)};
151
+ c = #{_slot.remove_first.('*s', value)};
152
+ if(c) --target->size;
153
+ return c;
154
+ }
155
+ end
156
+ put.configure do
157
+ code %{
158
+ #{_slot.lvalue} s;
159
+ assert(target);
160
+ s = (#{_slot.lvalue})#{_find_slot.(target, value)};
161
+ if(!#{_slot.find_first.('*s', value)}) {
162
+ #{_expand.(target, 0)};
163
+ #{_slot.push_front.('*s', value)};
164
+ ++target->size;
165
+ return 1;
166
+ } else return 0;
167
+ }
168
+ end
169
+ push.configure do
170
+ code %{
171
+ #{_slot.lvalue} s;
172
+ assert(target);
173
+ s = (#{_slot.lvalue})#{_find_slot.(target, value)};
174
+ if(#{_slot._replace_first.('*s', value)}) {
175
+ return 1;
176
+ } else {
177
+ /* add brand new value */
178
+ #{_expand.(target, 0)};
179
+ #{_slot.push_front.('*s', value)};
180
+ ++target->size;
181
+ return 0;
182
+ }
183
+ }
184
+ end
185
+ default_create.configure do
186
+ dependencies << create_capacity
187
+ inline_code %{
188
+ #{create_capacity.(target, 8)};
189
+ }
190
+ end
191
+ find_first.configure do
192
+ code %{
193
+ #{_slot.const_lvalue} s = #{_find_slot.(target, value)};
194
+ return #{_slot.find_first.('*s', value)};
195
+ }
196
+ end
197
+ copy.configure do
198
+ code %{
199
+ assert(target);
200
+ assert(source);
201
+ #{_bin.copy.('target->bin', 'source->bin')};
202
+ target->hash_mask = source->hash_mask;
203
+ target->size = source->size;
204
+ }
205
+ end
206
+ empty.configure do
207
+ inline_code %{
208
+ assert(target);
209
+ return target->size == 0;
210
+ }
211
+ end
212
+ size.configure do
213
+ inline_code %{
214
+ assert(target);
215
+ return target->size;
216
+ }
217
+ end
218
+ contains.configure do
219
+ code %{
220
+ #{_slot.const_lvalue} s;
221
+ assert(target);
222
+ s = #{_find_slot.(target, value)};
223
+ return #{_slot.contains.('*s', value)};
224
+ }
225
+ end
226
+ destroy.configure do
227
+ code %{
228
+ assert(target);
229
+ #{_bin.destroy.('target->bin')};
230
+ }
231
+ end
232
+ hash_code.configure do
233
+ code %{
234
+ #{range} r;
235
+ size_t hash;
236
+ for(hash = AUTOC_HASHER_SEED, r = #{range.new.(target)}; !#{range.empty.(:r)}; #{range.pop_front.(:r)}) {
237
+ #{element.const_lvalue} e = #{range.view_front.(:r)};
238
+ hash ^= #{element.hash_code.('*e')}; /* default incremental hasher is applicable to ordered collections only */
239
+ }
240
+ return hash;
241
+ }
242
+ end
243
+ end
244
+
245
+ end # HashSet
246
+
247
+
248
+ class HashSet::Range < ForwardRange
249
+
250
+ def render_interface(stream)
251
+ if public?
252
+ render_type_description(stream)
253
+ stream << %{
254
+ /**
255
+ #{ingroup}
256
+ @brief Opaque structure holding state of the hash set's range
257
+ @since 2.0
258
+ */
259
+ }
260
+ else
261
+ stream << PRIVATE
262
+ end
263
+ stream << %{
264
+ typedef struct {
265
+ #{_bin} bin; /**< @private */
266
+ #{_slot} slot; /**< @private */
267
+ } #{signature};
268
+ }
269
+ end
270
+
271
+ def _slot = iterable._slot.range
272
+
273
+ def _bin = iterable._bin.range
274
+
275
+ private
276
+
277
+ def configure
278
+ super
279
+ method(:void, :_advance, { range: rvalue }, visibility: :internal ).configure do
280
+ code %{
281
+ assert(range);
282
+ while(1) {
283
+ if(#{_slot.empty.('range->slot')}) {
284
+ /* current slot's range is empty - iterate forward to the next one */
285
+ #{_bin.pop_front.('range->bin')};
286
+ if(#{_bin.empty.('range->bin')}) {
287
+ /* all bin are iterated through, slot range is also empty - end of set */
288
+ break;
289
+ } else {
290
+ /* advance to the new (possibly empty) slot */
291
+ #{iterable._slot.const_lvalue} b = #{_bin.view_front.('range->bin')};
292
+ range->slot = #{_slot.new.('*b')};
293
+ }
294
+ } else {
295
+ /* current slot's range is not empty - no need to proceed */
296
+ break;
297
+ }
298
+ }
299
+ }
300
+ end
301
+ custom_create.configure do
302
+ code %{
303
+ #{_iterable._slot.const_lvalue} s;
304
+ assert(range);
305
+ assert(iterable);
306
+ range->bin = #{_bin.new.('iterable->bin')};
307
+ /* get the first slot's range regardless of its emptiness status */
308
+ s = #{_bin.view_front.('range->bin')};
309
+ range->slot = #{_slot.new.('*s')};
310
+ /* actually advance to the first non-empty slot */
311
+ #{_advance.(range)};
312
+ }
313
+ end
314
+ empty.configure do
315
+ code %{
316
+ assert(range);
317
+ return #{_slot.empty.('range->slot')};
318
+ }
319
+ end
320
+ pop_front.configure do
321
+ code %{
322
+ assert(range);
323
+ #{_slot.pop_front.('range->slot')};
324
+ #{_advance.(range)};
325
+ }
326
+ end
327
+ view_front.configure do
328
+ code %{
329
+ assert(range);
330
+ assert(!#{empty.(range)});
331
+ return #{_slot.view_front.('range->slot')};
332
+ }
333
+ end
334
+ end
335
+
336
+ end # Range
337
+
338
+
339
+ end