1 module tagion.dart.DARTRim; 2 3 import std.format; 4 import tagion.basic.Debug; 5 import tagion.basic.Types; 6 import tagion.basic.basic : EnumText; 7 import tagion.hibon.HiBONRecord; 8 9 @safe: 10 enum RIMS_IN_SECTOR = 2; 11 /** 12 * Sector range 13 */ 14 static struct SectorRange { 15 private { 16 @exclude ushort _sector; 17 @label("from") ushort _from_sector; 18 @label("to") ushort _to_sector; 19 } 20 /** 21 * The start start sector 22 * Returns: start angle 23 */ 24 @property ushort from_sector() const { 25 return _from_sector; 26 } 27 28 /** 29 * The end sector 30 * Returns: end angle 31 */ 32 @property ushort to_sector() const { 33 return _to_sector; 34 } 35 36 @exclude protected bool flag; 37 mixin HiBONRecord!(q{ 38 this(const ushort from_sector, const ushort to_sector) pure nothrow @nogc { 39 _from_sector = from_sector; 40 _to_sector = to_sector; 41 _sector = from_sector; 42 } 43 }); 44 45 /** 46 * Checks if the range is a full angle dart (0x0000 to 0xFFFF) 47 * Returns: true if it a full-range=full-angle 48 */ 49 bool isFullRange() const pure nothrow { 50 return _from_sector == _to_sector; 51 } 52 53 /** 54 * Checks if the sector is within the sector-range 55 * Params: 56 * sector = sector number 57 * Returns: true if sector is within the range 58 */ 59 bool inRange(const ushort sector) const pure nothrow { 60 return sectorInRange(sector, _from_sector, _to_sector); 61 } 62 63 /** 64 * Checks if the sector of a rim is within the sector-range 65 * Params: 66 * rims = a rim path 67 * Returns: 68 */ 69 bool inRange(const Rims rims) const pure nothrow { 70 if (rims.path.length == 1) { 71 return sectorInRange(rims.path[0] << 8, _from_sector & 0xFF00, _to_sector); 72 } 73 return (rims.path.length == 0) || sectorInRange(rims.sector, _from_sector, _to_sector); 74 } 75 76 /** 77 * Checks if sector is within range 78 * Params: 79 * sector = sector number 80 * from_sector = sector start angle 81 * to_sector = sector end angle 82 * Returns: true if the sector is within the angle-span 83 */ 84 static bool sectorInRange( 85 const ushort sector, 86 const ushort from_sector, 87 const ushort to_sector) pure nothrow { 88 if (to_sector == from_sector) { 89 return true; 90 } 91 else { 92 immutable ushort sector_origin = (sector - from_sector) & ushort.max; 93 immutable ushort to_origin = (to_sector - from_sector) & ushort.max; 94 return (sector_origin < to_origin); 95 } 96 } 97 98 /** 99 * Check if current sector has reached the end 100 * Returns: true of the sector reach the end of the angle-span 101 */ 102 bool empty() const pure nothrow { 103 return !inRange(_sector) || flag; 104 } 105 106 /** 107 * Progress one sector 108 */ 109 void popFront() { 110 if (!empty) { 111 _sector++; 112 if (_sector == _from_sector) { 113 flag = true; 114 } 115 } 116 } 117 118 /** 119 * Gets the current sector 120 * Returns: current sector 121 */ 122 ushort front() const pure nothrow { 123 return _sector; 124 } 125 126 /** 127 * Gives an representation of the angle span 128 * Returns: text of angle span 129 */ 130 string toString() const pure { 131 return format("(%04X, %04X)", _from_sector, _to_sector); 132 } 133 134 /// 135 unittest { 136 enum full_dart_sectors_count = ushort.max + 1; 137 { //SectorRange: full sector iterator 138 auto sector_range = SectorRange(0, 0); 139 auto iteration = 0; 140 foreach (sector; sector_range) { 141 iteration++; 142 143 if (iteration > full_dart_sectors_count) 144 assert(0, "Range overflow"); 145 } 146 assert(iteration == full_dart_sectors_count); 147 } 148 { //SectorRange: full sector iterator 149 auto sector_range = SectorRange(5, 5); 150 auto iteration = 0; 151 foreach (sector; sector_range) { 152 iteration++; 153 154 if (iteration > full_dart_sectors_count) 155 assert(0, "Range overflow"); 156 } 157 assert(iteration == full_dart_sectors_count); 158 } 159 { //SectorRange: 160 auto sector_range = SectorRange(1, 10); 161 auto iteration = 0; 162 foreach (sector; sector_range) { 163 iteration++; 164 165 if (iteration > 9) 166 assert(0, "Range overflow"); 167 } 168 assert(iteration == 9); 169 } 170 } 171 } 172 173 /** 174 * Rim selecter 175 */ 176 @recordType("Rims") 177 struct Rims { 178 Buffer path; 179 @label("keys") @optional @(filter.Initialized) Buffer key_leaves; 180 protected enum root_rim_path = []; 181 static immutable root = Rims(root_rim_path); 182 /** 183 * Returns: sector of the selected path 184 */ 185 ushort sector() const pure nothrow { 186 if (path.length == 0) { 187 return ushort.init; 188 } 189 return .sector(path); 190 } 191 192 mixin HiBONRecord!( 193 q{ 194 this(Buffer r, Buffer key_leaves=null) { 195 this.path=r; 196 this.key_leaves=key_leaves; 197 } 198 199 this(const ushort sector) 200 out { 201 assert(path.length is ushort.sizeof); 202 } 203 do { 204 path=[sector >> 8*ubyte.sizeof, sector & ubyte.max]; 205 key_leaves=null; 206 } 207 208 this(I)(const Rims rim, const I key) if (isIntegral!I) 209 in (key >= 0 && key <= ubyte.max) 210 do { 211 212 path = rim.path ~ cast(ubyte) key; 213 this.key_leaves= rim.key_leaves.idup; 214 } 215 }); 216 217 /** 218 * rim-path as hex value 219 * Returns: hex string 220 */ 221 string toString() const pure nothrow { 222 import std.exception : assumeWontThrow; 223 224 if (path.length == 0) { 225 return "XXXX"; 226 } 227 return assumeWontThrow(format!"%(%02x%)"(path)); 228 } 229 } 230 231 /++ 232 + Sector is the little ending value the first two bytes of an fingerprint 233 + Returns: 234 + Sector number of a fingerpint 235 +/ 236 @safe 237 ushort sector(F)(const(F) fingerprint) pure nothrow @nogc if (isBufferType!F) 238 in (fingerprint.length >= ubyte.sizeof) 239 do { 240 ushort result = ushort(fingerprint[0]) << 8; 241 if (fingerprint.length > ubyte.sizeof) { 242 result |= fingerprint[1]; 243 244 } 245 return result; 246 } 247 248 @safe 249 unittest { 250 import std.stdio; 251 import tagion.crypto.Types : Fingerprint; 252 253 ubyte[] buf1 = [0xA7]; 254 assert(sector(buf1) == 0xA700); 255 assert(sector(cast(Fingerprint)[0xA7, 0x15]) == 0xA715); 256 Buffer buf2 = [0xA7, 0x15, 0xE3]; 257 assert(sector(buf2) == 0xA715); 258 259 }