1 /++
2 Ranges.
3
4 See_also: $(MREF mir,_primitives).
5
6 License: $(HTTP www.apache.org/licenses/LICENSE-2.0, Apache-2.0)
7 Copyright: 2020 Ilia Ki, Kaleidic Associates Advisory Limited, Symmetry Investments
8 Authors: Ilia Ki, Phobos Authors
9 +/
10 module mir.range;
11
12 /++
13 Data size counter.
14
15 Does not store anything.
16 +/
17 struct Counter(T)
18 {
19 import std.range: isInputRange, ElementType;
20 import std.traits: isImplicitlyConvertible, isSomeChar;
21 ///
22 size_t _count;
23
24 /// Data count.
25 size_t count()() @property
26 {
27 return _count;
28 }
29
30 private template canPutItem(U)
31 {
32 enum bool canPutItem =
33 isImplicitlyConvertible!(U, T) ||
34 isSomeChar!T && isSomeChar!U;
35 }
36
37 private template canPutRange(Range)
38 {
39 import mir.primitives: front;
40 enum bool canPutRange =
41 isInputRange!Range &&
42 is(typeof(Counter.init.put(Range.init.front)));
43 }
44
45 ///
46 void put(U)(auto ref U item) if (canPutItem!U)
47 {
48 static if (isSomeChar!T && isSomeChar!U && T.sizeof < U.sizeof)
49 {
50 import std.utf: codeLength;
51 _count += codeLength!T(item);
52 }
53 else
54 {
55 _count++;
56 }
57 }
58
59 ///
60 void put(Range)(Range items) if (canPutRange!Range)
61 {
62 // note, we disable this branch for appending one type of char to
63 // another because we can't trust the length portion.
64 static if (!(isSomeChar!T && isSomeChar!(ElementType!Range) &&
65 !is(immutable Range == immutable T[])))
66 {
67 import mir.primitives: hasLength;
68 static if (hasLength!Range)
69 {
70 _count += items.length;
71 }
72 else
73 {
74 for (;!items.empty; items.popFront)
75 _count++;
76 }
77 }
78 else
79 {
80 import std.utf: codeLength;
81 _count += codeLength!T(items);
82 }
83 }
84 }
85
86 ///
87 version(mir_test) unittest
88 {
89 Counter!char counter;
90 counter.put("Ми");
91 assert(counter.count == 4);
92 counter.put('р'); // Cyrillic
93 assert(counter.count == 6);
94 }
95
96 ///
97 version(mir_test) unittest
98 {
99 Counter!wchar counter;
100 counter.put("Ми");
101 assert(counter.count == 2);
102 counter.put('р'); // Cyrillic
103 assert(counter.count == 3);
104 }
105
106 ///
107 version(mir_test) unittest
108 {
109 Counter!int counter;
110 import std.algorithm: until;
111 counter.put([1, 2, 3, 4, 5].until(3));
112 }