Skip to content

Instantly share code, notes, and snippets.

@CyberShadow
Created January 21, 2024 10:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CyberShadow/3756e58c3f0236de77fba70b14cb54fe to your computer and use it in GitHub Desktop.
Save CyberShadow/3756e58c3f0236de77fba70b14cb54fe to your computer and use it in GitHub Desktop.
Numeric encoding
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