1 /// Authors: Chance Snow 2 /// Copyright: Copyright © 2024 Chance Snow. All rights reserved. 3 /// License: MIT License 4 module dbpf.types; 5 6 import std.conv : castFrom, to; 7 8 /// A fixed-sized string. 9 /// Params: 10 /// Size: Size of string, in bytes. 11 struct str(int Size) { 12 align(1): 13 private ubyte[Size] payload; 14 alias value this; 15 16 /// 17 this(string str) { 18 value = str; 19 } 20 21 string value() inout @property { 22 import std.string : fromStringz; 23 return castFrom!(inout ubyte[4]).to!(inout char*)(payload).fromStringz.to!string; 24 } 25 26 string value(string str) @property { 27 import std.algorithm : copy; 28 import std.conv : text; 29 import std.string : toStringz; 30 31 assert(str.length <= payload.sizeof, "Value is too long."); 32 // Ensure the null-terminator is leftover 33 assert(str.toStringz[0..str.length].copy(payload[]).length == 1); 34 return str; 35 } 36 } 37 38 static assert(str!4.alignof == 1); 39 static assert(str!4.sizeof == 4); 40 41 unittest { 42 import std.algorithm : equal; 43 44 str!4 id = "foo"; 45 assert(id.length == 3); 46 assert(id.value.equal("foo")); 47 } 48 49 /// A 24-bit signed integer. 50 /// See_Also: <a href="https://forum.dlang.org/thread/sarwanlrindyawtztlgh@forum.dlang.org"24-bit int</a> (D Forum) 51 struct int24 { 52 align(1): 53 private ubyte[3] payload; 54 alias value this; 55 56 /// 57 this(int x) { 58 value = x; 59 } 60 61 /// 62 int value() inout @property { 63 int val = *cast(int*)&payload & 0xFFFFFF; 64 if (val & 0x800000) 65 val |= 0xFF000000; 66 return val; 67 } 68 69 /// 70 int value(int x) @property { 71 version(BigEndian) payload = (cast(ubyte*)&x)[1..4]; 72 else payload = (cast(ubyte*)&x)[0 .. 3]; 73 return value; 74 } 75 76 /// 77 auto opUnary(string op)() { 78 static if (op == "++") 79 value = value + 1; 80 else static if (op == "--") 81 value = value - 1; 82 else static if (op == "+") 83 return value; 84 else static if (op == "-") 85 return -value; 86 else static if (op == "~") 87 return ~value; 88 else 89 static assert(0, "Unary operator '" ~ op ~ "' is not supported by `int24`."); 90 } 91 92 /// 93 auto opOpAssign(string op)(int x) { 94 static const error = "Binary operator '" ~ op ~ "' is not supported by `int24`."; 95 static assert(__traits(compiles, { mixin("value = value " ~ op ~ " x;"); }), error); 96 97 mixin("value = value " ~ op ~ " x;"); 98 return this; 99 } 100 } 101 102 static assert(int24.sizeof == 3); 103 static assert(int24.alignof == 1); 104 105 unittest { 106 int24[3] a; 107 assert(a.sizeof == 9); 108 109 // Max value 110 a[1] = 8_388_607; 111 assert(a[1] == 8_388_607); 112 // Test for buffer overflow: 113 assert(a[0] == 0); 114 assert(a[2] == 0); 115 116 // Overflow 117 a[1] = 8_388_608; 118 assert(a[1] == -8_388_608); 119 // Test for buffer overflow: 120 assert(a[0] == 0); 121 assert(a[2] == 0); 122 123 // Negative value 124 a[1] = -1; 125 assert(a[1] == -1); 126 // Test for buffer overflow: 127 assert(a[0] == 0); 128 assert(a[2] == 0); 129 130 // Unary operators 131 a[1] = 0; 132 assert(~a[1] == -1); 133 a[1]--; 134 assert(a[1] == -1); 135 assert(-a[1] == 1); 136 assert(+a[1] == -1); 137 a[1]++; 138 assert(a[1] == 0); 139 140 // Binary operators 141 a[1] = 0; 142 a[1] = a[1] + 1; 143 assert(a[1] == 1); 144 a[1] += 1; 145 assert(a[1] == 2); 146 a[1] = a[1] - 1; 147 assert(a[1] == 1); 148 a[1] -= 1; 149 assert(a[1] == 0); 150 151 a[1] = 3; 152 a[1] = a[1] * 2; 153 assert(a[1] == 6); 154 a[1] = a[1] / 2; 155 assert(a[1] == 3); 156 a[1] *= 2; 157 assert(a[1] == 6); 158 a[1] /= 2; 159 assert(a[1] == 3); 160 a[1] = a[1] << 1; 161 assert(a[1] == 6); 162 a[1] <<= 1; 163 assert(a[1] == 12); 164 a[1] = a[1] >> 1; 165 assert(a[1] == 6); 166 a[1] >>= 1; 167 assert(a[1] == 3); 168 169 a[1] |= 4; 170 assert(a[1] == 7); 171 a[1] &= 5; 172 assert(a[1] == 5); 173 a[1] = a[1] | 2; 174 assert(a[1] == 7); 175 a[1] = a[1] & 3; 176 assert(a[1] == 3); 177 }