Support size
parent
53c0d2e130
commit
77d77263f7
|
@ -0,0 +1,5 @@
|
||||||
|
#! /usr/bin/env bash
|
||||||
|
|
||||||
|
cd "$(dirname "$0")" &&
|
||||||
|
dub test --coverage &&
|
||||||
|
rm -v -- ./-tmp*
|
|
@ -2,8 +2,10 @@ module structs;
|
||||||
|
|
||||||
private
|
private
|
||||||
{
|
{
|
||||||
|
import core.exception;
|
||||||
import std.array;
|
import std.array;
|
||||||
import std.bitmanip;
|
import std.bitmanip;
|
||||||
|
import std.exception;
|
||||||
import std.system;
|
import std.system;
|
||||||
|
|
||||||
/++
|
/++
|
||||||
|
@ -28,9 +30,9 @@ private
|
||||||
struct Element
|
struct Element
|
||||||
{
|
{
|
||||||
Endian endian; /// The endian to use
|
Endian endian; /// The endian to use
|
||||||
bool isArray; /// If it's an array
|
bool is_array; /// If it's an array
|
||||||
size_t arraySize; /// Array size
|
size_t array_size; /// Array size
|
||||||
FORMAT_TYPE formatType; /// The formated type
|
FORMAT_TYPE format_type; /// The formated type
|
||||||
|
|
||||||
/++
|
/++
|
||||||
+ Calculate the size of the element
|
+ Calculate the size of the element
|
||||||
|
@ -40,7 +42,7 @@ private
|
||||||
{
|
{
|
||||||
// Base format type size
|
// Base format type size
|
||||||
size_t base_size = 0;
|
size_t base_size = 0;
|
||||||
final switch(this.formatType)
|
final switch(this.format_type)
|
||||||
{
|
{
|
||||||
case FORMAT_TYPE.STRING:
|
case FORMAT_TYPE.STRING:
|
||||||
case FORMAT_TYPE.INT_8:
|
case FORMAT_TYPE.INT_8:
|
||||||
|
@ -62,7 +64,111 @@ private
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add array size
|
// 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(" ", "");
|
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.
|
// Test remove whitespaces.
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
assert(remove_whitespaces(" a b c ") == "abc");
|
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("<i");
|
||||||
|
assert(tmp.endian == Endian.littleEndian);
|
||||||
|
assert(tmp.is_array == false);
|
||||||
|
assert(tmp.array_size == 1);
|
||||||
|
assert(tmp.format_type == FORMAT_TYPE.INT_32);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto tmp = Element.genFromString("<1i");
|
||||||
|
assert(tmp.endian == Endian.littleEndian);
|
||||||
|
assert(tmp.is_array == true);
|
||||||
|
assert(tmp.array_size == 1);
|
||||||
|
assert(tmp.format_type == FORMAT_TYPE.INT_32);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto tmp = Element.genFromString("<11i");
|
||||||
|
assert(tmp.endian == Endian.littleEndian);
|
||||||
|
assert(tmp.is_array == true);
|
||||||
|
assert(tmp.array_size == 11);
|
||||||
|
assert(tmp.format_type == FORMAT_TYPE.INT_32);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto tmp = Element.genFromString("<111i");
|
||||||
|
assert(tmp.endian == Endian.littleEndian);
|
||||||
|
assert(tmp.is_array == true);
|
||||||
|
assert(tmp.array_size == 111);
|
||||||
|
assert(tmp.format_type == FORMAT_TYPE.INT_32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test types parse
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
{
|
||||||
|
const auto tmp = Element.genFromString("<b");
|
||||||
|
assert(tmp.endian == Endian.littleEndian);
|
||||||
|
assert(tmp.is_array == false);
|
||||||
|
assert(tmp.array_size == 1);
|
||||||
|
assert(tmp.format_type == FORMAT_TYPE.INT_8);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto tmp = Element.genFromString("<B");
|
||||||
|
assert(tmp.endian == Endian.littleEndian);
|
||||||
|
assert(tmp.is_array == false);
|
||||||
|
assert(tmp.array_size == 1);
|
||||||
|
assert(tmp.format_type == FORMAT_TYPE.UINT_8);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto tmp = Element.genFromString("<h");
|
||||||
|
assert(tmp.endian == Endian.littleEndian);
|
||||||
|
assert(tmp.is_array == false);
|
||||||
|
assert(tmp.array_size == 1);
|
||||||
|
assert(tmp.format_type == FORMAT_TYPE.INT_16);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto tmp = Element.genFromString("<H");
|
||||||
|
assert(tmp.endian == Endian.littleEndian);
|
||||||
|
assert(tmp.is_array == false);
|
||||||
|
assert(tmp.array_size == 1);
|
||||||
|
assert(tmp.format_type == FORMAT_TYPE.UINT_16);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto tmp = Element.genFromString("<i");
|
||||||
|
assert(tmp.endian == Endian.littleEndian);
|
||||||
|
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.littleEndian);
|
||||||
|
assert(tmp.is_array == false);
|
||||||
|
assert(tmp.array_size == 1);
|
||||||
|
assert(tmp.format_type == FORMAT_TYPE.UINT_32);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto tmp = Element.genFromString("<q");
|
||||||
|
assert(tmp.endian == Endian.littleEndian);
|
||||||
|
assert(tmp.is_array == false);
|
||||||
|
assert(tmp.array_size == 1);
|
||||||
|
assert(tmp.format_type == FORMAT_TYPE.INT_64);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto tmp = Element.genFromString("<Q");
|
||||||
|
assert(tmp.endian == Endian.littleEndian);
|
||||||
|
assert(tmp.is_array == false);
|
||||||
|
assert(tmp.array_size == 1);
|
||||||
|
assert(tmp.format_type == FORMAT_TYPE.UINT_64);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto tmp = Element.genFromString("<10s");
|
||||||
|
assert(tmp.endian == Endian.littleEndian);
|
||||||
|
assert(tmp.is_array == true);
|
||||||
|
assert(tmp.array_size == 10);
|
||||||
|
assert(tmp.format_type == FORMAT_TYPE.STRING);
|
||||||
|
}
|
||||||
|
assertThrown!AssertError(Element.genFromString("s"));
|
||||||
|
assertThrown!AssertError(Element.genFromString("Z"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test parse string
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
{
|
||||||
|
const auto tmp = parse_string("<16i>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
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue