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 Ilya Yaroshenko, Kaleidic Associates Advisory Limited, Symmetry Investments 8 Authors: Ilya Yaroshenko, 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 }