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,707 @@
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
+ # @abstract
15
+ class Range < Composite
16
+
17
+ attr_reader :iterable
18
+
19
+ def default_constructible? = false
20
+ def destructible? = false
21
+ def comparable? = false
22
+ def orderable? = false
23
+ def copyable? = false
24
+
25
+ def to_value = @v ||= Value.new(self)
26
+
27
+ def initialize(iterable, visibility:)
28
+ super(iterable.identifier(:range, abbreviate: visibility == :internal), visibility:)
29
+ dependencies << (@iterable = iterable) << INFO
30
+ end
31
+
32
+ def type_tag = "#{iterable.type_tag}::Range"
33
+
34
+ def brief = "@brief Range (iterator) for type #{iterable.type_tag}"
35
+
36
+ def render_type_description(stream)
37
+ stream << %{
38
+ /**
39
+ #{defgroup}
40
+
41
+ #{brief}
42
+
43
+ Range is means of traversing though the container contents in a sequential manner.
44
+ It is basically an extension of iterator.
45
+
46
+ It can be used the following way:
47
+
48
+ @code{.c}
49
+ for(#{signature} r = #{new}(&it); !#{empty}(&r); #{pop_front}(&r)) { ... }
50
+ @endcode
51
+
52
+ @see @ref Range
53
+
54
+ @since 2.0
55
+ */
56
+ }
57
+ end
58
+
59
+ private
60
+
61
+ alias _iterable iterable # Use _iterable.() within method bodies as it is shadowed by the commonly used iterable function parameter
62
+
63
+ def configure
64
+ super
65
+ method(:void, :create, { range: lvalue, iterable: iterable.const_rvalue }, instance: :custom_create).configure do
66
+ header %{
67
+ @brief Create a new range for the specified iterable
68
+
69
+ @param[out] range range to be initialized
70
+ @param[in] iterable container to iterate over
71
+
72
+ This function creates a range to iterate over all iterable's elements.
73
+
74
+ @note Previous contents of `*range` is overwritten.
75
+
76
+ @see #{type.new}
77
+
78
+ @since 2.0
79
+ }
80
+ end
81
+ method(self, :new, { iterable: iterable.const_rvalue }).configure do
82
+ dependencies << custom_create
83
+ header %{
84
+ @brief Return new range iterator for the specified container
85
+
86
+ @param[in] iterable container to iterate over
87
+ @return new initialized range
88
+
89
+ This function returns a new range created by @ref #{type.custom_create}.
90
+ It is intended to be used within the ***for(;;)*** statement as follows
91
+
92
+ @code{.c}
93
+ for(#{type.signature} r = #{type.new}(&it); !#{type.empty}(&r); #{type.pop_front}(&r)) { ... }
94
+ @endcode
95
+
96
+ where `it` is the iterable to iterate over and `r` is a locally-scoped range bound to it.
97
+
98
+ @since 2.0
99
+ }
100
+ inline_code %{
101
+ #{type} r;
102
+ assert(iterable);
103
+ #{custom_create.(:r, iterable)};
104
+ return r;
105
+ }
106
+ end
107
+ end
108
+
109
+ end # Range
110
+
111
+
112
+ # @abstract
113
+ class InputRange < Range
114
+
115
+ private
116
+
117
+ def configure
118
+ super
119
+ method(:int, :empty, { range: const_rvalue }).configure do
120
+ header %{
121
+ @brief Check for range emptiness
122
+
123
+ @param[in] range range to check
124
+ @return non-zero value if the range is not empty or zero value otherwise
125
+
126
+ An empty range is the range for which there are to accessible elements left.
127
+ This specifically means that any calls to the element retrieval and position change functions
128
+ (@ref #{type.take_front}, @ref #{type.view_front}, @ref #{type.pop_front} et al.) are invalid for empty ranges.
129
+
130
+ @since 2.0
131
+ }
132
+ end
133
+ method(:void, :pop_front, { range: rvalue }).configure do
134
+ header %{
135
+ @brief Advance front position to the next existing element
136
+
137
+ @param[in] range range to advance front position for
138
+
139
+ This function is used to get to the next element in the range.
140
+
141
+ @note Prior calling this function one must ensure that the range is not empty (see @ref #{type.empty}).
142
+ Advancing position of a range that is already empty results in undefined behaviour.
143
+
144
+ @since 2.0
145
+ }
146
+ end
147
+ method(iterable.element.const_lvalue, :view_front, { range: const_rvalue }).configure do
148
+ header %{
149
+ @brief Get a view of the front element
150
+
151
+ @param[in] range range to retrieve element from
152
+ @return a view of an element at the range's front position
153
+
154
+ This function is used to get a constant reference (in form of the C pointer) to the value contained in the iterable container at the range's front position.
155
+ Refer to @ref #{type.take_front} to get an independent copy of that element.
156
+
157
+ It is generally not safe to bypass the constness and to alter the value in place (although no one prevents to).
158
+
159
+ @note Range must not be empty (see @ref #{type.empty}).
160
+
161
+ @since 2.0
162
+ }
163
+ end
164
+ method(iterable.element, :take_front, { range: const_rvalue }, constraint:-> { iterable.element.copyable? }).configure do
165
+ dependencies << empty << view_front
166
+ inline_code %{
167
+ #{iterable.element} result;
168
+ #{iterable.element.const_lvalue} e;
169
+ assert(!#{empty.(range)});
170
+ e = #{view_front.(range)};
171
+ #{iterable.element.copy.(:result, '*e')};
172
+ return result;
173
+ }
174
+ header %{
175
+ @brief Get a copy of the front element
176
+
177
+ @param[in] range range to retrieve element from
178
+ @return a *copy* of element at the range's front position
179
+
180
+ This function is used to get a *copy* of the value contained in the iterable container at the range's front position.
181
+ Refer to @ref #{type.view_front} to get a view of the element without making an independent copy.
182
+
183
+ This function requires the element type to be *copyable* (i.e. to have a well-defined copy operation).
184
+
185
+ @note Range must not be empty (see @ref #{type.empty}).
186
+
187
+ @since 2.0
188
+ }
189
+ end
190
+ end
191
+
192
+ end # InputRange
193
+
194
+
195
+ # @abstract
196
+ class ForwardRange < InputRange
197
+
198
+ def copyable? = true
199
+
200
+ private
201
+
202
+ def configure
203
+ super
204
+ copy.configure do
205
+ header %{
206
+ @brief Create a copy of the range state
207
+
208
+ @param[out] target range to be created
209
+ @param[in] source range to be cloned
210
+
211
+ This function is meant to an independent copy (a clone) of `*source` range in place of `*target`.
212
+
213
+ Previous contents of `*target` is overwritten.
214
+
215
+ @since 2.0
216
+ }
217
+ inline_code %{
218
+ assert(target);
219
+ assert(source);
220
+ *target = *source;
221
+ }
222
+ end
223
+ end
224
+
225
+ end # ForwardRange
226
+
227
+
228
+ # @abstract
229
+ class BidirectionalRange < ForwardRange
230
+
231
+ private
232
+
233
+ def configure
234
+ super
235
+ method(:void, :pop_back, { range: rvalue }).configure do
236
+ header %{
237
+ @brief Rewind back position to the previous existing element
238
+
239
+ @param[in] range range to rewind back position for
240
+
241
+ This function is used to get to the previous element in the range.
242
+
243
+ @note Prior calling this function one must ensure that the range is not empty (see @ref #{type.empty}).
244
+ Rewinding position of a range that is already empty results in undefined behaviour.
245
+
246
+ @since 2.0
247
+ }
248
+ end
249
+ method(iterable.element.const_lvalue, :view_back, { range: const_rvalue }).configure do
250
+ header %{
251
+ @brief Get a view of the back element
252
+
253
+ @param[in] range range to retrieve element from
254
+ @return a view of an element at the range's back position
255
+
256
+ This function is used to get a constant reference (in form of the C pointer) to the value contained in the iterable container at the range's back position.
257
+ Refer to @ref #{type.take_back} to get an independent copy of that element.
258
+
259
+ It is generally not safe to bypass the constness and to alter the value in place (although no one prevents to).
260
+
261
+ @note Range must not be empty (see @ref #{type.empty}).
262
+
263
+ @since 2.0
264
+ }
265
+ end
266
+ method(iterable.element, :take_back, { range: const_rvalue }, constraint:-> { iterable.element.copyable? }).configure do
267
+ dependencies << empty << view_back
268
+ inline_code %{
269
+ #{iterable.element} result;
270
+ #{iterable.element.const_lvalue} e;
271
+ assert(!#{empty.(range)});
272
+ e = #{view_back.(range)};
273
+ #{iterable.element.copy.(:result, '*e')};
274
+ return result;
275
+ }
276
+ header %{
277
+ @brief Get a copy of the back element
278
+
279
+ @param[in] range range to retrieve element from
280
+ @return a *copy* of element at the range's back position
281
+
282
+ This function is used to get a *copy* of the value contained in the iterable container at the range's front position.
283
+ Refer to @ref #{type.view_back} to get a view of the element without making an independent copy.
284
+
285
+ This function requires the element type to be *copyable* (i.e. to have a well-defined copy operation).
286
+
287
+ @note Range must not be empty (see @ref #{type.empty}).
288
+
289
+ @since 2.0
290
+ }
291
+ end
292
+ end
293
+
294
+ end # BidirectionalRange
295
+
296
+
297
+ # @abstract
298
+ class DirectAccessRange < BidirectionalRange
299
+
300
+ private
301
+
302
+ def configure
303
+ super
304
+ method(:size_t, :size, { range: const_rvalue }).configure do
305
+ header %{
306
+ @brief Get a number of elements in the range
307
+
308
+ @param[in] range range to query
309
+ @return a number of elements
310
+
311
+ This function returns a number of elements between the range's front and back positions inclusively.
312
+ As a consequence, the result changes with every invocation of position change functions (@ref #{type.pop_front}, @ref #{type.pop_back}),
313
+ so be careful not to cache this value.
314
+
315
+ For empty range this function returns 0.
316
+
317
+ @since 2.0
318
+ }
319
+ end
320
+ method(:int, :check, { range: const_rvalue, index: :size_t.const_rvalue } ).configure do
321
+ dependencies << size
322
+ inline_code %{
323
+ assert(range);
324
+ return index < #{size.(range)};
325
+ }
326
+ header %{
327
+ @brief Validate specified range's index
328
+
329
+ @param[in] range range to query
330
+ @param[in] index index to verify
331
+ @return non-zero value if speicfied index is valid and zero value otherwise
332
+
333
+ This function performs the range's index validity check.
334
+
335
+ In any case, this function should be used for the index validation prior getting direct access to range's elements
336
+ with @ref #{type.get}, @ref #{type.view} etc. as these functions do not normally do it themselves for performance reasons.
337
+
338
+ @since 2.0
339
+ }
340
+ end
341
+ method(iterable.element.const_lvalue, :view, { range: const_rvalue, index: :size_t.const_rvalue }).configure do
342
+ header %{
343
+ @brief Get view of the specific element
344
+
345
+ @param[in] range range to view element from
346
+ @param[in] index position to access element at
347
+ @return a view of element at `index`
348
+
349
+ This function is used to get a constant reference (in form of the C pointer) to the value contained in the range at the specific position.
350
+ Refer to @ref #{type.get} to get a copy of the element.
351
+
352
+ @note The specified `index` is required to be within the [0, @ref #{type.size}) range.
353
+
354
+ @since 2.0
355
+ }
356
+ end
357
+ method(iterable.element, :get, { range: const_rvalue, index: :size_t.const_rvalue }, constraint:-> { iterable.element.copyable? }).configure do
358
+ dependencies << check << view
359
+ inline_code %{
360
+ #{iterable.element} r;
361
+ #{iterable.element.const_lvalue} e;
362
+ assert(#{check.(range, index)});
363
+ e = #{view.(range, index)};
364
+ #{iterable.element.copy.(:r, '*e')};
365
+ return r;
366
+ }
367
+ header %{
368
+ @brief Get a copy of the specific element
369
+
370
+ @param[in] range range to retrieve element from
371
+ @param[in] index position to view element at
372
+ @return a *copy* of element at `index`
373
+
374
+ This function is used to get a *copy* of the value contained in the range at the specific position.
375
+ Refer to @ref #{type.view} to get a view of the element without making an independent copy.
376
+
377
+ This function requires the element type to be *copyable* (i.e. to have a well-defined copy operation).
378
+
379
+ @note The specified `position` is required to be within the [0, @ref #{type.size}) range.
380
+
381
+ @since 2.0
382
+ }
383
+ end
384
+ end
385
+
386
+ end # DirectAccessRange
387
+
388
+
389
+ # @abstract
390
+ class ContiguousRange < DirectAccessRange
391
+
392
+ def initialize(iterable, visibility: :public, parallel: nil)
393
+ super(iterable, visibility:)
394
+ @parallel = parallel
395
+ end
396
+
397
+ def render_interface(stream)
398
+ if public?
399
+ case @parallel
400
+ when nil
401
+ stream << %{
402
+ /**
403
+ #{defgroup}
404
+
405
+ #{brief}
406
+
407
+ This is the range for contiguous data structures (vectors, strings etc.)
408
+
409
+ It can be used the following way:
410
+
411
+ @code{.c}
412
+ for(#{signature} r = #{new}(&it); !#{empty}(&r); #{pop_front}(&r)) { ... }
413
+ @endcode
414
+
415
+ @see @ref Range
416
+
417
+ @since 2.0
418
+ */
419
+ }
420
+ when :openmp
421
+ stream << %{
422
+ /**
423
+ #{defgroup}
424
+
425
+ #{brief}
426
+
427
+ This is the range for contiguous data structures (vectors, strings etc.)
428
+
429
+ The @ref #{new} and @ref #{custom_create} range constructors create OpenMP-aware range objects
430
+ which account for parallel iteration in the way
431
+
432
+ @code{.c}
433
+ #pragma omp parallel
434
+ for(#{signature} r = #{new}(&it); !#{empty}(&r); #{pop_front}(&r)) { ... }
435
+ @endcode
436
+
437
+ @see @ref Range
438
+
439
+ @since 2.0
440
+ */
441
+ }
442
+ end
443
+ else
444
+ stream << PRIVATE
445
+ end
446
+ if public?
447
+ stream << %{
448
+ /**
449
+ #{ingroup}
450
+ @brief Opaque structure holding state of the contiguous container's range
451
+ @since 2.0
452
+ */
453
+ }
454
+ else
455
+ stream << PRIVATE
456
+ end
457
+ stream << %{
458
+ typedef struct {
459
+ #{iterable.element.lvalue} front; /**< @private */
460
+ #{iterable.element.lvalue} back; /**< @private */
461
+ } #{signature};
462
+ }
463
+ end
464
+
465
+ private
466
+
467
+ OPTIONAL_OMP_H = AutoC::Code.new interface: %{
468
+ #ifdef _OPENMP
469
+ #include <omp.h>
470
+ #endif
471
+ }
472
+
473
+ def configure
474
+ super
475
+ case @parallel
476
+ when nil
477
+ custom_create.configure do
478
+ inline_code %{
479
+ assert(range);
480
+ assert(iterable);
481
+ range->front = #{_iterable.storage(iterable)};
482
+ range->back = #{_iterable.storage(iterable)} + #{_iterable.size.(iterable)} - 1;
483
+ }
484
+ end
485
+ when :openmp
486
+ dependencies << OPTIONAL_OMP_H
487
+ custom_create.configure do
488
+ inline_code %{
489
+ size_t size;
490
+ #ifdef _OPENMP
491
+ unsigned chunk_count;
492
+ #endif
493
+ assert(range);
494
+ assert(iterable);
495
+ size = #{_iterable.size.(iterable)};
496
+ #ifdef _OPENMP
497
+ if(omp_in_parallel() && (chunk_count = omp_get_num_threads()) > 1) {
498
+ int chunk_id = omp_get_thread_num();
499
+ size_t chunk_size = size / omp_get_num_threads();
500
+ range->front = #{_iterable.storage(iterable)} + chunk_id*chunk_size;
501
+ range->back = #{_iterable.storage(iterable)} + (
502
+ chunk_id < chunk_count - 1 ?
503
+ (chunk_id + 1)*chunk_size - 1 :
504
+ size - 1
505
+ );
506
+ } else {
507
+ #endif
508
+ range->front = #{_iterable.storage(iterable)};
509
+ range->back = #{_iterable.storage(iterable)} + size - 1;
510
+ #ifdef _OPENMP
511
+ }
512
+ #endif
513
+ }
514
+ end
515
+ else
516
+ raise "unsupported parallel range specifier #{@parallel}"
517
+ end
518
+ empty.configure do
519
+ inline_code %{
520
+ assert(range);
521
+ assert(range->front);
522
+ assert(range->back);
523
+ return range->front > range->back;
524
+ }
525
+ end
526
+ pop_front.configure do
527
+ dependencies << empty
528
+ inline_code %{
529
+ assert(range);
530
+ assert(range->front);
531
+ assert(!#{empty.(range)});
532
+ ++range->front;
533
+ }
534
+ end
535
+ pop_back.configure do
536
+ dependencies << empty
537
+ inline_code %{
538
+ assert(range);
539
+ assert(range->back);
540
+ assert(!#{empty.(range)});
541
+ --range->back;
542
+ }
543
+ end
544
+ view_front.configure do
545
+ dependencies << empty
546
+ inline_code %{
547
+ assert(range);
548
+ assert(range->front);
549
+ assert(!#{empty.(range)});
550
+ return range->front;
551
+ }
552
+ end
553
+ view_back.configure do
554
+ dependencies << empty
555
+ inline_code %{
556
+ assert(range);
557
+ assert(range->back);
558
+ assert(!#{empty.(range)});
559
+ return range->back;
560
+ }
561
+ end
562
+ size.configure do
563
+ dependencies << empty
564
+ inline_code %{
565
+ assert(range);
566
+ assert(range->front);
567
+ assert(range->back);
568
+ return #{empty.(range)} ? 0 : range->back - range->front + 1;
569
+ }
570
+ end
571
+ view.configure do
572
+ dependencies << check
573
+ inline_code %{
574
+ assert(range);
575
+ assert(#{check.(range, index)});
576
+ return range->front + index;
577
+ }
578
+ end
579
+ end
580
+
581
+ end # ContiguousRange
582
+
583
+
584
+ class AssociativeRange < ForwardRange
585
+
586
+ private
587
+
588
+ def configure
589
+ super
590
+ method(iterable.index.const_lvalue, :view_index_front, { range: const_rvalue }).configure do
591
+ header %{
592
+ @brief Get a view of the front index
593
+
594
+ @param[in] range range to retrieve element from
595
+ @return a view of an index at the range's front position
596
+
597
+ This function is used to get a constant reference (in form of the C pointer) to the index associated with element at the range's front position.
598
+ Refer to @ref #{type.take_index_front} to get an independent copy of that index.
599
+
600
+ It is generally not safe to bypass the constness and to alter the value in place (although no one prevents to).
601
+
602
+ @note Range must not be empty (see @ref #{type.empty}).
603
+
604
+ @since 2.0
605
+ }
606
+ end
607
+ method(iterable.index, :take_index_front, { range: const_rvalue }, constraint:-> { iterable.index.copyable? && iterable.element.copyable? }).configure do
608
+ dependencies << empty << view_index_front
609
+ inline_code %{
610
+ #{iterable.index} result;
611
+ #{iterable.index.const_lvalue} e;
612
+ assert(!#{empty.(range)});
613
+ e = #{view_index_front.(range)};
614
+ #{iterable.index.copy.(:result, '*e')};
615
+ return result;
616
+ }
617
+ header %{
618
+ @brief Get a copy of the front index associated with element
619
+
620
+ @param[in] range range to retrieve element from
621
+ @return a *copy* of index at the range's front position
622
+
623
+ This function is used to get a *copy* of the index associated with element at the range's front position.
624
+ Refer to @ref #{type.view_index_front} to get a view of the index without making an independent copy.
625
+
626
+ This function requires the element type to be *copyable* (i.e. to have a well-defined copy operation).
627
+
628
+ @note Range must not be empty (see @ref #{type.empty}).
629
+
630
+ @since 2.0
631
+ }
632
+ end
633
+ end
634
+
635
+ end # AssociativeRange
636
+
637
+
638
+ Range::INFO = Code.new interface: %{
639
+ /**
640
+ @page Range
641
+
642
+ @brief Generalization of the iterator
643
+
644
+ A range is a means of traversing through the container's contents in which it is similar to the iterator.
645
+
646
+ Current implementation is loosely modeled after the [D language ranges](https://dlang.org/phobos/std_range.html).
647
+
648
+ Note that current ranges' implementation is fairly basic lacking iterable alteration, thread safety etc.
649
+ On the other hand, all currently implemented ranges are the simple value types which do not require explicit
650
+ copying/destruction thus making life slightly easier.
651
+ Therefore they can be passed out in/out the functions as is - just watch out the dangers of passing the
652
+ iterable values they are bound to.
653
+
654
+ A sample code involving iteration over the contents of a hypothetical `List` iterable value is shown below.
655
+
656
+ @code{.c}
657
+ List list;
658
+ ...
659
+ for(ListRange r = ListRangeNew(&list); !ListRangeEmpty(&r); ListRangePopFront(&r)) {
660
+ ... = ListRangeTakeFront(&r);
661
+ }
662
+ @endcode
663
+
664
+ Currently implemented range archetypes:
665
+ @subpage InputRange
666
+ @subpage ForwardRange
667
+ @subpage BidirectionalRange
668
+ @subpage DirectAccessRange
669
+
670
+ @since 2.0
671
+
672
+ @page InputRange
673
+
674
+ @brief Basic unidirectional range
675
+
676
+ An input range is a @ref Range which sports a single direction of traversing the elements.
677
+
678
+ @since 2.0
679
+
680
+ @page ForwardRange
681
+
682
+ @brief Unidirectional range with checkpoint
683
+
684
+ A forward range is an @ref InputRange which also allows to make a snapshot of the current range's state for possible fallback.
685
+
686
+ @since 2.0
687
+
688
+ @page BidirectionalRange
689
+
690
+ @brief Basic bidirectional range
691
+
692
+ A bidirectional range is a @ref ForwardRange which can also be traversed backwards.
693
+
694
+ @since 2.0
695
+
696
+ @page DirectAccessRange
697
+
698
+ @brief Bidirectional range with indexed access to specific elements
699
+
700
+ A random access range is a @ref BidirectionalRange which is also capable of accessing the elements directly using index.
701
+
702
+ @since 2.0
703
+ */
704
+ }
705
+
706
+
707
+ end