autoc 1.4 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|