Compare commits
31 Commits
0.27.0
...
0.27.3-sp2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f999839e59 | ||
|
|
f1bc662a24 | ||
|
|
232693419a | ||
|
|
ed66b951c6 | ||
|
|
70c2854f7c | ||
|
|
e9381ddeb2 | ||
|
|
9cc8eec773 | ||
|
|
0b45535061 | ||
|
|
95973ba3e8 | ||
|
|
ac64731d55 | ||
|
|
5dc064e971 | ||
|
|
c24732ed4e | ||
|
|
ba710bee86 | ||
|
|
c20392ca80 | ||
|
|
8eb05d0950 | ||
|
|
0f94e2c0c3 | ||
|
|
a25508b98d | ||
|
|
e825433a38 | ||
|
|
d1c08889fe | ||
|
|
0b82b5a0d6 | ||
|
|
a33d0d4fb6 | ||
|
|
ba42334d36 | ||
|
|
2e62641aa4 | ||
|
|
dad460dcfc | ||
|
|
3ae23b6a54 | ||
|
|
97126f18b1 | ||
|
|
3838d222c2 | ||
|
|
96c3292210 | ||
|
|
b0fd92cb3f | ||
|
|
6276c55cc9 | ||
|
|
afa6ff7c4b |
@@ -809,20 +809,22 @@
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\api.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\common.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\create.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\arena.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\bucket.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\buffers.h">
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\buffer.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\bulkio.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\cache.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\config.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\field.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\format.h">
|
||||
@@ -831,21 +833,19 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\pool.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\posix_file.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\stream.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\win32_file.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\error.h">
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\varint.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\file.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\mode.h">
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\identity_codec.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\beast\beast\nudb\nudb.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\posix_file.h">
|
||||
</ClInclude>
|
||||
<None Include="..\..\src\beast\beast\nudb\README.md">
|
||||
</None>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\recover.h">
|
||||
@@ -865,6 +865,9 @@
|
||||
<ClCompile Include="..\..\src\beast\beast\nudb\tests\store_test.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\beast\beast\nudb\tests\varint_test.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\beast\beast\nudb\tests\verify_test.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
@@ -872,6 +875,8 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\visit.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\win32_file.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\random\rngfill.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\random\xor_shift_engine.h">
|
||||
@@ -1553,6 +1558,16 @@
|
||||
<ClCompile Include="..\..\src\leveldb\util\status.cc">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\lz4\lib\lz4.c">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\lz4\lib\lz4.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\lz4\lib\xxhash.c">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\lz4\lib\xxhash.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\protobuf\src\google\protobuf\compiler\importer.cc">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
@@ -2524,6 +2539,9 @@
|
||||
<ClCompile Include="..\..\src\ripple\nodestore\backend\RocksDBFactory.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\nodestore\backend\RocksDBQuickFactory.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\nodestore\Database.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\nodestore\DatabaseRotating.h">
|
||||
@@ -2537,6 +2555,8 @@
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\nodestore\impl\BatchWriter.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\nodestore\impl\codec.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\nodestore\impl\DatabaseImp.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\nodestore\impl\DatabaseRotatingImp.cpp">
|
||||
@@ -2586,6 +2606,9 @@
|
||||
<ClCompile Include="..\..\src\ripple\nodestore\tests\Database.test.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\nodestore\tests\import_test.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\nodestore\tests\Timing.test.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
@@ -3389,6 +3412,8 @@
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\unity\leveldb.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\unity\lz4.c">
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\unity\net.cpp">
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\unity\nodestore.cpp">
|
||||
|
||||
@@ -265,6 +265,12 @@
|
||||
<Filter Include="leveldb\util">
|
||||
<UniqueIdentifier>{A3DA589F-2CB8-7260-66DC-5975D80AB46B}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="lz4">
|
||||
<UniqueIdentifier>{B211F8F1-22D2-47BA-C39E-F9846A844D11}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="lz4\lib">
|
||||
<UniqueIdentifier>{4F65E5BD-7EC4-113A-4603-B4625F16BC18}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="protobuf">
|
||||
<UniqueIdentifier>{C535C933-C404-7C0F-2AB9-059F92DE0A80}</UniqueIdentifier>
|
||||
</Filter>
|
||||
@@ -1473,6 +1479,12 @@
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb.h">
|
||||
<Filter>beast</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\api.h">
|
||||
<Filter>beast\nudb</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\common.h">
|
||||
<Filter>beast\nudb</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\create.h">
|
||||
<Filter>beast\nudb</Filter>
|
||||
</ClInclude>
|
||||
@@ -1482,7 +1494,7 @@
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\bucket.h">
|
||||
<Filter>beast\nudb\detail</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\buffers.h">
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\buffer.h">
|
||||
<Filter>beast\nudb\detail</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\bulkio.h">
|
||||
@@ -1491,9 +1503,6 @@
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\cache.h">
|
||||
<Filter>beast\nudb\detail</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\config.h">
|
||||
<Filter>beast\nudb\detail</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\field.h">
|
||||
<Filter>beast\nudb\detail</Filter>
|
||||
</ClInclude>
|
||||
@@ -1506,27 +1515,24 @@
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\pool.h">
|
||||
<Filter>beast\nudb\detail</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\posix_file.h">
|
||||
<Filter>beast\nudb\detail</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\stream.h">
|
||||
<Filter>beast\nudb\detail</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\win32_file.h">
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\detail\varint.h">
|
||||
<Filter>beast\nudb\detail</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\error.h">
|
||||
<Filter>beast\nudb</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\file.h">
|
||||
<Filter>beast\nudb</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\mode.h">
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\identity_codec.h">
|
||||
<Filter>beast\nudb</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\beast\beast\nudb\nudb.cpp">
|
||||
<Filter>beast\nudb</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\posix_file.h">
|
||||
<Filter>beast\nudb</Filter>
|
||||
</ClInclude>
|
||||
<None Include="..\..\src\beast\beast\nudb\README.md">
|
||||
<Filter>beast\nudb</Filter>
|
||||
</None>
|
||||
@@ -1551,6 +1557,9 @@
|
||||
<ClCompile Include="..\..\src\beast\beast\nudb\tests\store_test.cpp">
|
||||
<Filter>beast\nudb\tests</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\beast\beast\nudb\tests\varint_test.cpp">
|
||||
<Filter>beast\nudb\tests</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\beast\beast\nudb\tests\verify_test.cpp">
|
||||
<Filter>beast\nudb\tests</Filter>
|
||||
</ClCompile>
|
||||
@@ -1560,6 +1569,9 @@
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\visit.h">
|
||||
<Filter>beast\nudb</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\nudb\win32_file.h">
|
||||
<Filter>beast\nudb</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\beast\beast\random\rngfill.h">
|
||||
<Filter>beast\random</Filter>
|
||||
</ClInclude>
|
||||
@@ -2427,6 +2439,18 @@
|
||||
<ClCompile Include="..\..\src\leveldb\util\status.cc">
|
||||
<Filter>leveldb\util</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\lz4\lib\lz4.c">
|
||||
<Filter>lz4\lib</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\lz4\lib\lz4.h">
|
||||
<Filter>lz4\lib</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\lz4\lib\xxhash.c">
|
||||
<Filter>lz4\lib</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\lz4\lib\xxhash.h">
|
||||
<Filter>lz4\lib</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\protobuf\src\google\protobuf\compiler\importer.cc">
|
||||
<Filter>protobuf\src\google\protobuf\compiler</Filter>
|
||||
</ClCompile>
|
||||
@@ -3606,6 +3630,9 @@
|
||||
<ClCompile Include="..\..\src\ripple\nodestore\backend\RocksDBFactory.cpp">
|
||||
<Filter>ripple\nodestore\backend</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\nodestore\backend\RocksDBQuickFactory.cpp">
|
||||
<Filter>ripple\nodestore\backend</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\nodestore\Database.h">
|
||||
<Filter>ripple\nodestore</Filter>
|
||||
</ClInclude>
|
||||
@@ -3624,6 +3651,9 @@
|
||||
<ClInclude Include="..\..\src\ripple\nodestore\impl\BatchWriter.h">
|
||||
<Filter>ripple\nodestore\impl</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\nodestore\impl\codec.h">
|
||||
<Filter>ripple\nodestore\impl</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\nodestore\impl\DatabaseImp.h">
|
||||
<Filter>ripple\nodestore\impl</Filter>
|
||||
</ClInclude>
|
||||
@@ -3684,6 +3714,9 @@
|
||||
<ClCompile Include="..\..\src\ripple\nodestore\tests\Database.test.cpp">
|
||||
<Filter>ripple\nodestore\tests</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\nodestore\tests\import_test.cpp">
|
||||
<Filter>ripple\nodestore\tests</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\nodestore\tests\Timing.test.cpp">
|
||||
<Filter>ripple\nodestore\tests</Filter>
|
||||
</ClCompile>
|
||||
@@ -4638,6 +4671,9 @@
|
||||
<ClInclude Include="..\..\src\ripple\unity\leveldb.h">
|
||||
<Filter>ripple\unity</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\unity\lz4.c">
|
||||
<Filter>ripple\unity</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\unity\net.cpp">
|
||||
<Filter>ripple\unity</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name: rippled
|
||||
Version: 0.27.0
|
||||
Version: 0.27.3-sp2
|
||||
Release: 1%{?dist}
|
||||
Summary: Ripple peer-to-peer network daemon
|
||||
|
||||
|
||||
@@ -667,6 +667,7 @@ for tu_style in ['classic', 'unity']:
|
||||
object_builder.add_source_files(
|
||||
'src/beast/beast/unity/hash_unity.cpp',
|
||||
'src/ripple/unity/beast.cpp',
|
||||
'src/ripple/unity/lz4.c',
|
||||
'src/ripple/unity/protobuf.cpp',
|
||||
'src/ripple/unity/ripple.proto.cpp',
|
||||
'src/ripple/unity/resource.cpp',
|
||||
|
||||
@@ -2,13 +2,10 @@
|
||||
"name": "rippled",
|
||||
"version": "0.0.1",
|
||||
"description": "Rippled Server",
|
||||
|
||||
"private": true,
|
||||
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
|
||||
"dependencies": {
|
||||
"ripple-lib": "0.8.2",
|
||||
"async": "~0.2.9",
|
||||
@@ -17,18 +14,16 @@
|
||||
"deep-equal": "0.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"assert-diff": "^1.0.1",
|
||||
"coffee-script": "~1.6.3",
|
||||
"mocha": "~1.13.0"
|
||||
},
|
||||
|
||||
"scripts": {
|
||||
"test": "mocha test/websocket-test.js test/server-test.js test/*-test.{js,coffee}"
|
||||
},
|
||||
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/ripple/rippled.git"
|
||||
},
|
||||
|
||||
"readmeFilename": "README.md"
|
||||
}
|
||||
|
||||
@@ -231,16 +231,13 @@ private:
|
||||
using argument_type = element;
|
||||
using result_type = value_type;
|
||||
|
||||
const_buffers_type const* buffers_;
|
||||
basic_streambuf const* streambuf_ = nullptr;
|
||||
|
||||
transform()
|
||||
: buffers_ (nullptr)
|
||||
{
|
||||
}
|
||||
transform() = default;
|
||||
|
||||
explicit
|
||||
transform (const_buffers_type const& buffers)
|
||||
: buffers_ (&buffers)
|
||||
transform (basic_streambuf const& streambuf)
|
||||
: streambuf_ (&streambuf)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -255,11 +252,15 @@ public:
|
||||
transform, typename list_type::const_iterator,
|
||||
value_type, value_type>;
|
||||
|
||||
const_buffers_type() = default;
|
||||
const_buffers_type (const_buffers_type const&) = default;
|
||||
const_buffers_type& operator= (const_buffers_type const&) = default;
|
||||
|
||||
const_iterator
|
||||
begin() const
|
||||
{
|
||||
return const_iterator (streambuf_->list_.begin(),
|
||||
transform(*this));
|
||||
transform(*streambuf_));
|
||||
}
|
||||
|
||||
const_iterator
|
||||
@@ -267,7 +268,7 @@ public:
|
||||
{
|
||||
return const_iterator (streambuf_->out_ ==
|
||||
streambuf_->list_.end() ? streambuf_->list_.end() :
|
||||
std::next(streambuf_->out_), transform(*this));
|
||||
std::next(streambuf_->out_), transform(*streambuf_));
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -290,12 +291,11 @@ basic_streambuf<Allocator>::const_buffers_type::
|
||||
transform::operator() (element const& e) const ->
|
||||
value_type const
|
||||
{
|
||||
basic_streambuf const& streambuf = *buffers_->streambuf_;
|
||||
return value_type (e.data(),
|
||||
(streambuf.out_ == streambuf.list_.end() ||
|
||||
&e != &*streambuf.out_) ? e.size() : streambuf.out_pos_) +
|
||||
(&e == &*streambuf.list_.begin() ?
|
||||
streambuf.in_pos_ : 0);
|
||||
(streambuf_->out_ == streambuf_->list_.end() ||
|
||||
&e != &*streambuf_->out_) ? e.size() : streambuf_->out_pos_) +
|
||||
(&e == &*streambuf_->list_.begin() ?
|
||||
streambuf_->in_pos_ : 0);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -312,16 +312,13 @@ private:
|
||||
using argument_type = element;
|
||||
using result_type = value_type;
|
||||
|
||||
mutable_buffers_type const* buffers_;
|
||||
basic_streambuf const* streambuf_ = nullptr;
|
||||
|
||||
transform()
|
||||
: buffers_ (nullptr)
|
||||
{
|
||||
}
|
||||
transform() = default;
|
||||
|
||||
explicit
|
||||
transform (mutable_buffers_type const& buffers)
|
||||
: buffers_ (&buffers)
|
||||
transform (basic_streambuf const& streambuf)
|
||||
: streambuf_ (&streambuf)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -336,18 +333,22 @@ public:
|
||||
transform, typename list_type::const_iterator,
|
||||
value_type, value_type>;
|
||||
|
||||
mutable_buffers_type() = default;
|
||||
mutable_buffers_type (mutable_buffers_type const&) = default;
|
||||
mutable_buffers_type& operator= (mutable_buffers_type const&) = default;
|
||||
|
||||
const_iterator
|
||||
begin() const
|
||||
{
|
||||
return const_iterator (streambuf_->out_,
|
||||
transform(*this));
|
||||
transform(*streambuf_));
|
||||
}
|
||||
|
||||
const_iterator
|
||||
end() const
|
||||
{
|
||||
return const_iterator (streambuf_->list_.end(),
|
||||
transform(*this));
|
||||
transform(*streambuf_));
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -368,10 +369,9 @@ basic_streambuf<Allocator>::mutable_buffers_type::
|
||||
transform::operator() (element const& e) const ->
|
||||
value_type const
|
||||
{
|
||||
basic_streambuf const& streambuf = *buffers_->streambuf_;
|
||||
return value_type (e.data(), &e == &*std::prev(streambuf.list_.end()) ?
|
||||
streambuf.out_end_ : e.size()) + (&e == &*streambuf.out_ ?
|
||||
streambuf.out_pos_ : 0);
|
||||
return value_type (e.data(), &e == &*std::prev(streambuf_->list_.end()) ?
|
||||
streambuf_->out_end_ : e.size()) + (&e == &*streambuf_->out_ ?
|
||||
streambuf_->out_pos_ : 0);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -165,9 +165,11 @@ trim (std::string const& s)
|
||||
http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2
|
||||
*/
|
||||
template <class FwdIt,
|
||||
class Result = std::vector<std::basic_string<typename FwdIt::value_type>>>
|
||||
class Result = std::vector<
|
||||
std::basic_string<typename FwdIt::value_type>>,
|
||||
class Char>
|
||||
Result
|
||||
split_commas(FwdIt first, FwdIt last)
|
||||
split(FwdIt first, FwdIt last, Char delim)
|
||||
{
|
||||
Result result;
|
||||
using string = typename Result::value_type;
|
||||
@@ -206,7 +208,7 @@ split_commas(FwdIt first, FwdIt last)
|
||||
e.clear();
|
||||
}
|
||||
}
|
||||
else if (*iter == ',')
|
||||
else if (*iter == delim)
|
||||
{
|
||||
e = trim_right (e);
|
||||
if (! e.empty())
|
||||
@@ -235,6 +237,15 @@ split_commas(FwdIt first, FwdIt last)
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class FwdIt,
|
||||
class Result = std::vector<
|
||||
std::basic_string<typename FwdIt::value_type>>>
|
||||
Result
|
||||
split_commas(FwdIt first, FwdIt last)
|
||||
{
|
||||
return split(first, last, ',');
|
||||
}
|
||||
|
||||
template <class Result = std::vector<std::string>>
|
||||
Result
|
||||
split_commas(std::string const& s)
|
||||
|
||||
@@ -24,8 +24,9 @@
|
||||
#ifndef BEAST_ELEMENTCOMPARATOR_H_INCLUDED
|
||||
#define BEAST_ELEMENTCOMPARATOR_H_INCLUDED
|
||||
|
||||
namespace beast
|
||||
{
|
||||
#include <algorithm>
|
||||
|
||||
namespace beast {
|
||||
|
||||
#ifndef DOXYGEN
|
||||
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
#ifndef BEAST_NUDB_H_INCLUDED
|
||||
#define BEAST_NUDB_H_INCLUDED
|
||||
|
||||
#include <beast/nudb/api.h>
|
||||
#include <beast/nudb/create.h>
|
||||
#include <beast/nudb/error.h>
|
||||
#include <beast/nudb/common.h>
|
||||
#include <beast/nudb/file.h>
|
||||
#include <beast/nudb/mode.h>
|
||||
#include <beast/nudb/recover.h>
|
||||
#include <beast/nudb/store.h>
|
||||
#include <beast/nudb/verify.h>
|
||||
|
||||
@@ -167,16 +167,23 @@ fixed-length Bucket Records.
|
||||
|
||||
char[8] Type The characters "nudb.key"
|
||||
uint16 Version Holds the version number
|
||||
uint64 UID Unique ID generated on creation
|
||||
uint64 Appnum Application defined constant
|
||||
uint16 KeySize Key size in bytes
|
||||
|
||||
uint64 Salt A random seed
|
||||
uint64 Pepper The salt hashed
|
||||
uint16 KeySize Key size in bytes
|
||||
uint16 BlockSize Size of a file block in bytes
|
||||
|
||||
uint16 LoadFactor Target fraction in 65536ths
|
||||
uint8[64] Reserved Zeroes
|
||||
|
||||
uint8[56] Reserved Zeroes
|
||||
uint8[] Reserved Zero-pad to block size
|
||||
|
||||
The Type identifies the file as belonging to nudb. Salt is
|
||||
The Type identifies the file as belonging to nudb. The UID is
|
||||
generated randomly when the database is created, and this value
|
||||
is stored in the data and log files as well. The UID is used
|
||||
to determine if files belong to the same database. Salt is
|
||||
generated when the database is created and helps prevent
|
||||
complexity attacks; the salt is prepended to the key material
|
||||
when computing a hash, or used to initialize the state of
|
||||
@@ -197,7 +204,8 @@ bucket, and defines the size of a bucket record. The load factor
|
||||
is the target fraction of bucket occupancy.
|
||||
|
||||
None of the information in the key file header or the data file
|
||||
header may be changed after the database is created.
|
||||
header may be changed after the database is created, including
|
||||
the Appnum.
|
||||
|
||||
#### Bucket Record (fixed-length)
|
||||
|
||||
@@ -209,7 +217,7 @@ header may be changed after the database is created.
|
||||
|
||||
uint48 Offset Offset in data file of the data
|
||||
uint48 Size The size of the value in bytes
|
||||
uint8[KeySize] Key The key
|
||||
uint48 Hash The hash of the key
|
||||
|
||||
### Data File
|
||||
|
||||
@@ -220,14 +228,15 @@ variable-length Value Records and Spill Records.
|
||||
|
||||
char[8] Type The characters "nudb.dat"
|
||||
uint16 Version Holds the version number
|
||||
uint64 UID Unique ID generated on creation
|
||||
uint64 Appnum Application defined constant
|
||||
uint64 Salt A random seed
|
||||
uint16 KeySize Key size in bytes
|
||||
|
||||
uint8[64] Reserved Zeroes
|
||||
|
||||
Salt contains the same value as the salt in the corresponding
|
||||
key file. This is placed in the data file so that key and value
|
||||
files belonging to the same database can be identified.
|
||||
UID contains the same value as the salt in the corresponding key
|
||||
file. This is placed in the data file so that key and value files
|
||||
belonging to the same database can be identified.
|
||||
|
||||
#### Data Record (variable-length)
|
||||
|
||||
@@ -244,15 +253,24 @@ files belonging to the same database can be identified.
|
||||
### Log File
|
||||
|
||||
The Log file contains the Header followed by zero or more fixed size
|
||||
log records. Each log record contains a snapshot of a bucket. When a
|
||||
database is not closed cleanly, the recovery process applies the log
|
||||
records to the key file, overwriting data that may be only partially
|
||||
updated with known good information. After the log records are applied,
|
||||
the data and key files are truncated to the last known good size.
|
||||
|
||||
#### Header (44 bytes)
|
||||
#### Header (62 bytes)
|
||||
|
||||
char[8] Type The characters "nudb.log"
|
||||
uint16 Version Holds the version number
|
||||
uint64 UID Unique ID generated on creation
|
||||
uint64 Appnum Application defined constant
|
||||
uint16 KeySize Key size in bytes
|
||||
|
||||
uint64 Salt A random seed.
|
||||
uint64 Pepper The salt hashed
|
||||
uint16 KeySize Key size in bytes
|
||||
uint16 BlockSize Size of a file block in bytes
|
||||
|
||||
uint64 KeyFileSize Size of key file.
|
||||
uint64 DataFileSize Size of data file.
|
||||
|
||||
|
||||
109
src/beast/beast/nudb/api.h
Normal file
@@ -0,0 +1,109 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2014, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_NUDB_API_H_INCLUDED
|
||||
#define BEAST_NUDB_API_H_INCLUDED
|
||||
|
||||
#include <beast/nudb/create.h>
|
||||
#include <beast/nudb/store.h>
|
||||
#include <beast/nudb/recover.h>
|
||||
#include <beast/nudb/verify.h>
|
||||
#include <beast/nudb/visit.h>
|
||||
#include <cstdint>
|
||||
|
||||
namespace beast {
|
||||
namespace nudb {
|
||||
|
||||
// Convenience for consolidating template arguments
|
||||
//
|
||||
template <
|
||||
class Hasher,
|
||||
class Codec,
|
||||
class File = native_file,
|
||||
std::size_t BufferSize = 16 * 1024 * 1024
|
||||
>
|
||||
struct api
|
||||
{
|
||||
using hash_type = Hasher;
|
||||
using codec_type = Codec;
|
||||
using file_type = File;
|
||||
using store = nudb::store<Hasher, Codec, File>;
|
||||
|
||||
static std::size_t const buffer_size = BufferSize;
|
||||
|
||||
template <class... Args>
|
||||
static
|
||||
bool
|
||||
create (
|
||||
path_type const& dat_path,
|
||||
path_type const& key_path,
|
||||
path_type const& log_path,
|
||||
std::uint64_t appnum,
|
||||
std::uint64_t salt,
|
||||
std::size_t key_size,
|
||||
std::size_t block_size,
|
||||
float load_factor,
|
||||
Args&&... args)
|
||||
{
|
||||
return nudb::create<Hasher, Codec, File>(
|
||||
dat_path, key_path, log_path,
|
||||
appnum, salt, key_size, block_size,
|
||||
load_factor, args...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
static
|
||||
bool
|
||||
recover (
|
||||
path_type const& dat_path,
|
||||
path_type const& key_path,
|
||||
path_type const& log_path,
|
||||
Args&&... args)
|
||||
{
|
||||
return nudb::recover<Hasher, Codec, File>(
|
||||
dat_path, key_path, log_path, BufferSize,
|
||||
args...);
|
||||
}
|
||||
|
||||
static
|
||||
verify_info
|
||||
verify (
|
||||
path_type const& dat_path,
|
||||
path_type const& key_path)
|
||||
{
|
||||
return nudb::verify<Hasher>(
|
||||
dat_path, key_path, BufferSize);
|
||||
}
|
||||
|
||||
template <class Function>
|
||||
static
|
||||
bool
|
||||
visit(
|
||||
path_type const& path,
|
||||
Function&& f)
|
||||
{
|
||||
return nudb::visit<Codec>(
|
||||
path, BufferSize, f);
|
||||
}
|
||||
};
|
||||
|
||||
} // nudb
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -17,32 +17,48 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_NUDB_ERROR_H_INCLUDED
|
||||
#define BEAST_NUDB_ERROR_H_INCLUDED
|
||||
#ifndef BEAST_NUDB_COMMON_H_INCLUDED
|
||||
#define BEAST_NUDB_COMMON_H_INCLUDED
|
||||
|
||||
#include <beast/nudb/detail/config.h>
|
||||
#include <beast/utility/noexcept.h>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
namespace nudb {
|
||||
|
||||
// Commonly used types
|
||||
|
||||
enum class file_mode
|
||||
{
|
||||
scan, // read sequential
|
||||
read, // read random
|
||||
append, // read random, write append
|
||||
write // read random, write random
|
||||
};
|
||||
|
||||
using path_type = std::string;
|
||||
|
||||
// All exceptions thrown by nudb are derived
|
||||
// from std::exception except for fail_error
|
||||
// from std::runtime_error except for fail_error
|
||||
|
||||
/** Thrown when a codec fails, e.g. corrupt data. */
|
||||
struct codec_error : std::runtime_error
|
||||
{
|
||||
template <class String>
|
||||
explicit
|
||||
codec_error (String const& s)
|
||||
: runtime_error(s)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/** Base class for all errors thrown by file classes. */
|
||||
struct file_error : std::runtime_error
|
||||
{
|
||||
template <class String>
|
||||
explicit
|
||||
file_error (char const* s)
|
||||
: std::runtime_error(s)
|
||||
{
|
||||
}
|
||||
|
||||
explicit
|
||||
file_error (std::string const& s)
|
||||
: std::runtime_error(s)
|
||||
file_error (String const& s)
|
||||
: runtime_error(s)
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -67,21 +83,24 @@ struct file_short_write_error : file_error
|
||||
}
|
||||
};
|
||||
|
||||
/** Thrown when end of istream reached while reading. */
|
||||
struct short_read_error : std::runtime_error
|
||||
{
|
||||
short_read_error()
|
||||
: std::runtime_error(
|
||||
"nudb: short read")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/** Base class for all exceptions thrown by store. */
|
||||
class store_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
template <class String>
|
||||
explicit
|
||||
store_error (char const* m)
|
||||
: std::runtime_error(
|
||||
std::string("nudb: ") + m)
|
||||
{
|
||||
}
|
||||
|
||||
explicit
|
||||
store_error (std::string const& m)
|
||||
: std::runtime_error(
|
||||
std::string("nudb: ") + m)
|
||||
store_error (String const& s)
|
||||
: runtime_error(s)
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -90,15 +109,10 @@ public:
|
||||
class store_corrupt_error : public store_error
|
||||
{
|
||||
public:
|
||||
template <class String>
|
||||
explicit
|
||||
store_corrupt_error (char const* m)
|
||||
: store_error (m)
|
||||
{
|
||||
}
|
||||
|
||||
explicit
|
||||
store_corrupt_error (std::string const& m)
|
||||
: store_error (m)
|
||||
store_corrupt_error (String const& s)
|
||||
: store_error(s)
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -22,16 +22,49 @@
|
||||
|
||||
#include <beast/nudb/file.h>
|
||||
#include <beast/nudb/detail/bucket.h>
|
||||
#include <beast/nudb/detail/config.h>
|
||||
#include <beast/nudb/detail/format.h>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <random>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace nudb {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class = void>
|
||||
std::uint64_t
|
||||
make_uid()
|
||||
{
|
||||
std::random_device rng;
|
||||
std::mt19937_64 gen {rng()};
|
||||
std::uniform_int_distribution <std::size_t> dist;
|
||||
return dist(gen);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Generate a random salt. */
|
||||
template <class = void>
|
||||
std::uint64_t
|
||||
make_salt()
|
||||
{
|
||||
std::random_device rng;
|
||||
std::mt19937_64 gen {rng()};
|
||||
std::uniform_int_distribution <std::size_t> dist;
|
||||
return dist(gen);
|
||||
}
|
||||
|
||||
/** Returns the best guess at the volume's block size. */
|
||||
inline
|
||||
std::size_t
|
||||
block_size (path_type const& /*path*/)
|
||||
{
|
||||
return 4096;
|
||||
}
|
||||
|
||||
/** Create a new database.
|
||||
Preconditions:
|
||||
The files must not exist
|
||||
@@ -40,7 +73,12 @@ namespace nudb {
|
||||
@param args Arguments passed to File constructors
|
||||
@return `false` if any file could not be created.
|
||||
*/
|
||||
template <class Hasher = default_hash>
|
||||
template <
|
||||
class Hasher,
|
||||
class Codec,
|
||||
class File,
|
||||
class... Args
|
||||
>
|
||||
bool
|
||||
create (
|
||||
path_type const& dat_path,
|
||||
@@ -50,10 +88,10 @@ create (
|
||||
std::uint64_t salt,
|
||||
std::size_t key_size,
|
||||
std::size_t block_size,
|
||||
float load_factor)
|
||||
float load_factor,
|
||||
Args&&... args)
|
||||
{
|
||||
using namespace detail;
|
||||
using File = native_file;
|
||||
if (key_size < 1)
|
||||
throw std::domain_error(
|
||||
"invalid key size");
|
||||
@@ -67,43 +105,41 @@ create (
|
||||
throw std::domain_error(
|
||||
"nudb: load factor too large");
|
||||
auto const capacity =
|
||||
bucket_capacity(key_size, block_size);
|
||||
bucket_capacity(block_size);
|
||||
if (capacity < 1)
|
||||
throw std::domain_error(
|
||||
"nudb: block size too small");
|
||||
File df;
|
||||
File kf;
|
||||
File lf;
|
||||
for(;;)
|
||||
File df(args...);
|
||||
File kf(args...);
|
||||
File lf(args...);
|
||||
if (df.create(
|
||||
file_mode::append, dat_path))
|
||||
{
|
||||
if (df.create(
|
||||
file_mode::append, dat_path))
|
||||
if (kf.create (
|
||||
file_mode::append, key_path))
|
||||
{
|
||||
if (kf.create (
|
||||
file_mode::append, key_path))
|
||||
{
|
||||
if (lf.create(
|
||||
file_mode::append, log_path))
|
||||
break;
|
||||
File::erase (dat_path);
|
||||
}
|
||||
File::erase (key_path);
|
||||
if (lf.create(
|
||||
file_mode::append, log_path))
|
||||
goto success;
|
||||
File::erase (dat_path);
|
||||
}
|
||||
return false;
|
||||
File::erase (key_path);
|
||||
}
|
||||
|
||||
return false;
|
||||
success:
|
||||
dat_file_header dh;
|
||||
dh.version = currentVersion;
|
||||
dh.uid = make_uid();
|
||||
dh.appnum = appnum;
|
||||
dh.salt = salt;
|
||||
dh.key_size = key_size;
|
||||
|
||||
key_file_header kh;
|
||||
kh.version = currentVersion;
|
||||
kh.uid = dh.uid;
|
||||
kh.appnum = appnum;
|
||||
kh.key_size = key_size;
|
||||
kh.salt = salt;
|
||||
kh.pepper = pepper<Hasher>(salt);
|
||||
kh.key_size = key_size;
|
||||
kh.block_size = block_size;
|
||||
// VFALCO Should it be 65536?
|
||||
// How do we set the min?
|
||||
@@ -113,8 +149,7 @@ create (
|
||||
write (kf, kh);
|
||||
buffer buf(block_size);
|
||||
std::memset(buf.get(), 0, block_size);
|
||||
bucket b (key_size, block_size,
|
||||
buf.get(), empty);
|
||||
bucket b (block_size, buf.get(), empty);
|
||||
b.write (kf, block_size);
|
||||
// VFALCO Leave log file empty?
|
||||
df.sync();
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#ifndef BEAST_NUDB_ARENA_H_INCLUDED
|
||||
#define BEAST_NUDB_ARENA_H_INCLUDED
|
||||
|
||||
#include <beast/nudb/detail/config.h>
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
@@ -20,12 +20,11 @@
|
||||
#ifndef BEAST_NUDB_BUCKET_H_INCLUDED
|
||||
#define BEAST_NUDB_BUCKET_H_INCLUDED
|
||||
|
||||
#include <beast/nudb/error.h>
|
||||
#include <beast/nudb/common.h>
|
||||
#include <beast/nudb/detail/bulkio.h>
|
||||
#include <beast/nudb/detail/config.h>
|
||||
#include <beast/nudb/detail/field.h>
|
||||
#include <beast/nudb/detail/format.h>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
@@ -33,21 +32,7 @@ namespace beast {
|
||||
namespace nudb {
|
||||
namespace detail {
|
||||
|
||||
// Key, hash, and bucket calculations:
|
||||
|
||||
// Returns the hash of a key given the salt
|
||||
//
|
||||
template <class Hasher>
|
||||
inline
|
||||
typename Hasher::result_type
|
||||
hash (void const* key,
|
||||
std::size_t key_size, std::size_t salt)
|
||||
{
|
||||
Hasher h (salt);
|
||||
h.append (key, key_size);
|
||||
return static_cast<
|
||||
typename Hasher::result_type>(h);
|
||||
}
|
||||
// bucket calculations:
|
||||
|
||||
// Returns bucket index given hash, buckets, and modulus
|
||||
//
|
||||
@@ -62,30 +47,6 @@ bucket_index (std::size_t h,
|
||||
return n;
|
||||
}
|
||||
|
||||
// Returns the bucket index of a key
|
||||
//
|
||||
template <class Hasher>
|
||||
inline
|
||||
std::size_t
|
||||
bucket_index (void const* key, std::size_t key_size,
|
||||
std::size_t salt, std::size_t buckets,
|
||||
std::size_t modulus)
|
||||
{
|
||||
return bucket_index (hash<Hasher>
|
||||
(key, key_size, salt), buckets, modulus);
|
||||
}
|
||||
|
||||
// Returns the bucket index of a key
|
||||
// given the key file header
|
||||
template <class Hasher>
|
||||
inline
|
||||
std::size_t
|
||||
bucket_index (void const* key, key_file_header const& kh)
|
||||
{
|
||||
return bucket_index<Hasher>(key, kh.key_size,
|
||||
kh.salt, kh.buckets, kh.modulus);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Tag for constructing empty buckets
|
||||
@@ -97,9 +58,8 @@ template <class = void>
|
||||
class bucket_t
|
||||
{
|
||||
private:
|
||||
std::size_t key_size_; // Size of key in bytes
|
||||
std::size_t block_size_; // Size of a key file block
|
||||
std::size_t count_; // Current key count
|
||||
std::size_t size_; // Current key count
|
||||
std::size_t spill_; // Offset of next spill record or 0
|
||||
std::uint8_t* p_; // Pointer to the bucket blob
|
||||
|
||||
@@ -108,23 +68,15 @@ public:
|
||||
{
|
||||
std::size_t offset;
|
||||
std::size_t size;
|
||||
void const* key;
|
||||
std::size_t hash;
|
||||
};
|
||||
|
||||
bucket_t (bucket_t const&) = default;
|
||||
bucket_t& operator= (bucket_t const&) = default;
|
||||
|
||||
bucket_t (std::size_t key_size,
|
||||
std::size_t block_size, void* p);
|
||||
bucket_t (std::size_t block_size, void* p);
|
||||
|
||||
bucket_t (std::size_t key_size,
|
||||
std::size_t block_size, void* p, empty_t);
|
||||
|
||||
std::size_t
|
||||
key_size() const
|
||||
{
|
||||
return key_size_;
|
||||
}
|
||||
bucket_t (std::size_t block_size, void* p, empty_t);
|
||||
|
||||
std::size_t
|
||||
block_size() const
|
||||
@@ -135,44 +87,46 @@ public:
|
||||
std::size_t
|
||||
compact_size() const
|
||||
{
|
||||
return detail::compact_size(
|
||||
key_size_, count_);
|
||||
return detail::bucket_size(size_);
|
||||
}
|
||||
|
||||
bool
|
||||
empty() const
|
||||
{
|
||||
return count_ == 0;
|
||||
return size_ == 0;
|
||||
}
|
||||
|
||||
bool
|
||||
full() const
|
||||
{
|
||||
return count_ >= detail::bucket_capacity(
|
||||
key_size_, block_size_);
|
||||
return size_ >=
|
||||
detail::bucket_capacity(block_size_);
|
||||
}
|
||||
|
||||
std::size_t
|
||||
size() const
|
||||
{
|
||||
return count_;
|
||||
return size_;
|
||||
}
|
||||
|
||||
// Returns offset of next spill record or 0
|
||||
//
|
||||
std::size_t
|
||||
spill() const
|
||||
{
|
||||
return spill_;
|
||||
}
|
||||
|
||||
// Clear contents of the bucket
|
||||
void
|
||||
clear();
|
||||
|
||||
// Set offset of next spill record
|
||||
//
|
||||
void
|
||||
spill (std::size_t offset);
|
||||
|
||||
// Clear contents of the bucket
|
||||
//
|
||||
void
|
||||
clear();
|
||||
|
||||
// Returns the record for a key
|
||||
// entry without bounds checking.
|
||||
//
|
||||
@@ -185,12 +139,15 @@ public:
|
||||
return at(i);
|
||||
}
|
||||
|
||||
std::pair<value_type, bool>
|
||||
find (void const* key) const;
|
||||
// Returns index of entry with prefix
|
||||
// equal to or greater than the given prefix.
|
||||
//
|
||||
std::size_t
|
||||
lower_bound (std::size_t h) const;
|
||||
|
||||
void
|
||||
insert (std::size_t offset,
|
||||
std::size_t size, void const* key);
|
||||
std::size_t size, std::size_t h);
|
||||
|
||||
// Erase an element by index
|
||||
//
|
||||
@@ -227,45 +184,31 @@ private:
|
||||
// Update size and spill in the blob
|
||||
void
|
||||
update();
|
||||
|
||||
std::pair<std::size_t, bool>
|
||||
lower_bound (void const* key) const;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class _>
|
||||
bucket_t<_>::bucket_t (std::size_t key_size,
|
||||
bucket_t<_>::bucket_t (
|
||||
std::size_t block_size, void* p)
|
||||
: key_size_ (key_size)
|
||||
, block_size_ (block_size)
|
||||
: block_size_ (block_size)
|
||||
, p_ (reinterpret_cast<std::uint8_t*>(p))
|
||||
{
|
||||
// Bucket Record
|
||||
istream is(p_, block_size);
|
||||
detail::read<uint16_t>(is, count_); // Count
|
||||
detail::read<uint16_t>(is, size_); // Count
|
||||
detail::read<uint48_t>(is, spill_); // Spill
|
||||
}
|
||||
|
||||
template <class _>
|
||||
bucket_t<_>::bucket_t (std::size_t key_size,
|
||||
bucket_t<_>::bucket_t (
|
||||
std::size_t block_size, void* p, empty_t)
|
||||
: key_size_ (key_size)
|
||||
, block_size_ (block_size)
|
||||
, count_ (0)
|
||||
: block_size_ (block_size)
|
||||
, size_ (0)
|
||||
, spill_ (0)
|
||||
, p_ (reinterpret_cast<std::uint8_t*>(p))
|
||||
{
|
||||
update();
|
||||
}
|
||||
|
||||
template <class _>
|
||||
void
|
||||
bucket_t<_>::clear()
|
||||
{
|
||||
count_ = 0;
|
||||
spill_ = 0;
|
||||
update();
|
||||
clear();
|
||||
}
|
||||
|
||||
template <class _>
|
||||
@@ -276,6 +219,15 @@ bucket_t<_>::spill (std::size_t offset)
|
||||
update();
|
||||
}
|
||||
|
||||
template <class _>
|
||||
void
|
||||
bucket_t<_>::clear()
|
||||
{
|
||||
size_ = 0;
|
||||
spill_ = 0;
|
||||
std::memset(p_, 0, block_size_);
|
||||
}
|
||||
|
||||
template <class _>
|
||||
auto
|
||||
bucket_t<_>::at (std::size_t i) const ->
|
||||
@@ -286,7 +238,7 @@ bucket_t<_>::at (std::size_t i) const ->
|
||||
std::size_t const w =
|
||||
field<uint48_t>::size + // Offset
|
||||
field<uint48_t>::size + // Size
|
||||
key_size_; // Key
|
||||
field<hash_t>::size; // Prefix
|
||||
// Bucket Record
|
||||
detail::istream is(p_ +
|
||||
field<std::uint16_t>::size + // Count
|
||||
@@ -297,54 +249,80 @@ bucket_t<_>::at (std::size_t i) const ->
|
||||
is, result.offset); // Offset
|
||||
detail::read<uint48_t>(
|
||||
is, result.size); // Size
|
||||
result.key = is.data(key_size_); // Key
|
||||
detail::read<hash_t>(
|
||||
is, result.hash); // Hash
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class _>
|
||||
auto
|
||||
bucket_t<_>::find (void const* key) const ->
|
||||
std::pair<value_type, bool>
|
||||
std::size_t
|
||||
bucket_t<_>::lower_bound (
|
||||
std::size_t h) const
|
||||
{
|
||||
std::pair<value_type, bool> result;
|
||||
std::size_t i;
|
||||
std::tie(i, result.second) = lower_bound(key);
|
||||
if (result.second)
|
||||
result.first = at(i);
|
||||
return result;
|
||||
// Bucket Entry
|
||||
auto const w =
|
||||
field<uint48_t>::size + // Offset
|
||||
field<uint48_t>::size + // Size
|
||||
field<hash_t>::size; // Hash
|
||||
// Bucket Record
|
||||
auto const p = p_ +
|
||||
field<std::uint16_t>::size + // Count
|
||||
field<uint48_t>::size + // Spill
|
||||
// Bucket Entry
|
||||
field<uint48_t>::size + // Offset
|
||||
field<uint48_t>::size; // Size
|
||||
std::size_t step;
|
||||
std::size_t first = 0;
|
||||
std::size_t count = size_;
|
||||
while (count > 0)
|
||||
{
|
||||
step = count / 2;
|
||||
auto const i = first + step;
|
||||
std::size_t h1;
|
||||
readp<hash_t>(p + i * w, h1);
|
||||
if (h1 < h)
|
||||
{
|
||||
first = i + 1;
|
||||
count -= step + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
count = step;
|
||||
}
|
||||
}
|
||||
return first;
|
||||
}
|
||||
|
||||
template <class _>
|
||||
void
|
||||
bucket_t<_>::insert (std::size_t offset,
|
||||
std::size_t size, void const* key)
|
||||
std::size_t size, std::size_t h)
|
||||
{
|
||||
bool found;
|
||||
std::size_t i;
|
||||
std::tie(i, found) = lower_bound(key);
|
||||
(void)found;
|
||||
assert(! found);
|
||||
std::size_t i = lower_bound(h);
|
||||
// Bucket Record
|
||||
auto const p = p_ +
|
||||
field<std::uint16_t>::size + // Count
|
||||
field<uint48_t>::size; // Spill
|
||||
field<
|
||||
std::uint16_t>::size + // Count
|
||||
field<uint48_t>::size; // Spill
|
||||
// Bucket Entry
|
||||
std::size_t const w =
|
||||
field<uint48_t>::size + // Offset
|
||||
field<uint48_t>::size + // Size
|
||||
key_size_; // Key
|
||||
field<uint48_t>::size + // Offset
|
||||
field<uint48_t>::size + // Size
|
||||
field<hash_t>::size; // Hash
|
||||
std::memmove (
|
||||
p + (i + 1) * w,
|
||||
p + i * w,
|
||||
(count_ - i) * w);
|
||||
count_++;
|
||||
(size_ - i) * w);
|
||||
size_++;
|
||||
update();
|
||||
// Bucket Entry
|
||||
ostream os (p + i * w, w);
|
||||
detail::write<uint48_t>(os, offset); // Offset
|
||||
detail::write<uint48_t>(os, size); // Size
|
||||
std::memcpy (os.data(key_size_),
|
||||
key, key_size_); // Key
|
||||
detail::write<uint48_t>(
|
||||
os, offset); // Offset
|
||||
detail::write<uint48_t>(
|
||||
os, size); // Size
|
||||
detail::write<hash_t>(
|
||||
os, h); // Prefix
|
||||
}
|
||||
|
||||
template <class _>
|
||||
@@ -353,18 +331,20 @@ bucket_t<_>::erase (std::size_t i)
|
||||
{
|
||||
// Bucket Record
|
||||
auto const p = p_ +
|
||||
field<std::uint16_t>::size + // Count
|
||||
field<uint48_t>::size; // Spill
|
||||
field<
|
||||
std::uint16_t>::size + // Count
|
||||
field<uint48_t>::size; // Spill
|
||||
auto const w =
|
||||
field<uint48_t>::size + // Offset
|
||||
field<uint48_t>::size + // Size
|
||||
key_size_; // Key
|
||||
--count_;
|
||||
if (i != count_)
|
||||
field<uint48_t>::size + // Offset
|
||||
field<uint48_t>::size + // Size
|
||||
field<hash_t>::size; // Hash
|
||||
--size_;
|
||||
if (i < size_)
|
||||
std::memmove(
|
||||
p + i * w,
|
||||
p + (i + 1) * w,
|
||||
(count_ - i) * w);
|
||||
p + i * w,
|
||||
p + (i + 1) * w,
|
||||
(size_ - i) * w);
|
||||
std::memset(p + size_ * w, 0, w);
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -374,17 +354,15 @@ void
|
||||
bucket_t<_>::read (File& f, std::size_t offset)
|
||||
{
|
||||
auto const cap = bucket_capacity (
|
||||
key_size_, block_size_);
|
||||
block_size_);
|
||||
// Excludes padding to block size
|
||||
f.read (offset, p_, bucket_size(
|
||||
key_size_, bucket_capacity(
|
||||
key_size_, block_size_)));
|
||||
f.read (offset, p_, bucket_size(cap));
|
||||
istream is(p_, block_size_);
|
||||
detail::read<
|
||||
std::uint16_t>(is, count_); // Count
|
||||
std::uint16_t>(is, size_); // Count
|
||||
detail::read<
|
||||
uint48_t>(is, spill_); // Spill
|
||||
if (count_ > cap)
|
||||
if (size_ > cap)
|
||||
throw store_corrupt_error(
|
||||
"bad bucket size");
|
||||
}
|
||||
@@ -399,19 +377,21 @@ bucket_t<_>::read (bulk_reader<File>& r)
|
||||
detail::field<std::uint16_t>::size +
|
||||
detail::field<uint48_t>::size);
|
||||
detail::read<
|
||||
std::uint16_t>(is, count_); // Count
|
||||
detail::read<uint48_t>(is, spill_); // Spill
|
||||
std::uint16_t>(is, size_); // Count
|
||||
detail::read<uint48_t>(
|
||||
is, spill_); // Spill
|
||||
update();
|
||||
// Excludes empty bucket entries
|
||||
auto const w = count_ * (
|
||||
field<uint48_t>::size + // Offset
|
||||
field<uint48_t>::size + // Size
|
||||
key_size_); // Key
|
||||
auto const w = size_ * (
|
||||
field<uint48_t>::size + // Offset
|
||||
field<uint48_t>::size + // Size
|
||||
field<hash_t>::size); // Hash
|
||||
is = r.prepare (w);
|
||||
std::memcpy(p_ +
|
||||
field<std::uint16_t>::size + // Count
|
||||
field<uint48_t>::size, // Spill
|
||||
is.data(w), w); // Entries
|
||||
field<
|
||||
std::uint16_t>::size + // Count
|
||||
field<uint48_t>::size, // Spill
|
||||
is.data(w), w); // Entries
|
||||
}
|
||||
|
||||
template <class _>
|
||||
@@ -447,56 +427,40 @@ bucket_t<_>::update()
|
||||
// Bucket Record
|
||||
ostream os(p_, block_size_);
|
||||
detail::write<
|
||||
std::uint16_t>(os, count_); // Count
|
||||
std::uint16_t>(os, size_); // Count
|
||||
detail::write<
|
||||
uint48_t>(os, spill_); // Spill
|
||||
}
|
||||
|
||||
// bool is true if key matches index
|
||||
template <class _>
|
||||
std::pair<std::size_t, bool>
|
||||
bucket_t<_>::lower_bound (
|
||||
void const* key) const
|
||||
{
|
||||
// Bucket Entry
|
||||
auto const w =
|
||||
field<uint48_t>::size + // Offset
|
||||
field<uint48_t>::size + // Size
|
||||
key_size_; // Key
|
||||
// Bucket Record
|
||||
auto const p = p_ +
|
||||
field<std::uint16_t>::size + // Count
|
||||
field<uint48_t>::size + // Spill
|
||||
// Bucket Entry
|
||||
field<uint48_t>::size + // Offset
|
||||
field<uint48_t>::size; // Size
|
||||
std::size_t step;
|
||||
std::size_t first = 0;
|
||||
std::size_t count = count_;
|
||||
while (count > 0)
|
||||
{
|
||||
step = count / 2;
|
||||
auto const i = first + step;
|
||||
auto const c = std::memcmp (
|
||||
p + i * w, key, key_size_);
|
||||
if (c < 0)
|
||||
{
|
||||
first = i + 1;
|
||||
count -= step + 1;
|
||||
}
|
||||
else if (c > 0)
|
||||
{
|
||||
count = step;
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::make_pair (i, true);
|
||||
}
|
||||
}
|
||||
return std::make_pair (first, false);
|
||||
}
|
||||
using bucket = bucket_t<>;
|
||||
|
||||
// Spill bucket if full.
|
||||
// The bucket is cleared after it spills.
|
||||
//
|
||||
template <class File>
|
||||
void
|
||||
maybe_spill(bucket& b, bulk_writer<File>& w)
|
||||
{
|
||||
if (b.full())
|
||||
{
|
||||
// Spill Record
|
||||
auto const offset = w.offset();
|
||||
auto os = w.prepare(
|
||||
field<uint48_t>::size + // Zero
|
||||
field<uint16_t>::size + // Size
|
||||
b.compact_size());
|
||||
write <uint48_t> (os, 0); // Zero
|
||||
write <std::uint16_t> (
|
||||
os, b.compact_size()); // Size
|
||||
auto const spill =
|
||||
offset + os.size();
|
||||
b.write (os); // Bucket
|
||||
// Update bucket
|
||||
b.clear();
|
||||
b.spill (spill);
|
||||
}
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // nudb
|
||||
} // beast
|
||||
|
||||
99
src/beast/beast/nudb/detail/buffer.h
Normal file
@@ -0,0 +1,99 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2014, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_NUDB_DETAIL_BUFFER_H_INCLUDED
|
||||
#define BEAST_NUDB_DETAIL_BUFFER_H_INCLUDED
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
namespace beast {
|
||||
namespace nudb {
|
||||
namespace detail {
|
||||
|
||||
// Simple growable memory buffer
|
||||
class buffer
|
||||
{
|
||||
private:
|
||||
std::size_t size_ = 0;
|
||||
std::unique_ptr<std::uint8_t[]> buf_;
|
||||
|
||||
public:
|
||||
~buffer() = default;
|
||||
buffer() = default;
|
||||
buffer (buffer const&) = delete;
|
||||
buffer& operator= (buffer const&) = delete;
|
||||
|
||||
explicit
|
||||
buffer (std::size_t n)
|
||||
: size_ (n)
|
||||
, buf_ (new std::uint8_t[n])
|
||||
{
|
||||
}
|
||||
|
||||
buffer (buffer&& other)
|
||||
: size_ (other.size_)
|
||||
, buf_ (std::move(other.buf_))
|
||||
{
|
||||
other.size_ = 0;
|
||||
}
|
||||
|
||||
buffer& operator= (buffer&& other)
|
||||
{
|
||||
size_ = other.size_;
|
||||
buf_ = std::move(other.buf_);
|
||||
other.size_ = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
size() const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
std::uint8_t*
|
||||
get() const
|
||||
{
|
||||
return buf_.get();
|
||||
}
|
||||
|
||||
void
|
||||
reserve (std::size_t n)
|
||||
{
|
||||
if (size_ < n)
|
||||
buf_.reset (new std::uint8_t[n]);
|
||||
size_ = n;
|
||||
}
|
||||
|
||||
// BufferFactory
|
||||
void*
|
||||
operator() (std::size_t n)
|
||||
{
|
||||
reserve(n);
|
||||
return buf_.get();
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // nudb
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -1,147 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2014, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_NUDB_BUFFERS_H_INCLUDED
|
||||
#define BEAST_NUDB_BUFFERS_H_INCLUDED
|
||||
|
||||
#include <beast/nudb/detail/config.h>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <new>
|
||||
|
||||
namespace beast {
|
||||
namespace nudb {
|
||||
namespace detail {
|
||||
|
||||
// Thread safe pool of temp buffers,
|
||||
// to avoid needless calls to malloc.
|
||||
template <class = void>
|
||||
class buffers_t
|
||||
{
|
||||
private:
|
||||
struct element
|
||||
{
|
||||
element* next;
|
||||
};
|
||||
|
||||
std::size_t const block_size_;
|
||||
std::mutex m_;
|
||||
element* h_ = nullptr;
|
||||
|
||||
public:
|
||||
class value_type
|
||||
{
|
||||
private:
|
||||
buffers_t& b_;
|
||||
element* e_;
|
||||
|
||||
public:
|
||||
value_type (value_type const&) = delete;
|
||||
value_type& operator= (value_type const&) = delete;
|
||||
|
||||
explicit
|
||||
value_type (buffers_t& b)
|
||||
: b_ (b)
|
||||
, e_ (b.acquire())
|
||||
{
|
||||
}
|
||||
|
||||
~value_type()
|
||||
{
|
||||
b_.release(e_);
|
||||
}
|
||||
|
||||
std::uint8_t*
|
||||
get() const
|
||||
{
|
||||
return const_cast <std::uint8_t*>(
|
||||
reinterpret_cast<
|
||||
std::uint8_t const*>(e_ + 1));
|
||||
}
|
||||
};
|
||||
|
||||
explicit
|
||||
buffers_t (std::size_t block_size);
|
||||
|
||||
~buffers_t();
|
||||
|
||||
private:
|
||||
element*
|
||||
acquire();
|
||||
|
||||
void
|
||||
release (element* e);
|
||||
};
|
||||
|
||||
template <class _>
|
||||
buffers_t<_>::buffers_t (std::size_t block_size)
|
||||
: block_size_ (block_size)
|
||||
, h_ (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
template <class _>
|
||||
buffers_t<_>::~buffers_t()
|
||||
{
|
||||
for (element* e = h_; e;)
|
||||
{
|
||||
element* const next = e->next;
|
||||
e->~element();
|
||||
delete[] reinterpret_cast<
|
||||
std::uint8_t*>(e);
|
||||
e = next;
|
||||
}
|
||||
}
|
||||
|
||||
template <class _>
|
||||
auto
|
||||
buffers_t<_>::acquire() ->
|
||||
element*
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> m(m_);
|
||||
element* e = h_;
|
||||
if (e)
|
||||
{
|
||||
h_ = e->next;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return ::new(
|
||||
new std::uint8_t[
|
||||
sizeof(element) + block_size_]
|
||||
) element;
|
||||
}
|
||||
|
||||
template <class _>
|
||||
void
|
||||
buffers_t<_>::release (element* e)
|
||||
{
|
||||
std::lock_guard<std::mutex> m(m_);
|
||||
e->next = h_;
|
||||
h_ = e;
|
||||
}
|
||||
|
||||
using buffers = buffers_t<>;
|
||||
|
||||
} // detail
|
||||
} // nudb
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -20,7 +20,7 @@
|
||||
#ifndef BEAST_NUDB_BULKIO_H_INCLUDED
|
||||
#define BEAST_NUDB_BULKIO_H_INCLUDED
|
||||
|
||||
#include <beast/nudb/detail/config.h>
|
||||
#include <beast/nudb/detail/buffer.h>
|
||||
#include <beast/nudb/detail/stream.h>
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
@@ -45,10 +45,16 @@ public:
|
||||
bulk_reader (File& f, std::size_t offset,
|
||||
std::size_t last, std::size_t buffer_size);
|
||||
|
||||
std::size_t
|
||||
offset() const
|
||||
{
|
||||
return offset_ - avail_;
|
||||
}
|
||||
|
||||
bool
|
||||
eof() const
|
||||
{
|
||||
return offset_ - avail_ == last_;
|
||||
return offset() >= last_;
|
||||
}
|
||||
|
||||
istream
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
#include <beast/nudb/detail/arena.h>
|
||||
#include <beast/nudb/detail/bucket.h>
|
||||
#include <beast/nudb/detail/config.h>
|
||||
#include <boost/iterator/transform_iterator.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
@@ -77,8 +76,8 @@ private:
|
||||
operator() (argument_type const& e) const
|
||||
{
|
||||
return std::make_pair(e.first,
|
||||
bucket (cache_->key_size_,
|
||||
cache_->block_size_, e.second));
|
||||
bucket (cache_->block_size_,
|
||||
e.second));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -209,7 +208,7 @@ cache_t<_>::create (std::size_t n)
|
||||
{
|
||||
auto const p = arena_.alloc (block_size_);
|
||||
map_.emplace (n, p);
|
||||
return bucket (key_size_, block_size_,
|
||||
return bucket (block_size_,
|
||||
p, detail::empty);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#ifndef BEAST_NUDB_FIELD_H_INCLUDED
|
||||
#define BEAST_NUDB_FIELD_H_INCLUDED
|
||||
|
||||
#include <beast/nudb/detail/config.h>
|
||||
#include <beast/nudb/detail/stream.h>
|
||||
#include <beast/config/CompilerConfig.h> // for BEAST_CONSTEXPR
|
||||
#include <cstddef>
|
||||
@@ -85,16 +84,26 @@ struct field <std::uint64_t>
|
||||
static std::size_t BEAST_CONSTEXPR max = 0xffffffffffffffff;
|
||||
};
|
||||
|
||||
// read field from istream
|
||||
// read field from memory
|
||||
|
||||
template <class T, class U, std::enable_if_t<
|
||||
std::is_same<T, std::uint8_t>::value>* = nullptr>
|
||||
void
|
||||
readp (void const* v, U& u)
|
||||
{
|
||||
std::uint8_t const* p =
|
||||
reinterpret_cast<std::uint8_t const*>(v);
|
||||
u = *p;
|
||||
}
|
||||
|
||||
template <class T, class U, std::enable_if_t<
|
||||
std::is_same<T, std::uint16_t>::value>* = nullptr>
|
||||
void
|
||||
read (istream& is, U& u)
|
||||
readp (void const* v, U& u)
|
||||
{
|
||||
T t;
|
||||
std::uint8_t const* p =
|
||||
is.data(field<T>::size);
|
||||
reinterpret_cast<std::uint8_t const*>(v);
|
||||
T t;
|
||||
t = T(*p++)<< 8;
|
||||
t = T(*p ) | t;
|
||||
u = t;
|
||||
@@ -103,25 +112,25 @@ read (istream& is, U& u)
|
||||
template <class T, class U, std::enable_if_t<
|
||||
std::is_same<T, uint24_t>::value>* = nullptr>
|
||||
void
|
||||
read (istream& is, U& u)
|
||||
readp (void const* v, U& u)
|
||||
{
|
||||
T t;
|
||||
std::uint8_t const* p =
|
||||
is.data(field<T>::size);
|
||||
t = (T(*p++)<<16) | t;
|
||||
t = (T(*p++)<< 8) | t;
|
||||
t = T(*p ) | t;
|
||||
reinterpret_cast<std::uint8_t const*>(v);
|
||||
std::uint32_t t;
|
||||
t = std::uint32_t(*p++)<<16;
|
||||
t = (std::uint32_t(*p++)<< 8) | t;
|
||||
t = std::uint32_t(*p ) | t;
|
||||
u = t;
|
||||
}
|
||||
|
||||
template <class T, class U, std::enable_if_t<
|
||||
std::is_same<T, std::uint32_t>::value>* = nullptr>
|
||||
void
|
||||
read (istream& is, U& u)
|
||||
readp (void const* v, U& u)
|
||||
{
|
||||
T t;
|
||||
std::uint8_t const* p =
|
||||
is.data(field<T>::size);
|
||||
reinterpret_cast<std::uint8_t const*>(v);
|
||||
T t;
|
||||
t = T(*p++)<<24;
|
||||
t = (T(*p++)<<16) | t;
|
||||
t = (T(*p++)<< 8) | t;
|
||||
@@ -132,11 +141,11 @@ read (istream& is, U& u)
|
||||
template <class T, class U, std::enable_if_t<
|
||||
std::is_same<T, uint48_t>::value>* = nullptr>
|
||||
void
|
||||
read (istream& is, U& u)
|
||||
readp (void const* v, U& u)
|
||||
{
|
||||
std::uint64_t t;
|
||||
std::uint8_t const* p =
|
||||
is.data(field<T>::size);
|
||||
reinterpret_cast<std::uint8_t const*>(v);
|
||||
std::uint64_t t;
|
||||
t = (std::uint64_t(*p++)<<40);
|
||||
t = (std::uint64_t(*p++)<<32) | t;
|
||||
t = (std::uint64_t(*p++)<<24) | t;
|
||||
@@ -149,11 +158,11 @@ read (istream& is, U& u)
|
||||
template <class T, class U, std::enable_if_t<
|
||||
std::is_same<T, std::uint64_t>::value>* = nullptr>
|
||||
void
|
||||
read (istream& is, U& u)
|
||||
readp (void const* v, U& u)
|
||||
{
|
||||
T t;
|
||||
std::uint8_t const* p =
|
||||
is.data(field<T>::size);
|
||||
reinterpret_cast<std::uint8_t const*>(v);
|
||||
T t;
|
||||
t = T(*p++)<<56;
|
||||
t = (T(*p++)<<48) | t;
|
||||
t = (T(*p++)<<40) | t;
|
||||
@@ -165,18 +174,32 @@ read (istream& is, U& u)
|
||||
u = t;
|
||||
}
|
||||
|
||||
// read field from istream
|
||||
|
||||
template <class T, class U>
|
||||
void
|
||||
read (istream& is, U& u)
|
||||
{
|
||||
readp<T>(is.data(field<T>::size), u);
|
||||
}
|
||||
|
||||
// write field to ostream
|
||||
|
||||
template <class T, class U, std::enable_if_t<
|
||||
std::is_same<T, std::uint8_t>::value>* = nullptr>
|
||||
void
|
||||
write (ostream& os, U const& u)
|
||||
{
|
||||
std::uint8_t* p =
|
||||
os.data(field<T>::size);
|
||||
*p = u;
|
||||
}
|
||||
|
||||
template <class T, class U, std::enable_if_t<
|
||||
std::is_same<T, std::uint16_t>::value>* = nullptr>
|
||||
void
|
||||
write (ostream& os, U const& u)
|
||||
{
|
||||
#ifndef BEAST_NUDB_NO_DOMAIN_CHECK
|
||||
if (u > field<T>::max)
|
||||
throw std::logic_error(
|
||||
"nudb: field max exceeded");
|
||||
#endif
|
||||
T t = u;
|
||||
std::uint8_t* p =
|
||||
os.data(field<T>::size);
|
||||
@@ -184,16 +207,11 @@ write (ostream& os, U const& u)
|
||||
*p = t &0xff;
|
||||
}
|
||||
|
||||
template <class T, class U,std::enable_if_t<
|
||||
template <class T, class U, std::enable_if_t<
|
||||
std::is_same<T, uint24_t>::value>* = nullptr>
|
||||
void
|
||||
write (ostream& os, U const& u)
|
||||
{
|
||||
#ifndef BEAST_NUDB_NO_DOMAIN_CHECK
|
||||
if (u > field<T>::max)
|
||||
throw std::logic_error(
|
||||
"nudb: field max exceeded");
|
||||
#endif
|
||||
T t = u;
|
||||
std::uint8_t* p =
|
||||
os.data(field<T>::size);
|
||||
@@ -202,16 +220,11 @@ write (ostream& os, U const& u)
|
||||
*p = t &0xff;
|
||||
}
|
||||
|
||||
template <class T, class U,std::enable_if_t<
|
||||
template <class T, class U, std::enable_if_t<
|
||||
std::is_same<T, std::uint32_t>::value>* = nullptr>
|
||||
void
|
||||
write (ostream& os, U const& u)
|
||||
{
|
||||
#ifndef BEAST_NUDB_NO_DOMAIN_CHECK
|
||||
if (u > field<T>::max)
|
||||
throw std::logic_error(
|
||||
"nudb: field max exceeded");
|
||||
#endif
|
||||
T t = u;
|
||||
std::uint8_t* p =
|
||||
os.data(field<T>::size);
|
||||
@@ -221,16 +234,11 @@ write (ostream& os, U const& u)
|
||||
*p = t &0xff;
|
||||
}
|
||||
|
||||
template <class T, class U,std::enable_if_t<
|
||||
template <class T, class U, std::enable_if_t<
|
||||
std::is_same<T, uint48_t>::value>* = nullptr>
|
||||
void
|
||||
write (ostream& os, U const& u)
|
||||
{
|
||||
#ifndef BEAST_NUDB_NO_DOMAIN_CHECK
|
||||
if (u > field<T>::max)
|
||||
throw std::logic_error(
|
||||
"nudb: field max exceeded");
|
||||
#endif
|
||||
std::uint64_t const t = u;
|
||||
std::uint8_t* p =
|
||||
os.data(field<T>::size);
|
||||
@@ -242,16 +250,11 @@ write (ostream& os, U const& u)
|
||||
*p = t &0xff;
|
||||
}
|
||||
|
||||
template <class T, class U,std::enable_if_t<
|
||||
template <class T, class U, std::enable_if_t<
|
||||
std::is_same<T, std::uint64_t>::value>* = nullptr>
|
||||
void
|
||||
write (ostream& os, U const& u)
|
||||
{
|
||||
#ifndef BEAST_NUDB_NO_DOMAIN_CHECK
|
||||
if (u > field<T>::max)
|
||||
throw std::logic_error(
|
||||
"nudb: field max exceeded");
|
||||
#endif
|
||||
T t = u;
|
||||
std::uint8_t* p =
|
||||
os.data(field<T>::size);
|
||||
|
||||
@@ -20,7 +20,8 @@
|
||||
#ifndef BEAST_NUDB_FORMAT_H_INCLUDED
|
||||
#define BEAST_NUDB_FORMAT_H_INCLUDED
|
||||
|
||||
#include <beast/nudb/error.h>
|
||||
#include <beast/nudb/common.h>
|
||||
#include <beast/nudb/detail/buffer.h>
|
||||
#include <beast/nudb/detail/field.h>
|
||||
#include <beast/nudb/detail/stream.h>
|
||||
#include <beast/config/CompilerConfig.h> // for BEAST_CONSTEXPR
|
||||
@@ -38,22 +39,23 @@ namespace detail {
|
||||
|
||||
// Format of the nudb files:
|
||||
|
||||
static std::size_t BEAST_CONSTEXPR currentVersion = 1;
|
||||
static std::size_t BEAST_CONSTEXPR currentVersion = 2;
|
||||
|
||||
struct dat_file_header
|
||||
{
|
||||
static std::size_t BEAST_CONSTEXPR size =
|
||||
8 + // Type
|
||||
2 + // Version
|
||||
8 + // UID
|
||||
8 + // Appnum
|
||||
8 + // Salt
|
||||
2 + // KeySize
|
||||
|
||||
64; // (Reserved)
|
||||
|
||||
char type[8];
|
||||
std::size_t version;
|
||||
std::uint64_t uid;
|
||||
std::uint64_t appnum;
|
||||
std::uint64_t salt;
|
||||
std::size_t key_size;
|
||||
};
|
||||
|
||||
@@ -62,20 +64,25 @@ struct key_file_header
|
||||
static std::size_t BEAST_CONSTEXPR size =
|
||||
8 + // Type
|
||||
2 + // Version
|
||||
8 + // UID
|
||||
8 + // Appnum
|
||||
2 + // KeySize
|
||||
|
||||
8 + // Salt
|
||||
8 + // Pepper
|
||||
2 + // KeySize
|
||||
2 + // BlockSize
|
||||
2 + // LoadFactor
|
||||
64; // (Reserved)
|
||||
|
||||
56; // (Reserved)
|
||||
|
||||
char type[8];
|
||||
std::size_t version;
|
||||
std::uint64_t uid;
|
||||
std::uint64_t appnum;
|
||||
std::size_t key_size;
|
||||
|
||||
std::uint64_t salt;
|
||||
std::uint64_t pepper;
|
||||
std::size_t key_size;
|
||||
std::size_t block_size;
|
||||
std::size_t load_factor;
|
||||
|
||||
@@ -91,23 +98,65 @@ struct log_file_header
|
||||
static std::size_t BEAST_CONSTEXPR size =
|
||||
8 + // Type
|
||||
2 + // Version
|
||||
8 + // UID
|
||||
8 + // Appnum
|
||||
2 + // KeySize
|
||||
|
||||
8 + // Salt
|
||||
8 + // Pepper
|
||||
2 + // KeySize
|
||||
2 + // BlockSize
|
||||
|
||||
8 + // KeyFileSize
|
||||
8; // DataFileSize
|
||||
|
||||
char type[8];
|
||||
std::size_t version;
|
||||
std::uint64_t uid;
|
||||
std::uint64_t appnum;
|
||||
std::size_t key_size;
|
||||
std::uint64_t salt;
|
||||
std::uint64_t pepper;
|
||||
std::size_t key_size;
|
||||
std::size_t block_size;
|
||||
std::size_t key_file_size;
|
||||
std::size_t dat_file_size;
|
||||
};
|
||||
|
||||
// Type used to store hashes in buckets.
|
||||
// This can be smaller than the output
|
||||
// of the hash function.
|
||||
//
|
||||
using hash_t = uint48_t;
|
||||
|
||||
static_assert(field<hash_t>::size <=
|
||||
sizeof(std::size_t), "");
|
||||
|
||||
template <class T>
|
||||
std::size_t
|
||||
make_hash (std::size_t h);
|
||||
|
||||
template<>
|
||||
inline
|
||||
std::size_t
|
||||
make_hash<uint48_t>(std::size_t h)
|
||||
{
|
||||
return (h>>16)&0xffffffffffff;
|
||||
}
|
||||
|
||||
// Returns the hash of a key given the salt.
|
||||
// Note: The hash is expressed in hash_t units
|
||||
//
|
||||
template <class Hasher>
|
||||
inline
|
||||
std::size_t
|
||||
hash (void const* key,
|
||||
std::size_t key_size, std::size_t salt)
|
||||
{
|
||||
Hasher h (salt);
|
||||
h.append (key, key_size);
|
||||
return make_hash<hash_t>(static_cast<
|
||||
typename Hasher::result_type>(h));
|
||||
}
|
||||
|
||||
// Computes pepper from salt
|
||||
//
|
||||
template <class Hasher>
|
||||
@@ -124,8 +173,7 @@ pepper (std::size_t salt)
|
||||
//
|
||||
template <class = void>
|
||||
std::size_t
|
||||
bucket_size (std::size_t key_size,
|
||||
std::size_t capacity)
|
||||
bucket_size (std::size_t capacity)
|
||||
{
|
||||
// Bucket Record
|
||||
return
|
||||
@@ -134,33 +182,14 @@ bucket_size (std::size_t key_size,
|
||||
capacity * (
|
||||
field<uint48_t>::size + // Offset
|
||||
field<uint48_t>::size + // Size
|
||||
key_size); // Key
|
||||
field<hash_t>::size); // Hash
|
||||
}
|
||||
|
||||
// Returns the size of a bucket large enough to
|
||||
// hold size keys of length key_size.
|
||||
//
|
||||
inline
|
||||
std::size_t
|
||||
compact_size(std::size_t key_size,
|
||||
std::size_t size)
|
||||
{
|
||||
// Bucket Record
|
||||
return
|
||||
field<std::uint16_t>::size + // Size
|
||||
field<uint48_t>::size + // Spill
|
||||
size * (
|
||||
field<uint48_t>::size + // Offset
|
||||
field<uint48_t>::size + // Size
|
||||
key_size); // Key
|
||||
}
|
||||
|
||||
// Returns: number of keys that fit in a bucket
|
||||
// Returns the number of entries that fit in a bucket
|
||||
//
|
||||
template <class = void>
|
||||
std::size_t
|
||||
bucket_capacity (std::size_t key_size,
|
||||
std::size_t block_size)
|
||||
bucket_capacity (std::size_t block_size)
|
||||
{
|
||||
// Bucket Record
|
||||
auto const size =
|
||||
@@ -169,17 +198,18 @@ bucket_capacity (std::size_t key_size,
|
||||
auto const entry_size =
|
||||
field<uint48_t>::size + // Offset
|
||||
field<uint48_t>::size + // Size
|
||||
key_size; // Key
|
||||
field<hash_t>::size; // Hash
|
||||
if (block_size < key_file_header::size ||
|
||||
block_size < size)
|
||||
return 0;
|
||||
return (block_size - size) / entry_size;
|
||||
}
|
||||
|
||||
// returns the number of bytes occupied by a value record
|
||||
// Returns the number of bytes occupied by a value record
|
||||
inline
|
||||
std::size_t
|
||||
data_size (std::size_t size, std::size_t key_size)
|
||||
value_size (std::size_t size,
|
||||
std::size_t key_size)
|
||||
{
|
||||
// Data Record
|
||||
return
|
||||
@@ -188,6 +218,34 @@ data_size (std::size_t size, std::size_t key_size)
|
||||
size; // Data
|
||||
}
|
||||
|
||||
// Returns the closest power of 2 not less than x
|
||||
template <class = void>
|
||||
std::size_t
|
||||
ceil_pow2 (unsigned long long x)
|
||||
{
|
||||
static const unsigned long long t[6] = {
|
||||
0xFFFFFFFF00000000ull,
|
||||
0x00000000FFFF0000ull,
|
||||
0x000000000000FF00ull,
|
||||
0x00000000000000F0ull,
|
||||
0x000000000000000Cull,
|
||||
0x0000000000000002ull
|
||||
};
|
||||
|
||||
int y = (((x & (x - 1)) == 0) ? 0 : 1);
|
||||
int j = 32;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < 6; i++) {
|
||||
int k = (((x & t[i]) == 0) ? 0 : j);
|
||||
y += k;
|
||||
x >>= k;
|
||||
j >>= 1;
|
||||
}
|
||||
|
||||
return std::size_t(1)<<y;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Read data file header from stream
|
||||
@@ -197,11 +255,12 @@ read (istream& is, dat_file_header& dh)
|
||||
{
|
||||
read (is, dh.type, sizeof(dh.type));
|
||||
read<std::uint16_t>(is, dh.version);
|
||||
read<std::uint64_t>(is, dh.uid);
|
||||
read<std::uint64_t>(is, dh.appnum);
|
||||
read<std::uint64_t>(is, dh.salt);
|
||||
read<std::uint16_t>(is, dh.key_size);
|
||||
std::array <std::uint8_t, 64> zero;
|
||||
read (is, zero.data(), zero.size());
|
||||
std::array <std::uint8_t, 64> reserved;
|
||||
read (is,
|
||||
reserved.data(), reserved.size());
|
||||
}
|
||||
|
||||
// Read data file header from file
|
||||
@@ -231,12 +290,13 @@ write (ostream& os, dat_file_header const& dh)
|
||||
{
|
||||
write (os, "nudb.dat", 8);
|
||||
write<std::uint16_t>(os, dh.version);
|
||||
write<std::uint64_t>(os, dh.uid);
|
||||
write<std::uint64_t>(os, dh.appnum);
|
||||
write<std::uint64_t>(os, dh.salt);
|
||||
write<std::uint16_t>(os, dh.key_size);
|
||||
std::array <std::uint8_t, 64> zero;
|
||||
zero.fill(0);
|
||||
write (os, zero.data(), zero.size());
|
||||
std::array <std::uint8_t, 64> reserved;
|
||||
reserved.fill(0);
|
||||
write (os,
|
||||
reserved.data(), reserved.size());
|
||||
}
|
||||
|
||||
// Write data file header to file
|
||||
@@ -259,25 +319,26 @@ read (istream& is, std::size_t file_size,
|
||||
{
|
||||
read(is, kh.type, sizeof(kh.type));
|
||||
read<std::uint16_t>(is, kh.version);
|
||||
read<std::uint64_t>(is, kh.uid);
|
||||
read<std::uint64_t>(is, kh.appnum);
|
||||
read<std::uint16_t>(is, kh.key_size);
|
||||
read<std::uint64_t>(is, kh.salt);
|
||||
read<std::uint64_t>(is, kh.pepper);
|
||||
read<std::uint16_t>(is, kh.key_size);
|
||||
read<std::uint16_t>(is, kh.block_size);
|
||||
read<std::uint16_t>(is, kh.load_factor);
|
||||
std::array <std::uint8_t, 64> zero;
|
||||
read (is, zero.data(), zero.size());
|
||||
std::array <std::uint8_t, 56> reserved;
|
||||
read (is,
|
||||
reserved.data(), reserved.size());
|
||||
|
||||
// VFALCO These need to be checked to handle
|
||||
// when the file size is too small
|
||||
kh.capacity = bucket_capacity(
|
||||
kh.key_size, kh.block_size);
|
||||
kh.bucket_size = bucket_size(
|
||||
kh.key_size, kh.capacity);
|
||||
kh.capacity = bucket_capacity(kh.block_size);
|
||||
kh.bucket_size = bucket_size(kh.capacity);
|
||||
if (file_size > kh.block_size)
|
||||
{
|
||||
// VFALCO This should be handled elsewhere.
|
||||
// we shouldn't put the computed fields in this header.
|
||||
// we shouldn't put the computed fields
|
||||
// in this header.
|
||||
if (kh.block_size > 0)
|
||||
kh.buckets = (file_size - kh.bucket_size)
|
||||
/ kh.block_size;
|
||||
@@ -319,15 +380,17 @@ write (ostream& os, key_file_header const& kh)
|
||||
{
|
||||
write (os, "nudb.key", 8);
|
||||
write<std::uint16_t>(os, kh.version);
|
||||
write<std::uint64_t>(os, kh.uid);
|
||||
write<std::uint64_t>(os, kh.appnum);
|
||||
write<std::uint16_t>(os, kh.key_size);
|
||||
write<std::uint64_t>(os, kh.salt);
|
||||
write<std::uint64_t>(os, kh.pepper);
|
||||
write<std::uint16_t>(os, kh.key_size);
|
||||
write<std::uint16_t>(os, kh.block_size);
|
||||
write<std::uint16_t>(os, kh.load_factor);
|
||||
std::array <std::uint8_t, 64> zero;
|
||||
zero.fill (0);
|
||||
write (os, zero.data(), zero.size());
|
||||
std::array <std::uint8_t, 56> reserved;
|
||||
reserved.fill (0);
|
||||
write (os,
|
||||
reserved.data(), reserved.size());
|
||||
}
|
||||
|
||||
// Write key file header to file
|
||||
@@ -335,12 +398,12 @@ template <class File>
|
||||
void
|
||||
write (File& f, key_file_header const& kh)
|
||||
{
|
||||
buffer buf;
|
||||
buf.reserve (kh.block_size);
|
||||
if (kh.block_size < key_file_header::size)
|
||||
throw std::logic_error(
|
||||
"nudb: block size too small");
|
||||
std::fill(buf.get(), buf.get() + buf.size(), 0);
|
||||
buffer buf(kh.block_size);
|
||||
std::fill(buf.get(),
|
||||
buf.get() + buf.size(), 0);
|
||||
ostream os (buf.get(), buf.size());
|
||||
write (os, kh);
|
||||
f.write (0, buf.get(), buf.size());
|
||||
@@ -353,10 +416,12 @@ read (istream& is, log_file_header& lh)
|
||||
{
|
||||
read (is, lh.type, sizeof(lh.type));
|
||||
read<std::uint16_t>(is, lh.version);
|
||||
read<std::uint64_t>(is, lh.uid);
|
||||
read<std::uint64_t>(is, lh.appnum);
|
||||
read<std::uint16_t>(is, lh.key_size);
|
||||
read<std::uint64_t>(is, lh.salt);
|
||||
read<std::uint64_t>(is, lh.pepper);
|
||||
read<std::uint16_t>(is, lh.key_size);
|
||||
read<std::uint16_t>(is, lh.block_size);
|
||||
read<std::uint64_t>(is, lh.key_file_size);
|
||||
read<std::uint64_t>(is, lh.dat_file_size);
|
||||
}
|
||||
@@ -381,10 +446,12 @@ write (ostream& os, log_file_header const& lh)
|
||||
{
|
||||
write (os, "nudb.log", 8);
|
||||
write<std::uint16_t>(os, lh.version);
|
||||
write<std::uint64_t>(os, lh.uid);
|
||||
write<std::uint64_t>(os, lh.appnum);
|
||||
write<std::uint16_t>(os, lh.key_size);
|
||||
write<std::uint64_t>(os, lh.salt);
|
||||
write<std::uint64_t>(os, lh.pepper);
|
||||
write<std::uint16_t>(os, lh.key_size);
|
||||
write<std::uint16_t>(os, lh.block_size);
|
||||
write<std::uint64_t>(os, lh.key_file_size);
|
||||
write<std::uint64_t>(os, lh.dat_file_size);
|
||||
}
|
||||
@@ -401,34 +468,6 @@ write (File& f, log_file_header const& lh)
|
||||
f.write (0, buf.data(), buf.size());
|
||||
}
|
||||
|
||||
template <class Hasher>
|
||||
void
|
||||
verify (key_file_header const& kh)
|
||||
{
|
||||
std::string const type (kh.type, 8);
|
||||
if (type != "nudb.key")
|
||||
throw store_corrupt_error (
|
||||
"bad type in key file");
|
||||
if (kh.version != currentVersion)
|
||||
throw store_corrupt_error (
|
||||
"bad version in key file");
|
||||
if (kh.pepper != pepper<Hasher>(kh.salt))
|
||||
throw store_corrupt_error(
|
||||
"wrong hash function for key file");
|
||||
if (kh.key_size < 1)
|
||||
throw store_corrupt_error (
|
||||
"bad key size in key file");
|
||||
if (kh.load_factor < 1)
|
||||
throw store_corrupt_error (
|
||||
"bad load factor in key file");
|
||||
if (kh.capacity < 1)
|
||||
throw store_corrupt_error (
|
||||
"bad capacity in key file");
|
||||
if (kh.buckets < 1)
|
||||
throw store_corrupt_error (
|
||||
"bad key file size");
|
||||
}
|
||||
|
||||
template <class = void>
|
||||
void
|
||||
verify (dat_file_header const& dh)
|
||||
@@ -445,6 +484,34 @@ verify (dat_file_header const& dh)
|
||||
"bad key size in data file");
|
||||
}
|
||||
|
||||
template <class Hasher>
|
||||
void
|
||||
verify (key_file_header const& kh)
|
||||
{
|
||||
std::string const type (kh.type, 8);
|
||||
if (type != "nudb.key")
|
||||
throw store_corrupt_error (
|
||||
"bad type in key file");
|
||||
if (kh.version != currentVersion)
|
||||
throw store_corrupt_error (
|
||||
"bad version in key file");
|
||||
if (kh.key_size < 1)
|
||||
throw store_corrupt_error (
|
||||
"bad key size in key file");
|
||||
if (kh.pepper != pepper<Hasher>(kh.salt))
|
||||
throw store_corrupt_error(
|
||||
"wrong hash function for key file");
|
||||
if (kh.load_factor < 1)
|
||||
throw store_corrupt_error (
|
||||
"bad load factor in key file");
|
||||
if (kh.capacity < 1)
|
||||
throw store_corrupt_error (
|
||||
"bad capacity in key file");
|
||||
if (kh.buckets < 1)
|
||||
throw store_corrupt_error (
|
||||
"bad key file size");
|
||||
}
|
||||
|
||||
template <class Hasher>
|
||||
void
|
||||
verify (log_file_header const& lh)
|
||||
@@ -470,17 +537,16 @@ void
|
||||
verify (dat_file_header const& dh,
|
||||
key_file_header const& kh)
|
||||
{
|
||||
verify (dh);
|
||||
verify<Hasher> (kh);
|
||||
if (kh.salt != dh.salt)
|
||||
if (kh.uid != dh.uid)
|
||||
throw store_corrupt_error(
|
||||
"salt mismatch");
|
||||
if (kh.key_size != dh.key_size)
|
||||
throw store_corrupt_error(
|
||||
"key size mismatch");
|
||||
"uid mismatch");
|
||||
if (kh.appnum != dh.appnum)
|
||||
throw store_corrupt_error(
|
||||
"appnum mismatch");
|
||||
if (kh.key_size != dh.key_size)
|
||||
throw store_corrupt_error(
|
||||
"key size mismatch");
|
||||
}
|
||||
|
||||
template <class Hasher>
|
||||
@@ -489,15 +555,24 @@ verify (key_file_header const& kh,
|
||||
log_file_header const& lh)
|
||||
{
|
||||
verify<Hasher>(lh);
|
||||
if (kh.salt != lh.salt)
|
||||
if (kh.uid != lh.uid)
|
||||
throw store_corrupt_error (
|
||||
"salt mismatch in log file");
|
||||
"uid mismatch in log file");
|
||||
if (kh.appnum != lh.appnum)
|
||||
throw store_corrupt_error(
|
||||
"appnum mismatch in log file");
|
||||
if (kh.key_size != lh.key_size)
|
||||
throw store_corrupt_error (
|
||||
"key size mismatch in log file");
|
||||
if (kh.appnum != lh.appnum)
|
||||
throw store_corrupt_error(
|
||||
"appnum mismatch");
|
||||
if (kh.salt != lh.salt)
|
||||
throw store_corrupt_error (
|
||||
"salt mismatch in log file");
|
||||
if (kh.pepper != lh.pepper)
|
||||
throw store_corrupt_error (
|
||||
"pepper mismatch in log file");
|
||||
if (kh.block_size != lh.block_size)
|
||||
throw store_corrupt_error (
|
||||
"block size mismatch in log file");
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#ifndef BEAST_NUDB_GENTEX_H_INCLUDED
|
||||
#define BEAST_NUDB_GENTEX_H_INCLUDED
|
||||
|
||||
#include <beast/nudb/detail/config.h>
|
||||
#include <beast/utility/noexcept.h>
|
||||
#include <condition_variable>
|
||||
#include <cstddef>
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
#include <beast/nudb/detail/arena.h>
|
||||
#include <beast/nudb/detail/bucket.h>
|
||||
#include <beast/nudb/detail/config.h>
|
||||
#include <beast/nudb/detail/format.h>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
@@ -20,8 +20,7 @@
|
||||
#ifndef BEAST_NUDB_STREAM_H_INCLUDED
|
||||
#define BEAST_NUDB_STREAM_H_INCLUDED
|
||||
|
||||
#include <beast/nudb/error.h>
|
||||
#include <beast/nudb/detail/config.h>
|
||||
#include <beast/nudb/common.h>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
@@ -32,114 +31,54 @@ namespace beast {
|
||||
namespace nudb {
|
||||
namespace detail {
|
||||
|
||||
// Simple growable memory buffer
|
||||
class buffer
|
||||
{
|
||||
private:
|
||||
std::size_t size_ = 0;
|
||||
std::unique_ptr<std::uint8_t[]> buf_;
|
||||
|
||||
public:
|
||||
buffer() = default;
|
||||
buffer (buffer const&) = delete;
|
||||
buffer& operator= (buffer const&) = delete;
|
||||
|
||||
explicit
|
||||
buffer (std::size_t n)
|
||||
: size_ (n)
|
||||
, buf_ (new std::uint8_t[n])
|
||||
{
|
||||
}
|
||||
|
||||
buffer (buffer&& other)
|
||||
: size_ (other.size_)
|
||||
, buf_ (std::move(other.buf_))
|
||||
{
|
||||
other.size_ = 0;
|
||||
}
|
||||
|
||||
buffer& operator= (buffer&& other)
|
||||
{
|
||||
size_ = other.size_;
|
||||
buf_ = std::move(other.buf_);
|
||||
other.size_ = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
size() const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
std::uint8_t*
|
||||
get() const
|
||||
{
|
||||
return buf_.get();
|
||||
}
|
||||
|
||||
void
|
||||
reserve (std::size_t n)
|
||||
{
|
||||
if (size_ < n)
|
||||
buf_.reset (new std::uint8_t[n]);
|
||||
size_ = n;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Input stream from bytes
|
||||
template <class = void>
|
||||
class istream_t
|
||||
{
|
||||
private:
|
||||
std::uint8_t const* buf_;
|
||||
#if ! BEAST_NUDB_NO_DOMAIN_CHECK
|
||||
std::size_t bytes_;
|
||||
#endif
|
||||
std::size_t size_ = 0;
|
||||
|
||||
public:
|
||||
istream_t (istream_t const&) = default;
|
||||
istream_t& operator= (istream_t const&) = default;
|
||||
|
||||
istream_t (void const* data, std::size_t
|
||||
#if ! BEAST_NUDB_NO_DOMAIN_CHECK
|
||||
bytes
|
||||
#endif
|
||||
)
|
||||
istream_t (void const* data, std::size_t size)
|
||||
: buf_(reinterpret_cast<
|
||||
std::uint8_t const*>(data))
|
||||
#if ! BEAST_NUDB_NO_DOMAIN_CHECK
|
||||
, bytes_(bytes)
|
||||
#endif
|
||||
, size_(size)
|
||||
{
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
istream_t (std::array<std::uint8_t, N> const& a)
|
||||
: buf_ (a.data())
|
||||
#if ! BEAST_NUDB_NO_DOMAIN_CHECK
|
||||
, bytes_ (a.size())
|
||||
#endif
|
||||
, size_ (a.size())
|
||||
{
|
||||
}
|
||||
|
||||
std::uint8_t const*
|
||||
data (std::size_t bytes)
|
||||
data (std::size_t bytes);
|
||||
|
||||
std::uint8_t const*
|
||||
operator()(std::size_t bytes)
|
||||
{
|
||||
#if ! BEAST_NUDB_NO_DOMAIN_CHECK
|
||||
if (bytes > bytes_)
|
||||
throw std::logic_error(
|
||||
"nudb: istream");
|
||||
bytes_ -= bytes;
|
||||
#endif
|
||||
auto const data = buf_;
|
||||
buf_ = buf_ + bytes;
|
||||
return data;
|
||||
return data(bytes);
|
||||
}
|
||||
};
|
||||
|
||||
template <class _>
|
||||
std::uint8_t const*
|
||||
istream_t<_>::data (std::size_t bytes)
|
||||
{
|
||||
if (size_ < bytes)
|
||||
throw short_read_error();
|
||||
auto const data = buf_;
|
||||
buf_ = buf_ + bytes;
|
||||
size_ -= bytes;
|
||||
return data;
|
||||
}
|
||||
|
||||
using istream = istream_t<>;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -151,32 +90,19 @@ class ostream_t
|
||||
private:
|
||||
std::uint8_t* buf_;
|
||||
std::size_t size_ = 0;
|
||||
#if ! BEAST_NUDB_NO_DOMAIN_CHECK
|
||||
std::size_t bytes_;
|
||||
#endif
|
||||
|
||||
public:
|
||||
ostream_t (ostream_t const&) = default;
|
||||
ostream_t& operator= (ostream_t const&) = default;
|
||||
|
||||
ostream_t (void* data, std::size_t
|
||||
#if ! BEAST_NUDB_NO_DOMAIN_CHECK
|
||||
bytes
|
||||
#endif
|
||||
)
|
||||
ostream_t (void* data, std::size_t)
|
||||
: buf_ (reinterpret_cast<std::uint8_t*>(data))
|
||||
#if ! BEAST_NUDB_NO_DOMAIN_CHECK
|
||||
, bytes_ (bytes)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
ostream_t (std::array<std::uint8_t, N>& a)
|
||||
: buf_ (a.data())
|
||||
#if ! BEAST_NUDB_NO_DOMAIN_CHECK
|
||||
, bytes_ (a.size())
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
@@ -188,21 +114,25 @@ public:
|
||||
}
|
||||
|
||||
std::uint8_t*
|
||||
data (std::size_t bytes)
|
||||
data (std::size_t bytes);
|
||||
|
||||
std::uint8_t*
|
||||
operator()(std::size_t bytes)
|
||||
{
|
||||
#if ! BEAST_NUDB_NO_DOMAIN_CHECK
|
||||
if (bytes > bytes_)
|
||||
throw std::logic_error(
|
||||
"nudb: ostream");
|
||||
bytes_ -= bytes;
|
||||
#endif
|
||||
auto const data = buf_;
|
||||
buf_ = buf_ + bytes;
|
||||
size_ += bytes;
|
||||
return data;
|
||||
return data(bytes);
|
||||
}
|
||||
};
|
||||
|
||||
template <class _>
|
||||
std::uint8_t*
|
||||
ostream_t<_>::data (std::size_t bytes)
|
||||
{
|
||||
auto const data = buf_;
|
||||
buf_ = buf_ + bytes;
|
||||
size_ += bytes;
|
||||
return data;
|
||||
}
|
||||
|
||||
using ostream = ostream_t<>;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
155
src/beast/beast/nudb/detail/varint.h
Normal file
@@ -0,0 +1,155 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2014, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_NUDB_VARINT_H_INCLUDED
|
||||
#define BEAST_NUDB_VARINT_H_INCLUDED
|
||||
|
||||
#include <beast/config/CompilerConfig.h> // for BEAST_CONSTEXPR
|
||||
#include <beast/nudb/detail/stream.h>
|
||||
#include <cstdint>
|
||||
#include <beast/cxx14/type_traits.h> // <type_traits>
|
||||
|
||||
namespace beast {
|
||||
namespace nudb {
|
||||
namespace detail {
|
||||
|
||||
// base128 varint format is from
|
||||
// google protocol buffers:
|
||||
// https://developers.google.com/protocol-buffers/docs/encoding#varints
|
||||
|
||||
// field tag
|
||||
struct varint;
|
||||
|
||||
// Metafuncton to return largest
|
||||
// possible size of T represented as varint.
|
||||
// T must be unsigned
|
||||
template <class T,
|
||||
bool = std::is_unsigned<T>::value>
|
||||
struct varint_traits;
|
||||
|
||||
template <class T>
|
||||
struct varint_traits<T, true>
|
||||
{
|
||||
static std::size_t BEAST_CONSTEXPR max =
|
||||
(8 * sizeof(T) + 6) / 7;
|
||||
};
|
||||
|
||||
// Returns: Number of bytes consumed or 0 on error,
|
||||
// if the buffer was too small or t overflowed.
|
||||
//
|
||||
template <class = void>
|
||||
std::size_t
|
||||
read_varint (void const* buf,
|
||||
std::size_t buflen, std::size_t& t)
|
||||
{
|
||||
t = 0;
|
||||
std::uint8_t const* p =
|
||||
reinterpret_cast<
|
||||
std::uint8_t const*>(buf);
|
||||
std::size_t n = 0;
|
||||
while (p[n] & 0x80)
|
||||
if (++n >= buflen)
|
||||
return 0;
|
||||
if (++n > buflen)
|
||||
return 0;
|
||||
// Special case for 0
|
||||
if (n == 1 && *p == 0)
|
||||
{
|
||||
t = 0;
|
||||
return 1;
|
||||
}
|
||||
auto const used = n;
|
||||
while (n--)
|
||||
{
|
||||
auto const d = p[n];
|
||||
auto const t0 = t;
|
||||
t *= 127;
|
||||
t += d & 0x7f;
|
||||
if (t <= t0)
|
||||
return 0; // overflow
|
||||
}
|
||||
return used;
|
||||
}
|
||||
|
||||
template <class T,
|
||||
std::enable_if_t<std::is_unsigned<
|
||||
T>::value>* = nullptr>
|
||||
std::size_t
|
||||
size_varint (T v)
|
||||
{
|
||||
std::size_t n = 0;
|
||||
do
|
||||
{
|
||||
v /= 127;
|
||||
++n;
|
||||
}
|
||||
while (v != 0);
|
||||
return n;
|
||||
}
|
||||
|
||||
template <class = void>
|
||||
std::size_t
|
||||
write_varint (void* p0, std::size_t v)
|
||||
{
|
||||
std::uint8_t* p = reinterpret_cast<
|
||||
std::uint8_t*>(p0);
|
||||
do
|
||||
{
|
||||
std::uint8_t d =
|
||||
v % 127;
|
||||
v /= 127;
|
||||
if (v != 0)
|
||||
d |= 0x80;
|
||||
*p++ = d;
|
||||
}
|
||||
while (v != 0);
|
||||
return p - reinterpret_cast<
|
||||
std::uint8_t*>(p0);
|
||||
}
|
||||
|
||||
// input stream
|
||||
|
||||
template <class T, std::enable_if_t<
|
||||
std::is_same<T, varint>::value>* = nullptr>
|
||||
void
|
||||
read (istream& is, std::size_t& u)
|
||||
{
|
||||
auto p0 = is(1);
|
||||
auto p1 = p0;
|
||||
while (*p1++ & 0x80)
|
||||
is(1);
|
||||
read_varint(p0, p1 - p0, u);
|
||||
}
|
||||
|
||||
// output stream
|
||||
|
||||
template <class T, std::enable_if_t<
|
||||
std::is_same<T, varint>::value>* = nullptr>
|
||||
void
|
||||
write (ostream& os, std::size_t t)
|
||||
{
|
||||
write_varint(os.data(
|
||||
size_varint(t)), t);
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // nudb
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -20,9 +20,8 @@
|
||||
#ifndef BEAST_NUDB_FILE_H_INCLUDED
|
||||
#define BEAST_NUDB_FILE_H_INCLUDED
|
||||
|
||||
#include <beast/nudb/detail/config.h>
|
||||
#include <beast/nudb/detail/posix_file.h>
|
||||
#include <beast/nudb/detail/win32_file.h>
|
||||
#include <beast/nudb/posix_file.h>
|
||||
#include <beast/nudb/win32_file.h>
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
|
||||
@@ -17,58 +17,47 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_NUDB_CONFIG_H_INCLUDED
|
||||
#define BEAST_NUDB_CONFIG_H_INCLUDED
|
||||
#ifndef BEAST_NUDB_IDENTITY_CODEC_H_INCLUDED
|
||||
#define BEAST_NUDB_IDENTITY_CODEC_H_INCLUDED
|
||||
|
||||
#include <beast/hash/xxhasher.h>
|
||||
|
||||
// Compiles out domain checks
|
||||
#ifndef BEAST_NUDB_NO_DOMAIN_CHECK
|
||||
# ifdef NDEBUG
|
||||
# define BEAST_NUDB_NO_DOMAIN_CHECK 1
|
||||
# else
|
||||
# define BEAST_NUDB_NO_DOMAIN_CHECK 0
|
||||
# endif
|
||||
#endif
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace nudb {
|
||||
|
||||
// xxhasher is the fastest and the best choice
|
||||
// when keys are already uniformly distributed
|
||||
using default_hash = xxhasher;
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Returns the closest power of 2 not less than x
|
||||
template <class = void>
|
||||
std::size_t
|
||||
ceil_pow2 (unsigned long long x)
|
||||
/** Codec which maps input directly to output. */
|
||||
class identity_codec
|
||||
{
|
||||
static const unsigned long long t[6] = {
|
||||
0xFFFFFFFF00000000ull,
|
||||
0x00000000FFFF0000ull,
|
||||
0x000000000000FF00ull,
|
||||
0x00000000000000F0ull,
|
||||
0x000000000000000Cull,
|
||||
0x0000000000000002ull
|
||||
};
|
||||
|
||||
int y = (((x & (x - 1)) == 0) ? 0 : 1);
|
||||
int j = 32;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < 6; i++) {
|
||||
int k = (((x & t[i]) == 0) ? 0 : j);
|
||||
y += k;
|
||||
x >>= k;
|
||||
j >>= 1;
|
||||
public:
|
||||
template <class... Args>
|
||||
explicit
|
||||
identity_codec(Args&&... args)
|
||||
{
|
||||
}
|
||||
|
||||
return std::size_t(1)<<y;
|
||||
}
|
||||
char const*
|
||||
name() const
|
||||
{
|
||||
return "none";
|
||||
}
|
||||
|
||||
template <class BufferFactory>
|
||||
std::pair<void const*, std::size_t>
|
||||
compress (void const* in,
|
||||
std::size_t in_size, BufferFactory&&) const
|
||||
{
|
||||
return std::make_pair(in, in_size);
|
||||
}
|
||||
|
||||
template <class BufferFactory>
|
||||
std::pair<void const*, std::size_t>
|
||||
decompress (void const* in,
|
||||
std::size_t in_size, BufferFactory&&) const
|
||||
{
|
||||
return std::make_pair(in, in_size);
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // nudb
|
||||
} // beast
|
||||
|
||||
@@ -17,9 +17,8 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <beast/nudb/detail/config.h>
|
||||
|
||||
#include <beast/nudb/tests/callgrind_test.cpp>
|
||||
#include <beast/nudb/tests/recover_test.cpp>
|
||||
#include <beast/nudb/tests/store_test.cpp>
|
||||
#include <beast/nudb/tests/varint_test.cpp>
|
||||
#include <beast/nudb/tests/verify_test.cpp>
|
||||
|
||||
@@ -20,11 +20,10 @@
|
||||
#ifndef BEAST_NUDB_POSIX_FILE_H_INCLUDED
|
||||
#define BEAST_NUDB_POSIX_FILE_H_INCLUDED
|
||||
|
||||
#include <beast/nudb/error.h>
|
||||
#include <beast/nudb/mode.h>
|
||||
#include <beast/nudb/detail/config.h>
|
||||
#include <string.h>
|
||||
#include <beast/nudb/common.h>
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
@@ -265,14 +264,21 @@ void
|
||||
posix_file<_>::read (std::size_t offset,
|
||||
void* buffer, std::size_t bytes)
|
||||
{
|
||||
auto const n = ::pread (
|
||||
fd_, buffer, bytes, offset);
|
||||
// VFALCO end of file should throw short_read
|
||||
if (n == -1)
|
||||
throw file_posix_error(
|
||||
"pread");
|
||||
if (n < bytes)
|
||||
throw file_short_read_error();
|
||||
while(bytes > 0)
|
||||
{
|
||||
auto const n = ::pread (
|
||||
fd_, buffer, bytes, offset);
|
||||
// VFALCO end of file should throw short_read
|
||||
if (n == -1)
|
||||
throw file_posix_error(
|
||||
"pread");
|
||||
if (n == 0)
|
||||
throw file_short_read_error();
|
||||
offset += n;
|
||||
bytes -= n;
|
||||
buffer = reinterpret_cast<
|
||||
char*>(buffer) + n;
|
||||
}
|
||||
}
|
||||
|
||||
template <class _>
|
||||
@@ -280,13 +286,20 @@ void
|
||||
posix_file<_>::write (std::size_t offset,
|
||||
void const* buffer, std::size_t bytes)
|
||||
{
|
||||
auto const n = ::pwrite (
|
||||
fd_, buffer, bytes, offset);
|
||||
if (n == -1)
|
||||
throw file_posix_error(
|
||||
"pwrite");
|
||||
if (n < bytes)
|
||||
throw file_short_write_error();
|
||||
while(bytes > 0)
|
||||
{
|
||||
auto const n = ::pwrite (
|
||||
fd_, buffer, bytes, offset);
|
||||
if (n == -1)
|
||||
throw file_posix_error(
|
||||
"pwrite");
|
||||
if (n == 0)
|
||||
throw file_short_write_error();
|
||||
offset += n;
|
||||
bytes -= n;
|
||||
buffer = reinterpret_cast<
|
||||
char const*>(buffer) + n;
|
||||
}
|
||||
}
|
||||
|
||||
template <class _>
|
||||
@@ -20,12 +20,10 @@
|
||||
#ifndef BEAST_NUDB_RECOVER_H_INCLUDED
|
||||
#define BEAST_NUDB_RECOVER_H_INCLUDED
|
||||
|
||||
#include <beast/nudb/error.h>
|
||||
#include <beast/nudb/common.h>
|
||||
#include <beast/nudb/file.h>
|
||||
#include <beast/nudb/mode.h>
|
||||
#include <beast/nudb/detail/bucket.h>
|
||||
#include <beast/nudb/detail/bulkio.h>
|
||||
#include <beast/nudb/detail/config.h>
|
||||
#include <beast/nudb/detail/format.h>
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
@@ -39,19 +37,22 @@ namespace nudb {
|
||||
any partially committed data.
|
||||
*/
|
||||
template <
|
||||
class Hasher = default_hash,
|
||||
class File = native_file>
|
||||
class Hasher,
|
||||
class Codec,
|
||||
class File = native_file,
|
||||
class... Args>
|
||||
bool
|
||||
recover (
|
||||
path_type const& dat_path,
|
||||
path_type const& key_path,
|
||||
path_type const& log_path,
|
||||
std::size_t read_size = 16 * 1024 * 1024)
|
||||
std::size_t read_size,
|
||||
Args&&... args)
|
||||
{
|
||||
using namespace detail;
|
||||
File df;
|
||||
File lf;
|
||||
File kf;
|
||||
File df(args...);
|
||||
File lf(args...);
|
||||
File kf(args...);
|
||||
if (! df.open (file_mode::append, dat_path))
|
||||
return false;
|
||||
if (! kf.open (file_mode::write, key_path))
|
||||
@@ -96,8 +97,7 @@ recover (
|
||||
verify<Hasher>(kh, lh);
|
||||
auto const df_size = df.actual_size();
|
||||
buffer buf(kh.block_size);
|
||||
bucket b (kh.key_size,
|
||||
kh.block_size, buf.get());
|
||||
bucket b (kh.block_size, buf.get());
|
||||
bulk_reader<File> r(lf, log_file_header::size,
|
||||
lf_size, read_size);
|
||||
while(! r.eof())
|
||||
|
||||
@@ -17,10 +17,7 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <beast/nudb/store.h>
|
||||
#include <beast/nudb/recover.h>
|
||||
#include <beast/nudb/tests/common.h>
|
||||
#include <beast/nudb/tests/fail_file.h>
|
||||
#include <beast/module/core/diagnostic/UnitTestUtilities.h>
|
||||
#include <beast/module/core/files/File.h>
|
||||
#include <beast/random/xor_shift_engine.h>
|
||||
@@ -44,18 +41,18 @@ public:
|
||||
// with keys not present.
|
||||
void
|
||||
do_test (std::size_t count,
|
||||
nudb::path_type const& path)
|
||||
path_type const& path)
|
||||
{
|
||||
auto const dp = path + ".dat";
|
||||
auto const kp = path + ".key";
|
||||
auto const lp = path + ".log";
|
||||
nudb::create (dp, kp, lp,
|
||||
test_api::create (dp, kp, lp,
|
||||
appnum,
|
||||
salt,
|
||||
sizeof(nudb::test::key_type),
|
||||
nudb::block_size(path),
|
||||
0.50);
|
||||
nudb::store db;
|
||||
test_api::store db;
|
||||
if (! expect (db.open(dp, kp, lp,
|
||||
arena_alloc_size), "open"))
|
||||
return;
|
||||
@@ -67,7 +64,7 @@ public:
|
||||
expect (db.insert(&v.key, v.data, v.size),
|
||||
"insert");
|
||||
}
|
||||
storage s;
|
||||
Storage s;
|
||||
for (std::size_t i = 0; i < count * 2; ++i)
|
||||
{
|
||||
if (! (i%2))
|
||||
|
||||
@@ -17,11 +17,13 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_NUDB_TEST_COMMON_H_INCLUDED
|
||||
#define BEAST_NUDB_TEST_COMMON_H_INCLUDED
|
||||
#ifndef BEAST_NUDB_TESTS_COMMON_H_INCLUDED
|
||||
#define BEAST_NUDB_TESTS_COMMON_H_INCLUDED
|
||||
|
||||
#include <beast/nudb.h>
|
||||
#include <beast/nudb/identity_codec.h>
|
||||
#include <beast/nudb/tests/fail_file.h>
|
||||
#include <beast/hash/xxhasher.h>
|
||||
#include <beast/random/xor_shift_engine.h>
|
||||
#include <cstdint>
|
||||
#include <iomanip>
|
||||
@@ -33,9 +35,17 @@ namespace test {
|
||||
|
||||
using key_type = std::size_t;
|
||||
|
||||
using fail_store = nudb::basic_store<
|
||||
beast::nudb::default_hash, nudb::fail_file <
|
||||
nudb::native_file>>;
|
||||
// xxhasher is fast and produces good results
|
||||
using test_api_base =
|
||||
nudb::api<xxhasher, identity_codec, native_file>;
|
||||
|
||||
struct test_api : test_api_base
|
||||
{
|
||||
using fail_store = nudb::store<
|
||||
typename test_api_base::hash_type,
|
||||
typename test_api_base::codec_type,
|
||||
nudb::fail_file <typename test_api_base::file_type>>;
|
||||
};
|
||||
|
||||
static std::size_t BEAST_CONSTEXPR arena_alloc_size = 16 * 1024 * 1024;
|
||||
|
||||
@@ -45,8 +55,8 @@ static std::uint64_t BEAST_CONSTEXPR salt = 42;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Meets the requirements of BufferFactory
|
||||
class storage
|
||||
// Meets the requirements of Handler
|
||||
class Storage
|
||||
{
|
||||
private:
|
||||
std::size_t size_ = 0;
|
||||
@@ -54,9 +64,9 @@ private:
|
||||
std::unique_ptr<std::uint8_t[]> buf_;
|
||||
|
||||
public:
|
||||
storage() = default;
|
||||
storage (storage const&) = delete;
|
||||
storage& operator= (storage const&) = delete;
|
||||
Storage() = default;
|
||||
Storage (Storage const&) = delete;
|
||||
Storage& operator= (Storage const&) = delete;
|
||||
|
||||
std::size_t
|
||||
size() const
|
||||
@@ -71,15 +81,23 @@ public:
|
||||
}
|
||||
|
||||
std::uint8_t*
|
||||
operator()(std::size_t n)
|
||||
reserve (std::size_t size)
|
||||
{
|
||||
if (capacity_ < n)
|
||||
if (capacity_ < size)
|
||||
{
|
||||
capacity_ = detail::ceil_pow2(n);
|
||||
capacity_ = detail::ceil_pow2(size);
|
||||
buf_.reset (
|
||||
new std::uint8_t[capacity_]);
|
||||
}
|
||||
size_ = n;
|
||||
size_ = size;
|
||||
return buf_.get();
|
||||
}
|
||||
|
||||
std::uint8_t*
|
||||
operator()(void const* data, std::size_t size)
|
||||
{
|
||||
reserve (size);
|
||||
std::memcpy(buf_.get(), data, size);
|
||||
return buf_.get();
|
||||
}
|
||||
};
|
||||
@@ -134,7 +152,7 @@ private:
|
||||
maxSize = 1250
|
||||
};
|
||||
|
||||
storage s_;
|
||||
Storage s_;
|
||||
beast::xor_shift_engine gen_;
|
||||
std::uniform_int_distribution<std::uint32_t> d_size_;
|
||||
|
||||
@@ -162,7 +180,7 @@ public:
|
||||
value_type v;
|
||||
rngcpy (&v.key, sizeof(v.key), gen_);
|
||||
v.size = d_size_(gen_);
|
||||
v.data = s_(v.size);
|
||||
v.data = s_.reserve(v.size);
|
||||
rngcpy (v.data, v.size, gen_);
|
||||
return v;
|
||||
}
|
||||
@@ -205,14 +223,18 @@ print (Log log,
|
||||
log << "actual_load: " << std::fixed << std::setprecision(0) <<
|
||||
info.actual_load * 100 << "%";
|
||||
log << "version: " << num(info.version);
|
||||
log << "salt: " << std::showbase << std::hex << info.salt;
|
||||
log << "uid: " << std::showbase << std::hex << info.uid;
|
||||
log << "appnum: " << info.appnum;
|
||||
log << "key_size: " << num(info.key_size);
|
||||
log << "salt: " << std::showbase << std::hex << info.salt;
|
||||
log << "pepper: " << std::showbase << std::hex << info.pepper;
|
||||
log << "block_size: " << num(info.block_size);
|
||||
log << "bucket_size: " << num(info.bucket_size);
|
||||
log << "load_factor: " << std::fixed << std::setprecision(0) <<
|
||||
info.load_factor * 100 << "%";
|
||||
log << "capacity: " << num(info.capacity);
|
||||
log << "buckets: " << num(info.buckets);
|
||||
log << "key_count: " << num(info.key_count);
|
||||
log << "value_count: " << num(info.value_count);
|
||||
log << "value_bytes: " << num(info.value_bytes);
|
||||
log << "spill_count: " << num(info.spill_count);
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#ifndef BEAST_NUDB_FAIL_FILE_H_INCLUDED
|
||||
#define BEAST_NUDB_FAIL_FILE_H_INCLUDED
|
||||
|
||||
#include <beast/nudb/error.h>
|
||||
#include <beast/nudb/common.h>
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
@@ -17,10 +17,7 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <beast/nudb/store.h>
|
||||
#include <beast/nudb/recover.h>
|
||||
#include <beast/nudb/tests/common.h>
|
||||
#include <beast/nudb/tests/fail_file.h>
|
||||
#include <beast/module/core/files/File.h>
|
||||
#include <beast/random/xor_shift_engine.h>
|
||||
#include <beast/unit_test/suite.h>
|
||||
@@ -42,17 +39,19 @@ public:
|
||||
// they are there. Uses a fail_file that causes the n-th
|
||||
// I/O to fail, causing an exception.
|
||||
void
|
||||
do_work (std::size_t n, std::size_t count,
|
||||
float load_factor, nudb::path_type const& path)
|
||||
do_work (std::size_t count, float load_factor,
|
||||
nudb::path_type const& path, fail_counter& c)
|
||||
{
|
||||
auto const dp = path + ".dat";
|
||||
auto const kp = path + ".key";
|
||||
auto const lp = path + ".log";
|
||||
nudb::fail_counter c(0);
|
||||
nudb::create (dp, kp, lp, appnum, salt,
|
||||
sizeof(key_type), block_size(path),
|
||||
load_factor);
|
||||
fail_store db;
|
||||
test_api::file_type::erase (dp);
|
||||
test_api::file_type::erase (kp);
|
||||
test_api::file_type::erase (lp);
|
||||
expect(test_api::create (
|
||||
dp, kp, lp, appnum, salt, sizeof(key_type),
|
||||
block_size(path), load_factor), "create");
|
||||
test_api::fail_store db;
|
||||
if (! expect(db.open(dp, kp, lp,
|
||||
arena_alloc_size, c), "open"))
|
||||
{
|
||||
@@ -60,14 +59,14 @@ public:
|
||||
// to report this and terminate the test.
|
||||
}
|
||||
expect (db.appnum() == appnum, "appnum");
|
||||
c.reset(n);
|
||||
Sequence seq;
|
||||
for (std::size_t i = 0; i < count; ++i)
|
||||
{
|
||||
auto const v = seq[i];
|
||||
db.insert(&v.key, v.data, v.size);
|
||||
expect(db.insert(&v.key, v.data, v.size),
|
||||
"insert");
|
||||
}
|
||||
storage s;
|
||||
Storage s;
|
||||
for (std::size_t i = 0; i < count; ++i)
|
||||
{
|
||||
auto const v = seq[i];
|
||||
@@ -81,26 +80,36 @@ public:
|
||||
break;
|
||||
}
|
||||
db.close();
|
||||
#ifndef NDEBUG
|
||||
print(log, verify(dp, kp));
|
||||
verify(dp, kp);
|
||||
#endif
|
||||
nudb::native_file::erase (dp);
|
||||
nudb::native_file::erase (kp);
|
||||
nudb::native_file::erase (lp);
|
||||
verify_info info;
|
||||
try
|
||||
{
|
||||
info = test_api::verify(dp, kp);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
print(log, info);
|
||||
throw;
|
||||
}
|
||||
test_api::file_type::erase (dp);
|
||||
test_api::file_type::erase (kp);
|
||||
test_api::file_type::erase (lp);
|
||||
}
|
||||
|
||||
void
|
||||
do_recover (path_type const& path)
|
||||
do_recover (path_type const& path,
|
||||
fail_counter& c)
|
||||
{
|
||||
auto const dp = path + ".dat";
|
||||
auto const kp = path + ".key";
|
||||
auto const lp = path + ".log";
|
||||
recover(dp, kp, lp);
|
||||
verify(dp, kp);
|
||||
nudb::native_file::erase (dp);
|
||||
nudb::native_file::erase (kp);
|
||||
nudb::native_file::erase (lp);
|
||||
recover<test_api::hash_type,
|
||||
test_api::codec_type, fail_file<
|
||||
test_api::file_type>>(dp, kp, lp,
|
||||
test_api::buffer_size, c);
|
||||
test_api::verify(dp, kp);
|
||||
test_api::file_type::erase (dp);
|
||||
test_api::file_type::erase (kp);
|
||||
test_api::file_type::erase (lp);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -114,12 +123,24 @@ public:
|
||||
{
|
||||
try
|
||||
{
|
||||
do_work (n, count, load_factor, path);
|
||||
fail_counter c(n);
|
||||
do_work (count, load_factor, path, c);
|
||||
break;
|
||||
}
|
||||
catch (nudb::fail_error const&)
|
||||
{
|
||||
do_recover (path);
|
||||
}
|
||||
for (std::size_t m = 1;;++m)
|
||||
{
|
||||
fail_counter c(m);
|
||||
try
|
||||
{
|
||||
do_recover (path, c);
|
||||
break;
|
||||
}
|
||||
catch (nudb::fail_error const&)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -131,11 +152,10 @@ public:
|
||||
void
|
||||
run() override
|
||||
{
|
||||
float lf = 0.75f;
|
||||
float lf = 0.55f;
|
||||
test_recover (lf, 0);
|
||||
test_recover (lf, 10);
|
||||
test_recover (lf, 100);
|
||||
test_recover (lf, 1000);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -148,7 +168,8 @@ public:
|
||||
run() override
|
||||
{
|
||||
float lf = 0.90f;
|
||||
test_recover (lf, 100000);
|
||||
test_recover (lf, 1000);
|
||||
test_recover (lf, 10000);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -18,9 +18,7 @@
|
||||
//==============================================================================
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <beast/nudb.h>
|
||||
#include <beast/nudb/tests/common.h>
|
||||
#include <beast/nudb/tests/fail_file.h>
|
||||
#include <beast/module/core/diagnostic/UnitTestUtilities.h>
|
||||
#include <beast/module/core/files/File.h>
|
||||
#include <beast/random/xor_shift_engine.h>
|
||||
@@ -55,15 +53,15 @@ public:
|
||||
auto const kp = path + ".key";
|
||||
auto const lp = path + ".log";
|
||||
Sequence seq;
|
||||
nudb::store db;
|
||||
test_api::store db;
|
||||
try
|
||||
{
|
||||
expect (nudb::create (dp, kp, lp, appnum,
|
||||
expect (test_api::create (dp, kp, lp, appnum,
|
||||
salt, sizeof(key_type), block_size,
|
||||
load_factor), "create");
|
||||
expect (db.open(dp, kp, lp,
|
||||
arena_alloc_size), "open");
|
||||
storage s;
|
||||
Storage s;
|
||||
// insert
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
{
|
||||
@@ -102,7 +100,9 @@ public:
|
||||
"insert 2");
|
||||
}
|
||||
db.close();
|
||||
auto const stats = nudb::verify (dp, kp);
|
||||
//auto const stats = test_api::verify(dp, kp);
|
||||
auto const stats = verify<test_api::hash_type>(
|
||||
dp, kp, 1 * 1024 * 1024);
|
||||
expect (stats.hist[1] > 0, "no splits");
|
||||
print (log, stats);
|
||||
}
|
||||
@@ -114,9 +114,9 @@ public:
|
||||
{
|
||||
fail (e.what());
|
||||
}
|
||||
expect (native_file::erase(dp));
|
||||
expect (native_file::erase(kp));
|
||||
expect (! native_file::erase(lp));
|
||||
expect (test_api::file_type::erase(dp));
|
||||
expect (test_api::file_type::erase(kp));
|
||||
expect (! test_api::file_type::erase(lp));
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
73
src/beast/beast/nudb/tests/varint_test.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2014, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <beast/nudb/detail/varint.h>
|
||||
#include <beast/unit_test/suite.h>
|
||||
#include <array>
|
||||
|
||||
namespace beast {
|
||||
namespace nudb {
|
||||
namespace tests {
|
||||
|
||||
class varint_test : public unit_test::suite
|
||||
{
|
||||
public:
|
||||
void
|
||||
test_varints (std::vector<std::size_t> vv)
|
||||
{
|
||||
testcase("encode, decode");
|
||||
for (auto const v : vv)
|
||||
{
|
||||
std::array<std::uint8_t,
|
||||
detail::varint_traits<
|
||||
std::size_t>::max> vi;
|
||||
auto const n0 =
|
||||
detail::write_varint(
|
||||
vi.data(), v);
|
||||
expect (n0 > 0, "write error");
|
||||
std::size_t v1;
|
||||
auto const n1 =
|
||||
detail::read_varint(
|
||||
vi.data(), n0, v1);
|
||||
expect(n1 == n0, "read error");
|
||||
expect(v == v1, "wrong value");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
test_varints({
|
||||
0, 1, 2,
|
||||
126, 127, 128,
|
||||
253, 254, 255,
|
||||
16127, 16128, 16129,
|
||||
0xff,
|
||||
0xffff,
|
||||
0xffffffff,
|
||||
0xffffffffffffUL,
|
||||
0xffffffffffffffffUL});
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(varint,nudb,beast);
|
||||
|
||||
} // test
|
||||
} // nudb
|
||||
} // beast
|
||||
@@ -20,11 +20,213 @@
|
||||
#include <beast/nudb/verify.h>
|
||||
#include <beast/nudb/tests/common.h>
|
||||
#include <beast/unit_test/suite.h>
|
||||
#include <beast/chrono/basic_seconds_clock.h>
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
#include <ostream>
|
||||
|
||||
namespace beast {
|
||||
namespace nudb {
|
||||
namespace test {
|
||||
|
||||
namespace detail {
|
||||
|
||||
class save_stream_state
|
||||
{
|
||||
std::ostream& os_;
|
||||
std::streamsize precision_;
|
||||
std::ios::fmtflags flags_;
|
||||
std::ios::char_type fill_;
|
||||
public:
|
||||
~save_stream_state()
|
||||
{
|
||||
os_.precision(precision_);
|
||||
os_.flags(flags_);
|
||||
os_.fill(fill_);
|
||||
}
|
||||
save_stream_state(save_stream_state const&) = delete;
|
||||
save_stream_state& operator=(save_stream_state const&) = delete;
|
||||
explicit save_stream_state(std::ostream& os)
|
||||
: os_(os)
|
||||
, precision_(os.precision())
|
||||
, flags_(os.flags())
|
||||
, fill_(os.fill())
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template <class Rep, class Period>
|
||||
std::ostream&
|
||||
pretty_time(std::ostream& os, std::chrono::duration<Rep, Period> d)
|
||||
{
|
||||
save_stream_state _(os);
|
||||
using namespace std::chrono;
|
||||
if (d < microseconds{1})
|
||||
{
|
||||
// use nanoseconds
|
||||
if (d < nanoseconds{100})
|
||||
{
|
||||
// use floating
|
||||
using ns = duration<float, std::nano>;
|
||||
os << std::fixed << std::setprecision(1) << ns(d).count();
|
||||
}
|
||||
else
|
||||
{
|
||||
// use integral
|
||||
os << std::chrono::duration_cast<nanoseconds>(d).count();
|
||||
}
|
||||
os << "ns";
|
||||
}
|
||||
else if (d < milliseconds{1})
|
||||
{
|
||||
// use microseconds
|
||||
if (d < microseconds{100})
|
||||
{
|
||||
// use floating
|
||||
using ms = duration<float, std::micro>;
|
||||
os << std::fixed << std::setprecision(1) << ms(d).count();
|
||||
}
|
||||
else
|
||||
{
|
||||
// use integral
|
||||
os << std::chrono::duration_cast<microseconds>(d).count();
|
||||
}
|
||||
os << "us";
|
||||
}
|
||||
else if (d < seconds{1})
|
||||
{
|
||||
// use milliseconds
|
||||
if (d < milliseconds{100})
|
||||
{
|
||||
// use floating
|
||||
using ms = duration<float, std::milli>;
|
||||
os << std::fixed << std::setprecision(1) << ms(d).count();
|
||||
}
|
||||
else
|
||||
{
|
||||
// use integral
|
||||
os << std::chrono::duration_cast<milliseconds>(d).count();
|
||||
}
|
||||
os << "ms";
|
||||
}
|
||||
else if (d < minutes{1})
|
||||
{
|
||||
// use seconds
|
||||
if (d < seconds{100})
|
||||
{
|
||||
// use floating
|
||||
using s = duration<float>;
|
||||
os << std::fixed << std::setprecision(1) << s(d).count();
|
||||
}
|
||||
else
|
||||
{
|
||||
// use integral
|
||||
os << std::chrono::duration_cast<seconds>(d).count();
|
||||
}
|
||||
os << "s";
|
||||
}
|
||||
else
|
||||
{
|
||||
// use minutes
|
||||
if (d < minutes{100})
|
||||
{
|
||||
// use floating
|
||||
using m = duration<float, std::ratio<60>>;
|
||||
os << std::fixed << std::setprecision(1) << m(d).count();
|
||||
}
|
||||
else
|
||||
{
|
||||
// use integral
|
||||
os << std::chrono::duration_cast<minutes>(d).count();
|
||||
}
|
||||
os << "min";
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
template <class Period, class Rep>
|
||||
inline
|
||||
std::string
|
||||
fmtdur(std::chrono::duration<Period, Rep> const& d)
|
||||
{
|
||||
std::stringstream ss;
|
||||
pretty_time(ss, d);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class Log>
|
||||
class progress
|
||||
{
|
||||
private:
|
||||
using clock_type =
|
||||
beast::basic_seconds_clock<
|
||||
std::chrono::steady_clock>;
|
||||
|
||||
Log& log_;
|
||||
clock_type::time_point start_ = clock_type::now();
|
||||
clock_type::time_point now_ = clock_type::now();
|
||||
clock_type::time_point report_ = clock_type::now();
|
||||
std::size_t prev_ = 0;
|
||||
bool estimate_ = false;
|
||||
|
||||
public:
|
||||
explicit
|
||||
progress(Log& log)
|
||||
: log_(log)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(std::size_t w, std::size_t w1)
|
||||
{
|
||||
using namespace std::chrono;
|
||||
auto const now = clock_type::now();
|
||||
if (now == now_)
|
||||
return;
|
||||
now_ = now;
|
||||
auto const elapsed = now - start_;
|
||||
if (! estimate_)
|
||||
{
|
||||
if (elapsed < seconds(15))
|
||||
return;
|
||||
estimate_ = true;
|
||||
}
|
||||
else if (now - report_ <
|
||||
std::chrono::seconds(60))
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto const rate =
|
||||
elapsed.count() / double(w);
|
||||
clock_type::duration const remain(
|
||||
static_cast<clock_type::duration::rep>(
|
||||
(w1 - w) * rate));
|
||||
log_ <<
|
||||
"Remaining: " << detail::fmtdur(remain) <<
|
||||
" (" << w << " of " << w1 <<
|
||||
" in " << detail::fmtdur(elapsed) <<
|
||||
", " << (w - prev_) <<
|
||||
" in " << detail::fmtdur(now - report_) <<
|
||||
")";
|
||||
report_ = now;
|
||||
prev_ = w;
|
||||
}
|
||||
|
||||
void
|
||||
finish()
|
||||
{
|
||||
log_ <<
|
||||
"Total time: " << detail::fmtdur(
|
||||
clock_type::now() - start_);
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class verify_test : public unit_test::suite
|
||||
{
|
||||
public:
|
||||
@@ -34,12 +236,41 @@ public:
|
||||
{
|
||||
auto const dp = path + ".dat";
|
||||
auto const kp = path + ".key";
|
||||
print(log, verify(dp, kp));
|
||||
print(log, test_api::verify(dp, kp));
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testcase(abort_on_fail) << "verify " << arg();
|
||||
if (arg().empty())
|
||||
return fail("missing unit test argument");
|
||||
do_verify(arg());
|
||||
pass();
|
||||
}
|
||||
};
|
||||
|
||||
class verify_fast_test : public unit_test::suite
|
||||
{
|
||||
public:
|
||||
// Runs verify on the database and reports statistics
|
||||
void
|
||||
do_verify (nudb::path_type const& path)
|
||||
{
|
||||
auto const dp = path + ".dat";
|
||||
auto const kp = path + ".key";
|
||||
progress<decltype(log)> p(log);
|
||||
// VFALCO HACK 32gb hardcoded!
|
||||
auto const info = verify_fast<
|
||||
test_api::hash_type>(
|
||||
dp, kp, 34359738368, p);
|
||||
print(log, info);
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testcase(abort_on_fail) << "verify_fast " << arg();
|
||||
if (arg().empty())
|
||||
return fail("missing unit test argument");
|
||||
do_verify(arg());
|
||||
@@ -48,8 +279,8 @@ public:
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE_MANUAL(verify,nudb,beast);
|
||||
BEAST_DEFINE_TESTSUITE_MANUAL(verify_fast,nudb,beast);
|
||||
|
||||
} // test
|
||||
} // nudb
|
||||
} // beast
|
||||
|
||||
|
||||
@@ -20,12 +20,10 @@
|
||||
#ifndef BEAST_NUDB_VERIFY_H_INCLUDED
|
||||
#define BEAST_NUDB_VERIFY_H_INCLUDED
|
||||
|
||||
#include <beast/nudb/error.h>
|
||||
#include <beast/nudb/common.h>
|
||||
#include <beast/nudb/file.h>
|
||||
#include <beast/nudb/mode.h>
|
||||
#include <beast/nudb/detail/bucket.h>
|
||||
#include <beast/nudb/detail/bulkio.h>
|
||||
#include <beast/nudb/detail/config.h>
|
||||
#include <beast/nudb/detail/format.h>
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
@@ -39,8 +37,11 @@ struct verify_info
|
||||
{
|
||||
// Configured
|
||||
std::size_t version = 0; // API version
|
||||
std::size_t salt = 0; // Salt or database ID
|
||||
std::size_t uid = 0; // UID
|
||||
std::size_t appnum = 0; // Appnum
|
||||
std::size_t key_size = 0; // Size of a key in bytes
|
||||
std::size_t salt = 0; // Salt
|
||||
std::size_t pepper = 0; // Pepper
|
||||
std::size_t block_size = 0; // Block size in bytes
|
||||
float load_factor = 0; // Target bucket fill fraction
|
||||
|
||||
@@ -82,12 +83,12 @@ struct verify_info
|
||||
Iterates the key and data files, throws store_corrupt_error
|
||||
on broken invariants.
|
||||
*/
|
||||
template <class Hasher = default_hash>
|
||||
template <class Hasher>
|
||||
verify_info
|
||||
verify (
|
||||
path_type const& dat_path,
|
||||
path_type const& key_path,
|
||||
std::size_t read_size = 16 * 1024 * 1024)
|
||||
std::size_t read_size)
|
||||
{
|
||||
using namespace detail;
|
||||
using File = native_file;
|
||||
@@ -103,12 +104,16 @@ verify (
|
||||
dat_file_header dh;
|
||||
read (df, dh);
|
||||
read (kf, kh);
|
||||
verify(dh);
|
||||
verify<Hasher>(dh, kh);
|
||||
|
||||
verify_info info;
|
||||
info.version = dh.version;
|
||||
info.salt = dh.salt;
|
||||
info.uid = dh.uid;
|
||||
info.appnum = dh.appnum;
|
||||
info.key_size = dh.key_size;
|
||||
info.salt = kh.salt;
|
||||
info.pepper = kh.pepper;
|
||||
info.block_size = kh.block_size;
|
||||
info.load_factor = kh.load_factor / 65536.f;
|
||||
info.capacity = kh.capacity;
|
||||
@@ -117,21 +122,28 @@ verify (
|
||||
info.key_file_size = kf.actual_size();
|
||||
info.dat_file_size = df.actual_size();
|
||||
|
||||
buffer buf (kh.block_size);
|
||||
bucket b (kh.key_size,
|
||||
kh.block_size, buf.get());
|
||||
// Data Record
|
||||
auto const dh_len =
|
||||
field<uint48_t>::size + // Size
|
||||
kh.key_size; // Key
|
||||
|
||||
std::size_t fetches = 0;
|
||||
|
||||
// Iterate Data File
|
||||
buffer buf (kh.block_size + dh_len);
|
||||
bucket b (kh.block_size, buf.get());
|
||||
std::uint8_t* pd = buf.get() + kh.block_size;
|
||||
{
|
||||
bulk_reader<File> r(df,
|
||||
dat_file_header::size,
|
||||
df.actual_size(), read_size);
|
||||
while (! r.eof())
|
||||
{
|
||||
auto const offset = r.offset();
|
||||
// Data Record or Spill Record
|
||||
std::size_t size;
|
||||
auto is = r.prepare(
|
||||
field<uint48_t>::size); // Size
|
||||
std::size_t size;
|
||||
read<uint48_t>(is, size);
|
||||
if (size > 0)
|
||||
{
|
||||
@@ -144,39 +156,49 @@ verify (
|
||||
std::uint8_t const* const data =
|
||||
is.data(size);
|
||||
(void)data;
|
||||
auto const h = hash<Hasher>(
|
||||
key, kh.key_size, kh.salt);
|
||||
// Check bucket and spills
|
||||
try
|
||||
{
|
||||
b.read (kf, (bucket_index<Hasher>(
|
||||
key, kh) + 1) * kh.block_size);
|
||||
auto const n = bucket_index(
|
||||
h, kh.buckets, kh.modulus);
|
||||
b.read (kf, (n + 1) * kh.block_size);
|
||||
++fetches;
|
||||
}
|
||||
catch (file_short_read_error const&)
|
||||
{
|
||||
throw store_corrupt_error(
|
||||
"short bucket");
|
||||
}
|
||||
for(;;)
|
||||
for (;;)
|
||||
{
|
||||
if (b.find(key).second)
|
||||
break;
|
||||
if (b.spill() != 0)
|
||||
for (auto i = b.lower_bound(h);
|
||||
i < b.size(); ++i)
|
||||
{
|
||||
try
|
||||
{
|
||||
b.read (df, b.spill());
|
||||
}
|
||||
catch (file_short_read_error const&)
|
||||
{
|
||||
throw store_corrupt_error(
|
||||
"short spill");
|
||||
}
|
||||
auto const item = b[i];
|
||||
if (item.hash != h)
|
||||
break;
|
||||
if (item.offset == offset)
|
||||
goto found;
|
||||
++fetches;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const spill = b.spill();
|
||||
if (! spill)
|
||||
throw store_corrupt_error(
|
||||
"orphaned value");
|
||||
try
|
||||
{
|
||||
b.read (df, spill);
|
||||
++fetches;
|
||||
}
|
||||
catch (file_short_read_error const&)
|
||||
{
|
||||
throw store_corrupt_error(
|
||||
"short spill");
|
||||
}
|
||||
}
|
||||
found:
|
||||
// Update
|
||||
++info.value_count;
|
||||
info.value_bytes += size;
|
||||
@@ -196,17 +218,12 @@ verify (
|
||||
field<uint48_t>::size + // Zero
|
||||
field<uint16_t>::size + // Size
|
||||
b.compact_size(); // Bucket
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate Key File
|
||||
{
|
||||
// Data Record (header)
|
||||
buffer buf (
|
||||
field<uint48_t>::size + // Size
|
||||
kh.key_size); // Key Size
|
||||
for (std::size_t n = 0; n < kh.buckets; ++n)
|
||||
{
|
||||
std::size_t nspill = 0;
|
||||
@@ -219,8 +236,7 @@ verify (
|
||||
auto const e = b[i];
|
||||
try
|
||||
{
|
||||
df.read (e.offset,
|
||||
buf.get(), buf.size());
|
||||
df.read (e.offset, pd, dh_len);
|
||||
}
|
||||
catch (file_short_read_error const&)
|
||||
{
|
||||
@@ -228,16 +244,19 @@ verify (
|
||||
"missing value");
|
||||
}
|
||||
// Data Record
|
||||
istream is(buf.get(), buf.size());
|
||||
istream is(pd, dh_len);
|
||||
std::size_t size;
|
||||
read<uint48_t>(is, size); // Size
|
||||
void const* key =
|
||||
is.data(kh.key_size); // Key
|
||||
if (size != e.size)
|
||||
throw store_corrupt_error(
|
||||
"wrong size");
|
||||
if (std::memcmp(is.data(kh.key_size),
|
||||
e.key, kh.key_size) != 0)
|
||||
auto const h = hash<Hasher>(key,
|
||||
kh.key_size, kh.salt);
|
||||
if (h != e.hash)
|
||||
throw store_corrupt_error(
|
||||
"wrong key");
|
||||
"wrong hash");
|
||||
}
|
||||
if (! b.spill())
|
||||
break;
|
||||
@@ -266,12 +285,242 @@ verify (
|
||||
float sum = 0;
|
||||
for (int i = 0; i < info.hist.size(); ++i)
|
||||
sum += info.hist[i] * (i + 1);
|
||||
info.avg_fetch = sum / info.buckets;
|
||||
//info.avg_fetch = sum / info.buckets;
|
||||
info.avg_fetch = float(fetches) / info.value_count;
|
||||
info.waste = (info.spill_bytes_tot - info.spill_bytes) /
|
||||
float(info.dat_file_size);
|
||||
info.overhead =
|
||||
float(info.key_file_size + info.dat_file_size) /
|
||||
(info.value_bytes + info.key_count * info.key_size) - 1;
|
||||
(
|
||||
info.value_bytes +
|
||||
info.key_count *
|
||||
(info.key_size +
|
||||
// Data Record
|
||||
field<uint48_t>::size) // Size
|
||||
) - 1;
|
||||
info.actual_load = info.key_count / float(
|
||||
info.capacity * info.buckets);
|
||||
return info;
|
||||
}
|
||||
|
||||
/** Verify consistency of the key and data files.
|
||||
Effects:
|
||||
Opens the key and data files in read-only mode.
|
||||
Throws file_error if a file can't be opened.
|
||||
Iterates the key and data files, throws store_corrupt_error
|
||||
on broken invariants.
|
||||
This uses a different algorithm that depends on allocating
|
||||
a lareg buffer.
|
||||
*/
|
||||
template <class Hasher, class Progress>
|
||||
verify_info
|
||||
verify_fast (
|
||||
path_type const& dat_path,
|
||||
path_type const& key_path,
|
||||
std::size_t buffer_size,
|
||||
Progress&& progress)
|
||||
{
|
||||
using namespace detail;
|
||||
using File = native_file;
|
||||
File df;
|
||||
File kf;
|
||||
if (! df.open (file_mode::scan, dat_path))
|
||||
throw store_corrupt_error(
|
||||
"no data file");
|
||||
if (! kf.open (file_mode::read, key_path))
|
||||
throw store_corrupt_error(
|
||||
"no key file");
|
||||
key_file_header kh;
|
||||
dat_file_header dh;
|
||||
read (df, dh);
|
||||
read (kf, kh);
|
||||
verify(dh);
|
||||
verify<Hasher>(dh, kh);
|
||||
|
||||
verify_info info;
|
||||
info.version = dh.version;
|
||||
info.uid = dh.uid;
|
||||
info.appnum = dh.appnum;
|
||||
info.key_size = dh.key_size;
|
||||
info.salt = kh.salt;
|
||||
info.pepper = kh.pepper;
|
||||
info.block_size = kh.block_size;
|
||||
info.load_factor = kh.load_factor / 65536.f;
|
||||
info.capacity = kh.capacity;
|
||||
info.buckets = kh.buckets;
|
||||
info.bucket_size = kh.bucket_size;
|
||||
info.key_file_size = kf.actual_size();
|
||||
info.dat_file_size = df.actual_size();
|
||||
|
||||
std::size_t fetches = 0;
|
||||
|
||||
// Counts unverified keys per bucket
|
||||
std::unique_ptr<std::uint32_t[]> nkeys(
|
||||
new std::uint32_t[kh.buckets]);
|
||||
|
||||
// Verify contiguous sequential sections of the
|
||||
// key file using multiple passes over the data.
|
||||
//
|
||||
auto const buckets = std::max<std::size_t>(1,
|
||||
buffer_size / kh.block_size);
|
||||
buffer buf((buckets + 1) * kh.block_size);
|
||||
bucket tmp(kh.block_size, buf.get() +
|
||||
buckets * kh.block_size);
|
||||
std::size_t const passes =
|
||||
(kh.buckets + buckets - 1) / buckets;
|
||||
auto const df_size = df.actual_size();
|
||||
std::size_t const work = passes * df_size;
|
||||
std::size_t npass = 0;
|
||||
for (std::size_t b0 = 0; b0 < kh.buckets;
|
||||
b0 += buckets)
|
||||
{
|
||||
auto const b1 = std::min(
|
||||
b0 + buckets, kh.buckets);
|
||||
// Buffered range is [b0, b1)
|
||||
auto const bn = b1 - b0;
|
||||
kf.read((b0 + 1) * kh.block_size,
|
||||
buf.get(), bn * kh.block_size);
|
||||
// Count keys in buckets
|
||||
for (std::size_t i = b0 ; i < b1; ++i)
|
||||
{
|
||||
bucket b(kh.block_size, buf.get() +
|
||||
(i - b0) * kh.block_size);
|
||||
nkeys[i] = b.size();
|
||||
std::size_t nspill = 0;
|
||||
auto spill = b.spill();
|
||||
while (spill != 0)
|
||||
{
|
||||
tmp.read(df, spill);
|
||||
nkeys[i] += tmp.size();
|
||||
spill = tmp.spill();
|
||||
++nspill;
|
||||
++info.spill_count;
|
||||
info.spill_bytes +=
|
||||
field<uint48_t>::size + // Zero
|
||||
field<uint16_t>::size + // Size
|
||||
tmp.compact_size(); // SpillBucket
|
||||
}
|
||||
if (nspill >= info.hist.size())
|
||||
nspill = info.hist.size() - 1;
|
||||
++info.hist[nspill];
|
||||
info.key_count += nkeys[i];
|
||||
}
|
||||
// Iterate Data File
|
||||
bulk_reader<File> r(df,
|
||||
dat_file_header::size, df_size,
|
||||
64 * 1024 * 1024);
|
||||
while (! r.eof())
|
||||
{
|
||||
auto const offset = r.offset();
|
||||
progress(npass * df_size + offset, work);
|
||||
// Data Record or Spill Record
|
||||
auto is = r.prepare(
|
||||
field<uint48_t>::size); // Size
|
||||
std::size_t size;
|
||||
read<uint48_t>(is, size);
|
||||
if (size > 0)
|
||||
{
|
||||
// Data Record
|
||||
is = r.prepare(
|
||||
kh.key_size + // Key
|
||||
size); // Data
|
||||
std::uint8_t const* const key =
|
||||
is.data(kh.key_size);
|
||||
std::uint8_t const* const data =
|
||||
is.data(size);
|
||||
(void)data;
|
||||
auto const h = hash<Hasher>(
|
||||
key, kh.key_size, kh.salt);
|
||||
auto const n = bucket_index(
|
||||
h, kh.buckets, kh.modulus);
|
||||
if (n < b0 || n >= b1)
|
||||
continue;
|
||||
// Check bucket and spills
|
||||
bucket b (kh.block_size, buf.get() +
|
||||
(n - b0) * kh.block_size);
|
||||
++fetches;
|
||||
for (;;)
|
||||
{
|
||||
for (auto i = b.lower_bound(h);
|
||||
i < b.size(); ++i)
|
||||
{
|
||||
auto const item = b[i];
|
||||
if (item.hash != h)
|
||||
break;
|
||||
if (item.offset == offset)
|
||||
goto found;
|
||||
++fetches;
|
||||
}
|
||||
auto const spill = b.spill();
|
||||
if (! spill)
|
||||
throw store_corrupt_error(
|
||||
"orphaned value");
|
||||
b = tmp;
|
||||
try
|
||||
{
|
||||
b.read (df, spill);
|
||||
++fetches;
|
||||
}
|
||||
catch (file_short_read_error const&)
|
||||
{
|
||||
throw store_corrupt_error(
|
||||
"short spill");
|
||||
}
|
||||
}
|
||||
found:
|
||||
// Update
|
||||
++info.value_count;
|
||||
info.value_bytes += size;
|
||||
if (nkeys[n]-- == 0)
|
||||
throw store_corrupt_error(
|
||||
"duplicate value");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Spill Record
|
||||
is = r.prepare(
|
||||
field<std::uint16_t>::size);
|
||||
read<std::uint16_t>(is, size); // Size
|
||||
if (size != kh.bucket_size)
|
||||
throw store_corrupt_error(
|
||||
"bad spill size");
|
||||
tmp.read(r); // Bucket
|
||||
if (b0 == 0)
|
||||
{
|
||||
++info.spill_count_tot;
|
||||
info.spill_bytes_tot +=
|
||||
field<uint48_t>::size + // Zero
|
||||
field<uint16_t>::size + // Size
|
||||
tmp.compact_size(); // Bucket
|
||||
}
|
||||
}
|
||||
}
|
||||
++npass;
|
||||
}
|
||||
|
||||
// Make sure every key in every bucket was visited
|
||||
for (std::size_t i = 0;
|
||||
i < kh.buckets; ++i)
|
||||
if (nkeys[i] != 0)
|
||||
throw store_corrupt_error(
|
||||
"orphan value");
|
||||
|
||||
float sum = 0;
|
||||
for (int i = 0; i < info.hist.size(); ++i)
|
||||
sum += info.hist[i] * (i + 1);
|
||||
//info.avg_fetch = sum / info.buckets;
|
||||
info.avg_fetch = float(fetches) / info.value_count;
|
||||
info.waste = (info.spill_bytes_tot - info.spill_bytes) /
|
||||
float(info.dat_file_size);
|
||||
info.overhead =
|
||||
float(info.key_file_size + info.dat_file_size) /
|
||||
(
|
||||
info.value_bytes +
|
||||
info.key_count *
|
||||
(info.key_size +
|
||||
// Data Record
|
||||
field<uint48_t>::size) // Size
|
||||
) - 1;
|
||||
info.actual_load = info.key_count / float(
|
||||
info.capacity * info.buckets);
|
||||
return info;
|
||||
|
||||
@@ -20,11 +20,10 @@
|
||||
#ifndef BEAST_NUDB_VISIT_H_INCLUDED
|
||||
#define BEAST_NUDB_VISIT_H_INCLUDED
|
||||
|
||||
#include <beast/nudb/error.h>
|
||||
#include <beast/nudb/common.h>
|
||||
#include <beast/nudb/file.h>
|
||||
#include <beast/nudb/mode.h>
|
||||
#include <beast/nudb/detail/buffer.h>
|
||||
#include <beast/nudb/detail/bulkio.h>
|
||||
#include <beast/nudb/detail/config.h>
|
||||
#include <beast/nudb/detail/format.h>
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
@@ -44,12 +43,12 @@ namespace nudb {
|
||||
@return `true` if the visit completed
|
||||
This only requires the data file.
|
||||
*/
|
||||
template <class Function>
|
||||
template <class Codec, class Function>
|
||||
bool
|
||||
visit(
|
||||
path_type const& path,
|
||||
Function f,
|
||||
std::size_t read_size = 16 * 1024 * 1024)
|
||||
std::size_t read_size,
|
||||
Function&& f)
|
||||
{
|
||||
using namespace detail;
|
||||
using File = native_file;
|
||||
@@ -57,11 +56,13 @@ visit(
|
||||
df.open (file_mode::scan, path);
|
||||
dat_file_header dh;
|
||||
read (df, dh);
|
||||
verify (dh);
|
||||
verify<Codec> (dh);
|
||||
Codec codec;
|
||||
// Iterate Data File
|
||||
bulk_reader<File> r(
|
||||
df, dat_file_header::size,
|
||||
df.actual_size(), read_size);
|
||||
buffer buf;
|
||||
try
|
||||
{
|
||||
while (! r.eof())
|
||||
@@ -79,10 +80,10 @@ visit(
|
||||
size); // Data
|
||||
std::uint8_t const* const key =
|
||||
is.data(dh.key_size);
|
||||
std::uint8_t const* const data =
|
||||
is.data(size);
|
||||
auto const result = codec.decompress(
|
||||
is.data(size), size, buf);
|
||||
if (! f(key, dh.key_size,
|
||||
data, size))
|
||||
result.first, result.second))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -20,9 +20,7 @@
|
||||
#ifndef BEAST_NUDB_WIN32_FILE_H_INCLUDED
|
||||
#define BEAST_NUDB_WIN32_FILE_H_INCLUDED
|
||||
|
||||
#include <beast/nudb/error.h>
|
||||
#include <beast/nudb/mode.h>
|
||||
#include <beast/nudb/detail/config.h>
|
||||
#include <beast/nudb/common.h>
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
@@ -321,25 +319,32 @@ void
|
||||
win32_file<_>::read (std::size_t offset,
|
||||
void* buffer, std::size_t bytes)
|
||||
{
|
||||
DWORD bytesRead;
|
||||
LARGE_INTEGER li;
|
||||
li.QuadPart = static_cast<LONGLONG>(offset);
|
||||
OVERLAPPED ov;
|
||||
ov.Offset = li.LowPart;
|
||||
ov.OffsetHigh = li.HighPart;
|
||||
ov.hEvent = NULL;
|
||||
BOOL const bSuccess = ::ReadFile(
|
||||
hf_, buffer, bytes, &bytesRead, &ov);
|
||||
if (! bSuccess)
|
||||
while(bytes > 0)
|
||||
{
|
||||
DWORD const dwError = ::GetLastError();
|
||||
if (dwError != ERROR_HANDLE_EOF)
|
||||
throw file_win32_error(
|
||||
"read file", dwError);
|
||||
throw file_short_read_error();
|
||||
DWORD bytesRead;
|
||||
LARGE_INTEGER li;
|
||||
li.QuadPart = static_cast<LONGLONG>(offset);
|
||||
OVERLAPPED ov;
|
||||
ov.Offset = li.LowPart;
|
||||
ov.OffsetHigh = li.HighPart;
|
||||
ov.hEvent = NULL;
|
||||
BOOL const bSuccess = ::ReadFile(
|
||||
hf_, buffer, bytes, &bytesRead, &ov);
|
||||
if (! bSuccess)
|
||||
{
|
||||
DWORD const dwError = ::GetLastError();
|
||||
if (dwError != ERROR_HANDLE_EOF)
|
||||
throw file_win32_error(
|
||||
"read file", dwError);
|
||||
throw file_short_read_error();
|
||||
}
|
||||
if (bytesRead == 0)
|
||||
throw file_short_read_error();
|
||||
offset += bytesRead;
|
||||
bytes -= bytesRead;
|
||||
buffer = reinterpret_cast<char*>(
|
||||
buffer) + bytesRead;
|
||||
}
|
||||
if (bytesRead != bytes)
|
||||
throw file_short_read_error();
|
||||
}
|
||||
|
||||
template <class _>
|
||||
@@ -347,20 +352,28 @@ void
|
||||
win32_file<_>::write (std::size_t offset,
|
||||
void const* buffer, std::size_t bytes)
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
li.QuadPart = static_cast<LONGLONG>(offset);
|
||||
OVERLAPPED ov;
|
||||
ov.Offset = li.LowPart;
|
||||
ov.OffsetHigh = li.HighPart;
|
||||
ov.hEvent = NULL;
|
||||
DWORD bytesWritten;
|
||||
BOOL const bSuccess = ::WriteFile(
|
||||
hf_, buffer, bytes, &bytesWritten, &ov);
|
||||
if (! bSuccess)
|
||||
throw file_win32_error(
|
||||
"write file");
|
||||
if (bytesWritten != bytes)
|
||||
throw file_short_write_error();
|
||||
while(bytes > 0)
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
li.QuadPart = static_cast<LONGLONG>(offset);
|
||||
OVERLAPPED ov;
|
||||
ov.Offset = li.LowPart;
|
||||
ov.OffsetHigh = li.HighPart;
|
||||
ov.hEvent = NULL;
|
||||
DWORD bytesWritten;
|
||||
BOOL const bSuccess = ::WriteFile(
|
||||
hf_, buffer, bytes, &bytesWritten, &ov);
|
||||
if (! bSuccess)
|
||||
throw file_win32_error(
|
||||
"write file");
|
||||
if (bytesWritten == 0)
|
||||
throw file_short_write_error();
|
||||
offset += bytesWritten;
|
||||
bytes -= bytesWritten;
|
||||
buffer = reinterpret_cast<
|
||||
char const*>(buffer) +
|
||||
bytesWritten;
|
||||
}
|
||||
}
|
||||
|
||||
template <class _>
|
||||
@@ -394,7 +407,6 @@ template <class _>
|
||||
std::pair<DWORD, DWORD>
|
||||
win32_file<_>::flags (file_mode mode)
|
||||
{
|
||||
mode = file_mode::write;
|
||||
std::pair<DWORD, DWORD> result(0, 0);
|
||||
switch (mode)
|
||||
{
|
||||
10
src/lz4/.gitattributes
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# Set the default behavior
|
||||
* text eol=lf
|
||||
|
||||
# Explicitly declare source files
|
||||
*.c text eol=lf
|
||||
*.h text eol=lf
|
||||
|
||||
# Denote files that should not be modified.
|
||||
*.odt binary
|
||||
*.png binary
|
||||
26
src/lz4/.travis.yml
Normal file
@@ -0,0 +1,26 @@
|
||||
language: c
|
||||
compiler: gcc
|
||||
script: make test-travis
|
||||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq gcc-multilib
|
||||
- sudo apt-get install -qq valgrind
|
||||
|
||||
env:
|
||||
- LZ4_TRAVIS_CI_ENV=travis-install
|
||||
- LZ4_TRAVIS_CI_ENV=streaming-examples
|
||||
- LZ4_TRAVIS_CI_ENV=cmake
|
||||
- LZ4_TRAVIS_CI_ENV=dist
|
||||
- LZ4_TRAVIS_CI_ENV=test-lz4
|
||||
- LZ4_TRAVIS_CI_ENV=test-lz4c
|
||||
- LZ4_TRAVIS_CI_ENV=test-lz4c32
|
||||
- LZ4_TRAVIS_CI_ENV=test-fullbench
|
||||
- LZ4_TRAVIS_CI_ENV=test-fullbench32
|
||||
- LZ4_TRAVIS_CI_ENV=test-fuzzer
|
||||
- LZ4_TRAVIS_CI_ENV=test-fuzzer32
|
||||
- LZ4_TRAVIS_CI_ENV=test-frametest
|
||||
- LZ4_TRAVIS_CI_ENV=test-frametest32
|
||||
- LZ4_TRAVIS_CI_ENV=test-mem
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
1
src/lz4/LZ4_Frame_Format.html
Normal file
136
src/lz4/Makefile
Normal file
@@ -0,0 +1,136 @@
|
||||
# ################################################################
|
||||
# LZ4 - Makefile
|
||||
# Copyright (C) Yann Collet 2011-2015
|
||||
# All rights reserved.
|
||||
#
|
||||
# BSD license
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# * Redistributions in binary form must reproduce the above copyright notice, this
|
||||
# list of conditions and the following disclaimer in the documentation and/or
|
||||
# other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# You can contact the author at :
|
||||
# - LZ4 source repository : http://code.google.com/p/lz4/
|
||||
# - LZ4 forum froup : https://groups.google.com/forum/#!forum/lz4c
|
||||
# ################################################################
|
||||
|
||||
# Version number
|
||||
export VERSION=126
|
||||
export RELEASE=r$(VERSION)
|
||||
|
||||
DESTDIR?=
|
||||
PREFIX ?= /usr
|
||||
|
||||
LIBDIR ?= $(PREFIX)/lib
|
||||
INCLUDEDIR=$(PREFIX)/include
|
||||
PRGDIR = programs
|
||||
LZ4DIR = lib
|
||||
DISTRIBNAME=lz4-$(RELEASE).tar.gz
|
||||
|
||||
TEXT = $(LZ4DIR)/lz4.c $(LZ4DIR)/lz4.h $(LZ4DIR)/lz4hc.c $(LZ4DIR)/lz4hc.h \
|
||||
$(LZ4DIR)/lz4frame.c $(LZ4DIR)/lz4frame.h $(LZ4DIR)/lz4frame_static.h \
|
||||
$(LZ4DIR)/xxhash.c $(LZ4DIR)/xxhash.h \
|
||||
$(LZ4DIR)/liblz4.pc.in $(LZ4DIR)/Makefile $(LZ4DIR)/LICENSE \
|
||||
Makefile lz4_block_format.txt LZ4_Frame_Format.html NEWS README.md \
|
||||
cmake_unofficial/CMakeLists.txt \
|
||||
$(PRGDIR)/fullbench.c $(PRGDIR)/lz4cli.c \
|
||||
$(PRGDIR)/datagen.c $(PRGDIR)/fuzzer.c \
|
||||
$(PRGDIR)/lz4io.c $(PRGDIR)/lz4io.h \
|
||||
$(PRGDIR)/bench.c $(PRGDIR)/bench.h \
|
||||
$(PRGDIR)/lz4.1 $(PRGDIR)/lz4c.1 $(PRGDIR)/lz4cat.1 \
|
||||
$(PRGDIR)/Makefile $(PRGDIR)/COPYING
|
||||
NONTEXT = images/image00.png images/image01.png images/image02.png \
|
||||
images/image03.png images/image04.png images/image05.png \
|
||||
images/image06.png
|
||||
SOURCES = $(TEXT) $(NONTEXT)
|
||||
|
||||
|
||||
# Select test target for Travis CI's Build Matrix
|
||||
ifneq (,$(filter test-%,$(LZ4_TRAVIS_CI_ENV)))
|
||||
TRAVIS_TARGET=prg-travis
|
||||
else
|
||||
TRAVIS_TARGET=$(LZ4_TRAVIS_CI_ENV)
|
||||
endif
|
||||
|
||||
|
||||
default: lz4programs
|
||||
|
||||
all:
|
||||
@cd $(LZ4DIR); $(MAKE) -e all
|
||||
@cd $(PRGDIR); $(MAKE) -e all
|
||||
|
||||
lz4programs:
|
||||
@cd $(PRGDIR); $(MAKE) -e
|
||||
|
||||
clean:
|
||||
@rm -f $(DISTRIBNAME) *.sha1
|
||||
@cd $(PRGDIR); $(MAKE) clean
|
||||
@cd $(LZ4DIR); $(MAKE) clean
|
||||
@cd examples; $(MAKE) clean
|
||||
@echo Cleaning completed
|
||||
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#make install is validated only for Linux, OSX, kFreeBSD and Hurd targets
|
||||
ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU))
|
||||
|
||||
install:
|
||||
@cd $(LZ4DIR); $(MAKE) -e install
|
||||
@cd $(PRGDIR); $(MAKE) -e install
|
||||
|
||||
uninstall:
|
||||
@cd $(LZ4DIR); $(MAKE) uninstall
|
||||
@cd $(PRGDIR); $(MAKE) uninstall
|
||||
|
||||
travis-install:
|
||||
sudo $(MAKE) install
|
||||
|
||||
dist: clean
|
||||
@install -dD -m 700 lz4-$(RELEASE)/lib/
|
||||
@install -dD -m 700 lz4-$(RELEASE)/programs/
|
||||
@install -dD -m 700 lz4-$(RELEASE)/cmake_unofficial/
|
||||
@install -dD -m 700 lz4-$(RELEASE)/images/
|
||||
@for f in $(TEXT); do \
|
||||
tr -d '\r' < $$f > .tmp; \
|
||||
install -m 600 .tmp lz4-$(RELEASE)/$$f; \
|
||||
done
|
||||
@rm .tmp
|
||||
@for f in $(NONTEXT); do \
|
||||
install -m 600 $$f lz4-$(RELEASE)/$$f; \
|
||||
done
|
||||
@tar -czf $(DISTRIBNAME) lz4-$(RELEASE)/
|
||||
@rm -rf lz4-$(RELEASE)
|
||||
@sha1sum $(DISTRIBNAME) > $(DISTRIBNAME).sha1
|
||||
@echo Distribution $(DISTRIBNAME) built
|
||||
|
||||
test:
|
||||
@cd $(PRGDIR); $(MAKE) -e test
|
||||
|
||||
test-travis: $(TRAVIS_TARGET)
|
||||
|
||||
cmake:
|
||||
@cd cmake_unofficial; cmake CMakeLists.txt; $(MAKE)
|
||||
|
||||
streaming-examples:
|
||||
cd examples; $(MAKE) -e test
|
||||
|
||||
prg-travis:
|
||||
@cd $(PRGDIR); $(MAKE) -e test-travis
|
||||
|
||||
endif
|
||||
133
src/lz4/NEWS
Normal file
@@ -0,0 +1,133 @@
|
||||
r126:
|
||||
New : lz4frame API is now integrated into liblz4
|
||||
Fixed : GCC 4.9 bug on highest performance settings, reported by Greg Slazinski
|
||||
Fixed : bug within LZ4 HC streaming mode, reported by James Boyle
|
||||
Fixed : older compiler don't like nameless unions, reported by Cheyi Lin
|
||||
Changed : lz4 is C90 compatible
|
||||
Changed : added -pedantic option, fixed a few mminor warnings
|
||||
|
||||
r125:
|
||||
Changed : endian and alignment code
|
||||
Changed : directory structure : new "lib" directory
|
||||
Updated : lz4io, now uses lz4frame
|
||||
Improved: slightly improved decoding speed
|
||||
Fixed : LZ4_compress_limitedOutput(); Special thanks to Christopher Speller !
|
||||
Fixed : some alignment warnings under clang
|
||||
Fixed : deprecated function LZ4_slideInputBufferHC()
|
||||
|
||||
r124:
|
||||
New : LZ4 HC streaming mode
|
||||
Fixed : LZ4F_compressBound() using null preferencesPtr
|
||||
Updated : xxHash to r38
|
||||
Updated library number, to 1.4.0
|
||||
|
||||
r123:
|
||||
Added : experimental lz4frame API, thanks to Takayuki Matsuoka and Christopher Jackson for testings
|
||||
Fix : s390x support, thanks to Nobuhiro Iwamatsu
|
||||
Fix : test mode (-t) no longer requires confirmation, thanks to Thary Nguyen
|
||||
|
||||
r122:
|
||||
Fix : AIX & AIX64 support (SamG)
|
||||
Fix : mips 64-bits support (lew van)
|
||||
Added : Examples directory, using code examples from Takayuki Matsuoka
|
||||
Updated : Framing specification, to v1.4.1
|
||||
Updated : xxHash, to r36
|
||||
|
||||
r121:
|
||||
Added : Makefile : install for kFreeBSD and Hurd (Nobuhiro Iwamatsu)
|
||||
Fix : Makefile : install for OS-X and BSD, thanks to Takayuki Matsuoka
|
||||
|
||||
r120:
|
||||
Modified : Streaming API, using strong types
|
||||
Added : LZ4_versionNumber(), thanks to Takayuki Matsuoka
|
||||
Fix : OS-X : library install name, thanks to Clemens Lang
|
||||
Updated : Makefile : synchronize library version number with lz4.h, thanks to Takayuki Matsuoka
|
||||
Updated : Makefile : stricter compilation flags
|
||||
Added : pkg-config, thanks to Zbigniew Jędrzejewski-Szmek (issue 135)
|
||||
Makefile : lz4-test only test native binaries, as suggested by Michał Górny (issue 136)
|
||||
Updated : xxHash to r35
|
||||
|
||||
r119:
|
||||
Fix : Issue 134 : extended malicious address space overflow in 32-bits mode for some specific configurations
|
||||
|
||||
r118:
|
||||
New : LZ4 Streaming API (Fast version), special thanks to Takayuki Matsuoka
|
||||
New : datagen : parametrable synthetic data generator for tests
|
||||
Improved : fuzzer, support more test cases, more parameters, ability to jump to specific test
|
||||
fix : support ppc64le platform (issue 131)
|
||||
fix : Issue 52 (malicious address space overflow in 32-bits mode when using large custom format)
|
||||
fix : Makefile : minor issue 130 : header files permissions
|
||||
|
||||
r117:
|
||||
Added : man pages for lz4c and lz4cat
|
||||
Added : automated tests on Travis, thanks to Takayuki Matsuoka !
|
||||
fix : block-dependency command line (issue 127)
|
||||
fix : lz4fullbench (issue 128)
|
||||
|
||||
r116:
|
||||
hotfix (issue 124 & 125)
|
||||
|
||||
r115:
|
||||
Added : lz4cat utility, installed on POSX systems (issue 118)
|
||||
OS-X compatible compilation of dynamic library (issue 115)
|
||||
|
||||
r114:
|
||||
Makefile : library correctly compiled with -O3 switch (issue 114)
|
||||
Makefile : library compilation compatible with clang
|
||||
Makefile : library is versioned and linked (issue 119)
|
||||
lz4.h : no more static inline prototypes (issue 116)
|
||||
man : improved header/footer (issue 111)
|
||||
Makefile : Use system default $(CC) & $(MAKE) variables (issue 112)
|
||||
xxhash : updated to r34
|
||||
|
||||
r113:
|
||||
Large decompression speed improvement for GCC 32-bits. Thanks to Valery Croizier !
|
||||
LZ4HC : Compression Level is now a programmable parameter (CLI from 4 to 9)
|
||||
Separated IO routines from command line (lz4io.c)
|
||||
Version number into lz4.h (suggested by Francesc Alted)
|
||||
|
||||
r112:
|
||||
quickfix
|
||||
|
||||
r111 :
|
||||
Makefile : added capability to install libraries
|
||||
Modified Directory tree, to better separate libraries from programs.
|
||||
|
||||
r110 :
|
||||
lz4 & lz4hc : added capability to allocate state & stream state with custom allocator (issue 99)
|
||||
fuzzer & fullbench : updated to test new functions
|
||||
man : documented -l command (Legacy format, for Linux kernel compression) (issue 102)
|
||||
cmake : improved version by Mika Attila, building programs and libraries (issue 100)
|
||||
xxHash : updated to r33
|
||||
Makefile : clean also delete local package .tar.gz
|
||||
|
||||
r109 :
|
||||
lz4.c : corrected issue 98 (LZ4_compress_limitedOutput())
|
||||
Makefile : can specify version number from makefile
|
||||
|
||||
r108 :
|
||||
lz4.c : corrected compression efficiency issue 97 in 64-bits chained mode (-BD) for streams > 4 GB (thanks Roman Strashkin for reporting)
|
||||
|
||||
r107 :
|
||||
Makefile : support DESTDIR for staged installs. Thanks Jorge Aparicio.
|
||||
Makefile : make install installs both lz4 and lz4c (Jorge Aparicio)
|
||||
Makefile : removed -Wno-implicit-declaration compilation switch
|
||||
lz4cli.c : include <stduni.h> for isatty() (Luca Barbato)
|
||||
lz4.h : introduced LZ4_MAX_INPUT_SIZE constant (Shay Green)
|
||||
lz4.h : LZ4_compressBound() : unified macro and inline definitions (Shay Green)
|
||||
lz4.h : LZ4_decompressSafe_partial() : clarify comments (Shay Green)
|
||||
lz4.c : LZ4_compress() verify input size condition (Shay Green)
|
||||
bench.c : corrected a bug in free memory size evaluation
|
||||
cmake : install into bin/ directory (Richard Yao)
|
||||
cmake : check for just C compiler (Elan Ruusamae)
|
||||
|
||||
r106 :
|
||||
Makefile : make dist modify text files in the package to respect Unix EoL convention
|
||||
lz4cli.c : corrected small display bug in HC mode
|
||||
|
||||
r105 :
|
||||
Makefile : New install script and man page, contributed by Prasad Pandit
|
||||
lz4cli.c : Minor modifications, for easier extensibility
|
||||
COPYING : added license file
|
||||
LZ4_Streaming_Format.odt : modified file name to remove white space characters
|
||||
Makefile : .exe suffix now properly added only for Windows target
|
||||
56
src/lz4/README.md
Normal file
@@ -0,0 +1,56 @@
|
||||
LZ4 - Extremely fast compression
|
||||
================================
|
||||
|
||||
LZ4 is lossless compression algorithm, providing compression speed at 400 MB/s per core, scalable with multi-cores CPU. It also features an extremely fast decoder, with speed in multiple GB/s per core, typically reaching RAM speed limits on multi-core systems.
|
||||
A high compression derivative, called LZ4_HC, is also provided. It trades CPU time for compression ratio.
|
||||
|
||||
|Branch |Status |
|
||||
|------------|---------|
|
||||
|master | [](https://travis-ci.org/Cyan4973/lz4) |
|
||||
|dev | [](https://travis-ci.org/Cyan4973/lz4) |
|
||||
|
||||
This is an official mirror of LZ4 project, [hosted on Google Code](http://code.google.com/p/lz4/).
|
||||
The intention is to offer github's capabilities to lz4 users, such as cloning, branch, pull requests or source download.
|
||||
|
||||
The "master" branch will reflect, the status of lz4 at its official homepage.
|
||||
The "dev" branch is the one where all contributions will be merged. If you plan to propose a patch, please commit into the "dev" branch. Direct commit to "master" are not permitted.
|
||||
Feature branches will also exist, typically to introduce new requirements, and be temporarily available for testing before merge into "dev" branch.
|
||||
|
||||
|
||||
Benchmarks
|
||||
-------------------------
|
||||
|
||||
The benchmark uses the [Open-Source Benchmark program by m^2 (v0.14.2)](http://encode.ru/threads/1371-Filesystem-benchmark?p=33548&viewfull=1#post33548) compiled with GCC v4.6.1 on Linux Ubuntu 64-bits v11.10,
|
||||
The reference system uses a Core i5-3340M @2.7GHz.
|
||||
Benchmark evaluates the compression of reference [Silesia Corpus](http://sun.aei.polsl.pl/~sdeor/index.php?page=silesia) in single-thread mode.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Compressor</th><th>Ratio</th><th>Compression</th><th>Decompression</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>LZ4 (r101)</th><th>2.084</th><th>422 MB/s</th><th>1820 MB/s</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>LZO 2.06</th><th>2.106</th><th>414 MB/s</th><th>600 MB/s</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>QuickLZ 1.5.1b6</th><th>2.237</th><th>373 MB/s</th><th>420 MB/s</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Snappy 1.1.0</th><th>2.091</th><th>323 MB/s</th><th>1070 MB/s</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>LZF</th><th>2.077</th><th>270 MB/s</th><th>570 MB/s</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>zlib 1.2.8 -1</th><th>2.730</th><th>65 MB/s</th><th>280 MB/s</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>LZ4 HC (r101)</th><th>2.720</th><th>25 MB/s</th><th>2080 MB/s</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>zlib 1.2.8 -6</th><th>3.099</th><th>21 MB/s</th><th>300 MB/s</th>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
82
src/lz4/cmake_unofficial/CMakeLists.txt
Normal file
@@ -0,0 +1,82 @@
|
||||
PROJECT(LZ4 C)
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "LZ4 compression library")
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR 1)
|
||||
set(CPACK_PACKAGE_VERSION_MINOR 5)
|
||||
set(CPACK_PACKAGE_VERSION_PATCH r126)
|
||||
set(VERSION_STRING " \"${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}\" ")
|
||||
include(CPack)
|
||||
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
INCLUDE (CheckTypeSize)
|
||||
check_type_size("void *" SIZEOF_VOID_P)
|
||||
IF( ${SIZEOF_VOID_P} STREQUAL "8" )
|
||||
set (CMAKE_SYSTEM_PROCESSOR "64bit")
|
||||
MESSAGE( STATUS "64 bit architecture detected size of void * is " ${SIZEOF_VOID_P})
|
||||
ENDIF()
|
||||
|
||||
option(BUILD_TOOLS "Build the command line tools" ON)
|
||||
option(BUILD_LIBS "Build the libraries in addition to the tools" OFF)
|
||||
|
||||
if(UNIX AND BUILD_LIBS)
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
|
||||
add_definitions(-fPIC)
|
||||
endif(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
|
||||
endif()
|
||||
|
||||
set(LZ4_DIR ../lib/)
|
||||
set(PRG_DIR ../programs/)
|
||||
set(LZ4_SRCS_LIB ${LZ4_DIR}lz4.c ${LZ4_DIR}lz4hc.c ${LZ4_DIR}lz4.h ${LZ4_DIR}lz4hc.h)
|
||||
set(LZ4_SRCS ${LZ4_DIR}lz4frame.c ${LZ4_DIR}xxhash.c ${PRG_DIR}bench.c ${PRG_DIR}lz4cli.c ${PRG_DIR}lz4io.c)
|
||||
|
||||
if(BUILD_TOOLS AND NOT BUILD_LIBS)
|
||||
set(LZ4_SRCS ${LZ4_SRCS} ${LZ4_SRCS_LIB})
|
||||
endif()
|
||||
|
||||
if(BUILD_TOOLS)
|
||||
add_executable(lz4 ${LZ4_SRCS})
|
||||
set_target_properties(lz4 PROPERTIES COMPILE_DEFINITIONS DISABLE_LZ4C_LEGACY_OPTIONS)
|
||||
install(TARGETS lz4 RUNTIME DESTINATION "bin/")
|
||||
add_executable(lz4c ${LZ4_SRCS})
|
||||
install(TARGETS lz4c RUNTIME DESTINATION "bin/")
|
||||
endif()
|
||||
|
||||
if(BUILD_LIBS)
|
||||
add_library(liblz4 ${LZ4_SRCS_LIB})
|
||||
|
||||
set_target_properties(liblz4 PROPERTIES
|
||||
OUTPUT_NAME lz4
|
||||
SOVERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}"
|
||||
)
|
||||
|
||||
install(TARGETS liblz4
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
)
|
||||
|
||||
install(FILES
|
||||
${LZ4_DIR}/lz4.h
|
||||
${LZ4_DIR}/lz4hc.h
|
||||
DESTINATION include
|
||||
)
|
||||
|
||||
if(BUILD_TOOLS)
|
||||
target_link_libraries(lz4 liblz4)
|
||||
target_link_libraries(lz4c liblz4)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
#warnings
|
||||
|
||||
ADD_DEFINITIONS("-Wall")
|
||||
ADD_DEFINITIONS("-Wextra")
|
||||
ADD_DEFINITIONS("-Wundef")
|
||||
ADD_DEFINITIONS("-Wshadow")
|
||||
ADD_DEFINITIONS("-Wcast-align")
|
||||
ADD_DEFINITIONS("-Wstrict-prototypes")
|
||||
ADD_DEFINITIONS("-std=c99")
|
||||
ADD_DEFINITIONS("-DLZ4_VERSION=\"${CPACK_PACKAGE_VERSION_PATCH}\"")
|
||||
INCLUDE_DIRECTORIES (${LZ4_DIR})
|
||||
|
||||
|
||||
|
||||
239
src/lz4/examples/HCStreaming_ringBuffer.c
Executable file
@@ -0,0 +1,239 @@
|
||||
// LZ4 HC streaming API example : ring buffer
|
||||
// Based on previous work from Takayuki Matsuoka
|
||||
|
||||
|
||||
/**************************************
|
||||
* Compiler Options
|
||||
**************************************/
|
||||
#ifdef _MSC_VER /* Visual Studio */
|
||||
# define _CRT_SECURE_NO_WARNINGS // for MSVC
|
||||
# define snprintf sprintf_s
|
||||
#endif
|
||||
|
||||
#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC diagnostic ignored "-Wmissing-braces" /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************
|
||||
* Includes
|
||||
**************************************/
|
||||
#include "lz4hc.h"
|
||||
#include "lz4.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
enum {
|
||||
MESSAGE_MAX_BYTES = 1024,
|
||||
RING_BUFFER_BYTES = 1024 * 8 + MESSAGE_MAX_BYTES,
|
||||
DEC_BUFFER_BYTES = RING_BUFFER_BYTES + MESSAGE_MAX_BYTES // Intentionally larger to test unsynchronized ring buffers
|
||||
};
|
||||
|
||||
|
||||
size_t write_int32(FILE* fp, int32_t i) {
|
||||
return fwrite(&i, sizeof(i), 1, fp);
|
||||
}
|
||||
|
||||
size_t write_bin(FILE* fp, const void* array, int arrayBytes) {
|
||||
return fwrite(array, 1, arrayBytes, fp);
|
||||
}
|
||||
|
||||
size_t read_int32(FILE* fp, int32_t* i) {
|
||||
return fread(i, sizeof(*i), 1, fp);
|
||||
}
|
||||
|
||||
size_t read_bin(FILE* fp, void* array, int arrayBytes) {
|
||||
return fread(array, 1, arrayBytes, fp);
|
||||
}
|
||||
|
||||
|
||||
void test_compress(FILE* outFp, FILE* inpFp)
|
||||
{
|
||||
LZ4_streamHC_t lz4Stream_body = { 0 };
|
||||
LZ4_streamHC_t* lz4Stream = &lz4Stream_body;
|
||||
|
||||
static char inpBuf[RING_BUFFER_BYTES];
|
||||
int inpOffset = 0;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
// Read random length ([1,MESSAGE_MAX_BYTES]) data to the ring buffer.
|
||||
char* const inpPtr = &inpBuf[inpOffset];
|
||||
const int randomLength = (rand() % MESSAGE_MAX_BYTES) + 1;
|
||||
const int inpBytes = (int) read_bin(inpFp, inpPtr, randomLength);
|
||||
if (0 == inpBytes) break;
|
||||
|
||||
{
|
||||
char cmpBuf[LZ4_COMPRESSBOUND(MESSAGE_MAX_BYTES)];
|
||||
const int cmpBytes = LZ4_compressHC_continue(lz4Stream, inpPtr, cmpBuf, inpBytes);
|
||||
|
||||
if(cmpBytes <= 0) break;
|
||||
write_int32(outFp, cmpBytes);
|
||||
write_bin(outFp, cmpBuf, cmpBytes);
|
||||
|
||||
inpOffset += inpBytes;
|
||||
|
||||
// Wraparound the ringbuffer offset
|
||||
if(inpOffset >= RING_BUFFER_BYTES - MESSAGE_MAX_BYTES)
|
||||
inpOffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
write_int32(outFp, 0);
|
||||
}
|
||||
|
||||
|
||||
void test_decompress(FILE* outFp, FILE* inpFp)
|
||||
{
|
||||
static char decBuf[DEC_BUFFER_BYTES];
|
||||
int decOffset = 0;
|
||||
LZ4_streamDecode_t lz4StreamDecode_body = { 0 };
|
||||
LZ4_streamDecode_t* lz4StreamDecode = &lz4StreamDecode_body;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
int cmpBytes = 0;
|
||||
char cmpBuf[LZ4_COMPRESSBOUND(MESSAGE_MAX_BYTES)];
|
||||
|
||||
{
|
||||
const size_t r0 = read_int32(inpFp, &cmpBytes);
|
||||
size_t r1;
|
||||
if(r0 != 1 || cmpBytes <= 0)
|
||||
break;
|
||||
|
||||
r1 = read_bin(inpFp, cmpBuf, cmpBytes);
|
||||
if(r1 != (size_t) cmpBytes)
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
char* const decPtr = &decBuf[decOffset];
|
||||
const int decBytes = LZ4_decompress_safe_continue(
|
||||
lz4StreamDecode, cmpBuf, decPtr, cmpBytes, MESSAGE_MAX_BYTES);
|
||||
if(decBytes <= 0)
|
||||
break;
|
||||
|
||||
decOffset += decBytes;
|
||||
write_bin(outFp, decPtr, decBytes);
|
||||
|
||||
// Wraparound the ringbuffer offset
|
||||
if(decOffset >= DEC_BUFFER_BYTES - MESSAGE_MAX_BYTES)
|
||||
decOffset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Compare 2 files content
|
||||
// return 0 if identical
|
||||
// return ByteNb>0 if different
|
||||
size_t compare(FILE* f0, FILE* f1)
|
||||
{
|
||||
size_t result = 1;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
char b0[65536];
|
||||
char b1[65536];
|
||||
const size_t r0 = fread(b0, 1, sizeof(b0), f0);
|
||||
const size_t r1 = fread(b1, 1, sizeof(b1), f1);
|
||||
|
||||
if ((r0==0) && (r1==0)) return 0; // success
|
||||
|
||||
if (r0 != r1)
|
||||
{
|
||||
size_t smallest = r0;
|
||||
if (r1<r0) smallest = r1;
|
||||
result += smallest;
|
||||
break;
|
||||
}
|
||||
|
||||
if (memcmp(b0, b1, r0))
|
||||
{
|
||||
unsigned errorPos = 0;
|
||||
while ((errorPos < r0) && (b0[errorPos]==b1[errorPos])) errorPos++;
|
||||
result += errorPos;
|
||||
break;
|
||||
}
|
||||
|
||||
result += sizeof(b0);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
char inpFilename[256] = { 0 };
|
||||
char lz4Filename[256] = { 0 };
|
||||
char decFilename[256] = { 0 };
|
||||
unsigned fileID = 1;
|
||||
unsigned pause = 0;
|
||||
|
||||
|
||||
if(argc < 2) {
|
||||
printf("Please specify input filename\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "-p")) pause = 1, fileID = 2;
|
||||
|
||||
snprintf(inpFilename, 256, "%s", argv[fileID]);
|
||||
snprintf(lz4Filename, 256, "%s.lz4s-%d", argv[fileID], 9);
|
||||
snprintf(decFilename, 256, "%s.lz4s-%d.dec", argv[fileID], 9);
|
||||
|
||||
printf("input = [%s]\n", inpFilename);
|
||||
printf("lz4 = [%s]\n", lz4Filename);
|
||||
printf("decoded = [%s]\n", decFilename);
|
||||
|
||||
// compress
|
||||
{
|
||||
FILE* inpFp = fopen(inpFilename, "rb");
|
||||
FILE* outFp = fopen(lz4Filename, "wb");
|
||||
|
||||
test_compress(outFp, inpFp);
|
||||
|
||||
fclose(outFp);
|
||||
fclose(inpFp);
|
||||
}
|
||||
|
||||
// decompress
|
||||
{
|
||||
FILE* inpFp = fopen(lz4Filename, "rb");
|
||||
FILE* outFp = fopen(decFilename, "wb");
|
||||
|
||||
test_decompress(outFp, inpFp);
|
||||
|
||||
fclose(outFp);
|
||||
fclose(inpFp);
|
||||
}
|
||||
|
||||
// verify
|
||||
{
|
||||
FILE* inpFp = fopen(inpFilename, "rb");
|
||||
FILE* decFp = fopen(decFilename, "rb");
|
||||
|
||||
const size_t cmp = compare(inpFp, decFp);
|
||||
if(0 == cmp) {
|
||||
printf("Verify : OK\n");
|
||||
} else {
|
||||
printf("Verify : NG : error at pos %u\n", (unsigned)cmp-1);
|
||||
}
|
||||
|
||||
fclose(decFp);
|
||||
fclose(inpFp);
|
||||
}
|
||||
|
||||
if (pause)
|
||||
{
|
||||
printf("Press enter to continue ...\n");
|
||||
getchar();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
89
src/lz4/examples/Makefile
Normal file
@@ -0,0 +1,89 @@
|
||||
# ##########################################################################
|
||||
# LZ4 examples - Makefile
|
||||
# Copyright (C) Yann Collet 2011-2014
|
||||
# GPL v2 License
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# You can contact the author at :
|
||||
# - LZ4 source repository : http://code.google.com/p/lz4/
|
||||
# - LZ4 forum froup : https://groups.google.com/forum/#!forum/lz4c
|
||||
# ##########################################################################
|
||||
# lz4 : Command Line Utility, supporting gzip-like arguments
|
||||
# lz4c : CLU, supporting also legacy lz4demo arguments
|
||||
# lz4c32: Same as lz4c, but forced to compile in 32-bits mode
|
||||
# fuzzer : Test tool, to check lz4 integrity on target platform
|
||||
# fuzzer32: Same as fuzzer, but forced to compile in 32-bits mode
|
||||
# fullbench : Precisely measure speed for each LZ4 function variant
|
||||
# fullbench32: Same as fullbench, but forced to compile in 32-bits mode
|
||||
# ##########################################################################
|
||||
|
||||
CC := $(CC)
|
||||
CFLAGS ?= -O3
|
||||
CFLAGS += -std=c99 -Wall -Wextra -Wundef -Wshadow -Wcast-align -Wstrict-prototypes -Wno-missing-braces # Wno-missing-braces required due to GCC <4.8.3 bug
|
||||
FLAGS = -I../lib $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)
|
||||
|
||||
TESTFILE= Makefile
|
||||
LZ4DIR = ../lib
|
||||
|
||||
|
||||
# Minimize test target for Travis CI's Build Matrix
|
||||
ifeq ($(LZ4_TRAVIS_CI_ENV),-m32)
|
||||
CFLAGS += -m32
|
||||
else ifeq ($(LZ4_TRAVIS_CI_ENV),-m64)
|
||||
endif
|
||||
|
||||
|
||||
# Define *.exe as extension for Windows systems
|
||||
ifneq (,$(filter Windows%,$(OS)))
|
||||
EXT =.exe
|
||||
VOID = nul
|
||||
else
|
||||
EXT =
|
||||
VOID = /dev/null
|
||||
endif
|
||||
|
||||
|
||||
default: all
|
||||
|
||||
all: printVersion doubleBuffer ringBuffer ringBufferHC lineCompress
|
||||
|
||||
printVersion: $(LZ4DIR)/lz4.c printVersion.c
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
doubleBuffer: $(LZ4DIR)/lz4.c blockStreaming_doubleBuffer.c
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
ringBuffer : $(LZ4DIR)/lz4.c blockStreaming_ringBuffer.c
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
ringBufferHC: $(LZ4DIR)/lz4.c $(LZ4DIR)/lz4hc.c HCStreaming_ringBuffer.c
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
lineCompress: $(LZ4DIR)/lz4.c blockStreaming_lineByLine.c
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
test : all
|
||||
./printVersion$(EXT)
|
||||
./doubleBuffer$(EXT) $(TESTFILE)
|
||||
./ringBuffer$(EXT) $(TESTFILE)
|
||||
./ringBufferHC$(EXT) $(TESTFILE)
|
||||
./lineCompress$(EXT) $(TESTFILE)
|
||||
|
||||
clean:
|
||||
@rm -f core *.o *.dec *-0 *-9 *-8192 *.lz4s \
|
||||
printVersion$(EXT) doubleBuffer$(EXT) ringBuffer$(EXT) ringBufferHC$(EXT) lineCompress$(EXT)
|
||||
@echo Cleaning completed
|
||||
|
||||
195
src/lz4/examples/blockStreaming_doubleBuffer.c
Normal file
@@ -0,0 +1,195 @@
|
||||
// LZ4 streaming API example : double buffer
|
||||
// Copyright : Takayuki Matsuoka
|
||||
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS // for MSVC
|
||||
#include "lz4.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
enum {
|
||||
BLOCK_BYTES = 1024 * 8,
|
||||
// BLOCK_BYTES = 1024 * 64,
|
||||
};
|
||||
|
||||
|
||||
size_t write_int(FILE* fp, int i) {
|
||||
return fwrite(&i, sizeof(i), 1, fp);
|
||||
}
|
||||
|
||||
size_t write_bin(FILE* fp, const void* array, size_t arrayBytes) {
|
||||
return fwrite(array, 1, arrayBytes, fp);
|
||||
}
|
||||
|
||||
size_t read_int(FILE* fp, int* i) {
|
||||
return fread(i, sizeof(*i), 1, fp);
|
||||
}
|
||||
|
||||
size_t read_bin(FILE* fp, void* array, size_t arrayBytes) {
|
||||
return fread(array, 1, arrayBytes, fp);
|
||||
}
|
||||
|
||||
|
||||
void test_compress(FILE* outFp, FILE* inpFp)
|
||||
{
|
||||
LZ4_stream_t lz4Stream_body = { 0 };
|
||||
LZ4_stream_t* lz4Stream = &lz4Stream_body;
|
||||
|
||||
char inpBuf[2][BLOCK_BYTES];
|
||||
int inpBufIndex = 0;
|
||||
|
||||
for(;;) {
|
||||
char* const inpPtr = inpBuf[inpBufIndex];
|
||||
const int inpBytes = (int) read_bin(inpFp, inpPtr, BLOCK_BYTES);
|
||||
if(0 == inpBytes) {
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
char cmpBuf[LZ4_COMPRESSBOUND(BLOCK_BYTES)];
|
||||
const int cmpBytes = LZ4_compress_continue(
|
||||
lz4Stream, inpPtr, cmpBuf, inpBytes);
|
||||
if(cmpBytes <= 0) {
|
||||
break;
|
||||
}
|
||||
write_int(outFp, cmpBytes);
|
||||
write_bin(outFp, cmpBuf, (size_t) cmpBytes);
|
||||
}
|
||||
|
||||
inpBufIndex = (inpBufIndex + 1) % 2;
|
||||
}
|
||||
|
||||
write_int(outFp, 0);
|
||||
}
|
||||
|
||||
|
||||
void test_decompress(FILE* outFp, FILE* inpFp)
|
||||
{
|
||||
LZ4_streamDecode_t lz4StreamDecode_body = { 0 };
|
||||
LZ4_streamDecode_t* lz4StreamDecode = &lz4StreamDecode_body;
|
||||
|
||||
char decBuf[2][BLOCK_BYTES];
|
||||
int decBufIndex = 0;
|
||||
|
||||
for(;;) {
|
||||
char cmpBuf[LZ4_COMPRESSBOUND(BLOCK_BYTES)];
|
||||
int cmpBytes = 0;
|
||||
|
||||
{
|
||||
const size_t readCount0 = read_int(inpFp, &cmpBytes);
|
||||
if(readCount0 != 1 || cmpBytes <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
const size_t readCount1 = read_bin(inpFp, cmpBuf, (size_t) cmpBytes);
|
||||
if(readCount1 != (size_t) cmpBytes) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
char* const decPtr = decBuf[decBufIndex];
|
||||
const int decBytes = LZ4_decompress_safe_continue(
|
||||
lz4StreamDecode, cmpBuf, decPtr, cmpBytes, BLOCK_BYTES);
|
||||
if(decBytes <= 0) {
|
||||
break;
|
||||
}
|
||||
write_bin(outFp, decPtr, (size_t) decBytes);
|
||||
}
|
||||
|
||||
decBufIndex = (decBufIndex + 1) % 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int compare(FILE* fp0, FILE* fp1)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
while(0 == result) {
|
||||
char b0[65536];
|
||||
char b1[65536];
|
||||
const size_t r0 = read_bin(fp0, b0, sizeof(b0));
|
||||
const size_t r1 = read_bin(fp1, b1, sizeof(b1));
|
||||
|
||||
result = (int) r0 - (int) r1;
|
||||
|
||||
if(0 == r0 || 0 == r1) {
|
||||
break;
|
||||
}
|
||||
if(0 == result) {
|
||||
result = memcmp(b0, b1, r0);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
char inpFilename[256] = { 0 };
|
||||
char lz4Filename[256] = { 0 };
|
||||
char decFilename[256] = { 0 };
|
||||
|
||||
if(argc < 2) {
|
||||
printf("Please specify input filename\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
snprintf(inpFilename, 256, "%s", argv[1]);
|
||||
snprintf(lz4Filename, 256, "%s.lz4s-%d", argv[1], BLOCK_BYTES);
|
||||
snprintf(decFilename, 256, "%s.lz4s-%d.dec", argv[1], BLOCK_BYTES);
|
||||
|
||||
printf("inp = [%s]\n", inpFilename);
|
||||
printf("lz4 = [%s]\n", lz4Filename);
|
||||
printf("dec = [%s]\n", decFilename);
|
||||
|
||||
// compress
|
||||
{
|
||||
FILE* inpFp = fopen(inpFilename, "rb");
|
||||
FILE* outFp = fopen(lz4Filename, "wb");
|
||||
|
||||
printf("compress : %s -> %s\n", inpFilename, lz4Filename);
|
||||
test_compress(outFp, inpFp);
|
||||
printf("compress : done\n");
|
||||
|
||||
fclose(outFp);
|
||||
fclose(inpFp);
|
||||
}
|
||||
|
||||
// decompress
|
||||
{
|
||||
FILE* inpFp = fopen(lz4Filename, "rb");
|
||||
FILE* outFp = fopen(decFilename, "wb");
|
||||
|
||||
printf("decompress : %s -> %s\n", lz4Filename, decFilename);
|
||||
test_decompress(outFp, inpFp);
|
||||
printf("decompress : done\n");
|
||||
|
||||
fclose(outFp);
|
||||
fclose(inpFp);
|
||||
}
|
||||
|
||||
// verify
|
||||
{
|
||||
FILE* inpFp = fopen(inpFilename, "rb");
|
||||
FILE* decFp = fopen(decFilename, "rb");
|
||||
|
||||
printf("verify : %s <-> %s\n", inpFilename, decFilename);
|
||||
const int cmp = compare(inpFp, decFp);
|
||||
if(0 == cmp) {
|
||||
printf("verify : OK\n");
|
||||
} else {
|
||||
printf("verify : NG\n");
|
||||
}
|
||||
|
||||
fclose(decFp);
|
||||
fclose(inpFp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
207
src/lz4/examples/blockStreaming_lineByLine.c
Normal file
@@ -0,0 +1,207 @@
|
||||
// LZ4 streaming API example : line-by-line logfile compression
|
||||
// Copyright : Takayuki Matsuoka
|
||||
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS // for MSVC
|
||||
#include "lz4.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static size_t write_uint16(FILE* fp, uint16_t i)
|
||||
{
|
||||
return fwrite(&i, sizeof(i), 1, fp);
|
||||
}
|
||||
|
||||
static size_t write_bin(FILE* fp, const void* array, int arrayBytes)
|
||||
{
|
||||
return fwrite(array, 1, arrayBytes, fp);
|
||||
}
|
||||
|
||||
static size_t read_uint16(FILE* fp, uint16_t* i)
|
||||
{
|
||||
return fread(i, sizeof(*i), 1, fp);
|
||||
}
|
||||
|
||||
static size_t read_bin(FILE* fp, void* array, int arrayBytes)
|
||||
{
|
||||
return fread(array, 1, arrayBytes, fp);
|
||||
}
|
||||
|
||||
|
||||
static void test_compress(
|
||||
FILE* outFp,
|
||||
FILE* inpFp,
|
||||
size_t messageMaxBytes,
|
||||
size_t ringBufferBytes)
|
||||
{
|
||||
LZ4_stream_t* const lz4Stream = LZ4_createStream();
|
||||
char* const cmpBuf = malloc(LZ4_COMPRESSBOUND(messageMaxBytes));
|
||||
char* const inpBuf = malloc(ringBufferBytes);
|
||||
int inpOffset = 0;
|
||||
|
||||
for ( ; ; )
|
||||
{
|
||||
char* const inpPtr = &inpBuf[inpOffset];
|
||||
|
||||
#if 0
|
||||
// Read random length data to the ring buffer.
|
||||
const int randomLength = (rand() % messageMaxBytes) + 1;
|
||||
const int inpBytes = (int) read_bin(inpFp, inpPtr, randomLength);
|
||||
if (0 == inpBytes) break;
|
||||
#else
|
||||
// Read line to the ring buffer.
|
||||
int inpBytes = 0;
|
||||
if (!fgets(inpPtr, (int) messageMaxBytes, inpFp))
|
||||
break;
|
||||
inpBytes = (int) strlen(inpPtr);
|
||||
#endif
|
||||
|
||||
{
|
||||
const int cmpBytes = LZ4_compress_continue(
|
||||
lz4Stream, inpPtr, cmpBuf, inpBytes);
|
||||
if (cmpBytes <= 0) break;
|
||||
write_uint16(outFp, (uint16_t) cmpBytes);
|
||||
write_bin(outFp, cmpBuf, cmpBytes);
|
||||
|
||||
// Add and wraparound the ringbuffer offset
|
||||
inpOffset += inpBytes;
|
||||
if ((size_t)inpOffset >= ringBufferBytes - messageMaxBytes) inpOffset = 0;
|
||||
}
|
||||
}
|
||||
write_uint16(outFp, 0);
|
||||
|
||||
free(inpBuf);
|
||||
free(cmpBuf);
|
||||
LZ4_freeStream(lz4Stream);
|
||||
}
|
||||
|
||||
|
||||
static void test_decompress(
|
||||
FILE* outFp,
|
||||
FILE* inpFp,
|
||||
size_t messageMaxBytes,
|
||||
size_t ringBufferBytes)
|
||||
{
|
||||
LZ4_streamDecode_t* const lz4StreamDecode = LZ4_createStreamDecode();
|
||||
char* const cmpBuf = malloc(LZ4_COMPRESSBOUND(messageMaxBytes));
|
||||
char* const decBuf = malloc(ringBufferBytes);
|
||||
int decOffset = 0;
|
||||
|
||||
for ( ; ; )
|
||||
{
|
||||
uint16_t cmpBytes = 0;
|
||||
|
||||
if (read_uint16(inpFp, &cmpBytes) != 1) break;
|
||||
if (cmpBytes <= 0) break;
|
||||
if (read_bin(inpFp, cmpBuf, cmpBytes) != cmpBytes) break;
|
||||
|
||||
{
|
||||
char* const decPtr = &decBuf[decOffset];
|
||||
const int decBytes = LZ4_decompress_safe_continue(
|
||||
lz4StreamDecode, cmpBuf, decPtr, cmpBytes, (int) messageMaxBytes);
|
||||
if (decBytes <= 0) break;
|
||||
write_bin(outFp, decPtr, decBytes);
|
||||
|
||||
// Add and wraparound the ringbuffer offset
|
||||
decOffset += decBytes;
|
||||
if ((size_t)decOffset >= ringBufferBytes - messageMaxBytes) decOffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
free(decBuf);
|
||||
free(cmpBuf);
|
||||
LZ4_freeStreamDecode(lz4StreamDecode);
|
||||
}
|
||||
|
||||
|
||||
static int compare(FILE* f0, FILE* f1)
|
||||
{
|
||||
int result = 0;
|
||||
const size_t tempBufferBytes = 65536;
|
||||
char* const b0 = malloc(tempBufferBytes);
|
||||
char* const b1 = malloc(tempBufferBytes);
|
||||
|
||||
while(0 == result)
|
||||
{
|
||||
const size_t r0 = fread(b0, 1, tempBufferBytes, f0);
|
||||
const size_t r1 = fread(b1, 1, tempBufferBytes, f1);
|
||||
|
||||
result = (int) r0 - (int) r1;
|
||||
|
||||
if (0 == r0 || 0 == r1) break;
|
||||
if (0 == result) result = memcmp(b0, b1, r0);
|
||||
}
|
||||
|
||||
free(b1);
|
||||
free(b0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
enum {
|
||||
MESSAGE_MAX_BYTES = 1024,
|
||||
RING_BUFFER_BYTES = 1024 * 256 + MESSAGE_MAX_BYTES,
|
||||
};
|
||||
|
||||
char inpFilename[256] = { 0 };
|
||||
char lz4Filename[256] = { 0 };
|
||||
char decFilename[256] = { 0 };
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
printf("Please specify input filename\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
snprintf(inpFilename, 256, "%s", argv[1]);
|
||||
snprintf(lz4Filename, 256, "%s.lz4s", argv[1]);
|
||||
snprintf(decFilename, 256, "%s.lz4s.dec", argv[1]);
|
||||
|
||||
printf("inp = [%s]\n", inpFilename);
|
||||
printf("lz4 = [%s]\n", lz4Filename);
|
||||
printf("dec = [%s]\n", decFilename);
|
||||
|
||||
// compress
|
||||
{
|
||||
FILE* inpFp = fopen(inpFilename, "rb");
|
||||
FILE* outFp = fopen(lz4Filename, "wb");
|
||||
|
||||
test_compress(outFp, inpFp, MESSAGE_MAX_BYTES, RING_BUFFER_BYTES);
|
||||
|
||||
fclose(outFp);
|
||||
fclose(inpFp);
|
||||
}
|
||||
|
||||
// decompress
|
||||
{
|
||||
FILE* inpFp = fopen(lz4Filename, "rb");
|
||||
FILE* outFp = fopen(decFilename, "wb");
|
||||
|
||||
test_decompress(outFp, inpFp, MESSAGE_MAX_BYTES, RING_BUFFER_BYTES);
|
||||
|
||||
fclose(outFp);
|
||||
fclose(inpFp);
|
||||
}
|
||||
|
||||
// verify
|
||||
{
|
||||
FILE* inpFp = fopen(inpFilename, "rb");
|
||||
FILE* decFp = fopen(decFilename, "rb");
|
||||
|
||||
const int cmp = compare(inpFp, decFp);
|
||||
if (0 == cmp)
|
||||
printf("Verify : OK\n");
|
||||
else
|
||||
printf("Verify : NG\n");
|
||||
|
||||
fclose(decFp);
|
||||
fclose(inpFp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
200
src/lz4/examples/blockStreaming_ringBuffer.c
Normal file
@@ -0,0 +1,200 @@
|
||||
// LZ4 streaming API example : ring buffer
|
||||
// Based on sample code from Takayuki Matsuoka
|
||||
|
||||
|
||||
/**************************************
|
||||
* Compiler Options
|
||||
**************************************/
|
||||
#ifdef _MSC_VER /* Visual Studio */
|
||||
# define _CRT_SECURE_NO_WARNINGS // for MSVC
|
||||
# define snprintf sprintf_s
|
||||
#endif
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC diagnostic ignored "-Wmissing-braces" /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************
|
||||
* Includes
|
||||
**************************************/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "lz4.h"
|
||||
|
||||
|
||||
enum {
|
||||
MESSAGE_MAX_BYTES = 1024,
|
||||
RING_BUFFER_BYTES = 1024 * 8 + MESSAGE_MAX_BYTES,
|
||||
DECODE_RING_BUFFER = RING_BUFFER_BYTES + MESSAGE_MAX_BYTES // Intentionally larger, to test unsynchronized ring buffers
|
||||
};
|
||||
|
||||
|
||||
size_t write_int32(FILE* fp, int32_t i) {
|
||||
return fwrite(&i, sizeof(i), 1, fp);
|
||||
}
|
||||
|
||||
size_t write_bin(FILE* fp, const void* array, int arrayBytes) {
|
||||
return fwrite(array, 1, arrayBytes, fp);
|
||||
}
|
||||
|
||||
size_t read_int32(FILE* fp, int32_t* i) {
|
||||
return fread(i, sizeof(*i), 1, fp);
|
||||
}
|
||||
|
||||
size_t read_bin(FILE* fp, void* array, int arrayBytes) {
|
||||
return fread(array, 1, arrayBytes, fp);
|
||||
}
|
||||
|
||||
|
||||
void test_compress(FILE* outFp, FILE* inpFp)
|
||||
{
|
||||
LZ4_stream_t lz4Stream_body = { 0 };
|
||||
LZ4_stream_t* lz4Stream = &lz4Stream_body;
|
||||
|
||||
static char inpBuf[RING_BUFFER_BYTES];
|
||||
int inpOffset = 0;
|
||||
|
||||
for(;;) {
|
||||
// Read random length ([1,MESSAGE_MAX_BYTES]) data to the ring buffer.
|
||||
char* const inpPtr = &inpBuf[inpOffset];
|
||||
const int randomLength = (rand() % MESSAGE_MAX_BYTES) + 1;
|
||||
const int inpBytes = (int) read_bin(inpFp, inpPtr, randomLength);
|
||||
if (0 == inpBytes) break;
|
||||
|
||||
{
|
||||
char cmpBuf[LZ4_COMPRESSBOUND(MESSAGE_MAX_BYTES)];
|
||||
const int cmpBytes = LZ4_compress_continue(lz4Stream, inpPtr, cmpBuf, inpBytes);
|
||||
if(cmpBytes <= 0) break;
|
||||
write_int32(outFp, cmpBytes);
|
||||
write_bin(outFp, cmpBuf, cmpBytes);
|
||||
|
||||
inpOffset += inpBytes;
|
||||
|
||||
// Wraparound the ringbuffer offset
|
||||
if(inpOffset >= RING_BUFFER_BYTES - MESSAGE_MAX_BYTES) inpOffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
write_int32(outFp, 0);
|
||||
}
|
||||
|
||||
|
||||
void test_decompress(FILE* outFp, FILE* inpFp)
|
||||
{
|
||||
static char decBuf[DECODE_RING_BUFFER];
|
||||
int decOffset = 0;
|
||||
LZ4_streamDecode_t lz4StreamDecode_body = { 0 };
|
||||
LZ4_streamDecode_t* lz4StreamDecode = &lz4StreamDecode_body;
|
||||
|
||||
for(;;) {
|
||||
int cmpBytes = 0;
|
||||
char cmpBuf[LZ4_COMPRESSBOUND(MESSAGE_MAX_BYTES)];
|
||||
|
||||
{
|
||||
const size_t r0 = read_int32(inpFp, &cmpBytes);
|
||||
if(r0 != 1 || cmpBytes <= 0) break;
|
||||
|
||||
const size_t r1 = read_bin(inpFp, cmpBuf, cmpBytes);
|
||||
if(r1 != (size_t) cmpBytes) break;
|
||||
}
|
||||
|
||||
{
|
||||
char* const decPtr = &decBuf[decOffset];
|
||||
const int decBytes = LZ4_decompress_safe_continue(
|
||||
lz4StreamDecode, cmpBuf, decPtr, cmpBytes, MESSAGE_MAX_BYTES);
|
||||
if(decBytes <= 0) break;
|
||||
decOffset += decBytes;
|
||||
write_bin(outFp, decPtr, decBytes);
|
||||
|
||||
// Wraparound the ringbuffer offset
|
||||
if(decOffset >= DECODE_RING_BUFFER - MESSAGE_MAX_BYTES) decOffset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int compare(FILE* f0, FILE* f1)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
while(0 == result) {
|
||||
char b0[65536];
|
||||
char b1[65536];
|
||||
const size_t r0 = fread(b0, 1, sizeof(b0), f0);
|
||||
const size_t r1 = fread(b1, 1, sizeof(b1), f1);
|
||||
|
||||
result = (int) r0 - (int) r1;
|
||||
|
||||
if(0 == r0 || 0 == r1) {
|
||||
break;
|
||||
}
|
||||
if(0 == result) {
|
||||
result = memcmp(b0, b1, r0);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
char inpFilename[256] = { 0 };
|
||||
char lz4Filename[256] = { 0 };
|
||||
char decFilename[256] = { 0 };
|
||||
|
||||
if(argc < 2) {
|
||||
printf("Please specify input filename\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
snprintf(inpFilename, 256, "%s", argv[1]);
|
||||
snprintf(lz4Filename, 256, "%s.lz4s-%d", argv[1], 0);
|
||||
snprintf(decFilename, 256, "%s.lz4s-%d.dec", argv[1], 0);
|
||||
|
||||
printf("inp = [%s]\n", inpFilename);
|
||||
printf("lz4 = [%s]\n", lz4Filename);
|
||||
printf("dec = [%s]\n", decFilename);
|
||||
|
||||
// compress
|
||||
{
|
||||
FILE* inpFp = fopen(inpFilename, "rb");
|
||||
FILE* outFp = fopen(lz4Filename, "wb");
|
||||
|
||||
test_compress(outFp, inpFp);
|
||||
|
||||
fclose(outFp);
|
||||
fclose(inpFp);
|
||||
}
|
||||
|
||||
// decompress
|
||||
{
|
||||
FILE* inpFp = fopen(lz4Filename, "rb");
|
||||
FILE* outFp = fopen(decFilename, "wb");
|
||||
|
||||
test_decompress(outFp, inpFp);
|
||||
|
||||
fclose(outFp);
|
||||
fclose(inpFp);
|
||||
}
|
||||
|
||||
// verify
|
||||
{
|
||||
FILE* inpFp = fopen(inpFilename, "rb");
|
||||
FILE* decFp = fopen(decFilename, "rb");
|
||||
|
||||
const int cmp = compare(inpFp, decFp);
|
||||
if(0 == cmp) {
|
||||
printf("Verify : OK\n");
|
||||
} else {
|
||||
printf("Verify : NG\n");
|
||||
}
|
||||
|
||||
fclose(decFp);
|
||||
fclose(inpFp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
13
src/lz4/examples/printVersion.c
Normal file
@@ -0,0 +1,13 @@
|
||||
// LZ4 trivial example : print Library version number
|
||||
// Copyright : Takayuki Matsuoka & Yann Collet
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "lz4.h"
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
(void)argc; (void)argv;
|
||||
printf("Hello World ! LZ4 Library version = %d\n", LZ4_versionNumber());
|
||||
return 0;
|
||||
}
|
||||
BIN
src/lz4/images/image00.png
Executable file
|
After Width: | Height: | Size: 7.8 KiB |
BIN
src/lz4/images/image01.png
Executable file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
src/lz4/images/image02.png
Executable file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
src/lz4/images/image03.png
Executable file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
src/lz4/images/image04.png
Executable file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
src/lz4/images/image05.png
Executable file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
src/lz4/images/image06.png
Executable file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
src/lz4/lib/LICENSE
Normal file
117
src/lz4/lib/Makefile
Normal file
@@ -0,0 +1,117 @@
|
||||
# ################################################################
|
||||
# LZ4 library - Makefile
|
||||
# Copyright (C) Yann Collet 2011-2015
|
||||
# All rights reserved.
|
||||
#
|
||||
# BSD license
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# * Redistributions in binary form must reproduce the above copyright notice, this
|
||||
# list of conditions and the following disclaimer in the documentation and/or
|
||||
# other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# You can contact the author at :
|
||||
# - LZ4 source repository : http://code.google.com/p/lz4/
|
||||
# - LZ4 source mirror : https://github.com/Cyan4973/lz4
|
||||
# - LZ4 forum froup : https://groups.google.com/forum/#!forum/lz4c
|
||||
# ################################################################
|
||||
|
||||
# Version numbers
|
||||
VERSION ?= 126
|
||||
LIBVER_MAJOR=`sed -n '/define LZ4_VERSION_MAJOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < lz4.h`
|
||||
LIBVER_MINOR=`sed -n '/define LZ4_VERSION_MINOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < lz4.h`
|
||||
LIBVER_PATCH=`sed -n '/define LZ4_VERSION_RELEASE/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < lz4.h`
|
||||
LIBVER=$(LIBVER_MAJOR).$(LIBVER_MINOR).$(LIBVER_PATCH)
|
||||
|
||||
DESTDIR?=
|
||||
PREFIX ?= /usr
|
||||
CFLAGS ?= -O3
|
||||
CFLAGS += -I. -std=c99 -Wall -Wextra -Wundef -Wshadow -Wcast-align -Wstrict-prototypes -pedantic
|
||||
|
||||
LIBDIR?= $(PREFIX)/lib
|
||||
INCLUDEDIR=$(PREFIX)/include
|
||||
|
||||
|
||||
# OS X linker doesn't support -soname, and use different extension
|
||||
# see : https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/DynamicLibraryDesignGuidelines.html
|
||||
ifeq ($(shell uname), Darwin)
|
||||
SHARED_EXT = dylib
|
||||
SHARED_EXT_MAJOR = $(LIBVER_MAJOR).$(SHARED_EXT)
|
||||
SHARED_EXT_VER = $(LIBVER).$(SHARED_EXT)
|
||||
SONAME_FLAGS = -install_name $(PREFIX)/lib/liblz4.$(SHARED_EXT_MAJOR) -compatibility_version $(LIBVER_MAJOR) -current_version $(LIBVER)
|
||||
else
|
||||
SONAME_FLAGS = -Wl,-soname=liblz4.$(SHARED_EXT).$(LIBVER_MAJOR)
|
||||
SHARED_EXT = so
|
||||
SHARED_EXT_MAJOR = $(SHARED_EXT).$(LIBVER_MAJOR)
|
||||
SHARED_EXT_VER = $(SHARED_EXT).$(LIBVER)
|
||||
endif
|
||||
|
||||
default: liblz4
|
||||
|
||||
all: liblz4
|
||||
|
||||
liblz4: lz4.c lz4hc.c lz4frame.c xxhash.c
|
||||
@echo compiling static library
|
||||
@$(CC) $(CPPFLAGS) $(CFLAGS) -c $^
|
||||
@$(AR) rcs liblz4.a lz4.o lz4hc.o lz4frame.o xxhash.o
|
||||
@echo compiling dynamic library $(LIBVER)
|
||||
@$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared $^ -fPIC $(SONAME_FLAGS) -o $@.$(SHARED_EXT_VER)
|
||||
@echo creating versioned links
|
||||
@ln -sf $@.$(SHARED_EXT_VER) $@.$(SHARED_EXT_MAJOR)
|
||||
@ln -sf $@.$(SHARED_EXT_VER) $@.$(SHARED_EXT)
|
||||
|
||||
clean:
|
||||
@rm -f core *.o *.a *.$(SHARED_EXT) *.$(SHARED_EXT).* liblz4.pc
|
||||
@echo Cleaning library completed
|
||||
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#make install is validated only for Linux, OSX, kFreeBSD and Hurd targets
|
||||
ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU))
|
||||
|
||||
liblz4.pc: liblz4.pc.in Makefile
|
||||
@echo creating pkgconfig
|
||||
@sed -e 's|@PREFIX@|$(PREFIX)|' \
|
||||
-e 's|@LIBDIR@|$(LIBDIR)|' \
|
||||
-e 's|@INCLUDEDIR@|$(INCLUDEDIR)|' \
|
||||
-e 's|@VERSION@|$(VERSION)|' \
|
||||
$< >$@
|
||||
|
||||
install: liblz4 liblz4.pc
|
||||
@install -d -m 755 $(DESTDIR)$(LIBDIR)/pkgconfig/ $(DESTDIR)$(INCLUDEDIR)/
|
||||
@install -m 755 liblz4.$(SHARED_EXT_VER) $(DESTDIR)$(LIBDIR)/liblz4.$(SHARED_EXT_VER)
|
||||
@cp -a liblz4.$(SHARED_EXT_MAJOR) $(DESTDIR)$(LIBDIR)
|
||||
@cp -a liblz4.$(SHARED_EXT) $(DESTDIR)$(LIBDIR)
|
||||
@cp -a liblz4.pc $(DESTDIR)$(LIBDIR)/pkgconfig/
|
||||
@install -m 644 liblz4.a $(DESTDIR)$(LIBDIR)/liblz4.a
|
||||
@install -m 644 lz4.h $(DESTDIR)$(INCLUDEDIR)/lz4.h
|
||||
@install -m 644 lz4hc.h $(DESTDIR)$(INCLUDEDIR)/lz4hc.h
|
||||
@install -m 644 lz4frame.h $(DESTDIR)$(INCLUDEDIR)/lz4frame.h
|
||||
@echo lz4 static and shared library installed
|
||||
|
||||
uninstall:
|
||||
@rm -f $(DESTDIR)$(LIBDIR)/liblz4.$(SHARED_EXT)
|
||||
@rm -f $(DESTDIR)$(LIBDIR)/liblz4.$(SHARED_EXT_MAJOR)
|
||||
@rm -f $(DESTDIR)$(LIBDIR)/pkgconfig/liblz4.pc
|
||||
@[ -x $(DESTDIR)$(LIBDIR)/liblz4.$(SHARED_EXT_VER) ] && rm -f $(DESTDIR)$(LIBDIR)/liblz4.$(SHARED_EXT_VER)
|
||||
@[ -f $(DESTDIR)$(LIBDIR)/liblz4.a ] && rm -f $(DESTDIR)$(LIBDIR)/liblz4.a
|
||||
@[ -f $(DESTDIR)$(INCLUDEDIR)/lz4.h ] && rm -f $(DESTDIR)$(INCLUDEDIR)/lz4.h
|
||||
@[ -f $(DESTDIR)$(INCLUDEDIR)/lz4hc.h ] && rm -f $(DESTDIR)$(INCLUDEDIR)/lz4hc.h
|
||||
@echo lz4 libraries successfully uninstalled
|
||||
|
||||
endif
|
||||
14
src/lz4/lib/liblz4.pc.in
Normal file
@@ -0,0 +1,14 @@
|
||||
# LZ4 - Fast LZ compression algorithm
|
||||
# Copyright (C) 2011-2014, Yann Collet.
|
||||
# BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
prefix=@PREFIX@
|
||||
libdir=@LIBDIR@
|
||||
includedir=@INCLUDEDIR@
|
||||
|
||||
Name: lz4
|
||||
Description: fast lossless compression algorithm library
|
||||
URL: http://code.google.com/p/lz4/
|
||||
Version: @VERSION@
|
||||
Libs: -L@LIBDIR@ -llz4
|
||||
Cflags: -I@INCLUDEDIR@
|
||||
1367
src/lz4/lib/lz4.c
Normal file
315
src/lz4/lib/lz4.h
Normal file
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
LZ4 - Fast LZ compression algorithm
|
||||
Header File
|
||||
Copyright (C) 2011-2014, Yann Collet.
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* lz4.h provides raw compression format functions, for optimal performance and integration into programs.
|
||||
* If you need to generate data using an inter-operable format (respecting the framing specification),
|
||||
* please use lz4frame.h instead.
|
||||
*/
|
||||
|
||||
/**************************************
|
||||
Version
|
||||
**************************************/
|
||||
#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */
|
||||
#define LZ4_VERSION_MINOR 5 /* for new (non-breaking) interface capabilities */
|
||||
#define LZ4_VERSION_RELEASE 0 /* for tweaks, bug-fixes, or development */
|
||||
#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE)
|
||||
int LZ4_versionNumber (void);
|
||||
|
||||
/**************************************
|
||||
Tuning parameter
|
||||
**************************************/
|
||||
/*
|
||||
* LZ4_MEMORY_USAGE :
|
||||
* Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
|
||||
* Increasing memory usage improves compression ratio
|
||||
* Reduced memory usage can improve speed, due to cache effect
|
||||
* Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache
|
||||
*/
|
||||
#define LZ4_MEMORY_USAGE 14
|
||||
|
||||
|
||||
/**************************************
|
||||
Simple Functions
|
||||
**************************************/
|
||||
|
||||
int LZ4_compress (const char* source, char* dest, int sourceSize);
|
||||
int LZ4_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize);
|
||||
|
||||
/*
|
||||
LZ4_compress() :
|
||||
Compresses 'sourceSize' bytes from 'source' into 'dest'.
|
||||
Destination buffer must be already allocated,
|
||||
and must be sized to handle worst cases situations (input data not compressible)
|
||||
Worst case size evaluation is provided by function LZ4_compressBound()
|
||||
inputSize : Max supported value is LZ4_MAX_INPUT_SIZE
|
||||
return : the number of bytes written in buffer dest
|
||||
or 0 if the compression fails
|
||||
|
||||
LZ4_decompress_safe() :
|
||||
compressedSize : is obviously the source size
|
||||
maxDecompressedSize : is the size of the destination buffer, which must be already allocated.
|
||||
return : the number of bytes decompressed into the destination buffer (necessarily <= maxDecompressedSize)
|
||||
If the destination buffer is not large enough, decoding will stop and output an error code (<0).
|
||||
If the source stream is detected malformed, the function will stop decoding and return a negative result.
|
||||
This function is protected against buffer overflow exploits,
|
||||
and never writes outside of output buffer, nor reads outside of input buffer.
|
||||
It is also protected against malicious data packets.
|
||||
*/
|
||||
|
||||
|
||||
/**************************************
|
||||
Advanced Functions
|
||||
**************************************/
|
||||
#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */
|
||||
#define LZ4_COMPRESSBOUND(isize) ((unsigned int)(isize) > (unsigned int)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16)
|
||||
|
||||
/*
|
||||
LZ4_compressBound() :
|
||||
Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible)
|
||||
This function is primarily useful for memory allocation purposes (output buffer size).
|
||||
Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example).
|
||||
|
||||
isize : is the input size. Max supported value is LZ4_MAX_INPUT_SIZE
|
||||
return : maximum output size in a "worst case" scenario
|
||||
or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE)
|
||||
*/
|
||||
int LZ4_compressBound(int isize);
|
||||
|
||||
|
||||
/*
|
||||
LZ4_compress_limitedOutput() :
|
||||
Compress 'sourceSize' bytes from 'source' into an output buffer 'dest' of maximum size 'maxOutputSize'.
|
||||
If it cannot achieve it, compression will stop, and result of the function will be zero.
|
||||
This saves time and memory on detecting non-compressible (or barely compressible) data.
|
||||
This function never writes outside of provided output buffer.
|
||||
|
||||
sourceSize : Max supported value is LZ4_MAX_INPUT_VALUE
|
||||
maxOutputSize : is the size of the destination buffer (which must be already allocated)
|
||||
return : the number of bytes written in buffer 'dest'
|
||||
or 0 if compression fails
|
||||
*/
|
||||
int LZ4_compress_limitedOutput (const char* source, char* dest, int sourceSize, int maxOutputSize);
|
||||
|
||||
|
||||
/*
|
||||
LZ4_compress_withState() :
|
||||
Same compression functions, but using an externally allocated memory space to store compression state.
|
||||
Use LZ4_sizeofState() to know how much memory must be allocated,
|
||||
and then, provide it as 'void* state' to compression functions.
|
||||
*/
|
||||
int LZ4_sizeofState(void);
|
||||
int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize);
|
||||
int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize);
|
||||
|
||||
|
||||
/*
|
||||
LZ4_decompress_fast() :
|
||||
originalSize : is the original and therefore uncompressed size
|
||||
return : the number of bytes read from the source buffer (in other words, the compressed size)
|
||||
If the source stream is detected malformed, the function will stop decoding and return a negative result.
|
||||
Destination buffer must be already allocated. Its size must be a minimum of 'originalSize' bytes.
|
||||
note : This function fully respect memory boundaries for properly formed compressed data.
|
||||
It is a bit faster than LZ4_decompress_safe().
|
||||
However, it does not provide any protection against intentionally modified data stream (malicious input).
|
||||
Use this function in trusted environment only (data to decode comes from a trusted source).
|
||||
*/
|
||||
int LZ4_decompress_fast (const char* source, char* dest, int originalSize);
|
||||
|
||||
|
||||
/*
|
||||
LZ4_decompress_safe_partial() :
|
||||
This function decompress a compressed block of size 'compressedSize' at position 'source'
|
||||
into destination buffer 'dest' of size 'maxDecompressedSize'.
|
||||
The function tries to stop decompressing operation as soon as 'targetOutputSize' has been reached,
|
||||
reducing decompression time.
|
||||
return : the number of bytes decoded in the destination buffer (necessarily <= maxDecompressedSize)
|
||||
Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller.
|
||||
Always control how many bytes were decoded.
|
||||
If the source stream is detected malformed, the function will stop decoding and return a negative result.
|
||||
This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets
|
||||
*/
|
||||
int LZ4_decompress_safe_partial (const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize);
|
||||
|
||||
|
||||
/***********************************************
|
||||
Streaming Compression Functions
|
||||
***********************************************/
|
||||
|
||||
#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4)
|
||||
#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(long long))
|
||||
/*
|
||||
* LZ4_stream_t
|
||||
* information structure to track an LZ4 stream.
|
||||
* important : init this structure content before first use !
|
||||
* note : only allocated directly the structure if you are statically linking LZ4
|
||||
* If you are using liblz4 as a DLL, please use below construction methods instead.
|
||||
*/
|
||||
typedef struct { long long table[LZ4_STREAMSIZE_U64]; } LZ4_stream_t;
|
||||
|
||||
/*
|
||||
* LZ4_resetStream
|
||||
* Use this function to init an allocated LZ4_stream_t structure
|
||||
*/
|
||||
void LZ4_resetStream (LZ4_stream_t* LZ4_streamPtr);
|
||||
|
||||
/*
|
||||
* LZ4_createStream will allocate and initialize an LZ4_stream_t structure
|
||||
* LZ4_freeStream releases its memory.
|
||||
* In the context of a DLL (liblz4), please use these methods rather than the static struct.
|
||||
* They are more future proof, in case of a change of LZ4_stream_t size.
|
||||
*/
|
||||
LZ4_stream_t* LZ4_createStream(void);
|
||||
int LZ4_freeStream (LZ4_stream_t* LZ4_streamPtr);
|
||||
|
||||
/*
|
||||
* LZ4_loadDict
|
||||
* Use this function to load a static dictionary into LZ4_stream.
|
||||
* Any previous data will be forgotten, only 'dictionary' will remain in memory.
|
||||
* Loading a size of 0 is allowed.
|
||||
* Return : dictionary size, in bytes (necessarily <= 64 KB)
|
||||
*/
|
||||
int LZ4_loadDict (LZ4_stream_t* LZ4_streamPtr, const char* dictionary, int dictSize);
|
||||
|
||||
/*
|
||||
* LZ4_compress_continue
|
||||
* Compress data block 'source', using blocks compressed before as dictionary to improve compression ratio
|
||||
* Previous data blocks are assumed to still be present at their previous location.
|
||||
*/
|
||||
int LZ4_compress_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize);
|
||||
|
||||
/*
|
||||
* LZ4_compress_limitedOutput_continue
|
||||
* Same as before, but also specify a maximum target compressed size (maxOutputSize)
|
||||
* If objective cannot be met, compression exits, and returns a zero.
|
||||
*/
|
||||
int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize);
|
||||
|
||||
/*
|
||||
* LZ4_saveDict
|
||||
* If previously compressed data block is not guaranteed to remain available at its memory location
|
||||
* save it into a safer place (char* safeBuffer)
|
||||
* Note : you don't need to call LZ4_loadDict() afterwards,
|
||||
* dictionary is immediately usable, you can therefore call again LZ4_compress_continue()
|
||||
* Return : dictionary size in bytes, or 0 if error
|
||||
* Note : any dictSize > 64 KB will be interpreted as 64KB.
|
||||
*/
|
||||
int LZ4_saveDict (LZ4_stream_t* LZ4_streamPtr, char* safeBuffer, int dictSize);
|
||||
|
||||
|
||||
/************************************************
|
||||
Streaming Decompression Functions
|
||||
************************************************/
|
||||
|
||||
#define LZ4_STREAMDECODESIZE_U64 4
|
||||
#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long))
|
||||
typedef struct { unsigned long long table[LZ4_STREAMDECODESIZE_U64]; } LZ4_streamDecode_t;
|
||||
/*
|
||||
* LZ4_streamDecode_t
|
||||
* information structure to track an LZ4 stream.
|
||||
* init this structure content using LZ4_setStreamDecode or memset() before first use !
|
||||
*
|
||||
* In the context of a DLL (liblz4) please prefer usage of construction methods below.
|
||||
* They are more future proof, in case of a change of LZ4_streamDecode_t size in the future.
|
||||
* LZ4_createStreamDecode will allocate and initialize an LZ4_streamDecode_t structure
|
||||
* LZ4_freeStreamDecode releases its memory.
|
||||
*/
|
||||
LZ4_streamDecode_t* LZ4_createStreamDecode(void);
|
||||
int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream);
|
||||
|
||||
/*
|
||||
* LZ4_setStreamDecode
|
||||
* Use this function to instruct where to find the dictionary.
|
||||
* Setting a size of 0 is allowed (same effect as reset).
|
||||
* Return : 1 if OK, 0 if error
|
||||
*/
|
||||
int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize);
|
||||
|
||||
/*
|
||||
*_continue() :
|
||||
These decoding functions allow decompression of multiple blocks in "streaming" mode.
|
||||
Previously decoded blocks *must* remain available at the memory position where they were decoded (up to 64 KB)
|
||||
If this condition is not possible, save the relevant part of decoded data into a safe buffer,
|
||||
and indicate where is its new address using LZ4_setStreamDecode()
|
||||
*/
|
||||
int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxDecompressedSize);
|
||||
int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize);
|
||||
|
||||
|
||||
/*
|
||||
Advanced decoding functions :
|
||||
*_usingDict() :
|
||||
These decoding functions work the same as
|
||||
a combination of LZ4_setDictDecode() followed by LZ4_decompress_x_continue()
|
||||
They are stand-alone and don't use nor update an LZ4_streamDecode_t structure.
|
||||
*/
|
||||
int LZ4_decompress_safe_usingDict (const char* source, char* dest, int compressedSize, int maxDecompressedSize, const char* dictStart, int dictSize);
|
||||
int LZ4_decompress_fast_usingDict (const char* source, char* dest, int originalSize, const char* dictStart, int dictSize);
|
||||
|
||||
|
||||
|
||||
/**************************************
|
||||
Obsolete Functions
|
||||
**************************************/
|
||||
/*
|
||||
Obsolete decompression functions
|
||||
These function names are deprecated and should no longer be used.
|
||||
They are only provided here for compatibility with older user programs.
|
||||
- LZ4_uncompress is the same as LZ4_decompress_fast
|
||||
- LZ4_uncompress_unknownOutputSize is the same as LZ4_decompress_safe
|
||||
These function prototypes are now disabled; uncomment them if you really need them.
|
||||
It is highly recommended to stop using these functions and migrate to newer ones */
|
||||
/* int LZ4_uncompress (const char* source, char* dest, int outputSize); */
|
||||
/* int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize); */
|
||||
|
||||
|
||||
/* Obsolete streaming functions; use new streaming interface whenever possible */
|
||||
void* LZ4_create (const char* inputBuffer);
|
||||
int LZ4_sizeofStreamState(void);
|
||||
int LZ4_resetStreamState(void* state, const char* inputBuffer);
|
||||
char* LZ4_slideInputBuffer (void* state);
|
||||
|
||||
/* Obsolete streaming decoding functions */
|
||||
int LZ4_decompress_safe_withPrefix64k (const char* source, char* dest, int compressedSize, int maxOutputSize);
|
||||
int LZ4_decompress_fast_withPrefix64k (const char* source, char* dest, int originalSize);
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
1330
src/lz4/lib/lz4frame.c
Normal file
252
src/lz4/lib/lz4frame.h
Normal file
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
LZ4 auto-framing library
|
||||
Header File
|
||||
Copyright (C) 2011-2015, Yann Collet.
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
- LZ4 source mirror : https://github.com/Cyan4973/lz4
|
||||
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
|
||||
/* LZ4F is a stand-alone API to create LZ4-compressed frames
|
||||
* fully conformant to specification v1.4.1.
|
||||
* All related operations, including memory management, are handled by the library.
|
||||
* You don't need lz4.h when using lz4frame.h.
|
||||
* */
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************
|
||||
Includes
|
||||
**************************************/
|
||||
#include <stddef.h> /* size_t */
|
||||
|
||||
|
||||
/**************************************
|
||||
* Error management
|
||||
* ************************************/
|
||||
typedef size_t LZ4F_errorCode_t;
|
||||
|
||||
unsigned LZ4F_isError(LZ4F_errorCode_t code);
|
||||
const char* LZ4F_getErrorName(LZ4F_errorCode_t code); /* return error code string; useful for debugging */
|
||||
|
||||
|
||||
/**************************************
|
||||
* Frame compression types
|
||||
* ************************************/
|
||||
typedef enum { LZ4F_default=0, max64KB=4, max256KB=5, max1MB=6, max4MB=7 } blockSizeID_t;
|
||||
typedef enum { blockLinked=0, blockIndependent} blockMode_t;
|
||||
typedef enum { noContentChecksum=0, contentChecksumEnabled } contentChecksum_t;
|
||||
|
||||
typedef struct {
|
||||
blockSizeID_t blockSizeID; /* max64KB, max256KB, max1MB, max4MB ; 0 == default */
|
||||
blockMode_t blockMode; /* blockLinked, blockIndependent ; 0 == default */
|
||||
contentChecksum_t contentChecksumFlag; /* noContentChecksum, contentChecksumEnabled ; 0 == default */
|
||||
unsigned reserved[5];
|
||||
} LZ4F_frameInfo_t;
|
||||
|
||||
typedef struct {
|
||||
LZ4F_frameInfo_t frameInfo;
|
||||
unsigned compressionLevel; /* 0 == default (fast mode); values above 16 count as 16 */
|
||||
unsigned autoFlush; /* 1 == always flush : reduce need for tmp buffer */
|
||||
unsigned reserved[4];
|
||||
} LZ4F_preferences_t;
|
||||
|
||||
|
||||
/***********************************
|
||||
* Simple compression function
|
||||
* *********************************/
|
||||
size_t LZ4F_compressFrameBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr);
|
||||
|
||||
size_t LZ4F_compressFrame(void* dstBuffer, size_t dstMaxSize, const void* srcBuffer, size_t srcSize, const LZ4F_preferences_t* preferencesPtr);
|
||||
/* LZ4F_compressFrame()
|
||||
* Compress an entire srcBuffer into a valid LZ4 frame, as defined by specification v1.4.1.
|
||||
* The most important rule is that dstBuffer MUST be large enough (dstMaxSize) to ensure compression completion even in worst case.
|
||||
* You can get the minimum value of dstMaxSize by using LZ4F_compressFrameBound()
|
||||
* If this condition is not respected, LZ4F_compressFrame() will fail (result is an errorCode)
|
||||
* The LZ4F_preferences_t structure is optional : you can provide NULL as argument. All preferences will be set to default.
|
||||
* The result of the function is the number of bytes written into dstBuffer.
|
||||
* The function outputs an error code if it fails (can be tested using LZ4F_isError())
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**********************************
|
||||
* Advanced compression functions
|
||||
* ********************************/
|
||||
typedef void* LZ4F_compressionContext_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned stableSrc; /* 1 == src content will remain available on future calls to LZ4F_compress(); avoid saving src content within tmp buffer as future dictionary */
|
||||
unsigned reserved[3];
|
||||
} LZ4F_compressOptions_t;
|
||||
|
||||
/* Resource Management */
|
||||
|
||||
#define LZ4F_VERSION 100
|
||||
LZ4F_errorCode_t LZ4F_createCompressionContext(LZ4F_compressionContext_t* LZ4F_compressionContextPtr, unsigned version);
|
||||
LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_compressionContext_t LZ4F_compressionContext);
|
||||
/* LZ4F_createCompressionContext() :
|
||||
* The first thing to do is to create a compressionContext object, which will be used in all compression operations.
|
||||
* This is achieved using LZ4F_createCompressionContext(), which takes as argument a version and an LZ4F_preferences_t structure.
|
||||
* The version provided MUST be LZ4F_VERSION. It is intended to track potential version differences between different binaries.
|
||||
* The function will provide a pointer to a fully allocated LZ4F_compressionContext_t object.
|
||||
* If the result LZ4F_errorCode_t is not zero, there was an error during context creation.
|
||||
* Object can release its memory using LZ4F_freeCompressionContext();
|
||||
*/
|
||||
|
||||
|
||||
/* Compression */
|
||||
|
||||
size_t LZ4F_compressBegin(LZ4F_compressionContext_t compressionContext, void* dstBuffer, size_t dstMaxSize, const LZ4F_preferences_t* preferencesPtr);
|
||||
/* LZ4F_compressBegin() :
|
||||
* will write the frame header into dstBuffer.
|
||||
* dstBuffer must be large enough to accommodate a header (dstMaxSize). Maximum header size is 19 bytes.
|
||||
* The LZ4F_preferences_t structure is optional : you can provide NULL as argument, all preferences will then be set to default.
|
||||
* The result of the function is the number of bytes written into dstBuffer for the header
|
||||
* or an error code (can be tested using LZ4F_isError())
|
||||
*/
|
||||
|
||||
size_t LZ4F_compressBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr);
|
||||
/* LZ4F_compressBound() :
|
||||
* Provides the minimum size of Dst buffer given srcSize to handle worst case situations.
|
||||
* preferencesPtr is optional : you can provide NULL as argument, all preferences will then be set to default.
|
||||
* Note that different preferences will produce in different results.
|
||||
*/
|
||||
|
||||
size_t LZ4F_compressUpdate(LZ4F_compressionContext_t compressionContext, void* dstBuffer, size_t dstMaxSize, const void* srcBuffer, size_t srcSize, const LZ4F_compressOptions_t* compressOptionsPtr);
|
||||
/* LZ4F_compressUpdate()
|
||||
* LZ4F_compressUpdate() can be called repetitively to compress as much data as necessary.
|
||||
* The most important rule is that dstBuffer MUST be large enough (dstMaxSize) to ensure compression completion even in worst case.
|
||||
* If this condition is not respected, LZ4F_compress() will fail (result is an errorCode)
|
||||
* You can get the minimum value of dstMaxSize by using LZ4F_compressBound()
|
||||
* The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
|
||||
* The result of the function is the number of bytes written into dstBuffer : it can be zero, meaning input data was just buffered.
|
||||
* The function outputs an error code if it fails (can be tested using LZ4F_isError())
|
||||
*/
|
||||
|
||||
size_t LZ4F_flush(LZ4F_compressionContext_t compressionContext, void* dstBuffer, size_t dstMaxSize, const LZ4F_compressOptions_t* compressOptionsPtr);
|
||||
/* LZ4F_flush()
|
||||
* Should you need to create compressed data immediately, without waiting for a block to be filled,
|
||||
* you can call LZ4_flush(), which will immediately compress any remaining data buffered within compressionContext.
|
||||
* The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
|
||||
* The result of the function is the number of bytes written into dstBuffer
|
||||
* (it can be zero, this means there was no data left within compressionContext)
|
||||
* The function outputs an error code if it fails (can be tested using LZ4F_isError())
|
||||
*/
|
||||
|
||||
size_t LZ4F_compressEnd(LZ4F_compressionContext_t compressionContext, void* dstBuffer, size_t dstMaxSize, const LZ4F_compressOptions_t* compressOptionsPtr);
|
||||
/* LZ4F_compressEnd()
|
||||
* When you want to properly finish the compressed frame, just call LZ4F_compressEnd().
|
||||
* It will flush whatever data remained within compressionContext (like LZ4_flush())
|
||||
* but also properly finalize the frame, with an endMark and a checksum.
|
||||
* The result of the function is the number of bytes written into dstBuffer (necessarily >= 4 (endMark size))
|
||||
* The function outputs an error code if it fails (can be tested using LZ4F_isError())
|
||||
* The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
|
||||
* compressionContext can then be used again, starting with LZ4F_compressBegin().
|
||||
*/
|
||||
|
||||
|
||||
/***********************************
|
||||
* Decompression functions
|
||||
* *********************************/
|
||||
|
||||
typedef void* LZ4F_decompressionContext_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned stableDst; /* guarantee that decompressed data will still be there on next function calls (avoid storage into tmp buffers) */
|
||||
unsigned reserved[3];
|
||||
} LZ4F_decompressOptions_t;
|
||||
|
||||
|
||||
/* Resource management */
|
||||
|
||||
LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_decompressionContext_t* ctxPtr, unsigned version);
|
||||
LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_decompressionContext_t ctx);
|
||||
/* LZ4F_createDecompressionContext() :
|
||||
* The first thing to do is to create a decompressionContext object, which will be used in all decompression operations.
|
||||
* This is achieved using LZ4F_createDecompressionContext().
|
||||
* The version provided MUST be LZ4F_VERSION. It is intended to track potential version differences between different binaries.
|
||||
* The function will provide a pointer to a fully allocated and initialized LZ4F_decompressionContext_t object.
|
||||
* If the result LZ4F_errorCode_t is not OK_NoError, there was an error during context creation.
|
||||
* Object can release its memory using LZ4F_freeDecompressionContext();
|
||||
*/
|
||||
|
||||
|
||||
/* Decompression */
|
||||
|
||||
size_t LZ4F_getFrameInfo(LZ4F_decompressionContext_t ctx,
|
||||
LZ4F_frameInfo_t* frameInfoPtr,
|
||||
const void* srcBuffer, size_t* srcSizePtr);
|
||||
/* LZ4F_getFrameInfo()
|
||||
* This function decodes frame header information, such as blockSize.
|
||||
* It is optional : you could start by calling directly LZ4F_decompress() instead.
|
||||
* The objective is to extract header information without starting decompression, typically for allocation purposes.
|
||||
* LZ4F_getFrameInfo() can also be used *after* starting decompression, on a valid LZ4F_decompressionContext_t.
|
||||
* The number of bytes read from srcBuffer will be provided within *srcSizePtr (necessarily <= original value).
|
||||
* You are expected to resume decompression from where it stopped (srcBuffer + *srcSizePtr)
|
||||
* The function result is an hint of how many srcSize bytes LZ4F_decompress() expects for next call,
|
||||
* or an error code which can be tested using LZ4F_isError().
|
||||
*/
|
||||
|
||||
size_t LZ4F_decompress(LZ4F_decompressionContext_t ctx,
|
||||
void* dstBuffer, size_t* dstSizePtr,
|
||||
const void* srcBuffer, size_t* srcSizePtr,
|
||||
const LZ4F_decompressOptions_t* optionsPtr);
|
||||
/* LZ4F_decompress()
|
||||
* Call this function repetitively to regenerate data compressed within srcBuffer.
|
||||
* The function will attempt to decode *srcSizePtr bytes from srcBuffer, into dstBuffer of maximum size *dstSizePtr.
|
||||
*
|
||||
* The number of bytes regenerated into dstBuffer will be provided within *dstSizePtr (necessarily <= original value).
|
||||
*
|
||||
* The number of bytes read from srcBuffer will be provided within *srcSizePtr (necessarily <= original value).
|
||||
* If number of bytes read is < number of bytes provided, then decompression operation is not completed.
|
||||
* It typically happens when dstBuffer is not large enough to contain all decoded data.
|
||||
* LZ4F_decompress() must be called again, starting from where it stopped (srcBuffer + *srcSizePtr)
|
||||
* The function will check this condition, and refuse to continue if it is not respected.
|
||||
*
|
||||
* dstBuffer is supposed to be flushed between each call to the function, since its content will be overwritten.
|
||||
* dst arguments can be changed at will with each consecutive call to the function.
|
||||
*
|
||||
* The function result is an hint of how many srcSize bytes LZ4F_decompress() expects for next call.
|
||||
* Schematically, it's the size of the current (or remaining) compressed block + header of next block.
|
||||
* Respecting the hint provides some boost to performance, since it does skip intermediate buffers.
|
||||
* This is just a hint, you can always provide any srcSize you want.
|
||||
* When a frame is fully decoded, the function result will be 0. (no more data expected)
|
||||
* If decompression failed, function result is an error code, which can be tested using LZ4F_isError().
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
72
src/lz4/lib/lz4frame_static.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
LZ4 auto-framing library
|
||||
Header File for static linking only
|
||||
Copyright (C) 2011-2015, Yann Collet.
|
||||
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
- LZ4 source mirror : https://github.com/Cyan4973/lz4
|
||||
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* lz4frame_static.h should be used solely in the context of static linking.
|
||||
* */
|
||||
|
||||
|
||||
/**************************************
|
||||
* Error management
|
||||
* ************************************/
|
||||
#define LZ4F_LIST_ERRORS(ITEM) \
|
||||
ITEM(OK_NoError) ITEM(ERROR_GENERIC) \
|
||||
ITEM(ERROR_maxBlockSize_invalid) ITEM(ERROR_blockMode_invalid) ITEM(ERROR_contentChecksumFlag_invalid) \
|
||||
ITEM(ERROR_compressionLevel_invalid) \
|
||||
ITEM(ERROR_allocation_failed) \
|
||||
ITEM(ERROR_srcSize_tooLarge) ITEM(ERROR_dstMaxSize_tooSmall) \
|
||||
ITEM(ERROR_decompressionFailed) \
|
||||
ITEM(ERROR_checksum_invalid) \
|
||||
ITEM(ERROR_maxCode)
|
||||
|
||||
#define LZ4F_GENERATE_ENUM(ENUM) ENUM,
|
||||
typedef enum { LZ4F_LIST_ERRORS(LZ4F_GENERATE_ENUM) } LZ4F_errorCodes; /* enum is exposed, to handle specific errors; compare function result to -enum value */
|
||||
|
||||
|
||||
/**************************************
|
||||
Includes
|
||||
**************************************/
|
||||
#include "lz4frame.h"
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
751
src/lz4/lib/lz4hc.c
Normal file
@@ -0,0 +1,751 @@
|
||||
/*
|
||||
LZ4 HC - High Compression Mode of LZ4
|
||||
Copyright (C) 2011-2014, Yann Collet.
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**************************************
|
||||
Tuning Parameter
|
||||
**************************************/
|
||||
static const int LZ4HC_compressionLevel_default = 8;
|
||||
|
||||
|
||||
/**************************************
|
||||
Includes
|
||||
**************************************/
|
||||
#include "lz4hc.h"
|
||||
|
||||
|
||||
/**************************************
|
||||
Local Compiler Options
|
||||
**************************************/
|
||||
#if defined(__GNUC__)
|
||||
# pragma GCC diagnostic ignored "-Wunused-function"
|
||||
#endif
|
||||
|
||||
#if defined (__clang__)
|
||||
# pragma clang diagnostic ignored "-Wunused-function"
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************
|
||||
Common LZ4 definition
|
||||
**************************************/
|
||||
#define LZ4_COMMONDEFS_ONLY
|
||||
#include "lz4.c"
|
||||
|
||||
|
||||
/**************************************
|
||||
Local Constants
|
||||
**************************************/
|
||||
#define DICTIONARY_LOGSIZE 16
|
||||
#define MAXD (1<<DICTIONARY_LOGSIZE)
|
||||
#define MAXD_MASK ((U32)(MAXD - 1))
|
||||
|
||||
#define HASH_LOG (DICTIONARY_LOGSIZE-1)
|
||||
#define HASHTABLESIZE (1 << HASH_LOG)
|
||||
#define HASH_MASK (HASHTABLESIZE - 1)
|
||||
|
||||
#define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH)
|
||||
|
||||
static const int g_maxCompressionLevel = 16;
|
||||
|
||||
|
||||
/**************************************
|
||||
Local Types
|
||||
**************************************/
|
||||
typedef struct
|
||||
{
|
||||
U32 hashTable[HASHTABLESIZE];
|
||||
U16 chainTable[MAXD];
|
||||
const BYTE* end; /* next block here to continue on current prefix */
|
||||
const BYTE* base; /* All index relative to this position */
|
||||
const BYTE* dictBase; /* alternate base for extDict */
|
||||
const BYTE* inputBuffer;/* deprecated */
|
||||
U32 dictLimit; /* below that point, need extDict */
|
||||
U32 lowLimit; /* below that point, no more dict */
|
||||
U32 nextToUpdate;
|
||||
U32 compressionLevel;
|
||||
} LZ4HC_Data_Structure;
|
||||
|
||||
|
||||
/**************************************
|
||||
Local Macros
|
||||
**************************************/
|
||||
#define HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH*8)-HASH_LOG))
|
||||
#define DELTANEXT(p) chainTable[(size_t)(p) & MAXD_MASK]
|
||||
#define GETNEXT(p) ((p) - (size_t)DELTANEXT(p))
|
||||
|
||||
static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); }
|
||||
|
||||
|
||||
|
||||
/**************************************
|
||||
HC Compression
|
||||
**************************************/
|
||||
static void LZ4HC_init (LZ4HC_Data_Structure* hc4, const BYTE* start)
|
||||
{
|
||||
MEM_INIT((void*)hc4->hashTable, 0, sizeof(hc4->hashTable));
|
||||
MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable));
|
||||
hc4->nextToUpdate = 64 KB;
|
||||
hc4->base = start - 64 KB;
|
||||
hc4->inputBuffer = start;
|
||||
hc4->end = start;
|
||||
hc4->dictBase = start - 64 KB;
|
||||
hc4->dictLimit = 64 KB;
|
||||
hc4->lowLimit = 64 KB;
|
||||
}
|
||||
|
||||
|
||||
/* Update chains up to ip (excluded) */
|
||||
FORCE_INLINE void LZ4HC_Insert (LZ4HC_Data_Structure* hc4, const BYTE* ip)
|
||||
{
|
||||
U16* chainTable = hc4->chainTable;
|
||||
U32* HashTable = hc4->hashTable;
|
||||
const BYTE* const base = hc4->base;
|
||||
const U32 target = (U32)(ip - base);
|
||||
U32 idx = hc4->nextToUpdate;
|
||||
|
||||
while(idx < target)
|
||||
{
|
||||
U32 h = LZ4HC_hashPtr(base+idx);
|
||||
size_t delta = idx - HashTable[h];
|
||||
if (delta>MAX_DISTANCE) delta = MAX_DISTANCE;
|
||||
chainTable[idx & 0xFFFF] = (U16)delta;
|
||||
HashTable[h] = idx;
|
||||
idx++;
|
||||
}
|
||||
|
||||
hc4->nextToUpdate = target;
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE int LZ4HC_InsertAndFindBestMatch (LZ4HC_Data_Structure* hc4, /* Index table will be updated */
|
||||
const BYTE* ip, const BYTE* const iLimit,
|
||||
const BYTE** matchpos,
|
||||
const int maxNbAttempts)
|
||||
{
|
||||
U16* const chainTable = hc4->chainTable;
|
||||
U32* const HashTable = hc4->hashTable;
|
||||
const BYTE* const base = hc4->base;
|
||||
const BYTE* const dictBase = hc4->dictBase;
|
||||
const U32 dictLimit = hc4->dictLimit;
|
||||
const U32 lowLimit = (hc4->lowLimit + 64 KB > (U32)(ip-base)) ? hc4->lowLimit : (U32)(ip - base) - (64 KB - 1);
|
||||
U32 matchIndex;
|
||||
const BYTE* match;
|
||||
int nbAttempts=maxNbAttempts;
|
||||
size_t ml=0;
|
||||
|
||||
/* HC4 match finder */
|
||||
LZ4HC_Insert(hc4, ip);
|
||||
matchIndex = HashTable[LZ4HC_hashPtr(ip)];
|
||||
|
||||
while ((matchIndex>=lowLimit) && (nbAttempts))
|
||||
{
|
||||
nbAttempts--;
|
||||
if (matchIndex >= dictLimit)
|
||||
{
|
||||
match = base + matchIndex;
|
||||
if (*(match+ml) == *(ip+ml)
|
||||
&& (LZ4_read32(match) == LZ4_read32(ip)))
|
||||
{
|
||||
size_t mlt = LZ4_count(ip+MINMATCH, match+MINMATCH, iLimit) + MINMATCH;
|
||||
if (mlt > ml) { ml = mlt; *matchpos = match; }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
match = dictBase + matchIndex;
|
||||
if (LZ4_read32(match) == LZ4_read32(ip))
|
||||
{
|
||||
size_t mlt;
|
||||
const BYTE* vLimit = ip + (dictLimit - matchIndex);
|
||||
if (vLimit > iLimit) vLimit = iLimit;
|
||||
mlt = LZ4_count(ip+MINMATCH, match+MINMATCH, vLimit) + MINMATCH;
|
||||
if ((ip+mlt == vLimit) && (vLimit < iLimit))
|
||||
mlt += LZ4_count(ip+mlt, base+dictLimit, iLimit);
|
||||
if (mlt > ml) { ml = mlt; *matchpos = base + matchIndex; } /* virtual matchpos */
|
||||
}
|
||||
}
|
||||
matchIndex -= chainTable[matchIndex & 0xFFFF];
|
||||
}
|
||||
|
||||
return (int)ml;
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch (
|
||||
LZ4HC_Data_Structure* hc4,
|
||||
const BYTE* ip,
|
||||
const BYTE* iLowLimit,
|
||||
const BYTE* iHighLimit,
|
||||
int longest,
|
||||
const BYTE** matchpos,
|
||||
const BYTE** startpos,
|
||||
const int maxNbAttempts)
|
||||
{
|
||||
U16* const chainTable = hc4->chainTable;
|
||||
U32* const HashTable = hc4->hashTable;
|
||||
const BYTE* const base = hc4->base;
|
||||
const U32 dictLimit = hc4->dictLimit;
|
||||
const U32 lowLimit = (hc4->lowLimit + 64 KB > (U32)(ip-base)) ? hc4->lowLimit : (U32)(ip - base) - (64 KB - 1);
|
||||
const BYTE* const dictBase = hc4->dictBase;
|
||||
const BYTE* match;
|
||||
U32 matchIndex;
|
||||
int nbAttempts = maxNbAttempts;
|
||||
int delta = (int)(ip-iLowLimit);
|
||||
|
||||
|
||||
/* First Match */
|
||||
LZ4HC_Insert(hc4, ip);
|
||||
matchIndex = HashTable[LZ4HC_hashPtr(ip)];
|
||||
|
||||
while ((matchIndex>=lowLimit) && (nbAttempts))
|
||||
{
|
||||
nbAttempts--;
|
||||
if (matchIndex >= dictLimit)
|
||||
{
|
||||
match = base + matchIndex;
|
||||
if (*(iLowLimit + longest) == *(match - delta + longest))
|
||||
if (LZ4_read32(match) == LZ4_read32(ip))
|
||||
{
|
||||
const BYTE* startt = ip;
|
||||
const BYTE* tmpMatch = match;
|
||||
const BYTE* const matchEnd = ip + MINMATCH + LZ4_count(ip+MINMATCH, match+MINMATCH, iHighLimit);
|
||||
|
||||
while ((startt>iLowLimit) && (tmpMatch > iLowLimit) && (startt[-1] == tmpMatch[-1])) {startt--; tmpMatch--;}
|
||||
|
||||
if ((matchEnd-startt) > longest)
|
||||
{
|
||||
longest = (int)(matchEnd-startt);
|
||||
*matchpos = tmpMatch;
|
||||
*startpos = startt;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
match = dictBase + matchIndex;
|
||||
if (LZ4_read32(match) == LZ4_read32(ip))
|
||||
{
|
||||
size_t mlt;
|
||||
int back=0;
|
||||
const BYTE* vLimit = ip + (dictLimit - matchIndex);
|
||||
if (vLimit > iHighLimit) vLimit = iHighLimit;
|
||||
mlt = LZ4_count(ip+MINMATCH, match+MINMATCH, vLimit) + MINMATCH;
|
||||
if ((ip+mlt == vLimit) && (vLimit < iHighLimit))
|
||||
mlt += LZ4_count(ip+mlt, base+dictLimit, iHighLimit);
|
||||
while ((ip+back > iLowLimit) && (matchIndex+back > lowLimit) && (ip[back-1] == match[back-1])) back--;
|
||||
mlt -= back;
|
||||
if ((int)mlt > longest) { longest = (int)mlt; *matchpos = base + matchIndex + back; *startpos = ip+back; }
|
||||
}
|
||||
}
|
||||
matchIndex -= chainTable[matchIndex & 0xFFFF];
|
||||
}
|
||||
|
||||
return longest;
|
||||
}
|
||||
|
||||
|
||||
typedef enum { noLimit = 0, limitedOutput = 1 } limitedOutput_directive;
|
||||
|
||||
#define LZ4HC_DEBUG 0
|
||||
#if LZ4HC_DEBUG
|
||||
static unsigned debug = 0;
|
||||
#endif
|
||||
|
||||
FORCE_INLINE int LZ4HC_encodeSequence (
|
||||
const BYTE** ip,
|
||||
BYTE** op,
|
||||
const BYTE** anchor,
|
||||
int matchLength,
|
||||
const BYTE* const match,
|
||||
limitedOutput_directive limitedOutputBuffer,
|
||||
BYTE* oend)
|
||||
{
|
||||
int length;
|
||||
BYTE* token;
|
||||
|
||||
#if LZ4HC_DEBUG
|
||||
if (debug) printf("literal : %u -- match : %u -- offset : %u\n", (U32)(*ip - *anchor), (U32)matchLength, (U32)(*ip-match));
|
||||
#endif
|
||||
|
||||
/* Encode Literal length */
|
||||
length = (int)(*ip - *anchor);
|
||||
token = (*op)++;
|
||||
if ((limitedOutputBuffer) && ((*op + (length>>8) + length + (2 + 1 + LASTLITERALS)) > oend)) return 1; /* Check output limit */
|
||||
if (length>=(int)RUN_MASK) { int len; *token=(RUN_MASK<<ML_BITS); len = length-RUN_MASK; for(; len > 254 ; len-=255) *(*op)++ = 255; *(*op)++ = (BYTE)len; }
|
||||
else *token = (BYTE)(length<<ML_BITS);
|
||||
|
||||
/* Copy Literals */
|
||||
LZ4_wildCopy(*op, *anchor, (*op) + length);
|
||||
*op += length;
|
||||
|
||||
/* Encode Offset */
|
||||
LZ4_writeLE16(*op, (U16)(*ip-match)); *op += 2;
|
||||
|
||||
/* Encode MatchLength */
|
||||
length = (int)(matchLength-MINMATCH);
|
||||
if ((limitedOutputBuffer) && (*op + (length>>8) + (1 + LASTLITERALS) > oend)) return 1; /* Check output limit */
|
||||
if (length>=(int)ML_MASK) { *token+=ML_MASK; length-=ML_MASK; for(; length > 509 ; length-=510) { *(*op)++ = 255; *(*op)++ = 255; } if (length > 254) { length-=255; *(*op)++ = 255; } *(*op)++ = (BYTE)length; }
|
||||
else *token += (BYTE)(length);
|
||||
|
||||
/* Prepare next loop */
|
||||
*ip += matchLength;
|
||||
*anchor = *ip;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int LZ4HC_compress_generic (
|
||||
void* ctxvoid,
|
||||
const char* source,
|
||||
char* dest,
|
||||
int inputSize,
|
||||
int maxOutputSize,
|
||||
int compressionLevel,
|
||||
limitedOutput_directive limit
|
||||
)
|
||||
{
|
||||
LZ4HC_Data_Structure* ctx = (LZ4HC_Data_Structure*) ctxvoid;
|
||||
const BYTE* ip = (const BYTE*) source;
|
||||
const BYTE* anchor = ip;
|
||||
const BYTE* const iend = ip + inputSize;
|
||||
const BYTE* const mflimit = iend - MFLIMIT;
|
||||
const BYTE* const matchlimit = (iend - LASTLITERALS);
|
||||
|
||||
BYTE* op = (BYTE*) dest;
|
||||
BYTE* const oend = op + maxOutputSize;
|
||||
|
||||
unsigned maxNbAttempts;
|
||||
int ml, ml2, ml3, ml0;
|
||||
const BYTE* ref=NULL;
|
||||
const BYTE* start2=NULL;
|
||||
const BYTE* ref2=NULL;
|
||||
const BYTE* start3=NULL;
|
||||
const BYTE* ref3=NULL;
|
||||
const BYTE* start0;
|
||||
const BYTE* ref0;
|
||||
|
||||
|
||||
/* init */
|
||||
if (compressionLevel > g_maxCompressionLevel) compressionLevel = g_maxCompressionLevel;
|
||||
if (compressionLevel < 1) compressionLevel = LZ4HC_compressionLevel_default;
|
||||
maxNbAttempts = 1 << (compressionLevel-1);
|
||||
ctx->end += inputSize;
|
||||
|
||||
ip++;
|
||||
|
||||
/* Main Loop */
|
||||
while (ip < mflimit)
|
||||
{
|
||||
ml = LZ4HC_InsertAndFindBestMatch (ctx, ip, matchlimit, (&ref), maxNbAttempts);
|
||||
if (!ml) { ip++; continue; }
|
||||
|
||||
/* saved, in case we would skip too much */
|
||||
start0 = ip;
|
||||
ref0 = ref;
|
||||
ml0 = ml;
|
||||
|
||||
_Search2:
|
||||
if (ip+ml < mflimit)
|
||||
ml2 = LZ4HC_InsertAndGetWiderMatch(ctx, ip + ml - 2, ip + 1, matchlimit, ml, &ref2, &start2, maxNbAttempts);
|
||||
else ml2 = ml;
|
||||
|
||||
if (ml2 == ml) /* No better match */
|
||||
{
|
||||
if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) return 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (start0 < ip)
|
||||
{
|
||||
if (start2 < ip + ml0) /* empirical */
|
||||
{
|
||||
ip = start0;
|
||||
ref = ref0;
|
||||
ml = ml0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Here, start0==ip */
|
||||
if ((start2 - ip) < 3) /* First Match too small : removed */
|
||||
{
|
||||
ml = ml2;
|
||||
ip = start2;
|
||||
ref =ref2;
|
||||
goto _Search2;
|
||||
}
|
||||
|
||||
_Search3:
|
||||
/*
|
||||
* Currently we have :
|
||||
* ml2 > ml1, and
|
||||
* ip1+3 <= ip2 (usually < ip1+ml1)
|
||||
*/
|
||||
if ((start2 - ip) < OPTIMAL_ML)
|
||||
{
|
||||
int correction;
|
||||
int new_ml = ml;
|
||||
if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML;
|
||||
if (ip+new_ml > start2 + ml2 - MINMATCH) new_ml = (int)(start2 - ip) + ml2 - MINMATCH;
|
||||
correction = new_ml - (int)(start2 - ip);
|
||||
if (correction > 0)
|
||||
{
|
||||
start2 += correction;
|
||||
ref2 += correction;
|
||||
ml2 -= correction;
|
||||
}
|
||||
}
|
||||
/* Now, we have start2 = ip+new_ml, with new_ml = min(ml, OPTIMAL_ML=18) */
|
||||
|
||||
if (start2 + ml2 < mflimit)
|
||||
ml3 = LZ4HC_InsertAndGetWiderMatch(ctx, start2 + ml2 - 3, start2, matchlimit, ml2, &ref3, &start3, maxNbAttempts);
|
||||
else ml3 = ml2;
|
||||
|
||||
if (ml3 == ml2) /* No better match : 2 sequences to encode */
|
||||
{
|
||||
/* ip & ref are known; Now for ml */
|
||||
if (start2 < ip+ml) ml = (int)(start2 - ip);
|
||||
/* Now, encode 2 sequences */
|
||||
if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) return 0;
|
||||
ip = start2;
|
||||
if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml2, ref2, limit, oend)) return 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (start3 < ip+ml+3) /* Not enough space for match 2 : remove it */
|
||||
{
|
||||
if (start3 >= (ip+ml)) /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */
|
||||
{
|
||||
if (start2 < ip+ml)
|
||||
{
|
||||
int correction = (int)(ip+ml - start2);
|
||||
start2 += correction;
|
||||
ref2 += correction;
|
||||
ml2 -= correction;
|
||||
if (ml2 < MINMATCH)
|
||||
{
|
||||
start2 = start3;
|
||||
ref2 = ref3;
|
||||
ml2 = ml3;
|
||||
}
|
||||
}
|
||||
|
||||
if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) return 0;
|
||||
ip = start3;
|
||||
ref = ref3;
|
||||
ml = ml3;
|
||||
|
||||
start0 = start2;
|
||||
ref0 = ref2;
|
||||
ml0 = ml2;
|
||||
goto _Search2;
|
||||
}
|
||||
|
||||
start2 = start3;
|
||||
ref2 = ref3;
|
||||
ml2 = ml3;
|
||||
goto _Search3;
|
||||
}
|
||||
|
||||
/*
|
||||
* OK, now we have 3 ascending matches; let's write at least the first one
|
||||
* ip & ref are known; Now for ml
|
||||
*/
|
||||
if (start2 < ip+ml)
|
||||
{
|
||||
if ((start2 - ip) < (int)ML_MASK)
|
||||
{
|
||||
int correction;
|
||||
if (ml > OPTIMAL_ML) ml = OPTIMAL_ML;
|
||||
if (ip + ml > start2 + ml2 - MINMATCH) ml = (int)(start2 - ip) + ml2 - MINMATCH;
|
||||
correction = ml - (int)(start2 - ip);
|
||||
if (correction > 0)
|
||||
{
|
||||
start2 += correction;
|
||||
ref2 += correction;
|
||||
ml2 -= correction;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ml = (int)(start2 - ip);
|
||||
}
|
||||
}
|
||||
if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) return 0;
|
||||
|
||||
ip = start2;
|
||||
ref = ref2;
|
||||
ml = ml2;
|
||||
|
||||
start2 = start3;
|
||||
ref2 = ref3;
|
||||
ml2 = ml3;
|
||||
|
||||
goto _Search3;
|
||||
}
|
||||
|
||||
/* Encode Last Literals */
|
||||
{
|
||||
int lastRun = (int)(iend - anchor);
|
||||
if ((limit) && (((char*)op - dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize)) return 0; /* Check output limit */
|
||||
if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK<<ML_BITS); lastRun-=RUN_MASK; for(; lastRun > 254 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; }
|
||||
else *op++ = (BYTE)(lastRun<<ML_BITS);
|
||||
memcpy(op, anchor, iend - anchor);
|
||||
op += iend-anchor;
|
||||
}
|
||||
|
||||
/* End */
|
||||
return (int) (((char*)op)-dest);
|
||||
}
|
||||
|
||||
|
||||
int LZ4_compressHC2(const char* source, char* dest, int inputSize, int compressionLevel)
|
||||
{
|
||||
LZ4HC_Data_Structure ctx;
|
||||
LZ4HC_init(&ctx, (const BYTE*)source);
|
||||
return LZ4HC_compress_generic (&ctx, source, dest, inputSize, 0, compressionLevel, noLimit);
|
||||
}
|
||||
|
||||
int LZ4_compressHC(const char* source, char* dest, int inputSize) { return LZ4_compressHC2(source, dest, inputSize, 0); }
|
||||
|
||||
int LZ4_compressHC2_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel)
|
||||
{
|
||||
LZ4HC_Data_Structure ctx;
|
||||
LZ4HC_init(&ctx, (const BYTE*)source);
|
||||
return LZ4HC_compress_generic (&ctx, source, dest, inputSize, maxOutputSize, compressionLevel, limitedOutput);
|
||||
}
|
||||
|
||||
int LZ4_compressHC_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize)
|
||||
{
|
||||
return LZ4_compressHC2_limitedOutput(source, dest, inputSize, maxOutputSize, 0);
|
||||
}
|
||||
|
||||
|
||||
/*****************************
|
||||
* Using external allocation
|
||||
* ***************************/
|
||||
int LZ4_sizeofStateHC(void) { return sizeof(LZ4HC_Data_Structure); }
|
||||
|
||||
|
||||
int LZ4_compressHC2_withStateHC (void* state, const char* source, char* dest, int inputSize, int compressionLevel)
|
||||
{
|
||||
if (((size_t)(state)&(sizeof(void*)-1)) != 0) return 0; /* Error : state is not aligned for pointers (32 or 64 bits) */
|
||||
LZ4HC_init ((LZ4HC_Data_Structure*)state, (const BYTE*)source);
|
||||
return LZ4HC_compress_generic (state, source, dest, inputSize, 0, compressionLevel, noLimit);
|
||||
}
|
||||
|
||||
int LZ4_compressHC_withStateHC (void* state, const char* source, char* dest, int inputSize)
|
||||
{ return LZ4_compressHC2_withStateHC (state, source, dest, inputSize, 0); }
|
||||
|
||||
|
||||
int LZ4_compressHC2_limitedOutput_withStateHC (void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel)
|
||||
{
|
||||
if (((size_t)(state)&(sizeof(void*)-1)) != 0) return 0; /* Error : state is not aligned for pointers (32 or 64 bits) */
|
||||
LZ4HC_init ((LZ4HC_Data_Structure*)state, (const BYTE*)source);
|
||||
return LZ4HC_compress_generic (state, source, dest, inputSize, maxOutputSize, compressionLevel, limitedOutput);
|
||||
}
|
||||
|
||||
int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* source, char* dest, int inputSize, int maxOutputSize)
|
||||
{ return LZ4_compressHC2_limitedOutput_withStateHC (state, source, dest, inputSize, maxOutputSize, 0); }
|
||||
|
||||
|
||||
|
||||
/**************************************
|
||||
* Streaming Functions
|
||||
* ************************************/
|
||||
/* allocation */
|
||||
LZ4_streamHC_t* LZ4_createStreamHC(void) { return (LZ4_streamHC_t*)malloc(sizeof(LZ4_streamHC_t)); }
|
||||
int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr) { free(LZ4_streamHCPtr); return 0; }
|
||||
|
||||
|
||||
/* initialization */
|
||||
void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
|
||||
{
|
||||
LZ4_STATIC_ASSERT(sizeof(LZ4HC_Data_Structure) <= LZ4_STREAMHCSIZE); /* if compilation fails here, LZ4_STREAMHCSIZE must be increased */
|
||||
((LZ4HC_Data_Structure*)LZ4_streamHCPtr)->base = NULL;
|
||||
((LZ4HC_Data_Structure*)LZ4_streamHCPtr)->compressionLevel = (unsigned)compressionLevel;
|
||||
}
|
||||
|
||||
int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, const char* dictionary, int dictSize)
|
||||
{
|
||||
LZ4HC_Data_Structure* ctxPtr = (LZ4HC_Data_Structure*) LZ4_streamHCPtr;
|
||||
if (dictSize > 64 KB)
|
||||
{
|
||||
dictionary += dictSize - 64 KB;
|
||||
dictSize = 64 KB;
|
||||
}
|
||||
LZ4HC_init (ctxPtr, (const BYTE*)dictionary);
|
||||
if (dictSize >= 4) LZ4HC_Insert (ctxPtr, (const BYTE*)dictionary +(dictSize-3));
|
||||
ctxPtr->end = (const BYTE*)dictionary + dictSize;
|
||||
return dictSize;
|
||||
}
|
||||
|
||||
|
||||
/* compression */
|
||||
|
||||
static void LZ4HC_setExternalDict(LZ4HC_Data_Structure* ctxPtr, const BYTE* newBlock)
|
||||
{
|
||||
if (ctxPtr->end >= ctxPtr->base + 4)
|
||||
LZ4HC_Insert (ctxPtr, ctxPtr->end-3); /* Referencing remaining dictionary content */
|
||||
/* Only one memory segment for extDict, so any previous extDict is lost at this stage */
|
||||
ctxPtr->lowLimit = ctxPtr->dictLimit;
|
||||
ctxPtr->dictLimit = (U32)(ctxPtr->end - ctxPtr->base);
|
||||
ctxPtr->dictBase = ctxPtr->base;
|
||||
ctxPtr->base = newBlock - ctxPtr->dictLimit;
|
||||
ctxPtr->end = newBlock;
|
||||
ctxPtr->nextToUpdate = ctxPtr->dictLimit; /* match referencing will resume from there */
|
||||
}
|
||||
|
||||
static int LZ4_compressHC_continue_generic (LZ4HC_Data_Structure* ctxPtr,
|
||||
const char* source, char* dest,
|
||||
int inputSize, int maxOutputSize, limitedOutput_directive limit)
|
||||
{
|
||||
/* auto-init if forgotten */
|
||||
if (ctxPtr->base == NULL)
|
||||
LZ4HC_init (ctxPtr, (const BYTE*) source);
|
||||
|
||||
/* Check overflow */
|
||||
if ((size_t)(ctxPtr->end - ctxPtr->base) > 2 GB)
|
||||
{
|
||||
size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->base) - ctxPtr->dictLimit;
|
||||
if (dictSize > 64 KB) dictSize = 64 KB;
|
||||
|
||||
LZ4_loadDictHC((LZ4_streamHC_t*)ctxPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize);
|
||||
}
|
||||
|
||||
/* Check if blocks follow each other */
|
||||
if ((const BYTE*)source != ctxPtr->end) LZ4HC_setExternalDict(ctxPtr, (const BYTE*)source);
|
||||
|
||||
/* Check overlapping input/dictionary space */
|
||||
{
|
||||
const BYTE* sourceEnd = (const BYTE*) source + inputSize;
|
||||
const BYTE* dictBegin = ctxPtr->dictBase + ctxPtr->lowLimit;
|
||||
const BYTE* dictEnd = ctxPtr->dictBase + ctxPtr->dictLimit;
|
||||
if ((sourceEnd > dictBegin) && ((BYTE*)source < dictEnd))
|
||||
{
|
||||
if (sourceEnd > dictEnd) sourceEnd = dictEnd;
|
||||
ctxPtr->lowLimit = (U32)(sourceEnd - ctxPtr->dictBase);
|
||||
if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4) ctxPtr->lowLimit = ctxPtr->dictLimit;
|
||||
}
|
||||
}
|
||||
|
||||
return LZ4HC_compress_generic (ctxPtr, source, dest, inputSize, maxOutputSize, ctxPtr->compressionLevel, limit);
|
||||
}
|
||||
|
||||
int LZ4_compressHC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize)
|
||||
{
|
||||
return LZ4_compressHC_continue_generic ((LZ4HC_Data_Structure*)LZ4_streamHCPtr, source, dest, inputSize, 0, noLimit);
|
||||
}
|
||||
|
||||
int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize, int maxOutputSize)
|
||||
{
|
||||
return LZ4_compressHC_continue_generic ((LZ4HC_Data_Structure*)LZ4_streamHCPtr, source, dest, inputSize, maxOutputSize, limitedOutput);
|
||||
}
|
||||
|
||||
|
||||
/* dictionary saving */
|
||||
|
||||
int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize)
|
||||
{
|
||||
LZ4HC_Data_Structure* streamPtr = (LZ4HC_Data_Structure*)LZ4_streamHCPtr;
|
||||
int prefixSize = (int)(streamPtr->end - (streamPtr->base + streamPtr->dictLimit));
|
||||
if (dictSize > 64 KB) dictSize = 64 KB;
|
||||
if (dictSize < 4) dictSize = 0;
|
||||
if (dictSize > prefixSize) dictSize = prefixSize;
|
||||
memcpy(safeBuffer, streamPtr->end - dictSize, dictSize);
|
||||
{
|
||||
U32 endIndex = (U32)(streamPtr->end - streamPtr->base);
|
||||
streamPtr->end = (const BYTE*)safeBuffer + dictSize;
|
||||
streamPtr->base = streamPtr->end - endIndex;
|
||||
streamPtr->dictLimit = endIndex - dictSize;
|
||||
streamPtr->lowLimit = endIndex - dictSize;
|
||||
if (streamPtr->nextToUpdate < streamPtr->dictLimit) streamPtr->nextToUpdate = streamPtr->dictLimit;
|
||||
}
|
||||
return dictSize;
|
||||
}
|
||||
|
||||
|
||||
/***********************************
|
||||
* Deprecated Functions
|
||||
***********************************/
|
||||
int LZ4_sizeofStreamStateHC(void) { return LZ4_STREAMHCSIZE; }
|
||||
|
||||
int LZ4_resetStreamStateHC(void* state, const char* inputBuffer)
|
||||
{
|
||||
if ((((size_t)state) & (sizeof(void*)-1)) != 0) return 1; /* Error : pointer is not aligned for pointer (32 or 64 bits) */
|
||||
LZ4HC_init((LZ4HC_Data_Structure*)state, (const BYTE*)inputBuffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* LZ4_createHC (const char* inputBuffer)
|
||||
{
|
||||
void* hc4 = ALLOCATOR(1, sizeof(LZ4HC_Data_Structure));
|
||||
LZ4HC_init ((LZ4HC_Data_Structure*)hc4, (const BYTE*)inputBuffer);
|
||||
return hc4;
|
||||
}
|
||||
|
||||
int LZ4_freeHC (void* LZ4HC_Data)
|
||||
{
|
||||
FREEMEM(LZ4HC_Data);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
int LZ4_compressHC_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize)
|
||||
{
|
||||
return LZ4HC_compress_generic (LZ4HC_Data, source, dest, inputSize, 0, 0, noLimit);
|
||||
}
|
||||
int LZ4_compressHC_limitedOutput_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int maxOutputSize)
|
||||
{
|
||||
return LZ4HC_compress_generic (LZ4HC_Data, source, dest, inputSize, maxOutputSize, 0, limitedOutput);
|
||||
}
|
||||
*/
|
||||
|
||||
int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int compressionLevel)
|
||||
{
|
||||
return LZ4HC_compress_generic (LZ4HC_Data, source, dest, inputSize, 0, compressionLevel, noLimit);
|
||||
}
|
||||
|
||||
int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel)
|
||||
{
|
||||
return LZ4HC_compress_generic (LZ4HC_Data, source, dest, inputSize, maxOutputSize, compressionLevel, limitedOutput);
|
||||
}
|
||||
|
||||
char* LZ4_slideInputBufferHC(void* LZ4HC_Data)
|
||||
{
|
||||
LZ4HC_Data_Structure* hc4 = (LZ4HC_Data_Structure*)LZ4HC_Data;
|
||||
int dictSize = LZ4_saveDictHC((LZ4_streamHC_t*)LZ4HC_Data, (char*)(hc4->inputBuffer), 64 KB);
|
||||
return (char*)(hc4->inputBuffer + dictSize);
|
||||
}
|
||||
174
src/lz4/lib/lz4hc.h
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
LZ4 HC - High Compression Mode of LZ4
|
||||
Header File
|
||||
Copyright (C) 2011-2014, Yann Collet.
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
int LZ4_compressHC (const char* source, char* dest, int inputSize);
|
||||
/*
|
||||
LZ4_compressHC :
|
||||
return : the number of bytes in compressed buffer dest
|
||||
or 0 if compression fails.
|
||||
note : destination buffer must be already allocated.
|
||||
To avoid any problem, size it to handle worst cases situations (input data not compressible)
|
||||
Worst case size evaluation is provided by function LZ4_compressBound() (see "lz4.h")
|
||||
*/
|
||||
|
||||
int LZ4_compressHC_limitedOutput (const char* source, char* dest, int inputSize, int maxOutputSize);
|
||||
/*
|
||||
LZ4_compress_limitedOutput() :
|
||||
Compress 'inputSize' bytes from 'source' into an output buffer 'dest' of maximum size 'maxOutputSize'.
|
||||
If it cannot achieve it, compression will stop, and result of the function will be zero.
|
||||
This function never writes outside of provided output buffer.
|
||||
|
||||
inputSize : Max supported value is 1 GB
|
||||
maxOutputSize : is maximum allowed size into the destination buffer (which must be already allocated)
|
||||
return : the number of output bytes written in buffer 'dest'
|
||||
or 0 if compression fails.
|
||||
*/
|
||||
|
||||
|
||||
int LZ4_compressHC2 (const char* source, char* dest, int inputSize, int compressionLevel);
|
||||
int LZ4_compressHC2_limitedOutput (const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel);
|
||||
/*
|
||||
Same functions as above, but with programmable 'compressionLevel'.
|
||||
Recommended values are between 4 and 9, although any value between 0 and 16 will work.
|
||||
'compressionLevel'==0 means use default 'compressionLevel' value.
|
||||
Values above 16 behave the same as 16.
|
||||
Equivalent variants exist for all other compression functions below.
|
||||
*/
|
||||
|
||||
/* Note :
|
||||
Decompression functions are provided within LZ4 source code (see "lz4.h") (BSD license)
|
||||
*/
|
||||
|
||||
|
||||
/**************************************
|
||||
Using an external allocation
|
||||
**************************************/
|
||||
int LZ4_sizeofStateHC(void);
|
||||
int LZ4_compressHC_withStateHC (void* state, const char* source, char* dest, int inputSize);
|
||||
int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* source, char* dest, int inputSize, int maxOutputSize);
|
||||
|
||||
int LZ4_compressHC2_withStateHC (void* state, const char* source, char* dest, int inputSize, int compressionLevel);
|
||||
int LZ4_compressHC2_limitedOutput_withStateHC(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel);
|
||||
|
||||
/*
|
||||
These functions are provided should you prefer to allocate memory for compression tables with your own allocation methods.
|
||||
To know how much memory must be allocated for the compression tables, use :
|
||||
int LZ4_sizeofStateHC();
|
||||
|
||||
Note that tables must be aligned for pointer (32 or 64 bits), otherwise compression will fail (return code 0).
|
||||
|
||||
The allocated memory can be provided to the compression functions using 'void* state' parameter.
|
||||
LZ4_compress_withStateHC() and LZ4_compress_limitedOutput_withStateHC() are equivalent to previously described functions.
|
||||
They just use the externally allocated memory for state instead of allocating their own (on stack, or on heap).
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**************************************
|
||||
Experimental Streaming Functions
|
||||
**************************************/
|
||||
#define LZ4_STREAMHCSIZE_U64 32774
|
||||
#define LZ4_STREAMHCSIZE (LZ4_STREAMHCSIZE_U64 * sizeof(unsigned long long))
|
||||
typedef struct { unsigned long long table[LZ4_STREAMHCSIZE_U64]; } LZ4_streamHC_t;
|
||||
/*
|
||||
LZ4_streamHC_t
|
||||
This structure allows static allocation of LZ4 HC streaming state.
|
||||
State must then be initialized using LZ4_resetStreamHC() before first use.
|
||||
|
||||
Static allocation should only be used with statically linked library.
|
||||
If you want to use LZ4 as a DLL, please use construction functions below, which are more future-proof.
|
||||
*/
|
||||
|
||||
|
||||
LZ4_streamHC_t* LZ4_createStreamHC(void);
|
||||
int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr);
|
||||
/*
|
||||
These functions create and release memory for LZ4 HC streaming state.
|
||||
Newly created states are already initialized.
|
||||
Existing state space can be re-used anytime using LZ4_resetStreamHC().
|
||||
If you use LZ4 as a DLL, please use these functions instead of direct struct allocation,
|
||||
to avoid size mismatch between different versions.
|
||||
*/
|
||||
|
||||
void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel);
|
||||
int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, const char* dictionary, int dictSize);
|
||||
|
||||
int LZ4_compressHC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize);
|
||||
int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize, int maxOutputSize);
|
||||
|
||||
int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int maxDictSize);
|
||||
|
||||
/*
|
||||
These functions compress data in successive blocks of any size, using previous blocks as dictionary.
|
||||
One key assumption is that each previous block will remain read-accessible while compressing next block.
|
||||
|
||||
Before starting compression, state must be properly initialized, using LZ4_resetStreamHC().
|
||||
A first "fictional block" can then be designated as initial dictionary, using LZ4_loadDictHC() (Optional).
|
||||
|
||||
Then, use LZ4_compressHC_continue() or LZ4_compressHC_limitedOutput_continue() to compress each successive block.
|
||||
They work like usual LZ4_compressHC() or LZ4_compressHC_limitedOutput(), but use previous memory blocks to improve compression.
|
||||
Previous memory blocks (including initial dictionary when present) must remain accessible and unmodified during compression.
|
||||
|
||||
If, for any reason, previous data block can't be preserved in memory during next compression block,
|
||||
you must save it to a safer memory space,
|
||||
using LZ4_saveDictHC().
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**************************************
|
||||
* Deprecated Streaming Functions
|
||||
* ************************************/
|
||||
/* Note : these streaming functions follows the older model, and should no longer be used */
|
||||
void* LZ4_createHC (const char* inputBuffer);
|
||||
char* LZ4_slideInputBufferHC (void* LZ4HC_Data);
|
||||
int LZ4_freeHC (void* LZ4HC_Data);
|
||||
|
||||
int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int compressionLevel);
|
||||
int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel);
|
||||
|
||||
int LZ4_sizeofStreamStateHC(void);
|
||||
int LZ4_resetStreamStateHC(void* state, const char* inputBuffer);
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
935
src/lz4/lib/xxhash.c
Normal file
@@ -0,0 +1,935 @@
|
||||
/*
|
||||
xxHash - Fast Hash algorithm
|
||||
Copyright (C) 2012-2015, Yann Collet
|
||||
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- xxHash source repository : http://code.google.com/p/xxhash/
|
||||
- xxHash source mirror : https://github.com/Cyan4973/xxHash
|
||||
- public discussion board : https://groups.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
|
||||
|
||||
/**************************************
|
||||
* Tuning parameters
|
||||
***************************************/
|
||||
/* Unaligned memory access is automatically enabled for "common" CPU, such as x86.
|
||||
* For others CPU, the compiler will be more cautious, and insert extra code to ensure aligned access is respected.
|
||||
* If you know your target CPU supports unaligned memory access, you want to force this option manually to improve performance.
|
||||
* You can also enable this parameter if you know your input data will always be aligned (boundaries of 4, for U32).
|
||||
*/
|
||||
#if defined(__ARM_FEATURE_UNALIGNED) || defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
|
||||
# define XXH_USE_UNALIGNED_ACCESS 1
|
||||
#endif
|
||||
|
||||
/* XXH_ACCEPT_NULL_INPUT_POINTER :
|
||||
* If the input pointer is a null pointer, xxHash default behavior is to trigger a memory access error, since it is a bad pointer.
|
||||
* When this option is enabled, xxHash output for null input pointers will be the same as a null-length input.
|
||||
* By default, this option is disabled. To enable it, uncomment below define :
|
||||
*/
|
||||
/* #define XXH_ACCEPT_NULL_INPUT_POINTER 1 */
|
||||
|
||||
/* XXH_FORCE_NATIVE_FORMAT :
|
||||
* By default, xxHash library provides endian-independant Hash values, based on little-endian convention.
|
||||
* Results are therefore identical for little-endian and big-endian CPU.
|
||||
* This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format.
|
||||
* Should endian-independance be of no importance for your application, you may set the #define below to 1.
|
||||
* It will improve speed for Big-endian CPU.
|
||||
* This option has no impact on Little_Endian CPU.
|
||||
*/
|
||||
#define XXH_FORCE_NATIVE_FORMAT 0
|
||||
|
||||
|
||||
/**************************************
|
||||
* Compiler Specific Options
|
||||
***************************************/
|
||||
#ifdef _MSC_VER /* Visual Studio */
|
||||
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
|
||||
# define FORCE_INLINE static __forceinline
|
||||
#else
|
||||
# if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
|
||||
# ifdef __GNUC__
|
||||
# define FORCE_INLINE static inline __attribute__((always_inline))
|
||||
# else
|
||||
# define FORCE_INLINE static inline
|
||||
# endif
|
||||
# else
|
||||
# define FORCE_INLINE static
|
||||
# endif /* __STDC_VERSION__ */
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************
|
||||
* Includes & Memory related functions
|
||||
***************************************/
|
||||
#include "xxhash.h"
|
||||
/* Modify the local functions below should you wish to use some other memory routines */
|
||||
/* for malloc(), free() */
|
||||
#include <stdlib.h>
|
||||
static void* XXH_malloc(size_t s) { return malloc(s); }
|
||||
static void XXH_free (void* p) { free(p); }
|
||||
/* for memcpy() */
|
||||
#include <string.h>
|
||||
static void* XXH_memcpy(void* dest, const void* src, size_t size)
|
||||
{
|
||||
return memcpy(dest,src,size);
|
||||
}
|
||||
|
||||
|
||||
/**************************************
|
||||
* Basic Types
|
||||
***************************************/
|
||||
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
|
||||
# include <stdint.h>
|
||||
typedef uint8_t BYTE;
|
||||
typedef uint16_t U16;
|
||||
typedef uint32_t U32;
|
||||
typedef int32_t S32;
|
||||
typedef uint64_t U64;
|
||||
#else
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned short U16;
|
||||
typedef unsigned int U32;
|
||||
typedef signed int S32;
|
||||
typedef unsigned long long U64;
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && !defined(XXH_USE_UNALIGNED_ACCESS)
|
||||
# define _PACKED __attribute__ ((packed))
|
||||
#else
|
||||
# define _PACKED
|
||||
#endif
|
||||
|
||||
#if !defined(XXH_USE_UNALIGNED_ACCESS) && !defined(__GNUC__)
|
||||
# ifdef __IBMC__
|
||||
# pragma pack(1)
|
||||
# else
|
||||
# pragma pack(push, 1)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
typedef struct _U32_S
|
||||
{
|
||||
U32 v;
|
||||
} _PACKED U32_S;
|
||||
typedef struct _U64_S
|
||||
{
|
||||
U64 v;
|
||||
} _PACKED U64_S;
|
||||
|
||||
#if !defined(XXH_USE_UNALIGNED_ACCESS) && !defined(__GNUC__)
|
||||
# pragma pack(pop)
|
||||
#endif
|
||||
|
||||
#define A32(x) (((U32_S *)(x))->v)
|
||||
#define A64(x) (((U64_S *)(x))->v)
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Compiler-specific Functions and Macros
|
||||
******************************************/
|
||||
#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
|
||||
|
||||
/* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */
|
||||
#if defined(_MSC_VER)
|
||||
# define XXH_rotl32(x,r) _rotl(x,r)
|
||||
# define XXH_rotl64(x,r) _rotl64(x,r)
|
||||
#else
|
||||
# define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))
|
||||
# define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r)))
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) /* Visual Studio */
|
||||
# define XXH_swap32 _byteswap_ulong
|
||||
# define XXH_swap64 _byteswap_uint64
|
||||
#elif GCC_VERSION >= 403
|
||||
# define XXH_swap32 __builtin_bswap32
|
||||
# define XXH_swap64 __builtin_bswap64
|
||||
#else
|
||||
static U32 XXH_swap32 (U32 x)
|
||||
{
|
||||
return ((x << 24) & 0xff000000 ) |
|
||||
((x << 8) & 0x00ff0000 ) |
|
||||
((x >> 8) & 0x0000ff00 ) |
|
||||
((x >> 24) & 0x000000ff );
|
||||
}
|
||||
static U64 XXH_swap64 (U64 x)
|
||||
{
|
||||
return ((x << 56) & 0xff00000000000000ULL) |
|
||||
((x << 40) & 0x00ff000000000000ULL) |
|
||||
((x << 24) & 0x0000ff0000000000ULL) |
|
||||
((x << 8) & 0x000000ff00000000ULL) |
|
||||
((x >> 8) & 0x00000000ff000000ULL) |
|
||||
((x >> 24) & 0x0000000000ff0000ULL) |
|
||||
((x >> 40) & 0x000000000000ff00ULL) |
|
||||
((x >> 56) & 0x00000000000000ffULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************
|
||||
* Constants
|
||||
***************************************/
|
||||
#define PRIME32_1 2654435761U
|
||||
#define PRIME32_2 2246822519U
|
||||
#define PRIME32_3 3266489917U
|
||||
#define PRIME32_4 668265263U
|
||||
#define PRIME32_5 374761393U
|
||||
|
||||
#define PRIME64_1 11400714785074694791ULL
|
||||
#define PRIME64_2 14029467366897019727ULL
|
||||
#define PRIME64_3 1609587929392839161ULL
|
||||
#define PRIME64_4 9650029242287828579ULL
|
||||
#define PRIME64_5 2870177450012600261ULL
|
||||
|
||||
|
||||
/***************************************
|
||||
* Architecture Macros
|
||||
****************************************/
|
||||
typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess;
|
||||
#ifndef XXH_CPU_LITTLE_ENDIAN /* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example using a compiler switch */
|
||||
static const int one = 1;
|
||||
# define XXH_CPU_LITTLE_ENDIAN (*(char*)(&one))
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************
|
||||
* Macros
|
||||
***************************************/
|
||||
#define XXH_STATIC_ASSERT(c) { enum { XXH_static_assert = 1/(!!(c)) }; } /* use only *after* variable declarations */
|
||||
|
||||
|
||||
/****************************
|
||||
* Memory reads
|
||||
*****************************/
|
||||
typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment;
|
||||
|
||||
FORCE_INLINE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
|
||||
{
|
||||
if (align==XXH_unaligned)
|
||||
return endian==XXH_littleEndian ? A32(ptr) : XXH_swap32(A32(ptr));
|
||||
else
|
||||
return endian==XXH_littleEndian ? *(U32*)ptr : XXH_swap32(*(U32*)ptr);
|
||||
}
|
||||
|
||||
FORCE_INLINE U32 XXH_readLE32(const void* ptr, XXH_endianess endian)
|
||||
{
|
||||
return XXH_readLE32_align(ptr, endian, XXH_unaligned);
|
||||
}
|
||||
|
||||
FORCE_INLINE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
|
||||
{
|
||||
if (align==XXH_unaligned)
|
||||
return endian==XXH_littleEndian ? A64(ptr) : XXH_swap64(A64(ptr));
|
||||
else
|
||||
return endian==XXH_littleEndian ? *(U64*)ptr : XXH_swap64(*(U64*)ptr);
|
||||
}
|
||||
|
||||
FORCE_INLINE U64 XXH_readLE64(const void* ptr, XXH_endianess endian)
|
||||
{
|
||||
return XXH_readLE64_align(ptr, endian, XXH_unaligned);
|
||||
}
|
||||
|
||||
|
||||
/****************************
|
||||
* Simple Hash Functions
|
||||
*****************************/
|
||||
FORCE_INLINE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align)
|
||||
{
|
||||
const BYTE* p = (const BYTE*)input;
|
||||
const BYTE* bEnd = p + len;
|
||||
U32 h32;
|
||||
#define XXH_get32bits(p) XXH_readLE32_align(p, endian, align)
|
||||
|
||||
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
|
||||
if (p==NULL)
|
||||
{
|
||||
len=0;
|
||||
bEnd=p=(const BYTE*)(size_t)16;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (len>=16)
|
||||
{
|
||||
const BYTE* const limit = bEnd - 16;
|
||||
U32 v1 = seed + PRIME32_1 + PRIME32_2;
|
||||
U32 v2 = seed + PRIME32_2;
|
||||
U32 v3 = seed + 0;
|
||||
U32 v4 = seed - PRIME32_1;
|
||||
|
||||
do
|
||||
{
|
||||
v1 += XXH_get32bits(p) * PRIME32_2;
|
||||
v1 = XXH_rotl32(v1, 13);
|
||||
v1 *= PRIME32_1;
|
||||
p+=4;
|
||||
v2 += XXH_get32bits(p) * PRIME32_2;
|
||||
v2 = XXH_rotl32(v2, 13);
|
||||
v2 *= PRIME32_1;
|
||||
p+=4;
|
||||
v3 += XXH_get32bits(p) * PRIME32_2;
|
||||
v3 = XXH_rotl32(v3, 13);
|
||||
v3 *= PRIME32_1;
|
||||
p+=4;
|
||||
v4 += XXH_get32bits(p) * PRIME32_2;
|
||||
v4 = XXH_rotl32(v4, 13);
|
||||
v4 *= PRIME32_1;
|
||||
p+=4;
|
||||
}
|
||||
while (p<=limit);
|
||||
|
||||
h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18);
|
||||
}
|
||||
else
|
||||
{
|
||||
h32 = seed + PRIME32_5;
|
||||
}
|
||||
|
||||
h32 += (U32) len;
|
||||
|
||||
while (p+4<=bEnd)
|
||||
{
|
||||
h32 += XXH_get32bits(p) * PRIME32_3;
|
||||
h32 = XXH_rotl32(h32, 17) * PRIME32_4 ;
|
||||
p+=4;
|
||||
}
|
||||
|
||||
while (p<bEnd)
|
||||
{
|
||||
h32 += (*p) * PRIME32_5;
|
||||
h32 = XXH_rotl32(h32, 11) * PRIME32_1 ;
|
||||
p++;
|
||||
}
|
||||
|
||||
h32 ^= h32 >> 15;
|
||||
h32 *= PRIME32_2;
|
||||
h32 ^= h32 >> 13;
|
||||
h32 *= PRIME32_3;
|
||||
h32 ^= h32 >> 16;
|
||||
|
||||
return h32;
|
||||
}
|
||||
|
||||
|
||||
unsigned int XXH32 (const void* input, size_t len, unsigned seed)
|
||||
{
|
||||
#if 0
|
||||
/* Simple version, good for code maintenance, but unfortunately slow for small inputs */
|
||||
XXH32_state_t state;
|
||||
XXH32_reset(&state, seed);
|
||||
XXH32_update(&state, input, len);
|
||||
return XXH32_digest(&state);
|
||||
#else
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
# if !defined(XXH_USE_UNALIGNED_ACCESS)
|
||||
if ((((size_t)input) & 3) == 0) /* Input is aligned, let's leverage the speed advantage */
|
||||
{
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
|
||||
else
|
||||
return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
|
||||
}
|
||||
# endif
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
|
||||
else
|
||||
return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
|
||||
#endif
|
||||
}
|
||||
|
||||
FORCE_INLINE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align)
|
||||
{
|
||||
const BYTE* p = (const BYTE*)input;
|
||||
const BYTE* bEnd = p + len;
|
||||
U64 h64;
|
||||
#define XXH_get64bits(p) XXH_readLE64_align(p, endian, align)
|
||||
|
||||
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
|
||||
if (p==NULL)
|
||||
{
|
||||
len=0;
|
||||
bEnd=p=(const BYTE*)(size_t)32;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (len>=32)
|
||||
{
|
||||
const BYTE* const limit = bEnd - 32;
|
||||
U64 v1 = seed + PRIME64_1 + PRIME64_2;
|
||||
U64 v2 = seed + PRIME64_2;
|
||||
U64 v3 = seed + 0;
|
||||
U64 v4 = seed - PRIME64_1;
|
||||
|
||||
do
|
||||
{
|
||||
v1 += XXH_get64bits(p) * PRIME64_2;
|
||||
p+=8;
|
||||
v1 = XXH_rotl64(v1, 31);
|
||||
v1 *= PRIME64_1;
|
||||
v2 += XXH_get64bits(p) * PRIME64_2;
|
||||
p+=8;
|
||||
v2 = XXH_rotl64(v2, 31);
|
||||
v2 *= PRIME64_1;
|
||||
v3 += XXH_get64bits(p) * PRIME64_2;
|
||||
p+=8;
|
||||
v3 = XXH_rotl64(v3, 31);
|
||||
v3 *= PRIME64_1;
|
||||
v4 += XXH_get64bits(p) * PRIME64_2;
|
||||
p+=8;
|
||||
v4 = XXH_rotl64(v4, 31);
|
||||
v4 *= PRIME64_1;
|
||||
}
|
||||
while (p<=limit);
|
||||
|
||||
h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
|
||||
|
||||
v1 *= PRIME64_2;
|
||||
v1 = XXH_rotl64(v1, 31);
|
||||
v1 *= PRIME64_1;
|
||||
h64 ^= v1;
|
||||
h64 = h64 * PRIME64_1 + PRIME64_4;
|
||||
|
||||
v2 *= PRIME64_2;
|
||||
v2 = XXH_rotl64(v2, 31);
|
||||
v2 *= PRIME64_1;
|
||||
h64 ^= v2;
|
||||
h64 = h64 * PRIME64_1 + PRIME64_4;
|
||||
|
||||
v3 *= PRIME64_2;
|
||||
v3 = XXH_rotl64(v3, 31);
|
||||
v3 *= PRIME64_1;
|
||||
h64 ^= v3;
|
||||
h64 = h64 * PRIME64_1 + PRIME64_4;
|
||||
|
||||
v4 *= PRIME64_2;
|
||||
v4 = XXH_rotl64(v4, 31);
|
||||
v4 *= PRIME64_1;
|
||||
h64 ^= v4;
|
||||
h64 = h64 * PRIME64_1 + PRIME64_4;
|
||||
}
|
||||
else
|
||||
{
|
||||
h64 = seed + PRIME64_5;
|
||||
}
|
||||
|
||||
h64 += (U64) len;
|
||||
|
||||
while (p+8<=bEnd)
|
||||
{
|
||||
U64 k1 = XXH_get64bits(p);
|
||||
k1 *= PRIME64_2;
|
||||
k1 = XXH_rotl64(k1,31);
|
||||
k1 *= PRIME64_1;
|
||||
h64 ^= k1;
|
||||
h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
|
||||
p+=8;
|
||||
}
|
||||
|
||||
if (p+4<=bEnd)
|
||||
{
|
||||
h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1;
|
||||
h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
|
||||
p+=4;
|
||||
}
|
||||
|
||||
while (p<bEnd)
|
||||
{
|
||||
h64 ^= (*p) * PRIME64_5;
|
||||
h64 = XXH_rotl64(h64, 11) * PRIME64_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h64 ^= h64 >> 33;
|
||||
h64 *= PRIME64_2;
|
||||
h64 ^= h64 >> 29;
|
||||
h64 *= PRIME64_3;
|
||||
h64 ^= h64 >> 32;
|
||||
|
||||
return h64;
|
||||
}
|
||||
|
||||
|
||||
unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed)
|
||||
{
|
||||
#if 0
|
||||
/* Simple version, good for code maintenance, but unfortunately slow for small inputs */
|
||||
XXH64_state_t state;
|
||||
XXH64_reset(&state, seed);
|
||||
XXH64_update(&state, input, len);
|
||||
return XXH64_digest(&state);
|
||||
#else
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
# if !defined(XXH_USE_UNALIGNED_ACCESS)
|
||||
if ((((size_t)input) & 7)==0) /* Input is aligned, let's leverage the speed advantage */
|
||||
{
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
|
||||
else
|
||||
return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
|
||||
}
|
||||
# endif
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
|
||||
else
|
||||
return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************
|
||||
* Advanced Hash Functions
|
||||
****************************************************/
|
||||
|
||||
/*** Allocation ***/
|
||||
typedef struct
|
||||
{
|
||||
U64 total_len;
|
||||
U32 seed;
|
||||
U32 v1;
|
||||
U32 v2;
|
||||
U32 v3;
|
||||
U32 v4;
|
||||
U32 mem32[4]; /* defined as U32 for alignment */
|
||||
U32 memsize;
|
||||
} XXH_istate32_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
U64 total_len;
|
||||
U64 seed;
|
||||
U64 v1;
|
||||
U64 v2;
|
||||
U64 v3;
|
||||
U64 v4;
|
||||
U64 mem64[4]; /* defined as U64 for alignment */
|
||||
U32 memsize;
|
||||
} XXH_istate64_t;
|
||||
|
||||
|
||||
XXH32_state_t* XXH32_createState(void)
|
||||
{
|
||||
XXH_STATIC_ASSERT(sizeof(XXH32_state_t) >= sizeof(XXH_istate32_t)); /* A compilation error here means XXH32_state_t is not large enough */
|
||||
return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t));
|
||||
}
|
||||
XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr)
|
||||
{
|
||||
XXH_free(statePtr);
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
XXH64_state_t* XXH64_createState(void)
|
||||
{
|
||||
XXH_STATIC_ASSERT(sizeof(XXH64_state_t) >= sizeof(XXH_istate64_t)); /* A compilation error here means XXH64_state_t is not large enough */
|
||||
return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t));
|
||||
}
|
||||
XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr)
|
||||
{
|
||||
XXH_free(statePtr);
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
|
||||
/*** Hash feed ***/
|
||||
|
||||
XXH_errorcode XXH32_reset(XXH32_state_t* state_in, U32 seed)
|
||||
{
|
||||
XXH_istate32_t* state = (XXH_istate32_t*) state_in;
|
||||
state->seed = seed;
|
||||
state->v1 = seed + PRIME32_1 + PRIME32_2;
|
||||
state->v2 = seed + PRIME32_2;
|
||||
state->v3 = seed + 0;
|
||||
state->v4 = seed - PRIME32_1;
|
||||
state->total_len = 0;
|
||||
state->memsize = 0;
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
XXH_errorcode XXH64_reset(XXH64_state_t* state_in, unsigned long long seed)
|
||||
{
|
||||
XXH_istate64_t* state = (XXH_istate64_t*) state_in;
|
||||
state->seed = seed;
|
||||
state->v1 = seed + PRIME64_1 + PRIME64_2;
|
||||
state->v2 = seed + PRIME64_2;
|
||||
state->v3 = seed + 0;
|
||||
state->v4 = seed - PRIME64_1;
|
||||
state->total_len = 0;
|
||||
state->memsize = 0;
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE XXH_errorcode XXH32_update_endian (XXH32_state_t* state_in, const void* input, size_t len, XXH_endianess endian)
|
||||
{
|
||||
XXH_istate32_t* state = (XXH_istate32_t *) state_in;
|
||||
const BYTE* p = (const BYTE*)input;
|
||||
const BYTE* const bEnd = p + len;
|
||||
|
||||
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
|
||||
if (input==NULL) return XXH_ERROR;
|
||||
#endif
|
||||
|
||||
state->total_len += len;
|
||||
|
||||
if (state->memsize + len < 16) /* fill in tmp buffer */
|
||||
{
|
||||
XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, len);
|
||||
state->memsize += (U32)len;
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
if (state->memsize) /* some data left from previous update */
|
||||
{
|
||||
XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, 16-state->memsize);
|
||||
{
|
||||
const U32* p32 = state->mem32;
|
||||
state->v1 += XXH_readLE32(p32, endian) * PRIME32_2;
|
||||
state->v1 = XXH_rotl32(state->v1, 13);
|
||||
state->v1 *= PRIME32_1;
|
||||
p32++;
|
||||
state->v2 += XXH_readLE32(p32, endian) * PRIME32_2;
|
||||
state->v2 = XXH_rotl32(state->v2, 13);
|
||||
state->v2 *= PRIME32_1;
|
||||
p32++;
|
||||
state->v3 += XXH_readLE32(p32, endian) * PRIME32_2;
|
||||
state->v3 = XXH_rotl32(state->v3, 13);
|
||||
state->v3 *= PRIME32_1;
|
||||
p32++;
|
||||
state->v4 += XXH_readLE32(p32, endian) * PRIME32_2;
|
||||
state->v4 = XXH_rotl32(state->v4, 13);
|
||||
state->v4 *= PRIME32_1;
|
||||
p32++;
|
||||
}
|
||||
p += 16-state->memsize;
|
||||
state->memsize = 0;
|
||||
}
|
||||
|
||||
if (p <= bEnd-16)
|
||||
{
|
||||
const BYTE* const limit = bEnd - 16;
|
||||
U32 v1 = state->v1;
|
||||
U32 v2 = state->v2;
|
||||
U32 v3 = state->v3;
|
||||
U32 v4 = state->v4;
|
||||
|
||||
do
|
||||
{
|
||||
v1 += XXH_readLE32(p, endian) * PRIME32_2;
|
||||
v1 = XXH_rotl32(v1, 13);
|
||||
v1 *= PRIME32_1;
|
||||
p+=4;
|
||||
v2 += XXH_readLE32(p, endian) * PRIME32_2;
|
||||
v2 = XXH_rotl32(v2, 13);
|
||||
v2 *= PRIME32_1;
|
||||
p+=4;
|
||||
v3 += XXH_readLE32(p, endian) * PRIME32_2;
|
||||
v3 = XXH_rotl32(v3, 13);
|
||||
v3 *= PRIME32_1;
|
||||
p+=4;
|
||||
v4 += XXH_readLE32(p, endian) * PRIME32_2;
|
||||
v4 = XXH_rotl32(v4, 13);
|
||||
v4 *= PRIME32_1;
|
||||
p+=4;
|
||||
}
|
||||
while (p<=limit);
|
||||
|
||||
state->v1 = v1;
|
||||
state->v2 = v2;
|
||||
state->v3 = v3;
|
||||
state->v4 = v4;
|
||||
}
|
||||
|
||||
if (p < bEnd)
|
||||
{
|
||||
XXH_memcpy(state->mem32, p, bEnd-p);
|
||||
state->memsize = (int)(bEnd-p);
|
||||
}
|
||||
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* input, size_t len)
|
||||
{
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH32_update_endian(state_in, input, len, XXH_littleEndian);
|
||||
else
|
||||
return XXH32_update_endian(state_in, input, len, XXH_bigEndian);
|
||||
}
|
||||
|
||||
|
||||
|
||||
FORCE_INLINE U32 XXH32_digest_endian (const XXH32_state_t* state_in, XXH_endianess endian)
|
||||
{
|
||||
XXH_istate32_t* state = (XXH_istate32_t*) state_in;
|
||||
const BYTE * p = (const BYTE*)state->mem32;
|
||||
BYTE* bEnd = (BYTE*)(state->mem32) + state->memsize;
|
||||
U32 h32;
|
||||
|
||||
if (state->total_len >= 16)
|
||||
{
|
||||
h32 = XXH_rotl32(state->v1, 1) + XXH_rotl32(state->v2, 7) + XXH_rotl32(state->v3, 12) + XXH_rotl32(state->v4, 18);
|
||||
}
|
||||
else
|
||||
{
|
||||
h32 = state->seed + PRIME32_5;
|
||||
}
|
||||
|
||||
h32 += (U32) state->total_len;
|
||||
|
||||
while (p+4<=bEnd)
|
||||
{
|
||||
h32 += XXH_readLE32(p, endian) * PRIME32_3;
|
||||
h32 = XXH_rotl32(h32, 17) * PRIME32_4;
|
||||
p+=4;
|
||||
}
|
||||
|
||||
while (p<bEnd)
|
||||
{
|
||||
h32 += (*p) * PRIME32_5;
|
||||
h32 = XXH_rotl32(h32, 11) * PRIME32_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h32 ^= h32 >> 15;
|
||||
h32 *= PRIME32_2;
|
||||
h32 ^= h32 >> 13;
|
||||
h32 *= PRIME32_3;
|
||||
h32 ^= h32 >> 16;
|
||||
|
||||
return h32;
|
||||
}
|
||||
|
||||
|
||||
U32 XXH32_digest (const XXH32_state_t* state_in)
|
||||
{
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH32_digest_endian(state_in, XXH_littleEndian);
|
||||
else
|
||||
return XXH32_digest_endian(state_in, XXH_bigEndian);
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE XXH_errorcode XXH64_update_endian (XXH64_state_t* state_in, const void* input, size_t len, XXH_endianess endian)
|
||||
{
|
||||
XXH_istate64_t * state = (XXH_istate64_t *) state_in;
|
||||
const BYTE* p = (const BYTE*)input;
|
||||
const BYTE* const bEnd = p + len;
|
||||
|
||||
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
|
||||
if (input==NULL) return XXH_ERROR;
|
||||
#endif
|
||||
|
||||
state->total_len += len;
|
||||
|
||||
if (state->memsize + len < 32) /* fill in tmp buffer */
|
||||
{
|
||||
XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, len);
|
||||
state->memsize += (U32)len;
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
if (state->memsize) /* some data left from previous update */
|
||||
{
|
||||
XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, 32-state->memsize);
|
||||
{
|
||||
const U64* p64 = state->mem64;
|
||||
state->v1 += XXH_readLE64(p64, endian) * PRIME64_2;
|
||||
state->v1 = XXH_rotl64(state->v1, 31);
|
||||
state->v1 *= PRIME64_1;
|
||||
p64++;
|
||||
state->v2 += XXH_readLE64(p64, endian) * PRIME64_2;
|
||||
state->v2 = XXH_rotl64(state->v2, 31);
|
||||
state->v2 *= PRIME64_1;
|
||||
p64++;
|
||||
state->v3 += XXH_readLE64(p64, endian) * PRIME64_2;
|
||||
state->v3 = XXH_rotl64(state->v3, 31);
|
||||
state->v3 *= PRIME64_1;
|
||||
p64++;
|
||||
state->v4 += XXH_readLE64(p64, endian) * PRIME64_2;
|
||||
state->v4 = XXH_rotl64(state->v4, 31);
|
||||
state->v4 *= PRIME64_1;
|
||||
p64++;
|
||||
}
|
||||
p += 32-state->memsize;
|
||||
state->memsize = 0;
|
||||
}
|
||||
|
||||
if (p+32 <= bEnd)
|
||||
{
|
||||
const BYTE* const limit = bEnd - 32;
|
||||
U64 v1 = state->v1;
|
||||
U64 v2 = state->v2;
|
||||
U64 v3 = state->v3;
|
||||
U64 v4 = state->v4;
|
||||
|
||||
do
|
||||
{
|
||||
v1 += XXH_readLE64(p, endian) * PRIME64_2;
|
||||
v1 = XXH_rotl64(v1, 31);
|
||||
v1 *= PRIME64_1;
|
||||
p+=8;
|
||||
v2 += XXH_readLE64(p, endian) * PRIME64_2;
|
||||
v2 = XXH_rotl64(v2, 31);
|
||||
v2 *= PRIME64_1;
|
||||
p+=8;
|
||||
v3 += XXH_readLE64(p, endian) * PRIME64_2;
|
||||
v3 = XXH_rotl64(v3, 31);
|
||||
v3 *= PRIME64_1;
|
||||
p+=8;
|
||||
v4 += XXH_readLE64(p, endian) * PRIME64_2;
|
||||
v4 = XXH_rotl64(v4, 31);
|
||||
v4 *= PRIME64_1;
|
||||
p+=8;
|
||||
}
|
||||
while (p<=limit);
|
||||
|
||||
state->v1 = v1;
|
||||
state->v2 = v2;
|
||||
state->v3 = v3;
|
||||
state->v4 = v4;
|
||||
}
|
||||
|
||||
if (p < bEnd)
|
||||
{
|
||||
XXH_memcpy(state->mem64, p, bEnd-p);
|
||||
state->memsize = (int)(bEnd-p);
|
||||
}
|
||||
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* input, size_t len)
|
||||
{
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH64_update_endian(state_in, input, len, XXH_littleEndian);
|
||||
else
|
||||
return XXH64_update_endian(state_in, input, len, XXH_bigEndian);
|
||||
}
|
||||
|
||||
|
||||
|
||||
FORCE_INLINE U64 XXH64_digest_endian (const XXH64_state_t* state_in, XXH_endianess endian)
|
||||
{
|
||||
XXH_istate64_t * state = (XXH_istate64_t *) state_in;
|
||||
const BYTE * p = (const BYTE*)state->mem64;
|
||||
BYTE* bEnd = (BYTE*)state->mem64 + state->memsize;
|
||||
U64 h64;
|
||||
|
||||
if (state->total_len >= 32)
|
||||
{
|
||||
U64 v1 = state->v1;
|
||||
U64 v2 = state->v2;
|
||||
U64 v3 = state->v3;
|
||||
U64 v4 = state->v4;
|
||||
|
||||
h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
|
||||
|
||||
v1 *= PRIME64_2;
|
||||
v1 = XXH_rotl64(v1, 31);
|
||||
v1 *= PRIME64_1;
|
||||
h64 ^= v1;
|
||||
h64 = h64*PRIME64_1 + PRIME64_4;
|
||||
|
||||
v2 *= PRIME64_2;
|
||||
v2 = XXH_rotl64(v2, 31);
|
||||
v2 *= PRIME64_1;
|
||||
h64 ^= v2;
|
||||
h64 = h64*PRIME64_1 + PRIME64_4;
|
||||
|
||||
v3 *= PRIME64_2;
|
||||
v3 = XXH_rotl64(v3, 31);
|
||||
v3 *= PRIME64_1;
|
||||
h64 ^= v3;
|
||||
h64 = h64*PRIME64_1 + PRIME64_4;
|
||||
|
||||
v4 *= PRIME64_2;
|
||||
v4 = XXH_rotl64(v4, 31);
|
||||
v4 *= PRIME64_1;
|
||||
h64 ^= v4;
|
||||
h64 = h64*PRIME64_1 + PRIME64_4;
|
||||
}
|
||||
else
|
||||
{
|
||||
h64 = state->seed + PRIME64_5;
|
||||
}
|
||||
|
||||
h64 += (U64) state->total_len;
|
||||
|
||||
while (p+8<=bEnd)
|
||||
{
|
||||
U64 k1 = XXH_readLE64(p, endian);
|
||||
k1 *= PRIME64_2;
|
||||
k1 = XXH_rotl64(k1,31);
|
||||
k1 *= PRIME64_1;
|
||||
h64 ^= k1;
|
||||
h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
|
||||
p+=8;
|
||||
}
|
||||
|
||||
if (p+4<=bEnd)
|
||||
{
|
||||
h64 ^= (U64)(XXH_readLE32(p, endian)) * PRIME64_1;
|
||||
h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
|
||||
p+=4;
|
||||
}
|
||||
|
||||
while (p<bEnd)
|
||||
{
|
||||
h64 ^= (*p) * PRIME64_5;
|
||||
h64 = XXH_rotl64(h64, 11) * PRIME64_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h64 ^= h64 >> 33;
|
||||
h64 *= PRIME64_2;
|
||||
h64 ^= h64 >> 29;
|
||||
h64 *= PRIME64_3;
|
||||
h64 ^= h64 >> 32;
|
||||
|
||||
return h64;
|
||||
}
|
||||
|
||||
|
||||
unsigned long long XXH64_digest (const XXH64_state_t* state_in)
|
||||
{
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH64_digest_endian(state_in, XXH_littleEndian);
|
||||
else
|
||||
return XXH64_digest_endian(state_in, XXH_bigEndian);
|
||||
}
|
||||
|
||||
|
||||
156
src/lz4/lib/xxhash.h
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
xxHash - Extremely Fast Hash algorithm
|
||||
Header File
|
||||
Copyright (C) 2012-2014, Yann Collet.
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- xxHash source repository : http://code.google.com/p/xxhash/
|
||||
*/
|
||||
|
||||
/* Notice extracted from xxHash homepage :
|
||||
|
||||
xxHash is an extremely fast Hash algorithm, running at RAM speed limits.
|
||||
It also successfully passes all tests from the SMHasher suite.
|
||||
|
||||
Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz)
|
||||
|
||||
Name Speed Q.Score Author
|
||||
xxHash 5.4 GB/s 10
|
||||
CrapWow 3.2 GB/s 2 Andrew
|
||||
MumurHash 3a 2.7 GB/s 10 Austin Appleby
|
||||
SpookyHash 2.0 GB/s 10 Bob Jenkins
|
||||
SBox 1.4 GB/s 9 Bret Mulvey
|
||||
Lookup3 1.2 GB/s 9 Bob Jenkins
|
||||
SuperFastHash 1.2 GB/s 1 Paul Hsieh
|
||||
CityHash64 1.05 GB/s 10 Pike & Alakuijala
|
||||
FNV 0.55 GB/s 5 Fowler, Noll, Vo
|
||||
CRC32 0.43 GB/s 9
|
||||
MD5-32 0.33 GB/s 10 Ronald L. Rivest
|
||||
SHA1-32 0.28 GB/s 10
|
||||
|
||||
Q.Score is a measure of quality of the hash function.
|
||||
It depends on successfully passing SMHasher test set.
|
||||
10 is a perfect score.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************
|
||||
Includes
|
||||
*****************************/
|
||||
#include <stddef.h> /* size_t */
|
||||
|
||||
|
||||
/*****************************
|
||||
Type
|
||||
*****************************/
|
||||
typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;
|
||||
|
||||
|
||||
|
||||
/*****************************
|
||||
Simple Hash Functions
|
||||
*****************************/
|
||||
|
||||
unsigned int XXH32 (const void* input, size_t length, unsigned seed);
|
||||
unsigned long long XXH64 (const void* input, size_t length, unsigned long long seed);
|
||||
|
||||
/*
|
||||
XXH32() :
|
||||
Calculate the 32-bits hash of sequence "length" bytes stored at memory address "input".
|
||||
The memory between input & input+length must be valid (allocated and read-accessible).
|
||||
"seed" can be used to alter the result predictably.
|
||||
This function successfully passes all SMHasher tests.
|
||||
Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s
|
||||
XXH64() :
|
||||
Calculate the 64-bits hash of sequence of length "len" stored at memory address "input".
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*****************************
|
||||
Advanced Hash Functions
|
||||
*****************************/
|
||||
typedef struct { long long ll[ 6]; } XXH32_state_t;
|
||||
typedef struct { long long ll[11]; } XXH64_state_t;
|
||||
|
||||
/*
|
||||
These structures allow static allocation of XXH states.
|
||||
States must then be initialized using XXHnn_reset() before first use.
|
||||
|
||||
If you prefer dynamic allocation, please refer to functions below.
|
||||
*/
|
||||
|
||||
XXH32_state_t* XXH32_createState(void);
|
||||
XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr);
|
||||
|
||||
XXH64_state_t* XXH64_createState(void);
|
||||
XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr);
|
||||
|
||||
/*
|
||||
These functions create and release memory for XXH state.
|
||||
States must then be initialized using XXHnn_reset() before first use.
|
||||
*/
|
||||
|
||||
|
||||
XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, unsigned seed);
|
||||
XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length);
|
||||
unsigned int XXH32_digest (const XXH32_state_t* statePtr);
|
||||
|
||||
XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, unsigned long long seed);
|
||||
XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length);
|
||||
unsigned long long XXH64_digest (const XXH64_state_t* statePtr);
|
||||
|
||||
/*
|
||||
These functions calculate the xxHash of an input provided in multiple smaller packets,
|
||||
as opposed to an input provided as a single block.
|
||||
|
||||
XXH state space must first be allocated, using either static or dynamic method provided above.
|
||||
|
||||
Start a new hash by initializing state with a seed, using XXHnn_reset().
|
||||
|
||||
Then, feed the hash state by calling XXHnn_update() as many times as necessary.
|
||||
Obviously, input must be valid, meaning allocated and read accessible.
|
||||
The function returns an error code, with 0 meaning OK, and any other value meaning there is an error.
|
||||
|
||||
Finally, you can produce a hash anytime, by using XXHnn_digest().
|
||||
This function returns the final nn-bits hash.
|
||||
You can nonetheless continue feeding the hash state with more input,
|
||||
and therefore get some new hashes, by calling again XXHnn_digest().
|
||||
|
||||
When you are done, don't forget to free XXH state space, using typically XXHnn_freeState().
|
||||
*/
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
120
src/lz4/lz4_block_format.txt
Normal file
@@ -0,0 +1,120 @@
|
||||
LZ4 Format Description
|
||||
Last revised: 2012-02-27
|
||||
Author : Y. Collet
|
||||
|
||||
|
||||
|
||||
This small specification intents to provide enough information
|
||||
to anyone willing to produce LZ4-compatible compressed data blocks
|
||||
using any programming language.
|
||||
|
||||
LZ4 is an LZ77-type compressor with a fixed, byte-oriented encoding.
|
||||
The most important design principle behind LZ4 is simplicity.
|
||||
It helps to create an easy to read and maintain source code.
|
||||
It also helps later on for optimisations, compactness, and speed.
|
||||
There is no entropy encoder backend nor framing layer.
|
||||
The latter is assumed to be handled by other parts of the system.
|
||||
|
||||
This document only describes the format,
|
||||
not how the LZ4 compressor nor decompressor actually work.
|
||||
The correctness of the decompressor should not depend
|
||||
on implementation details of the compressor, and vice versa.
|
||||
|
||||
|
||||
|
||||
-- Compressed block format --
|
||||
|
||||
An LZ4 compressed block is composed of sequences.
|
||||
Schematically, a sequence is a suite of literals, followed by a match copy.
|
||||
|
||||
Each sequence starts with a token.
|
||||
The token is a one byte value, separated into two 4-bits fields.
|
||||
Therefore each field ranges from 0 to 15.
|
||||
|
||||
|
||||
The first field uses the 4 high-bits of the token.
|
||||
It provides the length of literals to follow.
|
||||
(Note : a literal is a not-compressed byte).
|
||||
If the field value is 0, then there is no literal.
|
||||
If it is 15, then we need to add some more bytes to indicate the full length.
|
||||
Each additionnal byte then represent a value from 0 to 255,
|
||||
which is added to the previous value to produce a total length.
|
||||
When the byte value is 255, another byte is output.
|
||||
There can be any number of bytes following the token. There is no "size limit".
|
||||
(Sidenote this is why a not-compressible input block is expanded by 0.4%).
|
||||
|
||||
Example 1 : A length of 48 will be represented as :
|
||||
- 15 : value for the 4-bits High field
|
||||
- 33 : (=48-15) remaining length to reach 48
|
||||
|
||||
Example 2 : A length of 280 will be represented as :
|
||||
- 15 : value for the 4-bits High field
|
||||
- 255 : following byte is maxed, since 280-15 >= 255
|
||||
- 10 : (=280 - 15 - 255) ) remaining length to reach 280
|
||||
|
||||
Example 3 : A length of 15 will be represented as :
|
||||
- 15 : value for the 4-bits High field
|
||||
- 0 : (=15-15) yes, the zero must be output
|
||||
|
||||
Following the token and optional length bytes, are the literals themselves.
|
||||
They are exactly as numerous as previously decoded (length of literals).
|
||||
It's possible that there are zero literal.
|
||||
|
||||
|
||||
Following the literals is the match copy operation.
|
||||
|
||||
It starts by the offset.
|
||||
This is a 2 bytes value, in little endian format.
|
||||
|
||||
The offset represents the position of the match to be copied from.
|
||||
1 means "current position - 1 byte".
|
||||
The maximum offset value is 65535, 65536 cannot be coded.
|
||||
Note that 0 is an invalid value, not used.
|
||||
|
||||
Then we need to extract the match length.
|
||||
For this, we use the second token field, the low 4-bits.
|
||||
Value, obviously, ranges from 0 to 15.
|
||||
However here, 0 means that the copy operation will be minimal.
|
||||
The minimum length of a match, called minmatch, is 4.
|
||||
As a consequence, a 0 value means 4 bytes, and a value of 15 means 19+ bytes.
|
||||
Similar to literal length, on reaching the highest possible value (15),
|
||||
we output additional bytes, one at a time, with values ranging from 0 to 255.
|
||||
They are added to total to provide the final match length.
|
||||
A 255 value means there is another byte to read and add.
|
||||
There is no limit to the number of optional bytes that can be output this way.
|
||||
(This points towards a maximum achievable compression ratio of ~250).
|
||||
|
||||
With the offset and the matchlength,
|
||||
the decoder can now proceed to copy the data from the already decoded buffer.
|
||||
On decoding the matchlength, we reach the end of the compressed sequence,
|
||||
and therefore start another one.
|
||||
|
||||
|
||||
-- Parsing restrictions --
|
||||
|
||||
There are specific parsing rules to respect in order to remain compatible
|
||||
with assumptions made by the decoder :
|
||||
1) The last 5 bytes are always literals
|
||||
2) The last match must start at least 12 bytes before end of block
|
||||
Consequently, a block with less than 13 bytes cannot be compressed.
|
||||
These rules are in place to ensure that the decoder
|
||||
will never read beyond the input buffer, nor write beyond the output buffer.
|
||||
|
||||
Note that the last sequence is also incomplete,
|
||||
and stops right after literals.
|
||||
|
||||
|
||||
-- Additional notes --
|
||||
|
||||
There is no assumption nor limits to the way the compressor
|
||||
searches and selects matches within the source data block.
|
||||
It could be a fast scan, a multi-probe, a full search using BST,
|
||||
standard hash chains or MMC, well whatever.
|
||||
|
||||
Advanced parsing strategies can also be implemented, such as lazy match,
|
||||
or full optimal parsing.
|
||||
|
||||
All these trade-off offer distinctive speed/memory/compression advantages.
|
||||
Whatever the method used by the compressor, its result will be decodable
|
||||
by any LZ4 decoder if it follows the format specification described above.
|
||||
|
||||
339
src/lz4/programs/COPYING
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
206
src/lz4/programs/Makefile
Normal file
@@ -0,0 +1,206 @@
|
||||
# ##########################################################################
|
||||
# LZ4 programs - Makefile
|
||||
# Copyright (C) Yann Collet 2011-2015
|
||||
#
|
||||
# GPL v2 License
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# You can contact the author at :
|
||||
# - LZ4 source repository : http://code.google.com/p/lz4/
|
||||
# - LZ4 forum froup : https://groups.google.com/forum/#!forum/lz4c
|
||||
# ##########################################################################
|
||||
# lz4 : Command Line Utility, supporting gzip-like arguments
|
||||
# lz4c : CLU, supporting also legacy lz4demo arguments
|
||||
# lz4c32: Same as lz4c, but forced to compile in 32-bits mode
|
||||
# fuzzer : Test tool, to check lz4 integrity on target platform
|
||||
# fuzzer32: Same as fuzzer, but forced to compile in 32-bits mode
|
||||
# fullbench : Precisely measure speed for each LZ4 function variant
|
||||
# fullbench32: Same as fullbench, but forced to compile in 32-bits mode
|
||||
# ##########################################################################
|
||||
|
||||
RELEASE?= r126
|
||||
|
||||
DESTDIR?=
|
||||
PREFIX ?= /usr
|
||||
CFLAGS ?= -O3
|
||||
CFLAGS += -std=c99 -Wall -Wextra -Wundef -Wshadow -Wcast-align -Wstrict-prototypes -pedantic -DLZ4_VERSION=\"$(RELEASE)\"
|
||||
FLAGS = -I../lib $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)
|
||||
|
||||
BINDIR=$(PREFIX)/bin
|
||||
MANDIR=$(PREFIX)/share/man/man1
|
||||
LZ4DIR=../lib
|
||||
|
||||
TEST_FILES = COPYING
|
||||
TEST_TARGETS=test-native
|
||||
|
||||
|
||||
# Define *.exe as extension for Windows systems
|
||||
ifneq (,$(filter Windows%,$(OS)))
|
||||
EXT =.exe
|
||||
VOID = nul
|
||||
else
|
||||
EXT =
|
||||
VOID = /dev/null
|
||||
endif
|
||||
|
||||
|
||||
# Select test target for Travis CI's Build Matrix
|
||||
TRAVIS_TARGET=$(LZ4_TRAVIS_CI_ENV)
|
||||
|
||||
|
||||
default: lz4 lz4c
|
||||
|
||||
all: lz4 lz4c lz4c32 fullbench fullbench32 fuzzer fuzzer32 frametest frametest32 datagen
|
||||
|
||||
lz4: $(LZ4DIR)/lz4.c $(LZ4DIR)/lz4hc.c $(LZ4DIR)/lz4frame.c $(LZ4DIR)/xxhash.c bench.c lz4io.c lz4cli.c
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
lz4c : $(LZ4DIR)/lz4.c $(LZ4DIR)/lz4hc.c $(LZ4DIR)/lz4frame.c $(LZ4DIR)/xxhash.c bench.c lz4io.c lz4cli.c
|
||||
$(CC) $(FLAGS) -DENABLE_LZ4C_LEGACY_OPTIONS $^ -o $@$(EXT)
|
||||
|
||||
lz4c32: $(LZ4DIR)/lz4.c $(LZ4DIR)/lz4hc.c $(LZ4DIR)/lz4frame.c $(LZ4DIR)/xxhash.c bench.c lz4io.c lz4cli.c
|
||||
$(CC) -m32 $(FLAGS) -DENABLE_LZ4C_LEGACY_OPTIONS $^ -o $@$(EXT)
|
||||
|
||||
fullbench : $(LZ4DIR)/lz4.c $(LZ4DIR)/lz4hc.c $(LZ4DIR)/lz4frame.c $(LZ4DIR)/xxhash.c fullbench.c
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
fullbench32: $(LZ4DIR)/lz4.c $(LZ4DIR)/lz4hc.c $(LZ4DIR)/lz4frame.c $(LZ4DIR)/xxhash.c fullbench.c
|
||||
$(CC) -m32 $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
fuzzer : $(LZ4DIR)/lz4.c $(LZ4DIR)/lz4hc.c $(LZ4DIR)/xxhash.c fuzzer.c
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
fuzzer32: $(LZ4DIR)/lz4.c $(LZ4DIR)/lz4hc.c $(LZ4DIR)/xxhash.c fuzzer.c
|
||||
$(CC) -m32 $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
frametest: $(LZ4DIR)/lz4frame.c $(LZ4DIR)/lz4.c $(LZ4DIR)/lz4hc.c $(LZ4DIR)/xxhash.c frametest.c
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
frametest32: $(LZ4DIR)/lz4frame.c $(LZ4DIR)/lz4.c $(LZ4DIR)/lz4hc.c $(LZ4DIR)/xxhash.c frametest.c
|
||||
$(CC) -m32 $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
datagen : datagen.c
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
|
||||
clean:
|
||||
@rm -f core *.o *.test \
|
||||
lz4$(EXT) lz4c$(EXT) lz4c32$(EXT) \
|
||||
fullbench$(EXT) fullbench32$(EXT) \
|
||||
fuzzer$(EXT) fuzzer32$(EXT) \
|
||||
frametest$(EXT) frametest32$(EXT) \
|
||||
datagen$(EXT)
|
||||
@echo Cleaning completed
|
||||
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#make install is validated only for Linux, OSX, kFreeBSD and Hurd targets
|
||||
ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU))
|
||||
|
||||
install: lz4 lz4c
|
||||
@echo Installing binaries
|
||||
@install -d -m 755 $(DESTDIR)$(BINDIR)/ $(DESTDIR)$(MANDIR)/
|
||||
@install -m 755 lz4$(EXT) $(DESTDIR)$(BINDIR)/lz4$(EXT)
|
||||
@ln -sf lz4$(EXT) $(DESTDIR)$(BINDIR)/lz4cat
|
||||
@install -m 755 lz4c$(EXT) $(DESTDIR)$(BINDIR)/lz4c$(EXT)
|
||||
@echo Installing man pages
|
||||
@install -m 644 lz4.1 $(DESTDIR)$(MANDIR)/lz4.1
|
||||
@install -m 644 lz4c.1 $(DESTDIR)$(MANDIR)/lz4c.1
|
||||
@install -m 644 lz4cat.1 $(DESTDIR)$(MANDIR)/lz4cat.1
|
||||
@echo lz4 installation completed
|
||||
|
||||
uninstall:
|
||||
rm -f $(DESTDIR)$(BINDIR)/lz4cat
|
||||
[ -x $(DESTDIR)$(BINDIR)/lz4$(EXT) ] && rm -f $(DESTDIR)$(BINDIR)/lz4$(EXT)
|
||||
[ -x $(DESTDIR)$(BINDIR)/lz4c$(EXT) ] && rm -f $(DESTDIR)$(BINDIR)/lz4c$(EXT)
|
||||
[ -f $(DESTDIR)$(MANDIR)/lz4.1 ] && rm -f $(DESTDIR)$(MANDIR)/lz4.1
|
||||
[ -f $(DESTDIR)$(MANDIR)/lz4c.1 ] && rm -f $(DESTDIR)$(MANDIR)/lz4c.1
|
||||
[ -f $(DESTDIR)$(MANDIR)/lz4cat.1 ] && rm -f $(DESTDIR)$(MANDIR)/lz4cat.1
|
||||
@echo lz4 programs successfully uninstalled
|
||||
|
||||
test: test-lz4 test-lz4c test-frametest test-fullbench test-fuzzer test-mem
|
||||
|
||||
test32: test-lz4c32 test-frametest32 test-fullbench32 test-fuzzer32 test-mem32
|
||||
|
||||
test-all: test test32
|
||||
|
||||
test-travis: $(TRAVIS_TARGET)
|
||||
|
||||
test-lz4: lz4 datagen
|
||||
./datagen -g16KB | ./lz4 -9 | ./lz4 -vdq > $(VOID)
|
||||
./datagen | ./lz4 | ./lz4 -vdq > $(VOID)
|
||||
./datagen -g6M -p100 | ./lz4 -9BD | ./lz4 -vdq > $(VOID)
|
||||
./datagen -g256MB | ./lz4 -vqB4D | ./lz4 -vdq > $(VOID)
|
||||
./datagen -g6GB | ./lz4 -vqB5D | ./lz4 -vdq > $(VOID)
|
||||
# test frame concatenation with null-length frame
|
||||
@echo -n > empty.test
|
||||
@echo hi > nonempty.test
|
||||
cat nonempty.test empty.test nonempty.test > orig.test
|
||||
@./lz4 -zq empty.test > empty.lz4.test
|
||||
@./lz4 -zq nonempty.test > nonempty.lz4.test
|
||||
cat nonempty.lz4.test empty.lz4.test nonempty.lz4.test > concat.lz4.test
|
||||
./lz4 -d concat.lz4.test > result.test
|
||||
sdiff orig.test result.test
|
||||
@rm *.test
|
||||
@echo frame concatenation test completed
|
||||
# test frame concatenation with null-length frame
|
||||
|
||||
|
||||
test-lz4c: lz4c datagen
|
||||
./datagen -g256MB | ./lz4c -l -v | ./lz4c -vdq > $(VOID)
|
||||
|
||||
test-lz4c32: lz4 lz4c32 lz4 datagen
|
||||
./datagen -g16KB | ./lz4c32 -9 | ./lz4c32 -vdq > $(VOID)
|
||||
./datagen -g16KB | ./lz4c32 -9 | ./lz4 -vdq > $(VOID)
|
||||
./datagen | ./lz4c32 | ./lz4c32 -vdq > $(VOID)
|
||||
./datagen | ./lz4c32 | ./lz4 -vdq > $(VOID)
|
||||
./datagen -g256MB | ./lz4c32 -vqB4D | ./lz4c32 -vdq > $(VOID)
|
||||
./datagen -g256MB | ./lz4c32 -vqB4D | ./lz4 -vdq > $(VOID)
|
||||
./datagen -g6GB | ./lz4c32 -vqB5D | ./lz4c32 -vdq > $(VOID)
|
||||
|
||||
test-fullbench: fullbench
|
||||
./fullbench --no-prompt $(TEST_FILES)
|
||||
|
||||
test-fullbench32: fullbench32
|
||||
./fullbench32 --no-prompt $(TEST_FILES)
|
||||
|
||||
test-fuzzer: fuzzer
|
||||
./fuzzer
|
||||
|
||||
test-fuzzer32: fuzzer32
|
||||
./fuzzer32
|
||||
|
||||
test-frametest: frametest
|
||||
./frametest
|
||||
|
||||
test-frametest32: frametest32
|
||||
./frametest32
|
||||
|
||||
test-mem: lz4 datagen fuzzer frametest
|
||||
./datagen -g16KB > tmp
|
||||
valgrind --leak-check=yes ./lz4 -9 -BD -f tmp /dev/null
|
||||
./datagen -g16MB > tmp
|
||||
valgrind --leak-check=yes ./lz4 -9 -B5D -f tmp /dev/null
|
||||
./datagen -g256MB > tmp
|
||||
valgrind --leak-check=yes ./lz4 -B4D -f -vq tmp /dev/null
|
||||
rm tmp
|
||||
valgrind --leak-check=yes ./fuzzer -i64 -t1
|
||||
valgrind --leak-check=yes ./frametest -i256
|
||||
|
||||
test-mem32: lz4c32 datagen
|
||||
# unfortunately, valgrind doesn't seem to work with non-native binary. If someone knows how to do a valgrind-test on a 32-bits exe with a 64-bits system...
|
||||
|
||||
endif
|
||||
435
src/lz4/programs/bench.c
Normal file
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
bench.c - Demo program to benchmark open-source compression algorithm
|
||||
Copyright (C) Yann Collet 2012-2014
|
||||
GPL v2 License
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
*/
|
||||
|
||||
/**************************************
|
||||
* Compiler Options
|
||||
***************************************/
|
||||
/* Disable some Visual warning messages */
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_DEPRECATE /* VS2005 */
|
||||
|
||||
/* Unix Large Files support (>4GB) */
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#if (defined(__sun__) && (!defined(__LP64__))) /* Sun Solaris 32-bits requires specific definitions */
|
||||
# define _LARGEFILE_SOURCE
|
||||
#elif ! defined(__LP64__) /* No point defining Large file for 64 bit */
|
||||
# define _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
/* S_ISREG & gettimeofday() are not supported by MSVC */
|
||||
#if defined(_MSC_VER) || defined(_WIN32)
|
||||
# define BMK_LEGACY_TIMER 1
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************
|
||||
* Includes
|
||||
***************************************/
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <stdio.h> /* fprintf, fopen, ftello64 */
|
||||
#include <sys/types.h> /* stat64 */
|
||||
#include <sys/stat.h> /* stat64 */
|
||||
|
||||
/* Use ftime() if gettimeofday() is not available on your target */
|
||||
#if defined(BMK_LEGACY_TIMER)
|
||||
# include <sys/timeb.h> /* timeb, ftime */
|
||||
#else
|
||||
# include <sys/time.h> /* gettimeofday */
|
||||
#endif
|
||||
|
||||
#include "lz4.h"
|
||||
#define COMPRESSOR0 LZ4_compress_local
|
||||
static int LZ4_compress_local(const char* src, char* dst, int size, int clevel) { (void)clevel; return LZ4_compress(src, dst, size); }
|
||||
#include "lz4hc.h"
|
||||
#define COMPRESSOR1 LZ4_compressHC2
|
||||
#define DEFAULTCOMPRESSOR COMPRESSOR0
|
||||
|
||||
#include "xxhash.h"
|
||||
|
||||
|
||||
/**************************************
|
||||
* Compiler specifics
|
||||
***************************************/
|
||||
#if !defined(S_ISREG)
|
||||
# define S_ISREG(x) (((x) & S_IFMT) == S_IFREG)
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************
|
||||
* Basic Types
|
||||
***************************************/
|
||||
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
|
||||
# include <stdint.h>
|
||||
typedef uint8_t BYTE;
|
||||
typedef uint16_t U16;
|
||||
typedef uint32_t U32;
|
||||
typedef int32_t S32;
|
||||
typedef uint64_t U64;
|
||||
#else
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned short U16;
|
||||
typedef unsigned int U32;
|
||||
typedef signed int S32;
|
||||
typedef unsigned long long U64;
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************
|
||||
* Constants
|
||||
***************************************/
|
||||
#define NBLOOPS 3
|
||||
#define TIMELOOP 2000
|
||||
|
||||
#define KB *(1 <<10)
|
||||
#define MB *(1 <<20)
|
||||
#define GB *(1U<<30)
|
||||
|
||||
#define MAX_MEM (2 GB - 64 MB)
|
||||
#define DEFAULT_CHUNKSIZE (4 MB)
|
||||
|
||||
|
||||
/**************************************
|
||||
* Local structures
|
||||
***************************************/
|
||||
struct chunkParameters
|
||||
{
|
||||
U32 id;
|
||||
char* origBuffer;
|
||||
char* compressedBuffer;
|
||||
int origSize;
|
||||
int compressedSize;
|
||||
};
|
||||
|
||||
struct compressionParameters
|
||||
{
|
||||
int (*compressionFunction)(const char*, char*, int, int);
|
||||
int (*decompressionFunction)(const char*, char*, int);
|
||||
};
|
||||
|
||||
|
||||
/**************************************
|
||||
* MACRO
|
||||
***************************************/
|
||||
#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
|
||||
|
||||
|
||||
/**************************************
|
||||
* Benchmark Parameters
|
||||
***************************************/
|
||||
static int chunkSize = DEFAULT_CHUNKSIZE;
|
||||
static int nbIterations = NBLOOPS;
|
||||
static int BMK_pause = 0;
|
||||
|
||||
void BMK_SetBlocksize(int bsize) { chunkSize = bsize; }
|
||||
|
||||
void BMK_SetNbIterations(int nbLoops)
|
||||
{
|
||||
nbIterations = nbLoops;
|
||||
DISPLAY("- %i iterations -\n", nbIterations);
|
||||
}
|
||||
|
||||
void BMK_SetPause(void) { BMK_pause = 1; }
|
||||
|
||||
|
||||
/*********************************************************
|
||||
* Private functions
|
||||
**********************************************************/
|
||||
|
||||
#if defined(BMK_LEGACY_TIMER)
|
||||
|
||||
static int BMK_GetMilliStart(void)
|
||||
{
|
||||
/* Based on Legacy ftime()
|
||||
Rolls over every ~ 12.1 days (0x100000/24/60/60)
|
||||
Use GetMilliSpan to correct for rollover */
|
||||
struct timeb tb;
|
||||
int nCount;
|
||||
ftime( &tb );
|
||||
nCount = (int) (tb.millitm + (tb.time & 0xfffff) * 1000);
|
||||
return nCount;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int BMK_GetMilliStart(void)
|
||||
{
|
||||
/* Based on newer gettimeofday()
|
||||
Use GetMilliSpan to correct for rollover */
|
||||
struct timeval tv;
|
||||
int nCount;
|
||||
gettimeofday(&tv, NULL);
|
||||
nCount = (int) (tv.tv_usec/1000 + (tv.tv_sec & 0xfffff) * 1000);
|
||||
return nCount;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static int BMK_GetMilliSpan( int nTimeStart )
|
||||
{
|
||||
int nSpan = BMK_GetMilliStart() - nTimeStart;
|
||||
if ( nSpan < 0 )
|
||||
nSpan += 0x100000 * 1000;
|
||||
return nSpan;
|
||||
}
|
||||
|
||||
|
||||
static size_t BMK_findMaxMem(U64 requiredMem)
|
||||
{
|
||||
size_t step = 64 MB;
|
||||
BYTE* testmem=NULL;
|
||||
|
||||
requiredMem = (((requiredMem >> 26) + 1) << 26);
|
||||
requiredMem += 2*step;
|
||||
if (requiredMem > MAX_MEM) requiredMem = MAX_MEM;
|
||||
|
||||
while (!testmem)
|
||||
{
|
||||
requiredMem -= step;
|
||||
testmem = (BYTE*) malloc ((size_t)requiredMem);
|
||||
}
|
||||
|
||||
free (testmem);
|
||||
return (size_t) (requiredMem - step);
|
||||
}
|
||||
|
||||
|
||||
static U64 BMK_GetFileSize(char* infilename)
|
||||
{
|
||||
int r;
|
||||
#if defined(_MSC_VER)
|
||||
struct _stat64 statbuf;
|
||||
r = _stat64(infilename, &statbuf);
|
||||
#else
|
||||
struct stat statbuf;
|
||||
r = stat(infilename, &statbuf);
|
||||
#endif
|
||||
if (r || !S_ISREG(statbuf.st_mode)) return 0; /* No good... */
|
||||
return (U64)statbuf.st_size;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************
|
||||
* Public function
|
||||
**********************************************************/
|
||||
|
||||
int BMK_benchFile(char** fileNamesTable, int nbFiles, int cLevel)
|
||||
{
|
||||
int fileIdx=0;
|
||||
char* orig_buff;
|
||||
struct compressionParameters compP;
|
||||
int cfunctionId;
|
||||
|
||||
U64 totals = 0;
|
||||
U64 totalz = 0;
|
||||
double totalc = 0.;
|
||||
double totald = 0.;
|
||||
|
||||
|
||||
/* Init */
|
||||
if (cLevel <= 3) cfunctionId = 0; else cfunctionId = 1;
|
||||
switch (cfunctionId)
|
||||
{
|
||||
#ifdef COMPRESSOR0
|
||||
case 0 : compP.compressionFunction = COMPRESSOR0; break;
|
||||
#endif
|
||||
#ifdef COMPRESSOR1
|
||||
case 1 : compP.compressionFunction = COMPRESSOR1; break;
|
||||
#endif
|
||||
default : compP.compressionFunction = DEFAULTCOMPRESSOR;
|
||||
}
|
||||
compP.decompressionFunction = LZ4_decompress_fast;
|
||||
|
||||
/* Loop for each file */
|
||||
while (fileIdx<nbFiles)
|
||||
{
|
||||
FILE* inFile;
|
||||
char* inFileName;
|
||||
U64 inFileSize;
|
||||
size_t benchedSize;
|
||||
int nbChunks;
|
||||
int maxCompressedChunkSize;
|
||||
size_t readSize;
|
||||
char* compressedBuffer; int compressedBuffSize;
|
||||
struct chunkParameters* chunkP;
|
||||
U32 crcOrig;
|
||||
|
||||
/* Check file existence */
|
||||
inFileName = fileNamesTable[fileIdx++];
|
||||
inFile = fopen( inFileName, "rb" );
|
||||
if (inFile==NULL)
|
||||
{
|
||||
DISPLAY( "Pb opening %s\n", inFileName);
|
||||
return 11;
|
||||
}
|
||||
|
||||
/* Memory allocation & restrictions */
|
||||
inFileSize = BMK_GetFileSize(inFileName);
|
||||
benchedSize = (size_t) BMK_findMaxMem(inFileSize * 2) / 2;
|
||||
if ((U64)benchedSize > inFileSize) benchedSize = (size_t)inFileSize;
|
||||
if (benchedSize < inFileSize)
|
||||
{
|
||||
DISPLAY("Not enough memory for '%s' full size; testing %i MB only...\n", inFileName, (int)(benchedSize>>20));
|
||||
}
|
||||
|
||||
/* Alloc */
|
||||
chunkP = (struct chunkParameters*) malloc(((benchedSize / (size_t)chunkSize)+1) * sizeof(struct chunkParameters));
|
||||
orig_buff = (char*)malloc((size_t )benchedSize);
|
||||
nbChunks = (int) ((int)benchedSize / chunkSize) + 1;
|
||||
maxCompressedChunkSize = LZ4_compressBound(chunkSize);
|
||||
compressedBuffSize = nbChunks * maxCompressedChunkSize;
|
||||
compressedBuffer = (char*)malloc((size_t )compressedBuffSize);
|
||||
|
||||
|
||||
if (!orig_buff || !compressedBuffer)
|
||||
{
|
||||
DISPLAY("\nError: not enough memory!\n");
|
||||
free(orig_buff);
|
||||
free(compressedBuffer);
|
||||
free(chunkP);
|
||||
fclose(inFile);
|
||||
return 12;
|
||||
}
|
||||
|
||||
/* Init chunks data */
|
||||
{
|
||||
int i;
|
||||
size_t remaining = benchedSize;
|
||||
char* in = orig_buff;
|
||||
char* out = compressedBuffer;
|
||||
for (i=0; i<nbChunks; i++)
|
||||
{
|
||||
chunkP[i].id = i;
|
||||
chunkP[i].origBuffer = in; in += chunkSize;
|
||||
if ((int)remaining > chunkSize) { chunkP[i].origSize = chunkSize; remaining -= chunkSize; } else { chunkP[i].origSize = (int)remaining; remaining = 0; }
|
||||
chunkP[i].compressedBuffer = out; out += maxCompressedChunkSize;
|
||||
chunkP[i].compressedSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill input buffer */
|
||||
DISPLAY("Loading %s... \r", inFileName);
|
||||
readSize = fread(orig_buff, 1, benchedSize, inFile);
|
||||
fclose(inFile);
|
||||
|
||||
if (readSize != benchedSize)
|
||||
{
|
||||
DISPLAY("\nError: problem reading file '%s' !! \n", inFileName);
|
||||
free(orig_buff);
|
||||
free(compressedBuffer);
|
||||
free(chunkP);
|
||||
return 13;
|
||||
}
|
||||
|
||||
/* Calculating input Checksum */
|
||||
crcOrig = XXH32(orig_buff, (unsigned int)benchedSize,0);
|
||||
|
||||
|
||||
/* Bench */
|
||||
{
|
||||
int loopNb, chunkNb;
|
||||
size_t cSize=0;
|
||||
double fastestC = 100000000., fastestD = 100000000.;
|
||||
double ratio=0.;
|
||||
U32 crcCheck=0;
|
||||
|
||||
DISPLAY("\r%79s\r", "");
|
||||
for (loopNb = 1; loopNb <= nbIterations; loopNb++)
|
||||
{
|
||||
int nbLoops;
|
||||
int milliTime;
|
||||
|
||||
/* Compression */
|
||||
DISPLAY("%1i-%-14.14s : %9i ->\r", loopNb, inFileName, (int)benchedSize);
|
||||
{ size_t i; for (i=0; i<benchedSize; i++) compressedBuffer[i]=(char)i; } /* warmimg up memory */
|
||||
|
||||
nbLoops = 0;
|
||||
milliTime = BMK_GetMilliStart();
|
||||
while(BMK_GetMilliStart() == milliTime);
|
||||
milliTime = BMK_GetMilliStart();
|
||||
while(BMK_GetMilliSpan(milliTime) < TIMELOOP)
|
||||
{
|
||||
for (chunkNb=0; chunkNb<nbChunks; chunkNb++)
|
||||
chunkP[chunkNb].compressedSize = compP.compressionFunction(chunkP[chunkNb].origBuffer, chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origSize, cLevel);
|
||||
nbLoops++;
|
||||
}
|
||||
milliTime = BMK_GetMilliSpan(milliTime);
|
||||
|
||||
if ((double)milliTime < fastestC*nbLoops) fastestC = (double)milliTime/nbLoops;
|
||||
cSize=0; for (chunkNb=0; chunkNb<nbChunks; chunkNb++) cSize += chunkP[chunkNb].compressedSize;
|
||||
ratio = (double)cSize/(double)benchedSize*100.;
|
||||
|
||||
DISPLAY("%1i-%-14.14s : %9i -> %9i (%5.2f%%),%7.1f MB/s\r", loopNb, inFileName, (int)benchedSize, (int)cSize, ratio, (double)benchedSize / fastestC / 1000.);
|
||||
|
||||
/* Decompression */
|
||||
{ size_t i; for (i=0; i<benchedSize; i++) orig_buff[i]=0; } /* zeroing area, for CRC checking */
|
||||
|
||||
nbLoops = 0;
|
||||
milliTime = BMK_GetMilliStart();
|
||||
while(BMK_GetMilliStart() == milliTime);
|
||||
milliTime = BMK_GetMilliStart();
|
||||
while(BMK_GetMilliSpan(milliTime) < TIMELOOP)
|
||||
{
|
||||
for (chunkNb=0; chunkNb<nbChunks; chunkNb++)
|
||||
chunkP[chunkNb].compressedSize = LZ4_decompress_fast(chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origBuffer, chunkP[chunkNb].origSize);
|
||||
nbLoops++;
|
||||
}
|
||||
milliTime = BMK_GetMilliSpan(milliTime);
|
||||
|
||||
if ((double)milliTime < fastestD*nbLoops) fastestD = (double)milliTime/nbLoops;
|
||||
DISPLAY("%1i-%-14.14s : %9i -> %9i (%5.2f%%),%7.1f MB/s ,%7.1f MB/s\r", loopNb, inFileName, (int)benchedSize, (int)cSize, ratio, (double)benchedSize / fastestC / 1000., (double)benchedSize / fastestD / 1000.);
|
||||
|
||||
/* CRC Checking */
|
||||
crcCheck = XXH32(orig_buff, (unsigned int)benchedSize,0);
|
||||
if (crcOrig!=crcCheck) { DISPLAY("\n!!! WARNING !!! %14s : Invalid Checksum : %x != %x\n", inFileName, (unsigned)crcOrig, (unsigned)crcCheck); break; }
|
||||
}
|
||||
|
||||
if (crcOrig==crcCheck)
|
||||
{
|
||||
if (ratio<100.)
|
||||
DISPLAY("%-16.16s : %9i -> %9i (%5.2f%%),%7.1f MB/s ,%7.1f MB/s\n", inFileName, (int)benchedSize, (int)cSize, ratio, (double)benchedSize / fastestC / 1000., (double)benchedSize / fastestD / 1000.);
|
||||
else
|
||||
DISPLAY("%-16.16s : %9i -> %9i (%5.1f%%),%7.1f MB/s ,%7.1f MB/s \n", inFileName, (int)benchedSize, (int)cSize, ratio, (double)benchedSize / fastestC / 1000., (double)benchedSize / fastestD / 1000.);
|
||||
}
|
||||
totals += benchedSize;
|
||||
totalz += cSize;
|
||||
totalc += fastestC;
|
||||
totald += fastestD;
|
||||
}
|
||||
|
||||
free(orig_buff);
|
||||
free(compressedBuffer);
|
||||
free(chunkP);
|
||||
}
|
||||
|
||||
if (nbFiles > 1)
|
||||
DISPLAY("%-16.16s :%10llu ->%10llu (%5.2f%%), %6.1f MB/s , %6.1f MB/s\n", " TOTAL", (long long unsigned int)totals, (long long unsigned int)totalz, (double)totalz/(double)totals*100., (double)totals/totalc/1000., (double)totals/totald/1000.);
|
||||
|
||||
if (BMK_pause) { DISPLAY("\npress enter...\n"); getchar(); }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
42
src/lz4/programs/bench.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
bench.h - Demo program to benchmark open-source compression algorithm
|
||||
Copyright (C) Yann Collet 2012-2014
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
- LZ4 public forum : https://group.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* Main function */
|
||||
int BMK_benchFile(char** fileNamesTable, int nbFiles, int cLevel);
|
||||
|
||||
/* Set Parameters */
|
||||
void BMK_SetBlocksize(int bsize);
|
||||
void BMK_SetNbIterations(int nbLoops);
|
||||
void BMK_SetPause(void);
|
||||
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
286
src/lz4/programs/datagen.c
Normal file
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
datagen.c - compressible data generator test tool
|
||||
Copyright (C) Yann Collet 2012-2015
|
||||
|
||||
GPL v2 License
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 source repository : http://code.google.com/p/lz4
|
||||
- LZ4 source mirror : https://github.com/Cyan4973/lz4
|
||||
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
|
||||
/**************************************
|
||||
Remove Visual warning messages
|
||||
**************************************/
|
||||
#define _CRT_SECURE_NO_WARNINGS // fgets
|
||||
|
||||
|
||||
/**************************************
|
||||
Includes
|
||||
**************************************/
|
||||
#include <stdio.h> // fgets, sscanf
|
||||
#include <string.h> // strcmp
|
||||
|
||||
|
||||
/**************************************
|
||||
Basic Types
|
||||
**************************************/
|
||||
#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */
|
||||
# include <stdint.h>
|
||||
typedef uint8_t BYTE;
|
||||
typedef uint16_t U16;
|
||||
typedef uint32_t U32;
|
||||
typedef int32_t S32;
|
||||
typedef uint64_t U64;
|
||||
#else
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned short U16;
|
||||
typedef unsigned int U32;
|
||||
typedef signed int S32;
|
||||
typedef unsigned long long U64;
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************
|
||||
Constants
|
||||
**************************************/
|
||||
#ifndef LZ4_VERSION
|
||||
# define LZ4_VERSION "r125"
|
||||
#endif
|
||||
|
||||
#define KB *(1 <<10)
|
||||
#define MB *(1 <<20)
|
||||
#define GB *(1U<<30)
|
||||
|
||||
#define CDG_SIZE_DEFAULT (64 KB)
|
||||
#define CDG_SEED_DEFAULT 0
|
||||
#define CDG_COMPRESSIBILITY_DEFAULT 50
|
||||
#define PRIME1 2654435761U
|
||||
#define PRIME2 2246822519U
|
||||
|
||||
|
||||
/**************************************
|
||||
Macros
|
||||
**************************************/
|
||||
#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
|
||||
#define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
|
||||
|
||||
|
||||
/**************************************
|
||||
Local Parameters
|
||||
**************************************/
|
||||
static unsigned no_prompt = 0;
|
||||
static char* programName;
|
||||
static unsigned displayLevel = 2;
|
||||
|
||||
|
||||
/*********************************************************
|
||||
functions
|
||||
*********************************************************/
|
||||
|
||||
#define CDG_rotl32(x,r) ((x << r) | (x >> (32 - r)))
|
||||
static unsigned int CDG_rand(U32* src)
|
||||
{
|
||||
U32 rand32 = *src;
|
||||
rand32 *= PRIME1;
|
||||
rand32 += PRIME2;
|
||||
rand32 = CDG_rotl32(rand32, 13);
|
||||
*src = rand32;
|
||||
return rand32;
|
||||
}
|
||||
|
||||
|
||||
#define CDG_RAND15BITS ((CDG_rand(seed) >> 3) & 32767)
|
||||
#define CDG_RANDLENGTH ( ((CDG_rand(seed) >> 7) & 3) ? (CDG_rand(seed) % 14) : (CDG_rand(seed) & 511) + 15)
|
||||
#define CDG_RANDCHAR (((CDG_rand(seed) >> 9) & 63) + '0')
|
||||
static void CDG_generate(U64 size, U32* seed, double proba)
|
||||
{
|
||||
BYTE fullbuff[32 KB + 128 KB + 1];
|
||||
BYTE* buff = fullbuff + 32 KB;
|
||||
U64 total=0;
|
||||
U32 P32 = (U32)(32768 * proba);
|
||||
U32 pos=1;
|
||||
U32 genBlockSize = 128 KB;
|
||||
|
||||
// Build initial prefix
|
||||
fullbuff[0] = CDG_RANDCHAR;
|
||||
while (pos<32 KB)
|
||||
{
|
||||
// Select : Literal (char) or Match (within 32K)
|
||||
if (CDG_RAND15BITS < P32)
|
||||
{
|
||||
// Copy (within 64K)
|
||||
U32 d;
|
||||
int ref;
|
||||
int length = CDG_RANDLENGTH + 4;
|
||||
U32 offset = CDG_RAND15BITS + 1;
|
||||
if (offset > pos) offset = pos;
|
||||
ref = pos - offset;
|
||||
d = pos + length;
|
||||
while (pos < d) fullbuff[pos++] = fullbuff[ref++];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Literal (noise)
|
||||
U32 d = pos + CDG_RANDLENGTH;
|
||||
while (pos < d) fullbuff[pos++] = CDG_RANDCHAR;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate compressible data
|
||||
pos = 0;
|
||||
while (total < size)
|
||||
{
|
||||
if (size-total < 128 KB) genBlockSize = (U32)(size-total);
|
||||
total += genBlockSize;
|
||||
buff[genBlockSize] = 0;
|
||||
pos = 0;
|
||||
while (pos<genBlockSize)
|
||||
{
|
||||
// Select : Literal (char) or Match (within 32K)
|
||||
if (CDG_RAND15BITS < P32)
|
||||
{
|
||||
// Copy (within 64K)
|
||||
int ref;
|
||||
U32 d;
|
||||
int length = CDG_RANDLENGTH + 4;
|
||||
U32 offset = CDG_RAND15BITS + 1;
|
||||
if (pos + length > genBlockSize ) length = genBlockSize - pos;
|
||||
ref = pos - offset;
|
||||
d = pos + length;
|
||||
while (pos < d) buff[pos++] = buff[ref++];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Literal (noise)
|
||||
U32 d;
|
||||
int length = CDG_RANDLENGTH;
|
||||
if (pos + length > genBlockSize) length = genBlockSize - pos;
|
||||
d = pos + length;
|
||||
while (pos < d) buff[pos++] = CDG_RANDCHAR;
|
||||
}
|
||||
}
|
||||
// output datagen
|
||||
pos=0;
|
||||
for (;pos+512<=genBlockSize;pos+=512)
|
||||
printf("%512.512s", buff+pos);
|
||||
for (;pos<genBlockSize;pos++) printf("%c", buff[pos]);
|
||||
// Regenerate prefix
|
||||
memcpy(fullbuff, buff + 96 KB, 32 KB);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int CDG_usage(void)
|
||||
{
|
||||
DISPLAY( "Compressible data generator\n");
|
||||
DISPLAY( "Usage :\n");
|
||||
DISPLAY( " %s [size] [args]\n", programName);
|
||||
DISPLAY( "\n");
|
||||
DISPLAY( "Arguments :\n");
|
||||
DISPLAY( " -g# : generate # data (default:%i)\n", CDG_SIZE_DEFAULT);
|
||||
DISPLAY( " -s# : Select seed (default:%i)\n", CDG_SEED_DEFAULT);
|
||||
DISPLAY( " -p# : Select compressibility in %% (default:%i%%)\n", CDG_COMPRESSIBILITY_DEFAULT);
|
||||
DISPLAY( " -h : display help and exit\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int argNb;
|
||||
int proba = CDG_COMPRESSIBILITY_DEFAULT;
|
||||
U64 size = CDG_SIZE_DEFAULT;
|
||||
U32 seed = CDG_SEED_DEFAULT;
|
||||
|
||||
// Check command line
|
||||
programName = argv[0];
|
||||
for(argNb=1; argNb<argc; argNb++)
|
||||
{
|
||||
char* argument = argv[argNb];
|
||||
|
||||
if(!argument) continue; // Protection if argument empty
|
||||
|
||||
// Decode command (note : aggregated commands are allowed)
|
||||
if (*argument=='-')
|
||||
{
|
||||
if (!strcmp(argument, "--no-prompt")) { no_prompt=1; continue; }
|
||||
|
||||
argument++;
|
||||
while (*argument!=0)
|
||||
{
|
||||
switch(*argument)
|
||||
{
|
||||
case 'h':
|
||||
return CDG_usage();
|
||||
case 'g':
|
||||
argument++;
|
||||
size=0;
|
||||
while ((*argument>='0') && (*argument<='9'))
|
||||
{
|
||||
size *= 10;
|
||||
size += *argument - '0';
|
||||
argument++;
|
||||
}
|
||||
if (*argument=='K') { size <<= 10; argument++; }
|
||||
if (*argument=='M') { size <<= 20; argument++; }
|
||||
if (*argument=='G') { size <<= 30; argument++; }
|
||||
if (*argument=='B') { argument++; }
|
||||
break;
|
||||
case 's':
|
||||
argument++;
|
||||
seed=0;
|
||||
while ((*argument>='0') && (*argument<='9'))
|
||||
{
|
||||
seed *= 10;
|
||||
seed += *argument - '0';
|
||||
argument++;
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
argument++;
|
||||
proba=0;
|
||||
while ((*argument>='0') && (*argument<='9'))
|
||||
{
|
||||
proba *= 10;
|
||||
proba += *argument - '0';
|
||||
argument++;
|
||||
}
|
||||
if (proba<0) proba=0;
|
||||
if (proba>100) proba=100;
|
||||
break;
|
||||
case 'v':
|
||||
displayLevel = 4;
|
||||
argument++;
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Get Seed
|
||||
DISPLAYLEVEL(4, "Data Generator %s \n", LZ4_VERSION);
|
||||
DISPLAYLEVEL(3, "Seed = %u \n", seed);
|
||||
if (proba!=CDG_COMPRESSIBILITY_DEFAULT) DISPLAYLEVEL(3, "Compressibility : %i%%\n", proba);
|
||||
|
||||
CDG_generate(size, &seed, ((double)proba) / 100);
|
||||
|
||||
return 0;
|
||||
}
|
||||
669
src/lz4/programs/frametest.c
Normal file
@@ -0,0 +1,669 @@
|
||||
/*
|
||||
frameTest - test tool for lz4frame
|
||||
Copyright (C) Yann Collet 2014
|
||||
GPL v2 License
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
|
||||
/**************************************
|
||||
Compiler specific
|
||||
**************************************/
|
||||
#define _CRT_SECURE_NO_WARNINGS // fgets
|
||||
#ifdef _MSC_VER /* Visual Studio */
|
||||
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
|
||||
# pragma warning(disable : 4146) /* disable: C4146: minus unsigned expression */
|
||||
#endif
|
||||
#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC diagnostic ignored "-Wmissing-braces" /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */
|
||||
# pragma GCC diagnostic ignored "-Wmissing-field-initializers" /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************
|
||||
Includes
|
||||
**************************************/
|
||||
#include <stdlib.h> // free
|
||||
#include <stdio.h> // fgets, sscanf
|
||||
#include <sys/timeb.h> // timeb
|
||||
#include <string.h> // strcmp
|
||||
#include "lz4frame_static.h"
|
||||
#include "xxhash.h" // XXH64
|
||||
|
||||
|
||||
/**************************************
|
||||
Basic Types
|
||||
**************************************/
|
||||
#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */
|
||||
# include <stdint.h>
|
||||
typedef uint8_t BYTE;
|
||||
typedef uint16_t U16;
|
||||
typedef uint32_t U32;
|
||||
typedef int32_t S32;
|
||||
typedef uint64_t U64;
|
||||
#else
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned short U16;
|
||||
typedef unsigned int U32;
|
||||
typedef signed int S32;
|
||||
typedef unsigned long long U64;
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************
|
||||
Constants
|
||||
**************************************/
|
||||
#ifndef LZ4_VERSION
|
||||
# define LZ4_VERSION ""
|
||||
#endif
|
||||
|
||||
#define KB *(1U<<10)
|
||||
#define MB *(1U<<20)
|
||||
#define GB *(1U<<30)
|
||||
|
||||
static const U32 nbTestsDefault = 256 KB;
|
||||
#define COMPRESSIBLE_NOISE_LENGTH (2 MB)
|
||||
#define FUZ_COMPRESSIBILITY_DEFAULT 50
|
||||
static const U32 prime1 = 2654435761U;
|
||||
static const U32 prime2 = 2246822519U;
|
||||
|
||||
|
||||
|
||||
/**************************************
|
||||
Macros
|
||||
**************************************/
|
||||
#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
|
||||
#define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
|
||||
#define DISPLAYUPDATE(l, ...) if (displayLevel>=l) { \
|
||||
if ((FUZ_GetMilliSpan(g_time) > refreshRate) || (displayLevel>=4)) \
|
||||
{ g_time = FUZ_GetMilliStart(); DISPLAY(__VA_ARGS__); \
|
||||
if (displayLevel>=4) fflush(stdout); } }
|
||||
static const U32 refreshRate = 150;
|
||||
static U32 g_time = 0;
|
||||
|
||||
|
||||
/*****************************************
|
||||
Local Parameters
|
||||
*****************************************/
|
||||
static U32 no_prompt = 0;
|
||||
static char* programName;
|
||||
static U32 displayLevel = 2;
|
||||
static U32 pause = 0;
|
||||
|
||||
|
||||
/*********************************************************
|
||||
Fuzzer functions
|
||||
*********************************************************/
|
||||
static U32 FUZ_GetMilliStart(void)
|
||||
{
|
||||
struct timeb tb;
|
||||
U32 nCount;
|
||||
ftime( &tb );
|
||||
nCount = (U32) (((tb.time & 0xFFFFF) * 1000) + tb.millitm);
|
||||
return nCount;
|
||||
}
|
||||
|
||||
|
||||
static U32 FUZ_GetMilliSpan(U32 nTimeStart)
|
||||
{
|
||||
U32 nCurrent = FUZ_GetMilliStart();
|
||||
U32 nSpan = nCurrent - nTimeStart;
|
||||
if (nTimeStart > nCurrent)
|
||||
nSpan += 0x100000 * 1000;
|
||||
return nSpan;
|
||||
}
|
||||
|
||||
|
||||
# define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
|
||||
unsigned int FUZ_rand(unsigned int* src)
|
||||
{
|
||||
U32 rand32 = *src;
|
||||
rand32 *= prime1;
|
||||
rand32 += prime2;
|
||||
rand32 = FUZ_rotl32(rand32, 13);
|
||||
*src = rand32;
|
||||
return rand32 >> 5;
|
||||
}
|
||||
|
||||
|
||||
#define FUZ_RAND15BITS (FUZ_rand(seed) & 0x7FFF)
|
||||
#define FUZ_RANDLENGTH ( (FUZ_rand(seed) & 3) ? (FUZ_rand(seed) % 15) : (FUZ_rand(seed) % 510) + 15)
|
||||
static void FUZ_fillCompressibleNoiseBuffer(void* buffer, unsigned bufferSize, double proba, U32* seed)
|
||||
{
|
||||
BYTE* BBuffer = (BYTE*)buffer;
|
||||
unsigned pos = 0;
|
||||
U32 P32 = (U32)(32768 * proba);
|
||||
|
||||
// First Byte
|
||||
BBuffer[pos++] = (BYTE)(FUZ_rand(seed));
|
||||
|
||||
while (pos < bufferSize)
|
||||
{
|
||||
// Select : Literal (noise) or copy (within 64K)
|
||||
if (FUZ_RAND15BITS < P32)
|
||||
{
|
||||
// Copy (within 64K)
|
||||
unsigned match, end;
|
||||
unsigned length = FUZ_RANDLENGTH + 4;
|
||||
unsigned offset = FUZ_RAND15BITS + 1;
|
||||
if (offset > pos) offset = pos;
|
||||
if (pos + length > bufferSize) length = bufferSize - pos;
|
||||
match = pos - offset;
|
||||
end = pos + length;
|
||||
while (pos < end) BBuffer[pos++] = BBuffer[match++];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Literal (noise)
|
||||
unsigned end;
|
||||
unsigned length = FUZ_RANDLENGTH;
|
||||
if (pos + length > bufferSize) length = bufferSize - pos;
|
||||
end = pos + length;
|
||||
while (pos < end) BBuffer[pos++] = (BYTE)(FUZ_rand(seed) >> 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static unsigned FUZ_highbit(U32 v32)
|
||||
{
|
||||
unsigned nbBits = 0;
|
||||
if (v32==0) return 0;
|
||||
while (v32)
|
||||
{
|
||||
v32 >>= 1;
|
||||
nbBits ++;
|
||||
}
|
||||
return nbBits;
|
||||
}
|
||||
|
||||
|
||||
int basicTests(U32 seed, double compressibility)
|
||||
{
|
||||
int testResult = 0;
|
||||
void* CNBuffer;
|
||||
void* compressedBuffer;
|
||||
void* decodedBuffer;
|
||||
U32 randState = seed;
|
||||
size_t cSize, testSize;
|
||||
LZ4F_preferences_t prefs = { 0 };
|
||||
LZ4F_decompressionContext_t dCtx;
|
||||
U64 crcOrig;
|
||||
|
||||
// Create compressible test buffer
|
||||
CNBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
|
||||
compressedBuffer = malloc(LZ4F_compressFrameBound(COMPRESSIBLE_NOISE_LENGTH, NULL));
|
||||
decodedBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
|
||||
FUZ_fillCompressibleNoiseBuffer(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, compressibility, &randState);
|
||||
crcOrig = XXH64(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
|
||||
|
||||
// Trivial tests : one-step frame
|
||||
testSize = COMPRESSIBLE_NOISE_LENGTH;
|
||||
DISPLAYLEVEL(3, "Using NULL preferences : \n");
|
||||
cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, NULL);
|
||||
if (LZ4F_isError(cSize)) goto _output_error;
|
||||
DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
|
||||
|
||||
DISPLAYLEVEL(3, "Decompression test : \n");
|
||||
{
|
||||
size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
|
||||
size_t compressedBufferSize = cSize;
|
||||
BYTE* op = (BYTE*)decodedBuffer;
|
||||
BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
|
||||
BYTE* ip = (BYTE*)compressedBuffer;
|
||||
BYTE* const iend = (BYTE*)compressedBuffer + cSize;
|
||||
U64 crcDest;
|
||||
|
||||
LZ4F_errorCode_t errorCode = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
|
||||
if (LZ4F_isError(errorCode)) goto _output_error;
|
||||
|
||||
DISPLAYLEVEL(3, "Single Block : \n");
|
||||
errorCode = LZ4F_decompress(dCtx, decodedBuffer, &decodedBufferSize, compressedBuffer, &compressedBufferSize, NULL);
|
||||
crcDest = XXH64(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
|
||||
if (crcDest != crcOrig) goto _output_error;
|
||||
DISPLAYLEVEL(3, "Regenerated %i bytes \n", (int)decodedBufferSize);
|
||||
|
||||
DISPLAYLEVEL(3, "Byte after byte : \n");
|
||||
while (ip < iend)
|
||||
{
|
||||
size_t oSize = oend-op;
|
||||
size_t iSize = 1;
|
||||
//DISPLAY("%7i \n", (int)(ip-(BYTE*)compressedBuffer));
|
||||
errorCode = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL);
|
||||
if (LZ4F_isError(errorCode)) goto _output_error;
|
||||
op += oSize;
|
||||
ip += iSize;
|
||||
}
|
||||
crcDest = XXH64(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
|
||||
if (crcDest != crcOrig) goto _output_error;
|
||||
DISPLAYLEVEL(3, "Regenerated %i bytes \n", (int)decodedBufferSize);
|
||||
|
||||
errorCode = LZ4F_freeDecompressionContext(dCtx);
|
||||
if (LZ4F_isError(errorCode)) goto _output_error;
|
||||
}
|
||||
|
||||
DISPLAYLEVEL(3, "Using 64 KB block : \n");
|
||||
prefs.frameInfo.blockSizeID = max64KB;
|
||||
prefs.frameInfo.contentChecksumFlag = contentChecksumEnabled;
|
||||
cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
|
||||
if (LZ4F_isError(cSize)) goto _output_error;
|
||||
DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
|
||||
|
||||
DISPLAYLEVEL(3, "without checksum : \n");
|
||||
prefs.frameInfo.contentChecksumFlag = noContentChecksum;
|
||||
cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
|
||||
if (LZ4F_isError(cSize)) goto _output_error;
|
||||
DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
|
||||
|
||||
DISPLAYLEVEL(3, "Using 256 KB block : \n");
|
||||
prefs.frameInfo.blockSizeID = max256KB;
|
||||
prefs.frameInfo.contentChecksumFlag = contentChecksumEnabled;
|
||||
cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
|
||||
if (LZ4F_isError(cSize)) goto _output_error;
|
||||
DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
|
||||
|
||||
DISPLAYLEVEL(3, "Decompression test : \n");
|
||||
{
|
||||
size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
|
||||
unsigned maxBits = FUZ_highbit((U32)decodedBufferSize);
|
||||
BYTE* op = (BYTE*)decodedBuffer;
|
||||
BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
|
||||
BYTE* ip = (BYTE*)compressedBuffer;
|
||||
BYTE* const iend = (BYTE*)compressedBuffer + cSize;
|
||||
U64 crcDest;
|
||||
|
||||
LZ4F_errorCode_t errorCode = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
|
||||
if (LZ4F_isError(errorCode)) goto _output_error;
|
||||
|
||||
DISPLAYLEVEL(3, "random segment sizes : \n");
|
||||
while (ip < iend)
|
||||
{
|
||||
unsigned nbBits = FUZ_rand(&randState) % maxBits;
|
||||
size_t iSize = (FUZ_rand(&randState) & ((1<<nbBits)-1)) + 1;
|
||||
size_t oSize = oend-op;
|
||||
if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
|
||||
//DISPLAY("%7i : + %6i\n", (int)(ip-(BYTE*)compressedBuffer), (int)iSize);
|
||||
errorCode = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL);
|
||||
if (LZ4F_isError(errorCode)) goto _output_error;
|
||||
op += oSize;
|
||||
ip += iSize;
|
||||
}
|
||||
crcDest = XXH64(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
|
||||
if (crcDest != crcOrig) goto _output_error;
|
||||
DISPLAYLEVEL(3, "Regenerated %i bytes \n", (int)decodedBufferSize);
|
||||
|
||||
errorCode = LZ4F_freeDecompressionContext(dCtx);
|
||||
if (LZ4F_isError(errorCode)) goto _output_error;
|
||||
}
|
||||
|
||||
DISPLAYLEVEL(3, "without checksum : \n");
|
||||
prefs.frameInfo.contentChecksumFlag = noContentChecksum;
|
||||
cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
|
||||
if (LZ4F_isError(cSize)) goto _output_error;
|
||||
DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
|
||||
|
||||
DISPLAYLEVEL(3, "Using 1 MB block : \n");
|
||||
prefs.frameInfo.blockSizeID = max1MB;
|
||||
prefs.frameInfo.contentChecksumFlag = contentChecksumEnabled;
|
||||
cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
|
||||
if (LZ4F_isError(cSize)) goto _output_error;
|
||||
DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
|
||||
|
||||
DISPLAYLEVEL(3, "without checksum : \n");
|
||||
prefs.frameInfo.contentChecksumFlag = noContentChecksum;
|
||||
cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
|
||||
if (LZ4F_isError(cSize)) goto _output_error;
|
||||
DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
|
||||
|
||||
DISPLAYLEVEL(3, "Using 4 MB block : \n");
|
||||
prefs.frameInfo.blockSizeID = max4MB;
|
||||
prefs.frameInfo.contentChecksumFlag = contentChecksumEnabled;
|
||||
cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
|
||||
if (LZ4F_isError(cSize)) goto _output_error;
|
||||
DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
|
||||
|
||||
DISPLAYLEVEL(3, "without checksum : \n");
|
||||
prefs.frameInfo.contentChecksumFlag = noContentChecksum;
|
||||
cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
|
||||
if (LZ4F_isError(cSize)) goto _output_error;
|
||||
DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
|
||||
|
||||
DISPLAY("Basic tests completed \n");
|
||||
_end:
|
||||
free(CNBuffer);
|
||||
free(compressedBuffer);
|
||||
free(decodedBuffer);
|
||||
return testResult;
|
||||
|
||||
_output_error:
|
||||
testResult = 1;
|
||||
DISPLAY("Error detected ! \n");
|
||||
goto _end;
|
||||
}
|
||||
|
||||
|
||||
static void locateBuffDiff(const void* buff1, const void* buff2, size_t size, unsigned nonContiguous)
|
||||
{
|
||||
int p=0;
|
||||
BYTE* b1=(BYTE*)buff1;
|
||||
BYTE* b2=(BYTE*)buff2;
|
||||
if (nonContiguous)
|
||||
{
|
||||
DISPLAY("Non-contiguous output test (%i bytes)\n", (int)size);
|
||||
return;
|
||||
}
|
||||
while (b1[p]==b2[p]) p++;
|
||||
DISPLAY("Error at pos %i/%i : %02X != %02X \n", p, (int)size, b1[p], b2[p]);
|
||||
}
|
||||
|
||||
|
||||
static const U32 srcDataLength = 9 MB; /* needs to be > 2x4MB to test large blocks */
|
||||
|
||||
int fuzzerTests(U32 seed, unsigned nbTests, unsigned startTest, double compressibility)
|
||||
{
|
||||
unsigned testResult = 0;
|
||||
unsigned testNb = 0;
|
||||
void* srcBuffer = NULL;
|
||||
void* compressedBuffer = NULL;
|
||||
void* decodedBuffer = NULL;
|
||||
U32 coreRand = seed;
|
||||
LZ4F_decompressionContext_t dCtx = NULL;
|
||||
LZ4F_compressionContext_t cCtx = NULL;
|
||||
size_t result;
|
||||
XXH64_state_t xxh64;
|
||||
# define CHECK(cond, ...) if (cond) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \
|
||||
DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); goto _output_error; }
|
||||
|
||||
// Create buffers
|
||||
result = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
|
||||
CHECK(LZ4F_isError(result), "Allocation failed (error %i)", (int)result);
|
||||
result = LZ4F_createCompressionContext(&cCtx, LZ4F_VERSION);
|
||||
CHECK(LZ4F_isError(result), "Allocation failed (error %i)", (int)result);
|
||||
srcBuffer = malloc(srcDataLength);
|
||||
CHECK(srcBuffer==NULL, "srcBuffer Allocation failed");
|
||||
compressedBuffer = malloc(LZ4F_compressFrameBound(srcDataLength, NULL));
|
||||
CHECK(compressedBuffer==NULL, "compressedBuffer Allocation failed");
|
||||
decodedBuffer = malloc(srcDataLength);
|
||||
CHECK(decodedBuffer==NULL, "decodedBuffer Allocation failed");
|
||||
FUZ_fillCompressibleNoiseBuffer(srcBuffer, srcDataLength, compressibility, &coreRand);
|
||||
|
||||
// jump to requested testNb
|
||||
for (testNb =0; testNb < startTest; testNb++) (void)FUZ_rand(&coreRand); // sync randomizer
|
||||
|
||||
// main fuzzer loop
|
||||
for ( ; testNb < nbTests; testNb++)
|
||||
{
|
||||
U32 randState = coreRand ^ prime1;
|
||||
unsigned BSId = 4 + (FUZ_rand(&randState) & 3);
|
||||
unsigned BMId = FUZ_rand(&randState) & 1;
|
||||
unsigned CCflag = FUZ_rand(&randState) & 1;
|
||||
unsigned autoflush = (FUZ_rand(&randState) & 7) == 2;
|
||||
LZ4F_preferences_t prefs = { 0 };
|
||||
LZ4F_compressOptions_t cOptions = { 0 };
|
||||
LZ4F_decompressOptions_t dOptions = { 0 };
|
||||
unsigned nbBits = (FUZ_rand(&randState) % (FUZ_highbit(srcDataLength-1) - 1)) + 1;
|
||||
size_t srcSize = (FUZ_rand(&randState) & ((1<<nbBits)-1)) + 1;
|
||||
size_t srcStart = FUZ_rand(&randState) % (srcDataLength - srcSize);
|
||||
size_t cSize;
|
||||
U64 crcOrig, crcDecoded;
|
||||
LZ4F_preferences_t* prefsPtr = &prefs;
|
||||
|
||||
(void)FUZ_rand(&coreRand); // update rand seed
|
||||
prefs.frameInfo.blockMode = (blockMode_t)BMId;
|
||||
prefs.frameInfo.blockSizeID = (blockSizeID_t)BSId;
|
||||
prefs.frameInfo.contentChecksumFlag = (contentChecksum_t)CCflag;
|
||||
prefs.autoFlush = autoflush;
|
||||
prefs.compressionLevel = FUZ_rand(&randState) % 5;
|
||||
if ((FUZ_rand(&randState)&0xF) == 1) prefsPtr = NULL;
|
||||
|
||||
DISPLAYUPDATE(2, "\r%5u ", testNb);
|
||||
crcOrig = XXH64((BYTE*)srcBuffer+srcStart, (U32)srcSize, 1);
|
||||
|
||||
if ((FUZ_rand(&randState)&0xF) == 2)
|
||||
{
|
||||
cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(srcSize, prefsPtr), (char*)srcBuffer + srcStart, srcSize, prefsPtr);
|
||||
CHECK(LZ4F_isError(cSize), "LZ4F_compressFrame failed : error %i (%s)", (int)cSize, LZ4F_getErrorName(cSize));
|
||||
}
|
||||
else
|
||||
{
|
||||
const BYTE* ip = (const BYTE*)srcBuffer + srcStart;
|
||||
const BYTE* const iend = ip + srcSize;
|
||||
BYTE* op = (BYTE*)compressedBuffer;
|
||||
BYTE* const oend = op + LZ4F_compressFrameBound(srcDataLength, NULL);
|
||||
unsigned maxBits = FUZ_highbit((U32)srcSize);
|
||||
result = LZ4F_compressBegin(cCtx, op, oend-op, prefsPtr);
|
||||
CHECK(LZ4F_isError(result), "Compression header failed (error %i)", (int)result);
|
||||
op += result;
|
||||
while (ip < iend)
|
||||
{
|
||||
unsigned nbBitsSeg = FUZ_rand(&randState) % maxBits;
|
||||
size_t iSize = (FUZ_rand(&randState) & ((1<<nbBitsSeg)-1)) + 1;
|
||||
size_t oSize = LZ4F_compressBound(iSize, prefsPtr);
|
||||
unsigned forceFlush = ((FUZ_rand(&randState) & 3) == 1);
|
||||
if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
|
||||
cOptions.stableSrc = ((FUZ_rand(&randState) & 3) == 1);
|
||||
|
||||
result = LZ4F_compressUpdate(cCtx, op, oSize, ip, iSize, &cOptions);
|
||||
CHECK(LZ4F_isError(result), "Compression failed (error %i)", (int)result);
|
||||
op += result;
|
||||
ip += iSize;
|
||||
|
||||
if (forceFlush)
|
||||
{
|
||||
result = LZ4F_flush(cCtx, op, oend-op, &cOptions);
|
||||
CHECK(LZ4F_isError(result), "Compression failed (error %i)", (int)result);
|
||||
op += result;
|
||||
}
|
||||
}
|
||||
result = LZ4F_compressEnd(cCtx, op, oend-op, &cOptions);
|
||||
CHECK(LZ4F_isError(result), "Compression completion failed (error %i)", (int)result);
|
||||
op += result;
|
||||
cSize = op-(BYTE*)compressedBuffer;
|
||||
}
|
||||
|
||||
{
|
||||
const BYTE* ip = (const BYTE*)compressedBuffer;
|
||||
const BYTE* const iend = ip + cSize;
|
||||
BYTE* op = (BYTE*)decodedBuffer;
|
||||
BYTE* const oend = op + srcDataLength;
|
||||
unsigned maxBits = FUZ_highbit((U32)cSize);
|
||||
unsigned nonContiguousDst = (FUZ_rand(&randState) & 3) == 1;
|
||||
nonContiguousDst += FUZ_rand(&randState) & nonContiguousDst; /* 0=>0; 1=>1,2 */
|
||||
XXH64_reset(&xxh64, 1);
|
||||
while (ip < iend)
|
||||
{
|
||||
unsigned nbBitsI = (FUZ_rand(&randState) % (maxBits-1)) + 1;
|
||||
unsigned nbBitsO = (FUZ_rand(&randState) % (maxBits)) + 1;
|
||||
size_t iSize = (FUZ_rand(&randState) & ((1<<nbBitsI)-1)) + 1;
|
||||
size_t oSize = (FUZ_rand(&randState) & ((1<<nbBitsO)-1)) + 2;
|
||||
if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
|
||||
if (oSize > (size_t)(oend-op)) oSize = oend-op;
|
||||
dOptions.stableDst = FUZ_rand(&randState) & 1;
|
||||
if (nonContiguousDst==2) dOptions.stableDst = 0;
|
||||
//if (ip == compressedBuffer+62073) DISPLAY("oSize : %i : pos %i \n", (int)oSize, (int)(op-(BYTE*)decodedBuffer));
|
||||
result = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, &dOptions);
|
||||
//if (op+oSize >= (BYTE*)decodedBuffer+94727) DISPLAY("iSize : %i : pos %i \n", (int)iSize, (int)(ip-(BYTE*)compressedBuffer));
|
||||
//if ((int)result<0) DISPLAY("iSize : %i : pos %i \n", (int)iSize, (int)(ip-(BYTE*)compressedBuffer));
|
||||
if (result == (size_t)-ERROR_checksum_invalid) locateBuffDiff((BYTE*)srcBuffer+srcStart, decodedBuffer, srcSize, nonContiguousDst);
|
||||
CHECK(LZ4F_isError(result), "Decompression failed (error %i:%s)", (int)result, LZ4F_getErrorName((LZ4F_errorCode_t)result));
|
||||
XXH64_update(&xxh64, op, (U32)oSize);
|
||||
op += oSize;
|
||||
ip += iSize;
|
||||
op += nonContiguousDst;
|
||||
if (nonContiguousDst==2) op = decodedBuffer; // overwritten destination
|
||||
}
|
||||
CHECK(result != 0, "Frame decompression failed (error %i)", (int)result);
|
||||
crcDecoded = XXH64_digest(&xxh64);
|
||||
if (crcDecoded != crcOrig) locateBuffDiff((BYTE*)srcBuffer+srcStart, decodedBuffer, srcSize, nonContiguousDst);
|
||||
CHECK(crcDecoded != crcOrig, "Decompression corruption");
|
||||
}
|
||||
}
|
||||
|
||||
DISPLAYLEVEL(2, "\rAll tests completed \n");
|
||||
|
||||
_end:
|
||||
LZ4F_freeDecompressionContext(dCtx);
|
||||
LZ4F_freeCompressionContext(cCtx);
|
||||
free(srcBuffer);
|
||||
free(compressedBuffer);
|
||||
free(decodedBuffer);
|
||||
|
||||
if (pause)
|
||||
{
|
||||
DISPLAY("press enter to finish \n");
|
||||
getchar();
|
||||
}
|
||||
return testResult;
|
||||
|
||||
_output_error:
|
||||
testResult = 1;
|
||||
goto _end;
|
||||
}
|
||||
|
||||
|
||||
int FUZ_usage(void)
|
||||
{
|
||||
DISPLAY( "Usage :\n");
|
||||
DISPLAY( " %s [args]\n", programName);
|
||||
DISPLAY( "\n");
|
||||
DISPLAY( "Arguments :\n");
|
||||
DISPLAY( " -i# : Nb of tests (default:%u) \n", nbTestsDefault);
|
||||
DISPLAY( " -s# : Select seed (default:prompt user)\n");
|
||||
DISPLAY( " -t# : Select starting test number (default:0)\n");
|
||||
DISPLAY( " -p# : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT);
|
||||
DISPLAY( " -v : verbose\n");
|
||||
DISPLAY( " -h : display help and exit\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
U32 seed=0;
|
||||
int seedset=0;
|
||||
int argNb;
|
||||
int nbTests = nbTestsDefault;
|
||||
int testNb = 0;
|
||||
int proba = FUZ_COMPRESSIBILITY_DEFAULT;
|
||||
int result=0;
|
||||
|
||||
// Check command line
|
||||
programName = argv[0];
|
||||
for(argNb=1; argNb<argc; argNb++)
|
||||
{
|
||||
char* argument = argv[argNb];
|
||||
|
||||
if(!argument) continue; // Protection if argument empty
|
||||
|
||||
// Decode command (note : aggregated commands are allowed)
|
||||
if (argument[0]=='-')
|
||||
{
|
||||
if (!strcmp(argument, "--no-prompt"))
|
||||
{
|
||||
no_prompt=1;
|
||||
seedset=1;
|
||||
displayLevel=1;
|
||||
continue;
|
||||
}
|
||||
argument++;
|
||||
|
||||
while (*argument!=0)
|
||||
{
|
||||
switch(*argument)
|
||||
{
|
||||
case 'h':
|
||||
return FUZ_usage();
|
||||
case 'v':
|
||||
argument++;
|
||||
displayLevel=4;
|
||||
break;
|
||||
case 'q':
|
||||
argument++;
|
||||
displayLevel--;
|
||||
break;
|
||||
case 'p': /* pause at the end */
|
||||
argument++;
|
||||
pause = 1;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
argument++;
|
||||
nbTests=0;
|
||||
while ((*argument>='0') && (*argument<='9'))
|
||||
{
|
||||
nbTests *= 10;
|
||||
nbTests += *argument - '0';
|
||||
argument++;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
argument++;
|
||||
seed=0;
|
||||
seedset=1;
|
||||
while ((*argument>='0') && (*argument<='9'))
|
||||
{
|
||||
seed *= 10;
|
||||
seed += *argument - '0';
|
||||
argument++;
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
argument++;
|
||||
testNb=0;
|
||||
while ((*argument>='0') && (*argument<='9'))
|
||||
{
|
||||
testNb *= 10;
|
||||
testNb += *argument - '0';
|
||||
argument++;
|
||||
}
|
||||
break;
|
||||
case 'P': /* compressibility % */
|
||||
argument++;
|
||||
proba=0;
|
||||
while ((*argument>='0') && (*argument<='9'))
|
||||
{
|
||||
proba *= 10;
|
||||
proba += *argument - '0';
|
||||
argument++;
|
||||
}
|
||||
if (proba<0) proba=0;
|
||||
if (proba>100) proba=100;
|
||||
break;
|
||||
default:
|
||||
;
|
||||
return FUZ_usage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get Seed
|
||||
printf("Starting lz4frame tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), LZ4_VERSION);
|
||||
|
||||
if (!seedset) seed = FUZ_GetMilliStart() % 10000;
|
||||
printf("Seed = %u\n", seed);
|
||||
if (proba!=FUZ_COMPRESSIBILITY_DEFAULT) printf("Compressibility : %i%%\n", proba);
|
||||
|
||||
if (nbTests<=0) nbTests=1;
|
||||
|
||||
if (testNb==0) result = basicTests(seed, ((double)proba) / 100);
|
||||
if (result) return 1;
|
||||
return fuzzerTests(seed, nbTests, testNb, ((double)proba) / 100);
|
||||
}
|
||||
842
src/lz4/programs/fullbench.c
Normal file
@@ -0,0 +1,842 @@
|
||||
/*
|
||||
bench.c - Demo program to benchmark open-source compression algorithm
|
||||
Copyright (C) Yann Collet 2012-2015
|
||||
|
||||
GPL v2 License
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 source repository : http://code.google.com/p/lz4
|
||||
- LZ4 source mirror : https://github.com/Cyan4973/lz4
|
||||
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
|
||||
//**************************************
|
||||
// Compiler Options
|
||||
//**************************************
|
||||
// Disable some Visual warning messages
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_DEPRECATE // VS2005
|
||||
|
||||
// Unix Large Files support (>4GB)
|
||||
#if (defined(__sun__) && (!defined(__LP64__))) // Sun Solaris 32-bits requires specific definitions
|
||||
# define _LARGEFILE_SOURCE
|
||||
# define _FILE_OFFSET_BITS 64
|
||||
#elif ! defined(__LP64__) // No point defining Large file for 64 bit
|
||||
# define _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
// S_ISREG & gettimeofday() are not supported by MSVC
|
||||
#if defined(_MSC_VER) || defined(_WIN32)
|
||||
# define BMK_LEGACY_TIMER 1
|
||||
#endif
|
||||
|
||||
|
||||
//**************************************
|
||||
// Includes
|
||||
//**************************************
|
||||
#include <stdlib.h> // malloc
|
||||
#include <stdio.h> // fprintf, fopen, ftello64
|
||||
#include <sys/types.h> // stat64
|
||||
#include <sys/stat.h> // stat64
|
||||
#include <string.h> // strcmp
|
||||
|
||||
// Use ftime() if gettimeofday() is not available on your target
|
||||
#if defined(BMK_LEGACY_TIMER)
|
||||
# include <sys/timeb.h> // timeb, ftime
|
||||
#else
|
||||
# include <sys/time.h> // gettimeofday
|
||||
#endif
|
||||
|
||||
#include "lz4.h"
|
||||
#include "lz4hc.h"
|
||||
#include "lz4frame.h"
|
||||
|
||||
#include "xxhash.h"
|
||||
|
||||
|
||||
//**************************************
|
||||
// Compiler Options
|
||||
//**************************************
|
||||
// S_ISREG & gettimeofday() are not supported by MSVC
|
||||
#if !defined(S_ISREG)
|
||||
# define S_ISREG(x) (((x) & S_IFMT) == S_IFREG)
|
||||
#endif
|
||||
|
||||
// GCC does not support _rotl outside of Windows
|
||||
#if !defined(_WIN32)
|
||||
# define _rotl(x,r) ((x << r) | (x >> (32 - r)))
|
||||
#endif
|
||||
|
||||
|
||||
//**************************************
|
||||
// Basic Types
|
||||
//**************************************
|
||||
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L // C99
|
||||
# include <stdint.h>
|
||||
typedef uint8_t BYTE;
|
||||
typedef uint16_t U16;
|
||||
typedef uint32_t U32;
|
||||
typedef int32_t S32;
|
||||
typedef uint64_t U64;
|
||||
#else
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned short U16;
|
||||
typedef unsigned int U32;
|
||||
typedef signed int S32;
|
||||
typedef unsigned long long U64;
|
||||
#endif
|
||||
|
||||
|
||||
//****************************
|
||||
// Constants
|
||||
//****************************
|
||||
#define PROGRAM_DESCRIPTION "LZ4 speed analyzer"
|
||||
#ifndef LZ4_VERSION
|
||||
# define LZ4_VERSION ""
|
||||
#endif
|
||||
#define AUTHOR "Yann Collet"
|
||||
#define WELCOME_MESSAGE "*** %s %s %i-bits, by %s (%s) ***\n", PROGRAM_DESCRIPTION, LZ4_VERSION, (int)(sizeof(void*)*8), AUTHOR, __DATE__
|
||||
|
||||
#define NBLOOPS 6
|
||||
#define TIMELOOP 2500
|
||||
|
||||
#define KNUTH 2654435761U
|
||||
#define MAX_MEM (1984<<20)
|
||||
#define DEFAULT_CHUNKSIZE (4<<20)
|
||||
|
||||
#define ALL_COMPRESSORS 0
|
||||
#define ALL_DECOMPRESSORS 0
|
||||
|
||||
|
||||
//**************************************
|
||||
// Local structures
|
||||
//**************************************
|
||||
struct chunkParameters
|
||||
{
|
||||
U32 id;
|
||||
char* origBuffer;
|
||||
char* compressedBuffer;
|
||||
int origSize;
|
||||
int compressedSize;
|
||||
};
|
||||
|
||||
|
||||
//**************************************
|
||||
// MACRO
|
||||
//**************************************
|
||||
#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
|
||||
#define PROGRESS(...) no_prompt ? 0 : DISPLAY(__VA_ARGS__)
|
||||
|
||||
|
||||
|
||||
//**************************************
|
||||
// Benchmark Parameters
|
||||
//**************************************
|
||||
static int chunkSize = DEFAULT_CHUNKSIZE;
|
||||
static int nbIterations = NBLOOPS;
|
||||
static int BMK_pause = 0;
|
||||
static int compressionTest = 1;
|
||||
static int decompressionTest = 1;
|
||||
static int compressionAlgo = ALL_COMPRESSORS;
|
||||
static int decompressionAlgo = ALL_DECOMPRESSORS;
|
||||
static int no_prompt = 0;
|
||||
|
||||
void BMK_SetBlocksize(int bsize)
|
||||
{
|
||||
chunkSize = bsize;
|
||||
DISPLAY("-Using Block Size of %i KB-\n", chunkSize>>10);
|
||||
}
|
||||
|
||||
void BMK_SetNbIterations(int nbLoops)
|
||||
{
|
||||
nbIterations = nbLoops;
|
||||
DISPLAY("- %i iterations -\n", nbIterations);
|
||||
}
|
||||
|
||||
void BMK_SetPause(void)
|
||||
{
|
||||
BMK_pause = 1;
|
||||
}
|
||||
|
||||
//*********************************************************
|
||||
// Private functions
|
||||
//*********************************************************
|
||||
|
||||
#if defined(BMK_LEGACY_TIMER)
|
||||
|
||||
static int BMK_GetMilliStart(void)
|
||||
{
|
||||
// Based on Legacy ftime()
|
||||
// Rolls over every ~ 12.1 days (0x100000/24/60/60)
|
||||
// Use GetMilliSpan to correct for rollover
|
||||
struct timeb tb;
|
||||
int nCount;
|
||||
ftime( &tb );
|
||||
nCount = (int) (tb.millitm + (tb.time & 0xfffff) * 1000);
|
||||
return nCount;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int BMK_GetMilliStart(void)
|
||||
{
|
||||
// Based on newer gettimeofday()
|
||||
// Use GetMilliSpan to correct for rollover
|
||||
struct timeval tv;
|
||||
int nCount;
|
||||
gettimeofday(&tv, NULL);
|
||||
nCount = (int) (tv.tv_usec/1000 + (tv.tv_sec & 0xfffff) * 1000);
|
||||
return nCount;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static int BMK_GetMilliSpan( int nTimeStart )
|
||||
{
|
||||
int nSpan = BMK_GetMilliStart() - nTimeStart;
|
||||
if ( nSpan < 0 )
|
||||
nSpan += 0x100000 * 1000;
|
||||
return nSpan;
|
||||
}
|
||||
|
||||
|
||||
static size_t BMK_findMaxMem(U64 requiredMem)
|
||||
{
|
||||
size_t step = (64U<<20); // 64 MB
|
||||
BYTE* testmem=NULL;
|
||||
|
||||
requiredMem = (((requiredMem >> 25) + 1) << 26);
|
||||
if (requiredMem > MAX_MEM) requiredMem = MAX_MEM;
|
||||
|
||||
requiredMem += 2*step;
|
||||
while (!testmem)
|
||||
{
|
||||
requiredMem -= step;
|
||||
testmem = (BYTE*) malloc ((size_t)requiredMem);
|
||||
}
|
||||
|
||||
free (testmem);
|
||||
return (size_t) (requiredMem - step);
|
||||
}
|
||||
|
||||
|
||||
static U64 BMK_GetFileSize(char* infilename)
|
||||
{
|
||||
int r;
|
||||
#if defined(_MSC_VER)
|
||||
struct _stat64 statbuf;
|
||||
r = _stat64(infilename, &statbuf);
|
||||
#else
|
||||
struct stat statbuf;
|
||||
r = stat(infilename, &statbuf);
|
||||
#endif
|
||||
if (r || !S_ISREG(statbuf.st_mode)) return 0; // No good...
|
||||
return (U64)statbuf.st_size;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************
|
||||
Benchmark function
|
||||
*********************************************************/
|
||||
|
||||
static int local_LZ4_compress_limitedOutput(const char* in, char* out, int inSize)
|
||||
{
|
||||
return LZ4_compress_limitedOutput(in, out, inSize, LZ4_compressBound(inSize));
|
||||
}
|
||||
|
||||
static void* stateLZ4;
|
||||
static int local_LZ4_compress_withState(const char* in, char* out, int inSize)
|
||||
{
|
||||
return LZ4_compress_withState(stateLZ4, in, out, inSize);
|
||||
}
|
||||
|
||||
static int local_LZ4_compress_limitedOutput_withState(const char* in, char* out, int inSize)
|
||||
{
|
||||
return LZ4_compress_limitedOutput_withState(stateLZ4, in, out, inSize, LZ4_compressBound(inSize));
|
||||
}
|
||||
|
||||
static LZ4_stream_t* ctx;
|
||||
static int local_LZ4_compress_continue(const char* in, char* out, int inSize)
|
||||
{
|
||||
return LZ4_compress_continue(ctx, in, out, inSize);
|
||||
}
|
||||
|
||||
static int local_LZ4_compress_limitedOutput_continue(const char* in, char* out, int inSize)
|
||||
{
|
||||
return LZ4_compress_limitedOutput_continue(ctx, in, out, inSize, LZ4_compressBound(inSize));
|
||||
}
|
||||
|
||||
|
||||
LZ4_stream_t LZ4_dict;
|
||||
static void* local_LZ4_resetDictT(const char* fake)
|
||||
{
|
||||
(void)fake;
|
||||
memset(&LZ4_dict, 0, sizeof(LZ4_stream_t));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int inputSize);
|
||||
static int local_LZ4_compress_forceDict(const char* in, char* out, int inSize)
|
||||
{
|
||||
return LZ4_compress_forceExtDict(&LZ4_dict, in, out, inSize);
|
||||
}
|
||||
|
||||
|
||||
static void* stateLZ4HC;
|
||||
static int local_LZ4_compressHC_withStateHC(const char* in, char* out, int inSize)
|
||||
{
|
||||
return LZ4_compressHC_withStateHC(stateLZ4HC, in, out, inSize);
|
||||
}
|
||||
|
||||
static int local_LZ4_compressHC_limitedOutput_withStateHC(const char* in, char* out, int inSize)
|
||||
{
|
||||
return LZ4_compressHC_limitedOutput_withStateHC(stateLZ4HC, in, out, inSize, LZ4_compressBound(inSize));
|
||||
}
|
||||
|
||||
static int local_LZ4_compressHC_limitedOutput(const char* in, char* out, int inSize)
|
||||
{
|
||||
return LZ4_compressHC_limitedOutput(in, out, inSize, LZ4_compressBound(inSize));
|
||||
}
|
||||
|
||||
static int local_LZ4_compressHC_continue(const char* in, char* out, int inSize)
|
||||
{
|
||||
return LZ4_compressHC_continue((LZ4_streamHC_t*)ctx, in, out, inSize);
|
||||
}
|
||||
|
||||
static int local_LZ4_compressHC_limitedOutput_continue(const char* in, char* out, int inSize)
|
||||
{
|
||||
return LZ4_compressHC_limitedOutput_continue((LZ4_streamHC_t*)ctx, in, out, inSize, LZ4_compressBound(inSize));
|
||||
}
|
||||
|
||||
static int local_LZ4F_compressFrame(const char* in, char* out, int inSize)
|
||||
{
|
||||
return (int)LZ4F_compressFrame(out, 2*inSize + 16, in, inSize, NULL);
|
||||
}
|
||||
|
||||
static int local_LZ4_saveDict(const char* in, char* out, int inSize)
|
||||
{
|
||||
(void)in;
|
||||
return LZ4_saveDict(&LZ4_dict, out, inSize);
|
||||
}
|
||||
|
||||
LZ4_streamHC_t LZ4_dictHC;
|
||||
static int local_LZ4_saveDictHC(const char* in, char* out, int inSize)
|
||||
{
|
||||
(void)in;
|
||||
return LZ4_saveDictHC(&LZ4_dictHC, out, inSize);
|
||||
}
|
||||
|
||||
|
||||
static int local_LZ4_decompress_fast(const char* in, char* out, int inSize, int outSize)
|
||||
{
|
||||
(void)inSize;
|
||||
LZ4_decompress_fast(in, out, outSize);
|
||||
return outSize;
|
||||
}
|
||||
|
||||
static int local_LZ4_decompress_fast_withPrefix64k(const char* in, char* out, int inSize, int outSize)
|
||||
{
|
||||
(void)inSize;
|
||||
LZ4_decompress_fast_withPrefix64k(in, out, outSize);
|
||||
return outSize;
|
||||
}
|
||||
|
||||
static int local_LZ4_decompress_fast_usingDict(const char* in, char* out, int inSize, int outSize)
|
||||
{
|
||||
(void)inSize;
|
||||
LZ4_decompress_fast_usingDict(in, out, outSize, out - 65536, 65536);
|
||||
return outSize;
|
||||
}
|
||||
|
||||
static int local_LZ4_decompress_safe_usingDict(const char* in, char* out, int inSize, int outSize)
|
||||
{
|
||||
(void)inSize;
|
||||
LZ4_decompress_safe_usingDict(in, out, inSize, outSize, out - 65536, 65536);
|
||||
return outSize;
|
||||
}
|
||||
|
||||
extern int LZ4_decompress_safe_forceExtDict(const char* in, char* out, int inSize, int outSize, const char* dict, int dictSize);
|
||||
|
||||
static int local_LZ4_decompress_safe_forceExtDict(const char* in, char* out, int inSize, int outSize)
|
||||
{
|
||||
(void)inSize;
|
||||
LZ4_decompress_safe_forceExtDict(in, out, inSize, outSize, out - 65536, 65536);
|
||||
return outSize;
|
||||
}
|
||||
|
||||
static int local_LZ4_decompress_safe_partial(const char* in, char* out, int inSize, int outSize)
|
||||
{
|
||||
return LZ4_decompress_safe_partial(in, out, inSize, outSize - 5, outSize);
|
||||
}
|
||||
|
||||
static LZ4F_decompressionContext_t g_dCtx;
|
||||
|
||||
static int local_LZ4F_decompress(const char* in, char* out, int inSize, int outSize)
|
||||
{
|
||||
size_t srcSize = inSize;
|
||||
size_t dstSize = outSize;
|
||||
size_t result;
|
||||
result = LZ4F_decompress(g_dCtx, out, &dstSize, in, &srcSize, NULL);
|
||||
if (result!=0) { DISPLAY("Error decompressing frame : unfinished frame\n"); exit(8); }
|
||||
if (srcSize != (size_t)inSize) { DISPLAY("Error decompressing frame : read size incorrect\n"); exit(9); }
|
||||
return (int)dstSize;
|
||||
}
|
||||
|
||||
|
||||
int fullSpeedBench(char** fileNamesTable, int nbFiles)
|
||||
{
|
||||
int fileIdx=0;
|
||||
char* orig_buff;
|
||||
# define NB_COMPRESSION_ALGORITHMS 16
|
||||
double totalCTime[NB_COMPRESSION_ALGORITHMS+1] = {0};
|
||||
double totalCSize[NB_COMPRESSION_ALGORITHMS+1] = {0};
|
||||
# define NB_DECOMPRESSION_ALGORITHMS 9
|
||||
double totalDTime[NB_DECOMPRESSION_ALGORITHMS+1] = {0};
|
||||
size_t errorCode;
|
||||
|
||||
errorCode = LZ4F_createDecompressionContext(&g_dCtx, LZ4F_VERSION);
|
||||
if (LZ4F_isError(errorCode))
|
||||
{
|
||||
DISPLAY("dctx allocation issue \n");
|
||||
return 10;
|
||||
}
|
||||
|
||||
// Loop for each file
|
||||
while (fileIdx<nbFiles)
|
||||
{
|
||||
FILE* inFile;
|
||||
char* inFileName;
|
||||
U64 inFileSize;
|
||||
size_t benchedSize;
|
||||
int nbChunks;
|
||||
int maxCompressedChunkSize;
|
||||
struct chunkParameters* chunkP;
|
||||
size_t readSize;
|
||||
char* compressed_buff; int compressedBuffSize;
|
||||
U32 crcOriginal;
|
||||
|
||||
|
||||
// Init
|
||||
stateLZ4 = LZ4_createStream();
|
||||
stateLZ4HC = LZ4_createStreamHC();
|
||||
|
||||
// Check file existence
|
||||
inFileName = fileNamesTable[fileIdx++];
|
||||
inFile = fopen( inFileName, "rb" );
|
||||
if (inFile==NULL)
|
||||
{
|
||||
DISPLAY( "Pb opening %s\n", inFileName);
|
||||
return 11;
|
||||
}
|
||||
|
||||
// Memory allocation & restrictions
|
||||
inFileSize = BMK_GetFileSize(inFileName);
|
||||
benchedSize = (size_t) BMK_findMaxMem(inFileSize) / 2;
|
||||
if ((U64)benchedSize > inFileSize) benchedSize = (size_t)inFileSize;
|
||||
if (benchedSize < inFileSize)
|
||||
{
|
||||
DISPLAY("Not enough memory for '%s' full size; testing %i MB only...\n", inFileName, (int)(benchedSize>>20));
|
||||
}
|
||||
|
||||
// Alloc
|
||||
chunkP = (struct chunkParameters*) malloc(((benchedSize / (size_t)chunkSize)+1) * sizeof(struct chunkParameters));
|
||||
orig_buff = (char*) malloc((size_t)benchedSize);
|
||||
nbChunks = (int) (((int)benchedSize + (chunkSize-1))/ chunkSize);
|
||||
maxCompressedChunkSize = LZ4_compressBound(chunkSize);
|
||||
compressedBuffSize = nbChunks * maxCompressedChunkSize;
|
||||
compressed_buff = (char*)malloc((size_t)compressedBuffSize);
|
||||
|
||||
|
||||
if(!orig_buff || !compressed_buff)
|
||||
{
|
||||
DISPLAY("\nError: not enough memory!\n");
|
||||
free(orig_buff);
|
||||
free(compressed_buff);
|
||||
free(chunkP);
|
||||
fclose(inFile);
|
||||
return 12;
|
||||
}
|
||||
|
||||
// Fill input buffer
|
||||
DISPLAY("Loading %s... \r", inFileName);
|
||||
readSize = fread(orig_buff, 1, benchedSize, inFile);
|
||||
fclose(inFile);
|
||||
|
||||
if(readSize != benchedSize)
|
||||
{
|
||||
DISPLAY("\nError: problem reading file '%s' !! \n", inFileName);
|
||||
free(orig_buff);
|
||||
free(compressed_buff);
|
||||
free(chunkP);
|
||||
return 13;
|
||||
}
|
||||
|
||||
// Calculating input Checksum
|
||||
crcOriginal = XXH32(orig_buff, (unsigned int)benchedSize,0);
|
||||
|
||||
|
||||
// Bench
|
||||
{
|
||||
int loopNb, nb_loops, chunkNb, cAlgNb, dAlgNb;
|
||||
size_t cSize=0;
|
||||
double ratio=0.;
|
||||
|
||||
DISPLAY("\r%79s\r", "");
|
||||
DISPLAY(" %s : \n", inFileName);
|
||||
|
||||
// Compression Algorithms
|
||||
for (cAlgNb=1; (cAlgNb <= NB_COMPRESSION_ALGORITHMS) && (compressionTest); cAlgNb++)
|
||||
{
|
||||
const char* compressorName;
|
||||
int (*compressionFunction)(const char*, char*, int);
|
||||
void* (*initFunction)(const char*) = NULL;
|
||||
double bestTime = 100000000.;
|
||||
|
||||
// Init data chunks
|
||||
{
|
||||
int i;
|
||||
size_t remaining = benchedSize;
|
||||
char* in = orig_buff;
|
||||
char* out = compressed_buff;
|
||||
nbChunks = (int) (((int)benchedSize + (chunkSize-1))/ chunkSize);
|
||||
for (i=0; i<nbChunks; i++)
|
||||
{
|
||||
chunkP[i].id = i;
|
||||
chunkP[i].origBuffer = in; in += chunkSize;
|
||||
if ((int)remaining > chunkSize) { chunkP[i].origSize = chunkSize; remaining -= chunkSize; } else { chunkP[i].origSize = (int)remaining; remaining = 0; }
|
||||
chunkP[i].compressedBuffer = out; out += maxCompressedChunkSize;
|
||||
chunkP[i].compressedSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((compressionAlgo != ALL_COMPRESSORS) && (compressionAlgo != cAlgNb)) continue;
|
||||
|
||||
switch(cAlgNb)
|
||||
{
|
||||
case 1 : compressionFunction = LZ4_compress; compressorName = "LZ4_compress"; break;
|
||||
case 2 : compressionFunction = local_LZ4_compress_limitedOutput; compressorName = "LZ4_compress_limitedOutput"; break;
|
||||
case 3 : compressionFunction = local_LZ4_compress_withState; compressorName = "LZ4_compress_withState"; break;
|
||||
case 4 : compressionFunction = local_LZ4_compress_limitedOutput_withState; compressorName = "LZ4_compress_limitedOutput_withState"; break;
|
||||
case 5 : compressionFunction = local_LZ4_compress_continue; initFunction = LZ4_create; compressorName = "LZ4_compress_continue"; break;
|
||||
case 6 : compressionFunction = local_LZ4_compress_limitedOutput_continue; initFunction = LZ4_create; compressorName = "LZ4_compress_limitedOutput_continue"; break;
|
||||
case 7 : compressionFunction = LZ4_compressHC; compressorName = "LZ4_compressHC"; break;
|
||||
case 8 : compressionFunction = local_LZ4_compressHC_limitedOutput; compressorName = "LZ4_compressHC_limitedOutput"; break;
|
||||
case 9 : compressionFunction = local_LZ4_compressHC_withStateHC; compressorName = "LZ4_compressHC_withStateHC"; break;
|
||||
case 10: compressionFunction = local_LZ4_compressHC_limitedOutput_withStateHC; compressorName = "LZ4_compressHC_limitedOutput_withStateHC"; break;
|
||||
case 11: compressionFunction = local_LZ4_compressHC_continue; initFunction = LZ4_createHC; compressorName = "LZ4_compressHC_continue"; break;
|
||||
case 12: compressionFunction = local_LZ4_compressHC_limitedOutput_continue; initFunction = LZ4_createHC; compressorName = "LZ4_compressHC_limitedOutput_continue"; break;
|
||||
case 13: compressionFunction = local_LZ4_compress_forceDict; initFunction = local_LZ4_resetDictT; compressorName = "LZ4_compress_forceDict"; break;
|
||||
case 14: compressionFunction = local_LZ4F_compressFrame; compressorName = "LZ4F_compressFrame";
|
||||
chunkP[0].origSize = (int)benchedSize; nbChunks=1;
|
||||
break;
|
||||
case 15: compressionFunction = local_LZ4_saveDict; compressorName = "LZ4_saveDict";
|
||||
LZ4_loadDict(&LZ4_dict, chunkP[0].origBuffer, chunkP[0].origSize);
|
||||
break;
|
||||
case 16: compressionFunction = local_LZ4_saveDictHC; compressorName = "LZ4_saveDictHC";
|
||||
LZ4_loadDictHC(&LZ4_dictHC, chunkP[0].origBuffer, chunkP[0].origSize);
|
||||
break;
|
||||
default : DISPLAY("ERROR ! Bad algorithm Id !! \n"); free(chunkP); return 1;
|
||||
}
|
||||
|
||||
for (loopNb = 1; loopNb <= nbIterations; loopNb++)
|
||||
{
|
||||
double averageTime;
|
||||
int milliTime;
|
||||
|
||||
PROGRESS("%1i- %-28.28s :%9i ->\r", loopNb, compressorName, (int)benchedSize);
|
||||
{ size_t i; for (i=0; i<benchedSize; i++) compressed_buff[i]=(char)i; } // warming up memory
|
||||
|
||||
nb_loops = 0;
|
||||
milliTime = BMK_GetMilliStart();
|
||||
while(BMK_GetMilliStart() == milliTime);
|
||||
milliTime = BMK_GetMilliStart();
|
||||
while(BMK_GetMilliSpan(milliTime) < TIMELOOP)
|
||||
{
|
||||
if (initFunction!=NULL) ctx = initFunction(chunkP[0].origBuffer);
|
||||
for (chunkNb=0; chunkNb<nbChunks; chunkNb++)
|
||||
{
|
||||
chunkP[chunkNb].compressedSize = compressionFunction(chunkP[chunkNb].origBuffer, chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origSize);
|
||||
if (chunkP[chunkNb].compressedSize==0) DISPLAY("ERROR ! %s() = 0 !! \n", compressorName), exit(1);
|
||||
}
|
||||
if (initFunction!=NULL) free(ctx);
|
||||
nb_loops++;
|
||||
}
|
||||
milliTime = BMK_GetMilliSpan(milliTime);
|
||||
|
||||
averageTime = (double)milliTime / nb_loops;
|
||||
if (averageTime < bestTime) bestTime = averageTime;
|
||||
cSize=0; for (chunkNb=0; chunkNb<nbChunks; chunkNb++) cSize += chunkP[chunkNb].compressedSize;
|
||||
ratio = (double)cSize/(double)benchedSize*100.;
|
||||
PROGRESS("%1i- %-28.28s :%9i ->%9i (%5.2f%%),%7.1f MB/s\r", loopNb, compressorName, (int)benchedSize, (int)cSize, ratio, (double)benchedSize / bestTime / 1000.);
|
||||
}
|
||||
|
||||
if (ratio<100.)
|
||||
DISPLAY("%2i-%-28.28s :%9i ->%9i (%5.2f%%),%7.1f MB/s\n", cAlgNb, compressorName, (int)benchedSize, (int)cSize, ratio, (double)benchedSize / bestTime / 1000.);
|
||||
else
|
||||
DISPLAY("%2i-%-28.28s :%9i ->%9i (%5.1f%%),%7.1f MB/s\n", cAlgNb, compressorName, (int)benchedSize, (int)cSize, ratio, (double)benchedSize / bestTime / 1000.);
|
||||
|
||||
totalCTime[cAlgNb] += bestTime;
|
||||
totalCSize[cAlgNb] += cSize;
|
||||
}
|
||||
|
||||
// Prepare layout for decompression
|
||||
// Init data chunks
|
||||
{
|
||||
int i;
|
||||
size_t remaining = benchedSize;
|
||||
char* in = orig_buff;
|
||||
char* out = compressed_buff;
|
||||
nbChunks = (int) (((int)benchedSize + (chunkSize-1))/ chunkSize);
|
||||
for (i=0; i<nbChunks; i++)
|
||||
{
|
||||
chunkP[i].id = i;
|
||||
chunkP[i].origBuffer = in; in += chunkSize;
|
||||
if ((int)remaining > chunkSize) { chunkP[i].origSize = chunkSize; remaining -= chunkSize; } else { chunkP[i].origSize = (int)remaining; remaining = 0; }
|
||||
chunkP[i].compressedBuffer = out; out += maxCompressedChunkSize;
|
||||
chunkP[i].compressedSize = 0;
|
||||
}
|
||||
}
|
||||
for (chunkNb=0; chunkNb<nbChunks; chunkNb++)
|
||||
{
|
||||
chunkP[chunkNb].compressedSize = LZ4_compress(chunkP[chunkNb].origBuffer, chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origSize);
|
||||
if (chunkP[chunkNb].compressedSize==0) DISPLAY("ERROR ! %s() = 0 !! \n", "LZ4_compress"), exit(1);
|
||||
}
|
||||
|
||||
// Decompression Algorithms
|
||||
for (dAlgNb=1; (dAlgNb <= NB_DECOMPRESSION_ALGORITHMS) && (decompressionTest); dAlgNb++)
|
||||
{
|
||||
//const char* dName = decompressionNames[dAlgNb];
|
||||
const char* dName;
|
||||
int (*decompressionFunction)(const char*, char*, int, int);
|
||||
double bestTime = 100000000.;
|
||||
|
||||
if ((decompressionAlgo != ALL_DECOMPRESSORS) && (decompressionAlgo != dAlgNb)) continue;
|
||||
|
||||
switch(dAlgNb)
|
||||
{
|
||||
case 1: decompressionFunction = local_LZ4_decompress_fast; dName = "LZ4_decompress_fast"; break;
|
||||
case 2: decompressionFunction = local_LZ4_decompress_fast_withPrefix64k; dName = "LZ4_decompress_fast_withPrefix64k"; break;
|
||||
case 3: decompressionFunction = local_LZ4_decompress_fast_usingDict; dName = "LZ4_decompress_fast_usingDict"; break;
|
||||
case 4: decompressionFunction = LZ4_decompress_safe; dName = "LZ4_decompress_safe"; break;
|
||||
case 5: decompressionFunction = LZ4_decompress_safe_withPrefix64k; dName = "LZ4_decompress_safe_withPrefix64k"; break;
|
||||
case 6: decompressionFunction = local_LZ4_decompress_safe_usingDict; dName = "LZ4_decompress_safe_usingDict"; break;
|
||||
case 7: decompressionFunction = local_LZ4_decompress_safe_partial; dName = "LZ4_decompress_safe_partial"; break;
|
||||
case 8: decompressionFunction = local_LZ4_decompress_safe_forceExtDict; dName = "LZ4_decompress_safe_forceExtDict"; break;
|
||||
case 9: decompressionFunction = local_LZ4F_decompress; dName = "LZ4F_decompress";
|
||||
errorCode = LZ4F_compressFrame(compressed_buff, compressedBuffSize, orig_buff, benchedSize, NULL);
|
||||
if (LZ4F_isError(errorCode)) { DISPLAY("Preparation error compressing frame\n"); return 1; }
|
||||
chunkP[0].origSize = (int)benchedSize;
|
||||
chunkP[0].compressedSize = (int)errorCode;
|
||||
nbChunks = 1;
|
||||
break;
|
||||
default : DISPLAY("ERROR ! Bad decompression algorithm Id !! \n"); free(chunkP); return 1;
|
||||
}
|
||||
|
||||
{ size_t i; for (i=0; i<benchedSize; i++) orig_buff[i]=0; } // zeroing source area, for CRC checking
|
||||
|
||||
for (loopNb = 1; loopNb <= nbIterations; loopNb++)
|
||||
{
|
||||
double averageTime;
|
||||
int milliTime;
|
||||
U32 crcDecoded;
|
||||
|
||||
PROGRESS("%1i- %-29.29s :%10i ->\r", loopNb, dName, (int)benchedSize);
|
||||
|
||||
nb_loops = 0;
|
||||
milliTime = BMK_GetMilliStart();
|
||||
while(BMK_GetMilliStart() == milliTime);
|
||||
milliTime = BMK_GetMilliStart();
|
||||
while(BMK_GetMilliSpan(milliTime) < TIMELOOP)
|
||||
{
|
||||
for (chunkNb=0; chunkNb<nbChunks; chunkNb++)
|
||||
{
|
||||
int decodedSize = decompressionFunction(chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origBuffer, chunkP[chunkNb].compressedSize, chunkP[chunkNb].origSize);
|
||||
if (chunkP[chunkNb].origSize != decodedSize) DISPLAY("ERROR ! %s() == %i != %i !! \n", dName, decodedSize, chunkP[chunkNb].origSize), exit(1);
|
||||
}
|
||||
nb_loops++;
|
||||
}
|
||||
milliTime = BMK_GetMilliSpan(milliTime);
|
||||
|
||||
averageTime = (double)milliTime / nb_loops;
|
||||
if (averageTime < bestTime) bestTime = averageTime;
|
||||
|
||||
PROGRESS("%1i- %-29.29s :%10i -> %7.1f MB/s\r", loopNb, dName, (int)benchedSize, (double)benchedSize / bestTime / 1000.);
|
||||
|
||||
// CRC Checking
|
||||
crcDecoded = XXH32(orig_buff, (int)benchedSize, 0);
|
||||
if (crcOriginal!=crcDecoded) { DISPLAY("\n!!! WARNING !!! %14s : Invalid Checksum : %x != %x\n", inFileName, (unsigned)crcOriginal, (unsigned)crcDecoded); exit(1); }
|
||||
}
|
||||
|
||||
DISPLAY("%2i-%-29.29s :%10i -> %7.1f MB/s\n", dAlgNb, dName, (int)benchedSize, (double)benchedSize / bestTime / 1000.);
|
||||
|
||||
totalDTime[dAlgNb] += bestTime;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
free(orig_buff);
|
||||
free(compressed_buff);
|
||||
free(chunkP);
|
||||
}
|
||||
|
||||
if (BMK_pause) { printf("press enter...\n"); getchar(); }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int usage(char* exename)
|
||||
{
|
||||
DISPLAY( "Usage :\n");
|
||||
DISPLAY( " %s [arg] file1 file2 ... fileX\n", exename);
|
||||
DISPLAY( "Arguments :\n");
|
||||
DISPLAY( " -c : compression tests only\n");
|
||||
DISPLAY( " -d : decompression tests only\n");
|
||||
DISPLAY( " -H/-h : Help (this text + advanced options)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usage_advanced(void)
|
||||
{
|
||||
DISPLAY( "\nAdvanced options :\n");
|
||||
DISPLAY( " -c# : test only compression function # [1-%i]\n", NB_COMPRESSION_ALGORITHMS);
|
||||
DISPLAY( " -d# : test only decompression function # [1-%i]\n", NB_DECOMPRESSION_ALGORITHMS);
|
||||
DISPLAY( " -i# : iteration loops [1-9](default : %i)\n", NBLOOPS);
|
||||
DISPLAY( " -B# : Block size [4-7](default : 7)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int badusage(char* exename)
|
||||
{
|
||||
DISPLAY("Wrong parameters\n");
|
||||
usage(exename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int i,
|
||||
filenamesStart=2;
|
||||
char* exename=argv[0];
|
||||
char* input_filename=0;
|
||||
|
||||
// Welcome message
|
||||
DISPLAY(WELCOME_MESSAGE);
|
||||
|
||||
if (argc<2) { badusage(exename); return 1; }
|
||||
|
||||
for(i=1; i<argc; i++)
|
||||
{
|
||||
char* argument = argv[i];
|
||||
|
||||
if(!argument) continue; // Protection if argument empty
|
||||
if (!strcmp(argument, "--no-prompt"))
|
||||
{
|
||||
no_prompt = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Decode command (note : aggregated commands are allowed)
|
||||
if (argument[0]=='-')
|
||||
{
|
||||
while (argument[1]!=0)
|
||||
{
|
||||
argument ++;
|
||||
|
||||
switch(argument[0])
|
||||
{
|
||||
// Select compression algorithm only
|
||||
case 'c':
|
||||
decompressionTest = 0;
|
||||
while ((argument[1]>= '0') && (argument[1]<= '9'))
|
||||
{
|
||||
compressionAlgo *= 10;
|
||||
compressionAlgo += argument[1] - '0';
|
||||
argument++;
|
||||
}
|
||||
break;
|
||||
|
||||
// Select decompression algorithm only
|
||||
case 'd':
|
||||
compressionTest = 0;
|
||||
while ((argument[1]>= '0') && (argument[1]<= '9'))
|
||||
{
|
||||
decompressionAlgo *= 10;
|
||||
decompressionAlgo += argument[1] - '0';
|
||||
argument++;
|
||||
}
|
||||
break;
|
||||
|
||||
// Display help on usage
|
||||
case 'h' :
|
||||
case 'H': usage(exename); usage_advanced(); return 0;
|
||||
|
||||
// Modify Block Properties
|
||||
case 'B':
|
||||
while (argument[1]!=0)
|
||||
switch(argument[1])
|
||||
{
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
{
|
||||
int B = argument[1] - '0';
|
||||
int S = 1 << (8 + 2*B);
|
||||
BMK_SetBlocksize(S);
|
||||
argument++;
|
||||
break;
|
||||
}
|
||||
case 'D': argument++; break;
|
||||
default : goto _exit_blockProperties;
|
||||
}
|
||||
_exit_blockProperties:
|
||||
break;
|
||||
|
||||
// Modify Nb Iterations
|
||||
case 'i':
|
||||
if ((argument[1] >='1') && (argument[1] <='9'))
|
||||
{
|
||||
int iters = argument[1] - '0';
|
||||
BMK_SetNbIterations(iters);
|
||||
argument++;
|
||||
}
|
||||
break;
|
||||
|
||||
// Pause at the end (hidden option)
|
||||
case 'p': BMK_SetPause(); break;
|
||||
|
||||
// Unknown command
|
||||
default : badusage(exename); return 1;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// first provided filename is input
|
||||
if (!input_filename) { input_filename=argument; filenamesStart=i; continue; }
|
||||
|
||||
}
|
||||
|
||||
// No input filename ==> Error
|
||||
if(!input_filename) { badusage(exename); return 1; }
|
||||
|
||||
return fullSpeedBench(argv+filenamesStart, argc-filenamesStart);
|
||||
|
||||
}
|
||||
|
||||
1167
src/lz4/programs/fuzzer.c
Normal file
88
src/lz4/programs/lz4.1
Normal file
@@ -0,0 +1,88 @@
|
||||
\"
|
||||
\" lz4.1: This is a manual page for 'lz4' program. This file is part of the
|
||||
\" lz4 <https://code.google.com/p/lz4/> project.
|
||||
\"
|
||||
|
||||
\" No hyphenation
|
||||
.hy 0
|
||||
.nr HY 0
|
||||
|
||||
.TH lz4 "1" "2014-02-27" "lz4" "User Commands"
|
||||
.SH NAME
|
||||
\fBlz4\fR - Extremely fast compression algorithm
|
||||
|
||||
.SH SYNOPSIS
|
||||
.TP 5
|
||||
\fBlz4\fR [\fBOPTIONS\fR] [-|INPUT-FILE] <OUTPUT-FILE>
|
||||
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
\fBlz4\fR is an extremely fast lossless compression algorithm. It is based on
|
||||
the \fBLZ77\fR family of compression scheme. At the compression speed of 400
|
||||
MB/s per core, \fBlz4\fR is also scalable with multi-core CPUs. It features
|
||||
an extremely fast decoder, with speed in multiple GB/s per core, typically
|
||||
reaching the RAM speed limits on multi-core systems. \fBlz4\fR supports
|
||||
following options
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-1
|
||||
fast compression (default)
|
||||
.TP
|
||||
.B \-9
|
||||
high compression
|
||||
.TP
|
||||
.B \-d
|
||||
decompression
|
||||
.TP
|
||||
.B \-f
|
||||
overwrite output without prompting
|
||||
.TP
|
||||
.B \-h/\-H
|
||||
display help/long help and exit
|
||||
.TP
|
||||
.B \-V
|
||||
display Version number and exit
|
||||
.TP
|
||||
.B \-v
|
||||
verbose mode
|
||||
.TP
|
||||
.B \-q
|
||||
suppress warnings; specify twice to suppress errors too
|
||||
.TP
|
||||
.B \-c
|
||||
force write to standard output, even if it is the console
|
||||
.TP
|
||||
.B \-t
|
||||
test compressed file integrity
|
||||
.TP
|
||||
.B \-z
|
||||
force compression
|
||||
.TP
|
||||
.B \-l
|
||||
use Legacy format (useful for Linux Kernel compression)
|
||||
.TP
|
||||
.B \-B#
|
||||
block size [4-7](default : 7)
|
||||
B4= 64KB ; B5= 256KB ; B6= 1MB ; B7= 4MB
|
||||
.TP
|
||||
.B \-BD
|
||||
block dependency (improve compression ratio)
|
||||
.TP
|
||||
.B \-BX
|
||||
enable block checksum (default:disabled)
|
||||
.TP
|
||||
.B \-Sx
|
||||
disable stream checksum (default:enabled)
|
||||
.TP
|
||||
.B \-b
|
||||
benchmark file(s)
|
||||
.TP
|
||||
.B \-i#
|
||||
iteration loops [1-9](default : 3), benchmark mode only
|
||||
|
||||
.SH BUGS
|
||||
Report bugs at:- https://code.google.com/p/lz4/
|
||||
|
||||
.SH AUTHOR
|
||||
Yann Collet
|
||||
33
src/lz4/programs/lz4c.1
Normal file
@@ -0,0 +1,33 @@
|
||||
\"
|
||||
\" lz4c.1: This is a manual page for 'lz4c' program. This file is part of the
|
||||
\" lz4 <https://code.google.com/p/lz4/> project.
|
||||
\"
|
||||
|
||||
\" No hyphenation
|
||||
.hy 0
|
||||
.nr HY 0
|
||||
|
||||
.TH lz4c "1" "2014-04-15" "lz4c" "User Commands"
|
||||
.SH NAME
|
||||
\fBlz4\fR - Extremely fast compression algorithm
|
||||
|
||||
.SH SYNOPSIS
|
||||
.TP 5
|
||||
\fBlz4c\fR [\fBOPTIONS\fR] [-|INPUT-FILE] <OUTPUT-FILE>
|
||||
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
\fBlz4c\fR is the legacy version of \fBlz4\fR.
|
||||
As such, it supports older supplementary legacy commands.
|
||||
\fBlz4c\fR is now deprecated.
|
||||
It is recommended to use \fBlz4\fR instead whenever possible.
|
||||
|
||||
To get a list of commands specific to lz4c, do :
|
||||
lz4c -h
|
||||
|
||||
|
||||
.SH BUGS
|
||||
Report bugs at:- https://code.google.com/p/lz4/
|
||||
|
||||
.SH AUTHOR
|
||||
Yann Collet
|
||||
32
src/lz4/programs/lz4cat.1
Normal file
@@ -0,0 +1,32 @@
|
||||
\"
|
||||
\" lz4cat.1: This is a manual page for 'lz4cat' program. This file is part of
|
||||
\" the lz4 <https://code.google.com/p/lz4/> project.
|
||||
\"
|
||||
|
||||
\" No hyphenation
|
||||
.hy 0
|
||||
.nr HY 0
|
||||
|
||||
.TH lz4cat "1" "2014-06-20" "lz4cat" "User Commands"
|
||||
.SH NAME
|
||||
\fBlz4cat\fR - Utility based on LZ4
|
||||
|
||||
.SH SYNOPSIS
|
||||
.TP 5
|
||||
\fBlz4cat\fR [\fBOPTIONS\fR] [-|INPUT-FILE]
|
||||
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
\fBlz4cat\fR is an utility based on \fBlz4\fR, an extremely fast lossless compression algorithm.
|
||||
|
||||
\fBlz4cat\fR decompress input file or stream, redirecting its output to the console.
|
||||
It is equivalent to \fBlz4 -cd\fR,
|
||||
|
||||
Available options are the same as \fBlz4\fR ones (man lz4).
|
||||
|
||||
|
||||
.SH BUGS
|
||||
Report bugs at:- https://code.google.com/p/lz4/
|
||||
|
||||
.SH AUTHOR
|
||||
Yann Collet
|
||||
501
src/lz4/programs/lz4cli.c
Normal file
@@ -0,0 +1,501 @@
|
||||
/*
|
||||
LZ4cli - LZ4 Command Line Interface
|
||||
Copyright (C) Yann Collet 2011-2014
|
||||
|
||||
GPL v2 License
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
/*
|
||||
Note : this is stand-alone program.
|
||||
It is not part of LZ4 compression library, it is a user program of the LZ4 library.
|
||||
The license of LZ4 library is BSD.
|
||||
The license of xxHash library is BSD.
|
||||
The license of this compression CLI program is GPLv2.
|
||||
*/
|
||||
|
||||
/**************************************
|
||||
* Tuning parameters
|
||||
***************************************/
|
||||
/* ENABLE_LZ4C_LEGACY_OPTIONS :
|
||||
Control the availability of -c0, -c1 and -hc legacy arguments
|
||||
Default : Legacy options are disabled */
|
||||
/* #define ENABLE_LZ4C_LEGACY_OPTIONS */
|
||||
|
||||
|
||||
/**************************************
|
||||
* Compiler Options
|
||||
***************************************/
|
||||
/* Disable some Visual warning messages */
|
||||
#ifdef _MSC_VER
|
||||
# define _CRT_SECURE_NO_WARNINGS
|
||||
# define _CRT_SECURE_NO_DEPRECATE /* VS2005 */
|
||||
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
|
||||
#endif
|
||||
|
||||
#define _POSIX_SOURCE 1 /* for fileno() within <stdio.h> on unix */
|
||||
|
||||
|
||||
/****************************
|
||||
* Includes
|
||||
*****************************/
|
||||
#include <stdio.h> /* fprintf, getchar */
|
||||
#include <stdlib.h> /* exit, calloc, free */
|
||||
#include <string.h> /* strcmp, strlen */
|
||||
#include "bench.h" /* BMK_benchFile, BMK_SetNbIterations, BMK_SetBlocksize, BMK_SetPause */
|
||||
#include "lz4io.h"
|
||||
|
||||
|
||||
/****************************
|
||||
* OS-specific Includes
|
||||
*****************************/
|
||||
#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__)
|
||||
# include <fcntl.h> /* _O_BINARY */
|
||||
# include <io.h> /* _setmode, _isatty */
|
||||
# ifdef __MINGW32__
|
||||
int _fileno(FILE *stream); /* MINGW somehow forgets to include this prototype into <stdio.h> */
|
||||
# endif
|
||||
# define SET_BINARY_MODE(file) _setmode(_fileno(file), _O_BINARY)
|
||||
# define IS_CONSOLE(stdStream) _isatty(_fileno(stdStream))
|
||||
#else
|
||||
# include <unistd.h> /* isatty */
|
||||
# define SET_BINARY_MODE(file)
|
||||
# define IS_CONSOLE(stdStream) isatty(fileno(stdStream))
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************
|
||||
* Constants
|
||||
******************************/
|
||||
#define COMPRESSOR_NAME "LZ4 command line interface"
|
||||
#ifndef LZ4_VERSION
|
||||
# define LZ4_VERSION "r126"
|
||||
#endif
|
||||
#define AUTHOR "Yann Collet"
|
||||
#define WELCOME_MESSAGE "*** %s %i-bits %s, by %s (%s) ***\n", COMPRESSOR_NAME, (int)(sizeof(void*)*8), LZ4_VERSION, AUTHOR, __DATE__
|
||||
#define LZ4_EXTENSION ".lz4"
|
||||
#define LZ4_CAT "lz4cat"
|
||||
|
||||
#define KB *(1U<<10)
|
||||
#define MB *(1U<<20)
|
||||
#define GB *(1U<<30)
|
||||
|
||||
#define LZ4_BLOCKSIZEID_DEFAULT 7
|
||||
|
||||
|
||||
/**************************************
|
||||
* Macros
|
||||
***************************************/
|
||||
#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
|
||||
#define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
|
||||
static unsigned displayLevel = 2; /* 0 : no display ; 1: errors ; 2 : + result + interaction + warnings ; 3 : + progression; 4 : + information */
|
||||
|
||||
|
||||
/**************************************
|
||||
* Local Variables
|
||||
***************************************/
|
||||
static char* programName;
|
||||
|
||||
|
||||
/**************************************
|
||||
* Exceptions
|
||||
***************************************/
|
||||
#define DEBUG 0
|
||||
#define DEBUGOUTPUT(...) if (DEBUG) DISPLAY(__VA_ARGS__);
|
||||
#define EXM_THROW(error, ...) \
|
||||
{ \
|
||||
DEBUGOUTPUT("Error defined at %s, line %i : \n", __FILE__, __LINE__); \
|
||||
DISPLAYLEVEL(1, "Error %i : ", error); \
|
||||
DISPLAYLEVEL(1, __VA_ARGS__); \
|
||||
DISPLAYLEVEL(1, "\n"); \
|
||||
exit(error); \
|
||||
}
|
||||
|
||||
|
||||
/**************************************
|
||||
* Version modifiers
|
||||
***************************************/
|
||||
#define EXTENDED_ARGUMENTS
|
||||
#define EXTENDED_HELP
|
||||
#define EXTENDED_FORMAT
|
||||
#define DEFAULT_COMPRESSOR LZ4IO_compressFilename
|
||||
#define DEFAULT_DECOMPRESSOR LZ4IO_decompressFilename
|
||||
int LZ4IO_compressFilename_Legacy(char* input_filename, char* output_filename, int compressionlevel); /* hidden function */
|
||||
|
||||
|
||||
/****************************
|
||||
* Functions
|
||||
*****************************/
|
||||
static int usage(void)
|
||||
{
|
||||
DISPLAY( "Usage :\n");
|
||||
DISPLAY( " %s [arg] [input] [output]\n", programName);
|
||||
DISPLAY( "\n");
|
||||
DISPLAY( "input : a filename\n");
|
||||
DISPLAY( " with no FILE, or when FILE is - or %s, read standard input\n", stdinmark);
|
||||
DISPLAY( "Arguments :\n");
|
||||
DISPLAY( " -1 : Fast compression (default) \n");
|
||||
DISPLAY( " -9 : High compression \n");
|
||||
DISPLAY( " -d : decompression (default for %s extension)\n", LZ4_EXTENSION);
|
||||
DISPLAY( " -z : force compression\n");
|
||||
DISPLAY( " -f : overwrite output without prompting \n");
|
||||
DISPLAY( " -h/-H : display help/long help and exit\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usage_advanced(void)
|
||||
{
|
||||
DISPLAY(WELCOME_MESSAGE);
|
||||
usage();
|
||||
DISPLAY( "\n");
|
||||
DISPLAY( "Advanced arguments :\n");
|
||||
DISPLAY( " -V : display Version number and exit\n");
|
||||
DISPLAY( " -v : verbose mode\n");
|
||||
DISPLAY( " -q : suppress warnings; specify twice to suppress errors too\n");
|
||||
DISPLAY( " -c : force write to standard output, even if it is the console\n");
|
||||
DISPLAY( " -t : test compressed file integrity\n");
|
||||
DISPLAY( " -l : compress using Legacy format (Linux kernel compression)\n");
|
||||
DISPLAY( " -B# : Block size [4-7](default : 7)\n");
|
||||
DISPLAY( " -BD : Block dependency (improve compression ratio)\n");
|
||||
/* DISPLAY( " -BX : enable block checksum (default:disabled)\n"); *//* Option currently inactive */
|
||||
DISPLAY( " -Sx : disable stream checksum (default:enabled)\n");
|
||||
DISPLAY( "Benchmark arguments :\n");
|
||||
DISPLAY( " -b : benchmark file(s)\n");
|
||||
DISPLAY( " -i# : iteration loops [1-9](default : 3), benchmark mode only\n");
|
||||
#if defined(ENABLE_LZ4C_LEGACY_OPTIONS)
|
||||
DISPLAY( "Legacy arguments :\n");
|
||||
DISPLAY( " -c0 : fast compression\n");
|
||||
DISPLAY( " -c1 : high compression\n");
|
||||
DISPLAY( " -hc : high compression\n");
|
||||
DISPLAY( " -y : overwrite output without prompting \n");
|
||||
DISPLAY( " -s : suppress warnings \n");
|
||||
#endif /* ENABLE_LZ4C_LEGACY_OPTIONS */
|
||||
EXTENDED_HELP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usage_longhelp(void)
|
||||
{
|
||||
DISPLAY( "\n");
|
||||
DISPLAY( "Which values can get [output] ? \n");
|
||||
DISPLAY( "[output] : a filename\n");
|
||||
DISPLAY( " '%s', or '-' for standard output (pipe mode)\n", stdoutmark);
|
||||
DISPLAY( " '%s' to discard output (test mode)\n", NULL_OUTPUT);
|
||||
DISPLAY( "[output] can be left empty. In this case, it receives the following value : \n");
|
||||
DISPLAY( " - if stdout is not the console, then [output] = stdout \n");
|
||||
DISPLAY( " - if stdout is console : \n");
|
||||
DISPLAY( " + if compression selected, output to filename%s \n", LZ4_EXTENSION);
|
||||
DISPLAY( " + if decompression selected, output to filename without '%s'\n", LZ4_EXTENSION);
|
||||
DISPLAY( " > if input filename has no '%s' extension : error\n", LZ4_EXTENSION);
|
||||
DISPLAY( "\n");
|
||||
DISPLAY( "Compression levels : \n");
|
||||
DISPLAY( "There are technically 2 accessible compression levels.\n");
|
||||
DISPLAY( "-0 ... -2 => Fast compression\n");
|
||||
DISPLAY( "-3 ... -9 => High compression\n");
|
||||
DISPLAY( "\n");
|
||||
DISPLAY( "stdin, stdout and the console : \n");
|
||||
DISPLAY( "To protect the console from binary flooding (bad argument mistake)\n");
|
||||
DISPLAY( "%s will refuse to read from console, or write to console \n", programName);
|
||||
DISPLAY( "except if '-c' command is specified, to force output to console \n");
|
||||
DISPLAY( "\n");
|
||||
DISPLAY( "Simple example :\n");
|
||||
DISPLAY( "1 : compress 'filename' fast, using default output name 'filename.lz4'\n");
|
||||
DISPLAY( " %s filename\n", programName);
|
||||
DISPLAY( "\n");
|
||||
DISPLAY( "Arguments can be appended together, or provided independently. For example :\n");
|
||||
DISPLAY( "2 : compress 'filename' in high compression mode, overwrite output if exists\n");
|
||||
DISPLAY( " %s -f9 filename \n", programName);
|
||||
DISPLAY( " is equivalent to :\n");
|
||||
DISPLAY( " %s -f -9 filename \n", programName);
|
||||
DISPLAY( "\n");
|
||||
DISPLAY( "%s can be used in 'pure pipe mode', for example :\n", programName);
|
||||
DISPLAY( "3 : compress data stream from 'generator', send result to 'consumer'\n");
|
||||
DISPLAY( " generator | %s | consumer \n", programName);
|
||||
#if defined(ENABLE_LZ4C_LEGACY_OPTIONS)
|
||||
DISPLAY( "\n");
|
||||
DISPLAY( "Warning :\n");
|
||||
DISPLAY( "Legacy arguments take precedence. Therefore : \n");
|
||||
DISPLAY( " %s -hc filename\n", programName);
|
||||
DISPLAY( "means 'compress filename in high compression mode'\n");
|
||||
DISPLAY( "It is not equivalent to :\n");
|
||||
DISPLAY( " %s -h -c filename\n", programName);
|
||||
DISPLAY( "which would display help text and exit\n");
|
||||
#endif /* ENABLE_LZ4C_LEGACY_OPTIONS */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int badusage(void)
|
||||
{
|
||||
DISPLAYLEVEL(1, "Incorrect parameters\n");
|
||||
if (displayLevel >= 1) usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
static void waitEnter(void)
|
||||
{
|
||||
DISPLAY("Press enter to continue...\n");
|
||||
getchar();
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int i,
|
||||
cLevel=0,
|
||||
decode=0,
|
||||
bench=0,
|
||||
filenamesStart=2,
|
||||
legacy_format=0,
|
||||
forceStdout=0,
|
||||
forceCompress=0,
|
||||
main_pause=0;
|
||||
char* input_filename=0;
|
||||
char* output_filename=0;
|
||||
char* dynNameSpace=0;
|
||||
char nullOutput[] = NULL_OUTPUT;
|
||||
char extension[] = LZ4_EXTENSION;
|
||||
int blockSize;
|
||||
|
||||
/* Init */
|
||||
programName = argv[0];
|
||||
LZ4IO_setOverwrite(0);
|
||||
blockSize = LZ4IO_setBlockSizeID(LZ4_BLOCKSIZEID_DEFAULT);
|
||||
|
||||
/* lz4cat behavior */
|
||||
if (!strcmp(programName, LZ4_CAT)) { decode=1; forceStdout=1; output_filename=stdoutmark; displayLevel=1; }
|
||||
|
||||
/* command switches */
|
||||
for(i=1; i<argc; i++)
|
||||
{
|
||||
char* argument = argv[i];
|
||||
|
||||
if(!argument) continue; /* Protection if argument empty */
|
||||
|
||||
/* Decode command (note : aggregated commands are allowed) */
|
||||
if (argument[0]=='-')
|
||||
{
|
||||
/* '-' means stdin/stdout */
|
||||
if (argument[1]==0)
|
||||
{
|
||||
if (!input_filename) input_filename=stdinmark;
|
||||
else output_filename=stdoutmark;
|
||||
}
|
||||
|
||||
while (argument[1]!=0)
|
||||
{
|
||||
argument ++;
|
||||
|
||||
#if defined(ENABLE_LZ4C_LEGACY_OPTIONS)
|
||||
/* Legacy arguments (-c0, -c1, -hc, -y, -s) */
|
||||
if ((argument[0]=='c') && (argument[1]=='0')) { cLevel=0; argument++; continue; } /* -c0 (fast compression) */
|
||||
if ((argument[0]=='c') && (argument[1]=='1')) { cLevel=9; argument++; continue; } /* -c1 (high compression) */
|
||||
if ((argument[0]=='h') && (argument[1]=='c')) { cLevel=9; argument++; continue; } /* -hc (high compression) */
|
||||
if (*argument=='y') { LZ4IO_setOverwrite(1); continue; } /* -y (answer 'yes' to overwrite permission) */
|
||||
if (*argument=='s') { displayLevel=1; continue; } /* -s (silent mode) */
|
||||
#endif /* ENABLE_LZ4C_LEGACY_OPTIONS */
|
||||
|
||||
if ((*argument>='0') && (*argument<='9'))
|
||||
{
|
||||
cLevel = 0;
|
||||
while ((*argument >= '0') && (*argument <= '9'))
|
||||
{
|
||||
cLevel *= 10;
|
||||
cLevel += *argument - '0';
|
||||
argument++;
|
||||
}
|
||||
argument--;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(argument[0])
|
||||
{
|
||||
/* Display help */
|
||||
case 'V': DISPLAY(WELCOME_MESSAGE); return 0; /* Version */
|
||||
case 'h': usage_advanced(); return 0;
|
||||
case 'H': usage_advanced(); usage_longhelp(); return 0;
|
||||
|
||||
/* Compression (default) */
|
||||
case 'z': forceCompress = 1; break;
|
||||
|
||||
/* Use Legacy format (ex : Linux kernel compression) */
|
||||
case 'l': legacy_format = 1; blockSize = 8 MB; break;
|
||||
|
||||
/* Decoding */
|
||||
case 'd': decode=1; break;
|
||||
|
||||
/* Force stdout, even if stdout==console */
|
||||
case 'c': forceStdout=1; output_filename=stdoutmark; displayLevel=1; break;
|
||||
|
||||
/* Test integrity */
|
||||
case 't': decode=1; LZ4IO_setOverwrite(1); output_filename=nulmark; break;
|
||||
|
||||
/* Overwrite */
|
||||
case 'f': LZ4IO_setOverwrite(1); break;
|
||||
|
||||
/* Verbose mode */
|
||||
case 'v': displayLevel=4; break;
|
||||
|
||||
/* Quiet mode */
|
||||
case 'q': displayLevel--; break;
|
||||
|
||||
/* keep source file (default anyway, so useless) (for xz/lzma compatibility) */
|
||||
case 'k': break;
|
||||
|
||||
/* Modify Block Properties */
|
||||
case 'B':
|
||||
while (argument[1]!=0)
|
||||
{
|
||||
int exitBlockProperties=0;
|
||||
switch(argument[1])
|
||||
{
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
{
|
||||
int B = argument[1] - '0';
|
||||
blockSize = LZ4IO_setBlockSizeID(B);
|
||||
BMK_SetBlocksize(blockSize);
|
||||
argument++;
|
||||
break;
|
||||
}
|
||||
case 'D': LZ4IO_setBlockMode(LZ4IO_blockLinked); argument++; break;
|
||||
case 'X': LZ4IO_setBlockChecksumMode(1); argument ++; break; /* currently disables */
|
||||
default : exitBlockProperties=1;
|
||||
}
|
||||
if (exitBlockProperties) break;
|
||||
}
|
||||
break;
|
||||
|
||||
/* Modify Stream properties */
|
||||
case 'S': if (argument[1]=='x') { LZ4IO_setStreamChecksumMode(0); argument++; break; } else { badusage(); }
|
||||
|
||||
/* Benchmark */
|
||||
case 'b': bench=1; break;
|
||||
|
||||
/* Modify Nb Iterations (benchmark only) */
|
||||
case 'i':
|
||||
if ((argument[1] >='1') && (argument[1] <='9'))
|
||||
{
|
||||
int iters = argument[1] - '0';
|
||||
BMK_SetNbIterations(iters);
|
||||
argument++;
|
||||
}
|
||||
break;
|
||||
|
||||
/* Pause at the end (hidden option) */
|
||||
case 'p': main_pause=1; BMK_SetPause(); break;
|
||||
|
||||
/* Specific commands for customized versions */
|
||||
EXTENDED_ARGUMENTS;
|
||||
|
||||
/* Unrecognised command */
|
||||
default : badusage();
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* first provided filename is input */
|
||||
if (!input_filename) { input_filename=argument; filenamesStart=i; continue; }
|
||||
|
||||
/* second provided filename is output */
|
||||
if (!output_filename)
|
||||
{
|
||||
output_filename=argument;
|
||||
if (!strcmp (output_filename, nullOutput)) output_filename = nulmark;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
DISPLAYLEVEL(3, WELCOME_MESSAGE);
|
||||
if (!decode) DISPLAYLEVEL(4, "Blocks size : %i KB\n", blockSize>>10);
|
||||
|
||||
/* No input filename ==> use stdin */
|
||||
if(!input_filename) { input_filename=stdinmark; }
|
||||
|
||||
/* Check if input or output are defined as console; trigger an error in this case */
|
||||
if (!strcmp(input_filename, stdinmark) && IS_CONSOLE(stdin) ) badusage();
|
||||
|
||||
/* Check if benchmark is selected */
|
||||
if (bench) return BMK_benchFile(argv+filenamesStart, argc-filenamesStart, cLevel);
|
||||
|
||||
/* No output filename ==> try to select one automatically (when possible) */
|
||||
while (!output_filename)
|
||||
{
|
||||
if (!IS_CONSOLE(stdout)) { output_filename=stdoutmark; break; } /* Default to stdout whenever possible (i.e. not a console) */
|
||||
if ((!decode) && !(forceCompress)) /* auto-determine compression or decompression, based on file extension */
|
||||
{
|
||||
size_t l = strlen(input_filename);
|
||||
if (!strcmp(input_filename+(l-4), LZ4_EXTENSION)) decode=1;
|
||||
}
|
||||
if (!decode) /* compression to file */
|
||||
{
|
||||
size_t l = strlen(input_filename);
|
||||
dynNameSpace = (char*)calloc(1,l+5);
|
||||
output_filename = dynNameSpace;
|
||||
strcpy(output_filename, input_filename);
|
||||
strcpy(output_filename+l, LZ4_EXTENSION);
|
||||
DISPLAYLEVEL(2, "Compressed filename will be : %s \n", output_filename);
|
||||
break;
|
||||
}
|
||||
/* decompression to file (automatic name will work only if input filename has correct format extension) */
|
||||
{
|
||||
size_t outl;
|
||||
size_t inl = strlen(input_filename);
|
||||
dynNameSpace = (char*)calloc(1,inl+1);
|
||||
output_filename = dynNameSpace;
|
||||
strcpy(output_filename, input_filename);
|
||||
outl = inl;
|
||||
if (inl>4)
|
||||
while ((outl >= inl-4) && (input_filename[outl] == extension[outl-inl+4])) output_filename[outl--]=0;
|
||||
if (outl != inl-5) { DISPLAYLEVEL(1, "Cannot determine an output filename\n"); badusage(); }
|
||||
DISPLAYLEVEL(2, "Decoding file %s \n", output_filename);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if output is defined as console; trigger an error in this case */
|
||||
if (!strcmp(output_filename,stdoutmark) && IS_CONSOLE(stdout) && !forceStdout) badusage();
|
||||
|
||||
/* No warning message in pure pipe mode (stdin + stdout) */
|
||||
if (!strcmp(input_filename, stdinmark) && !strcmp(output_filename,stdoutmark) && (displayLevel==2)) displayLevel=1;
|
||||
|
||||
|
||||
/* IO Stream/File */
|
||||
LZ4IO_setNotificationLevel(displayLevel);
|
||||
if (decode) DEFAULT_DECOMPRESSOR(input_filename, output_filename);
|
||||
else
|
||||
{
|
||||
/* compression is default action */
|
||||
if (legacy_format)
|
||||
{
|
||||
DISPLAYLEVEL(3, "! Generating compressed LZ4 using Legacy format (deprecated) ! \n");
|
||||
LZ4IO_compressFilename_Legacy(input_filename, output_filename, cLevel);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEFAULT_COMPRESSOR(input_filename, output_filename, cLevel);
|
||||
}
|
||||
}
|
||||
|
||||
if (main_pause) waitEnter();
|
||||
free(dynNameSpace);
|
||||
return 0;
|
||||
}
|
||||
669
src/lz4/programs/lz4io.c
Normal file
@@ -0,0 +1,669 @@
|
||||
/*
|
||||
LZ4io.c - LZ4 File/Stream Interface
|
||||
Copyright (C) Yann Collet 2011-2014
|
||||
GPL v2 License
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
/*
|
||||
Note : this is stand-alone program.
|
||||
It is not part of LZ4 compression library, it is a user code of the LZ4 library.
|
||||
- The license of LZ4 library is BSD.
|
||||
- The license of xxHash library is BSD.
|
||||
- The license of this source file is GPLv2.
|
||||
*/
|
||||
|
||||
/**************************************
|
||||
* Compiler Options
|
||||
***************************************/
|
||||
#ifdef _MSC_VER /* Visual Studio */
|
||||
# define _CRT_SECURE_NO_WARNINGS
|
||||
# define _CRT_SECURE_NO_DEPRECATE /* VS2005 */
|
||||
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
|
||||
#endif
|
||||
|
||||
#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC diagnostic ignored "-Wmissing-braces" /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */
|
||||
# pragma GCC diagnostic ignored "-Wmissing-field-initializers" /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */
|
||||
#endif
|
||||
|
||||
#define _LARGE_FILES /* Large file support on 32-bits AIX */
|
||||
#define _FILE_OFFSET_BITS 64 /* Large file support on 32-bits unix */
|
||||
#define _POSIX_SOURCE 1 /* for fileno() within <stdio.h> on unix */
|
||||
|
||||
|
||||
/****************************
|
||||
* Includes
|
||||
*****************************/
|
||||
#include <stdio.h> /* fprintf, fopen, fread, _fileno, stdin, stdout */
|
||||
#include <stdlib.h> /* malloc, free */
|
||||
#include <string.h> /* strcmp, strlen */
|
||||
#include <time.h> /* clock */
|
||||
#include "lz4io.h"
|
||||
#include "lz4.h" /* still required for legacy format */
|
||||
#include "lz4hc.h" /* still required for legacy format */
|
||||
#include "lz4frame.h"
|
||||
|
||||
|
||||
/****************************
|
||||
* OS-specific Includes
|
||||
*****************************/
|
||||
#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__)
|
||||
# include <fcntl.h> /* _O_BINARY */
|
||||
# include <io.h> /* _setmode, _isatty */
|
||||
# ifdef __MINGW32__
|
||||
int _fileno(FILE *stream); /* MINGW somehow forgets to include this windows declaration into <stdio.h> */
|
||||
# endif
|
||||
# define SET_BINARY_MODE(file) _setmode(_fileno(file), _O_BINARY)
|
||||
# define IS_CONSOLE(stdStream) _isatty(_fileno(stdStream))
|
||||
#else
|
||||
# include <unistd.h> /* isatty */
|
||||
# define SET_BINARY_MODE(file)
|
||||
# define IS_CONSOLE(stdStream) isatty(fileno(stdStream))
|
||||
#endif
|
||||
|
||||
|
||||
/****************************
|
||||
* Constants
|
||||
*****************************/
|
||||
#define KB *(1 <<10)
|
||||
#define MB *(1 <<20)
|
||||
#define GB *(1U<<30)
|
||||
|
||||
#define _1BIT 0x01
|
||||
#define _2BITS 0x03
|
||||
#define _3BITS 0x07
|
||||
#define _4BITS 0x0F
|
||||
#define _8BITS 0xFF
|
||||
|
||||
#define MAGICNUMBER_SIZE 4
|
||||
#define LZ4S_MAGICNUMBER 0x184D2204
|
||||
#define LZ4S_SKIPPABLE0 0x184D2A50
|
||||
#define LZ4S_SKIPPABLEMASK 0xFFFFFFF0
|
||||
#define LEGACY_MAGICNUMBER 0x184C2102
|
||||
|
||||
#define CACHELINE 64
|
||||
#define LEGACY_BLOCKSIZE (8 MB)
|
||||
#define MIN_STREAM_BUFSIZE (192 KB)
|
||||
#define LZ4S_BLOCKSIZEID_DEFAULT 7
|
||||
#define LZ4S_CHECKSUM_SEED 0
|
||||
#define LZ4S_EOS 0
|
||||
#define LZ4S_MAXHEADERSIZE (MAGICNUMBER_SIZE+2+8+4+1)
|
||||
|
||||
|
||||
/**************************************
|
||||
* Macros
|
||||
***************************************/
|
||||
#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
|
||||
#define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
|
||||
#define DISPLAYUPDATE(l, ...) if (displayLevel>=l) { \
|
||||
if ((LZ4IO_GetMilliSpan(g_time) > refreshRate) || (displayLevel>=4)) \
|
||||
{ g_time = clock(); DISPLAY(__VA_ARGS__); \
|
||||
if (displayLevel>=4) fflush(stdout); } }
|
||||
static const unsigned refreshRate = 150;
|
||||
static clock_t g_time = 0;
|
||||
|
||||
|
||||
/**************************************
|
||||
* Local Parameters
|
||||
***************************************/
|
||||
static int displayLevel = 0; /* 0 : no display ; 1: errors ; 2 : + result + interaction + warnings ; 3 : + progression; 4 : + information */
|
||||
static int overwrite = 1;
|
||||
static int globalBlockSizeId = LZ4S_BLOCKSIZEID_DEFAULT;
|
||||
static int blockChecksum = 0;
|
||||
static int streamChecksum = 1;
|
||||
static int blockIndependence = 1;
|
||||
|
||||
static const int minBlockSizeID = 4;
|
||||
static const int maxBlockSizeID = 7;
|
||||
|
||||
|
||||
/**************************************
|
||||
* Exceptions
|
||||
***************************************/
|
||||
#define DEBUG 0
|
||||
#define DEBUGOUTPUT(...) if (DEBUG) DISPLAY(__VA_ARGS__);
|
||||
#define EXM_THROW(error, ...) \
|
||||
{ \
|
||||
DEBUGOUTPUT("Error defined at %s, line %i : \n", __FILE__, __LINE__); \
|
||||
DISPLAYLEVEL(1, "Error %i : ", error); \
|
||||
DISPLAYLEVEL(1, __VA_ARGS__); \
|
||||
DISPLAYLEVEL(1, "\n"); \
|
||||
exit(error); \
|
||||
}
|
||||
|
||||
|
||||
/**************************************
|
||||
* Version modifiers
|
||||
***************************************/
|
||||
#define EXTENDED_ARGUMENTS
|
||||
#define EXTENDED_HELP
|
||||
#define EXTENDED_FORMAT
|
||||
#define DEFAULT_COMPRESSOR compress_file
|
||||
#define DEFAULT_DECOMPRESSOR decodeLZ4S
|
||||
|
||||
|
||||
/* ************************************************** */
|
||||
/* ****************** Parameters ******************** */
|
||||
/* ************************************************** */
|
||||
|
||||
/* Default setting : overwrite = 1; return : overwrite mode (0/1) */
|
||||
int LZ4IO_setOverwrite(int yes)
|
||||
{
|
||||
overwrite = (yes!=0);
|
||||
return overwrite;
|
||||
}
|
||||
|
||||
/* blockSizeID : valid values : 4-5-6-7 */
|
||||
int LZ4IO_setBlockSizeID(int bsid)
|
||||
{
|
||||
static const int blockSizeTable[] = { 64 KB, 256 KB, 1 MB, 4 MB };
|
||||
if ((bsid < minBlockSizeID) || (bsid > maxBlockSizeID)) return -1;
|
||||
globalBlockSizeId = bsid;
|
||||
return blockSizeTable[globalBlockSizeId-minBlockSizeID];
|
||||
}
|
||||
|
||||
int LZ4IO_setBlockMode(LZ4IO_blockMode_t blockMode)
|
||||
{
|
||||
blockIndependence = (blockMode == LZ4IO_blockIndependent);
|
||||
return blockIndependence;
|
||||
}
|
||||
|
||||
/* Default setting : no checksum */
|
||||
int LZ4IO_setBlockChecksumMode(int xxhash)
|
||||
{
|
||||
blockChecksum = (xxhash != 0);
|
||||
return blockChecksum;
|
||||
}
|
||||
|
||||
/* Default setting : checksum enabled */
|
||||
int LZ4IO_setStreamChecksumMode(int xxhash)
|
||||
{
|
||||
streamChecksum = (xxhash != 0);
|
||||
return streamChecksum;
|
||||
}
|
||||
|
||||
/* Default setting : 0 (no notification) */
|
||||
int LZ4IO_setNotificationLevel(int level)
|
||||
{
|
||||
displayLevel = level;
|
||||
return displayLevel;
|
||||
}
|
||||
|
||||
static unsigned LZ4IO_GetMilliSpan(clock_t nPrevious)
|
||||
{
|
||||
clock_t nCurrent = clock();
|
||||
unsigned nSpan = (unsigned)(((nCurrent - nPrevious) * 1000) / CLOCKS_PER_SEC);
|
||||
return nSpan;
|
||||
}
|
||||
|
||||
|
||||
/* ************************************************************************ */
|
||||
/* ********************** LZ4 File / Pipe compression ********************* */
|
||||
/* ************************************************************************ */
|
||||
|
||||
static int LZ4S_GetBlockSize_FromBlockId (int id) { return (1 << (8 + (2 * id))); }
|
||||
static int LZ4S_isSkippableMagicNumber(unsigned int magic) { return (magic & LZ4S_SKIPPABLEMASK) == LZ4S_SKIPPABLE0; }
|
||||
|
||||
|
||||
static int get_fileHandle(char* input_filename, char* output_filename, FILE** pfinput, FILE** pfoutput)
|
||||
{
|
||||
|
||||
if (!strcmp (input_filename, stdinmark))
|
||||
{
|
||||
DISPLAYLEVEL(4,"Using stdin for input\n");
|
||||
*pfinput = stdin;
|
||||
SET_BINARY_MODE(stdin);
|
||||
}
|
||||
else
|
||||
{
|
||||
*pfinput = fopen(input_filename, "rb");
|
||||
}
|
||||
|
||||
if (!strcmp (output_filename, stdoutmark))
|
||||
{
|
||||
DISPLAYLEVEL(4,"Using stdout for output\n");
|
||||
*pfoutput = stdout;
|
||||
SET_BINARY_MODE(stdout);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check if destination file already exists */
|
||||
*pfoutput=0;
|
||||
if (output_filename != nulmark) *pfoutput = fopen( output_filename, "rb" );
|
||||
if (*pfoutput!=0)
|
||||
{
|
||||
fclose(*pfoutput);
|
||||
if (!overwrite)
|
||||
{
|
||||
char ch;
|
||||
DISPLAYLEVEL(2, "Warning : %s already exists\n", output_filename);
|
||||
DISPLAYLEVEL(2, "Overwrite ? (Y/N) : ");
|
||||
if (displayLevel <= 1) EXM_THROW(11, "Operation aborted : %s already exists", output_filename); /* No interaction possible */
|
||||
ch = (char)getchar();
|
||||
if ((ch!='Y') && (ch!='y')) EXM_THROW(11, "Operation aborted : %s already exists", output_filename);
|
||||
}
|
||||
}
|
||||
*pfoutput = fopen( output_filename, "wb" );
|
||||
}
|
||||
|
||||
if ( *pfinput==0 ) EXM_THROW(12, "Pb opening %s", input_filename);
|
||||
if ( *pfoutput==0) EXM_THROW(13, "Pb opening %s", output_filename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/***************************************
|
||||
* Legacy Compression
|
||||
* *************************************/
|
||||
|
||||
/* unoptimized version; solves endianess & alignment issues */
|
||||
static void LZ4IO_writeLE32 (void* p, unsigned value32)
|
||||
{
|
||||
unsigned char* dstPtr = p;
|
||||
dstPtr[0] = (unsigned char)value32;
|
||||
dstPtr[1] = (unsigned char)(value32 >> 8);
|
||||
dstPtr[2] = (unsigned char)(value32 >> 16);
|
||||
dstPtr[3] = (unsigned char)(value32 >> 24);
|
||||
}
|
||||
|
||||
/* LZ4IO_compressFilename_Legacy :
|
||||
* This function is intentionally "hidden" (not published in .h)
|
||||
* It generates compressed streams using the old 'legacy' format */
|
||||
int LZ4IO_compressFilename_Legacy(char* input_filename, char* output_filename, int compressionlevel)
|
||||
{
|
||||
int (*compressionFunction)(const char*, char*, int);
|
||||
unsigned long long filesize = 0;
|
||||
unsigned long long compressedfilesize = MAGICNUMBER_SIZE;
|
||||
char* in_buff;
|
||||
char* out_buff;
|
||||
FILE* finput;
|
||||
FILE* foutput;
|
||||
clock_t start, end;
|
||||
size_t sizeCheck;
|
||||
|
||||
|
||||
/* Init */
|
||||
start = clock();
|
||||
if (compressionlevel < 3) compressionFunction = LZ4_compress; else compressionFunction = LZ4_compressHC;
|
||||
|
||||
get_fileHandle(input_filename, output_filename, &finput, &foutput);
|
||||
if ((displayLevel==2) && (compressionlevel==1)) displayLevel=3;
|
||||
|
||||
/* Allocate Memory */
|
||||
in_buff = (char*)malloc(LEGACY_BLOCKSIZE);
|
||||
out_buff = (char*)malloc(LZ4_compressBound(LEGACY_BLOCKSIZE));
|
||||
if (!in_buff || !out_buff) EXM_THROW(21, "Allocation error : not enough memory");
|
||||
|
||||
/* Write Archive Header */
|
||||
LZ4IO_writeLE32(out_buff, LEGACY_MAGICNUMBER);
|
||||
sizeCheck = fwrite(out_buff, 1, MAGICNUMBER_SIZE, foutput);
|
||||
if (sizeCheck!=MAGICNUMBER_SIZE) EXM_THROW(22, "Write error : cannot write header");
|
||||
|
||||
/* Main Loop */
|
||||
while (1)
|
||||
{
|
||||
unsigned int outSize;
|
||||
/* Read Block */
|
||||
int inSize = (int) fread(in_buff, (size_t)1, (size_t)LEGACY_BLOCKSIZE, finput);
|
||||
if( inSize<=0 ) break;
|
||||
filesize += inSize;
|
||||
|
||||
/* Compress Block */
|
||||
outSize = compressionFunction(in_buff, out_buff+4, inSize);
|
||||
compressedfilesize += outSize+4;
|
||||
DISPLAYUPDATE(3, "\rRead : %i MB ==> %.2f%% ", (int)(filesize>>20), (double)compressedfilesize/filesize*100);
|
||||
|
||||
/* Write Block */
|
||||
LZ4IO_writeLE32(out_buff, outSize);
|
||||
sizeCheck = fwrite(out_buff, 1, outSize+4, foutput);
|
||||
if (sizeCheck!=(size_t)(outSize+4)) EXM_THROW(23, "Write error : cannot write compressed block");
|
||||
}
|
||||
|
||||
/* Status */
|
||||
end = clock();
|
||||
DISPLAYLEVEL(2, "\r%79s\r", "");
|
||||
DISPLAYLEVEL(2,"Compressed %llu bytes into %llu bytes ==> %.2f%%\n",
|
||||
(unsigned long long) filesize, (unsigned long long) compressedfilesize, (double)compressedfilesize/filesize*100);
|
||||
{
|
||||
double seconds = (double)(end - start)/CLOCKS_PER_SEC;
|
||||
DISPLAYLEVEL(4,"Done in %.2f s ==> %.2f MB/s\n", seconds, (double)filesize / seconds / 1024 / 1024);
|
||||
}
|
||||
|
||||
/* Close & Free */
|
||||
free(in_buff);
|
||||
free(out_buff);
|
||||
fclose(finput);
|
||||
fclose(foutput);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************
|
||||
* Compression using Frame format
|
||||
* ********************************************/
|
||||
|
||||
int LZ4IO_compressFilename(char* input_filename, char* output_filename, int compressionLevel)
|
||||
{
|
||||
unsigned long long filesize = 0;
|
||||
unsigned long long compressedfilesize = 0;
|
||||
char* in_buff;
|
||||
char* out_buff;
|
||||
FILE* finput;
|
||||
FILE* foutput;
|
||||
clock_t start, end;
|
||||
int blockSize;
|
||||
size_t sizeCheck, headerSize, readSize, outBuffSize;
|
||||
LZ4F_compressionContext_t ctx;
|
||||
LZ4F_errorCode_t errorCode;
|
||||
LZ4F_preferences_t prefs = {0};
|
||||
|
||||
|
||||
/* Init */
|
||||
start = clock();
|
||||
if ((displayLevel==2) && (compressionLevel>=3)) displayLevel=3;
|
||||
errorCode = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION);
|
||||
if (LZ4F_isError(errorCode)) EXM_THROW(30, "Allocation error : can't create LZ4F context : %s", LZ4F_getErrorName(errorCode));
|
||||
get_fileHandle(input_filename, output_filename, &finput, &foutput);
|
||||
blockSize = LZ4S_GetBlockSize_FromBlockId (globalBlockSizeId);
|
||||
|
||||
/* Set compression parameters */
|
||||
prefs.autoFlush = 1;
|
||||
prefs.compressionLevel = compressionLevel;
|
||||
prefs.frameInfo.blockMode = blockIndependence;
|
||||
prefs.frameInfo.blockSizeID = globalBlockSizeId;
|
||||
prefs.frameInfo.contentChecksumFlag = streamChecksum;
|
||||
|
||||
/* Allocate Memory */
|
||||
in_buff = (char*)malloc(blockSize);
|
||||
outBuffSize = LZ4F_compressBound(blockSize, &prefs);
|
||||
out_buff = (char*)malloc(outBuffSize);
|
||||
if (!in_buff || !out_buff) EXM_THROW(31, "Allocation error : not enough memory");
|
||||
|
||||
/* Write Archive Header */
|
||||
headerSize = LZ4F_compressBegin(ctx, out_buff, outBuffSize, &prefs);
|
||||
if (LZ4F_isError(headerSize)) EXM_THROW(32, "File header generation failed : %s", LZ4F_getErrorName(headerSize));
|
||||
sizeCheck = fwrite(out_buff, 1, headerSize, foutput);
|
||||
if (sizeCheck!=headerSize) EXM_THROW(33, "Write error : cannot write header");
|
||||
compressedfilesize += headerSize;
|
||||
|
||||
/* read first block */
|
||||
readSize = fread(in_buff, (size_t)1, (size_t)blockSize, finput);
|
||||
filesize += readSize;
|
||||
|
||||
/* Main Loop */
|
||||
while (readSize>0)
|
||||
{
|
||||
size_t outSize;
|
||||
|
||||
/* Compress Block */
|
||||
outSize = LZ4F_compressUpdate(ctx, out_buff, outBuffSize, in_buff, readSize, NULL);
|
||||
if (LZ4F_isError(outSize)) EXM_THROW(34, "Compression failed : %s", LZ4F_getErrorName(outSize));
|
||||
compressedfilesize += outSize;
|
||||
DISPLAYUPDATE(3, "\rRead : %i MB ==> %.2f%% ", (int)(filesize>>20), (double)compressedfilesize/filesize*100);
|
||||
|
||||
/* Write Block */
|
||||
sizeCheck = fwrite(out_buff, 1, outSize, foutput);
|
||||
if (sizeCheck!=outSize) EXM_THROW(35, "Write error : cannot write compressed block");
|
||||
|
||||
/* Read next block */
|
||||
readSize = fread(in_buff, (size_t)1, (size_t)blockSize, finput);
|
||||
filesize += readSize;
|
||||
}
|
||||
|
||||
/* End of Stream mark */
|
||||
headerSize = LZ4F_compressEnd(ctx, out_buff, outBuffSize, NULL);
|
||||
if (LZ4F_isError(headerSize)) EXM_THROW(36, "End of file generation failed : %s", LZ4F_getErrorName(headerSize));
|
||||
|
||||
sizeCheck = fwrite(out_buff, 1, headerSize, foutput);
|
||||
if (sizeCheck!=headerSize) EXM_THROW(37, "Write error : cannot write end of stream");
|
||||
compressedfilesize += headerSize;
|
||||
|
||||
/* Close & Free */
|
||||
free(in_buff);
|
||||
free(out_buff);
|
||||
fclose(finput);
|
||||
fclose(foutput);
|
||||
errorCode = LZ4F_freeCompressionContext(ctx);
|
||||
if (LZ4F_isError(errorCode)) EXM_THROW(38, "Error : can't free LZ4F context resource : %s", LZ4F_getErrorName(errorCode));
|
||||
|
||||
/* Final Status */
|
||||
end = clock();
|
||||
DISPLAYLEVEL(2, "\r%79s\r", "");
|
||||
DISPLAYLEVEL(2, "Compressed %llu bytes into %llu bytes ==> %.2f%%\n",
|
||||
(unsigned long long) filesize, (unsigned long long) compressedfilesize, (double)compressedfilesize/filesize*100);
|
||||
{
|
||||
double seconds = (double)(end - start)/CLOCKS_PER_SEC;
|
||||
DISPLAYLEVEL(4, "Done in %.2f s ==> %.2f MB/s\n", seconds, (double)filesize / seconds / 1024 / 1024);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* ********************************************************************* */
|
||||
/* ********************** LZ4 File / Stream decoding ******************* */
|
||||
/* ********************************************************************* */
|
||||
|
||||
static unsigned LZ4IO_readLE32 (const void* s)
|
||||
{
|
||||
const unsigned char* srcPtr = s;
|
||||
unsigned value32 = srcPtr[0];
|
||||
value32 += (srcPtr[1]<<8);
|
||||
value32 += (srcPtr[2]<<16);
|
||||
value32 += (srcPtr[3]<<24);
|
||||
return value32;
|
||||
}
|
||||
|
||||
static unsigned long long decodeLegacyStream(FILE* finput, FILE* foutput)
|
||||
{
|
||||
unsigned long long filesize = 0;
|
||||
char* in_buff;
|
||||
char* out_buff;
|
||||
|
||||
/* Allocate Memory */
|
||||
in_buff = (char*)malloc(LZ4_compressBound(LEGACY_BLOCKSIZE));
|
||||
out_buff = (char*)malloc(LEGACY_BLOCKSIZE);
|
||||
if (!in_buff || !out_buff) EXM_THROW(51, "Allocation error : not enough memory");
|
||||
|
||||
/* Main Loop */
|
||||
while (1)
|
||||
{
|
||||
int decodeSize;
|
||||
size_t sizeCheck;
|
||||
unsigned int blockSize;
|
||||
|
||||
/* Block Size */
|
||||
sizeCheck = fread(in_buff, 1, 4, finput);
|
||||
if (sizeCheck==0) break; /* Nothing to read : file read is completed */
|
||||
blockSize = LZ4IO_readLE32(in_buff); /* Convert to Little Endian */
|
||||
if (blockSize > LZ4_COMPRESSBOUND(LEGACY_BLOCKSIZE))
|
||||
{ /* Cannot read next block : maybe new stream ? */
|
||||
fseek(finput, -4, SEEK_CUR);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read Block */
|
||||
sizeCheck = fread(in_buff, 1, blockSize, finput);
|
||||
|
||||
/* Decode Block */
|
||||
decodeSize = LZ4_decompress_safe(in_buff, out_buff, blockSize, LEGACY_BLOCKSIZE);
|
||||
if (decodeSize < 0) EXM_THROW(52, "Decoding Failed ! Corrupted input detected !");
|
||||
filesize += decodeSize;
|
||||
|
||||
/* Write Block */
|
||||
sizeCheck = fwrite(out_buff, 1, decodeSize, foutput);
|
||||
if (sizeCheck != (size_t)decodeSize) EXM_THROW(53, "Write error : cannot write decoded block into output\n");
|
||||
}
|
||||
|
||||
/* Free */
|
||||
free(in_buff);
|
||||
free(out_buff);
|
||||
|
||||
return filesize;
|
||||
}
|
||||
|
||||
|
||||
static unsigned long long decodeLZ4S(FILE* finput, FILE* foutput)
|
||||
{
|
||||
unsigned long long filesize = 0;
|
||||
char* inBuff;
|
||||
char* outBuff;
|
||||
# define HEADERMAX 20
|
||||
char headerBuff[HEADERMAX];
|
||||
size_t sizeCheck, nextToRead, outBuffSize, inBuffSize;
|
||||
LZ4F_decompressionContext_t ctx;
|
||||
LZ4F_errorCode_t errorCode;
|
||||
LZ4F_frameInfo_t frameInfo;
|
||||
|
||||
/* init */
|
||||
errorCode = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION);
|
||||
if (LZ4F_isError(errorCode)) EXM_THROW(60, "Allocation error : can't create context : %s", LZ4F_getErrorName(errorCode));
|
||||
LZ4IO_writeLE32(headerBuff, LZ4S_MAGICNUMBER); /* regenerated here, as it was already read from finput */
|
||||
|
||||
/* Decode stream descriptor */
|
||||
outBuffSize = 0; inBuffSize = 0; sizeCheck = MAGICNUMBER_SIZE;
|
||||
nextToRead = LZ4F_decompress(ctx, NULL, &outBuffSize, headerBuff, &sizeCheck, NULL);
|
||||
if (LZ4F_isError(nextToRead)) EXM_THROW(61, "Decompression error : %s", LZ4F_getErrorName(nextToRead));
|
||||
if (nextToRead > HEADERMAX) EXM_THROW(62, "Header too large (%i>%i)", (int)nextToRead, HEADERMAX);
|
||||
sizeCheck = fread(headerBuff, 1, nextToRead, finput);
|
||||
if (sizeCheck!=nextToRead) EXM_THROW(63, "Read error ");
|
||||
nextToRead = LZ4F_decompress(ctx, NULL, &outBuffSize, headerBuff, &sizeCheck, NULL);
|
||||
errorCode = LZ4F_getFrameInfo(ctx, &frameInfo, NULL, &inBuffSize);
|
||||
if (LZ4F_isError(errorCode)) EXM_THROW(64, "can't decode frame header : %s", LZ4F_getErrorName(errorCode));
|
||||
|
||||
/* Allocate Memory */
|
||||
outBuffSize = LZ4IO_setBlockSizeID(frameInfo.blockSizeID);
|
||||
inBuffSize = outBuffSize + 4;
|
||||
inBuff = (char*)malloc(inBuffSize);
|
||||
outBuff = (char*)malloc(outBuffSize);
|
||||
if (!inBuff || !outBuff) EXM_THROW(65, "Allocation error : not enough memory");
|
||||
|
||||
/* Main Loop */
|
||||
while (nextToRead != 0)
|
||||
{
|
||||
size_t decodedBytes = outBuffSize;
|
||||
|
||||
/* Read Block */
|
||||
sizeCheck = fread(inBuff, 1, nextToRead, finput);
|
||||
if (sizeCheck!=nextToRead) EXM_THROW(66, "Read error ");
|
||||
|
||||
/* Decode Block */
|
||||
errorCode = LZ4F_decompress(ctx, outBuff, &decodedBytes, inBuff, &sizeCheck, NULL);
|
||||
if (LZ4F_isError(errorCode)) EXM_THROW(67, "Decompression error : %s", LZ4F_getErrorName(errorCode));
|
||||
if (sizeCheck!=nextToRead) EXM_THROW(67, "Synchronization error");
|
||||
nextToRead = errorCode;
|
||||
filesize += decodedBytes;
|
||||
|
||||
/* Write Block */
|
||||
sizeCheck = fwrite(outBuff, 1, decodedBytes, foutput);
|
||||
if (sizeCheck != decodedBytes) EXM_THROW(68, "Write error : cannot write decoded block\n");
|
||||
}
|
||||
|
||||
/* Free */
|
||||
free(inBuff);
|
||||
free(outBuff);
|
||||
errorCode = LZ4F_freeDecompressionContext(ctx);
|
||||
if (LZ4F_isError(errorCode)) EXM_THROW(69, "Error : can't free LZ4F context resource : %s", LZ4F_getErrorName(errorCode));
|
||||
|
||||
return filesize;
|
||||
}
|
||||
|
||||
|
||||
#define ENDOFSTREAM ((unsigned long long)-1)
|
||||
static unsigned long long selectDecoder( FILE* finput, FILE* foutput)
|
||||
{
|
||||
unsigned char U32store[MAGICNUMBER_SIZE];
|
||||
unsigned magicNumber, size;
|
||||
int errorNb;
|
||||
size_t nbReadBytes;
|
||||
|
||||
/* Check Archive Header */
|
||||
nbReadBytes = fread(U32store, 1, MAGICNUMBER_SIZE, finput);
|
||||
if (nbReadBytes==0) return ENDOFSTREAM; /* EOF */
|
||||
if (nbReadBytes != MAGICNUMBER_SIZE) EXM_THROW(40, "Unrecognized header : Magic Number unreadable");
|
||||
magicNumber = LZ4IO_readLE32(U32store); /* Little Endian format */
|
||||
if (LZ4S_isSkippableMagicNumber(magicNumber)) magicNumber = LZ4S_SKIPPABLE0; /* fold skippable magic numbers */
|
||||
|
||||
switch(magicNumber)
|
||||
{
|
||||
case LZ4S_MAGICNUMBER:
|
||||
return DEFAULT_DECOMPRESSOR(finput, foutput);
|
||||
case LEGACY_MAGICNUMBER:
|
||||
DISPLAYLEVEL(4, "Detected : Legacy format \n");
|
||||
return decodeLegacyStream(finput, foutput);
|
||||
case LZ4S_SKIPPABLE0:
|
||||
DISPLAYLEVEL(4, "Skipping detected skippable area \n");
|
||||
nbReadBytes = fread(U32store, 1, 4, finput);
|
||||
if (nbReadBytes != 4) EXM_THROW(42, "Stream error : skippable size unreadable");
|
||||
size = LZ4IO_readLE32(U32store); /* Little Endian format */
|
||||
errorNb = fseek(finput, size, SEEK_CUR);
|
||||
if (errorNb != 0) EXM_THROW(43, "Stream error : cannot skip skippable area");
|
||||
return selectDecoder(finput, foutput);
|
||||
EXTENDED_FORMAT;
|
||||
default:
|
||||
if (ftell(finput) == MAGICNUMBER_SIZE) EXM_THROW(44,"Unrecognized header : file cannot be decoded"); /* Wrong magic number at the beginning of 1st stream */
|
||||
DISPLAYLEVEL(2, "Stream followed by unrecognized data\n");
|
||||
return ENDOFSTREAM;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int LZ4IO_decompressFilename(char* input_filename, char* output_filename)
|
||||
{
|
||||
unsigned long long filesize = 0, decodedSize=0;
|
||||
FILE* finput;
|
||||
FILE* foutput;
|
||||
clock_t start, end;
|
||||
|
||||
|
||||
/* Init */
|
||||
start = clock();
|
||||
get_fileHandle(input_filename, output_filename, &finput, &foutput);
|
||||
|
||||
/* Loop over multiple streams */
|
||||
do
|
||||
{
|
||||
decodedSize = selectDecoder(finput, foutput);
|
||||
if (decodedSize != ENDOFSTREAM)
|
||||
filesize += decodedSize;
|
||||
} while (decodedSize != ENDOFSTREAM);
|
||||
|
||||
/* Final Status */
|
||||
end = clock();
|
||||
DISPLAYLEVEL(2, "\r%79s\r", "");
|
||||
DISPLAYLEVEL(2, "Successfully decoded %llu bytes \n", filesize);
|
||||
{
|
||||
double seconds = (double)(end - start)/CLOCKS_PER_SEC;
|
||||
DISPLAYLEVEL(4, "Done in %.2f s ==> %.2f MB/s\n", seconds, (double)filesize / seconds / 1024 / 1024);
|
||||
}
|
||||
|
||||
/* Close */
|
||||
fclose(finput);
|
||||
fclose(foutput);
|
||||
|
||||
/* Error status = OK */
|
||||
return 0;
|
||||
}
|
||||
|
||||
77
src/lz4/programs/lz4io.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
LZ4io.h - LZ4 File/Stream Interface
|
||||
Copyright (C) Yann Collet 2011-2014
|
||||
GPL v2 License
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
/*
|
||||
Note : this is stand-alone program.
|
||||
It is not part of LZ4 compression library, it is a user code of the LZ4 library.
|
||||
- The license of LZ4 library is BSD.
|
||||
- The license of xxHash library is BSD.
|
||||
- The license of this source file is GPLv2.
|
||||
*/
|
||||
|
||||
|
||||
/* ************************************************** */
|
||||
/* Special input/output values */
|
||||
/* ************************************************** */
|
||||
#define NULL_OUTPUT "null"
|
||||
static char stdinmark[] = "stdin";
|
||||
static char stdoutmark[] = "stdout";
|
||||
#ifdef _WIN32
|
||||
static char nulmark[] = "nul";
|
||||
#else
|
||||
static char nulmark[] = "/dev/null";
|
||||
#endif
|
||||
|
||||
|
||||
/* ************************************************** */
|
||||
/* ****************** Functions ********************* */
|
||||
/* ************************************************** */
|
||||
|
||||
int LZ4IO_compressFilename (char* input_filename, char* output_filename, int compressionlevel);
|
||||
int LZ4IO_decompressFilename(char* input_filename, char* output_filename);
|
||||
|
||||
|
||||
/* ************************************************** */
|
||||
/* ****************** Parameters ******************** */
|
||||
/* ************************************************** */
|
||||
|
||||
/* Default setting : overwrite = 1;
|
||||
return : overwrite mode (0/1) */
|
||||
int LZ4IO_setOverwrite(int yes);
|
||||
|
||||
/* blockSizeID : valid values : 4-5-6-7
|
||||
return : -1 if error, blockSize if OK */
|
||||
int LZ4IO_setBlockSizeID(int blockSizeID);
|
||||
|
||||
/* Default setting : independent blocks */
|
||||
typedef enum { LZ4IO_blockLinked=0, LZ4IO_blockIndependent} LZ4IO_blockMode_t;
|
||||
int LZ4IO_setBlockMode(LZ4IO_blockMode_t blockMode);
|
||||
|
||||
/* Default setting : no checksum */
|
||||
int LZ4IO_setBlockChecksumMode(int xxhash);
|
||||
|
||||
/* Default setting : checksum enabled */
|
||||
int LZ4IO_setStreamChecksumMode(int xxhash);
|
||||
|
||||
/* Default setting : 0 (no notification) */
|
||||
int LZ4IO_setNotificationLevel(int level);
|
||||
@@ -44,6 +44,7 @@ private:
|
||||
uint256 m_dir;
|
||||
uint256 m_index;
|
||||
SLE::pointer m_entry;
|
||||
Quality m_quality;
|
||||
|
||||
LedgerView&
|
||||
view() const noexcept
|
||||
@@ -67,10 +68,10 @@ public:
|
||||
return m_index;
|
||||
}
|
||||
|
||||
Quality const
|
||||
Quality const&
|
||||
quality() const noexcept
|
||||
{
|
||||
return Quality (getQuality (m_dir));
|
||||
return m_quality;
|
||||
}
|
||||
|
||||
SLE::pointer const&
|
||||
|
||||
@@ -28,6 +28,7 @@ BookTip::BookTip (LedgerView& view, BookRef book)
|
||||
, m_valid (false)
|
||||
, m_book (getBookBase (book))
|
||||
, m_end (getQualityNext (m_book))
|
||||
, m_quality ()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -46,31 +47,33 @@ BookTip::step ()
|
||||
for(;;)
|
||||
{
|
||||
// See if there's an entry at or worse than current quality.
|
||||
auto const page (
|
||||
view().getNextLedgerIndex (m_book, m_end));
|
||||
auto const first_page (view().getNextLedgerIndex (m_book, m_end));
|
||||
|
||||
if (page.isZero())
|
||||
if (first_page.isZero())
|
||||
return false;
|
||||
|
||||
unsigned int di (0);
|
||||
SLE::pointer dir;
|
||||
if (view().dirFirst (page, dir, di, m_index))
|
||||
|
||||
if (view().dirFirst (first_page, dir, di, m_index))
|
||||
{
|
||||
m_dir = dir->getIndex();
|
||||
m_entry = view().entryCache (ltOFFER, m_index);
|
||||
m_quality = Quality (getQuality (first_page));
|
||||
m_valid = true;
|
||||
|
||||
// Next query should start before this directory
|
||||
m_book = page;
|
||||
m_book = first_page;
|
||||
|
||||
// The quality immediately before the next quality
|
||||
--m_book;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// There should never be an empty directory but just in case,
|
||||
// we handle that case by advancing to the next directory.
|
||||
m_book = page;
|
||||
m_book = first_page;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -27,8 +27,7 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
AccountStateSF::AccountStateSF (std::uint32_t ledgerSeq)
|
||||
: mLedgerSeq (ledgerSeq)
|
||||
AccountStateSF::AccountStateSF()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -41,7 +40,8 @@ void AccountStateSF::gotNode (bool fromFilter,
|
||||
// VFALCO SHAMapSync filters should be passed the SHAMap, the
|
||||
// SHAMap should provide an accessor to get the injected Database,
|
||||
// and this should use that Database instad of getNodeStore
|
||||
getApp().getNodeStore ().store (hotACCOUNT_NODE, mLedgerSeq, std::move (nodeData), nodeHash);
|
||||
getApp().getNodeStore ().store (
|
||||
hotACCOUNT_NODE, std::move (nodeData), nodeHash);
|
||||
}
|
||||
|
||||
bool AccountStateSF::haveNode (SHAMapNodeID const& id,
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace ripple {
|
||||
class AccountStateSF : public SHAMapSyncFilter
|
||||
{
|
||||
public:
|
||||
explicit AccountStateSF (std::uint32_t ledgerSeq);
|
||||
AccountStateSF();
|
||||
|
||||
// Note that the nodeData is overwritten by this call
|
||||
void gotNode (bool fromFilter,
|
||||
@@ -41,9 +41,6 @@ public:
|
||||
bool haveNode (SHAMapNodeID const& id,
|
||||
uint256 const& nodeHash,
|
||||
Blob& nodeData);
|
||||
|
||||
private:
|
||||
std::uint32_t mLedgerSeq;
|
||||
};
|
||||
|
||||
} // ripple
|
||||
|
||||
@@ -142,8 +142,8 @@ bool InboundLedger::tryLocal ()
|
||||
if (m_journal.trace) m_journal.trace <<
|
||||
"Ledger header found in fetch pack";
|
||||
mLedger = std::make_shared<Ledger> (data, true);
|
||||
getApp().getNodeStore ().store (hotLEDGER,
|
||||
mLedger->getLedgerSeq (), std::move (data), mHash);
|
||||
getApp().getNodeStore ().store (
|
||||
hotLEDGER, std::move (data), mHash);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -173,7 +173,7 @@ bool InboundLedger::tryLocal ()
|
||||
}
|
||||
else
|
||||
{
|
||||
TransactionStateSF filter (mLedger->getLedgerSeq ());
|
||||
TransactionStateSF filter;
|
||||
|
||||
if (mLedger->peekTransactionMap ()->fetchRoot (
|
||||
mLedger->getTransHash (), &filter))
|
||||
@@ -201,7 +201,7 @@ bool InboundLedger::tryLocal ()
|
||||
}
|
||||
else
|
||||
{
|
||||
AccountStateSF filter (mLedger->getLedgerSeq ());
|
||||
AccountStateSF filter;
|
||||
|
||||
if (mLedger->peekAccountStateMap ()->fetchRoot (
|
||||
mLedger->getAccountHash (), &filter))
|
||||
@@ -571,7 +571,7 @@ void InboundLedger::trigger (Peer::ptr const& peer)
|
||||
// VFALCO Why 256? Make this a constant
|
||||
nodeIDs.reserve (256);
|
||||
nodeHashes.reserve (256);
|
||||
AccountStateSF filter (mSeq);
|
||||
AccountStateSF filter;
|
||||
|
||||
// Release the lock while we process the large state map
|
||||
sl.unlock();
|
||||
@@ -650,7 +650,7 @@ void InboundLedger::trigger (Peer::ptr const& peer)
|
||||
std::vector<uint256> nodeHashes;
|
||||
nodeIDs.reserve (256);
|
||||
nodeHashes.reserve (256);
|
||||
TransactionStateSF filter (mSeq);
|
||||
TransactionStateSF filter;
|
||||
mLedger->peekTransactionMap ()->getMissingNodes (
|
||||
nodeIDs, nodeHashes, 256, &filter);
|
||||
|
||||
@@ -805,8 +805,8 @@ bool InboundLedger::takeHeader (std::string const& data)
|
||||
Serializer s (data.size () + 4);
|
||||
s.add32 (HashPrefix::ledgerMaster);
|
||||
s.addRaw (data);
|
||||
getApp().getNodeStore ().store (hotLEDGER,
|
||||
mLedger->getLedgerSeq (), std::move (s.modData ()), mHash);
|
||||
getApp().getNodeStore ().store (
|
||||
hotLEDGER, std::move (s.modData ()), mHash);
|
||||
|
||||
progress ();
|
||||
|
||||
@@ -842,7 +842,7 @@ bool InboundLedger::takeTxNode (const std::list<SHAMapNodeID>& nodeIDs,
|
||||
|
||||
std::list<SHAMapNodeID>::const_iterator nodeIDit = nodeIDs.begin ();
|
||||
std::list< Blob >::const_iterator nodeDatait = data.begin ();
|
||||
TransactionStateSF tFilter (mLedger->getLedgerSeq ());
|
||||
TransactionStateSF tFilter;
|
||||
|
||||
while (nodeIDit != nodeIDs.end ())
|
||||
{
|
||||
@@ -909,7 +909,7 @@ bool InboundLedger::takeAsNode (const std::list<SHAMapNodeID>& nodeIDs,
|
||||
|
||||
std::list<SHAMapNodeID>::const_iterator nodeIDit = nodeIDs.begin ();
|
||||
std::list< Blob >::const_iterator nodeDatait = data.begin ();
|
||||
AccountStateSF tFilter (mLedger->getLedgerSeq ());
|
||||
AccountStateSF tFilter;
|
||||
|
||||
while (nodeIDit != nodeIDs.end ())
|
||||
{
|
||||
@@ -973,7 +973,7 @@ bool InboundLedger::takeAsRootNode (Blob const& data, SHAMapAddNode& san)
|
||||
return false;
|
||||
}
|
||||
|
||||
AccountStateSF tFilter (mLedger->getLedgerSeq ());
|
||||
AccountStateSF tFilter;
|
||||
san += mLedger->peekAccountStateMap ()->addRootNode (
|
||||
mLedger->getAccountHash (), data, snfWIRE, &tFilter);
|
||||
return san.isGood();
|
||||
@@ -997,7 +997,7 @@ bool InboundLedger::takeTxRootNode (Blob const& data, SHAMapAddNode& san)
|
||||
return false;
|
||||
}
|
||||
|
||||
TransactionStateSF tFilter (mLedger->getLedgerSeq ());
|
||||
TransactionStateSF tFilter;
|
||||
san += mLedger->peekTransactionMap ()->addRootNode (
|
||||
mLedger->getTransHash (), data, snfWIRE, &tFilter);
|
||||
return san.isGood();
|
||||
@@ -1016,7 +1016,7 @@ std::vector<InboundLedger::neededHash_t> InboundLedger::getNeededHashes ()
|
||||
|
||||
if (!mHaveState)
|
||||
{
|
||||
AccountStateSF filter (mLedger->getLedgerSeq ());
|
||||
AccountStateSF filter;
|
||||
// VFALCO NOTE What's the number 4?
|
||||
for (auto const& h : mLedger->getNeededAccountStateHashes (4, &filter))
|
||||
{
|
||||
@@ -1027,7 +1027,7 @@ std::vector<InboundLedger::neededHash_t> InboundLedger::getNeededHashes ()
|
||||
|
||||
if (!mHaveTransactions)
|
||||
{
|
||||
TransactionStateSF filter (mLedger->getLedgerSeq ());
|
||||
TransactionStateSF filter;
|
||||
// VFALCO NOTE What's the number 4?
|
||||
for (auto const& h : mLedger->getNeededTransactionHashes (4, &filter))
|
||||
{
|
||||
|
||||
@@ -688,7 +688,7 @@ bool Ledger::saveValidatedLedger (bool current)
|
||||
s.add32 (HashPrefix::ledgerMaster);
|
||||
addRaw (s);
|
||||
getApp().getNodeStore ().store (
|
||||
hotLEDGER, mLedgerSeq, std::move (s.modData ()), mHash);
|
||||
hotLEDGER, std::move (s.modData ()), mHash);
|
||||
}
|
||||
|
||||
AcceptedLedger::pointer aLedger;
|
||||
|
||||
@@ -1342,6 +1342,12 @@ TER LedgerEntrySet::trustCreate (
|
||||
const bool bSetDst = saLimit.getIssuer () == uDstAccountID;
|
||||
const bool bSetHigh = bSrcHigh ^ bSetDst;
|
||||
|
||||
assert (sleAccount->getFieldAccount160 (sfAccount) ==
|
||||
(bSetHigh ? uHighAccountID : uLowAccountID));
|
||||
SLE::pointer slePeer = entryCache (ltACCOUNT_ROOT,
|
||||
getAccountRootIndex (bSetHigh ? uLowAccountID : uHighAccountID));
|
||||
assert (slePeer);
|
||||
|
||||
// Remember deletion hints.
|
||||
sleRippleState->setFieldU64 (sfLowNode, uLowNode);
|
||||
sleRippleState->setFieldU64 (sfHighNode, uHighNode);
|
||||
@@ -1376,6 +1382,12 @@ TER LedgerEntrySet::trustCreate (
|
||||
uFlags |= (!bSetHigh ? lsfLowFreeze : lsfHighFreeze);
|
||||
}
|
||||
|
||||
if ((slePeer->getFlags() & lsfDefaultRipple) == 0)
|
||||
{
|
||||
// The other side's default is no rippling
|
||||
uFlags |= (bSetHigh ? lsfLowNoRipple : lsfHighNoRipple);
|
||||
}
|
||||
|
||||
sleRippleState->setFieldU32 (sfFlags, uFlags);
|
||||
incrementOwnerCount (sleAccount);
|
||||
|
||||
@@ -1507,7 +1519,9 @@ TER LedgerEntrySet::rippleCredit (
|
||||
// Sender is zero or negative.
|
||||
&& (uFlags & (!bSenderHigh ? lsfLowReserve : lsfHighReserve))
|
||||
// Sender reserve is set.
|
||||
&& !(uFlags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple))
|
||||
&& static_cast <bool> (uFlags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)) !=
|
||||
static_cast <bool> (entryCache (ltACCOUNT_ROOT,
|
||||
getAccountRootIndex (uSenderID))->getFlags() & lsfDefaultRipple)
|
||||
&& !(uFlags & (!bSenderHigh ? lsfLowFreeze : lsfHighFreeze))
|
||||
&& !sleRippleState->getFieldAmount (
|
||||
!bSenderHigh ? sfLowLimit : sfHighLimit)
|
||||
|
||||
@@ -27,8 +27,7 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
TransactionStateSF::TransactionStateSF (std::uint32_t ledgerSeq)
|
||||
: mLedgerSeq (ledgerSeq)
|
||||
TransactionStateSF::TransactionStateSF()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -43,7 +42,6 @@ void TransactionStateSF::gotNode (bool fromFilter,
|
||||
// and this should use that Database instad of getNodeStore
|
||||
getApp().getNodeStore ().store (
|
||||
(type == SHAMapTreeNode::tnTRANSACTION_NM) ? hotTRANSACTION : hotTRANSACTION_NODE,
|
||||
mLedgerSeq,
|
||||
std::move (nodeData),
|
||||
nodeHash);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace ripple {
|
||||
class TransactionStateSF : public SHAMapSyncFilter
|
||||
{
|
||||
public:
|
||||
explicit TransactionStateSF (std::uint32_t ledgerSeq);
|
||||
TransactionStateSF();
|
||||
|
||||
// Note that the nodeData is overwritten by this call
|
||||
void gotNode (bool fromFilter,
|
||||
@@ -42,9 +42,6 @@ public:
|
||||
bool haveNode (SHAMapNodeID const& id,
|
||||
uint256 const& nodeHash,
|
||||
Blob& nodeData);
|
||||
|
||||
private:
|
||||
std::uint32_t mLedgerSeq;
|
||||
};
|
||||
|
||||
} // ripple
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
// VFALCO NOTE LedgerIndex in CommittedObjects is obsolete
|
||||
|
||||
static const char* s_nodeStoreDBInit [] =
|
||||
{
|
||||
"PRAGMA synchronous=NORMAL;",
|
||||
@@ -94,7 +96,7 @@ public:
|
||||
uint256 const hash (uint256::fromVoid (key));
|
||||
|
||||
static SqliteStatement pSt (m_db->getDB()->getSqliteDB(),
|
||||
"SELECT ObjType,LedgerIndex,Object FROM CommittedObjects WHERE Hash = ?;");
|
||||
"SELECT ObjType,Object FROM CommittedObjects WHERE Hash = ?;");
|
||||
|
||||
pSt.bind (1, to_string (hash));
|
||||
|
||||
@@ -102,10 +104,9 @@ public:
|
||||
{
|
||||
// VFALCO NOTE This is unfortunately needed,
|
||||
// the DatabaseCon creates the blob?
|
||||
Blob data (pSt.getBlob (2));
|
||||
Blob data (pSt.getBlob(1));
|
||||
*pObject = NodeObject::createObject (
|
||||
getTypeFromString (pSt.peekString (0)),
|
||||
pSt.getUInt32 (1),
|
||||
std::move(data),
|
||||
hash);
|
||||
}
|
||||
@@ -131,15 +132,13 @@ public:
|
||||
|
||||
void storeBatch (NodeStore::Batch const& batch)
|
||||
{
|
||||
// VFALCO TODO Rewrite this to use Beast::db
|
||||
|
||||
auto sl (m_db->lock());
|
||||
|
||||
static SqliteStatement pStB (m_db->getDB()->getSqliteDB(), "BEGIN TRANSACTION;");
|
||||
static SqliteStatement pStE (m_db->getDB()->getSqliteDB(), "END TRANSACTION;");
|
||||
static SqliteStatement pSt (m_db->getDB()->getSqliteDB(),
|
||||
"INSERT OR IGNORE INTO CommittedObjects "
|
||||
"(Hash,ObjType,LedgerIndex,Object) VALUES (?, ?, ?, ?);");
|
||||
"(Hash,ObjType,Object) VALUES (?, ?, ?, ?);");
|
||||
|
||||
pStB.step();
|
||||
pStB.reset();
|
||||
@@ -163,7 +162,7 @@ public:
|
||||
uint256 hash;
|
||||
|
||||
static SqliteStatement pSt(m_db->getDB()->getSqliteDB(),
|
||||
"SELECT ObjType,LedgerIndex,Object,Hash FROM CommittedObjects;");
|
||||
"SELECT ObjType,Object,Hash FROM CommittedObjects;");
|
||||
|
||||
while (pSt.isRow (pSt.step()))
|
||||
{
|
||||
@@ -171,10 +170,9 @@ public:
|
||||
|
||||
// VFALCO NOTE This is unfortunately needed,
|
||||
// the DatabaseCon creates the blob?
|
||||
Blob data (pSt.getBlob (2));
|
||||
Blob data (pSt.getBlob (1));
|
||||
NodeObject::Ptr const object (NodeObject::createObject (
|
||||
getTypeFromString (pSt.peekString (0)),
|
||||
pSt.getUInt32 (1),
|
||||
std::move(data),
|
||||
hash));
|
||||
|
||||
@@ -207,8 +205,7 @@ public:
|
||||
|
||||
statement.bind(1, to_string (object->getHash()));
|
||||
statement.bind(2, type);
|
||||
statement.bind(3, object->getLedgerIndex());
|
||||
statement.bindStatic(4, object->getData());
|
||||
statement.bindStatic(3, object->getData());
|
||||
}
|
||||
|
||||
NodeObjectType getTypeFromString (std::string const& s)
|
||||
|
||||
@@ -168,6 +168,15 @@ public:
|
||||
uFlagsOut &= ~lsfDisableMaster;
|
||||
}
|
||||
|
||||
if (uSetFlag == asfDefaultRipple)
|
||||
{
|
||||
uFlagsOut |= lsfDefaultRipple;
|
||||
}
|
||||
else if (uClearFlag == asfDefaultRipple)
|
||||
{
|
||||
uFlagsOut &= ~lsfDefaultRipple;
|
||||
}
|
||||
|
||||
if (uSetFlag == asfNoFreeze)
|
||||
{
|
||||
m_journal.trace << "Set NoFreeze flag";
|
||||
|
||||
@@ -288,15 +288,17 @@ public:
|
||||
|
||||
if (QUALITY_ONE == uHighQualityOut) uHighQualityOut = 0;
|
||||
|
||||
bool const bLowDefRipple = sleLowAccount->getFlags() & lsfDefaultRipple;
|
||||
bool const bHighDefRipple = sleHighAccount->getFlags() & lsfDefaultRipple;
|
||||
|
||||
bool const bLowReserveSet = uLowQualityIn || uLowQualityOut ||
|
||||
(uFlagsOut & lsfLowNoRipple) ||
|
||||
((uFlagsOut & lsfLowNoRipple) == 0) != bLowDefRipple ||
|
||||
(uFlagsOut & lsfLowFreeze) ||
|
||||
saLowLimit || saLowBalance > zero;
|
||||
bool const bLowReserveClear = !bLowReserveSet;
|
||||
|
||||
bool const bHighReserveSet = uHighQualityIn || uHighQualityOut ||
|
||||
(uFlagsOut & lsfHighNoRipple) ||
|
||||
((uFlagsOut & lsfHighNoRipple) == 0) != bHighDefRipple ||
|
||||
(uFlagsOut & lsfHighFreeze) ||
|
||||
saHighLimit || saHighBalance > zero;
|
||||
bool const bHighReserveClear = !bHighReserveSet;
|
||||
|
||||