Created
January 21, 2024 10:53
-
-
Save CyberShadow/3756e58c3f0236de77fba70b14cb54fe to your computer and use it in GitHub Desktop.
Numeric encoding
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private struct MaybeDynamicArray(T, size_t size = -1) | |
{ | |
static if (size == -1) | |
{ | |
T[] items; | |
alias items this; | |
} | |
else | |
{ | |
T[size] items; | |
size_t length; | |
void opOpAssign(string op : "~")(T item) { items[length++] = item; } | |
T[] opSlice() { return items[0 .. length]; } | |
} | |
} | |
struct Encoder( | |
/// Numeric type for decoded items. | |
I, | |
/// Numeric type for encoded result. | |
E, | |
/// Maximum number of encoded items. | |
/// If -1, a dynamic array will be used. | |
size_t maxSize = -1, | |
/// Use an encoding with an explicit end of items. | |
bool withEOF = false, | |
) | |
{ | |
struct Item { I n, max; } | |
MaybeDynamicArray!(Item, maxSize) items; | |
void put(I n, I max) | |
{ | |
assert(0 <= n && n < max); | |
items ~= Item(n, max); | |
} | |
E finish() | |
{ | |
E result = withEOF ? 1 : 0; | |
foreach_reverse (ref item; items) | |
{ | |
result *= item.max; | |
result += item.n; | |
} | |
return result; | |
} | |
} | |
struct Decoder( | |
/// Numeric type for decoded items. | |
I, | |
/// Numeric type for encoded result. | |
E, | |
/// Use an encoding with an explicit end of items. | |
bool withEOF = false, | |
) | |
{ | |
E encoded; | |
this(E encoded) | |
{ | |
this.encoded = encoded; | |
static if (withEOF) | |
assert(encoded > 0); | |
} | |
I get(I max) | |
{ | |
I value = encoded % max; | |
encoded /= max; | |
static if (withEOF) | |
assert(encoded > 0, "Decoding error"); | |
return value; | |
} | |
static if (withEOF) | |
@property bool empty() const { return encoded == 1; } | |
} | |
unittest | |
{ | |
import std.meta : AliasSeq; | |
alias I = uint; | |
alias E = uint; | |
foreach (dynamicSize; AliasSeq!(false, true)) | |
foreach (withEOF; AliasSeq!(false, true)) | |
{ | |
void testImpl() | |
{ | |
Encoder!(I, E, dynamicSize ? -1 : 2, withEOF) encoder; | |
encoder.put(5, 8); | |
encoder.put(1, 2); | |
auto result = encoder.finish(); | |
auto decoder = Decoder!(I, E, withEOF)(result); | |
static if (withEOF) assert(!decoder.empty); | |
assert(decoder.get(8) == 5); | |
static if (withEOF) assert(!decoder.empty); | |
assert(decoder.get(2) == 1); | |
static if (withEOF) assert(decoder.empty); | |
} | |
static if (!dynamicSize) | |
{ | |
@nogc void test() { testImpl(); } | |
test(); | |
} | |
else | |
testImpl(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment