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.
- checksums.yaml +5 -5
- data/CHANGES.md +3 -0
- data/README.md +149 -0
- data/cmake/AutoC.cmake +39 -0
- data/lib/autoc/allocators.rb +51 -0
- data/lib/autoc/association.rb +126 -0
- data/lib/autoc/box.rb +311 -0
- data/lib/autoc/cmake.rb +54 -0
- data/lib/autoc/collection.rb +83 -110
- data/lib/autoc/composite.rb +333 -0
- data/lib/autoc/cstring.rb +263 -0
- data/lib/autoc/function.rb +247 -0
- data/lib/autoc/hash_map.rb +328 -0
- data/lib/autoc/hash_set.rb +339 -0
- data/lib/autoc/hashers.rb +102 -0
- data/lib/autoc/list.rb +444 -0
- data/lib/autoc/module.rb +434 -0
- data/lib/autoc/openmp.rb +15 -0
- data/lib/autoc/primitive.rb +27 -0
- data/lib/autoc/ranges.rb +707 -0
- data/lib/autoc/record.rb +247 -0
- data/lib/autoc/scaffold/docs.rb +117 -0
- data/lib/autoc/scaffold/generic_value.rb +86 -0
- data/lib/autoc/scaffold/project.rb +75 -0
- data/lib/autoc/scaffold/test_cstring.rb +113 -0
- data/lib/autoc/scaffold/test_cstring_hash_set.rb +35 -0
- data/lib/autoc/scaffold/test_int_box.rb +22 -0
- data/lib/autoc/scaffold/test_int_hash_set.rb +448 -0
- data/lib/autoc/scaffold/test_int_list.rb +106 -0
- data/lib/autoc/scaffold/test_int_vector.rb +83 -0
- data/lib/autoc/scaffold/test_v2v_hash_map.rb +83 -0
- data/lib/autoc/scaffold/test_value_hash_set.rb +60 -0
- data/lib/autoc/scaffold/test_value_vector.rb +146 -0
- data/{test/test.rb → lib/autoc/scaffold/tests.rb} +179 -158
- data/lib/autoc/scaffold.rb +12 -0
- data/lib/autoc/sequential.rb +99 -0
- data/lib/autoc/set.rb +331 -0
- data/lib/autoc/std.rb +149 -0
- data/lib/autoc/type.rb +93 -531
- data/lib/autoc/vector.rb +290 -0
- data/lib/autoc.rb +4 -35
- metadata +55 -85
- data/.yardopts +0 -4
- data/CHANGES +0 -23
- data/README +0 -28
- data/doc/AutoC/Code.html +0 -523
- data/doc/AutoC/Collection.html +0 -1214
- data/doc/AutoC/HashMap.html +0 -1441
- data/doc/AutoC/HashSet.html +0 -916
- data/doc/AutoC/Iterators/Bidirectional.html +0 -204
- data/doc/AutoC/Iterators/Unidirectional.html +0 -200
- data/doc/AutoC/Iterators.html +0 -126
- data/doc/AutoC/List.html +0 -1039
- data/doc/AutoC/Maps.html +0 -290
- data/doc/AutoC/Module/File.html +0 -415
- data/doc/AutoC/Module/Header.html +0 -437
- data/doc/AutoC/Module/Source.html +0 -707
- data/doc/AutoC/Module.html +0 -948
- data/doc/AutoC/Priority.html +0 -138
- data/doc/AutoC/Queue.html +0 -1172
- data/doc/AutoC/Reference.html +0 -735
- data/doc/AutoC/Sets.html +0 -520
- data/doc/AutoC/String.html +0 -1394
- data/doc/AutoC/TreeMap.html +0 -1565
- data/doc/AutoC/TreeSet.html +0 -1447
- data/doc/AutoC/Type.html +0 -2148
- data/doc/AutoC/UserDefinedType.html +0 -1047
- data/doc/AutoC/Vector.html +0 -987
- data/doc/AutoC.html +0 -331
- data/doc/_index.html +0 -388
- data/doc/class_list.html +0 -51
- data/doc/css/common.css +0 -1
- data/doc/css/full_list.css +0 -58
- data/doc/css/style.css +0 -481
- data/doc/file.CHANGES.html +0 -117
- data/doc/file.README.html +0 -116
- data/doc/file_list.html +0 -61
- data/doc/frames.html +0 -17
- data/doc/index.html +0 -116
- data/doc/js/app.js +0 -243
- data/doc/js/full_list.js +0 -216
- data/doc/js/jquery.js +0 -4
- data/doc/method_list.html +0 -1307
- data/doc/top-level-namespace.html +0 -112
- data/lib/autoc/code.rb +0 -237
- data/lib/autoc/collection/hash_map.rb +0 -385
- data/lib/autoc/collection/hash_set.rb +0 -337
- data/lib/autoc/collection/iterator.rb +0 -39
- data/lib/autoc/collection/list.rb +0 -429
- data/lib/autoc/collection/map.rb +0 -41
- data/lib/autoc/collection/queue.rb +0 -517
- data/lib/autoc/collection/set.rb +0 -134
- data/lib/autoc/collection/tree_map.rb +0 -464
- data/lib/autoc/collection/tree_set.rb +0 -611
- data/lib/autoc/collection/vector.rb +0 -336
- data/lib/autoc/string.rb +0 -492
- data/test/test_auto.c +0 -7141
- data/test/test_auto.h +0 -753
- data/test/test_char_string.rb +0 -270
- data/test/test_int_list.rb +0 -35
- data/test/test_int_tree_set.rb +0 -111
- data/test/test_int_vector.rb +0 -34
- data/test/test_value_hash_map.rb +0 -162
- data/test/test_value_hash_set.rb +0 -173
- data/test/test_value_list.rb +0 -193
- data/test/test_value_queue.rb +0 -275
- data/test/test_value_tree_map.rb +0 -176
- data/test/test_value_tree_set.rb +0 -173
- data/test/test_value_vector.rb +0 -155
- 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
|