1 /// \file Text.d 2 3 module tagion.betterC.utils.Text; 4 5 @nogc: 6 7 import std.traits : Unqual, isIntegral, isSigned; 8 import tagion.betterC.utils.Memory; 9 import tagion.betterC.utils.platform : calloc; 10 11 //import core.stdc.stdio; 12 13 struct Text { 14 @nogc: 15 protected { 16 char[] str; 17 size_t index; 18 } 19 20 this(const size_t size) { 21 if (size > 0) { 22 str.create(size); 23 } 24 } 25 26 this(const(char[]) _str) { 27 this(_str.length + 1); 28 str[0 .. _str.length] = _str[0 .. $]; 29 index = _str.length; 30 str[$ - 1] = '\0'; 31 } 32 /** 33 This takes over the overship of the data 34 */ 35 this(ref Text _surrender) { 36 this.str = _surrender.str; 37 this.index = _surrender.index; 38 _surrender.str = null; 39 _surrender.index = 0; 40 } 41 42 char[] expropriate() { 43 scope (exit) { 44 str = null; 45 index = 0; 46 } 47 return str[0 .. index]; 48 } 49 50 @property size_t length() const pure { 51 return index; 52 } 53 54 char opIndex(const size_t i) pure const { 55 if (i < index) { 56 return str[i]; 57 } 58 return '\0'; 59 } 60 61 string opSlice(const size_t from, const size_t to) const 62 in { 63 assert(from <= to); 64 assert(to <= index); 65 } 66 do { 67 return cast(string)(str[from .. to]); 68 } 69 70 string opSlice() const pure { 71 return cast(immutable) str[0 .. index]; 72 } 73 74 alias serialize = opSlice; 75 void opOpAssign(string op)(const(char[]) cat) if (op == "~") { 76 const new_index = index + cat.length; 77 scope (exit) { 78 index = new_index; 79 } 80 if (index + cat.length + 1 > str.length) { 81 resize(str, index + cat.length + 1); 82 } 83 str[index .. new_index] = cat; 84 str[new_index] = '\0'; 85 } 86 87 ref Text opCall(const(char[]) cat) return { 88 opOpAssign!"~"(cat); 89 return this; 90 } 91 92 ref Text opCall(T)(T num, const size_t base = 10) if (isIntegral!T) { 93 //const negative=(num < 0); 94 enum numbers = "0123456789abcdef"; 95 static if (isSigned!T) { 96 enum max_size = T.min.stringof.length + 1; 97 } 98 else { 99 enum max_size = T.max.stringof.length + 1; 100 } 101 102 if (index + max_size > str.length) { 103 resize(str, index + max_size); 104 } 105 static if (isSigned!T) { 106 if (num < 0) { 107 str[index] = '-'; 108 num = -num; 109 index++; 110 } 111 } 112 const(char[]) fill_numbers(T num, char[] s) { 113 alias Mutable = Unqual!T; 114 Mutable n = num; 115 uint i; 116 do { 117 const n_index = cast(uint)(n % cast(T) base); 118 s[i++] = numbers[n_index]; 119 n /= base; 120 } 121 while (n > 0); 122 return s[0 .. i]; 123 } 124 125 char[max_size] buf; 126 const reverse_numbers = fill_numbers(num, buf); 127 foreach_reverse (i, c; reverse_numbers) { 128 str[index] = c; 129 index++; 130 } 131 str[index] = '\0'; 132 return this; 133 } 134 135 void dispose() { 136 str.dispose; 137 index = 0; 138 } 139 140 ~this() { 141 str.dispose; 142 } 143 } 144 145 unittest { 146 // import core.stdc.stdio; 147 Text text; 148 immutable(char[12]) check = "Some text 42"; 149 size_t size = 4; 150 text ~= check[0 .. size]; 151 assert(text.serialize == check[0 .. size]); 152 text ~= check[size .. size + 6]; 153 size += 6; 154 assert(text.serialize == check[0 .. size]); 155 text(42); 156 assert(text.serialize == check); 157 }