add pessimal compression

This commit is contained in:
Martin Michelsen
2024-03-24 21:59:28 -07:00
parent cb05dce764
commit ce2300b116
4 changed files with 58 additions and 0 deletions
+39
View File
@@ -438,6 +438,45 @@ string prs_compress_optimal(const string& data, ProgressCallback progress_fn) {
return prs_compress_optimal(data.data(), data.size(), progress_fn);
}
string prs_compress_pessimal(const void* vdata, size_t size) {
const uint8_t* in_data = reinterpret_cast<const uint8_t*>(vdata);
// The worst possible encoding we can do is a literal byte when no byte with
// the same value is within the window, or an extended copy if there is a byte
// with the same value in the window.
WindowIndex<0x1FFF, 1> window(in_data, size);
LZSSInterleavedWriter w;
for (size_t z = 0; z < size; z++) {
auto match = window.get_best_match();
if (match.second >= 1) {
// Write extended copy
int16_t offset = match.first - window.offset;
w.write_control(false);
w.flush_if_ready();
w.write_control(true);
uint16_t a = (offset << 3);
w.write_data(a & 0xFF);
w.write_data(a >> 8);
w.write_data(0);
} else {
// Write literal
w.write_control(true);
w.write_data(in_data[z]);
}
w.flush_if_ready();
window.advance();
}
// Write stop command
w.write_control(false);
w.flush_if_ready();
w.write_control(true);
w.write_data(0);
w.write_data(0);
return std::move(w.close());
}
PRSCompressor::PRSCompressor(
ssize_t compression_level, ProgressCallback progress_fn)
: compression_level(compression_level),
+4
View File
@@ -177,6 +177,10 @@ std::string prs_compress_indexed(
std::string prs_compress_optimal(const void* vdata, size_t size, ProgressCallback progress_fn = nullptr);
std::string prs_compress_optimal(const std::string& data, ProgressCallback progress_fn = nullptr);
// Compresses data using PRS to the LARGEST possible output size. There is no
// practical use for this function except for amusement.
std::string prs_compress_pessimal(const void* vdata, size_t size);
// Decompresses PRS-compressed data.
struct PRSDecompressResult {
std::string data;
+3
View File
@@ -266,6 +266,7 @@ static void a_compress_decompress_fn(Arguments& args) {
bool is_decompress = starts_with(action, "decompress-");
bool is_big_endian = args.get<bool>("big-endian");
bool is_optimal = args.get<bool>("optimal");
bool is_pessimal = args.get<bool>("pessimal");
int8_t compression_level = args.get<int8_t>("compression-level", 0);
size_t bytes = args.get<size_t>("bytes", 0);
string seed = args.get<string>("seed");
@@ -298,6 +299,8 @@ static void a_compress_decompress_fn(Arguments& args) {
if (!is_decompress && (is_prs || is_pr2 || is_prc)) {
if (is_optimal) {
data = prs_compress_optimal(data.data(), data.size(), optimal_progress_fn);
} else if (is_pessimal) {
data = prs_compress_pessimal(data.data(), data.size());
} else {
data = prs_compress(data, compression_level, progress_fn);
}
+12
View File
@@ -20,6 +20,10 @@ echo "... compress with level=0"
$EXECUTABLE compress-$SCHEME --compression-level=0 $BASENAME.mnrd $BASENAME.mnrd.$SCHEME.l0
echo "... compress with level=1"
$EXECUTABLE compress-$SCHEME --compression-level=1 $BASENAME.mnrd $BASENAME.mnrd.$SCHEME.l1
echo "... compress optimally"
$EXECUTABLE compress-$SCHEME --optimal $BASENAME.mnrd $BASENAME.mnrd.$SCHEME.lo
echo "... compress pessimally"
$EXECUTABLE compress-$SCHEME --pessimal $BASENAME.mnrd $BASENAME.mnrd.$SCHEME.lp
echo "... decompress from level=-1 (no compression)"
$EXECUTABLE decompress-$SCHEME $BASENAME.mnrd.$SCHEME.lN $BASENAME.mnrd.$SCHEME.lN.dec
@@ -27,6 +31,10 @@ echo "... decompress from level=0"
$EXECUTABLE decompress-$SCHEME $BASENAME.mnrd.$SCHEME.l0 $BASENAME.mnrd.$SCHEME.l0.dec
echo "... decompress from level=1"
$EXECUTABLE decompress-$SCHEME $BASENAME.mnrd.$SCHEME.l1 $BASENAME.mnrd.$SCHEME.l1.dec
echo "... decompress from optimal"
$EXECUTABLE decompress-$SCHEME $BASENAME.mnrd.$SCHEME.lo $BASENAME.mnrd.$SCHEME.lo.dec
echo "... decompress from pessimal"
$EXECUTABLE decompress-$SCHEME $BASENAME.mnrd.$SCHEME.lp $BASENAME.mnrd.$SCHEME.lp.dec
echo "... check result from level=-1 (no compression)"
diff $BASENAME.mnrd $BASENAME.mnrd.$SCHEME.lN.dec
@@ -34,6 +42,10 @@ echo "... check result from level=0"
diff $BASENAME.mnrd $BASENAME.mnrd.$SCHEME.l0.dec
echo "... check result from level=1"
diff $BASENAME.mnrd $BASENAME.mnrd.$SCHEME.l1.dec
echo "... check result from optimal"
diff $BASENAME.mnrd $BASENAME.mnrd.$SCHEME.lo.dec
echo "... check result from pessimal"
diff $BASENAME.mnrd $BASENAME.mnrd.$SCHEME.lp.dec
echo "... clean up"
rm $BASENAME.mnrd \