From 77d77263f7cebc0bfa5fca86ffba106d59ab5b6f Mon Sep 17 00:00:00 2001 From: Marko Semet Date: Sun, 14 Jun 2020 22:15:34 +0200 Subject: [PATCH] Support size --- coverage.sh | 5 + source/structs/package.d | 336 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 336 insertions(+), 5 deletions(-) create mode 100755 coverage.sh diff --git a/coverage.sh b/coverage.sh new file mode 100755 index 0000000..9efdb7c --- /dev/null +++ b/coverage.sh @@ -0,0 +1,5 @@ +#! /usr/bin/env bash + +cd "$(dirname "$0")" && +dub test --coverage && +rm -v -- ./-tmp* diff --git a/source/structs/package.d b/source/structs/package.d index 7c58aee..68d5d2f 100644 --- a/source/structs/package.d +++ b/source/structs/package.d @@ -2,8 +2,10 @@ module structs; private { + import core.exception; import std.array; import std.bitmanip; + import std.exception; import std.system; /++ @@ -28,9 +30,9 @@ private struct Element { Endian endian; /// The endian to use - bool isArray; /// If it's an array - size_t arraySize; /// Array size - FORMAT_TYPE formatType; /// The formated type + bool is_array; /// If it's an array + size_t array_size; /// Array size + FORMAT_TYPE format_type; /// The formated type /++ + Calculate the size of the element @@ -40,7 +42,7 @@ private { // Base format type size size_t base_size = 0; - final switch(this.formatType) + final switch(this.format_type) { case FORMAT_TYPE.STRING: case FORMAT_TYPE.INT_8: @@ -62,7 +64,111 @@ private } // Add array size - return base_size * this.arraySize; + return base_size * this.array_size; + } + + static pure Element genFromString(string data) + in(data.length > 0, "Format can't be empty.") + { + // Pre checks + size_t current_pos = 0; + + // Read endian + Endian endian_found = std.system.endian; + switch(data[0]) + { + case '=': + endian_found = std.system.endian; + current_pos++; + break; + case '<': + endian_found = Endian.littleEndian; + current_pos++; + break; + case '!': + case '>': + endian_found = Endian.bigEndian; + current_pos++; + break; + default: + } + + // Get size + bool set_size = false; + size_t size = 0; + while((current_pos < data.length) && ('0' <= data[current_pos]) && (data[current_pos] <= '9')) + { + set_size = true; + size = (size * 10) + (data[current_pos] - '0'); + current_pos++; + } + if(!set_size) + { + size = 1; + } + + // Get format + assert(current_pos + 1 == data.length, "Format '" ~ data[current_pos..$] ~ "' isn't a valid format type."); + FORMAT_TYPE format_type_found; + switch(data[current_pos]) + { + case 'b': + format_type_found = FORMAT_TYPE.INT_8; + current_pos++; + break; + case 'B': + format_type_found = FORMAT_TYPE.UINT_8; + current_pos++; + break; + case 'h': + format_type_found = FORMAT_TYPE.INT_16; + current_pos++; + break; + case 'H': + format_type_found = FORMAT_TYPE.UINT_16; + current_pos++; + break; + case 'i': + format_type_found = FORMAT_TYPE.INT_32; + current_pos++; + break; + case 'I': + format_type_found = FORMAT_TYPE.UINT_32; + current_pos++; + break; + case 'q': + format_type_found = FORMAT_TYPE.INT_64; + current_pos++; + break; + case 'Q': + format_type_found = FORMAT_TYPE.UINT_64; + current_pos++; + break; + case 's': + assert(set_size, "Size have to be set for the string."); + format_type_found = FORMAT_TYPE.STRING; + current_pos++; + break; + default: + assert(false, "Unknown format string: '" ~ data[current_pos..$] ~ "'"); + } + + // Return new struct + assert(current_pos == data.length); + Element result = {endian: endian_found, is_array: set_size, array_size: size, format_type: format_type_found}; + return result; + } + } + + template GET_TYPE(Element ELEMENT) + { + static if(ELEEMENT.format_type == FORMAT_TYPE.STRING) + { + alias GET_TYPE = string; + } + else + { + static assert(false); } } @@ -77,14 +183,234 @@ private return source.replace(" ", ""); } + pure Element[] parse_string(string source) + { + // Remove whitespaces + source = remove_whitespaces(source); + + // Split after char + Element[] elements = []; + size_t pos = 0; + size_t last = 0; + while(pos < source.length) + { + if((source[pos] >= 'a' && source[pos] <= 'z') || (source[pos] >= 'A' && source[pos] <= 'Z')) + { + elements ~= [Element.genFromString(source[last..pos + 1])]; + last = pos + 1; + } + pos++; + } + assert(last == pos, "Format doesn't end correctly."); + return elements; + } + // Test remove whitespaces. unittest { assert(remove_whitespaces(" a b c ") == "abc"); } + + // Test endian and length + unittest + { + { + const auto tmp = Element.genFromString("i"); + assert(tmp.endian == endian); + assert(tmp.is_array == false); + assert(tmp.array_size == 1); + assert(tmp.format_type == FORMAT_TYPE.INT_32); + } + { + const auto tmp = Element.genFromString("=i"); + assert(tmp.endian == endian); + assert(tmp.is_array == false); + assert(tmp.array_size == 1); + assert(tmp.format_type == FORMAT_TYPE.INT_32); + } + { + const auto tmp = Element.genFromString(">i"); + assert(tmp.endian == Endian.bigEndian); + assert(tmp.is_array == false); + assert(tmp.array_size == 1); + assert(tmp.format_type == FORMAT_TYPE.INT_32); + } + { + const auto tmp = Element.genFromString("!i"); + assert(tmp.endian == Endian.bigEndian); + assert(tmp.is_array == false); + assert(tmp.array_size == 1); + assert(tmp.format_type == FORMAT_TYPE.INT_32); + } + { + const auto tmp = Element.genFromString("16i=16i!16i"); + foreach(i; tmp) + { + assert(i.is_array == true); + assert(i.array_size == 16); + assert(i.format_type == FORMAT_TYPE.INT_32); + } + } + assertThrown!AssertError(parse_string("i16")); + assertThrown!AssertError(parse_string("i!")); + assertThrown!AssertError(parse_string("16!i")); + } } public { + /++ + + Base format type + +/ + struct BaseFormat(string CONFIG) + { + private + { + const(Element[]) elements = parse_string(CONFIG); + } + public + { + /++ + + Calculate the size of the format. + + Returns: Size of the format + +/ + static size_t size() + { + size_t result = 0; + static foreach (i; elements) + { + result += i.packSize(); + } + return result; + } + } + } +} + +private +{ + unittest + { + assert(BaseFormat!"10s".size() == 10); + assert(BaseFormat!"b".size() == 1); + assert(BaseFormat!"4b".size() == 4); + assert(BaseFormat!"B".size() == 1); + assert(BaseFormat!"4B".size() == 4); + assert(BaseFormat!"h".size() == 2); + assert(BaseFormat!"4h".size() == 8); + assert(BaseFormat!"H".size() == 2); + assert(BaseFormat!"4H".size() == 8); + assert(BaseFormat!"i".size() == 4); + assert(BaseFormat!"4i".size() == 16); + assert(BaseFormat!"I".size() == 4); + assert(BaseFormat!"4I".size() == 16); + assert(BaseFormat!"q".size() == 8); + assert(BaseFormat!"4q".size() == 32); + assert(BaseFormat!"Q".size() == 8); + assert(BaseFormat!"4Q".size() == 32); + } }