-
Notifications
You must be signed in to change notification settings - Fork 0
/
bb_comp.cpp
132 lines (89 loc) · 2.58 KB
/
bb_comp.cpp
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
// includes
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>
#include "bb_comp.hpp"
#include "common.hpp"
#include "libmy.hpp"
#include "util.hpp"
namespace bb {
// constants
const int RLE_Size {255 / 3};
const Index Block_Size {1 << 8};
// variables
static Index RLE[RLE_Size + 1];
static int Code_Value[256];
static Index Code_Length[256];
// functions
void comp_init() {
for (int i = 0; i < RLE_Size; i++) {
RLE[i] = ml::round(std::pow(1.2, double(i)));
}
for (int byte = 0; byte < 256; byte++) {
Code_Value[byte] = byte % 3;
Code_Length[byte] = RLE[byte / 3];
}
}
void Index_::load(const std::string & file_name, Index size) {
std::ifstream file(file_name.c_str(), std::ios::binary);
if (!file) {
std::cerr << "unable to open file \"" << file_name << "\"" << std::endl;
std::exit(EXIT_FAILURE);
}
m_size = size;
load_file(m_table, file);
// create index table for on-line decompression
Index table_size = Index(m_table.size());
Index index_size = (table_size + Block_Size - 1) / Block_Size;
m_index.clear();
m_index.reserve(index_size + 1); // sentinel for debug
Index pos = 0;
for (Index i = 0; i < table_size;) {
assert(i % Block_Size == 0);
m_index.push_back(pos);
Index next = std::min(i + Block_Size, table_size);
for (; i < next; i++) {
pos += Code_Length[m_table[i]];
}
}
if (pos != m_size) {
std::cerr << "unmatched uncompressed size: " << file_name << ": " << m_size << " -> " << pos << std::endl;
std::exit(EXIT_FAILURE);
}
assert(Index(m_index.size()) == index_size);
m_index.push_back(m_size); // sentinel for debug
}
int Index_::operator[](Index pos) const {
assert(pos < m_size);
// find the compressed block using the index table
Index low = 0;
Index high = m_index.size() - 1;
assert(low <= high);
while (low < high) {
Index mid = (low + high + 1) / 2;
assert(mid > low && mid <= high);
if (m_index[mid] <= pos) {
low = mid;
assert(low <= high);
} else {
high = mid - 1;
assert(low <= high);
}
}
assert(low == high);
assert(m_index[low] <= pos);
assert(m_index[low + 1] > pos);
// find the value using on-line RLE
assert(pos >= m_index[low]);
pos -= m_index[low];
for (Index i = low * Block_Size; true; i++) {
int byte = m_table[i];
Index len = Code_Length[byte];
if (pos < len) return Code_Value[byte];
pos -= len;
}
}
} // namespace bb