forked from google/gipfeli
-
Notifications
You must be signed in to change notification settings - Fork 0
/
gipfeli-internal.h
184 lines (165 loc) · 5.71 KB
/
gipfeli-internal.h
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
// Copyright 2011 Google Inc. All Rights Reserved.
// [email protected] (Rasto Lenhardt)
#ifndef UTIL_COMPRESSION_GIPFELI_INTERNAL_GIPFELI_H_
#define UTIL_COMPRESSION_GIPFELI_INTERNAL_GIPFELI_H_
#include "gipfeli.h"
#include "compression.h"
namespace util {
namespace compression {
namespace gipfeli {
class LZ77;
class Gipfeli : public util::compression::Compressor {
public:
Gipfeli() : compressor_state_(NULL), decompressor_state_(NULL) {}
virtual ~Gipfeli() {
delete compressor_state_;
delete decompressor_state_;
}
virtual size_t Compress(const string& input, string* output);
virtual size_t MaxCompressedLength(size_t source_bytes);
virtual bool Uncompress(
const string& compressed, string* uncompressed);
virtual bool GetUncompressedLength(
const string& compressed, size_t* result);
virtual size_t CompressStream(
Source* source, Sink* sink);
virtual bool GetUncompressedLengthStream(
Source* compressed, size_t* result);
virtual bool UncompressStream(
Source* source, Sink* sink);
private:
class CompressorState {
public:
CompressorState() : lz77_(NULL), lz77_input_size_(0) {}
~CompressorState();
LZ77* ReallocateLZ77(int size);
private:
LZ77* lz77_;
size_t lz77_input_size_;
};
class DecompressorState {
public:
DecompressorState() : commands_(NULL), commands_size_(0) {}
~DecompressorState() { delete[] commands_; }
uint32* ReallocateCommands(int size);
private:
uint32* commands_;
int commands_size_;
};
size_t RawCompress(const string& input, char* compressed);
bool RawUncompress(const char* compressed, size_t compressed_length,
char* uncompressed, size_t uncompressed_length);
bool InternalRawUncompress(
const char* compressed, size_t compressed_length,
char* uncompressed, size_t uncompressed_length);
bool InternalRawUncompressStream(
Source* source,
Sink* uncompressed, size_t uncompressed_length);
CompressorState* compressor_state_;
DecompressorState* decompressor_state_;
DISALLOW_COPY_AND_ASSIGN(Gipfeli);
};
class GipfeliAdaptor : public util::compression::Compressor {
public:
GipfeliAdaptor() {}
virtual ~GipfeliAdaptor() {}
virtual inline size_t Compress(const string& input, string* output) {
Gipfeli gipfeli;
return gipfeli.Compress(input, output);
}
virtual inline size_t MaxCompressedLength(size_t source_bytes) {
Gipfeli gipfeli;
return gipfeli.MaxCompressedLength(source_bytes);
}
virtual inline bool Uncompress(
const string& compressed, string* uncompressed) {
Gipfeli gipfeli;
return gipfeli.Uncompress(compressed, uncompressed);
}
virtual inline bool GetUncompressedLength(
const string& compressed, size_t* result) {
Gipfeli gipfeli;
return gipfeli.GetUncompressedLength(compressed, result);
}
virtual inline size_t CompressStream(
Source* source, Sink* sink) {
Gipfeli gipfeli;
return gipfeli.CompressStream(source, sink);
}
virtual inline bool GetUncompressedLengthStream(
Source* compressed, size_t* result) {
Gipfeli gipfeli;
return gipfeli.GetUncompressedLengthStream(compressed, result);
}
virtual inline bool UncompressStream(
Source* source, Sink* sink) {
Gipfeli gipfeli;
return gipfeli.UncompressStream(source, sink);
}
private:
DISALLOW_COPY_AND_ASSIGN(GipfeliAdaptor);
};
static const int kMaxIncrementCopyOverflow = 10;
// Copy "len" bytes from "src" to "op", one byte at a time. Used for
// handling COPY operations where the input and output regions may
// overlap. For example, suppose:
// src == "ab"
// op == src + 2
// len == 20
// After IncrementalCopy(src, op, len), the result will have
// eleven copies of "ab"
// ababababababababababab
// Note that this does not match the semantics of either memcpy()
// or memmove().
inline void IncrementalCopy(const char* src, char* op, int len) {
do {
*op++ = *src++;
} while (--len > 0);
}
// Equivalent to IncrementalCopy except that it can write up to ten extra
// bytes after the end of the copy, and that it is faster.
//
// The main part of this loop is a simple copy of eight bytes at a time until
// we've copied (at least) the requested amount of bytes. However, if op and
// src are less than eight bytes apart (indicating a repeating pattern of
// length < 8), we first need to expand the pattern in order to get the correct
// results. For instance, if the buffer looks like this, with the eight-byte
// <src> and <op> patterns marked as intervals:
//
// abxxxxxxxxxxxx
// [------] src
// [------] op
//
// a single eight-byte copy from <src> to <op> will repeat the pattern once,
// after which we can move <op> two bytes without moving <src>:
//
// ababxxxxxxxxxx
// [------] src
// [------] op
//
// and repeat the exercise until the two no longer overlap.
//
// This allows us to do very well in the special case of one single byte
// repeated many times, without taking a big hit for more general cases.
//
// The worst case of extra writing past the end of the match occurs when
// op - src == 1 and len == 1; the last copy will read from byte positions
// [0..7] and write to [4..11], whereas it was only supposed to write to
// position 1. Thus, ten excess bytes.
inline void IncrementalCopyFastPath(const char* src, char* op, int len) {
while (op - src < 8) {
UNALIGNED_STORE64(op, UNALIGNED_LOAD64(src));
len -= op - src;
op += op - src;
}
while (len > 0) {
UNALIGNED_STORE64(op, UNALIGNED_LOAD64(src));
src += 8;
op += 8;
len -= 8;
}
}
} // namespace gipfeli
} // namespace compression
} // namespace util
#endif // UTIL_COMPRESSION_GIPFELI_INTERNAL_GIPFELI_H_