-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrle.cpp
More file actions
139 lines (128 loc) · 4.04 KB
/
Copy pathrle.cpp
File metadata and controls
139 lines (128 loc) · 4.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// KKO - RLE compressor/decompressor
// Last change: 13.5.2025
#include "rle.h"
// RLE encode a vector of 8bit values, returns a bool (indicating whether RLE was actually used) and the resulting vector
std::pair<bool, std::vector<uint8_t>> rle_encode(const std::vector<uint8_t> &text, uint16_t min_repeat)
{
std::vector<uint8_t> result; // result to be returned
uint64_t length = text.size(); // length of the input text
uint64_t i = 0; // input text index
std::vector<uint8_t> buffer; // buffer storing currect sequence of same chars
uint64_t buffer_limit = 255; // max buffer size
// go through the whole text
while(i < length)
{
// no character in buffer OR repeating character found
if(buffer.empty() || text[i] == buffer.back())
{
// buffer is full
if(buffer.size() == buffer_limit)
{
result.push_back(1);
result.push_back(buffer.size());
result.push_back(buffer.back());
buffer.clear();
}
buffer.push_back(text[i]);
i++;
}
// different character found
else
{
// there is enough repeating characters in buffer => rle can be used
if(buffer.size() >= min_repeat)
{
result.push_back(1);
result.push_back(buffer.size());
result.push_back(buffer.back());
buffer.clear();
}
// not enough repeating chars, saving as normal
else
{
for(uint64_t j = 0; j < buffer.size(); j++)
{
result.push_back(0);
result.push_back(buffer[j]);
}
buffer.clear();
}
}
}
// finish whatever remained in buffer
if(!buffer.empty())
{
if(buffer.size() >= min_repeat)
{
result.push_back(1);
result.push_back(buffer.size());
result.push_back(buffer.back());
}
else
{
for(uint64_t j = 0; j < buffer.size(); j++)
{
result.push_back(0);
result.push_back(buffer[j]);
}
}
}
// calculate the total length of encoded text (in bits) to determine if rle is worth it
uint64_t totalLength = 0;
i = 0;
while(i < result.size())
{
if(result[i] == 1)
{
// 1 bit indicationg rle usage, 8 bits for the number of repetitions, 8 bits for the repeated value
totalLength += 17;
i += 3;
}
else if(result[i] == 0)
{
// 1 bit indicationg (not) rle usage, 8 bits for the value
totalLength += 9;
i += 2;
}
else
{
std::cerr << "rle_compress: invalid result value - rle will no be used" << std::endl;
return {false, text};
}
}
// check if rle is worth it
if(totalLength < text.size() * 8)
{
return {true, result};
}
// rle is not used
return {false, text};
}
// RLE decode a vector of 16bit values (only 9 bits are actually used though, first bit is rle flag, 8 bits are actual values), returns a vector of 8bit values
std::vector<uint8_t> rle_decode(const std::vector<uint16_t> &text)
{
std::vector<uint8_t> result; // final vector of 8bit values
// decode 9bit values
uint64_t i = 0;
while(i < text.size())
{
// rle used
if(text[i] > 255)
{
uint16_t repeat = text[i] - 256; // skip first bit, next eight bits - number of repetitions
uint16_t item = text[i + 1]; // next eight bits - repeated value
for(uint16_t j = 0; j < repeat; j++)
{
result.push_back(item);
}
i += 2;
}
// rle was not used
else
{
result.push_back(text[i]); // 8bit char value
i++;
}
}
return result;
}