mirror of
https://github.com/mhx/dwarfs.git
synced 2025-09-08 11:59:48 -04:00
Update libfsst
This commit is contained in:
parent
656b7a7780
commit
13f954ca12
@ -21,5 +21,5 @@ FSST ensures that strings that are equal, are also equal in their compressed for
|
|||||||
|
|
||||||
FSST compression is quite useful in database systems and data file formats. It e.g., allows fine-grained decompression of values in case of selection predicates that are pushed down into a scan operator. But, very often FSST even allows to postpone decompression of string data. This means hash tables (in joins and aggregations) become smaller, and network communication (in case of distributed query processing) is reduced. All of this without requiring much structural changes to existing systems: after all, FSST compressed strings still remain strings.
|
FSST compression is quite useful in database systems and data file formats. It e.g., allows fine-grained decompression of values in case of selection predicates that are pushed down into a scan operator. But, very often FSST even allows to postpone decompression of string data. This means hash tables (in joins and aggregations) become smaller, and network communication (in case of distributed query processing) is reduced. All of this without requiring much structural changes to existing systems: after all, FSST compressed strings still remain strings.
|
||||||
|
|
||||||
The implementation of FSST is quite portable, using CMake and has been verified to work on 64-bits x86 computers running Linux, MacOS and Windows.
|
The implementation of FSST is quite portable, using CMake and has been verified to work on 64-bits x86 computers running Linux, Windows and MacOS (the latter also using arm64).
|
||||||
|
|
||||||
|
40
fsst/fsst.h
40
fsst/fsst.h
@ -45,8 +45,8 @@
|
|||||||
* We optionally support C-style zero-terminated strings (zero appearing only at the end). In this case, the compressed strings are
|
* We optionally support C-style zero-terminated strings (zero appearing only at the end). In this case, the compressed strings are
|
||||||
* also zero-terminated strings. In zero-terminated mode, the zero-byte at the end *is* counted in the string byte-length.
|
* also zero-terminated strings. In zero-terminated mode, the zero-byte at the end *is* counted in the string byte-length.
|
||||||
*/
|
*/
|
||||||
#ifndef _FSST_H_
|
#ifndef FSST_INCLUDED_H
|
||||||
#define _FSST_H_
|
#define FSST_INCLUDED_H
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#define __restrict__
|
#define __restrict__
|
||||||
@ -62,6 +62,7 @@ static inline int __builtin_ctzl(unsigned long long x) {
|
|||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
#define FSST_FALLTHROUGH [[fallthrough]]
|
#define FSST_FALLTHROUGH [[fallthrough]]
|
||||||
|
#include <cstring>
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#else
|
#else
|
||||||
#define FSST_FALLTHROUGH
|
#define FSST_FALLTHROUGH
|
||||||
@ -151,22 +152,24 @@ fsst_decompress(
|
|||||||
unsigned char*__restrict__ strOut = (unsigned char* __restrict__) output;
|
unsigned char*__restrict__ strOut = (unsigned char* __restrict__) output;
|
||||||
unsigned long long*__restrict__ symbol = (unsigned long long* __restrict__) decoder->symbol;
|
unsigned long long*__restrict__ symbol = (unsigned long long* __restrict__) decoder->symbol;
|
||||||
size_t code, posOut = 0, posIn = 0;
|
size_t code, posOut = 0, posIn = 0;
|
||||||
#ifndef FSST_MUST_ALIGN_STORES /* define this if your platform does not allow unaligned memory access */
|
#ifndef FSST_MUST_ALIGN /* defining on platforms that require aligned memory access may help their performance */
|
||||||
|
#define FSST_UNALIGNED_STORE(dst,src) memcpy((unsigned long long*) (dst), &(src), sizeof(unsigned long long))
|
||||||
#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
||||||
while (posOut+32 <= size && posIn+4 <= lenIn) {
|
while (posOut+32 <= size && posIn+4 <= lenIn) {
|
||||||
unsigned int nextBlock = *((unsigned int*) (strIn+posIn));
|
unsigned int nextBlock, escapeMask;
|
||||||
unsigned int escapeMask = (nextBlock&0x80808080u)&((((~nextBlock)&0x7F7F7F7Fu)+0x7F7F7F7Fu)^0x80808080u);
|
memcpy(&nextBlock, strIn+posIn, sizeof(unsigned int));
|
||||||
|
escapeMask = (nextBlock&0x80808080u)&((((~nextBlock)&0x7F7F7F7Fu)+0x7F7F7F7Fu)^0x80808080u);
|
||||||
if (escapeMask == 0) {
|
if (escapeMask == 0) {
|
||||||
code = strIn[posIn++]; *(unsigned long long*) (strOut+posOut) = symbol[code]; posOut += len[code];
|
code = strIn[posIn++]; FSST_UNALIGNED_STORE(strOut+posOut, symbol[code]); posOut += len[code];
|
||||||
code = strIn[posIn++]; *(unsigned long long*) (strOut+posOut) = symbol[code]; posOut += len[code];
|
code = strIn[posIn++]; FSST_UNALIGNED_STORE(strOut+posOut, symbol[code]); posOut += len[code];
|
||||||
code = strIn[posIn++]; *(unsigned long long*) (strOut+posOut) = symbol[code]; posOut += len[code];
|
code = strIn[posIn++]; FSST_UNALIGNED_STORE(strOut+posOut, symbol[code]); posOut += len[code];
|
||||||
code = strIn[posIn++]; *(unsigned long long*) (strOut+posOut) = symbol[code]; posOut += len[code];
|
code = strIn[posIn++]; FSST_UNALIGNED_STORE(strOut+posOut, symbol[code]); posOut += len[code];
|
||||||
} else {
|
} else {
|
||||||
unsigned long firstEscapePos=__builtin_ctzl((unsigned long long) escapeMask)>>3;
|
unsigned long firstEscapePos=__builtin_ctzl((unsigned long long) escapeMask)>>3;
|
||||||
switch(firstEscapePos) { /* Duff's device */
|
switch(firstEscapePos) { /* Duff's device */
|
||||||
case 3: code = strIn[posIn++]; *(unsigned long long*) (strOut+posOut) = symbol[code]; posOut += len[code]; FSST_FALLTHROUGH;
|
case 3: code = strIn[posIn++]; FSST_UNALIGNED_STORE(strOut+posOut, symbol[code]); posOut += len[code];
|
||||||
case 2: code = strIn[posIn++]; *(unsigned long long*) (strOut+posOut) = symbol[code]; posOut += len[code]; FSST_FALLTHROUGH;
|
case 2: code = strIn[posIn++]; FSST_UNALIGNED_STORE(strOut+posOut, symbol[code]); posOut += len[code];
|
||||||
case 1: code = strIn[posIn++]; *(unsigned long long*) (strOut+posOut) = symbol[code]; posOut += len[code]; FSST_FALLTHROUGH;
|
case 1: code = strIn[posIn++]; FSST_UNALIGNED_STORE(strOut+posOut, symbol[code]); posOut += len[code];
|
||||||
case 0: posIn+=2; strOut[posOut++] = strIn[posIn-1]; /* decompress an escaped byte */
|
case 0: posIn+=2; strOut[posOut++] = strIn[posIn-1]; /* decompress an escaped byte */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,9 +178,9 @@ fsst_decompress(
|
|||||||
if (posIn+2 <= lenIn) {
|
if (posIn+2 <= lenIn) {
|
||||||
strOut[posOut] = strIn[posIn+1];
|
strOut[posOut] = strIn[posIn+1];
|
||||||
if (strIn[posIn] != FSST_ESC) {
|
if (strIn[posIn] != FSST_ESC) {
|
||||||
code = strIn[posIn++]; *(unsigned long long*) (strOut+posOut) = symbol[code]; posOut += len[code];
|
code = strIn[posIn++]; FSST_UNALIGNED_STORE(strOut+posOut, symbol[code]); posOut += len[code];
|
||||||
if (strIn[posIn] != FSST_ESC) {
|
if (strIn[posIn] != FSST_ESC) {
|
||||||
code = strIn[posIn++]; *(unsigned long long*) (strOut+posOut) = symbol[code]; posOut += len[code];
|
code = strIn[posIn++]; FSST_UNALIGNED_STORE(strOut+posOut, symbol[code]); posOut += len[code];
|
||||||
} else {
|
} else {
|
||||||
posIn += 2; strOut[posOut++] = strIn[posIn-1];
|
posIn += 2; strOut[posOut++] = strIn[posIn-1];
|
||||||
}
|
}
|
||||||
@ -186,13 +189,13 @@ fsst_decompress(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (posIn < lenIn) { // last code cannot be an escape
|
if (posIn < lenIn) { // last code cannot be an escape
|
||||||
code = strIn[posIn++]; *(unsigned long long*) (strOut+posOut) = symbol[code]; posOut += len[code];
|
code = strIn[posIn++]; FSST_UNALIGNED_STORE(strOut+posOut, symbol[code]); posOut += len[code];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
while (posOut+8 <= size && posIn < lenIn)
|
while (posOut+8 <= size && posIn < lenIn)
|
||||||
if ((code = strIn[posIn++]) < FSST_ESC) { /* symbol compressed as code? */
|
if ((code = strIn[posIn++]) < FSST_ESC) { /* symbol compressed as code? */
|
||||||
*(unsigned long long*) (strOut+posOut) = symbol[code]; /* unaligned memory write */
|
FSST_UNALIGNED_STORE(strOut+posOut, symbol[code]); /* unaligned memory write */
|
||||||
posOut += len[code];
|
posOut += len[code];
|
||||||
} else {
|
} else {
|
||||||
strOut[posOut] = strIn[posIn]; /* decompress an escaped byte */
|
strOut[posOut] = strIn[posIn]; /* decompress an escaped byte */
|
||||||
@ -218,5 +221,4 @@ fsst_decompress(
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#endif /* FSST_INCLUDED_H */
|
||||||
#endif /* _FSST_H_ */
|
|
||||||
|
@ -17,6 +17,12 @@
|
|||||||
// You can contact the authors via the FSST source repository : https://github.com/cwida/fsst
|
// You can contact the authors via the FSST source repository : https://github.com/cwida/fsst
|
||||||
#include "libfsst.hpp"
|
#include "libfsst.hpp"
|
||||||
|
|
||||||
|
inline uint64_t fsst_unaligned_load(u8 const* V) {
|
||||||
|
uint64_t Ret;
|
||||||
|
memcpy(&Ret, V, sizeof(uint64_t)); // compiler will generate efficient code (unaligned load, where possible)
|
||||||
|
return Ret;
|
||||||
|
}
|
||||||
|
|
||||||
Symbol concat(Symbol a, Symbol b) {
|
Symbol concat(Symbol a, Symbol b) {
|
||||||
Symbol s;
|
Symbol s;
|
||||||
u32 length = a.length()+b.length();
|
u32 length = a.length()+b.length();
|
||||||
@ -109,7 +115,7 @@ SymbolTable *buildSymbolTable(Counters& counters, vector<u8*> line, size_t len[]
|
|||||||
if (st->symbols[pos1].length() != 1)
|
if (st->symbols[pos1].length() != 1)
|
||||||
counters.count1Inc(*cur);
|
counters.count1Inc(*cur);
|
||||||
if (cur<end-7) {
|
if (cur<end-7) {
|
||||||
size_t word = reinterpret_cast<const uint64_t*>(cur)[0];
|
u64 word = fsst_unaligned_load(cur);
|
||||||
size_t pos = word & 0xFFFFFF;
|
size_t pos = word & 0xFFFFFF;
|
||||||
size_t idx = FSST_HASH(pos)&(st->hashTabSize-1);
|
size_t idx = FSST_HASH(pos)&(st->hashTabSize-1);
|
||||||
Symbol s = st->hashTab[idx];
|
Symbol s = st->hashTab[idx];
|
||||||
@ -321,8 +327,8 @@ static inline size_t compressSIMD(SymbolTable &symbolTable, u8* symbolBase, size
|
|||||||
u8* end = symbolBase + job.end;
|
u8* end = symbolBase + job.end;
|
||||||
u8* out = codeBase + job.out;
|
u8* out = codeBase + job.out;
|
||||||
while (cur < end) {
|
while (cur < end) {
|
||||||
u64 word = reinterpret_cast<const uint64_t*>(cur)[0];
|
u64 word = fsst_unaligned_load(cur);
|
||||||
u64 code = symbolTable.shortCodes[word & 0xFFFF];
|
size_t code = symbolTable.shortCodes[word & 0xFFFF];
|
||||||
size_t pos = word & 0xFFFFFF;
|
size_t pos = word & 0xFFFFFF;
|
||||||
size_t idx = FSST_HASH(pos)&(symbolTable.hashTabSize-1);
|
size_t idx = FSST_HASH(pos)&(symbolTable.hashTabSize-1);
|
||||||
Symbol s = symbolTable.hashTab[idx];
|
Symbol s = symbolTable.hashTab[idx];
|
||||||
@ -376,7 +382,7 @@ static inline size_t compressBulk(SymbolTable &symbolTable, size_t nlines, size_
|
|||||||
// three variants are possible. dead code falls away since the bool arguments are constants
|
// three variants are possible. dead code falls away since the bool arguments are constants
|
||||||
auto compressVariant = [&](bool noSuffixOpt, bool avoidBranch) {
|
auto compressVariant = [&](bool noSuffixOpt, bool avoidBranch) {
|
||||||
while (cur < end) {
|
while (cur < end) {
|
||||||
u64 word = reinterpret_cast<const uint64_t*>(cur)[0];
|
u64 word = fsst_unaligned_load(cur);
|
||||||
size_t code = symbolTable.shortCodes[word & 0xFFFF];
|
size_t code = symbolTable.shortCodes[word & 0xFFFF];
|
||||||
if (noSuffixOpt && ((u8) code) < suffixLim) {
|
if (noSuffixOpt && ((u8) code) < suffixLim) {
|
||||||
// 2 byte code without having to worry about longer matches
|
// 2 byte code without having to worry about longer matches
|
||||||
|
@ -71,22 +71,12 @@ struct Symbol {
|
|||||||
explicit Symbol(const char* begin, const char* end) : Symbol(begin, (u32) (end-begin)) {}
|
explicit Symbol(const char* begin, const char* end) : Symbol(begin, (u32) (end-begin)) {}
|
||||||
explicit Symbol(u8* begin, u8* end) : Symbol((const char*)begin, (u32) (end-begin)) {}
|
explicit Symbol(u8* begin, u8* end) : Symbol((const char*)begin, (u32) (end-begin)) {}
|
||||||
explicit Symbol(const char* input, u32 len) {
|
explicit Symbol(const char* input, u32 len) {
|
||||||
u8 ignoredBits = 0;
|
val.num = 0;
|
||||||
if (len>=8) {
|
if (len>=8) {
|
||||||
val.num = reinterpret_cast<const uint64_t*>(input)[0];
|
len = 8;
|
||||||
len = 8;
|
memcpy(val.str, input, 8);
|
||||||
} else {
|
} else {
|
||||||
#ifdef MEMDEBUG
|
memcpy(val.str, input, len);
|
||||||
for(u32 i=0; i<len; i++) val.str[i] = input[i];
|
|
||||||
#else
|
|
||||||
ignoredBits = 8*(8-len);
|
|
||||||
if ((reinterpret_cast<uintptr_t>(input)&63)<=(64-8)) {
|
|
||||||
u64 eight = reinterpret_cast<const uint64_t*>(input)[0];
|
|
||||||
val.num = (eight<<ignoredBits)>>ignoredBits;
|
|
||||||
} else {
|
|
||||||
val.num = reinterpret_cast<const uint64_t*>(input+len-8)[0]>>ignoredBits;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
set_code_len(FSST_CODE_MAX, len);
|
set_code_len(FSST_CODE_MAX, len);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user