RosettaCodeData/Task/LZW-compression/D/lzw-compression-2.d

96 lines
2.5 KiB
D
Raw Permalink Normal View History

2013-04-10 21:29:02 -07:00
struct LZW {
2014-01-17 05:32:22 +00:00
import std.array: empty;
2013-04-10 21:29:02 -07:00
// T is ubyte instead of char because D strings are UTF-8.
alias T = ubyte;
alias Tcomp = ushort;
static assert(Tcomp.sizeof > 1);
alias Ta = immutable(T)[];
enum int initDictSize = 256;
static immutable ubyte[initDictSize] bytes;
static this() {
2014-04-02 16:56:35 +00:00
foreach (immutable T i; 0 .. initDictSize)
bytes[i] = i;
2013-04-10 21:29:02 -07:00
}
2015-02-20 00:35:01 -05:00
static Tcomp[] compress(immutable scope T[] original) pure nothrow @safe
2014-01-17 05:32:22 +00:00
out(result) {
2013-04-10 21:29:02 -07:00
if (!original.empty)
assert(result[0] < initDictSize);
} body {
if (original.empty)
return [];
Tcomp[Ta] dict;
foreach (immutable b; bytes)
dict[[b]] = b;
2014-01-17 05:32:22 +00:00
// Here built-in slices give lower efficiency.
2013-04-10 21:29:02 -07:00
struct Slice {
size_t start, end;
2015-02-20 00:35:01 -05:00
@property opSlice() const pure nothrow @safe @nogc {
2013-04-10 21:29:02 -07:00
return original[start .. end];
}
alias opSlice this;
}
Slice w;
Tcomp[] result;
foreach (immutable i; 0 .. original.length) {
2014-01-17 05:32:22 +00:00
auto wc = Slice(w.start, w.end + 1); // Extend slice.
2013-04-10 21:29:02 -07:00
if (wc in dict) {
w = wc;
} else {
result ~= dict[w];
assert(dict.length < Tcomp.max); // Overflow guard.
2014-01-17 05:32:22 +00:00
dict[wc] = cast(Tcomp)dict.length;
2013-04-10 21:29:02 -07:00
w = Slice(i, i + 1);
}
}
if (!w.empty)
result ~= dict[w];
return result;
}
2015-02-20 00:35:01 -05:00
static Ta decompress(in Tcomp[] compressed) pure @safe
2013-04-10 21:29:02 -07:00
in {
if (!compressed.empty)
assert(compressed[0] < initDictSize, "Bad compressed");
} body {
if (compressed.empty)
return [];
auto dict = new Ta[initDictSize];
foreach (immutable b; bytes)
dict[b] = [b];
auto w = dict[compressed[0]];
auto result = w;
foreach (immutable k; compressed[1 .. $]) {
Ta entry;
if (k < dict.length)
entry = dict[k];
else if (k == dict.length)
entry = w ~ w[0];
else
throw new Exception("Bad compressed k.");
result ~= entry;
dict ~= w ~ entry[0];
w = entry;
}
return result;
}
}
void main() {
2014-01-17 05:32:22 +00:00
import std.stdio, std.string;
2013-04-10 21:29:02 -07:00
immutable txt = "TOBEORNOTTOBEORTOBEORNOT";
2014-01-17 05:32:22 +00:00
immutable compressed = LZW.compress(txt.representation);
compressed.writeln;
2015-02-20 00:35:01 -05:00
LZW.decompress(compressed).assumeUTF.writeln;
2013-04-10 21:29:02 -07:00
}