Compare commits
252 Commits
0.26.4-sp2
...
0.27.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
c6c8e5d70c | ||
|
|
fa354ec8d9 | ||
|
|
d0375f697d | ||
|
|
33c8257d25 | ||
|
|
f389bc33c3 | ||
|
|
4d5dca71ce | ||
|
|
a9c44a1b9c | ||
|
|
4144f800a1 | ||
|
|
6ef9a81017 | ||
|
|
8c6722f3c5 | ||
|
|
40e138627b | ||
|
|
a470dda4e6 | ||
|
|
b725410623 | ||
|
|
a9dfb33126 | ||
|
|
8b848770dc | ||
|
|
94629edb9b | ||
|
|
2a3f2ca28d | ||
|
|
8ab1e7d432 | ||
|
|
b2ba6a0c85 | ||
|
|
cca5421aed | ||
|
|
799d9a73e6 | ||
|
|
b0781622b2 | ||
|
|
0d0eec6345 | ||
|
|
1af79f7960 | ||
|
|
15b570bbdd | ||
|
|
7aa5599cc2 | ||
|
|
676293ec42 | ||
|
|
abc4fb81b1 | ||
|
|
53a16f354f | ||
|
|
6ab1ecd836 | ||
|
|
e7b16e7b47 | ||
|
|
14804f81a8 | ||
|
|
9a61b8d77d | ||
|
|
f42c2763d5 | ||
|
|
98d4e0e1b5 | ||
|
|
9156633baf | ||
|
|
bcf4f836b4 | ||
|
|
dbc1d70f99 | ||
|
|
78bc190a85 | ||
|
|
02855d7fed | ||
|
|
6fdd5d32be | ||
|
|
d7f32b105b | ||
|
|
0ac480a0bd | ||
|
|
417996de02 | ||
|
|
6c2d60cec2 | ||
|
|
743bd6c917 | ||
|
|
ab61aa41d9 | ||
|
|
36396ae29e | ||
|
|
749e083e6e | ||
|
|
67b9cf9e82 | ||
|
|
27fb20f3ab | ||
|
|
1c71b274f0 | ||
|
|
fcd20b63fe | ||
|
|
8ec344ac1b | ||
|
|
df966a9ac6 | ||
|
|
f634666dc6 | ||
|
|
e2f9f5d7e5 | ||
|
|
d078b0d143 | ||
|
|
0ccdea3cd8 | ||
|
|
df54b47cd0 | ||
|
|
2e595830b3 | ||
|
|
96fbcc9a5a | ||
|
|
6283801981 | ||
|
|
9a3214d46e | ||
|
|
9eb7c8344f | ||
|
|
4140bbb1f7 | ||
|
|
ea44497136 | ||
|
|
07737c6e5b | ||
|
|
98d5eefc86 | ||
|
|
4f2d93bb65 | ||
|
|
a5df3f1747 | ||
|
|
7f5f73887d | ||
|
|
91ce7807b9 | ||
|
|
d26fae9875 | ||
|
|
60bdc79ec4 | ||
|
|
253ddf2998 | ||
|
|
9fa15b390a | ||
|
|
e7d6fe6c8b | ||
|
|
9650b1aa70 | ||
|
|
eafa6f960f | ||
|
|
c62ccf4870 | ||
|
|
ef34439a79 | ||
|
|
b328ec2462 | ||
|
|
60f27178b8 | ||
|
|
e3fbb83ad0 | ||
|
|
28b70a7b9a | ||
|
|
dcdc341d0f | ||
|
|
fce77c9372 | ||
|
|
a360c481c2 | ||
|
|
c72db5fa5f | ||
|
|
fc9a23d6d4 | ||
|
|
167f4666e2 | ||
|
|
1cbcc7be21 | ||
|
|
8053598069 | ||
|
|
7cfac1a91a | ||
|
|
192cdd028e | ||
|
|
029c143922 | ||
|
|
00298cc68c | ||
|
|
d9c7db51af | ||
|
|
f12b15d22b | ||
|
|
409b8bac00 | ||
|
|
28b09bde4b | ||
|
|
2f6af906f4 | ||
|
|
628e3ac1eb | ||
|
|
fbf5785e35 | ||
|
|
eeea2b1ff8 | ||
|
|
32062e439f | ||
|
|
930a0beaf1 | ||
|
|
4a49fefdd9 | ||
|
|
8e792855e0 | ||
|
|
69f5c6987a | ||
|
|
85fc9e4ecf | ||
|
|
d5c3f0c9cf | ||
|
|
a48120e675 | ||
|
|
36f8e4f2ad | ||
|
|
1084a39a45 | ||
|
|
86df482842 | ||
|
|
b0d47ebcc6 | ||
|
|
fffdf1dfba | ||
|
|
3273ed2616 | ||
|
|
aa7b0a31b0 | ||
|
|
fb0d44d403 | ||
|
|
cd8ec89cbb | ||
|
|
252f271dc5 | ||
|
|
62d400c3a9 | ||
|
|
f9aa3e0da5 | ||
|
|
685fe5b0fb | ||
|
|
5180e71a0d | ||
|
|
55637f7508 | ||
|
|
7d72dfe0be | ||
|
|
02529a0fc2 | ||
|
|
b44974677e | ||
|
|
d4fd5e4fce | ||
|
|
30123eaa4a | ||
|
|
454ec97d51 | ||
|
|
c2ac331e78 | ||
|
|
be4a35af11 | ||
|
|
445b29ad0d | ||
|
|
64d0f7fffd | ||
|
|
baf0d09455 | ||
|
|
08a81a0ab9 | ||
|
|
31110c7fd9 | ||
|
|
0e1dd92d9b | ||
|
|
a3204a4df7 | ||
|
|
2288ab48b9 | ||
|
|
670401884c | ||
|
|
37181c341e | ||
|
|
be7e677448 | ||
|
|
b2eeb49a45 | ||
|
|
9aa040d917 | ||
|
|
c2043a223b | ||
|
|
f24e859f17 | ||
|
|
737b33f9d1 | ||
|
|
00791d2151 | ||
|
|
b141598f9b | ||
|
|
d1618d79b0 | ||
|
|
00c84dfe5c | ||
|
|
0829ee9234 | ||
|
|
b22e33444b | ||
|
|
d115a12cbe | ||
|
|
b7b744de94 | ||
|
|
68e46e406a | ||
|
|
329a969761 | ||
|
|
30170bc394 | ||
|
|
f193302e15 | ||
|
|
7c4870d641 | ||
|
|
8b84a76d5d | ||
|
|
a4cd761372 | ||
|
|
63d2cfd6ba | ||
|
|
fbffe2367e | ||
|
|
e442a2846d | ||
|
|
f6985586ea | ||
|
|
2bae5b0959 | ||
|
|
1e58809fcc | ||
|
|
6b1d213cc2 | ||
|
|
42bec13a83 | ||
|
|
4415a179b3 | ||
|
|
5d42604efd | ||
|
|
b134b7d3f6 | ||
|
|
788219fe05 | ||
|
|
9a7f66cfe9 | ||
|
|
daa4d16e61 | ||
|
|
cf05f87795 | ||
|
|
c2f2f83b7c | ||
|
|
b30b2a523f | ||
|
|
150a3810a8 | ||
|
|
ac0eaa912b | ||
|
|
e37d4043f6 | ||
|
|
d073425b44 | ||
|
|
825b18cf71 | ||
|
|
549ad3204f | ||
|
|
35f9499b67 | ||
|
|
db82c35c17 | ||
|
|
73c74f753c | ||
|
|
a38fb2a5dc | ||
|
|
38e99e01f9 | ||
|
|
a1f46e84b8 | ||
|
|
6540804571 | ||
|
|
ffe6707595 | ||
|
|
9b21740c9f | ||
|
|
bd12e2ab95 | ||
|
|
bffb5ef8b4 | ||
|
|
e4c9822d78 | ||
|
|
73187d8832 | ||
|
|
8101154d5e | ||
|
|
c02937fd6f | ||
|
|
3430be4075 | ||
|
|
3f2b6f771f | ||
|
|
6e39b49cc2 | ||
|
|
71c34ed4e0 | ||
|
|
477178675c | ||
|
|
dbdf68b248 | ||
|
|
2fd139b307 | ||
|
|
a6c2657062 | ||
|
|
78a0bc0e2c | ||
|
|
d7116d6867 | ||
|
|
edc15b9fa2 | ||
|
|
93d4b73b2f | ||
|
|
8e3849e591 | ||
|
|
acaa1098f7 | ||
|
|
c1a5e88752 | ||
|
|
74b99014d2 | ||
|
|
9cba944d21 | ||
|
|
8c1c2f5d05 | ||
|
|
bf0fa8c562 | ||
|
|
3e1fc9ba6c | ||
|
|
4ceba603e4 |
14
.travis.yml
@@ -6,20 +6,10 @@ before_install:
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq python-software-properties
|
||||
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
- sudo add-apt-repository -y ppa:boost-latest/ppa
|
||||
- sudo add-apt-repository -y ppa:afrank/boost
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq g++-4.8
|
||||
- sudo apt-get install -qq libboost1.55-all-dev
|
||||
# We want debug symbols for boost as we install gdb later
|
||||
- sudo apt-get install -qq libboost1.55-dbg
|
||||
- | # Setup the BOOST_ROOT
|
||||
export BOOST_ROOT=$HOME/boost_root
|
||||
mkdir -p $BOOST_ROOT/stage
|
||||
ln -s /usr/lib/x86_64-linux-gnu $BOOST_ROOT/stage/lib
|
||||
ln -s /usr/include/boost $BOOST_ROOT/boost
|
||||
- | # Try to patch boost
|
||||
sudo patch /usr/include/boost/bimap/detail/debug/static_error.hpp Builds/travis/static_error.boost.patch
|
||||
sudo patch /usr/include/boost/config/compiler/clang.hpp Builds/travis/clang.boost.patch
|
||||
- sudo apt-get install -qq libboost1.57-all-dev
|
||||
- sudo apt-get install -qq mlocate
|
||||
- sudo updatedb
|
||||
- sudo locate libboost | grep /lib | grep -e ".a$"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Express 2013 for Windows Desktop
|
||||
VisualStudioVersion = 12.0.30110.0
|
||||
VisualStudioVersion = 12.0.31101.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RippleD", "RippleD.vcxproj", "{26B7D9AC-1A80-8EF8-6703-D061F1BECB75}"
|
||||
EndProject
|
||||
@@ -14,9 +14,11 @@ Global
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{26B7D9AC-1A80-8EF8-6703-D061F1BECB75}.Debug|Win32.ActiveCfg = debug|x64
|
||||
{26B7D9AC-1A80-8EF8-6703-D061F1BECB75}.Debug|Win32.Build.0 = debug|x64
|
||||
{26B7D9AC-1A80-8EF8-6703-D061F1BECB75}.Debug|x64.ActiveCfg = debug|x64
|
||||
{26B7D9AC-1A80-8EF8-6703-D061F1BECB75}.Debug|x64.Build.0 = debug|x64
|
||||
{26B7D9AC-1A80-8EF8-6703-D061F1BECB75}.Release|Win32.ActiveCfg = release|x64
|
||||
{26B7D9AC-1A80-8EF8-6703-D061F1BECB75}.Release|Win32.Build.0 = release|x64
|
||||
{26B7D9AC-1A80-8EF8-6703-D061F1BECB75}.Release|x64.ActiveCfg = release|x64
|
||||
{26B7D9AC-1A80-8EF8-6703-D061F1BECB75}.Release|x64.Build.0 = release|x64
|
||||
EndGlobalSection
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name: rippled
|
||||
Version: 0.26.4-sp2
|
||||
Version: 0.27.2
|
||||
Release: 1%{?dist}
|
||||
Summary: Ripple peer-to-peer network daemon
|
||||
|
||||
@@ -50,4 +50,3 @@ rm -rf %{buildroot}
|
||||
/usr/bin/rippled
|
||||
/usr/share/rippled/LICENSE
|
||||
/etc/rippled/rippled-example.cfg
|
||||
|
||||
|
||||
82
README.md
@@ -1,3 +1,77 @@
|
||||

|
||||
|
||||
#The World’s Fastest and Most Secure Payment System
|
||||
|
||||
**What is Ripple?**
|
||||
|
||||
Ripple is the open-source, distributed payment protocol that enables instant
|
||||
payments with low fees, no chargebacks, and currency flexibility (for example
|
||||
dollars, yen, euros, bitcoins, or even loyalty points). Businesses of any size
|
||||
can easily build payment solutions such as banking or remittance apps, and
|
||||
accelerate the movement of money. Ripple enables the world to move value the
|
||||
way it moves information on the Internet.
|
||||
|
||||

|
||||
|
||||
**What is a Gateway?**
|
||||
|
||||
Ripple works with gateways: independent businesses which hold customer
|
||||
deposits in various currencies such as U.S. dollars (USD) or Euros (EUR),
|
||||
in exchange for providing cryptographically-signed issuances that users can
|
||||
send and trade with one another in seconds on the Ripple network. Within the
|
||||
protocol, exchanges between multiple currencies can occur atomically without
|
||||
any central authority to monitor them. Later, customers can withdraw their
|
||||
Ripple balances from the gateways that created those issuances.
|
||||
|
||||
**How do Ripple payments work?**
|
||||
|
||||
A sender specifies the amount and currency the recipient should receive and
|
||||
Ripple automatically converts the sender’s available currencies using the
|
||||
distributed order books integrated into the Ripple protocol. Independent third
|
||||
parties acting as market makers provide liquidity in these order books.
|
||||
|
||||
Ripple uses a pathfinding algorithm that considers currency pairs when
|
||||
converting from the source to the destination currency. This algorithm searches
|
||||
for a series of currency swaps that gives the user the lowest cost. Since
|
||||
anyone can participate as a market maker, market forces drive fees to the
|
||||
lowest practical level.
|
||||
|
||||
**What can you do with Ripple?**
|
||||
|
||||
The protocol is entirely open-source and the network’s shared ledger is public
|
||||
information, so no central authority prevents anyone from participating.Anyone
|
||||
can become a market maker, create a wallet or a gateway, or monitor network
|
||||
behavior. Competition drives down spreads and fees, making the network useful
|
||||
to everyone.
|
||||
|
||||
|
||||
###Key Protocol Features
|
||||
1. XRP is Ripple’s native [cryptocurrency]
|
||||
(http://en.wikipedia.org/wiki/Cryptocurrency) with a fixed supply that
|
||||
decreases slowly over time, with no mining. XRP acts as a bridge currency, and
|
||||
pays for transaction fees that protect the network against spam
|
||||

|
||||
|
||||
2. Pathfinding discovers cheap and efficient payment paths through multiple
|
||||
[order books](https://www.ripplecharts.com) allowing anyone to [trade](https://www.rippletrade.com) anything. When two accounts aren’t linked by relationships of trust, the Ripple pathfinding engine considers intermediate links and order books to produce a set of possible paths the transaction can take. When the payment is processed, the liquidity along these paths is iteratively consumed in best-first order.
|
||||

|
||||
|
||||
3. [Consensus](https://www.youtube.com/watch?v=pj1QVb1vlC0) confirms
|
||||
transactions in an atomic fashion, without mining, ensuring efficient use of
|
||||
resources.
|
||||
|
||||
[transact]: https://ripple.com/files/ripple-FIs.pdf
|
||||
[build]: https://ripple.com/build/
|
||||
|
||||
[transact.png]: /images/transact.png
|
||||
[build.png]: /images/build.png
|
||||
[contribute.png]: /images/contribute.png
|
||||
|
||||
###Join The Ripple Community
|
||||
|![Transact][transact.png]|![Build][build.png]|![Contribute][contribute.png]|
|
||||
|:-----------------------:|:-----------------:|:---------------------------:|
|
||||
|[Transact on the fastest payment infrastructure][transact]|[Build Imaginative Apps][build]|Contribute to the Ripple Protocol Implementation|
|
||||
|
||||
#rippled - Ripple P2P server
|
||||
|
||||
##[](https://travis-ci.org/ripple/rippled)
|
||||
@@ -37,5 +111,9 @@ Ripple is open source and permissively licensed under the ISC license. See the
|
||||
LICENSE file for more details.
|
||||
|
||||
###For more information:
|
||||
* https://ripple.com
|
||||
* https://ripple.com/wiki
|
||||
* Ripple Wiki - https://ripple.com/wiki/
|
||||
* Ripple Primer - https://ripple.com/ripple_primer.pdf
|
||||
* Ripple Primer (Market Making) - https://ripple.com/ripple-mm.pdf
|
||||
* Ripple Gateway Primer - https://ripple.com/ripple-gateways.pdf
|
||||
* Consensus - https://wiki.ripple.com/Consensus
|
||||
|
||||
|
||||
399
SConstruct
@@ -11,14 +11,17 @@
|
||||
all All available variants
|
||||
debug All available debug variants
|
||||
release All available release variants
|
||||
profile All available profile variants
|
||||
|
||||
clang All clang variants
|
||||
clang.debug clang debug variant
|
||||
clang.release clang release variant
|
||||
clang.profile clang profile variant
|
||||
|
||||
gcc All gcc variants
|
||||
gcc.debug gcc debug variant
|
||||
gcc.release gcc release variant
|
||||
gcc.profile gcc profile variant
|
||||
|
||||
msvc All msvc variants
|
||||
msvc.debug MSVC debug variant
|
||||
@@ -26,6 +29,13 @@
|
||||
|
||||
vcxproj Generate Visual Studio 2013 project file
|
||||
|
||||
count Show line count metrics
|
||||
|
||||
Any individual target can also have ".nounity" appended for a classic,
|
||||
non unity build. Example:
|
||||
|
||||
scons gcc.debug.nounity
|
||||
|
||||
If the clang toolchain is detected, then the default target will use it, else
|
||||
the gcc toolchain will be used. On Windows environments, the MSVC toolchain is
|
||||
also detected.
|
||||
@@ -199,7 +209,10 @@ def config_base(env):
|
||||
)
|
||||
check_openssl()
|
||||
|
||||
env.Append(CPPDEFINES=['OPENSSL_NO_SSL2'])
|
||||
env.Append(CPPDEFINES=[
|
||||
'OPENSSL_NO_SSL2'
|
||||
,'DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER'
|
||||
])
|
||||
|
||||
try:
|
||||
BOOST_ROOT = os.path.normpath(os.environ['BOOST_ROOT'])
|
||||
@@ -245,7 +258,7 @@ def config_env(toolchain, variant, env):
|
||||
if variant == 'debug':
|
||||
env.Append(CPPDEFINES=['DEBUG', '_DEBUG'])
|
||||
|
||||
elif variant == 'release':
|
||||
elif variant == 'release' or variant == 'profile':
|
||||
env.Append(CPPDEFINES=['NDEBUG'])
|
||||
|
||||
if toolchain in Split('clang gcc'):
|
||||
@@ -263,14 +276,32 @@ def config_env(toolchain, variant, env):
|
||||
'-g' # generate debug symbols
|
||||
])
|
||||
|
||||
env.Append(LINKFLAGS=[
|
||||
'-rdynamic',
|
||||
'-g',
|
||||
])
|
||||
|
||||
if variant == 'profile':
|
||||
env.Append(CCFLAGS=[
|
||||
'-p',
|
||||
'-pg',
|
||||
])
|
||||
env.Append(LINKFLAGS=[
|
||||
'-p',
|
||||
'-pg',
|
||||
])
|
||||
|
||||
if toolchain == 'clang':
|
||||
env.Append(CCFLAGS=['-Wno-redeclared-class-member'])
|
||||
env.Append(CPPDEFINES=['BOOST_ASIO_HAS_STD_ARRAY'])
|
||||
|
||||
env.Append(CXXFLAGS=[
|
||||
'-frtti',
|
||||
'-std=c++11',
|
||||
'-Wno-invalid-offsetof'])
|
||||
|
||||
env.Append(CPPDEFINES=['_FILE_OFFSET_BITS=64'])
|
||||
|
||||
if Beast.system.osx:
|
||||
env.Append(CPPDEFINES={
|
||||
'BEAST_COMPILE_OBJECTIVE_CPP': 1,
|
||||
@@ -298,11 +329,10 @@ def config_env(toolchain, variant, env):
|
||||
'boost_program_options',
|
||||
'boost_regex',
|
||||
'boost_system',
|
||||
'boost_thread'
|
||||
]
|
||||
# We prefer static libraries for boost
|
||||
if env.get('BOOST_ROOT'):
|
||||
# Need to add boost_thread. Not needed when dynamic linking is used.
|
||||
boost_libs += ['boost_thread']
|
||||
static_libs = ['%s/stage/lib/lib%s.a' % (env['BOOST_ROOT'], l) for
|
||||
l in boost_libs]
|
||||
if all(os.path.exists(f) for f in static_libs):
|
||||
@@ -324,22 +354,12 @@ def config_env(toolchain, variant, env):
|
||||
else:
|
||||
env.Append(LIBS=['rt'])
|
||||
|
||||
env.Append(LINKFLAGS=[
|
||||
'-rdynamic'
|
||||
])
|
||||
|
||||
if variant == 'release':
|
||||
env.Append(CCFLAGS=[
|
||||
'-O3',
|
||||
'-fno-strict-aliasing'
|
||||
])
|
||||
|
||||
if toolchain != 'msvc':
|
||||
git = Beast.Git(env)
|
||||
if git.exists:
|
||||
id = '%s+%s.%s' % (git.tags, git.user, git.branch)
|
||||
env.Append(CPPDEFINES={'GIT_COMMIT_ID' : '\'"%s"\'' % id })
|
||||
|
||||
if toolchain == 'clang':
|
||||
if Beast.system.osx:
|
||||
env.Replace(CC='clang', CXX='clang++', LINK='clang++')
|
||||
@@ -480,7 +500,7 @@ base.Append(CPPPATH=[
|
||||
])
|
||||
|
||||
# Configure the toolchains, variants, default toolchain, and default target
|
||||
variants = ['debug', 'release']
|
||||
variants = ['debug', 'release', 'profile']
|
||||
all_toolchains = ['clang', 'gcc', 'msvc']
|
||||
if Beast.system.osx:
|
||||
toolchains = ['clang']
|
||||
@@ -501,6 +521,8 @@ else:
|
||||
default_toolchain = 'clang'
|
||||
else:
|
||||
raise ValueError("Don't understand toolchains in " + str(toolchains))
|
||||
|
||||
default_tu_style = 'unity'
|
||||
default_variant = 'release'
|
||||
default_target = None
|
||||
|
||||
@@ -527,144 +549,216 @@ class ObjectBuilder(object):
|
||||
if kwds:
|
||||
env = env.Clone()
|
||||
env.Prepend(**kwds)
|
||||
path = UNITY_BUILD_DIRECTORY + filename
|
||||
o = env.Object(Beast.variantFile(path, self.variant_dirs))
|
||||
o = env.Object(Beast.variantFile(filename, self.variant_dirs))
|
||||
self.objects.append(o)
|
||||
|
||||
def list_sources(base, suffixes):
|
||||
def _iter(base):
|
||||
for parent, dirs, files in os.walk(base):
|
||||
files = [f for f in files if not f[0] == '.']
|
||||
dirs[:] = [d for d in dirs if not d[0] == '.']
|
||||
for path in files:
|
||||
path = os.path.join(parent, path)
|
||||
r = os.path.splitext(path)
|
||||
if r[1] and r[1] in suffixes:
|
||||
yield os.path.normpath(path)
|
||||
return list(_iter(base))
|
||||
|
||||
# Declare the targets
|
||||
aliases = collections.defaultdict(list)
|
||||
msvc_configs = []
|
||||
for toolchain in all_toolchains:
|
||||
for variant in variants:
|
||||
# Configure this variant's construction environment
|
||||
env = base.Clone()
|
||||
config_env(toolchain, variant, env)
|
||||
variant_name = '%s.%s' % (toolchain, variant)
|
||||
variant_dir = os.path.join(build_dir, variant_name)
|
||||
variant_dirs = {
|
||||
os.path.join(variant_dir, 'src') :
|
||||
'src',
|
||||
os.path.join(variant_dir, 'proto') :
|
||||
os.path.join (build_dir, 'proto'),
|
||||
}
|
||||
for dest, source in variant_dirs.iteritems():
|
||||
env.VariantDir(dest, source, duplicate=0)
|
||||
|
||||
object_builder = ObjectBuilder(env, variant_dirs)
|
||||
object_builder.add_source_files(
|
||||
'app.cpp',
|
||||
'app1.cpp',
|
||||
'app2.cpp',
|
||||
'app3.cpp',
|
||||
'app4.cpp',
|
||||
'app5.cpp',
|
||||
'app6.cpp',
|
||||
'app7.cpp',
|
||||
'app8.cpp',
|
||||
'app9.cpp',
|
||||
'basics.cpp',
|
||||
'beast.cpp',
|
||||
'common.cpp',
|
||||
'core.cpp',
|
||||
'data.cpp',
|
||||
'http.cpp',
|
||||
'json.cpp',
|
||||
'net.cpp',
|
||||
'overlay.cpp',
|
||||
'peerfinder.cpp',
|
||||
'protobuf.cpp',
|
||||
'ripple.proto.cpp',
|
||||
'resource.cpp',
|
||||
'rpcx.cpp',
|
||||
'sitefiles.cpp',
|
||||
'sslutil.cpp',
|
||||
'types.cpp',
|
||||
'validators.cpp',
|
||||
'websocket.cpp',
|
||||
)
|
||||
for tu_style in ['classic', 'unity']:
|
||||
for toolchain in all_toolchains:
|
||||
for variant in variants:
|
||||
if variant == 'profile' and toolchain == 'msvc':
|
||||
continue
|
||||
# Configure this variant's construction environment
|
||||
env = base.Clone()
|
||||
config_env(toolchain, variant, env)
|
||||
variant_name = '%s.%s' % (toolchain, variant)
|
||||
if tu_style == 'classic':
|
||||
variant_name += '.nounity'
|
||||
variant_dir = os.path.join(build_dir, variant_name)
|
||||
variant_dirs = {
|
||||
os.path.join(variant_dir, 'src') :
|
||||
'src',
|
||||
os.path.join(variant_dir, 'proto') :
|
||||
os.path.join (build_dir, 'proto'),
|
||||
}
|
||||
for dest, source in variant_dirs.iteritems():
|
||||
env.VariantDir(dest, source, duplicate=0)
|
||||
|
||||
object_builder.add_source_files(
|
||||
'beastc.c',
|
||||
CCFLAGS=['-Wno-array-bounds'])
|
||||
object_builder = ObjectBuilder(env, variant_dirs)
|
||||
|
||||
object_builder.add_source_files(
|
||||
'nodestore.cpp',
|
||||
CPPPATH=[
|
||||
'src/leveldb/include',
|
||||
#'src/hyperleveldb/include', # hyper
|
||||
'src/rocksdb2/include',
|
||||
]
|
||||
)
|
||||
if tu_style == 'classic':
|
||||
object_builder.add_source_files(
|
||||
*list_sources('src/ripple/app', '.cpp'))
|
||||
object_builder.add_source_files(
|
||||
*list_sources('src/ripple/basics', '.cpp'))
|
||||
object_builder.add_source_files(
|
||||
*list_sources('src/ripple/core', '.cpp'))
|
||||
object_builder.add_source_files(
|
||||
*list_sources('src/ripple/crypto', '.cpp'))
|
||||
object_builder.add_source_files(
|
||||
*list_sources('src/ripple/json', '.cpp'))
|
||||
object_builder.add_source_files(
|
||||
*list_sources('src/ripple/net', '.cpp'))
|
||||
object_builder.add_source_files(
|
||||
*list_sources('src/ripple/overlay', '.cpp'))
|
||||
object_builder.add_source_files(
|
||||
*list_sources('src/ripple/peerfinder', '.cpp'))
|
||||
object_builder.add_source_files(
|
||||
*list_sources('src/ripple/protocol', '.cpp'))
|
||||
object_builder.add_source_files(
|
||||
*list_sources('src/ripple/shamap', '.cpp'))
|
||||
object_builder.add_source_files(
|
||||
*list_sources('src/ripple/nodestore', '.cpp'),
|
||||
CPPPATH=[
|
||||
'src/leveldb/include',
|
||||
'src/rocksdb2/include',
|
||||
'src/snappy/snappy',
|
||||
'src/snappy/config',
|
||||
])
|
||||
else:
|
||||
object_builder.add_source_files(
|
||||
'src/ripple/unity/app.cpp',
|
||||
'src/ripple/unity/app1.cpp',
|
||||
'src/ripple/unity/app2.cpp',
|
||||
'src/ripple/unity/app3.cpp',
|
||||
'src/ripple/unity/app4.cpp',
|
||||
'src/ripple/unity/app5.cpp',
|
||||
'src/ripple/unity/app6.cpp',
|
||||
'src/ripple/unity/app7.cpp',
|
||||
'src/ripple/unity/app8.cpp',
|
||||
'src/ripple/unity/app9.cpp',
|
||||
'src/ripple/unity/core.cpp',
|
||||
'src/ripple/unity/basics.cpp',
|
||||
'src/ripple/unity/crypto.cpp',
|
||||
'src/ripple/unity/net.cpp',
|
||||
'src/ripple/unity/overlay.cpp',
|
||||
'src/ripple/unity/peerfinder.cpp',
|
||||
'src/ripple/unity/json.cpp',
|
||||
'src/ripple/unity/protocol.cpp',
|
||||
'src/ripple/unity/shamap.cpp',
|
||||
)
|
||||
|
||||
if 'gcc' in toolchain:
|
||||
no_uninitialized_warning = {'CCFLAGS': ['-Wno-maybe-uninitialized']}
|
||||
else:
|
||||
no_uninitialized_warning = {}
|
||||
object_builder.add_source_files(
|
||||
'src/ripple/unity/nodestore.cpp',
|
||||
CPPPATH=[
|
||||
'src/leveldb/include',
|
||||
'src/rocksdb2/include',
|
||||
'src/snappy/snappy',
|
||||
'src/snappy/config',
|
||||
])
|
||||
|
||||
object_builder.add_source_files(
|
||||
'leveldb.cpp',
|
||||
CPPPATH=[
|
||||
'src/leveldb/',
|
||||
'src/leveldb/include',
|
||||
'src/snappy/snappy',
|
||||
'src/snappy/config',
|
||||
],
|
||||
**no_uninitialized_warning
|
||||
)
|
||||
git_commit_tag = {}
|
||||
if toolchain != 'msvc':
|
||||
git = Beast.Git(env)
|
||||
if git.exists:
|
||||
id = '%s+%s.%s' % (git.tags, git.user, git.branch)
|
||||
git_commit_tag = {'CPPDEFINES':
|
||||
{'GIT_COMMIT_ID' : '\'"%s"\'' % id }}
|
||||
|
||||
object_builder.add_source_files(
|
||||
'hyperleveldb.cpp',
|
||||
CPPPATH=[
|
||||
'src/hyperleveldb',
|
||||
'src/snappy/snappy',
|
||||
'src/snappy/config',
|
||||
],
|
||||
**no_uninitialized_warning
|
||||
)
|
||||
object_builder.add_source_files(
|
||||
'src/ripple/unity/git_id.cpp',
|
||||
**git_commit_tag)
|
||||
|
||||
object_builder.add_source_files(
|
||||
'rocksdb.cpp',
|
||||
CPPPATH=[
|
||||
'src/rocksdb2',
|
||||
'src/rocksdb2/include',
|
||||
'src/snappy/snappy',
|
||||
'src/snappy/config',
|
||||
],
|
||||
**no_uninitialized_warning
|
||||
)
|
||||
|
||||
object_builder.add_source_files(
|
||||
'snappy.cpp',
|
||||
CCFLAGS=['-Wno-unused-function'],
|
||||
CPPPATH=[
|
||||
'src/snappy/snappy',
|
||||
'src/snappy/config',
|
||||
]
|
||||
)
|
||||
|
||||
if toolchain == "clang" and Beast.system.osx:
|
||||
object_builder.add_source_files('beastobjc.mm')
|
||||
|
||||
target = env.Program(
|
||||
target=os.path.join(variant_dir, 'rippled'),
|
||||
source=object_builder.objects
|
||||
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',
|
||||
'src/ripple/unity/rpcx.cpp',
|
||||
'src/ripple/unity/server.cpp',
|
||||
'src/ripple/unity/validators.cpp',
|
||||
'src/ripple/unity/websocket.cpp'
|
||||
)
|
||||
|
||||
if toolchain == default_toolchain and variant == default_variant:
|
||||
default_target = target
|
||||
install_target = env.Install (build_dir, source=default_target)
|
||||
env.Alias ('install', install_target)
|
||||
env.Default (install_target)
|
||||
aliases['all'].extend(install_target)
|
||||
if toolchain == 'msvc':
|
||||
config = env.VSProjectConfig(variant, 'x64', target, env)
|
||||
msvc_configs.append(config)
|
||||
if toolchain in toolchains:
|
||||
aliases['all'].extend(target)
|
||||
aliases[variant].extend(target)
|
||||
aliases[toolchain].extend(target)
|
||||
env.Alias(variant_name, target)
|
||||
object_builder.add_source_files(
|
||||
'src/ripple/unity/beastc.c',
|
||||
CCFLAGS = ([] if toolchain == 'msvc' else ['-Wno-array-bounds']))
|
||||
|
||||
if 'gcc' in toolchain:
|
||||
no_uninitialized_warning = {'CCFLAGS': ['-Wno-maybe-uninitialized']}
|
||||
else:
|
||||
no_uninitialized_warning = {}
|
||||
|
||||
object_builder.add_source_files(
|
||||
'src/ripple/unity/ed25519.c',
|
||||
CPPPATH=[
|
||||
'src/ed25519-donna',
|
||||
]
|
||||
)
|
||||
|
||||
object_builder.add_source_files(
|
||||
'src/ripple/unity/leveldb.cpp',
|
||||
CPPPATH=[
|
||||
'src/leveldb/',
|
||||
'src/leveldb/include',
|
||||
'src/snappy/snappy',
|
||||
'src/snappy/config',
|
||||
],
|
||||
**no_uninitialized_warning
|
||||
)
|
||||
|
||||
object_builder.add_source_files(
|
||||
'src/ripple/unity/hyperleveldb.cpp',
|
||||
CPPPATH=[
|
||||
'src/hyperleveldb',
|
||||
'src/snappy/snappy',
|
||||
'src/snappy/config',
|
||||
],
|
||||
**no_uninitialized_warning
|
||||
)
|
||||
|
||||
object_builder.add_source_files(
|
||||
'src/ripple/unity/rocksdb.cpp',
|
||||
CPPPATH=[
|
||||
'src/rocksdb2',
|
||||
'src/rocksdb2/include',
|
||||
'src/snappy/snappy',
|
||||
'src/snappy/config',
|
||||
],
|
||||
**no_uninitialized_warning
|
||||
)
|
||||
|
||||
object_builder.add_source_files(
|
||||
'src/ripple/unity/snappy.cpp',
|
||||
CCFLAGS=([] if toolchain == 'msvc' else ['-Wno-unused-function']),
|
||||
CPPPATH=[
|
||||
'src/snappy/snappy',
|
||||
'src/snappy/config',
|
||||
]
|
||||
)
|
||||
|
||||
if toolchain == "clang" and Beast.system.osx:
|
||||
object_builder.add_source_files('src/ripple/unity/beastobjc.mm')
|
||||
|
||||
target = env.Program(
|
||||
target=os.path.join(variant_dir, 'rippled'),
|
||||
source=object_builder.objects
|
||||
)
|
||||
|
||||
if tu_style == default_tu_style:
|
||||
if toolchain == default_toolchain and (
|
||||
variant == default_variant):
|
||||
default_target = target
|
||||
install_target = env.Install (build_dir, source=default_target)
|
||||
env.Alias ('install', install_target)
|
||||
env.Default (install_target)
|
||||
aliases['all'].extend(install_target)
|
||||
if toolchain == 'msvc':
|
||||
config = env.VSProjectConfig(variant, 'x64', target, env)
|
||||
msvc_configs.append(config)
|
||||
if toolchain in toolchains:
|
||||
aliases['all'].extend(target)
|
||||
aliases[toolchain].extend(target)
|
||||
if toolchain in toolchains:
|
||||
aliases[variant].extend(target)
|
||||
env.Alias(variant_name, target)
|
||||
|
||||
for key, value in aliases.iteritems():
|
||||
env.Alias(key, value)
|
||||
@@ -675,3 +769,32 @@ vcxproj = base.VSProject(
|
||||
VSPROJECT_ROOT_DIRS = ['src/beast', 'src', '.'],
|
||||
VSPROJECT_CONFIGS = msvc_configs)
|
||||
base.Alias('vcxproj', vcxproj)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
# Adds a phony target to the environment that always builds
|
||||
# See: http://www.scons.org/wiki/PhonyTargets
|
||||
def PhonyTargets(env = None, **kw):
|
||||
if not env: env = DefaultEnvironment()
|
||||
for target, action in kw.items():
|
||||
env.AlwaysBuild(env.Alias(target, [], action))
|
||||
|
||||
# Build the list of rippled source files that hold unit tests
|
||||
def do_count(target, source, env):
|
||||
def list_testfiles(base, suffixes):
|
||||
def _iter(base):
|
||||
for parent, _, files in os.walk(base):
|
||||
for path in files:
|
||||
path = os.path.join(parent, path)
|
||||
r = os.path.splitext(path)
|
||||
if r[1] in suffixes:
|
||||
if r[0].endswith('.test'):
|
||||
yield os.path.normpath(path)
|
||||
return list(_iter(base))
|
||||
testfiles = list_testfiles(os.path.join('src', 'ripple'), env.get('CPPSUFFIXES'))
|
||||
lines = 0
|
||||
for f in testfiles:
|
||||
lines = lines + sum(1 for line in open(f))
|
||||
print "Total unit test lines: %d" % lines
|
||||
|
||||
PhonyTargets(env, count = do_count)
|
||||
|
||||
77
appveyor.yml
Normal file
@@ -0,0 +1,77 @@
|
||||
# Set environment variables.
|
||||
environment:
|
||||
PYTHON: C:/Python27-x64
|
||||
|
||||
# We bundle up protoc.exe and only the parts of boost and openssl we need so
|
||||
# that it's a small download. We also use appveyor's free cache, avoiding fees
|
||||
# downloading from S3 each time.
|
||||
# TODO: script to create this package.
|
||||
RIPPLED_DEPS_URL: https://s3-ap-northeast-1.amazonaws.com/history-replay/rippled_deps.zip
|
||||
|
||||
# Other dependencies we just download each time.
|
||||
PIP_URL: https://bootstrap.pypa.io/get-pip.py
|
||||
PYWIN32_URL: https://downloads.sourceforge.net/project/pywin32/pywin32/Build%20219/pywin32-219.win-amd64-py2.7.exe
|
||||
|
||||
# Scons honours these environment variables, setting the include/lib paths.
|
||||
BOOST_ROOT: C:/rippled_deps/boost
|
||||
OPENSSL_ROOT: C:/rippled_deps/openssl
|
||||
|
||||
# At the end of each successful build we cache this directory. It must be less
|
||||
# than 100MB total compressed.
|
||||
cache:
|
||||
- 'C:\\rippled_deps'
|
||||
|
||||
# This means we'll download a zip of the branch we want, rather than the full
|
||||
# history.
|
||||
shallow_clone: true
|
||||
|
||||
install:
|
||||
# We want easy_install, python and protoc.exe on PATH.
|
||||
- SET PATH=%PYTHON%;%PYTHON%/Scripts;C:/rippled_deps;%PATH%
|
||||
|
||||
# `ps` prefix means the command is executed by powershell.
|
||||
- ps: Start-FileDownload $env:PIP_URL
|
||||
- ps: Start-FileDownload $env:PYWIN32_URL
|
||||
|
||||
# Installing pip will install setuptools/easy_install.
|
||||
- python get-pip.py
|
||||
|
||||
# Pip has some problems installing scons on windows so we use easy install.
|
||||
- easy_install scons
|
||||
|
||||
# Scons has problems with parallel builds on windows without pywin32.
|
||||
- easy_install pywin32-219.win-amd64-py2.7.exe
|
||||
# (easy_install can do headless installs of .exe wizards)
|
||||
|
||||
# Download dependencies if appveyor didn't restore them from the cache.
|
||||
# Use 7zip to unzip.
|
||||
- ps: |
|
||||
if (-not(Test-Path 'C:/rippled_deps')) {
|
||||
Start-FileDownload "$env:RIPPLED_DEPS_URL"
|
||||
7z x rippled_deps.zip -oC:\ -y > $null
|
||||
}
|
||||
|
||||
# TODO: This is giving me grief
|
||||
# artifacts:
|
||||
# # Save rippled.exe in the cloud after each build.
|
||||
# - path: "build\\rippled.exe"
|
||||
|
||||
build_script:
|
||||
# We set the environment variables needed to put compilers on the PATH.
|
||||
- '"%VS120COMNTOOLS%../../VC/vcvarsall.bat" x86_amd64'
|
||||
# Show which version of the compiler we are using.
|
||||
- cl
|
||||
- scons msvc.debug -j%NUMBER_OF_PROCESSORS%
|
||||
|
||||
after_build:
|
||||
# Put our executable in a place where npm test can find it.
|
||||
- ps: cp build/msvc.debug/rippled.exe build
|
||||
- ps: ls build
|
||||
|
||||
test_script:
|
||||
# Run the unit tests
|
||||
- build\\rippled --unittest
|
||||
|
||||
# Run the integration tests
|
||||
- npm install
|
||||
- npm test
|
||||
133
bin/stop-test.js
Normal file
@@ -0,0 +1,133 @@
|
||||
/* -------------------------------- REQUIRES -------------------------------- */
|
||||
|
||||
var child = require("child_process");
|
||||
var assert = require("assert");
|
||||
|
||||
/* --------------------------------- CONFIG --------------------------------- */
|
||||
|
||||
if (process.argv[2] == null) {
|
||||
[
|
||||
'Usage: ',
|
||||
'',
|
||||
' `node bin/stop-test.js i,j [rippled_path] [rippled_conf]`',
|
||||
'',
|
||||
' Launch rippled and stop it after n seconds for all n in [i, j}',
|
||||
' For all even values of n launch rippled with `--fg`',
|
||||
' For values of n where n % 3 == 0 launch rippled with `--fg`\n',
|
||||
'Examples: ',
|
||||
'',
|
||||
' $ node bin/stop-test.js 5,10',
|
||||
(' $ node bin/stop-test.js 1,4 ' +
|
||||
'build/clang.debug/rippled $HOME/.confs/rippled.cfg')
|
||||
]
|
||||
.forEach(function(l){console.log(l)});
|
||||
|
||||
process.exit();
|
||||
} else {
|
||||
var testRange = process.argv[2].split(',').map(Number);
|
||||
var rippledPath = process.argv[3] || 'build/rippled'
|
||||
var rippledConf = process.argv[4] || 'rippled.cfg'
|
||||
}
|
||||
|
||||
var options = {
|
||||
env: process.env,
|
||||
stdio: 'ignore' // we could dump the child io when it fails abnormally
|
||||
};
|
||||
|
||||
// default args
|
||||
var conf_args = ['--conf='+rippledConf];
|
||||
var start_args = conf_args.concat([/*'--net'*/])
|
||||
var stop_args = conf_args.concat(['stop']);
|
||||
|
||||
/* --------------------------------- HELPERS -------------------------------- */
|
||||
|
||||
function start(args) {
|
||||
return child.spawn(rippledPath, args, options);
|
||||
}
|
||||
function stop(rippled) { child.execFile(rippledPath, stop_args, options)}
|
||||
function secs_l8r(ms, f) {setTimeout(f, ms * 1000); }
|
||||
|
||||
function show_results_and_exit(results) {
|
||||
console.log(JSON.stringify(results, undefined, 2));
|
||||
process.exit();
|
||||
}
|
||||
|
||||
var timeTakes = function (range) {
|
||||
function sumRange(n) {return (n+1) * n /2}
|
||||
var ret = sumRange(range[1]);
|
||||
if (range[0] > 1) {
|
||||
ret = ret - sumRange(range[0] - 1)
|
||||
}
|
||||
var stopping = (range[1] - range[0]) * 0.5;
|
||||
return ret + stopping;
|
||||
}
|
||||
|
||||
/* ---------------------------------- TEST ---------------------------------- */
|
||||
|
||||
console.log("Test will take ~%s seconds", timeTakes(testRange));
|
||||
|
||||
(function oneTest(n /* seconds */, results) {
|
||||
if (n >= testRange[1]) {
|
||||
// show_results_and_exit(results);
|
||||
console.log(JSON.stringify(results, undefined, 2));
|
||||
oneTest(testRange[0], []);
|
||||
return;
|
||||
}
|
||||
|
||||
var args = start_args;
|
||||
if (n % 2 == 0) {args = args.concat(['--fg'])}
|
||||
if (n % 3 == 0) {args = args.concat(['--net'])}
|
||||
|
||||
var result = {args: args, alive_for: n};
|
||||
results.push(result);
|
||||
|
||||
console.log("\nLaunching `%s` with `%s` for %d seconds",
|
||||
rippledPath, JSON.stringify(args), n);
|
||||
|
||||
rippled = start(args);
|
||||
console.log("Rippled pid: %d", rippled.pid);
|
||||
|
||||
// defaults
|
||||
var b4StopSent = false;
|
||||
var stopSent = false;
|
||||
var stop_took = null;
|
||||
|
||||
rippled.once('exit', function(){
|
||||
if (!stopSent && !b4StopSent) {
|
||||
console.warn('\nRippled exited itself b4 stop issued');
|
||||
process.exit();
|
||||
};
|
||||
|
||||
// The io handles close AFTER exit, may have implications for
|
||||
// `stdio:'inherit'` option to `child.spawn`.
|
||||
rippled.once('close', function() {
|
||||
result.stop_took = (+new Date() - stop_took) / 1000; // seconds
|
||||
console.log("Stopping after %d seconds took %s seconds",
|
||||
n, result.stop_took);
|
||||
oneTest(n+1, results);
|
||||
});
|
||||
});
|
||||
|
||||
secs_l8r(n, function(){
|
||||
console.log("Stopping rippled after %d seconds", n);
|
||||
|
||||
// possible race here ?
|
||||
// seems highly unlikely, but I was having issues at one point
|
||||
b4StopSent=true;
|
||||
stop_took = (+new Date());
|
||||
// when does `exit` actually get sent?
|
||||
stop();
|
||||
stopSent=true;
|
||||
|
||||
// Sometimes we want to attach with a debugger.
|
||||
if (process.env.ABORT_TESTS_ON_STALL != null) {
|
||||
// We wait 30 seconds, and if it hasn't stopped, we abort the process
|
||||
secs_l8r(30, function() {
|
||||
if (result.stop_took == null) {
|
||||
console.log("rippled has stalled");
|
||||
process.exit();
|
||||
};
|
||||
});
|
||||
}
|
||||
})
|
||||
}(testRange[0], []));
|
||||
@@ -6,23 +6,23 @@
|
||||
#
|
||||
# Contents
|
||||
#
|
||||
# 1. Peer Networking
|
||||
# 1. Server
|
||||
#
|
||||
# 2. Websocket Networking
|
||||
# 2. Peer Protocol
|
||||
#
|
||||
# 3. RPC Networking
|
||||
# 3. SMS Gateway
|
||||
#
|
||||
# 4. SMS Gateway
|
||||
# 4. Ripple Protocol
|
||||
#
|
||||
# 5. Ripple Protcol
|
||||
# 5. HTTPS Client
|
||||
#
|
||||
# 6. HTTPS Client
|
||||
# 6. Database
|
||||
#
|
||||
# 7. Database
|
||||
# 7. Diagnostics
|
||||
#
|
||||
# 8. Diagnostics
|
||||
# 8. Voting
|
||||
#
|
||||
# 9. Voting
|
||||
# 9. Example Settings
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
@@ -44,19 +44,235 @@
|
||||
# or Mac style end of lines. Blank lines and lines beginning with '#' are
|
||||
# ignored. Undefined sections are reserved. No escapes are currently defined.
|
||||
#
|
||||
# Notation
|
||||
#
|
||||
# In this document a simple BNF notation is used. Angle brackets denote
|
||||
# required elements, square brackets denote optional elements, and single
|
||||
# quotes indicate string literals. A vertical bar separating 1 or more
|
||||
# elements is a logical "or"; Any one of the elements may be chosen.
|
||||
# Parenthesis are notational only, and used to group elements, they are not
|
||||
# part of the syntax unless they appear in quotes. White space may always
|
||||
# appear between elements, it has no effect on values.
|
||||
#
|
||||
# <key> A required identifier
|
||||
# '=' The equals sign character
|
||||
# | Logical "or"
|
||||
# ( ) Used for grouping
|
||||
#
|
||||
#
|
||||
# An identifier is a string of upper or lower case letters, digits, or
|
||||
# underscores subject to the requirement that the first character of an
|
||||
# identifier must be a letter. Identifiers are not case sensitive (but
|
||||
# values may be).
|
||||
#
|
||||
# Some configuration sections contain key/value pairs. A line containing
|
||||
# a key/value pair has this syntax:
|
||||
#
|
||||
# <identifier> '=' <value>
|
||||
#
|
||||
# Depending on the section and key, different value types are possible:
|
||||
#
|
||||
# <integer> A signed integer
|
||||
# <unsigned> An unsigned integer
|
||||
# <flag> A boolean. 1 = true/yes/on, 0 = false/no/off.
|
||||
#
|
||||
# Consult the documentation on the key in question to determine the possible
|
||||
# value types.
|
||||
#
|
||||
#
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 1. Peer Networking
|
||||
# 1. Server
|
||||
#
|
||||
#-------------------
|
||||
#----------
|
||||
#
|
||||
#
|
||||
#
|
||||
# rippled offers various server protocols to clients making inbound
|
||||
# connections. The listening ports rippled uses are "universal" ports
|
||||
# which may be configured to handshake in one or more of the available
|
||||
# supported protocols. These universal ports simplify administration:
|
||||
# A single open port can be used for multiple protocols.
|
||||
#
|
||||
# NOTE At least one server port must be defined in order
|
||||
# to accept incoming network connections.
|
||||
#
|
||||
#
|
||||
# [server]
|
||||
#
|
||||
# A list of port names and key/value pairs. A port name must start with a
|
||||
# letter and contain only letters and numbers. The name is not case-sensitive.
|
||||
# For each name in this list, rippled will look for a configuration file
|
||||
# section with the same name and use it to create a listening port. The
|
||||
# name is informational only; the choice of name does not affect the function
|
||||
# of the listening port.
|
||||
#
|
||||
# Key/value pairs specified in this section are optional, and apply to all
|
||||
# listening ports unless the port overrides the value in its section. They
|
||||
# may be considered default values.
|
||||
#
|
||||
# Suggestion:
|
||||
#
|
||||
# To avoid a conflict with port names and future configuration sections,
|
||||
# we recommend prepending "port_" to the port name. This prefix is not
|
||||
# required, but suggested.
|
||||
#
|
||||
# This example defines two ports with different port numbers and settings:
|
||||
#
|
||||
# [server]
|
||||
# port_public
|
||||
# port_private
|
||||
# port = 80
|
||||
#
|
||||
# [port_public]
|
||||
# ip=0.0.0.0
|
||||
# port = 443
|
||||
# protocol=peer,https
|
||||
#
|
||||
# [port_private]
|
||||
# ip=127.0.0.1
|
||||
# protocol=http
|
||||
#
|
||||
# When rippled is used as a command line client (for example, issuing a
|
||||
# server stop command), the first port advertising the http or https
|
||||
# protocol will be used to make the connection.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [<name>]
|
||||
#
|
||||
# A series of key/value pairs that define the settings for the port with
|
||||
# the corresponding name. These keys are possible:
|
||||
#
|
||||
# ip = <IP-address>
|
||||
#
|
||||
# Required. Determines the IP address of the network interface to bind
|
||||
# to. To bind to all available interfaces, uses 0.0.0.0
|
||||
#
|
||||
# port = <number>
|
||||
#
|
||||
# Required. Sets the port number to use for this port.
|
||||
#
|
||||
# protocol = [ http, https, peer ]
|
||||
#
|
||||
# Required. A comma-separated list of protocols to support:
|
||||
#
|
||||
# http JSON-RPC over HTTP
|
||||
# https JSON-RPC over HTTPS
|
||||
# ws Websockets
|
||||
# wss Secure Websockets
|
||||
# peer Peer Protocol
|
||||
#
|
||||
# Restrictions:
|
||||
#
|
||||
# Only one port may be configured to support the peer protocol.
|
||||
# A port cannot have websocket and non websocket protocols at the
|
||||
# same time. It is possible have both Websockets and Secure Websockets
|
||||
# together in one port.
|
||||
#
|
||||
# NOTE If no ports support the peer protocol, rippled cannot
|
||||
# receive incoming peer connections or become a superpeer.
|
||||
#
|
||||
# user = <text>
|
||||
# password = <text>
|
||||
#
|
||||
# When set, these credentials will be required on HTTP/S requests.
|
||||
# The credentials must be provided using HTTP's Basic Authentication
|
||||
# headers. If either or both fields are empty, then no credentials are
|
||||
# required. IP address restrictions, if any, will be checked in addition
|
||||
# to the credentials specified here.
|
||||
#
|
||||
# When acting in the client role, rippled will supply these credentials
|
||||
# using HTTP's Basic Authentication headers when making outbound HTTP/S
|
||||
# requests.
|
||||
#
|
||||
# admin = no | allow
|
||||
#
|
||||
# Controls whether or not administrative commands are allowed. These
|
||||
# commands may be issued over http, https, ws, or wss if configured
|
||||
# on the port. If unspecified, the default is to not allow
|
||||
# administrative commands.
|
||||
#
|
||||
# admin_user = <text>
|
||||
# admin_password = <text>
|
||||
#
|
||||
# When set, clients must provide these credentials in the submitted
|
||||
# JSON for any administrative command requests submitted to the HTTP/S,
|
||||
# WS, or WSS protocol interfaces. If administrative commands are
|
||||
# disabled for a port, these credentials have no effect.
|
||||
#
|
||||
# When acting in the client role, rippled will supply these credentials
|
||||
# in the submitted JSON for any administrative command requests when
|
||||
# invoking JSON-RPC commands on remote servers.
|
||||
#
|
||||
# ssl_key = <filename>
|
||||
# ssl_cert = <filename>
|
||||
# ssl_chain = <filename>
|
||||
#
|
||||
# Use the specified files when configuring SSL on the port.
|
||||
#
|
||||
# NOTE If no files are specified and secure protocols are selected,
|
||||
# rippled will generate an internal self-signed certificate.
|
||||
#
|
||||
# The files have these meanings:
|
||||
#
|
||||
# ssl_key
|
||||
#
|
||||
# Specifies the filename holding the SSL key in PEM format.
|
||||
#
|
||||
# ssl_cert
|
||||
#
|
||||
# Specifies the path to the SSL certificate file in PEM format.
|
||||
# This is not needed if the chain includes it.
|
||||
#
|
||||
# ssl_chain
|
||||
#
|
||||
# If you need a certificate chain, specify the path to the
|
||||
# certificate chain here. The chain may include the end certificate.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_admin_allow]
|
||||
#
|
||||
# Specify a list of IP addresses allowed to have admin access. One per line.
|
||||
# If you want to test the output of non-admin commands add this section and
|
||||
# just put an ip address not under your control.
|
||||
# Defaults to 127.0.0.1.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_startup]
|
||||
#
|
||||
# Specify a list of RPC commands to run at startup.
|
||||
#
|
||||
# Examples:
|
||||
# { "command" : "server_info" }
|
||||
# { "command" : "log_level", "partition" : "ripplecalc", "severity" : "trace" }
|
||||
#
|
||||
#
|
||||
#
|
||||
# [websocket_ping_frequency]
|
||||
#
|
||||
# <number>
|
||||
#
|
||||
# The amount of time to wait in seconds, before sending a websocket 'ping'
|
||||
# message. Ping messages are used to determine if the remote end of the
|
||||
# connection is no longer available.
|
||||
#
|
||||
#
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 2. Peer Protocol
|
||||
#
|
||||
#-----------------
|
||||
#
|
||||
# These settings control security and access attributes of the Peer to Peer
|
||||
# server section of the rippled process. Peer Networking implements the
|
||||
# server section of the rippled process. Peer Protocol implements the
|
||||
# Ripple Payment protocol. It is over peer connections that transactions
|
||||
# and validations are passed from to machine to machine, to make up the
|
||||
# components of closed ledgers.
|
||||
# and validations are passed from to machine to machine, to determine the
|
||||
# contents of validated ledgers.
|
||||
#
|
||||
#
|
||||
#
|
||||
@@ -95,40 +311,6 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
# [peer_ip]
|
||||
#
|
||||
# IP address or domain to bind to allow external connections from peers.
|
||||
# Defaults to not binding, which disallows external connections from peers.
|
||||
#
|
||||
# Examples: 0.0.0.0 - Bind on all interfaces.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [peer_port]
|
||||
#
|
||||
# If peer_ip is supplied, corresponding port to bind to for peer connections.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [peer_port_proxy]
|
||||
#
|
||||
# An optional, additional listening port number for peers. Incoming
|
||||
# connections on this port will be required to provide a PROXY Protocol
|
||||
# handshake, described in this document (external link):
|
||||
#
|
||||
# http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt
|
||||
#
|
||||
# The PROXY Protocol is a popular method used by elastic load balancing
|
||||
# service providers such as Amazon, to identify the true IP address and
|
||||
# port number of external incoming connections.
|
||||
#
|
||||
# In addition to enabling this setting, it will also be required to
|
||||
# use your provider-specific control panel or administrative web page
|
||||
# to configure your server instance to receive PROXY Protocol handshakes,
|
||||
# and also to restrict access to your instance to the Elastic Load Balancer.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [peer_private]
|
||||
#
|
||||
# 0 or 1.
|
||||
@@ -147,19 +329,6 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
# [peer_ssl_cipher_list]
|
||||
#
|
||||
# A colon delimited string with the allowed SSL cipher modes for peer. The
|
||||
# choices for for ciphers are defined by the OpenSSL API function
|
||||
# SSL_CTX_set_cipher_list, documented here (external link):
|
||||
#
|
||||
# http://pic.dhe.ibm.com/infocenter/tpfhelp/current/index.jsp?topic=%2Fcom.ibm.ztpf-ztpfdf.doc_put.cur%2Fgtpc2%2Fcpp_ssl_ctx_set_cipher_list.html
|
||||
#
|
||||
# The default setting is "ALL:!LOW:!EXP:!MD5:@STRENGTH", which allows
|
||||
# non-authenticated peer connections (they are, however, secure).
|
||||
#
|
||||
#
|
||||
#
|
||||
# [node_seed]
|
||||
#
|
||||
# This is used for clustering. To force a particular node seed or key, the
|
||||
@@ -193,245 +362,49 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
# [overlay] EXPERIMENTAL
|
||||
#
|
||||
# 2. Websocket Networking
|
||||
# This section is EXPERIMENTAL, and should not be
|
||||
# present for production configuration settings.
|
||||
#
|
||||
#------------------------
|
||||
# A set of key/value pair parameters to configure the overlay.
|
||||
#
|
||||
# These settings control security and access attributes of the Websocket
|
||||
# server section of the rippled process, primarily used to service
|
||||
# client requests and backend applications.
|
||||
# auto_connect = 0 | 1
|
||||
#
|
||||
# When set, activates the autoconnect feature. This maintains outgoing
|
||||
# connections using PeerFinder's "Outgoing Connection Strategy."
|
||||
#
|
||||
# http_handshake = 0 | 1
|
||||
#
|
||||
# [websocket_public_ip]
|
||||
# When set, outgoing peer connections will handshaking using a HTTP
|
||||
# request instead of the legacy TMHello protocol buffers message.
|
||||
# Incoming peer connections have their handshakes detected automatically.
|
||||
#
|
||||
# IP address or domain to bind to allow untrusted connections from clients.
|
||||
# In the future, this option will go away and the peer_ip will accept
|
||||
# websocket client connections.
|
||||
# become_superpeer = 'never' | 'always' | 'auto'
|
||||
#
|
||||
# Examples: 0.0.0.0 - Bind on all interfaces.
|
||||
# 127.0.0.1 - Bind on localhost interface. Only local programs may connect.
|
||||
# Controls the selection of peer roles:
|
||||
#
|
||||
# 'never' Always handshake in the leaf role.
|
||||
# 'always' Always handshake in the superpeer role.
|
||||
# 'auto' Start as a leaf, promote to superpeer after
|
||||
# passing capability check (default).
|
||||
#
|
||||
# In the leaf role, a peer does not advertise its IP and port for
|
||||
# the purpose of receiving incoming connections. The peer also does
|
||||
# not forward transactions and validations received from other peers.
|
||||
#
|
||||
# [websocket_public_port]
|
||||
#
|
||||
# Port to bind to allow untrusted connections from clients. In the future,
|
||||
# this option will go away and the peer_ip will accept websocket client
|
||||
# connections.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [websocket_public_secure]
|
||||
#
|
||||
# 0, 1 or 2.
|
||||
# 0: Provide ws service for websocket_public_ip/websocket_public_port.
|
||||
# 1: Provide both ws and wss service for websocket_public_ip/websocket_public_port. [default]
|
||||
# 2: Provide wss service only for websocket_public_ip/websocket_public_port.
|
||||
#
|
||||
# Browser pages like the Ripple client will not be able to connect to a secure
|
||||
# websocket connection if a self-signed certificate is used. As the Ripple
|
||||
# reference client currently shares secrets with its server, this should be
|
||||
# enabled.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [websocket_ping_frequency]
|
||||
#
|
||||
# <number>
|
||||
#
|
||||
# The amount of time to wait in seconds, before sending a websocket 'ping'
|
||||
# message. Ping messages are used to determine if the remote end of the
|
||||
# connection is no longer available.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [websocket_ip]
|
||||
#
|
||||
# IP address or domain to bind to allow trusted ADMIN connections from backend
|
||||
# applications.
|
||||
#
|
||||
# Examples: 0.0.0.0 - Bind on all interfaces.
|
||||
# 127.0.0.1 - Bind on localhost interface. Only local programs may connect.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [websocket_port]
|
||||
#
|
||||
# Port to bind to allow trusted ADMIN connections from backend applications.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [websocket_secure]
|
||||
#
|
||||
# 0, 1, or 2.
|
||||
# 0: Provide ws service only for websocket_ip/websocket_port. [default]
|
||||
# 1: Provide ws and wss service for websocket_ip/websocket_port
|
||||
# 2: Provide wss service for websocket_ip/websocket_port.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [websocket_ssl_cert]
|
||||
#
|
||||
# Specify the path to the SSL certificate file in PEM format.
|
||||
# This is not needed if the chain includes it.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [websocket_ssl_chain]
|
||||
#
|
||||
# If you need a certificate chain, specify the path to the certificate chain
|
||||
# here. The chain may include the end certificate.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [websocket_ssl_key]
|
||||
#
|
||||
# Specify the filename holding the SSL key in PEM format.
|
||||
# In the superpeer role, a peer advertises its IP and port for
|
||||
# receiving incoming connections after passing an incoming connection
|
||||
# test. Superpeers forward transactions and protocol messages to all
|
||||
# other peers. Superpeers do not forward validations to other superpeers.
|
||||
# Instead, a validation received by a superpeer from a leaf is forwarded
|
||||
# only to other leaf connections.
|
||||
#
|
||||
#
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 3. RPC Networking
|
||||
#
|
||||
#------------------
|
||||
#
|
||||
# This group of settings configures security and access attributes of the
|
||||
# RPC server section of the rippled process, used to service both local
|
||||
# and optional remote clients.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_allow_remote]
|
||||
#
|
||||
# 0 or 1.
|
||||
#
|
||||
# 0: Allow RPC connections only from 127.0.0.1. [default]
|
||||
# 1: Allow RPC connections from any IP.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_admin_allow]
|
||||
#
|
||||
# Specify a list of IP addresses allowed to have admin access. One per line.
|
||||
# If you want to test the output of non-admin commands add this section and
|
||||
# just put an ip address not under your control.
|
||||
# Defaults to 127.0.0.1.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_admin_user]
|
||||
#
|
||||
# As a server, require this as the admin user to be specified. Also, require
|
||||
# rpc_admin_user and rpc_admin_password to be checked for RPC admin functions.
|
||||
# The request must specify these as the admin_user and admin_password in the
|
||||
# request object.
|
||||
#
|
||||
# As a client, supply this to the server in the request object.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_admin_password]
|
||||
#
|
||||
# As a server, require this as the admin password to be specified. Also,
|
||||
# require rpc_admin_user and rpc_admin_password to be checked for RPC admin
|
||||
# functions. The request must specify these as the admin_user and
|
||||
# admin_password in the request object.
|
||||
#
|
||||
# As a client, supply this to the server in the request object.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_ip]
|
||||
#
|
||||
# IP address or domain to bind to allow insecure RPC connections.
|
||||
# Defaults to not binding, which disallows RPC connections.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_port]
|
||||
#
|
||||
# If rpc_ip is supplied, corresponding port to bind to for peer connections.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_user]
|
||||
#
|
||||
# As a server, require this user to be specified and require rpc_password to
|
||||
# be checked for RPC access via the rpc_ip and rpc_port. The user and password
|
||||
# must be specified via HTTP's basic authentication method.
|
||||
# As a client, supply this to the server via HTTP's basic authentication
|
||||
# method.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_password]
|
||||
#
|
||||
# As a server, require this password to be specified and require rpc_user to
|
||||
# be checked for RPC access via the rpc_ip and rpc_port. The user and password
|
||||
# must be specified via HTTP's basic authentication method.
|
||||
# As a client, supply this to the server via HTTP's basic authentication
|
||||
# method.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_startup]
|
||||
#
|
||||
# Specify a list of RPC commands to run at startup.
|
||||
#
|
||||
# Examples:
|
||||
# { "command" : "server_info" }
|
||||
# { "command" : "log_level", "partition" : "ripplecalc", "severity" : "trace" }
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_secure]
|
||||
#
|
||||
# 0 or 1.
|
||||
#
|
||||
# 0: Server certificates are not provided for RPC clients using SSL [default]
|
||||
# 1: Client RPC connections wil be provided with SSL certificates.
|
||||
#
|
||||
# Note that if rpc_secure is enabled, it will also be necessary to configure
|
||||
# the certificate file settings located in rpc_ssl_cert, rpc_ssl_chain, and
|
||||
# rpc_ssl_key
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_ssl_cert]
|
||||
#
|
||||
# <pathname>
|
||||
#
|
||||
# A file system path leading to the SSL certificate file to use for secure
|
||||
# RPC. The file is in PEM format. The file is not needed if the chain
|
||||
# includes it.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_ssl_chain]
|
||||
#
|
||||
# <pathname>
|
||||
#
|
||||
# A file system path leading to the file with the certificate chain.
|
||||
# The chain may include the end certificate.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [rpc_ssl_key]
|
||||
#
|
||||
# <pathname>
|
||||
#
|
||||
# A file system path leading to the file with the SSL key.
|
||||
# The file is in PEM format.
|
||||
#
|
||||
#
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 4. SMS Gateway
|
||||
# 3. SMS Gateway
|
||||
#
|
||||
#---------------
|
||||
#
|
||||
@@ -467,9 +440,9 @@
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 5. Ripple Protocol
|
||||
# 4. Ripple Protocol
|
||||
#
|
||||
#------------------
|
||||
#-------------------
|
||||
#
|
||||
# These settings affect the behavior of the server instance with respect
|
||||
# to Ripple payment protocol level activities such as validating and
|
||||
@@ -508,6 +481,13 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
# [ledger_history_index]
|
||||
#
|
||||
# If set to greater than 0, the index number of the earliest ledger to
|
||||
# acquire.
|
||||
#
|
||||
#
|
||||
#
|
||||
# [fetch_depth]
|
||||
#
|
||||
# The number of past ledgers to serve to other peers that request historical
|
||||
@@ -611,7 +591,7 @@
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 6. HTTPS Client
|
||||
# 5. HTTPS Client
|
||||
#
|
||||
#----------------
|
||||
#
|
||||
@@ -625,7 +605,9 @@
|
||||
# 0 or 1.
|
||||
#
|
||||
# 0. HTTPS client connections will not verify certificates.
|
||||
# 1. Certificates will be checked for HTTPS client connections .
|
||||
# 1. Certificates will be checked for HTTPS client connections.
|
||||
#
|
||||
# If not specified, this parameter defaults to 1.
|
||||
#
|
||||
#
|
||||
#
|
||||
@@ -651,7 +633,7 @@
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 7. Database
|
||||
# 6. Database
|
||||
#
|
||||
#------------
|
||||
#
|
||||
@@ -690,16 +672,24 @@
|
||||
#
|
||||
# Choices for 'type' (not case-sensitive)
|
||||
# RocksDB Use Facebook's RocksDB database (preferred)
|
||||
# HyperLevelDB Use an improved version of LevelDB
|
||||
# SQLite Use SQLite
|
||||
# LevelDB Use Google's LevelDB database (deprecated)
|
||||
# none Use no backend
|
||||
# NuDB Use Ripple Labs' NuDB (Windows preferred)
|
||||
# HyperLevelDB (Deprecated)
|
||||
# SQLite (Deprecated)
|
||||
# LevelDB (Deprecated)
|
||||
# none (No backend)
|
||||
#
|
||||
# Required keys:
|
||||
# path Location to store the database (all types)
|
||||
#
|
||||
# Optional keys:
|
||||
# compression 0 for none, 1 for Snappy compression
|
||||
# online_delete Minimum value of 256. Enable automatic purging
|
||||
# of older ledger information. Maintain at least this
|
||||
# number of ledger records online. Must be greater
|
||||
# than or equal to ledger_history.
|
||||
# advisory_delete 0 for disabled, 1 for enabled. If set, then
|
||||
# require administrative RPC call "can_delete"
|
||||
# to enable online deletion of ledger records.
|
||||
#
|
||||
# Notes:
|
||||
# The 'node_db' entry configures the primary, persistent storage.
|
||||
@@ -724,7 +714,7 @@
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 8. Diagnostics
|
||||
# 7. Diagnostics
|
||||
#
|
||||
#---------------
|
||||
#
|
||||
@@ -780,7 +770,7 @@
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 9. Voting
|
||||
# 8. Voting
|
||||
#
|
||||
#----------
|
||||
#
|
||||
@@ -830,41 +820,84 @@
|
||||
# owner_reserve = 5000000 # 5 XRP
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
# Allow other peers to connect to this server.
|
||||
#
|
||||
[peer_ip]
|
||||
0.0.0.0
|
||||
|
||||
[peer_port]
|
||||
51235
|
||||
|
||||
# Allow untrusted clients to connect to this server.
|
||||
# 9. Example Settings
|
||||
#
|
||||
[websocket_public_ip]
|
||||
0.0.0.0
|
||||
|
||||
[websocket_public_port]
|
||||
5006
|
||||
|
||||
# Provide trusted websocket ADMIN access to the localhost.
|
||||
#--------------------
|
||||
#
|
||||
[websocket_ip]
|
||||
127.0.0.1
|
||||
|
||||
[websocket_port]
|
||||
6006
|
||||
|
||||
# Provide trusted json-rpc ADMIN access to the localhost.
|
||||
# Administrators can use these values as a starting poing for configuring
|
||||
# their instance of rippled, but each value should be checked to make sure
|
||||
# it meets the business requirements for the organization.
|
||||
#
|
||||
[rpc_ip]
|
||||
127.0.0.1
|
||||
# Server
|
||||
#
|
||||
# These example configuration settings create these ports:
|
||||
#
|
||||
# "peer"
|
||||
#
|
||||
# Peer protocol open to everyone. This is required to accept
|
||||
# incoming rippled connections. This does not affect automatic
|
||||
# or manual outgoing Peer protocol connections.
|
||||
#
|
||||
# "rpc"
|
||||
#
|
||||
# Administrative RPC commands over HTTPS, when originating from
|
||||
# the same machine (via the loopback adapter at 127.0.0.1).
|
||||
#
|
||||
# "wss_admin"
|
||||
#
|
||||
# Admin level API commands over Secure Websockets, when originating
|
||||
# from the same machine (via the loopback adapter at 127.0.0.1).
|
||||
#
|
||||
# This port is commented out but can be enabled by removing
|
||||
# the '#' from each corresponding line including the entry under [server]
|
||||
#
|
||||
# "wss_public"
|
||||
#
|
||||
# Guest level API commands over Secure Websockets, open to everyone.
|
||||
#
|
||||
# For HTTPS and Secure Websockets ports, if no certificate and key file
|
||||
# are specified then a self-signed certificate will be generated on startup.
|
||||
# If you have a certificate and key file, uncomment the corresponding lines
|
||||
# and ensure the paths to the files are correct.
|
||||
#
|
||||
# NOTE
|
||||
#
|
||||
# To accept connections on well known ports such as 80 (HTTP) or
|
||||
# 443 (HTTPS), most operating systems will require rippled to
|
||||
# run with administrator privileges, or else rippled will not start.
|
||||
|
||||
[rpc_port]
|
||||
5005
|
||||
[server]
|
||||
port_rpc
|
||||
port_peer
|
||||
port_wss_admin
|
||||
#port_ws_public
|
||||
#ssl_key = /etc/ssl/private/server.key
|
||||
#ssl_cert = /etc/ssl/certs/server.crt
|
||||
|
||||
[rpc_allow_remote]
|
||||
0
|
||||
[port_rpc]
|
||||
port = 5005
|
||||
ip = 127.0.0.1
|
||||
admin = allow
|
||||
protocol = https
|
||||
|
||||
[port_peer]
|
||||
port = 51235
|
||||
ip = 0.0.0.0
|
||||
protocol = peer
|
||||
|
||||
[port_wss_admin]
|
||||
port = 6006
|
||||
ip = 127.0.0.1
|
||||
admin = allow
|
||||
protocol = wss
|
||||
|
||||
#[port_ws_public]
|
||||
#port = 5005
|
||||
#ip = 127.0.0.1
|
||||
#protocol = wss
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
[node_size]
|
||||
medium
|
||||
@@ -872,6 +905,8 @@ medium
|
||||
# This is primary persistent datastore for rippled. This includes transaction
|
||||
# metadata, account states, and ledger headers. Helpful information can be
|
||||
# found here: https://ripple.com/wiki/NodeBackEnd
|
||||
# delete old ledgers while maintaining at least 2000. Do not require an
|
||||
# external administrative command to initiate deletion.
|
||||
[node_db]
|
||||
type=RocksDB
|
||||
path=/var/lib/rippled/db/rocksdb
|
||||
@@ -880,6 +915,8 @@ filter_bits=12
|
||||
cache_mb=256
|
||||
file_size_mb=8
|
||||
file_size_mult=2
|
||||
online_delete=2000
|
||||
advisory_delete=0
|
||||
|
||||
[database_path]
|
||||
/var/lib/rippled/db
|
||||
@@ -919,22 +956,7 @@ n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA RL5
|
||||
[rpc_startup]
|
||||
{ "command": "log_level", "severity": "warning" }
|
||||
|
||||
# Configure SSL for WebSockets. Not enabled by default because not everybody
|
||||
# has an SSL cert on their server, but if you uncomment the following lines and
|
||||
# set the path to the SSL certificate and private key the WebSockets protocol
|
||||
# will be protected by SSL/TLS.
|
||||
#[websocket_secure]
|
||||
#1
|
||||
|
||||
#[websocket_ssl_cert]
|
||||
#/etc/ssl/certs/server.crt
|
||||
|
||||
#[websocket_ssl_key]
|
||||
#/etc/ssl/private/server.key
|
||||
|
||||
# Defaults to 0 ("no") so that you can use self-signed SSL certificates for
|
||||
# development, or internally.
|
||||
# Defaults to 1 ("yes") so that certificates will be validated. To allow the use
|
||||
# of self-signed certificates for development or internal use, set to 0 ("no").
|
||||
#[ssl_verify]
|
||||
#0
|
||||
|
||||
|
||||
|
||||
BIN
images/build.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
images/contribute.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
images/network.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
images/pathfinding.png
Normal file
|
After Width: | Height: | Size: 77 KiB |
BIN
images/ripple.png
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
images/transact.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
images/vehicle_currency.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
@@ -66,17 +66,6 @@
|
||||
//#define BEAST_CHECK_MEMORY_LEAKS 0
|
||||
#endif
|
||||
|
||||
/** Config: BEAST_COMPILER_CHECKS_SOCKET_OVERRIDES
|
||||
Setting this option makes Socket-derived classes generate compile errors
|
||||
if they forget any of the virtual overrides As some Socket-derived classes
|
||||
intentionally omit member functions that are not applicable, this macro
|
||||
should only be enabled temporarily when writing your own Socket-derived
|
||||
class, to make sure that the function signatures match as expected.
|
||||
*/
|
||||
#ifndef BEAST_COMPILER_CHECKS_SOCKET_OVERRIDES
|
||||
//#define BEAST_COMPILER_CHECKS_SOCKET_OVERRIDES 1
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Libraries
|
||||
@@ -208,17 +197,18 @@
|
||||
#define RIPPLE_SINGLE_IO_SERVICE_THREAD 0
|
||||
#endif
|
||||
|
||||
/** Config: RIPPLE_STRUCTURED_OVERLAY_CLIENT
|
||||
RIPPLE_STRUCTURED_OVERLAY_SERVER
|
||||
Enables Structured Overlay support for the client or server roles.
|
||||
This feature is currently in development:
|
||||
https://ripplelabs.atlassian.net/browse/RIPD-157
|
||||
/** Config: RIPPLE_HOOK_VALIDATORS
|
||||
Activates code for handling validations and validators (work in progress).
|
||||
*/
|
||||
#ifndef RIPPLE_STRUCTURED_OVERLAY_CLIENT
|
||||
#define RIPPLE_STRUCTURED_OVERLAY_CLIENT 0
|
||||
#ifndef RIPPLE_HOOK_VALIDATORS
|
||||
#define RIPPLE_HOOK_VALIDATORS 0
|
||||
#endif
|
||||
#ifndef RIPPLE_STRUCTURED_OVERLAY_SERVER
|
||||
#define RIPPLE_STRUCTURED_OVERLAY_SERVER 1
|
||||
|
||||
/** Config: RIPPLE_ENABLE_TICKETS
|
||||
Enables processing of ticket transactions
|
||||
*/
|
||||
#ifndef RIPPLE_ENABLE_TICKETS
|
||||
#define RIPPLE_ENABLE_TICKETS 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -64,17 +64,6 @@
|
||||
//#define BEAST_CHECK_MEMORY_LEAKS 0
|
||||
#endif
|
||||
|
||||
/** Config: BEAST_COMPILER_CHECKS_SOCKET_OVERRIDES
|
||||
Setting this option makes Socket-derived classes generate compile errors
|
||||
if they forget any of the virtual overrides As some Socket-derived classes
|
||||
intentionally omit member functions that are not applicable, this macro
|
||||
should only be enabled temporarily when writing your own Socket-derived
|
||||
class, to make sure that the function signatures match as expected.
|
||||
*/
|
||||
#ifndef BEAST_COMPILER_CHECKS_SOCKET_OVERRIDES
|
||||
//#define BEAST_COMPILER_CHECKS_SOCKET_OVERRIDES 1
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Libraries
|
||||
|
||||
@@ -1,429 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.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_ATOMIC_H_INCLUDED
|
||||
#define BEAST_ATOMIC_H_INCLUDED
|
||||
|
||||
#include <beast/Config.h>
|
||||
|
||||
#include <beast/utility/noexcept.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace beast {
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Simple class to hold a primitive value and perform atomic operations on it.
|
||||
|
||||
The type used must be a 32 or 64 bit primitive, like an int, pointer, etc.
|
||||
There are methods to perform most of the basic atomic operations.
|
||||
*/
|
||||
template <typename Type>
|
||||
class Atomic
|
||||
{
|
||||
// This class can only be used for types which are 32 or 64 bits in size.
|
||||
static_assert (sizeof (Type) == 4 || sizeof (Type) == 8,
|
||||
"Atomic arguments must be 32- or 64-bit long primitive types.");
|
||||
|
||||
public:
|
||||
/** Creates a new value, initialised to zero. */
|
||||
inline Atomic() noexcept
|
||||
: value (0)
|
||||
{
|
||||
}
|
||||
|
||||
/** Creates a new value, with a given initial value. */
|
||||
inline Atomic (const Type initialValue) noexcept
|
||||
: value (initialValue)
|
||||
{
|
||||
}
|
||||
|
||||
/** Copies another value (atomically). */
|
||||
inline Atomic (const Atomic& other) noexcept
|
||||
: value (other.get())
|
||||
{
|
||||
}
|
||||
|
||||
/** Destructor. */
|
||||
inline ~Atomic() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
/** Atomically reads and returns the current value. */
|
||||
Type get() const noexcept;
|
||||
|
||||
/** Copies another value onto this one (atomically). */
|
||||
Atomic& operator= (const Atomic& other) noexcept
|
||||
{ exchange (other.get()); return *this; }
|
||||
|
||||
/** Copies another value onto this one (atomically). */
|
||||
Atomic& operator= (const Type newValue) noexcept
|
||||
{ exchange (newValue); return *this; }
|
||||
|
||||
/** Atomically sets the current value. */
|
||||
void set (Type newValue) noexcept
|
||||
{ exchange (newValue); }
|
||||
|
||||
/** Atomically sets the current value, returning the value that was replaced. */
|
||||
Type exchange (Type value) noexcept;
|
||||
|
||||
/** Atomically adds a number to this value, returning the new value. */
|
||||
Type operator+= (Type amountToAdd) noexcept;
|
||||
|
||||
/** Atomically subtracts a number from this value, returning the new value. */
|
||||
Type operator-= (Type amountToSubtract) noexcept;
|
||||
|
||||
/** Atomically increments this value, returning the new value. */
|
||||
Type operator++() noexcept;
|
||||
|
||||
/** Atomically decrements this value, returning the new value. */
|
||||
Type operator--() noexcept;
|
||||
|
||||
/** Atomically compares this value with a target value, and if it is equal, sets
|
||||
this to be equal to a new value.
|
||||
|
||||
This operation is the atomic equivalent of doing this:
|
||||
@code
|
||||
bool compareAndSetBool (Type newValue, Type valueToCompare)
|
||||
{
|
||||
if (get() == valueToCompare)
|
||||
{
|
||||
set (newValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@endcode
|
||||
|
||||
@returns true if the comparison was true and the value was replaced; false if
|
||||
the comparison failed and the value was left unchanged.
|
||||
@see compareAndSetValue
|
||||
*/
|
||||
bool compareAndSetBool (Type newValue, Type valueToCompare) noexcept;
|
||||
|
||||
/** Atomically compares this value with a target value, and if it is equal, sets
|
||||
this to be equal to a new value.
|
||||
|
||||
This operation is the atomic equivalent of doing this:
|
||||
@code
|
||||
Type compareAndSetValue (Type newValue, Type valueToCompare)
|
||||
{
|
||||
Type oldValue = get();
|
||||
if (oldValue == valueToCompare)
|
||||
set (newValue);
|
||||
|
||||
return oldValue;
|
||||
}
|
||||
@endcode
|
||||
|
||||
@returns the old value before it was changed.
|
||||
@see compareAndSetBool
|
||||
*/
|
||||
Type compareAndSetValue (Type newValue, Type valueToCompare) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
#if BEAST_64BIT
|
||||
BEAST_ALIGN (8)
|
||||
#else
|
||||
BEAST_ALIGN (4)
|
||||
#endif
|
||||
|
||||
/** The raw value that this class operates on.
|
||||
This is exposed publically in case you need to manipulate it directly
|
||||
for performance reasons.
|
||||
*/
|
||||
volatile Type value;
|
||||
|
||||
private:
|
||||
template <typename Dest, typename Source>
|
||||
static inline Dest castTo (Source value) noexcept { union { Dest d; Source s; } u; u.s = value; return u.d; }
|
||||
|
||||
static inline Type castFrom32Bit (std::int32_t value) noexcept { return castTo <Type, std::int32_t> (value); }
|
||||
static inline Type castFrom64Bit (std::int64_t value) noexcept { return castTo <Type, std::int64_t> (value); }
|
||||
static inline std::int32_t castTo32Bit (Type value) noexcept { return castTo <std::int32_t, Type> (value); }
|
||||
static inline std::int64_t castTo64Bit (Type value) noexcept { return castTo <std::int64_t, Type> (value); }
|
||||
|
||||
|
||||
Type operator++ (int); // better to just use pre-increment with atomics..
|
||||
Type operator-- (int);
|
||||
|
||||
/** This templated negate function will negate pointers as well as integers */
|
||||
template <typename ValueType>
|
||||
inline ValueType negateValue (ValueType n) noexcept
|
||||
{
|
||||
return sizeof (ValueType) == 1 ? (ValueType) -(signed char) n
|
||||
: (sizeof (ValueType) == 2 ? (ValueType) -(short) n
|
||||
: (sizeof (ValueType) == 4 ? (ValueType) -(int) n
|
||||
: ((ValueType) -(std::int64_t) n)));
|
||||
}
|
||||
|
||||
/** This templated negate function will negate pointers as well as integers */
|
||||
template <typename PointerType>
|
||||
inline PointerType* negateValue (PointerType* n) noexcept
|
||||
{
|
||||
return reinterpret_cast <PointerType*> (-reinterpret_cast <std::intptr_t> (n));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/*
|
||||
The following code is in the header so that the atomics can be inlined where possible...
|
||||
*/
|
||||
#if BEAST_IOS || (BEAST_MAC && (BEAST_PPC || BEAST_CLANG || __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2)))
|
||||
#define BEAST_ATOMICS_MAC 1 // Older OSX builds using gcc4.1 or earlier
|
||||
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
|
||||
#define BEAST_MAC_ATOMICS_VOLATILE
|
||||
#else
|
||||
#define BEAST_MAC_ATOMICS_VOLATILE volatile
|
||||
#endif
|
||||
|
||||
#if BEAST_PPC || BEAST_IOS
|
||||
// None of these atomics are available for PPC or for iOS 3.1 or earlier!!
|
||||
template <typename Type> static Type OSAtomicAdd64Barrier (Type b, BEAST_MAC_ATOMICS_VOLATILE Type* a) noexcept { bassertfalse; return *a += b; }
|
||||
template <typename Type> static Type OSAtomicIncrement64Barrier (BEAST_MAC_ATOMICS_VOLATILE Type* a) noexcept { bassertfalse; return ++*a; }
|
||||
template <typename Type> static Type OSAtomicDecrement64Barrier (BEAST_MAC_ATOMICS_VOLATILE Type* a) noexcept { bassertfalse; return --*a; }
|
||||
template <typename Type> static bool OSAtomicCompareAndSwap64Barrier (Type old, Type newValue, BEAST_MAC_ATOMICS_VOLATILE Type* value) noexcept
|
||||
{ bassertfalse; if (old == *value) { *value = newValue; return true; } return false; }
|
||||
#define BEAST_64BIT_ATOMICS_UNAVAILABLE 1
|
||||
#endif
|
||||
|
||||
#elif BEAST_CLANG && BEAST_LINUX
|
||||
#define BEAST_ATOMICS_GCC 1
|
||||
|
||||
//==============================================================================
|
||||
#elif BEAST_GCC
|
||||
#define BEAST_ATOMICS_GCC 1 // GCC with intrinsics
|
||||
|
||||
#if BEAST_IOS || BEAST_ANDROID // (64-bit ops will compile but not link on these mobile OSes)
|
||||
#define BEAST_64BIT_ATOMICS_UNAVAILABLE 1
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#else
|
||||
#define BEAST_ATOMICS_WINDOWS 1 // Windows with intrinsics
|
||||
|
||||
#if BEAST_USE_INTRINSICS
|
||||
#ifndef __INTEL_COMPILER
|
||||
#pragma intrinsic (_InterlockedExchange, _InterlockedIncrement, _InterlockedDecrement, _InterlockedCompareExchange, \
|
||||
_InterlockedCompareExchange64, _InterlockedExchangeAdd, _ReadWriteBarrier)
|
||||
#endif
|
||||
#define beast_InterlockedExchange(a, b) _InterlockedExchange(a, b)
|
||||
#define beast_InterlockedIncrement(a) _InterlockedIncrement(a)
|
||||
#define beast_InterlockedDecrement(a) _InterlockedDecrement(a)
|
||||
#define beast_InterlockedExchangeAdd(a, b) _InterlockedExchangeAdd(a, b)
|
||||
#define beast_InterlockedCompareExchange(a, b, c) _InterlockedCompareExchange(a, b, c)
|
||||
#define beast_InterlockedCompareExchange64(a, b, c) _InterlockedCompareExchange64(a, b, c)
|
||||
#define beast_MemoryBarrier _ReadWriteBarrier
|
||||
#else
|
||||
long beast_InterlockedExchange (volatile long* a, long b) noexcept;
|
||||
long beast_InterlockedIncrement (volatile long* a) noexcept;
|
||||
long beast_InterlockedDecrement (volatile long* a) noexcept;
|
||||
long beast_InterlockedExchangeAdd (volatile long* a, long b) noexcept;
|
||||
long beast_InterlockedCompareExchange (volatile long* a, long b, long c) noexcept;
|
||||
__int64 beast_InterlockedCompareExchange64 (volatile __int64* a, __int64 b, __int64 c) noexcept;
|
||||
inline void beast_MemoryBarrier() noexcept { long x = 0; beast_InterlockedIncrement (&x); }
|
||||
#endif
|
||||
|
||||
#if BEAST_64BIT
|
||||
#ifndef __INTEL_COMPILER
|
||||
#pragma intrinsic (_InterlockedExchangeAdd64, _InterlockedExchange64, _InterlockedIncrement64, _InterlockedDecrement64)
|
||||
#endif
|
||||
#define beast_InterlockedExchangeAdd64(a, b) _InterlockedExchangeAdd64(a, b)
|
||||
#define beast_InterlockedExchange64(a, b) _InterlockedExchange64(a, b)
|
||||
#define beast_InterlockedIncrement64(a) _InterlockedIncrement64(a)
|
||||
#define beast_InterlockedDecrement64(a) _InterlockedDecrement64(a)
|
||||
#else
|
||||
// None of these atomics are available in a 32-bit Windows build!!
|
||||
template <typename Type> static Type beast_InterlockedExchangeAdd64 (volatile Type* a, Type b) noexcept { bassertfalse; Type old = *a; *a += b; return old; }
|
||||
template <typename Type> static Type beast_InterlockedExchange64 (volatile Type* a, Type b) noexcept { bassertfalse; Type old = *a; *a = b; return old; }
|
||||
template <typename Type> static Type beast_InterlockedIncrement64 (volatile Type* a) noexcept { bassertfalse; return ++*a; }
|
||||
template <typename Type> static Type beast_InterlockedDecrement64 (volatile Type* a) noexcept { bassertfalse; return --*a; }
|
||||
#define BEAST_64BIT_ATOMICS_UNAVAILABLE 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if BEAST_MSVC
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4311) // (truncation warning)
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::get() const noexcept
|
||||
{
|
||||
#if BEAST_ATOMICS_MAC
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((std::int32_t) OSAtomicAdd32Barrier ((int32_t) 0, (BEAST_MAC_ATOMICS_VOLATILE int32_t*) &value))
|
||||
: castFrom64Bit ((std::int64_t) OSAtomicAdd64Barrier ((int64_t) 0, (BEAST_MAC_ATOMICS_VOLATILE int64_t*) &value));
|
||||
#elif BEAST_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((std::int32_t) beast_InterlockedExchangeAdd ((volatile long*) &value, (long) 0))
|
||||
: castFrom64Bit ((std::int64_t) beast_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) 0));
|
||||
#elif BEAST_ATOMICS_GCC
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((std::int32_t) __sync_add_and_fetch ((volatile std::int32_t*) &value, 0))
|
||||
: castFrom64Bit ((std::int64_t) __sync_add_and_fetch ((volatile std::int64_t*) &value, 0));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::exchange (const Type newValue) noexcept
|
||||
{
|
||||
#if BEAST_ATOMICS_MAC || BEAST_ATOMICS_GCC
|
||||
Type currentVal = value;
|
||||
while (! compareAndSetBool (newValue, currentVal)) { currentVal = value; }
|
||||
return currentVal;
|
||||
#elif BEAST_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((std::int32_t) beast_InterlockedExchange ((volatile long*) &value, (long) castTo32Bit (newValue)))
|
||||
: castFrom64Bit ((std::int64_t) beast_InterlockedExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue)));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::operator+= (const Type amountToAdd) noexcept
|
||||
{
|
||||
#if BEAST_ATOMICS_MAC
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wint-to-void-pointer-cast"
|
||||
# pragma clang diagnostic ignored "-Wint-to-pointer-cast"
|
||||
# endif
|
||||
return sizeof (Type) == 4 ? (Type) OSAtomicAdd32Barrier ((int32_t) castTo32Bit (amountToAdd), (BEAST_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||
: (Type) OSAtomicAdd64Barrier ((int64_t) amountToAdd, (BEAST_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
# endif
|
||||
#elif BEAST_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? (Type) (beast_InterlockedExchangeAdd ((volatile long*) &value, (long) amountToAdd) + (long) amountToAdd)
|
||||
: (Type) (beast_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) amountToAdd) + (__int64) amountToAdd);
|
||||
#elif BEAST_ATOMICS_GCC
|
||||
return (Type) __sync_add_and_fetch (&value, amountToAdd);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::operator-= (const Type amountToSubtract) noexcept
|
||||
{
|
||||
return operator+= (negateValue (amountToSubtract));
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::operator++() noexcept
|
||||
{
|
||||
#if BEAST_ATOMICS_MAC
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wint-to-void-pointer-cast"
|
||||
# pragma clang diagnostic ignored "-Wint-to-pointer-cast"
|
||||
# endif
|
||||
return sizeof (Type) == 4 ? (Type) OSAtomicIncrement32Barrier ((BEAST_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||
: (Type) OSAtomicIncrement64Barrier ((BEAST_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
# endif
|
||||
#elif BEAST_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? (Type) beast_InterlockedIncrement ((volatile long*) &value)
|
||||
: (Type) beast_InterlockedIncrement64 ((volatile __int64*) &value);
|
||||
#elif BEAST_ATOMICS_GCC
|
||||
return (Type) __sync_add_and_fetch (&value, (Type) 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::operator--() noexcept
|
||||
{
|
||||
#if BEAST_ATOMICS_MAC
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wint-to-void-pointer-cast"
|
||||
# pragma clang diagnostic ignored "-Wint-to-pointer-cast"
|
||||
# endif
|
||||
return sizeof (Type) == 4 ? (Type) OSAtomicDecrement32Barrier ((BEAST_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||
: (Type) OSAtomicDecrement64Barrier ((BEAST_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
# endif
|
||||
#elif BEAST_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? (Type) beast_InterlockedDecrement ((volatile long*) &value)
|
||||
: (Type) beast_InterlockedDecrement64 ((volatile __int64*) &value);
|
||||
#elif BEAST_ATOMICS_GCC
|
||||
return (Type) __sync_add_and_fetch (&value, (Type) -1);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline bool Atomic<Type>::compareAndSetBool (const Type newValue, const Type valueToCompare) noexcept
|
||||
{
|
||||
#if BEAST_ATOMICS_MAC
|
||||
return sizeof (Type) == 4 ? OSAtomicCompareAndSwap32Barrier ((int32_t) castTo32Bit (valueToCompare), (int32_t) castTo32Bit (newValue), (BEAST_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||
: OSAtomicCompareAndSwap64Barrier ((int64_t) castTo64Bit (valueToCompare), (int64_t) castTo64Bit (newValue), (BEAST_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||
#elif BEAST_ATOMICS_WINDOWS
|
||||
return compareAndSetValue (newValue, valueToCompare) == valueToCompare;
|
||||
#elif BEAST_ATOMICS_GCC
|
||||
return sizeof (Type) == 4 ? __sync_bool_compare_and_swap ((volatile std::int32_t*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue))
|
||||
: __sync_bool_compare_and_swap ((volatile std::int64_t*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type Atomic<Type>::compareAndSetValue (const Type newValue, const Type valueToCompare) noexcept
|
||||
{
|
||||
#if BEAST_ATOMICS_MAC
|
||||
for (;;) // Annoying workaround for only having a bool CAS operation..
|
||||
{
|
||||
if (compareAndSetBool (newValue, valueToCompare))
|
||||
return valueToCompare;
|
||||
|
||||
const Type result = value;
|
||||
if (result != valueToCompare)
|
||||
return result;
|
||||
}
|
||||
|
||||
#elif BEAST_ATOMICS_WINDOWS
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((std::int32_t) beast_InterlockedCompareExchange ((volatile long*) &value, (long) castTo32Bit (newValue), (long) castTo32Bit (valueToCompare)))
|
||||
: castFrom64Bit ((std::int64_t) beast_InterlockedCompareExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue), (__int64) castTo64Bit (valueToCompare)));
|
||||
#elif BEAST_ATOMICS_GCC
|
||||
return sizeof (Type) == 4 ? castFrom32Bit ((std::int32_t) __sync_val_compare_and_swap ((volatile std::int32_t*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue)))
|
||||
: castFrom64Bit ((std::int64_t) __sync_val_compare_and_swap ((volatile std::int64_t*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue)));
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void memoryBarrier() noexcept
|
||||
{
|
||||
#if BEAST_ATOMICS_MAC
|
||||
OSMemoryBarrier();
|
||||
#elif BEAST_ATOMICS_GCC
|
||||
__sync_synchronize();
|
||||
#elif BEAST_ATOMICS_WINDOWS
|
||||
beast_MemoryBarrier();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if BEAST_MSVC
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -26,9 +26,6 @@
|
||||
|
||||
// VFALCO NOTE this is analogous to <boost/config.hpp>
|
||||
|
||||
// Assert to boost that we always have std::array support
|
||||
#define BOOST_ASIO_HAS_STD_ARRAY 1
|
||||
|
||||
#if !defined(BEAST_COMPILER_CONFIG) && !defined(BEAST_NO_COMPILER_CONFIG) && !defined(BEAST_NO_CONFIG)
|
||||
#include <beast/config/SelectCompilerConfig.h>
|
||||
#endif
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#ifndef BEAST_CRYPTO_H_INCLUDED
|
||||
#define BEAST_CRYPTO_H_INCLUDED
|
||||
|
||||
#include <beast/crypto/MurmurHash.h>
|
||||
#include <beast/crypto/Sha256.h>
|
||||
|
||||
#endif
|
||||
|
||||
@@ -25,11 +25,9 @@
|
||||
#include <beast/threads/SharedLockGuard.h>
|
||||
#include <beast/threads/SharedMutexAdapter.h>
|
||||
#include <beast/threads/SharedData.h>
|
||||
#include <beast/threads/ServiceQueue.h>
|
||||
#include <beast/threads/SpinLock.h>
|
||||
#include <beast/threads/Stoppable.h>
|
||||
#include <beast/threads/Thread.h>
|
||||
#include <beast/threads/ThreadLocalValue.h>
|
||||
#include <beast/threads/WaitableEvent.h>
|
||||
#include <beast/threads/ScopedWrapperContext.h>
|
||||
|
||||
|
||||
@@ -23,4 +23,5 @@
|
||||
|
||||
#include <beast/asio/impl/IPAddressConversion.cpp>
|
||||
#include <beast/asio/tests/bind_handler.test.cpp>
|
||||
#include <beast/asio/tests/streambuf.test.cpp>
|
||||
|
||||
|
||||
@@ -21,7 +21,9 @@
|
||||
#define BEAST_ASIO_SSL_BUNDLE_H_INCLUDED
|
||||
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/ssl/context.hpp>
|
||||
#include <boost/asio/ssl/stream.hpp>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
@@ -33,21 +35,33 @@ namespace asio {
|
||||
*/
|
||||
struct ssl_bundle
|
||||
{
|
||||
typedef boost::asio::ip::tcp::socket socket_type;
|
||||
typedef boost::asio::ssl::stream <socket_type&> stream_type;
|
||||
using socket_type = boost::asio::ip::tcp::socket;
|
||||
using stream_type = boost::asio::ssl::stream <socket_type&>;
|
||||
using shared_context = std::shared_ptr<boost::asio::ssl::context>;
|
||||
|
||||
template <class... Args>
|
||||
ssl_bundle (boost::asio::ssl::context& context, Args&&... args);
|
||||
ssl_bundle (shared_context const& context_, Args&&... args);
|
||||
|
||||
// DEPRECATED
|
||||
template <class... Args>
|
||||
ssl_bundle (boost::asio::ssl::context& context_, Args&&... args);
|
||||
|
||||
shared_context context;
|
||||
socket_type socket;
|
||||
stream_type stream;
|
||||
};
|
||||
|
||||
template <class... Args>
|
||||
ssl_bundle::ssl_bundle (boost::asio::ssl::context& context,
|
||||
Args&&... args)
|
||||
ssl_bundle::ssl_bundle (shared_context const& context_, Args&&... args)
|
||||
: socket(std::forward<Args>(args)...)
|
||||
, stream (socket, context)
|
||||
, stream (socket, *context_)
|
||||
{
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
ssl_bundle::ssl_bundle (boost::asio::ssl::context& context_, Args&&... args)
|
||||
: socket(std::forward<Args>(args)...)
|
||||
, stream (socket, context_)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
679
src/beast/beast/asio/streambuf.h
Normal file
@@ -0,0 +1,679 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, 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_ASIO_STREAMBUF_H_INCLUDED
|
||||
#define BEAST_ASIO_STREAMBUF_H_INCLUDED
|
||||
|
||||
#include <beast/utility/empty_base_optimization.h>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include <boost/iterator/transform_iterator.hpp>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <exception>
|
||||
#include <beast/cxx14/type_traits.h> // <type_traits>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace asio {
|
||||
|
||||
/** Implements asio::streambuf interface using multiple buffers. */
|
||||
template <class Allocator>
|
||||
class basic_streambuf
|
||||
: private empty_base_optimization<Allocator>
|
||||
{
|
||||
public:
|
||||
using size_type = typename std::allocator_traits<Allocator>::size_type;
|
||||
using const_buffer = boost::asio::const_buffer;
|
||||
using mutable_buffer = boost::asio::mutable_buffer;
|
||||
|
||||
private:
|
||||
class element;
|
||||
|
||||
using alloc_traits = std::allocator_traits<Allocator>;
|
||||
using list_type = typename boost::intrusive::make_list <element,
|
||||
boost::intrusive::constant_time_size <true>>::type;
|
||||
using iterator = typename list_type::iterator;
|
||||
using const_iterator = typename list_type::const_iterator;
|
||||
|
||||
/* These diagrams illustrate the layout and state variables.
|
||||
|
||||
Input and output contained entirely in one element:
|
||||
|
||||
0 out_
|
||||
|<-------------+------------------------------------------->|
|
||||
in_pos_ out_pos_ out_end_
|
||||
|
||||
|
||||
Output contained in first and second elements:
|
||||
|
||||
out_
|
||||
|<------+----------+------->| |<----------+-------------->|
|
||||
in_pos_ out_pos_ out_end_
|
||||
|
||||
|
||||
Output contained in the second element:
|
||||
|
||||
out_
|
||||
|<------------+------------>| |<----+-------------------->|
|
||||
in_pos_ out_pos_ out_end_
|
||||
|
||||
|
||||
Output contained in second and third elements:
|
||||
|
||||
out_
|
||||
|<-----+-------->| |<-------+------>| |<--------------->|
|
||||
in_pos_ out_pos_ out_end_
|
||||
|
||||
|
||||
Input sequence is empty:
|
||||
|
||||
out_
|
||||
|<------+------------------>| |<-----------+------------->|
|
||||
out_pos_ out_end_
|
||||
in_pos_
|
||||
|
||||
|
||||
Output sequence is empty:
|
||||
|
||||
out_
|
||||
|<------+------------------>| |<------+------------------>|
|
||||
in_pos_ out_pos_
|
||||
out_end_
|
||||
|
||||
|
||||
The end of output can point to the end of an element.
|
||||
But out_pos_ should never point to the end:
|
||||
|
||||
out_
|
||||
|<------+------------------>| |<------+------------------>|
|
||||
in_pos_ out_pos_ out_end_
|
||||
|
||||
|
||||
When the input sequence entirely fills the last element and
|
||||
the output sequence is empty, out_ will point to the end of
|
||||
the list of buffers, and out_pos_ and out_end_ will be 0:
|
||||
|
||||
|
||||
|<------+------------------>| out_ == list_.end()
|
||||
in_pos_ out_pos_ == 0
|
||||
out_end_ == 0
|
||||
*/
|
||||
|
||||
list_type list_;
|
||||
size_type block_size_;
|
||||
size_type block_size_next_;
|
||||
size_type in_size_ = 0; // size of the input sequence
|
||||
iterator out_; // element that contains out_pos_
|
||||
size_type in_pos_ = 0; // input offset in list_.front()
|
||||
size_type out_pos_ = 0; // output offset in *out_
|
||||
size_type out_end_ = 0; // output end offset in list_.back()
|
||||
|
||||
public:
|
||||
class const_buffers_type;
|
||||
class mutable_buffers_type;
|
||||
|
||||
basic_streambuf (basic_streambuf const& other) = delete;
|
||||
basic_streambuf& operator= (basic_streambuf const& other) = delete;
|
||||
basic_streambuf& operator= (basic_streambuf&& other) = delete;
|
||||
|
||||
~basic_streambuf();
|
||||
|
||||
explicit
|
||||
basic_streambuf(std::size_t block_size = 16*1024,
|
||||
Allocator const& alloc = Allocator{});
|
||||
|
||||
basic_streambuf (basic_streambuf&& other);
|
||||
|
||||
/** Get the maximum size of the basic_streambuf. */
|
||||
size_type
|
||||
max_size() const
|
||||
{
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
}
|
||||
|
||||
/** Get the size of the input sequence. */
|
||||
size_type
|
||||
size() const
|
||||
{
|
||||
return in_size_;
|
||||
}
|
||||
|
||||
/** Get a list of buffers that represents the output sequence, with the given size. */
|
||||
mutable_buffers_type
|
||||
prepare (size_type n);
|
||||
|
||||
/** Move bytes from the output sequence to the input sequence. */
|
||||
void
|
||||
commit (size_type n);
|
||||
|
||||
/** Get a list of buffers that represents the input sequence. */
|
||||
const_buffers_type
|
||||
data() const;
|
||||
|
||||
/** Remove bytes from the input sequence. */
|
||||
void
|
||||
consume (size_type n);
|
||||
|
||||
private:
|
||||
void
|
||||
debug_check() const;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class Allocator>
|
||||
class basic_streambuf<Allocator>::element
|
||||
: public boost::intrusive::list_base_hook <
|
||||
boost::intrusive::link_mode <boost::intrusive::normal_link>>
|
||||
{
|
||||
private:
|
||||
size_type const size_; // size of the allocation minus sizeof(element)
|
||||
|
||||
public:
|
||||
element (element const&) = delete;
|
||||
element& operator= (element const&) = delete;
|
||||
|
||||
explicit
|
||||
element (size_type block_size)
|
||||
: size_(block_size)
|
||||
{ }
|
||||
|
||||
size_type
|
||||
size() const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
size_type
|
||||
alloc_size() const
|
||||
{
|
||||
return size_ + sizeof(*this);
|
||||
}
|
||||
|
||||
char*
|
||||
data() const
|
||||
{
|
||||
return const_cast<char*>(
|
||||
reinterpret_cast<char const*>(this+1));
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class Allocator>
|
||||
class basic_streambuf<Allocator>::const_buffers_type
|
||||
{
|
||||
public:
|
||||
using value_type = const_buffer;
|
||||
|
||||
private:
|
||||
struct transform
|
||||
{
|
||||
using argument_type = element;
|
||||
using result_type = value_type;
|
||||
|
||||
basic_streambuf const* streambuf_ = nullptr;
|
||||
|
||||
transform() = default;
|
||||
|
||||
explicit
|
||||
transform (basic_streambuf const& streambuf)
|
||||
: streambuf_ (&streambuf)
|
||||
{
|
||||
}
|
||||
|
||||
value_type const
|
||||
operator() (element const& e) const;
|
||||
};
|
||||
|
||||
basic_streambuf const* streambuf_ = nullptr;
|
||||
|
||||
public:
|
||||
using const_iterator = boost::transform_iterator<
|
||||
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(*streambuf_));
|
||||
}
|
||||
|
||||
const_iterator
|
||||
end() const
|
||||
{
|
||||
return const_iterator (streambuf_->out_ ==
|
||||
streambuf_->list_.end() ? streambuf_->list_.end() :
|
||||
std::next(streambuf_->out_), transform(*streambuf_));
|
||||
}
|
||||
|
||||
private:
|
||||
friend class basic_streambuf;
|
||||
|
||||
explicit
|
||||
const_buffers_type (basic_streambuf const& streambuf);
|
||||
};
|
||||
|
||||
template <class Allocator>
|
||||
basic_streambuf<Allocator>::const_buffers_type::const_buffers_type (
|
||||
basic_streambuf const& streambuf)
|
||||
: streambuf_ (&streambuf)
|
||||
{
|
||||
}
|
||||
|
||||
template <class Allocator>
|
||||
auto
|
||||
basic_streambuf<Allocator>::const_buffers_type::
|
||||
transform::operator() (element const& e) const ->
|
||||
value_type const
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class Allocator>
|
||||
class basic_streambuf<Allocator>::mutable_buffers_type
|
||||
{
|
||||
public:
|
||||
using value_type = mutable_buffer;
|
||||
|
||||
private:
|
||||
struct transform
|
||||
{
|
||||
using argument_type = element;
|
||||
using result_type = value_type;
|
||||
|
||||
basic_streambuf const* streambuf_ = nullptr;
|
||||
|
||||
transform() = default;
|
||||
|
||||
explicit
|
||||
transform (basic_streambuf const& streambuf)
|
||||
: streambuf_ (&streambuf)
|
||||
{
|
||||
}
|
||||
|
||||
value_type const
|
||||
operator() (element const& e) const;
|
||||
};
|
||||
|
||||
basic_streambuf const* streambuf_;
|
||||
|
||||
public:
|
||||
using const_iterator = boost::transform_iterator<
|
||||
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(*streambuf_));
|
||||
}
|
||||
|
||||
const_iterator
|
||||
end() const
|
||||
{
|
||||
return const_iterator (streambuf_->list_.end(),
|
||||
transform(*streambuf_));
|
||||
}
|
||||
|
||||
private:
|
||||
friend class basic_streambuf;
|
||||
mutable_buffers_type (basic_streambuf const& streambuf);
|
||||
};
|
||||
|
||||
template <class Allocator>
|
||||
basic_streambuf<Allocator>::mutable_buffers_type::mutable_buffers_type (
|
||||
basic_streambuf const& streambuf)
|
||||
: streambuf_ (&streambuf)
|
||||
{
|
||||
}
|
||||
|
||||
template <class Allocator>
|
||||
auto
|
||||
basic_streambuf<Allocator>::mutable_buffers_type::
|
||||
transform::operator() (element const& e) const ->
|
||||
value_type const
|
||||
{
|
||||
return value_type (e.data(), &e == &*std::prev(streambuf_->list_.end()) ?
|
||||
streambuf_->out_end_ : e.size()) + (&e == &*streambuf_->out_ ?
|
||||
streambuf_->out_pos_ : 0);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class Allocator>
|
||||
basic_streambuf<Allocator>::~basic_streambuf()
|
||||
{
|
||||
for(auto iter = list_.begin(); iter != list_.end();)
|
||||
{
|
||||
auto& e = *iter++;
|
||||
size_type const n = e.alloc_size();
|
||||
alloc_traits::destroy(this->member(), &e);
|
||||
alloc_traits::deallocate(this->member(),
|
||||
reinterpret_cast<char*>(&e), n);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Allocator>
|
||||
basic_streambuf<Allocator>::basic_streambuf(std::size_t block_size,
|
||||
Allocator const& alloc)
|
||||
: empty_base_optimization<Allocator>(alloc)
|
||||
, block_size_ (block_size)
|
||||
, block_size_next_ (block_size)
|
||||
, out_ (list_.end())
|
||||
{
|
||||
if (! (block_size > 0))
|
||||
throw std::invalid_argument(
|
||||
"basic_streambuf: invalid block_size");
|
||||
}
|
||||
|
||||
template <class Allocator>
|
||||
basic_streambuf<Allocator>::basic_streambuf (basic_streambuf&& other)
|
||||
: empty_base_optimization<Allocator>(other.member())
|
||||
, list_ (std::move(other.list_))
|
||||
, block_size_ (other.block_size_)
|
||||
, block_size_next_ (other.block_size_next_)
|
||||
, in_size_ (other.in_size_)
|
||||
, out_ (other.out_)
|
||||
, in_pos_ (other.in_pos_)
|
||||
, out_pos_ (other.out_pos_)
|
||||
, out_end_ (other.out_end_)
|
||||
{
|
||||
other.in_size_ = 0;
|
||||
other.out_ = other.list_.end();
|
||||
other.in_pos_ = 0;
|
||||
other.out_pos_ = 0;
|
||||
other.out_end_ = 0;
|
||||
}
|
||||
|
||||
template <class Allocator>
|
||||
auto
|
||||
basic_streambuf<Allocator>::prepare (size_type n) ->
|
||||
mutable_buffers_type
|
||||
{
|
||||
iterator pos = out_;
|
||||
if (pos != list_.end())
|
||||
{
|
||||
auto const avail = pos->size() - out_pos_;
|
||||
if (n > avail)
|
||||
{
|
||||
n -= avail;
|
||||
while (++pos != list_.end())
|
||||
{
|
||||
if (n < pos->size())
|
||||
{
|
||||
out_end_ = n;
|
||||
n = 0;
|
||||
++pos;
|
||||
break;
|
||||
}
|
||||
n -= pos->size();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++pos;
|
||||
out_end_ = out_pos_ + n;
|
||||
n = 0;
|
||||
}
|
||||
debug_check();
|
||||
}
|
||||
|
||||
if (n > 0)
|
||||
{
|
||||
assert(pos == list_.end());
|
||||
for(;;)
|
||||
{
|
||||
auto const avail = block_size_next_;
|
||||
auto& e = *reinterpret_cast<element*>(alloc_traits::allocate(
|
||||
this->member(), avail + sizeof(element)));
|
||||
alloc_traits::construct(this->member(), &e, avail);
|
||||
list_.push_back(e);
|
||||
if (out_ == list_.end())
|
||||
{
|
||||
out_ = list_.iterator_to(e);
|
||||
debug_check();
|
||||
}
|
||||
if (n <= avail)
|
||||
{
|
||||
out_end_ = n;
|
||||
debug_check();
|
||||
break;
|
||||
}
|
||||
n -= avail;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (pos != list_.end())
|
||||
{
|
||||
auto& e = *pos++;
|
||||
list_.erase(list_.iterator_to(e));
|
||||
auto const len = e.alloc_size();
|
||||
alloc_traits::destroy(this->member(), &e);
|
||||
alloc_traits::deallocate(this->member(),
|
||||
reinterpret_cast<char*>(&e), len);
|
||||
}
|
||||
debug_check();
|
||||
}
|
||||
|
||||
return mutable_buffers_type (*this);
|
||||
}
|
||||
|
||||
template <class Allocator>
|
||||
void
|
||||
basic_streambuf<Allocator>::commit (size_type n)
|
||||
{
|
||||
if (list_.empty())
|
||||
return;
|
||||
if (out_ == list_.end())
|
||||
return;
|
||||
auto const last = std::prev(list_.end());
|
||||
while (out_ != last)
|
||||
{
|
||||
auto const avail =
|
||||
out_->size() - out_pos_;
|
||||
if (n < avail)
|
||||
{
|
||||
out_pos_ += n;
|
||||
in_size_ += n;
|
||||
debug_check();
|
||||
return;
|
||||
}
|
||||
++out_;
|
||||
n -= avail;
|
||||
out_pos_ = 0;
|
||||
in_size_ += avail;
|
||||
debug_check();
|
||||
}
|
||||
|
||||
n = std::min (n, out_end_ - out_pos_);
|
||||
out_pos_ += n;
|
||||
in_size_ += n;
|
||||
if (out_pos_ == out_->size())
|
||||
{
|
||||
++out_;
|
||||
out_pos_ = 0;
|
||||
out_end_ = 0;
|
||||
}
|
||||
debug_check();
|
||||
}
|
||||
|
||||
template <class Allocator>
|
||||
auto
|
||||
basic_streambuf<Allocator>::data() const ->
|
||||
const_buffers_type
|
||||
{
|
||||
return const_buffers_type(*this);
|
||||
}
|
||||
|
||||
template <class Allocator>
|
||||
void
|
||||
basic_streambuf<Allocator>::consume (size_type n)
|
||||
{
|
||||
if (list_.empty())
|
||||
return;
|
||||
|
||||
auto pos = list_.begin();
|
||||
for(;;)
|
||||
{
|
||||
if (pos != out_)
|
||||
{
|
||||
auto const avail = pos->size() - in_pos_;
|
||||
if (n < avail)
|
||||
{
|
||||
in_size_ -= n;
|
||||
in_pos_ += n;
|
||||
debug_check();
|
||||
break;
|
||||
}
|
||||
n -= avail;
|
||||
in_size_ -= avail;
|
||||
in_pos_ = 0;
|
||||
debug_check();
|
||||
|
||||
element& e = *pos++;
|
||||
list_.erase(list_.iterator_to(e));
|
||||
size_type const len = e.alloc_size();
|
||||
alloc_traits::destroy(this->member(), &e);
|
||||
alloc_traits::deallocate(this->member(),
|
||||
reinterpret_cast<char*>(&e), len);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const avail = out_pos_ - in_pos_;
|
||||
if (n < avail)
|
||||
{
|
||||
in_size_ -= n;
|
||||
in_pos_ += n;
|
||||
}
|
||||
else
|
||||
{
|
||||
in_size_ -= avail;
|
||||
if (out_pos_ != out_end_||
|
||||
out_ != list_.iterator_to(list_.back()))
|
||||
{
|
||||
in_pos_ = out_pos_;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use the whole buffer now.
|
||||
// Alternatively we could deallocate it.
|
||||
in_pos_ = 0;
|
||||
out_pos_ = 0;
|
||||
out_end_ = 0;
|
||||
}
|
||||
}
|
||||
debug_check();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class Allocator>
|
||||
void
|
||||
basic_streambuf<Allocator>::debug_check() const
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (list_.empty())
|
||||
{
|
||||
assert(in_pos_ == 0);
|
||||
assert(in_size_ == 0);
|
||||
assert(out_pos_ == 0);
|
||||
assert(out_end_ == 0);
|
||||
assert(out_ == list_.end());
|
||||
return;
|
||||
}
|
||||
|
||||
auto const& front = list_.front();
|
||||
|
||||
assert(in_pos_ < front.size());
|
||||
|
||||
if (out_ == list_.end())
|
||||
{
|
||||
assert(out_pos_ == 0);
|
||||
assert(out_end_ == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const& out = *out_;
|
||||
auto const& back = list_.back();
|
||||
|
||||
assert(out_end_ <= back.size());
|
||||
assert(out_pos_ < out.size());
|
||||
assert(&out != &front || out_pos_ >= in_pos_);
|
||||
assert(&out != &front || out_pos_ - in_pos_ == in_size_);
|
||||
assert(&out != &back || out_pos_ <= out_end_);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class Alloc, class T>
|
||||
basic_streambuf<Alloc>&
|
||||
operator<< (basic_streambuf<Alloc>& buf, T const& t)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << t;
|
||||
auto const& s = ss.str();
|
||||
buf.commit(boost::asio::buffer_copy(
|
||||
buf.prepare(s.size()), boost::asio::buffer(s)));
|
||||
return buf;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using streambuf = basic_streambuf<std::allocator<char>>;
|
||||
|
||||
/** Convert the entire basic_streambuf to a string.
|
||||
@note It is more efficient to deal directly in the streambuf instead.
|
||||
*/
|
||||
template <class Allocator>
|
||||
std::string
|
||||
to_string (basic_streambuf<Allocator> const& buf)
|
||||
{
|
||||
std::string s;
|
||||
s.resize(buf.size());
|
||||
boost::asio::buffer_copy(boost::asio::buffer(
|
||||
&s[0], s.size()), buf.data());
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
158
src/beast/beast/asio/tests/streambuf.test.cpp
Normal file
@@ -0,0 +1,158 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, 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/asio/streambuf.h>
|
||||
#include <beast/unit_test/suite.h>
|
||||
|
||||
namespace beast {
|
||||
namespace asio {
|
||||
|
||||
class streambuf_test : public unit_test::suite
|
||||
{
|
||||
public:
|
||||
// Convert a buffer sequence to a string
|
||||
template <class Buffers>
|
||||
static
|
||||
std::string
|
||||
to_str (Buffers const& b)
|
||||
{
|
||||
std::string s;
|
||||
auto const n = boost::asio::buffer_size(b);
|
||||
s.resize(n);
|
||||
boost::asio::buffer_copy(
|
||||
boost::asio::buffer(&s[0], n), b);
|
||||
return s;
|
||||
}
|
||||
|
||||
// Fill a buffer sequence with predictable data
|
||||
template <class Buffers>
|
||||
static
|
||||
void
|
||||
fill (Buffers const& b)
|
||||
{
|
||||
char c = 0;
|
||||
auto first = boost::asio::buffers_begin(b);
|
||||
auto last = boost::asio::buffers_end(b);
|
||||
while (first != last)
|
||||
*first++ = c++;
|
||||
}
|
||||
|
||||
// Check that a buffer sequence has predictable data
|
||||
template <class Buffers>
|
||||
void
|
||||
check (Buffers const& b, char c = 0)
|
||||
{
|
||||
auto first = boost::asio::buffers_begin(b);
|
||||
auto last = boost::asio::buffers_end(b);
|
||||
while (first != last)
|
||||
expect (*first++ == c++);
|
||||
}
|
||||
|
||||
void
|
||||
test_prepare()
|
||||
{
|
||||
testcase << "prepare";
|
||||
beast::asio::streambuf b(11);
|
||||
for (std::size_t n = 0; n < 97; ++n)
|
||||
{
|
||||
fill(b.prepare(n));
|
||||
b.commit(n);
|
||||
check(b.data());
|
||||
b.consume(n);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test_commit()
|
||||
{
|
||||
testcase << "commit";
|
||||
beast::asio::streambuf b(11);
|
||||
for (std::size_t n = 0; n < 97; ++n)
|
||||
{
|
||||
fill(b.prepare(n));
|
||||
char c = 0;
|
||||
for (int i = 1;; ++i)
|
||||
{
|
||||
b.commit(i);
|
||||
check(b.data(), c);
|
||||
b.consume(i);
|
||||
if (b.size() < 1)
|
||||
break;
|
||||
c += i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test_consume()
|
||||
{
|
||||
testcase << "consume";
|
||||
beast::asio::streambuf b(11);
|
||||
for (std::size_t n = 0; n < 97; ++n)
|
||||
{
|
||||
fill(b.prepare(n));
|
||||
b.commit(n);
|
||||
char c = 0;
|
||||
for (int i = 1; b.size() > 0; ++i)
|
||||
{
|
||||
check(b.data(), c);
|
||||
b.consume(i);
|
||||
c += i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
{
|
||||
beast::asio::streambuf b(10);
|
||||
std::string const s = "1234567890";
|
||||
b << s;
|
||||
expect (to_str(b.data()) == s);
|
||||
b.prepare(5);
|
||||
}
|
||||
|
||||
{
|
||||
beast::asio::streambuf b(10);
|
||||
b.prepare(10);
|
||||
b.commit(10);
|
||||
b.consume(10);
|
||||
}
|
||||
|
||||
{
|
||||
beast::asio::streambuf b(5);
|
||||
boost::asio::buffer_copy(b.prepare(14),
|
||||
boost::asio::buffer(std::string("1234567890ABCD")));
|
||||
b.commit(4);
|
||||
expect(to_str(b.data()) == "1234");
|
||||
b.consume(4);
|
||||
b.commit(10);
|
||||
expect(to_str(b.data()) == "567890ABCD");
|
||||
}
|
||||
|
||||
test_prepare();
|
||||
test_commit();
|
||||
test_consume();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(streambuf,asio,beast);
|
||||
|
||||
}
|
||||
}
|
||||
315
src/beast/beast/asio/waitable_executor.h
Normal file
@@ -0,0 +1,315 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, 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_ASIO_WAITABLE_EXECUTOR_H_INCLUDED
|
||||
#define BEAST_ASIO_WAITABLE_EXECUTOR_H_INCLUDED
|
||||
|
||||
#include <boost/asio/handler_alloc_hook.hpp>
|
||||
#include <boost/asio/handler_continuation_hook.hpp>
|
||||
#include <boost/asio/handler_invoke_hook.hpp>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <beast/cxx14/type_traits.h> // <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace beast {
|
||||
namespace asio {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class Owner, class Handler>
|
||||
class waitable_executor_wrapped_handler
|
||||
{
|
||||
private:
|
||||
static_assert (std::is_same <std::decay_t <Owner>, Owner>::value,
|
||||
"Owner cannot be a const or reference type");
|
||||
|
||||
Handler handler_;
|
||||
std::reference_wrapper <Owner> owner_;
|
||||
bool cont_;
|
||||
|
||||
public:
|
||||
waitable_executor_wrapped_handler (Owner& owner,
|
||||
Handler&& handler, bool continuation = false)
|
||||
: handler_ (std::move(handler))
|
||||
, owner_ (owner)
|
||||
{
|
||||
using boost::asio::asio_handler_is_continuation;
|
||||
cont_ = continuation ? true :
|
||||
asio_handler_is_continuation(
|
||||
std::addressof(handler_));
|
||||
owner_.get().increment();
|
||||
}
|
||||
|
||||
waitable_executor_wrapped_handler (Owner& owner,
|
||||
Handler const& handler, bool continuation = false)
|
||||
: handler_ (handler)
|
||||
, owner_ (owner)
|
||||
{
|
||||
using boost::asio::asio_handler_is_continuation;
|
||||
cont_ = continuation ? true :
|
||||
asio_handler_is_continuation(
|
||||
std::addressof(handler_));
|
||||
owner_.get().increment();
|
||||
}
|
||||
|
||||
~waitable_executor_wrapped_handler()
|
||||
{
|
||||
owner_.get().decrement();
|
||||
}
|
||||
|
||||
waitable_executor_wrapped_handler (
|
||||
waitable_executor_wrapped_handler const& other)
|
||||
: handler_ (other.handler_)
|
||||
, owner_ (other.owner_)
|
||||
, cont_ (other.cont_)
|
||||
{
|
||||
owner_.get().increment();
|
||||
}
|
||||
|
||||
waitable_executor_wrapped_handler (
|
||||
waitable_executor_wrapped_handler&& other)
|
||||
: handler_ (std::move(other.handler_))
|
||||
, owner_ (other.owner_)
|
||||
, cont_ (other.cont_)
|
||||
{
|
||||
owner_.get().increment();
|
||||
}
|
||||
|
||||
waitable_executor_wrapped_handler& operator=(
|
||||
waitable_executor_wrapped_handler const&) = delete;
|
||||
|
||||
template <class... Args>
|
||||
void
|
||||
operator()(Args&&... args)
|
||||
{
|
||||
handler_(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
void
|
||||
operator()(Args&&... args) const
|
||||
{
|
||||
handler_(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Function>
|
||||
friend
|
||||
void
|
||||
asio_handler_invoke (Function& f,
|
||||
waitable_executor_wrapped_handler* h)
|
||||
{
|
||||
using boost::asio::asio_handler_invoke;
|
||||
asio_handler_invoke(f,
|
||||
std::addressof(h->handler_));
|
||||
}
|
||||
|
||||
template <class Function>
|
||||
friend
|
||||
void
|
||||
asio_handler_invoke (Function const& f,
|
||||
waitable_executor_wrapped_handler* h)
|
||||
{
|
||||
using boost::asio::asio_handler_invoke;
|
||||
asio_handler_invoke(f,
|
||||
std::addressof(h->handler_));
|
||||
}
|
||||
|
||||
friend
|
||||
void*
|
||||
asio_handler_allocate (std::size_t size,
|
||||
waitable_executor_wrapped_handler* h)
|
||||
{
|
||||
using boost::asio::asio_handler_allocate;
|
||||
return asio_handler_allocate(
|
||||
size, std::addressof(h->handler_));
|
||||
}
|
||||
|
||||
friend
|
||||
void
|
||||
asio_handler_deallocate (void* p, std::size_t size,
|
||||
waitable_executor_wrapped_handler* h)
|
||||
{
|
||||
using boost::asio::asio_handler_deallocate;
|
||||
asio_handler_deallocate(
|
||||
p, size, std::addressof(h->handler_));
|
||||
}
|
||||
|
||||
friend
|
||||
bool
|
||||
asio_handler_is_continuation (
|
||||
waitable_executor_wrapped_handler* h)
|
||||
{
|
||||
return h->cont_;
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Executor which provides blocking until all handlers are called. */
|
||||
class waitable_executor
|
||||
{
|
||||
private:
|
||||
template <class, class>
|
||||
friend class detail::waitable_executor_wrapped_handler;
|
||||
|
||||
std::mutex mutex_;
|
||||
std::condition_variable cond_;
|
||||
std::size_t count_ = 0;
|
||||
std::vector<std::function<void(void)>> notify_;
|
||||
|
||||
public:
|
||||
/** Block until all handlers are called. */
|
||||
template <class = void>
|
||||
void
|
||||
wait();
|
||||
|
||||
/** Blocks until all handlers are called or time elapses.
|
||||
@return `true` if all handlers are done or `false` if the time elapses.
|
||||
*/
|
||||
template <class Rep, class Period>
|
||||
bool
|
||||
wait_for (std::chrono::duration<
|
||||
Rep, Period> const& elapsed_time);
|
||||
|
||||
/** Blocks until all handlers are called or a time is reached.
|
||||
@return `true` if all handlers are done or `false` on timeout.
|
||||
*/
|
||||
template <class Clock, class Duration>
|
||||
bool
|
||||
wait_until (std::chrono::time_point<
|
||||
Clock, Duration> const& timeout_time);
|
||||
|
||||
/** Call a function asynchronously after all handlers are called.
|
||||
The function may be called on the callers thread.
|
||||
*/
|
||||
template <class = void>
|
||||
void
|
||||
async_wait(std::function<void(void)> f);
|
||||
|
||||
/** Create a new handler that dispatches the wrapped handler on the Context. */
|
||||
template <class Handler>
|
||||
detail::waitable_executor_wrapped_handler<waitable_executor,
|
||||
std::remove_reference_t<Handler>>
|
||||
wrap (Handler&& handler);
|
||||
|
||||
private:
|
||||
template <class = void>
|
||||
void
|
||||
increment();
|
||||
|
||||
template <class = void>
|
||||
void
|
||||
decrement();
|
||||
};
|
||||
|
||||
template <class>
|
||||
void
|
||||
waitable_executor::wait()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
cond_.wait(lock,
|
||||
[this]() { return count_ == 0; });
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
bool
|
||||
waitable_executor::wait_for (std::chrono::duration<
|
||||
Rep, Period> const& elapsed_time)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
return cond_.wait_for(lock, elapsed_time,
|
||||
[this]() { return count_ == 0; }) ==
|
||||
std::cv_status::no_timeout;
|
||||
}
|
||||
|
||||
template <class Clock, class Duration>
|
||||
bool
|
||||
waitable_executor::wait_until (std::chrono::time_point<
|
||||
Clock, Duration> const& timeout_time)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
return cond_.wait_until(lock, timeout_time,
|
||||
[this]() { return count_ == 0; }) ==
|
||||
std::cv_status::no_timeout;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class>
|
||||
void
|
||||
waitable_executor::async_wait(std::function<void(void)> f)
|
||||
{
|
||||
bool busy;
|
||||
{
|
||||
std::lock_guard<std::mutex> _(mutex_);
|
||||
busy = count_ > 0;
|
||||
if (busy)
|
||||
notify_.emplace_back(std::move(f));
|
||||
}
|
||||
if (! busy)
|
||||
f();
|
||||
}
|
||||
|
||||
template <class Handler>
|
||||
detail::waitable_executor_wrapped_handler<waitable_executor,
|
||||
std::remove_reference_t<Handler>>
|
||||
waitable_executor::wrap (Handler&& handler)
|
||||
{
|
||||
return detail::waitable_executor_wrapped_handler<
|
||||
waitable_executor, std::remove_reference_t<Handler>>(
|
||||
*this, std::forward<Handler>(handler));
|
||||
}
|
||||
|
||||
template <class>
|
||||
void
|
||||
waitable_executor::increment()
|
||||
{
|
||||
std::lock_guard<std::mutex> _(mutex_);
|
||||
++count_;
|
||||
}
|
||||
|
||||
template <class>
|
||||
void
|
||||
waitable_executor::decrement()
|
||||
{
|
||||
bool notify;
|
||||
std::vector<std::function<void(void)>> list;
|
||||
{
|
||||
std::lock_guard<std::mutex> _(mutex_);
|
||||
notify = --count_ == 0;
|
||||
if (notify)
|
||||
std::swap(list, notify_);
|
||||
}
|
||||
if (notify)
|
||||
{
|
||||
cond_.notify_all();
|
||||
for(auto& _ : list)
|
||||
_();
|
||||
}
|
||||
}
|
||||
|
||||
} // asio
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -27,12 +27,12 @@ namespace beast {
|
||||
|
||||
/** Abstract interface to a clock.
|
||||
|
||||
The abstract clock interface allows a dependency injection to take
|
||||
place so that the choice of implementation can be made at run-time
|
||||
instead of compile time. The trade-off is that the Duration used to
|
||||
represent the clock must be chosen at compile time and cannot be
|
||||
changed. This includes both the choice of representation (integers
|
||||
for example) and the period in ticks corresponding to one second.
|
||||
This makes now() a member function instead of a static member, so
|
||||
an instance of the class can be dependency injected, facilitating
|
||||
unit tests where time may be controlled.
|
||||
|
||||
An abstract_clock inherits all the nested types of the Clock
|
||||
template parameter.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -40,56 +40,37 @@ namespace beast {
|
||||
|
||||
struct Implementation
|
||||
{
|
||||
abstract_clock <std::chrono::seconds>& m_clock;
|
||||
|
||||
// Dependency injection
|
||||
//
|
||||
explicit Implementation (
|
||||
abstract_clock <std::chrono::seconds>& clock)
|
||||
: m_clock (clock)
|
||||
using clock_type = abstract_clock <std::chrono::steady_clock>;
|
||||
clock_type& clock_;
|
||||
explicit Implementation (clock_type& clock)
|
||||
: clock_(clock)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@endcode
|
||||
|
||||
@tparam The length of time, in seconds, corresponding to one tick.
|
||||
@tparam Clock A type meeting these requirements:
|
||||
http://en.cppreference.com/w/cpp/concept/Clock
|
||||
*/
|
||||
template <class Duration>
|
||||
template <class Clock>
|
||||
class abstract_clock
|
||||
{
|
||||
public:
|
||||
typedef typename Duration::rep rep;
|
||||
typedef typename Duration::period period;
|
||||
typedef Duration duration;
|
||||
typedef std::chrono::time_point <
|
||||
abstract_clock, duration> time_point;
|
||||
using rep = typename Clock::rep;
|
||||
using period = typename Clock::period;
|
||||
using duration = typename Clock::duration;
|
||||
using time_point = typename Clock::time_point;
|
||||
|
||||
virtual ~abstract_clock () { }
|
||||
static bool const is_steady = Clock::is_steady;
|
||||
|
||||
/** Returns `true` if this is a steady clock. */
|
||||
virtual bool is_steady () const = 0;
|
||||
virtual ~abstract_clock() = default;
|
||||
|
||||
/** Returns the current time. */
|
||||
virtual time_point now () const = 0;
|
||||
|
||||
#if 0
|
||||
/** Convert the specified time point to a string. */
|
||||
/** @{ */
|
||||
//virtual std::string to_string (time_point const& tp) const = 0;
|
||||
|
||||
template <class Duration2>
|
||||
std::string to_string (
|
||||
std::chrono::time_point <abstract_clock, Duration2> const& tp) const
|
||||
{
|
||||
return to_string (
|
||||
std::chrono::time_point_cast <Duration> (tp));
|
||||
}
|
||||
/** @} */
|
||||
#endif
|
||||
virtual time_point now() const = 0;
|
||||
|
||||
/** Returning elapsed ticks since the epoch. */
|
||||
rep elapsed () const
|
||||
rep elapsed()
|
||||
{
|
||||
return now().time_since_epoch().count();
|
||||
}
|
||||
@@ -99,68 +80,34 @@ public:
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class TrivialClock, class Duration>
|
||||
struct basic_abstract_clock_wrapper : public abstract_clock <Duration>
|
||||
{
|
||||
using typename abstract_clock <Duration>::duration;
|
||||
using typename abstract_clock <Duration>::time_point;
|
||||
|
||||
bool is_steady () const
|
||||
{
|
||||
return TrivialClock::is_steady;
|
||||
}
|
||||
|
||||
time_point now () const
|
||||
{
|
||||
return time_point (duration (
|
||||
std::chrono::duration_cast <duration> (
|
||||
TrivialClock::now().time_since_epoch ()).count ()));
|
||||
}
|
||||
};
|
||||
|
||||
template <class TrivialClock, class Duration>
|
||||
template <class Facade, class Clock>
|
||||
struct abstract_clock_wrapper
|
||||
: public basic_abstract_clock_wrapper <TrivialClock, Duration>
|
||||
: public abstract_clock<Facade>
|
||||
{
|
||||
// generic conversion displays the duration
|
||||
/*
|
||||
std::string to_string (typename basic_abstract_clock_wrapper <
|
||||
TrivialClock, Duration>::time_point const& tp) const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << tp.time_since_epoch();
|
||||
return ss.str ();
|
||||
}
|
||||
*/
|
||||
};
|
||||
using typename abstract_clock<Facade>::duration;
|
||||
using typename abstract_clock<Facade>::time_point;
|
||||
|
||||
/*
|
||||
template <class Duration>
|
||||
struct abstract_clock_wrapper <std::chrono::system_clock, Duration>
|
||||
: public basic_abstract_clock_wrapper <std::chrono::system_clock, Duration>
|
||||
{
|
||||
typedef std::chrono::system_clock clock_type;
|
||||
std::string to_string (time_point const& tp)
|
||||
time_point
|
||||
now() const override
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << clock_type::time_point (tp.time_since_epoch ());
|
||||
return ss.str ();
|
||||
return Clock::now();
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Retrieve a discrete clock for a type implementing the Clock concept.
|
||||
The interface is created as an object with static storage duration.
|
||||
/** Returns a global instance of an abstract clock.
|
||||
@tparam Facade A type meeting these requirements:
|
||||
http://en.cppreference.com/w/cpp/concept/Clock
|
||||
@tparam Clock The actual concrete clock to use.
|
||||
*/
|
||||
template <class TrivialClock, class Duration>
|
||||
abstract_clock <Duration>& get_abstract_clock ()
|
||||
template<class Facade, class Clock = Facade>
|
||||
abstract_clock<Facade>&
|
||||
get_abstract_clock()
|
||||
{
|
||||
static detail::abstract_clock_wrapper <
|
||||
TrivialClock, Duration> clock;
|
||||
static detail::abstract_clock_wrapper<Facade, Clock> clock;
|
||||
return clock;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,25 +45,25 @@ public:
|
||||
class seconds_clock_thread
|
||||
{
|
||||
public:
|
||||
typedef std::mutex mutex;
|
||||
typedef std::condition_variable cond_var;
|
||||
typedef std::lock_guard <mutex> lock_guard;
|
||||
typedef std::unique_lock <mutex> unique_lock;
|
||||
typedef std::chrono::steady_clock clock_type;
|
||||
typedef std::chrono::seconds seconds;
|
||||
typedef std::thread thread;
|
||||
typedef std::vector <seconds_clock_worker*> workers;
|
||||
using mutex = std::mutex;
|
||||
using cond_var = std::condition_variable;
|
||||
using lock_guard = std::lock_guard <mutex>;
|
||||
using unique_lock = std::unique_lock <mutex>;
|
||||
using clock_type = std::chrono::steady_clock;
|
||||
using seconds = std::chrono::seconds;
|
||||
using thread = std::thread;
|
||||
using workers = std::vector <seconds_clock_worker*>;
|
||||
|
||||
bool m_stop;
|
||||
mutex m_mutex;
|
||||
cond_var m_cond;
|
||||
workers m_workers;
|
||||
thread m_thread;
|
||||
bool stop_;
|
||||
mutex mutex_;
|
||||
cond_var cond_;
|
||||
workers workers_;
|
||||
thread thread_;
|
||||
|
||||
seconds_clock_thread ()
|
||||
: m_stop (false)
|
||||
: stop_ (false)
|
||||
{
|
||||
m_thread = thread (std::bind(
|
||||
thread_ = thread (std::bind(
|
||||
&seconds_clock_thread::run, this));
|
||||
}
|
||||
|
||||
@@ -74,37 +74,37 @@ public:
|
||||
|
||||
void add (seconds_clock_worker& w)
|
||||
{
|
||||
lock_guard lock (m_mutex);
|
||||
m_workers.push_back (&w);
|
||||
lock_guard lock (mutex_);
|
||||
workers_.push_back (&w);
|
||||
}
|
||||
|
||||
void remove (seconds_clock_worker& w)
|
||||
{
|
||||
lock_guard lock (m_mutex);
|
||||
m_workers.erase (std::find (
|
||||
m_workers.begin (), m_workers.end(), &w));
|
||||
lock_guard lock (mutex_);
|
||||
workers_.erase (std::find (
|
||||
workers_.begin (), workers_.end(), &w));
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
if (m_thread.joinable())
|
||||
if (thread_.joinable())
|
||||
{
|
||||
{
|
||||
lock_guard lock (m_mutex);
|
||||
m_stop = true;
|
||||
lock_guard lock (mutex_);
|
||||
stop_ = true;
|
||||
}
|
||||
m_cond.notify_all();
|
||||
m_thread.join();
|
||||
cond_.notify_all();
|
||||
thread_.join();
|
||||
}
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
unique_lock lock (m_mutex);;
|
||||
unique_lock lock (mutex_);;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
for (auto iter : m_workers)
|
||||
for (auto iter : workers_)
|
||||
iter->sample();
|
||||
|
||||
clock_type::time_point const when (
|
||||
@@ -112,7 +112,7 @@ public:
|
||||
clock_type::now().time_since_epoch()) +
|
||||
seconds (1));
|
||||
|
||||
if (m_cond.wait_until (lock, when, [this]{ return m_stop; }))
|
||||
if (cond_.wait_until (lock, when, [this]{ return stop_; }))
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -143,24 +143,26 @@ basic_seconds_clock_main_hook()
|
||||
}
|
||||
|
||||
/** A clock whose minimum resolution is one second.
|
||||
|
||||
The purpose of this class is to optimize the performance of the now()
|
||||
member function call. It uses a dedicated thread that wakes up at least
|
||||
once per second to sample the requested trivial clock.
|
||||
@tparam TrivialClock The clock to sample.
|
||||
|
||||
@tparam Clock A type meeting these requirements:
|
||||
http://en.cppreference.com/w/cpp/concept/Clock
|
||||
*/
|
||||
template <class TrivialClock>
|
||||
template <class Clock>
|
||||
class basic_seconds_clock
|
||||
{
|
||||
public:
|
||||
typedef std::chrono::seconds resolution;
|
||||
typedef typename resolution::rep rep;
|
||||
typedef typename resolution::period period;
|
||||
typedef std::chrono::duration <rep, period> duration;
|
||||
typedef std::chrono::time_point <basic_seconds_clock> time_point;
|
||||
using rep = typename Clock::rep;
|
||||
using period = typename Clock::period;
|
||||
using duration = typename Clock::duration;
|
||||
using time_point = typename Clock::time_point;
|
||||
|
||||
static bool const is_steady = TrivialClock::is_steady;
|
||||
static bool const is_steady = Clock::is_steady;
|
||||
|
||||
static time_point now ()
|
||||
static time_point now()
|
||||
{
|
||||
// Make sure the thread is constructed before the
|
||||
// worker otherwise we will crash during destruction
|
||||
@@ -176,45 +178,36 @@ public:
|
||||
|
||||
struct worker : detail::seconds_clock_worker
|
||||
{
|
||||
typedef std::mutex mutex;
|
||||
typedef std::lock_guard <mutex> lock_guard;
|
||||
|
||||
time_point m_now;
|
||||
mutex m_mutex;
|
||||
std::mutex mutex_;
|
||||
|
||||
static time_point get_now ()
|
||||
worker()
|
||||
: m_now(Clock::now())
|
||||
{
|
||||
return time_point (floor <resolution> (
|
||||
TrivialClock::now().time_since_epoch()));
|
||||
detail::seconds_clock_thread::instance().add(*this);
|
||||
}
|
||||
|
||||
worker ()
|
||||
: m_now (get_now ())
|
||||
~worker()
|
||||
{
|
||||
detail::seconds_clock_thread::instance().add (*this);
|
||||
}
|
||||
|
||||
~worker ()
|
||||
{
|
||||
detail::seconds_clock_thread::instance().remove (*this);
|
||||
detail::seconds_clock_thread::instance().remove(*this);
|
||||
}
|
||||
|
||||
time_point now()
|
||||
{
|
||||
lock_guard lock (m_mutex);
|
||||
std::lock_guard<std::mutex> lock (mutex_);
|
||||
return m_now;
|
||||
}
|
||||
|
||||
void sample ()
|
||||
void sample()
|
||||
{
|
||||
lock_guard lock (m_mutex);
|
||||
m_now = get_now ();
|
||||
std::lock_guard<std::mutex> lock (mutex_);
|
||||
m_now = Clock::now();
|
||||
}
|
||||
};
|
||||
|
||||
static worker w;
|
||||
|
||||
return w.now ();
|
||||
return w.now();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -32,8 +32,6 @@
|
||||
#include <beast/utility/noexcept.h>
|
||||
#include <ctime>
|
||||
#include <locale>
|
||||
|
||||
#define BEAST_CHRONO_NO_TIMEPOINT_IO 1
|
||||
|
||||
/*
|
||||
|
||||
@@ -798,292 +796,8 @@ time_fmt(timezone f)
|
||||
return __time_man(f);
|
||||
}
|
||||
|
||||
#if ! BEAST_CHRONO_NO_TIMEPOINT_IO
|
||||
} // chrono
|
||||
|
||||
template <class _CharT, class _Traits, class _Duration>
|
||||
basic_istream<_CharT, _Traits>&
|
||||
operator>>(basic_istream<_CharT, _Traits>& __is,
|
||||
time_point<steady_clock, _Duration>& __tp)
|
||||
{
|
||||
_Duration __d;
|
||||
__is >> __d;
|
||||
if (__is.good())
|
||||
{
|
||||
const _CharT __u[] = {' ', 's', 'i', 'n', 'c', 'e', ' ', 'b', 'o', 'o', 't'};
|
||||
const basic_string<_CharT> __units(__u, __u + sizeof(__u)/sizeof(__u[0]));
|
||||
ios_base::iostate __err = ios_base::goodbit;
|
||||
typedef istreambuf_iterator<_CharT, _Traits> _I;
|
||||
_I __i(__is);
|
||||
_I __e;
|
||||
ptrdiff_t __k = __scan_keyword(__i, __e,
|
||||
&__units, &__units + 1,
|
||||
use_facet<ctype<_CharT> >(__is.getloc()),
|
||||
__err) - &__units;
|
||||
if (__k == 1)
|
||||
{
|
||||
// failed to read epoch string
|
||||
__is.setstate(__err);
|
||||
return __is;
|
||||
}
|
||||
__tp = time_point<steady_clock, _Duration>(__d);
|
||||
}
|
||||
else
|
||||
__is.setstate(__is.failbit);
|
||||
return __is;
|
||||
}
|
||||
|
||||
template <class _CharT, class _Traits, class _Duration>
|
||||
basic_ostream<_CharT, _Traits>&
|
||||
operator<<(basic_ostream<_CharT, _Traits>& __os,
|
||||
const time_point<system_clock, _Duration>& __tp)
|
||||
{
|
||||
typename basic_ostream<_CharT, _Traits>::sentry ok(__os);
|
||||
if (ok)
|
||||
{
|
||||
bool failed = false;
|
||||
try
|
||||
{
|
||||
const _CharT* pb = nullptr;
|
||||
const _CharT* pe = pb;
|
||||
timezone tz = utc;
|
||||
typedef timepunct<_CharT> F;
|
||||
locale loc = __os.getloc();
|
||||
if (has_facet<F>(loc))
|
||||
{
|
||||
const F& f = use_facet<F>(loc);
|
||||
pb = f.fmt().data();
|
||||
pe = pb + f.fmt().size();
|
||||
tz = f.get_timezone();
|
||||
}
|
||||
time_t __t = system_clock::to_time_t(__tp);
|
||||
tm __tm;
|
||||
if (tz == local)
|
||||
{
|
||||
if (localtime_r(&__t, &__tm) == 0)
|
||||
failed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gmtime_r(&__t, &__tm) == 0)
|
||||
failed = true;
|
||||
}
|
||||
if (!failed)
|
||||
{
|
||||
const time_put<_CharT>& tp = use_facet<time_put<_CharT> >(loc);
|
||||
if (pb == pe)
|
||||
{
|
||||
_CharT pattern[] = {'%', 'F', 'T', '%', 'H', ':', '%', 'M', ':'};
|
||||
pb = pattern;
|
||||
pe = pb + sizeof(pattern) / sizeof(_CharT);
|
||||
failed = tp.put(__os, __os, __os.fill(), &__tm, pb, pe).failed();
|
||||
if (!failed)
|
||||
{
|
||||
duration<double> __d = __tp - system_clock::from_time_t(__t) +
|
||||
seconds(__tm.tm_sec);
|
||||
if (__d.count() < 10)
|
||||
__os << _CharT('0');
|
||||
ios::fmtflags __flgs = __os.flags();
|
||||
__os.setf(ios::fixed, ios::floatfield);
|
||||
__os << __d.count();
|
||||
__os.flags(__flgs);
|
||||
if (tz == local)
|
||||
{
|
||||
_CharT sub_pattern[] = {' ', '%', 'z'};
|
||||
pb = sub_pattern;
|
||||
pe = pb + + sizeof(sub_pattern) / sizeof(_CharT);
|
||||
failed = tp.put(__os, __os, __os.fill(), &__tm, pb, pe).failed();
|
||||
}
|
||||
else
|
||||
{
|
||||
_CharT sub_pattern[] = {' ', '+', '0', '0', '0', '0', 0};
|
||||
__os << sub_pattern;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
failed = tp.put(__os, __os, __os.fill(), &__tm, pb, pe).failed();
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
failed = true;
|
||||
}
|
||||
if (failed)
|
||||
__os.setstate(ios_base::failbit | ios_base::badbit);
|
||||
}
|
||||
return __os;
|
||||
}
|
||||
|
||||
template <class _CharT, class _InputIterator>
|
||||
minutes
|
||||
__extract_z(_InputIterator& __b, _InputIterator __e,
|
||||
ios_base::iostate& __err, const ctype<_CharT>& __ct)
|
||||
{
|
||||
int __minn = 0;
|
||||
if (__b != __e)
|
||||
{
|
||||
char __cn = __ct.narrow(*__b, 0);
|
||||
if (__cn != '+' && __cn != '-')
|
||||
{
|
||||
__err |= ios_base::failbit;
|
||||
return minutes(0);
|
||||
}
|
||||
int __sn = __cn == '-' ? -1 : 1;
|
||||
int __hr = 0;
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
if (++__b == __e)
|
||||
{
|
||||
__err |= ios_base::eofbit | ios_base::failbit;
|
||||
return minutes(0);
|
||||
}
|
||||
__cn = __ct.narrow(*__b, 0);
|
||||
if (!('0' <= __cn && __cn <= '9'))
|
||||
{
|
||||
__err |= ios_base::failbit;
|
||||
return minutes(0);
|
||||
}
|
||||
__hr = __hr * 10 + __cn - '0';
|
||||
}
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
if (++__b == __e)
|
||||
{
|
||||
__err |= ios_base::eofbit | ios_base::failbit;
|
||||
return minutes(0);
|
||||
}
|
||||
__cn = __ct.narrow(*__b, 0);
|
||||
if (!('0' <= __cn && __cn <= '9'))
|
||||
{
|
||||
__err |= ios_base::failbit;
|
||||
return minutes(0);
|
||||
}
|
||||
__minn = __minn * 10 + __cn - '0';
|
||||
}
|
||||
if (++__b == __e)
|
||||
__err |= ios_base::eofbit;
|
||||
__minn += __hr * 60;
|
||||
__minn *= __sn;
|
||||
}
|
||||
else
|
||||
__err |= ios_base::eofbit | ios_base::failbit;
|
||||
return minutes(__minn);
|
||||
}
|
||||
|
||||
template <class _CharT, class _Traits, class _Duration>
|
||||
basic_istream<_CharT, _Traits>&
|
||||
operator>>(basic_istream<_CharT, _Traits>& __is,
|
||||
time_point<system_clock, _Duration>& __tp)
|
||||
{
|
||||
typename basic_istream<_CharT,_Traits>::sentry ok(__is);
|
||||
if (ok)
|
||||
{
|
||||
ios_base::iostate err = ios_base::goodbit;
|
||||
try
|
||||
{
|
||||
const _CharT* pb = nullptr;
|
||||
const _CharT* pe = pb;
|
||||
typedef timepunct<_CharT> F;
|
||||
locale loc = __is.getloc();
|
||||
timezone tz = utc;
|
||||
if (has_facet<F>(loc))
|
||||
{
|
||||
const F& f = use_facet<F>(loc);
|
||||
pb = f.fmt().data();
|
||||
pe = pb + f.fmt().size();
|
||||
tz = f.get_timezone();
|
||||
}
|
||||
const time_get<_CharT>& tg = use_facet<time_get<_CharT> >(loc);
|
||||
const ctype<_CharT>& __ct = use_facet<ctype<_CharT> >(loc);
|
||||
tm __tm = {0};
|
||||
typedef istreambuf_iterator<_CharT, _Traits> _I;
|
||||
if (pb == pe)
|
||||
{
|
||||
_CharT pattern[] = {'%', 'Y', '-', '%', 'm', '-', '%', 'd',
|
||||
'T', '%', 'H', ':', '%', 'M', ':'};
|
||||
pb = pattern;
|
||||
pe = pb + sizeof(pattern) / sizeof(_CharT);
|
||||
tg.get(__is, 0, __is, err, &__tm, pb, pe);
|
||||
if (err & ios_base::failbit)
|
||||
goto __exit;
|
||||
double __sec;
|
||||
_CharT __c = _CharT();
|
||||
__is >> __sec;
|
||||
if (__is.fail())
|
||||
{
|
||||
err |= ios_base::failbit;
|
||||
goto __exit;
|
||||
}
|
||||
_I __i(__is);
|
||||
_I __eof;
|
||||
__c = *__i;
|
||||
if (++__i == __eof || __c != ' ')
|
||||
{
|
||||
err |= ios_base::failbit;
|
||||
goto __exit;
|
||||
}
|
||||
minutes __minn = __extract_z(__i, __eof, err, __ct);
|
||||
if (err & ios_base::failbit)
|
||||
goto __exit;
|
||||
time_t __t;
|
||||
__t = timegm(&__tm);
|
||||
__tp = system_clock::from_time_t(__t) - __minn
|
||||
+ round<microseconds>(duration<double>(__sec));
|
||||
}
|
||||
else
|
||||
{
|
||||
const _CharT __z[2] = {'%', 'z'};
|
||||
const _CharT* __fz = std::search(pb, pe, __z, __z+2);
|
||||
tg.get(__is, 0, __is, err, &__tm, pb, __fz);
|
||||
minutes __minn(0);
|
||||
if (__fz != pe)
|
||||
{
|
||||
if (err != ios_base::goodbit)
|
||||
{
|
||||
err |= ios_base::failbit;
|
||||
goto __exit;
|
||||
}
|
||||
_I __i(__is);
|
||||
_I __eof;
|
||||
__minn = __extract_z(__i, __eof, err, __ct);
|
||||
if (err & ios_base::failbit)
|
||||
goto __exit;
|
||||
if (__fz+2 != pe)
|
||||
{
|
||||
if (err != ios_base::goodbit)
|
||||
{
|
||||
err |= ios_base::failbit;
|
||||
goto __exit;
|
||||
}
|
||||
tg.get(__is, 0, __is, err, &__tm, __fz+2, pe);
|
||||
if (err & ios_base::failbit)
|
||||
goto __exit;
|
||||
}
|
||||
}
|
||||
__tm.tm_isdst = -1;
|
||||
time_t __t;
|
||||
if (tz == utc || __fz != pe)
|
||||
__t = timegm(&__tm);
|
||||
else
|
||||
__t = mktime(&__tm);
|
||||
__tp = system_clock::from_time_t(__t) - __minn;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
err |= ios_base::badbit | ios_base::failbit;
|
||||
}
|
||||
__exit:
|
||||
__is.setstate(err);
|
||||
}
|
||||
return __is;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // chrono
|
||||
|
||||
//_LIBCPP_END_NAMESPACE_STD
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -25,68 +25,73 @@
|
||||
namespace beast {
|
||||
|
||||
/** Manual clock implementation.
|
||||
|
||||
This concrete class implements the @ref abstract_clock interface and
|
||||
allows the time to be advanced manually, mainly for the purpose of
|
||||
providing a clock in unit tests.
|
||||
@tparam The length of time, in seconds, corresponding to one tick.
|
||||
|
||||
@tparam Clock A type meeting these requirements:
|
||||
http://en.cppreference.com/w/cpp/concept/Clock
|
||||
*/
|
||||
template <class Duration, bool IsSteady = true>
|
||||
class manual_clock : public abstract_clock <Duration>
|
||||
template <class Clock>
|
||||
class manual_clock
|
||||
: public abstract_clock<Clock>
|
||||
{
|
||||
public:
|
||||
using typename abstract_clock <Duration>::rep;
|
||||
using typename abstract_clock <Duration>::duration;
|
||||
using typename abstract_clock <Duration>::time_point;
|
||||
|
||||
explicit manual_clock (time_point const& t = time_point (Duration (0)))
|
||||
: m_now (t)
|
||||
{
|
||||
}
|
||||
|
||||
bool is_steady () const
|
||||
{
|
||||
return IsSteady;
|
||||
}
|
||||
|
||||
time_point now () const
|
||||
{
|
||||
return m_now;
|
||||
}
|
||||
|
||||
#if 0
|
||||
std::string to_string (time_point const& tp) const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << tp.time_since_epoch() << " from start";
|
||||
return ss.str ();
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Set the current time of the manual clock.
|
||||
Precondition:
|
||||
! IsSteady || t > now()
|
||||
*/
|
||||
void set (time_point const& t)
|
||||
{
|
||||
//if (IsSteady)
|
||||
m_now = t;
|
||||
}
|
||||
|
||||
/** Convenience for setting the time using a duration in @ref rep units. */
|
||||
void set (rep v)
|
||||
{
|
||||
set (time_point (duration (v)));
|
||||
}
|
||||
|
||||
/** Convenience for advancing the clock by one. */
|
||||
manual_clock& operator++ ()
|
||||
{
|
||||
m_now += duration (1);
|
||||
return *this;
|
||||
}
|
||||
using typename abstract_clock<Clock>::rep;
|
||||
using typename abstract_clock<Clock>::duration;
|
||||
using typename abstract_clock<Clock>::time_point;
|
||||
|
||||
private:
|
||||
time_point m_now;
|
||||
time_point now_;
|
||||
|
||||
public:
|
||||
explicit
|
||||
manual_clock (time_point const& now = time_point(duration(0)))
|
||||
: now_(now)
|
||||
{
|
||||
}
|
||||
|
||||
time_point
|
||||
now() const override
|
||||
{
|
||||
return now_;
|
||||
}
|
||||
|
||||
/** Set the current time of the manual clock. */
|
||||
void
|
||||
set (time_point const& when)
|
||||
{
|
||||
assert(! Clock::is_steady || when >= now_);
|
||||
now_ = when;
|
||||
}
|
||||
|
||||
/** Convenience for setting the time in seconds from epoch. */
|
||||
template <class Integer>
|
||||
void
|
||||
set(Integer seconds_from_epoch)
|
||||
{
|
||||
set(time_point(duration(
|
||||
std::chrono::seconds(seconds_from_epoch))));
|
||||
}
|
||||
|
||||
/** Advance the clock by a duration. */
|
||||
template <class Rep, class Period>
|
||||
void
|
||||
advance(std::chrono::duration<Rep, Period> const& elapsed)
|
||||
{
|
||||
assert(! Clock::is_steady ||
|
||||
(now_ + elapsed) >= now_);
|
||||
now_ += elapsed;
|
||||
}
|
||||
|
||||
/** Convenience for advancing the clock by one second. */
|
||||
manual_clock&
|
||||
operator++ ()
|
||||
{
|
||||
advance(std::chrono::seconds(1));
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -20,11 +20,8 @@
|
||||
// MODULES: ../impl/chrono_io.cpp
|
||||
|
||||
#include <beast/chrono/abstract_clock.h>
|
||||
#include <beast/chrono/abstract_clock_io.h>
|
||||
#include <beast/chrono/manual_clock.h>
|
||||
|
||||
#include <beast/unit_test/suite.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
@@ -34,7 +31,8 @@ namespace beast {
|
||||
class abstract_clock_test : public unit_test::suite
|
||||
{
|
||||
public:
|
||||
void test (abstract_clock <std::chrono::seconds>& c)
|
||||
template <class Clock>
|
||||
void test (abstract_clock<Clock>& c)
|
||||
{
|
||||
{
|
||||
auto const t1 (c.now ());
|
||||
@@ -53,18 +51,18 @@ public:
|
||||
|
||||
void test_manual ()
|
||||
{
|
||||
typedef manual_clock <std::chrono::seconds> clock_type;
|
||||
using clock_type = manual_clock<std::chrono::steady_clock>;
|
||||
clock_type c;
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
ss << "now() = " << c.now () << std::endl;
|
||||
ss << "now() = " << c.now().time_since_epoch() << std::endl;
|
||||
|
||||
c.set (clock_type::time_point (std::chrono::seconds (1)));
|
||||
ss << "now() = " << c.now () << std::endl;
|
||||
c.set (clock_type::time_point (std::chrono::seconds(1)));
|
||||
ss << "now() = " << c.now().time_since_epoch() << std::endl;
|
||||
|
||||
c.set (clock_type::time_point (std::chrono::seconds (2)));
|
||||
ss << "now() = " << c.now () << std::endl;
|
||||
c.set (clock_type::time_point (std::chrono::seconds(2)));
|
||||
ss << "now() = " << c.now().time_since_epoch() << std::endl;
|
||||
|
||||
log << ss.str();
|
||||
}
|
||||
@@ -72,16 +70,16 @@ public:
|
||||
void run ()
|
||||
{
|
||||
log << "steady_clock";
|
||||
test (get_abstract_clock <std::chrono::steady_clock,
|
||||
std::chrono::seconds> ());
|
||||
test (get_abstract_clock<
|
||||
std::chrono::steady_clock>());
|
||||
|
||||
log << "system_clock";
|
||||
test (get_abstract_clock <std::chrono::system_clock,
|
||||
std::chrono::seconds> ());
|
||||
test (get_abstract_clock<
|
||||
std::chrono::system_clock>());
|
||||
|
||||
log << "high_resolution_clock";
|
||||
test (get_abstract_clock <std::chrono::high_resolution_clock,
|
||||
std::chrono::seconds> ());
|
||||
test (get_abstract_clock<
|
||||
std::chrono::high_resolution_clock>());
|
||||
|
||||
log << "manual_clock";
|
||||
test_manual ();
|
||||
|
||||
@@ -44,10 +44,6 @@
|
||||
#define BEAST_DISABLE_CONTRACT_CHECKS 0
|
||||
#endif
|
||||
|
||||
#ifndef BEAST_COMPILER_CHECKS_SOCKET_OVERRIDES
|
||||
#define BEAST_COMPILER_CHECKS_SOCKET_OVERRIDES 0
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||
|
||||
@@ -21,10 +21,5 @@
|
||||
#include <BeastConfig.h>
|
||||
#endif
|
||||
|
||||
#include <beast/container/impl/spookyv2.cpp>
|
||||
#include <beast/container/impl/siphash.cpp>
|
||||
|
||||
#include <beast/container/tests/aged_associative_container.test.cpp>
|
||||
#include <beast/container/tests/buffer_view.test.cpp>
|
||||
#include <beast/container/tests/hardened_hash.test.cpp>
|
||||
#include <beast/container/tests/hash_append.test.cpp>
|
||||
|
||||
@@ -31,12 +31,12 @@ namespace beast {
|
||||
template <
|
||||
class Key,
|
||||
class T,
|
||||
class Duration = std::chrono::seconds,
|
||||
class Clock = std::chrono::steady_clock,
|
||||
class Compare = std::less <Key>,
|
||||
class Allocator = std::allocator <std::pair <Key const, T>>
|
||||
>
|
||||
using aged_map = detail::aged_ordered_container <
|
||||
false, true, Key, T, Duration, Compare, Allocator>;
|
||||
false, true, Key, T, Clock, Compare, Allocator>;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -31,12 +31,12 @@ namespace beast {
|
||||
template <
|
||||
class Key,
|
||||
class T,
|
||||
class Duration = std::chrono::seconds,
|
||||
class Clock = std::chrono::steady_clock,
|
||||
class Compare = std::less <Key>,
|
||||
class Allocator = std::allocator <std::pair <Key const, T>>
|
||||
>
|
||||
using aged_multimap = detail::aged_ordered_container <
|
||||
true, true, Key, T, Duration, Compare, Allocator>;
|
||||
true, true, Key, T, Clock, Compare, Allocator>;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -30,12 +30,12 @@ namespace beast {
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class Duration = std::chrono::seconds,
|
||||
class Clock = std::chrono::steady_clock,
|
||||
class Compare = std::less <Key>,
|
||||
class Allocator = std::allocator <Key>
|
||||
>
|
||||
using aged_multiset = detail::aged_ordered_container <
|
||||
true, false, Key, void, Duration, Compare, Allocator>;
|
||||
true, false, Key, void, Clock, Compare, Allocator>;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -30,12 +30,12 @@ namespace beast {
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class Duration = std::chrono::seconds,
|
||||
class Clock = std::chrono::steady_clock,
|
||||
class Compare = std::less <Key>,
|
||||
class Allocator = std::allocator <Key>
|
||||
>
|
||||
using aged_set = detail::aged_ordered_container <
|
||||
false, false, Key, void, Duration, Compare, Allocator>;
|
||||
false, false, Key, void, Clock, Compare, Allocator>;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -31,13 +31,13 @@ namespace beast {
|
||||
template <
|
||||
class Key,
|
||||
class T,
|
||||
class Duration = std::chrono::seconds,
|
||||
class Clock = std::chrono::steady_clock,
|
||||
class Hash = std::hash <Key>,
|
||||
class KeyEqual = std::equal_to <Key>,
|
||||
class Allocator = std::allocator <std::pair <Key const, T>>
|
||||
>
|
||||
using aged_unordered_map = detail::aged_unordered_container <
|
||||
false, true, Key, T, Duration, Hash, KeyEqual, Allocator>;
|
||||
false, true, Key, T, Clock, Hash, KeyEqual, Allocator>;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -31,13 +31,13 @@ namespace beast {
|
||||
template <
|
||||
class Key,
|
||||
class T,
|
||||
class Duration = std::chrono::seconds,
|
||||
class Clock = std::chrono::steady_clock,
|
||||
class Hash = std::hash <Key>,
|
||||
class KeyEqual = std::equal_to <Key>,
|
||||
class Allocator = std::allocator <std::pair <Key const, T>>
|
||||
>
|
||||
using aged_unordered_multimap = detail::aged_unordered_container <
|
||||
true, true, Key, T, Duration, Hash, KeyEqual, Allocator>;
|
||||
true, true, Key, T, Clock, Hash, KeyEqual, Allocator>;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -30,13 +30,13 @@ namespace beast {
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class Duration = std::chrono::seconds,
|
||||
class Clock = std::chrono::steady_clock,
|
||||
class Hash = std::hash <Key>,
|
||||
class KeyEqual = std::equal_to <Key>,
|
||||
class Allocator = std::allocator <Key>
|
||||
>
|
||||
using aged_unordered_multiset = detail::aged_unordered_container <
|
||||
true, false, Key, void, Duration, Hash, KeyEqual, Allocator>;
|
||||
true, false, Key, void, Clock, Hash, KeyEqual, Allocator>;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -30,13 +30,13 @@ namespace beast {
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class Duration = std::chrono::seconds,
|
||||
class Clock = std::chrono::steady_clock,
|
||||
class Hash = std::hash <Key>,
|
||||
class KeyEqual = std::equal_to <Key>,
|
||||
class Allocator = std::allocator <Key>
|
||||
>
|
||||
using aged_unordered_set = detail::aged_unordered_container <
|
||||
false, false, Key, void, Duration, Hash, KeyEqual, Allocator>;
|
||||
false, false, Key, void, Clock, Hash, KeyEqual, Allocator>;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -22,15 +22,11 @@
|
||||
|
||||
#include <beast/container/detail/aged_container_iterator.h>
|
||||
#include <beast/container/detail/aged_associative_container.h>
|
||||
|
||||
#include <beast/container/aged_container.h>
|
||||
|
||||
#include <beast/chrono/abstract_clock.h>
|
||||
#include <beast/utility/empty_base_optimization.h>
|
||||
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include <boost/intrusive/set.hpp>
|
||||
|
||||
#include <beast/cxx14/algorithm.h> // <algorithm>
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
@@ -75,7 +71,7 @@ template <
|
||||
bool IsMap,
|
||||
class Key,
|
||||
class T,
|
||||
class Duration = std::chrono::seconds,
|
||||
class Clock = std::chrono::steady_clock,
|
||||
class Compare = std::less <Key>,
|
||||
class Allocator = std::allocator <
|
||||
typename std::conditional <IsMap,
|
||||
@@ -85,25 +81,20 @@ template <
|
||||
class aged_ordered_container
|
||||
{
|
||||
public:
|
||||
typedef abstract_clock <Duration> clock_type;
|
||||
typedef typename clock_type::time_point time_point;
|
||||
typedef typename clock_type::duration duration;
|
||||
typedef Key key_type;
|
||||
typedef T mapped_type;
|
||||
typedef typename std::conditional <
|
||||
IsMap,
|
||||
std::pair <Key const, T>,
|
||||
Key>::type value_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
using clock_type = abstract_clock<Clock>;
|
||||
using time_point = typename clock_type::time_point;
|
||||
using duration = typename clock_type::duration;
|
||||
using key_type = Key;
|
||||
using mapped_type = T;
|
||||
using value_type = typename std::conditional <
|
||||
IsMap, std::pair <Key const, T>, Key>::type;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
// Introspection (for unit tests)
|
||||
typedef std::false_type is_unordered;
|
||||
typedef std::integral_constant <bool, IsMulti> is_multi;
|
||||
typedef std::integral_constant <bool, IsMap> is_map;
|
||||
|
||||
// VFALCO TODO How can we reorder the declarations to keep
|
||||
// all the public things together contiguously?
|
||||
using is_unordered = std::false_type;
|
||||
using is_multi = std::integral_constant <bool, IsMulti>;
|
||||
using is_map = std::integral_constant <bool, IsMap>;
|
||||
|
||||
private:
|
||||
static Key const& extract (value_type const& value)
|
||||
@@ -1237,8 +1228,8 @@ private:
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
class Clock, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
aged_ordered_container (
|
||||
clock_type& clock)
|
||||
: m_config (clock)
|
||||
@@ -1246,8 +1237,8 @@ aged_ordered_container (
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
class Clock, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
aged_ordered_container (
|
||||
clock_type& clock,
|
||||
Compare const& comp)
|
||||
@@ -1256,8 +1247,8 @@ aged_ordered_container (
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
class Clock, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
aged_ordered_container (
|
||||
clock_type& clock,
|
||||
Allocator const& alloc)
|
||||
@@ -1266,8 +1257,8 @@ aged_ordered_container (
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
class Clock, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
aged_ordered_container (
|
||||
clock_type& clock,
|
||||
Compare const& comp,
|
||||
@@ -1277,9 +1268,9 @@ aged_ordered_container (
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
template <class InputIt>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
aged_ordered_container (InputIt first, InputIt last,
|
||||
clock_type& clock)
|
||||
: m_config (clock)
|
||||
@@ -1288,9 +1279,9 @@ aged_ordered_container (InputIt first, InputIt last,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
template <class InputIt>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
aged_ordered_container (InputIt first, InputIt last,
|
||||
clock_type& clock,
|
||||
Compare const& comp)
|
||||
@@ -1300,9 +1291,9 @@ aged_ordered_container (InputIt first, InputIt last,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
template <class InputIt>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
aged_ordered_container (InputIt first, InputIt last,
|
||||
clock_type& clock,
|
||||
Allocator const& alloc)
|
||||
@@ -1312,9 +1303,9 @@ aged_ordered_container (InputIt first, InputIt last,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
template <class InputIt>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
aged_ordered_container (InputIt first, InputIt last,
|
||||
clock_type& clock,
|
||||
Compare const& comp,
|
||||
@@ -1325,8 +1316,8 @@ aged_ordered_container (InputIt first, InputIt last,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
class Clock, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
aged_ordered_container (aged_ordered_container const& other)
|
||||
: m_config (other.m_config)
|
||||
{
|
||||
@@ -1334,8 +1325,8 @@ aged_ordered_container (aged_ordered_container const& other)
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
class Clock, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
aged_ordered_container (aged_ordered_container const& other,
|
||||
Allocator const& alloc)
|
||||
: m_config (other.m_config, alloc)
|
||||
@@ -1344,8 +1335,8 @@ aged_ordered_container (aged_ordered_container const& other,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
class Clock, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
aged_ordered_container (aged_ordered_container&& other)
|
||||
: m_config (std::move (other.m_config))
|
||||
, m_cont (std::move (other.m_cont))
|
||||
@@ -1354,8 +1345,8 @@ aged_ordered_container (aged_ordered_container&& other)
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
class Clock, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
aged_ordered_container (aged_ordered_container&& other,
|
||||
Allocator const& alloc)
|
||||
: m_config (std::move (other.m_config), alloc)
|
||||
@@ -1365,8 +1356,8 @@ aged_ordered_container (aged_ordered_container&& other,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
class Clock, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
aged_ordered_container (std::initializer_list <value_type> init,
|
||||
clock_type& clock)
|
||||
: m_config (clock)
|
||||
@@ -1375,8 +1366,8 @@ aged_ordered_container (std::initializer_list <value_type> init,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
class Clock, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
aged_ordered_container (std::initializer_list <value_type> init,
|
||||
clock_type& clock,
|
||||
Compare const& comp)
|
||||
@@ -1386,8 +1377,8 @@ aged_ordered_container (std::initializer_list <value_type> init,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
class Clock, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
aged_ordered_container (std::initializer_list <value_type> init,
|
||||
clock_type& clock,
|
||||
Allocator const& alloc)
|
||||
@@ -1397,8 +1388,8 @@ aged_ordered_container (std::initializer_list <value_type> init,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
class Clock, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
aged_ordered_container (std::initializer_list <value_type> init,
|
||||
clock_type& clock,
|
||||
Compare const& comp,
|
||||
@@ -1409,17 +1400,17 @@ aged_ordered_container (std::initializer_list <value_type> init,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
class Clock, class Compare, class Allocator>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
~aged_ordered_container()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
auto
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
operator= (aged_ordered_container const& other) ->
|
||||
aged_ordered_container&
|
||||
{
|
||||
@@ -1433,9 +1424,9 @@ operator= (aged_ordered_container const& other) ->
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
auto
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
operator= (aged_ordered_container&& other) ->
|
||||
aged_ordered_container&
|
||||
{
|
||||
@@ -1447,9 +1438,9 @@ operator= (aged_ordered_container&& other) ->
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
auto
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
operator= (std::initializer_list <value_type> init) ->
|
||||
aged_ordered_container&
|
||||
{
|
||||
@@ -1461,10 +1452,10 @@ operator= (std::initializer_list <value_type> init) ->
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
template <class K, bool maybe_multi, bool maybe_map, class>
|
||||
typename std::conditional <IsMap, T, void*>::type&
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
at (K const& k)
|
||||
{
|
||||
auto const iter (m_cont.find (k,
|
||||
@@ -1475,10 +1466,10 @@ at (K const& k)
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
template <class K, bool maybe_multi, bool maybe_map, class>
|
||||
typename std::conditional <IsMap, T, void*>::type const&
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
at (K const& k) const
|
||||
{
|
||||
auto const iter (m_cont.find (k,
|
||||
@@ -1489,10 +1480,10 @@ at (K const& k) const
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
template <bool maybe_multi, bool maybe_map, class>
|
||||
typename std::conditional <IsMap, T, void*>::type&
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
operator[] (Key const& key)
|
||||
{
|
||||
typename cont_type::insert_commit_data d;
|
||||
@@ -1511,10 +1502,10 @@ operator[] (Key const& key)
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
template <bool maybe_multi, bool maybe_map, class>
|
||||
typename std::conditional <IsMap, T, void*>::type&
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
operator[] (Key&& key)
|
||||
{
|
||||
typename cont_type::insert_commit_data d;
|
||||
@@ -1536,9 +1527,9 @@ operator[] (Key&& key)
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
void
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
clear()
|
||||
{
|
||||
for (auto iter (chronological.list.begin());
|
||||
@@ -1550,10 +1541,10 @@ clear()
|
||||
|
||||
// map, set
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
template <bool maybe_multi>
|
||||
auto
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
insert (value_type const& value) ->
|
||||
typename std::enable_if <! maybe_multi,
|
||||
std::pair <iterator, bool>>::type
|
||||
@@ -1573,10 +1564,10 @@ insert (value_type const& value) ->
|
||||
|
||||
// multimap, multiset
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
template <bool maybe_multi>
|
||||
auto
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
insert (value_type const& value) ->
|
||||
typename std::enable_if <maybe_multi,
|
||||
iterator>::type
|
||||
@@ -1591,10 +1582,10 @@ insert (value_type const& value) ->
|
||||
|
||||
// set
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
template <bool maybe_multi, bool maybe_map>
|
||||
auto
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
insert (value_type&& value) ->
|
||||
typename std::enable_if <! maybe_multi && ! maybe_map,
|
||||
std::pair <iterator, bool>>::type
|
||||
@@ -1614,10 +1605,10 @@ insert (value_type&& value) ->
|
||||
|
||||
// multiset
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
template <bool maybe_multi, bool maybe_map>
|
||||
auto
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
insert (value_type&& value) ->
|
||||
typename std::enable_if <maybe_multi && ! maybe_map,
|
||||
iterator>::type
|
||||
@@ -1634,10 +1625,10 @@ insert (value_type&& value) ->
|
||||
|
||||
// map, set
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
template <bool maybe_multi>
|
||||
auto
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
insert (const_iterator hint, value_type const& value) ->
|
||||
typename std::enable_if <! maybe_multi,
|
||||
iterator>::type
|
||||
@@ -1657,10 +1648,10 @@ insert (const_iterator hint, value_type const& value) ->
|
||||
|
||||
// map, set
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
template <bool maybe_multi>
|
||||
auto
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
insert (const_iterator hint, value_type&& value) ->
|
||||
typename std::enable_if <! maybe_multi,
|
||||
iterator>::type
|
||||
@@ -1680,10 +1671,10 @@ insert (const_iterator hint, value_type&& value) ->
|
||||
|
||||
// map, set
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
template <bool maybe_multi, class... Args>
|
||||
auto
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
emplace (Args&&... args) ->
|
||||
typename std::enable_if <! maybe_multi,
|
||||
std::pair <iterator, bool>>::type
|
||||
@@ -1707,10 +1698,10 @@ emplace (Args&&... args) ->
|
||||
|
||||
// multiset, multimap
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
template <bool maybe_multi, class... Args>
|
||||
auto
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
emplace (Args&&... args) ->
|
||||
typename std::enable_if <maybe_multi,
|
||||
iterator>::type
|
||||
@@ -1726,10 +1717,10 @@ emplace (Args&&... args) ->
|
||||
|
||||
// map, set
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
template <bool maybe_multi, class... Args>
|
||||
auto
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
emplace_hint (const_iterator hint, Args&&... args) ->
|
||||
typename std::enable_if <! maybe_multi,
|
||||
std::pair <iterator, bool>>::type
|
||||
@@ -1752,10 +1743,10 @@ emplace_hint (const_iterator hint, Args&&... args) ->
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
template <bool is_const, class Iterator, class Base, class>
|
||||
detail::aged_container_iterator <false, Iterator, Base>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
erase (detail::aged_container_iterator <is_const, Iterator, Base> pos)
|
||||
{
|
||||
unlink_and_delete_element(&*((pos++).iterator()));
|
||||
@@ -1764,10 +1755,10 @@ erase (detail::aged_container_iterator <is_const, Iterator, Base> pos)
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
template <bool is_const, class Iterator, class Base, class>
|
||||
detail::aged_container_iterator <false, Iterator, Base>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
erase (detail::aged_container_iterator <is_const, Iterator, Base> first,
|
||||
detail::aged_container_iterator <is_const, Iterator, Base> last)
|
||||
{
|
||||
@@ -1779,10 +1770,10 @@ erase (detail::aged_container_iterator <is_const, Iterator, Base> first,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
template <class K>
|
||||
auto
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
erase (K const& k) ->
|
||||
size_type
|
||||
{
|
||||
@@ -1805,9 +1796,9 @@ erase (K const& k) ->
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
void
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
swap (aged_ordered_container& other) noexcept
|
||||
{
|
||||
swap_data (other);
|
||||
@@ -1818,10 +1809,10 @@ swap (aged_ordered_container& other) noexcept
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
template <class K>
|
||||
auto
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
touch (K const& k) ->
|
||||
size_type
|
||||
{
|
||||
@@ -1839,11 +1830,11 @@ touch (K const& k) ->
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
template <bool OtherIsMulti, bool OtherIsMap,
|
||||
class OtherT, class OtherDuration, class OtherAllocator>
|
||||
bool
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
operator== (
|
||||
aged_ordered_container <OtherIsMulti, OtherIsMap,
|
||||
Key, OtherT, OtherDuration, Compare,
|
||||
@@ -1866,10 +1857,10 @@ operator== (
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
template <bool is_const, class Iterator, class Base, class>
|
||||
void
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
touch (detail::aged_container_iterator <
|
||||
is_const, Iterator, Base> pos,
|
||||
typename clock_type::time_point const& now)
|
||||
@@ -1881,10 +1872,10 @@ touch (detail::aged_container_iterator <
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
template <bool maybe_propagate>
|
||||
typename std::enable_if <maybe_propagate>::type
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
swap_data (aged_ordered_container& other) noexcept
|
||||
{
|
||||
std::swap (m_config.key_compare(), other.m_config.key_compare());
|
||||
@@ -1893,10 +1884,10 @@ swap_data (aged_ordered_container& other) noexcept
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
template <bool maybe_propagate>
|
||||
typename std::enable_if <! maybe_propagate>::type
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
||||
swap_data (aged_ordered_container& other) noexcept
|
||||
{
|
||||
std::swap (m_config.key_compare(), other.m_config.key_compare());
|
||||
@@ -1908,9 +1899,9 @@ swap_data (aged_ordered_container& other) noexcept
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
struct is_aged_container <detail::aged_ordered_container <
|
||||
IsMulti, IsMap, Key, T, Duration, Compare, Allocator>>
|
||||
IsMulti, IsMap, Key, T, Clock, Compare, Allocator>>
|
||||
: std::true_type
|
||||
{
|
||||
};
|
||||
@@ -1918,22 +1909,22 @@ struct is_aged_container <detail::aged_ordered_container <
|
||||
// Free functions
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
class Clock, class Compare, class Allocator>
|
||||
void swap (
|
||||
detail::aged_ordered_container <IsMulti, IsMap,
|
||||
Key, T, Duration, Compare, Allocator>& lhs,
|
||||
Key, T, Clock, Compare, Allocator>& lhs,
|
||||
detail::aged_ordered_container <IsMulti, IsMap,
|
||||
Key, T, Duration, Compare, Allocator>& rhs) noexcept
|
||||
Key, T, Clock, Compare, Allocator>& rhs) noexcept
|
||||
{
|
||||
lhs.swap (rhs);
|
||||
}
|
||||
|
||||
/** Expire aged container items past the specified age. */
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator,
|
||||
class Clock, class Compare, class Allocator,
|
||||
class Rep, class Period>
|
||||
std::size_t expire (detail::aged_ordered_container <
|
||||
IsMulti, IsMap, Key, T, Duration, Compare, Allocator>& c,
|
||||
IsMulti, IsMap, Key, T, Clock, Compare, Allocator>& c,
|
||||
std::chrono::duration <Rep, Period> const& age)
|
||||
{
|
||||
std::size_t n (0);
|
||||
|
||||
@@ -22,15 +22,11 @@
|
||||
|
||||
#include <beast/container/detail/aged_container_iterator.h>
|
||||
#include <beast/container/detail/aged_associative_container.h>
|
||||
|
||||
#include <beast/container/aged_container.h>
|
||||
|
||||
#include <beast/chrono/abstract_clock.h>
|
||||
#include <beast/utility/empty_base_optimization.h>
|
||||
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include <boost/intrusive/unordered_set.hpp>
|
||||
|
||||
#include <beast/cxx14/algorithm.h> // <algorithm>
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
@@ -80,7 +76,7 @@ template <
|
||||
bool IsMap,
|
||||
class Key,
|
||||
class T,
|
||||
class Duration = std::chrono::seconds,
|
||||
class Clock = std::chrono::steady_clock,
|
||||
class Hash = std::hash <Key>,
|
||||
class KeyEqual = std::equal_to <Key>,
|
||||
class Allocator = std::allocator <
|
||||
@@ -91,24 +87,20 @@ template <
|
||||
class aged_unordered_container
|
||||
{
|
||||
public:
|
||||
typedef abstract_clock <Duration> clock_type;
|
||||
typedef typename clock_type::time_point time_point;
|
||||
typedef typename clock_type::duration duration;
|
||||
typedef Key key_type;
|
||||
typedef T mapped_type;
|
||||
typedef typename std::conditional <IsMap,
|
||||
std::pair <Key const, T>,
|
||||
Key>::type value_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
using clock_type = abstract_clock<Clock>;
|
||||
using time_point = typename clock_type::time_point;
|
||||
using duration = typename clock_type::duration;
|
||||
using key_type = Key;
|
||||
using mapped_type = T;
|
||||
using value_type = typename std::conditional <IsMap,
|
||||
std::pair <Key const, T>, Key>::type;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
// Introspection (for unit tests)
|
||||
typedef std::true_type is_unordered;
|
||||
typedef std::integral_constant <bool, IsMulti> is_multi;
|
||||
typedef std::integral_constant <bool, IsMap> is_map;
|
||||
|
||||
// VFALCO TODO How can we reorder the declarations to keep
|
||||
// all the public things together contiguously?
|
||||
using is_unordered = std::true_type;
|
||||
using is_multi = std::integral_constant <bool, IsMulti>;
|
||||
using is_map = std::integral_constant <bool, IsMap>;
|
||||
|
||||
private:
|
||||
static Key const& extract (value_type const& value)
|
||||
@@ -1504,8 +1496,8 @@ private:
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (
|
||||
clock_type& clock)
|
||||
@@ -1517,8 +1509,8 @@ aged_unordered_container (
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (
|
||||
clock_type& clock,
|
||||
@@ -1531,8 +1523,8 @@ aged_unordered_container (
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (
|
||||
clock_type& clock,
|
||||
@@ -1545,8 +1537,8 @@ aged_unordered_container (
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (
|
||||
clock_type& clock,
|
||||
@@ -1560,8 +1552,8 @@ aged_unordered_container (
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (
|
||||
clock_type& clock,
|
||||
@@ -1575,8 +1567,8 @@ aged_unordered_container (
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (
|
||||
clock_type& clock,
|
||||
@@ -1591,8 +1583,8 @@ aged_unordered_container (
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (
|
||||
clock_type& clock,
|
||||
@@ -1607,8 +1599,8 @@ aged_unordered_container (
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (
|
||||
clock_type& clock,
|
||||
@@ -1624,9 +1616,9 @@ aged_unordered_container (
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <class InputIt>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (InputIt first, InputIt last,
|
||||
clock_type& clock)
|
||||
@@ -1639,9 +1631,9 @@ aged_unordered_container (InputIt first, InputIt last,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <class InputIt>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (InputIt first, InputIt last,
|
||||
clock_type& clock,
|
||||
@@ -1655,9 +1647,9 @@ aged_unordered_container (InputIt first, InputIt last,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <class InputIt>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (InputIt first, InputIt last,
|
||||
clock_type& clock,
|
||||
@@ -1671,9 +1663,9 @@ aged_unordered_container (InputIt first, InputIt last,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <class InputIt>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (InputIt first, InputIt last,
|
||||
clock_type& clock,
|
||||
@@ -1688,9 +1680,9 @@ aged_unordered_container (InputIt first, InputIt last,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <class InputIt>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (InputIt first, InputIt last,
|
||||
clock_type& clock,
|
||||
@@ -1705,9 +1697,9 @@ aged_unordered_container (InputIt first, InputIt last,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <class InputIt>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (InputIt first, InputIt last,
|
||||
clock_type& clock,
|
||||
@@ -1723,9 +1715,9 @@ aged_unordered_container (InputIt first, InputIt last,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <class InputIt>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (InputIt first, InputIt last,
|
||||
clock_type& clock,
|
||||
@@ -1741,9 +1733,9 @@ aged_unordered_container (InputIt first, InputIt last,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <class InputIt>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (InputIt first, InputIt last,
|
||||
clock_type& clock,
|
||||
@@ -1760,8 +1752,8 @@ aged_unordered_container (InputIt first, InputIt last,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (aged_unordered_container const& other)
|
||||
: m_config (other.m_config)
|
||||
@@ -1774,8 +1766,8 @@ aged_unordered_container (aged_unordered_container const& other)
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (aged_unordered_container const& other,
|
||||
Allocator const& alloc)
|
||||
@@ -1789,8 +1781,8 @@ aged_unordered_container (aged_unordered_container const& other,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (aged_unordered_container&& other)
|
||||
: m_config (std::move (other.m_config))
|
||||
@@ -1801,8 +1793,8 @@ aged_unordered_container (aged_unordered_container&& other)
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (aged_unordered_container&& other,
|
||||
Allocator const& alloc)
|
||||
@@ -1817,8 +1809,8 @@ aged_unordered_container (aged_unordered_container&& other,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (std::initializer_list <value_type> init,
|
||||
clock_type& clock)
|
||||
@@ -1831,8 +1823,8 @@ aged_unordered_container (std::initializer_list <value_type> init,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (std::initializer_list <value_type> init,
|
||||
clock_type& clock,
|
||||
@@ -1846,8 +1838,8 @@ aged_unordered_container (std::initializer_list <value_type> init,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (std::initializer_list <value_type> init,
|
||||
clock_type& clock,
|
||||
@@ -1861,8 +1853,8 @@ aged_unordered_container (std::initializer_list <value_type> init,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (std::initializer_list <value_type> init,
|
||||
clock_type& clock,
|
||||
@@ -1877,8 +1869,8 @@ aged_unordered_container (std::initializer_list <value_type> init,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (std::initializer_list <value_type> init,
|
||||
clock_type& clock,
|
||||
@@ -1893,8 +1885,8 @@ aged_unordered_container (std::initializer_list <value_type> init,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (std::initializer_list <value_type> init,
|
||||
clock_type& clock,
|
||||
@@ -1910,8 +1902,8 @@ aged_unordered_container (std::initializer_list <value_type> init,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (std::initializer_list <value_type> init,
|
||||
clock_type& clock,
|
||||
@@ -1927,8 +1919,8 @@ aged_unordered_container (std::initializer_list <value_type> init,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container (std::initializer_list <value_type> init,
|
||||
clock_type& clock,
|
||||
@@ -1945,8 +1937,8 @@ aged_unordered_container (std::initializer_list <value_type> init,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
~aged_unordered_container()
|
||||
{
|
||||
@@ -1954,9 +1946,9 @@ aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
auto
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
operator= (aged_unordered_container const& other)
|
||||
-> aged_unordered_container&
|
||||
@@ -1974,9 +1966,9 @@ operator= (aged_unordered_container const& other)
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
auto
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
operator= (aged_unordered_container&& other) ->
|
||||
aged_unordered_container&
|
||||
@@ -1992,9 +1984,9 @@ operator= (aged_unordered_container&& other) ->
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
auto
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
operator= (std::initializer_list <value_type> init) ->
|
||||
aged_unordered_container&
|
||||
@@ -2007,10 +1999,10 @@ operator= (std::initializer_list <value_type> init) ->
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <class K, bool maybe_multi, bool maybe_map, class>
|
||||
typename std::conditional <IsMap, T, void*>::type&
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
at (K const& k)
|
||||
{
|
||||
@@ -2023,10 +2015,10 @@ at (K const& k)
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <class K, bool maybe_multi, bool maybe_map, class>
|
||||
typename std::conditional <IsMap, T, void*>::type const&
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
at (K const& k) const
|
||||
{
|
||||
@@ -2039,10 +2031,10 @@ at (K const& k) const
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <bool maybe_multi, bool maybe_map, class>
|
||||
typename std::conditional <IsMap, T, void*>::type&
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
operator[] (Key const& key)
|
||||
{
|
||||
@@ -2065,10 +2057,10 @@ operator[] (Key const& key)
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <bool maybe_multi, bool maybe_map, class>
|
||||
typename std::conditional <IsMap, T, void*>::type&
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
operator[] (Key&& key)
|
||||
{
|
||||
@@ -2093,9 +2085,9 @@ operator[] (Key&& key)
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
void
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
clear()
|
||||
{
|
||||
@@ -2109,10 +2101,10 @@ clear()
|
||||
|
||||
// map, set
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <bool maybe_multi>
|
||||
auto
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
insert (value_type const& value) ->
|
||||
typename std::enable_if <! maybe_multi,
|
||||
@@ -2135,10 +2127,10 @@ insert (value_type const& value) ->
|
||||
|
||||
// multimap, multiset
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <bool maybe_multi>
|
||||
auto
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
insert (value_type const& value) ->
|
||||
typename std::enable_if <maybe_multi,
|
||||
@@ -2153,10 +2145,10 @@ insert (value_type const& value) ->
|
||||
|
||||
// map, set
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <bool maybe_multi, bool maybe_map>
|
||||
auto
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
insert (value_type&& value) ->
|
||||
typename std::enable_if <! maybe_multi && ! maybe_map,
|
||||
@@ -2179,10 +2171,10 @@ insert (value_type&& value) ->
|
||||
|
||||
// multimap, multiset
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <bool maybe_multi, bool maybe_map>
|
||||
auto
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
insert (value_type&& value) ->
|
||||
typename std::enable_if <maybe_multi && ! maybe_map,
|
||||
@@ -2198,10 +2190,10 @@ insert (value_type&& value) ->
|
||||
#if 1 // Use insert() instead of insert_check() insert_commit()
|
||||
// set, map
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <bool maybe_multi, class... Args>
|
||||
auto
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
emplace (Args&&... args) ->
|
||||
typename std::enable_if <! maybe_multi,
|
||||
@@ -2223,10 +2215,10 @@ emplace (Args&&... args) ->
|
||||
#else // As original, use insert_check() / insert_commit () pair.
|
||||
// set, map
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <bool maybe_multi, class... Args>
|
||||
auto
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
emplace (Args&&... args) ->
|
||||
typename std::enable_if <! maybe_multi,
|
||||
@@ -2254,10 +2246,10 @@ emplace (Args&&... args) ->
|
||||
|
||||
// multiset, multimap
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <bool maybe_multi, class... Args>
|
||||
auto
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
emplace (Args&&... args) ->
|
||||
typename std::enable_if <maybe_multi,
|
||||
@@ -2273,10 +2265,10 @@ emplace (Args&&... args) ->
|
||||
|
||||
// set, map
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <bool maybe_multi, class... Args>
|
||||
auto
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
emplace_hint (const_iterator /*hint*/, Args&&... args) ->
|
||||
typename std::enable_if <! maybe_multi,
|
||||
@@ -2302,10 +2294,10 @@ emplace_hint (const_iterator /*hint*/, Args&&... args) ->
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <bool is_const, class Iterator, class Base>
|
||||
detail::aged_container_iterator <false, Iterator, Base>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
erase (detail::aged_container_iterator <
|
||||
is_const, Iterator, Base> pos)
|
||||
@@ -2316,10 +2308,10 @@ erase (detail::aged_container_iterator <
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <bool is_const, class Iterator, class Base>
|
||||
detail::aged_container_iterator <false, Iterator, Base>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
erase (detail::aged_container_iterator <
|
||||
is_const, Iterator, Base> first,
|
||||
@@ -2334,10 +2326,10 @@ erase (detail::aged_container_iterator <
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <class K>
|
||||
auto
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
erase (K const& k) ->
|
||||
size_type
|
||||
@@ -2361,9 +2353,9 @@ erase (K const& k) ->
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
void
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
swap (aged_unordered_container& other) noexcept
|
||||
{
|
||||
@@ -2373,10 +2365,10 @@ swap (aged_unordered_container& other) noexcept
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <class K>
|
||||
auto
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
touch (K const& k) ->
|
||||
size_type
|
||||
@@ -2393,7 +2385,7 @@ touch (K const& k) ->
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <
|
||||
bool OtherIsMap,
|
||||
class OtherKey,
|
||||
@@ -2405,7 +2397,7 @@ template <
|
||||
>
|
||||
typename std::enable_if <! maybe_multi, bool>::type
|
||||
aged_unordered_container <
|
||||
IsMulti, IsMap, Key, T, Duration, Hash, KeyEqual, Allocator>::
|
||||
IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::
|
||||
operator== (
|
||||
aged_unordered_container <false, OtherIsMap,
|
||||
OtherKey, OtherT, OtherDuration, OtherHash, KeyEqual,
|
||||
@@ -2424,7 +2416,7 @@ operator== (
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <
|
||||
bool OtherIsMap,
|
||||
class OtherKey,
|
||||
@@ -2436,7 +2428,7 @@ template <
|
||||
>
|
||||
typename std::enable_if <maybe_multi, bool>::type
|
||||
aged_unordered_container <
|
||||
IsMulti, IsMap, Key, T, Duration, Hash, KeyEqual, Allocator>::
|
||||
IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::
|
||||
operator== (
|
||||
aged_unordered_container <true, OtherIsMap,
|
||||
OtherKey, OtherT, OtherDuration, OtherHash, KeyEqual,
|
||||
@@ -2469,10 +2461,10 @@ operator== (
|
||||
|
||||
// map, set
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <bool maybe_multi>
|
||||
auto
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
insert_unchecked (value_type const& value) ->
|
||||
typename std::enable_if <! maybe_multi,
|
||||
@@ -2494,10 +2486,10 @@ insert_unchecked (value_type const& value) ->
|
||||
|
||||
// multimap, multiset
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
template <bool maybe_multi>
|
||||
auto
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Clock,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
insert_unchecked (value_type const& value) ->
|
||||
typename std::enable_if <maybe_multi,
|
||||
@@ -2516,32 +2508,32 @@ insert_unchecked (value_type const& value) ->
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
class Clock, class Hash, class KeyEqual, class Allocator>
|
||||
struct is_aged_container <detail::aged_unordered_container <
|
||||
IsMulti, IsMap, Key, T, Duration, Hash, KeyEqual, Allocator>>
|
||||
IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>>
|
||||
: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
// Free functions
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T, class Duration,
|
||||
template <bool IsMulti, bool IsMap, class Key, class T, class Clock,
|
||||
class Hash, class KeyEqual, class Allocator>
|
||||
void swap (
|
||||
detail::aged_unordered_container <IsMulti, IsMap,
|
||||
Key, T, Duration, Hash, KeyEqual, Allocator>& lhs,
|
||||
Key, T, Clock, Hash, KeyEqual, Allocator>& lhs,
|
||||
detail::aged_unordered_container <IsMulti, IsMap,
|
||||
Key, T, Duration, Hash, KeyEqual, Allocator>& rhs) noexcept
|
||||
Key, T, Clock, Hash, KeyEqual, Allocator>& rhs) noexcept
|
||||
{
|
||||
lhs.swap (rhs);
|
||||
}
|
||||
|
||||
/** Expire aged container items past the specified age. */
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator,
|
||||
class Clock, class Hash, class KeyEqual, class Allocator,
|
||||
class Rep, class Period>
|
||||
std::size_t expire (detail::aged_unordered_container <
|
||||
IsMulti, IsMap, Key, T, Duration, Hash, KeyEqual, Allocator>& c,
|
||||
IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>& c,
|
||||
std::chrono::duration <Rep, Period> const& age) noexcept
|
||||
{
|
||||
std::size_t n (0);
|
||||
|
||||
@@ -302,7 +302,7 @@ public:
|
||||
>
|
||||
using Cont = detail::aged_ordered_container <
|
||||
Base::is_multi::value, Base::is_map::value, typename Base::Key,
|
||||
typename Base::T, typename Base::Dur, Compare, Allocator>;
|
||||
typename Base::T, typename Base::Clock, Compare, Allocator>;
|
||||
};
|
||||
|
||||
// unordered
|
||||
@@ -318,7 +318,7 @@ public:
|
||||
>
|
||||
using Cont = detail::aged_unordered_container <
|
||||
Base::is_multi::value, Base::is_map::value,
|
||||
typename Base::Key, typename Base::T, typename Base::Dur,
|
||||
typename Base::Key, typename Base::T, typename Base::Clock,
|
||||
Hash, KeyEqual, Allocator>;
|
||||
};
|
||||
|
||||
@@ -327,8 +327,8 @@ public:
|
||||
struct TestTraitsBase
|
||||
{
|
||||
typedef std::string Key;
|
||||
typedef std::chrono::seconds Dur;
|
||||
typedef manual_clock <Dur> Clock;
|
||||
typedef std::chrono::steady_clock Clock;
|
||||
typedef manual_clock<Clock> ManualClock;
|
||||
};
|
||||
|
||||
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
||||
@@ -744,12 +744,12 @@ testConstructEmpty ()
|
||||
typedef typename Traits::Value Value;
|
||||
typedef typename Traits::Key Key;
|
||||
typedef typename Traits::T T;
|
||||
typedef typename Traits::Dur Dur;
|
||||
typedef typename Traits::Clock Clock;
|
||||
typedef typename Traits::Comp Comp;
|
||||
typedef typename Traits::Alloc Alloc;
|
||||
typedef typename Traits::MyComp MyComp;
|
||||
typedef typename Traits::MyAlloc MyAlloc;
|
||||
typename Traits::Clock clock;
|
||||
typename Traits::ManualClock clock;
|
||||
|
||||
//testcase (Traits::name() + " empty");
|
||||
testcase ("empty");
|
||||
@@ -789,14 +789,14 @@ testConstructEmpty ()
|
||||
typedef typename Traits::Value Value;
|
||||
typedef typename Traits::Key Key;
|
||||
typedef typename Traits::T T;
|
||||
typedef typename Traits::Dur Dur;
|
||||
typedef typename Traits::Clock Clock;
|
||||
typedef typename Traits::Hash Hash;
|
||||
typedef typename Traits::Equal Equal;
|
||||
typedef typename Traits::Alloc Alloc;
|
||||
typedef typename Traits::MyHash MyHash;
|
||||
typedef typename Traits::MyEqual MyEqual;
|
||||
typedef typename Traits::MyAlloc MyAlloc;
|
||||
typename Traits::Clock clock;
|
||||
typename Traits::ManualClock clock;
|
||||
|
||||
//testcase (Traits::name() + " empty");
|
||||
testcase ("empty");
|
||||
@@ -859,12 +859,12 @@ testConstructRange ()
|
||||
typedef typename Traits::Value Value;
|
||||
typedef typename Traits::Key Key;
|
||||
typedef typename Traits::T T;
|
||||
typedef typename Traits::Dur Dur;
|
||||
typedef typename Traits::Clock Clock;
|
||||
typedef typename Traits::Comp Comp;
|
||||
typedef typename Traits::Alloc Alloc;
|
||||
typedef typename Traits::MyComp MyComp;
|
||||
typedef typename Traits::MyAlloc MyAlloc;
|
||||
typename Traits::Clock clock;
|
||||
typename Traits::ManualClock clock;
|
||||
auto const v (Traits::values());
|
||||
|
||||
//testcase (Traits::name() + " range");
|
||||
@@ -922,14 +922,14 @@ testConstructRange ()
|
||||
typedef typename Traits::Value Value;
|
||||
typedef typename Traits::Key Key;
|
||||
typedef typename Traits::T T;
|
||||
typedef typename Traits::Dur Dur;
|
||||
typedef typename Traits::Clock Clock;
|
||||
typedef typename Traits::Hash Hash;
|
||||
typedef typename Traits::Equal Equal;
|
||||
typedef typename Traits::Alloc Alloc;
|
||||
typedef typename Traits::MyHash MyHash;
|
||||
typedef typename Traits::MyEqual MyEqual;
|
||||
typedef typename Traits::MyAlloc MyAlloc;
|
||||
typename Traits::Clock clock;
|
||||
typename Traits::ManualClock clock;
|
||||
auto const v (Traits::values());
|
||||
|
||||
//testcase (Traits::name() + " range");
|
||||
@@ -1002,12 +1002,12 @@ testConstructInitList ()
|
||||
typedef typename Traits::Value Value;
|
||||
typedef typename Traits::Key Key;
|
||||
typedef typename Traits::T T;
|
||||
typedef typename Traits::Dur Dur;
|
||||
typedef typename Traits::Clock Clock;
|
||||
typedef typename Traits::Comp Comp;
|
||||
typedef typename Traits::Alloc Alloc;
|
||||
typedef typename Traits::MyComp MyComp;
|
||||
typedef typename Traits::MyAlloc MyAlloc;
|
||||
typename Traits::Clock clock;
|
||||
typename Traits::ManualClock clock;
|
||||
|
||||
//testcase (Traits::name() + " init-list");
|
||||
testcase ("init-list");
|
||||
@@ -1027,14 +1027,14 @@ testConstructInitList ()
|
||||
typedef typename Traits::Value Value;
|
||||
typedef typename Traits::Key Key;
|
||||
typedef typename Traits::T T;
|
||||
typedef typename Traits::Dur Dur;
|
||||
typedef typename Traits::Clock Clock;
|
||||
typedef typename Traits::Hash Hash;
|
||||
typedef typename Traits::Equal Equal;
|
||||
typedef typename Traits::Alloc Alloc;
|
||||
typedef typename Traits::MyHash MyHash;
|
||||
typedef typename Traits::MyEqual MyEqual;
|
||||
typedef typename Traits::MyAlloc MyAlloc;
|
||||
typename Traits::Clock clock;
|
||||
typename Traits::ManualClock clock;
|
||||
|
||||
//testcase (Traits::name() + " init-list");
|
||||
testcase ("init-list");
|
||||
@@ -1057,7 +1057,7 @@ testCopyMove ()
|
||||
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
||||
typedef typename Traits::Value Value;
|
||||
typedef typename Traits::Alloc Alloc;
|
||||
typename Traits::Clock clock;
|
||||
typename Traits::ManualClock clock;
|
||||
auto const v (Traits::values());
|
||||
|
||||
//testcase (Traits::name() + " copy/move");
|
||||
@@ -1139,7 +1139,7 @@ testIterator()
|
||||
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
||||
typedef typename Traits::Value Value;
|
||||
typedef typename Traits::Alloc Alloc;
|
||||
typename Traits::Clock clock;
|
||||
typename Traits::ManualClock clock;
|
||||
auto const v (Traits::values());
|
||||
|
||||
//testcase (Traits::name() + " iterators");
|
||||
@@ -1202,7 +1202,7 @@ testReverseIterator()
|
||||
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
||||
typedef typename Traits::Value Value;
|
||||
typedef typename Traits::Alloc Alloc;
|
||||
typename Traits::Clock clock;
|
||||
typename Traits::ManualClock clock;
|
||||
auto const v (Traits::values());
|
||||
|
||||
//testcase (Traits::name() + " reverse_iterators");
|
||||
@@ -1357,7 +1357,7 @@ aged_associative_container_test_base::
|
||||
testModifiers()
|
||||
{
|
||||
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
||||
typename Traits::Clock clock;
|
||||
typename Traits::ManualClock clock;
|
||||
auto const v (Traits::values());
|
||||
auto const l (make_list (v));
|
||||
|
||||
@@ -1418,7 +1418,7 @@ testChronological ()
|
||||
{
|
||||
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
||||
typedef typename Traits::Value Value;
|
||||
typename Traits::Clock clock;
|
||||
typename Traits::ManualClock clock;
|
||||
auto const v (Traits::values());
|
||||
|
||||
//testcase (Traits::name() + " chronological");
|
||||
@@ -1484,7 +1484,7 @@ aged_associative_container_test_base::
|
||||
testArrayCreate()
|
||||
{
|
||||
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
||||
typename Traits::Clock clock;
|
||||
typename Traits::ManualClock clock;
|
||||
auto v (Traits::values());
|
||||
|
||||
//testcase (Traits::name() + " array create");
|
||||
@@ -1522,8 +1522,9 @@ reverseFillAgedContainer (Container& c, Values const& values)
|
||||
c.clear();
|
||||
|
||||
// c.clock() returns an abstract_clock, so dynamic_cast to manual_clock.
|
||||
typedef TestTraitsBase::Clock Clock;
|
||||
Clock& clk (dynamic_cast <Clock&> (c.clock ()));
|
||||
// VFALCO NOTE This is sketchy
|
||||
typedef TestTraitsBase::ManualClock ManualClock;
|
||||
ManualClock& clk (dynamic_cast <ManualClock&> (c.clock()));
|
||||
clk.set (0);
|
||||
|
||||
Values rev (values);
|
||||
@@ -1626,8 +1627,8 @@ testElementErase ()
|
||||
testcase ("element erase");
|
||||
|
||||
// Make and fill the container
|
||||
typename Traits::Clock ck;
|
||||
typename Traits::template Cont <> c {ck};
|
||||
typename Traits::ManualClock clock;
|
||||
typename Traits::template Cont <> c {clock};
|
||||
reverseFillAgedContainer (c, Traits::values());
|
||||
|
||||
{
|
||||
@@ -1756,8 +1757,8 @@ testRangeErase ()
|
||||
testcase ("range erase");
|
||||
|
||||
// Make and fill the container
|
||||
typename Traits::Clock ck;
|
||||
typename Traits::template Cont <> c {ck};
|
||||
typename Traits::ManualClock clock;
|
||||
typename Traits::template Cont <> c {clock};
|
||||
reverseFillAgedContainer (c, Traits::values());
|
||||
|
||||
// Not bothering to test range erase with reverse iterators.
|
||||
@@ -1785,7 +1786,7 @@ testCompare ()
|
||||
{
|
||||
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
||||
typedef typename Traits::Value Value;
|
||||
typename Traits::Clock clock;
|
||||
typename Traits::ManualClock clock;
|
||||
auto const v (Traits::values());
|
||||
|
||||
//testcase (Traits::name() + " array create");
|
||||
@@ -1819,7 +1820,7 @@ aged_associative_container_test_base::
|
||||
testObservers()
|
||||
{
|
||||
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
||||
typename Traits::Clock clock;
|
||||
typename Traits::ManualClock clock;
|
||||
|
||||
//testcase (Traits::name() + " observers");
|
||||
testcase ("observers");
|
||||
@@ -1838,7 +1839,7 @@ aged_associative_container_test_base::
|
||||
testObservers()
|
||||
{
|
||||
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
||||
typename Traits::Clock clock;
|
||||
typename Traits::ManualClock clock;
|
||||
|
||||
//testcase (Traits::name() + " observers");
|
||||
testcase ("observers");
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include <BeastConfig.h>
|
||||
#endif
|
||||
|
||||
#include <beast/crypto/impl/MurmurHash.cpp>
|
||||
#include <beast/crypto/impl/Sha256.cpp>
|
||||
|
||||
#include <beast/crypto/tests/base64.test.cpp>
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, 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_CRYPTO_MURMURHASH_H_INCLUDED
|
||||
#define BEAST_CRYPTO_MURMURHASH_H_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
|
||||
// Original source code links in .cpp file
|
||||
|
||||
namespace beast {
|
||||
namespace Murmur {
|
||||
|
||||
extern void MurmurHash3_x86_32 (const void* key, int len, std::uint32_t seed, void* out);
|
||||
extern void MurmurHash3_x86_128 (const void* key, int len, std::uint32_t seed, void* out);
|
||||
extern void MurmurHash3_x64_128 (const void* key, int len, std::uint32_t seed, void* out);
|
||||
|
||||
// Uses Beast to choose an appropriate routine
|
||||
|
||||
// This handy template deduces which size hash is desired
|
||||
template <typename HashType>
|
||||
inline void Hash (const void* key, int len, std::uint32_t seed, HashType* out)
|
||||
{
|
||||
switch (8 * sizeof (HashType))
|
||||
{
|
||||
case 32:
|
||||
MurmurHash3_x86_32 (key, len, seed, out);
|
||||
break;
|
||||
|
||||
#if BEAST_64BIT
|
||||
case 64:
|
||||
{
|
||||
HashType tmp[2];
|
||||
MurmurHash3_x64_128 (key, len, seed, &tmp[0]);
|
||||
*out = tmp[0];
|
||||
}
|
||||
break;
|
||||
|
||||
case 128:
|
||||
MurmurHash3_x64_128 (key, len, seed, out);
|
||||
break;
|
||||
|
||||
#else
|
||||
case 64:
|
||||
{
|
||||
HashType tmp[2];
|
||||
MurmurHash3_x86_128 (key, len, seed, &tmp[0]);
|
||||
*out = tmp[0];
|
||||
}
|
||||
break;
|
||||
|
||||
case 128:
|
||||
MurmurHash3_x86_128 (key, len, seed, out);
|
||||
break;
|
||||
|
||||
#endif
|
||||
|
||||
default:
|
||||
throw std::runtime_error ("invalid key size in MurmurHash");
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,492 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, 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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
// http://code.google.com/p/smhasher/
|
||||
|
||||
#include <beast/crypto/MurmurHash.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace beast {
|
||||
namespace Murmur {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Platform-specific functions and macros
|
||||
|
||||
// Microsoft Visual Studio
|
||||
|
||||
#if BEAST_MSVC
|
||||
|
||||
#define ROTL32(x,y) _rotl(x,y)
|
||||
#define ROTL64(x,y) _rotl64(x,y)
|
||||
|
||||
#define BIG_CONSTANT(x) (x)
|
||||
|
||||
// Other compilers
|
||||
|
||||
#else
|
||||
|
||||
static inline std::uint32_t rotl32 ( std::uint32_t x, int8_t r )
|
||||
{
|
||||
return (x << r) | (x >> (32 - r));
|
||||
}
|
||||
|
||||
static inline std::uint64_t rotl64 ( std::uint64_t x, int8_t r )
|
||||
{
|
||||
return (x << r) | (x >> (64 - r));
|
||||
}
|
||||
|
||||
#define ROTL32(x,y) rotl32(x,y)
|
||||
#define ROTL64(x,y) rotl64(x,y)
|
||||
|
||||
#define BIG_CONSTANT(x) (x##LLU)
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Block read - if your platform needs to do endian-swapping or can only
|
||||
// handle aligned reads, do the conversion here
|
||||
|
||||
static inline std::uint32_t getblock ( const std::uint32_t* p, int i )
|
||||
{
|
||||
return p[i];
|
||||
}
|
||||
|
||||
static inline std::uint64_t getblock ( const std::uint64_t* p, int i )
|
||||
{
|
||||
return p[i];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Finalization mix - force all bits of a hash block to avalanche
|
||||
|
||||
static inline std::uint32_t fmix ( std::uint32_t h )
|
||||
{
|
||||
h ^= h >> 16;
|
||||
h *= 0x85ebca6b;
|
||||
h ^= h >> 13;
|
||||
h *= 0xc2b2ae35;
|
||||
h ^= h >> 16;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
//----------
|
||||
|
||||
static inline std::uint64_t fmix ( std::uint64_t k )
|
||||
{
|
||||
k ^= k >> 33;
|
||||
k *= BIG_CONSTANT (0xff51afd7ed558ccd);
|
||||
k ^= k >> 33;
|
||||
k *= BIG_CONSTANT (0xc4ceb9fe1a85ec53);
|
||||
k ^= k >> 33;
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void MurmurHash3_x86_32 ( const void* key, int len,
|
||||
std::uint32_t seed, void* out )
|
||||
{
|
||||
const uint8_t* data = (const uint8_t*)key;
|
||||
const int nblocks = len / 4;
|
||||
|
||||
std::uint32_t h1 = seed;
|
||||
|
||||
std::uint32_t c1 = 0xcc9e2d51;
|
||||
std::uint32_t c2 = 0x1b873593;
|
||||
|
||||
//----------
|
||||
// body
|
||||
|
||||
const std::uint32_t* blocks = (const std::uint32_t*) (data + nblocks * 4);
|
||||
|
||||
for (int i = -nblocks; i; i++)
|
||||
{
|
||||
std::uint32_t k1 = getblock (blocks, i);
|
||||
|
||||
k1 *= c1;
|
||||
k1 = ROTL32 (k1, 15);
|
||||
k1 *= c2;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = ROTL32 (h1, 13);
|
||||
h1 = h1 * 5 + 0xe6546b64;
|
||||
}
|
||||
|
||||
//----------
|
||||
// tail
|
||||
|
||||
const uint8_t* tail = (const uint8_t*) (data + nblocks * 4);
|
||||
|
||||
std::uint32_t k1 = 0;
|
||||
|
||||
switch (len & 3)
|
||||
{
|
||||
case 3:
|
||||
k1 ^= tail[2] << 16;
|
||||
|
||||
case 2:
|
||||
k1 ^= tail[1] << 8;
|
||||
|
||||
case 1:
|
||||
k1 ^= tail[0];
|
||||
k1 *= c1;
|
||||
k1 = ROTL32 (k1, 15);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
};
|
||||
|
||||
//----------
|
||||
// finalization
|
||||
|
||||
h1 ^= len;
|
||||
|
||||
h1 = fmix (h1);
|
||||
|
||||
* (std::uint32_t*)out = h1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void MurmurHash3_x86_128 ( const void* key, const int len,
|
||||
std::uint32_t seed, void* out )
|
||||
{
|
||||
const uint8_t* data = (const uint8_t*)key;
|
||||
const int nblocks = len / 16;
|
||||
|
||||
std::uint32_t h1 = seed;
|
||||
std::uint32_t h2 = seed;
|
||||
std::uint32_t h3 = seed;
|
||||
std::uint32_t h4 = seed;
|
||||
|
||||
std::uint32_t c1 = 0x239b961b;
|
||||
std::uint32_t c2 = 0xab0e9789;
|
||||
std::uint32_t c3 = 0x38b34ae5;
|
||||
std::uint32_t c4 = 0xa1e38b93;
|
||||
|
||||
//----------
|
||||
// body
|
||||
|
||||
const std::uint32_t* blocks = (const std::uint32_t*) (data + nblocks * 16);
|
||||
|
||||
for (int i = -nblocks; i; i++)
|
||||
{
|
||||
std::uint32_t k1 = getblock (blocks, i * 4 + 0);
|
||||
std::uint32_t k2 = getblock (blocks, i * 4 + 1);
|
||||
std::uint32_t k3 = getblock (blocks, i * 4 + 2);
|
||||
std::uint32_t k4 = getblock (blocks, i * 4 + 3);
|
||||
|
||||
k1 *= c1;
|
||||
k1 = ROTL32 (k1, 15);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
|
||||
h1 = ROTL32 (h1, 19);
|
||||
h1 += h2;
|
||||
h1 = h1 * 5 + 0x561ccd1b;
|
||||
|
||||
k2 *= c2;
|
||||
k2 = ROTL32 (k2, 16);
|
||||
k2 *= c3;
|
||||
h2 ^= k2;
|
||||
|
||||
h2 = ROTL32 (h2, 17);
|
||||
h2 += h3;
|
||||
h2 = h2 * 5 + 0x0bcaa747;
|
||||
|
||||
k3 *= c3;
|
||||
k3 = ROTL32 (k3, 17);
|
||||
k3 *= c4;
|
||||
h3 ^= k3;
|
||||
|
||||
h3 = ROTL32 (h3, 15);
|
||||
h3 += h4;
|
||||
h3 = h3 * 5 + 0x96cd1c35;
|
||||
|
||||
k4 *= c4;
|
||||
k4 = ROTL32 (k4, 18);
|
||||
k4 *= c1;
|
||||
h4 ^= k4;
|
||||
|
||||
h4 = ROTL32 (h4, 13);
|
||||
h4 += h1;
|
||||
h4 = h4 * 5 + 0x32ac3b17;
|
||||
}
|
||||
|
||||
//----------
|
||||
// tail
|
||||
|
||||
const uint8_t* tail = (const uint8_t*) (data + nblocks * 16);
|
||||
|
||||
std::uint32_t k1 = 0;
|
||||
std::uint32_t k2 = 0;
|
||||
std::uint32_t k3 = 0;
|
||||
std::uint32_t k4 = 0;
|
||||
|
||||
switch (len & 15)
|
||||
{
|
||||
case 15:
|
||||
k4 ^= tail[14] << 16;
|
||||
|
||||
case 14:
|
||||
k4 ^= tail[13] << 8;
|
||||
|
||||
case 13:
|
||||
k4 ^= tail[12] << 0;
|
||||
k4 *= c4;
|
||||
k4 = ROTL32 (k4, 18);
|
||||
k4 *= c1;
|
||||
h4 ^= k4;
|
||||
|
||||
case 12:
|
||||
k3 ^= tail[11] << 24;
|
||||
|
||||
case 11:
|
||||
k3 ^= tail[10] << 16;
|
||||
|
||||
case 10:
|
||||
k3 ^= tail[ 9] << 8;
|
||||
|
||||
case 9:
|
||||
k3 ^= tail[ 8] << 0;
|
||||
k3 *= c3;
|
||||
k3 = ROTL32 (k3, 17);
|
||||
k3 *= c4;
|
||||
h3 ^= k3;
|
||||
|
||||
case 8:
|
||||
k2 ^= tail[ 7] << 24;
|
||||
|
||||
case 7:
|
||||
k2 ^= tail[ 6] << 16;
|
||||
|
||||
case 6:
|
||||
k2 ^= tail[ 5] << 8;
|
||||
|
||||
case 5:
|
||||
k2 ^= tail[ 4] << 0;
|
||||
k2 *= c2;
|
||||
k2 = ROTL32 (k2, 16);
|
||||
k2 *= c3;
|
||||
h2 ^= k2;
|
||||
|
||||
case 4:
|
||||
k1 ^= tail[ 3] << 24;
|
||||
|
||||
case 3:
|
||||
k1 ^= tail[ 2] << 16;
|
||||
|
||||
case 2:
|
||||
k1 ^= tail[ 1] << 8;
|
||||
|
||||
case 1:
|
||||
k1 ^= tail[ 0] << 0;
|
||||
k1 *= c1;
|
||||
k1 = ROTL32 (k1, 15);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
};
|
||||
|
||||
//----------
|
||||
// finalization
|
||||
|
||||
h1 ^= len;
|
||||
|
||||
h2 ^= len;
|
||||
|
||||
h3 ^= len;
|
||||
|
||||
h4 ^= len;
|
||||
|
||||
h1 += h2;
|
||||
|
||||
h1 += h3;
|
||||
|
||||
h1 += h4;
|
||||
|
||||
h2 += h1;
|
||||
|
||||
h3 += h1;
|
||||
|
||||
h4 += h1;
|
||||
|
||||
h1 = fmix (h1);
|
||||
|
||||
h2 = fmix (h2);
|
||||
|
||||
h3 = fmix (h3);
|
||||
|
||||
h4 = fmix (h4);
|
||||
|
||||
h1 += h2;
|
||||
|
||||
h1 += h3;
|
||||
|
||||
h1 += h4;
|
||||
|
||||
h2 += h1;
|
||||
|
||||
h3 += h1;
|
||||
|
||||
h4 += h1;
|
||||
|
||||
((std::uint32_t*)out)[0] = h1;
|
||||
|
||||
((std::uint32_t*)out)[1] = h2;
|
||||
|
||||
((std::uint32_t*)out)[2] = h3;
|
||||
|
||||
((std::uint32_t*)out)[3] = h4;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void MurmurHash3_x64_128 ( const void* key, const int len,
|
||||
const std::uint32_t seed, void* out )
|
||||
{
|
||||
const uint8_t* data = (const uint8_t*)key;
|
||||
const int nblocks = len / 16;
|
||||
|
||||
std::uint64_t h1 = seed;
|
||||
std::uint64_t h2 = seed;
|
||||
|
||||
std::uint64_t c1 = BIG_CONSTANT (0x87c37b91114253d5);
|
||||
std::uint64_t c2 = BIG_CONSTANT (0x4cf5ad432745937f);
|
||||
|
||||
//----------
|
||||
// body
|
||||
|
||||
const std::uint64_t* blocks = (const std::uint64_t*) (data);
|
||||
|
||||
for (int i = 0; i < nblocks; i++)
|
||||
{
|
||||
std::uint64_t k1 = getblock (blocks, i * 2 + 0);
|
||||
std::uint64_t k2 = getblock (blocks, i * 2 + 1);
|
||||
|
||||
k1 *= c1;
|
||||
k1 = ROTL64 (k1, 31);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
|
||||
h1 = ROTL64 (h1, 27);
|
||||
h1 += h2;
|
||||
h1 = h1 * 5 + 0x52dce729;
|
||||
|
||||
k2 *= c2;
|
||||
k2 = ROTL64 (k2, 33);
|
||||
k2 *= c1;
|
||||
h2 ^= k2;
|
||||
|
||||
h2 = ROTL64 (h2, 31);
|
||||
h2 += h1;
|
||||
h2 = h2 * 5 + 0x38495ab5;
|
||||
}
|
||||
|
||||
//----------
|
||||
// tail
|
||||
|
||||
const uint8_t* tail = (const uint8_t*) (data + nblocks * 16);
|
||||
|
||||
std::uint64_t k1 = 0;
|
||||
std::uint64_t k2 = 0;
|
||||
|
||||
switch (len & 15)
|
||||
{
|
||||
case 15:
|
||||
k2 ^= std::uint64_t (tail[14]) << 48;
|
||||
|
||||
case 14:
|
||||
k2 ^= std::uint64_t (tail[13]) << 40;
|
||||
|
||||
case 13:
|
||||
k2 ^= std::uint64_t (tail[12]) << 32;
|
||||
|
||||
case 12:
|
||||
k2 ^= std::uint64_t (tail[11]) << 24;
|
||||
|
||||
case 11:
|
||||
k2 ^= std::uint64_t (tail[10]) << 16;
|
||||
|
||||
case 10:
|
||||
k2 ^= std::uint64_t (tail[ 9]) << 8;
|
||||
|
||||
case 9:
|
||||
k2 ^= std::uint64_t (tail[ 8]) << 0;
|
||||
k2 *= c2;
|
||||
k2 = ROTL64 (k2, 33);
|
||||
k2 *= c1;
|
||||
h2 ^= k2;
|
||||
|
||||
case 8:
|
||||
k1 ^= std::uint64_t (tail[ 7]) << 56;
|
||||
|
||||
case 7:
|
||||
k1 ^= std::uint64_t (tail[ 6]) << 48;
|
||||
|
||||
case 6:
|
||||
k1 ^= std::uint64_t (tail[ 5]) << 40;
|
||||
|
||||
case 5:
|
||||
k1 ^= std::uint64_t (tail[ 4]) << 32;
|
||||
|
||||
case 4:
|
||||
k1 ^= std::uint64_t (tail[ 3]) << 24;
|
||||
|
||||
case 3:
|
||||
k1 ^= std::uint64_t (tail[ 2]) << 16;
|
||||
|
||||
case 2:
|
||||
k1 ^= std::uint64_t (tail[ 1]) << 8;
|
||||
|
||||
case 1:
|
||||
k1 ^= std::uint64_t (tail[ 0]) << 0;
|
||||
k1 *= c1;
|
||||
k1 = ROTL64 (k1, 31);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
};
|
||||
|
||||
//----------
|
||||
// finalization
|
||||
|
||||
h1 ^= len;
|
||||
|
||||
h2 ^= len;
|
||||
|
||||
h1 += h2;
|
||||
|
||||
h2 += h1;
|
||||
|
||||
h1 = fmix (h1);
|
||||
|
||||
h2 = fmix (h2);
|
||||
|
||||
h1 += h2;
|
||||
|
||||
h2 += h1;
|
||||
|
||||
((std::uint64_t*)out)[0] = h1;
|
||||
|
||||
((std::uint64_t*)out)[1] = h2;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
71
src/beast/beast/hash/fnv1a.h
Normal file
@@ -0,0 +1,71 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2014, Howard Hinnant <howard.hinnant@gmail.com>,
|
||||
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_HASH_FNV1A_H_INCLUDED
|
||||
#define BEAST_HASH_FNV1A_H_INCLUDED
|
||||
|
||||
#include <beast/utility/noexcept.h>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <beast/cxx14/type_traits.h> // <type_traits>
|
||||
|
||||
namespace beast {
|
||||
|
||||
// See http://www.isthe.com/chongo/tech/comp/fnv/
|
||||
//
|
||||
class fnv1a
|
||||
{
|
||||
private:
|
||||
std::uint64_t state_ = 14695981039346656037ULL;
|
||||
|
||||
public:
|
||||
using result_type = std::size_t;
|
||||
|
||||
fnv1a() = default;
|
||||
|
||||
template <class Seed,
|
||||
std::enable_if_t<
|
||||
std::is_unsigned<Seed>::value>* = nullptr>
|
||||
explicit
|
||||
fnv1a (Seed seed)
|
||||
{
|
||||
append (&seed, sizeof(seed));
|
||||
}
|
||||
|
||||
void
|
||||
append (void const* key, std::size_t len) noexcept
|
||||
{
|
||||
unsigned char const* p =
|
||||
static_cast<unsigned char const*>(key);
|
||||
unsigned char const* const e = p + len;
|
||||
for (; p < e; ++p)
|
||||
state_ = (state_ ^ *p) * 1099511628211ULL;
|
||||
}
|
||||
|
||||
explicit
|
||||
operator std::size_t() noexcept
|
||||
{
|
||||
return static_cast<std::size_t>(state_);
|
||||
}
|
||||
};
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -18,18 +18,14 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_CONTAINER_HASH_APPEND_H_INCLUDED
|
||||
#define BEAST_CONTAINER_HASH_APPEND_H_INCLUDED
|
||||
#ifndef BEAST_HASH_HASH_APPEND_H_INCLUDED
|
||||
#define BEAST_HASH_HASH_APPEND_H_INCLUDED
|
||||
|
||||
#include <beast/utility/meta.h>
|
||||
|
||||
#include <beast/container/impl/spookyv2.h>
|
||||
|
||||
#include <beast/utility/noexcept.h>
|
||||
#if BEAST_USE_BOOST_FEATURES
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#endif
|
||||
|
||||
#include <beast/utility/noexcept.h>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
@@ -656,96 +652,6 @@ hash_append (Hasher& h, T0 const& t0, T1 const& t1, T const& ...t) noexcept
|
||||
hash_append (h, t1, t...);
|
||||
}
|
||||
|
||||
// See http://www.isthe.com/chongo/tech/comp/fnv/
|
||||
class fnv1a
|
||||
{
|
||||
std::uint64_t state_ = 14695981039346656037ULL;
|
||||
public:
|
||||
|
||||
using result_type = std::size_t;
|
||||
|
||||
void
|
||||
append (void const* key, std::size_t len) noexcept
|
||||
{
|
||||
unsigned char const* p = static_cast<unsigned char const*>(key);
|
||||
unsigned char const* const e = p + len;
|
||||
for (; p < e; ++p)
|
||||
state_ = (state_ ^ *p) * 1099511628211ULL;
|
||||
}
|
||||
|
||||
explicit
|
||||
operator std::size_t() noexcept
|
||||
{
|
||||
return static_cast<std::size_t>(state_);
|
||||
}
|
||||
};
|
||||
|
||||
// See http://burtleburtle.net/bob/hash/spooky.html
|
||||
class spooky
|
||||
{
|
||||
SpookyHash state_;
|
||||
public:
|
||||
using result_type = std::size_t;
|
||||
|
||||
spooky (std::size_t seed1 = 1, std::size_t seed2 = 2) noexcept
|
||||
{
|
||||
state_.Init (seed1, seed2);
|
||||
}
|
||||
|
||||
void
|
||||
append (void const* key, std::size_t len) noexcept
|
||||
{
|
||||
state_.Update (key, len);
|
||||
}
|
||||
|
||||
explicit
|
||||
operator std::size_t() noexcept
|
||||
{
|
||||
std::uint64_t h1, h2;
|
||||
state_.Final (&h1, &h2);
|
||||
return static_cast <std::size_t> (h1);
|
||||
}
|
||||
};
|
||||
|
||||
// See https://131002.net/siphash/
|
||||
class siphash
|
||||
{
|
||||
std::uint64_t v0_ = 0x736f6d6570736575ULL;
|
||||
std::uint64_t v1_ = 0x646f72616e646f6dULL;
|
||||
std::uint64_t v2_ = 0x6c7967656e657261ULL;
|
||||
std::uint64_t v3_ = 0x7465646279746573ULL;
|
||||
unsigned char buf_[8];
|
||||
unsigned bufsize_ = 0;
|
||||
unsigned total_length_ = 0;
|
||||
public:
|
||||
using result_type = std::size_t;
|
||||
|
||||
siphash() = default;
|
||||
explicit siphash(std::uint64_t k0, std::uint64_t k1 = 0) noexcept;
|
||||
|
||||
void
|
||||
append (void const* key, std::size_t len) noexcept;
|
||||
|
||||
explicit
|
||||
operator std::size_t() noexcept;
|
||||
};
|
||||
|
||||
template <class Hasher = spooky>
|
||||
struct uhash
|
||||
{
|
||||
using result_type = typename Hasher::result_type;
|
||||
|
||||
template <class T>
|
||||
result_type
|
||||
operator()(T const& t) const noexcept
|
||||
{
|
||||
Hasher h;
|
||||
hash_append (h, t);
|
||||
return static_cast<result_type>(h);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
85
src/beast/beast/hash/impl/hash_speed_test.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, 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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#if BEAST_INCLUDE_BEASTCONFIG
|
||||
#include <BeastConfig.h>
|
||||
#endif
|
||||
#include <beast/container/fnv1a.h>
|
||||
#include <beast/container/siphash.h>
|
||||
#include <beast/container/xxhasher.h>
|
||||
#include <beast/random/rngfill.h>
|
||||
#include <beast/random/xor_shift_engine.h>
|
||||
#include <beast/unit_test/suite.h>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
#include <random>
|
||||
|
||||
namespace beast {
|
||||
|
||||
class hash_speed_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
using clock_type =
|
||||
std::chrono::high_resolution_clock;
|
||||
template <class Hasher, std::size_t KeySize>
|
||||
void
|
||||
test (std::string const& what, std::size_t n)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
xor_shift_engine g(1);
|
||||
array<std::uint8_t, KeySize> key;
|
||||
auto const start = clock_type::now();
|
||||
while(n--)
|
||||
{
|
||||
rngfill (key, g);
|
||||
Hasher h;
|
||||
h.append(key.data(), KeySize);
|
||||
volatile size_t temp =
|
||||
static_cast<std::size_t>(h);
|
||||
(void)temp;
|
||||
}
|
||||
auto const elapsed = clock_type::now() - start;
|
||||
log << setw(12) << what << " " <<
|
||||
duration<double>(elapsed) << "s";
|
||||
}
|
||||
|
||||
void
|
||||
run()
|
||||
{
|
||||
enum
|
||||
{
|
||||
N = 100000000
|
||||
};
|
||||
|
||||
#if ! BEAST_NO_XXHASH
|
||||
test<xxhasher,32> ("xxhash", N);
|
||||
#endif
|
||||
test<fnv1a,32> ("fnv1a", N);
|
||||
test<siphash,32> ("siphash", N);
|
||||
pass();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE_MANUAL(hash_speed,container,beast);
|
||||
|
||||
} // beast
|
||||
@@ -24,18 +24,15 @@
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include <beast/container/hash_append.h>
|
||||
#include <beast/hash/siphash.h>
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
// namespace acme is used to demonstrate example code. It is not proposed.
|
||||
|
||||
namespace beast
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
typedef std::uint64_t u64;
|
||||
typedef std::uint32_t u32;
|
||||
@@ -82,7 +79,7 @@ sipround(u64& v0, u64& v1, u64& v2, u64& v3)
|
||||
v2 = rotl(v2, 32);
|
||||
}
|
||||
|
||||
} // unnamed
|
||||
} // detail
|
||||
|
||||
siphash::siphash(std::uint64_t k0, std::uint64_t k1) noexcept
|
||||
{
|
||||
@@ -95,6 +92,7 @@ siphash::siphash(std::uint64_t k0, std::uint64_t k1) noexcept
|
||||
void
|
||||
siphash::append (void const* key, std::size_t inlen) noexcept
|
||||
{
|
||||
using namespace detail;
|
||||
u8 const* in = static_cast<const u8*>(key);
|
||||
total_length_ += inlen;
|
||||
if (bufsize_ + inlen < 8)
|
||||
@@ -130,6 +128,7 @@ siphash::append (void const* key, std::size_t inlen) noexcept
|
||||
|
||||
siphash::operator std::size_t() noexcept
|
||||
{
|
||||
using namespace detail;
|
||||
std::size_t b = static_cast<u64>(total_length_) << 56;
|
||||
switch(bufsize_)
|
||||
{
|
||||
@@ -163,4 +162,4 @@ siphash::operator std::size_t() noexcept
|
||||
return b;
|
||||
}
|
||||
|
||||
} // beast
|
||||
} // beast
|
||||
@@ -10,7 +10,7 @@
|
||||
// August 5 2012: SpookyV2: d = should be d += in short hash, and remove extra mix from long hash
|
||||
|
||||
#include <memory.h>
|
||||
#include <beast/container/impl/spookyv2.h>
|
||||
#include <beast/hash/impl/spookyv2.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (push)
|
||||
934
src/beast/beast/hash/impl/xxhash.c
Normal file
@@ -0,0 +1,934 @@
|
||||
/*
|
||||
xxHash - Fast Hash algorithm
|
||||
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/
|
||||
- public discussion board : https://groups.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
|
||||
#include <beast/hash/impl/xxhash.h>
|
||||
|
||||
//**************************************
|
||||
// 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.
|
||||
// This option has a very small performance cost (only measurable on small inputs).
|
||||
// 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
|
||||
//**************************************
|
||||
// Disable some Visual warning messages
|
||||
#ifdef _MSC_VER // Visual Studio
|
||||
# pragma warning(disable : 4127) // disable: C4127: conditional expression is constant
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER // Visual Studio
|
||||
# define FORCE_INLINE static __forceinline
|
||||
#else
|
||||
# ifdef __GNUC__
|
||||
# define FORCE_INLINE static inline __attribute__((always_inline))
|
||||
# else
|
||||
# define FORCE_INLINE static inline
|
||||
# endif
|
||||
#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
|
||||
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
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 inline U32 XXH_swap32 (U32 x)
|
||||
{
|
||||
return ((x << 24) & 0xff000000 ) |
|
||||
((x << 8) & 0x00ff0000 ) |
|
||||
((x >> 8) & 0x0000ff00 ) |
|
||||
((x >> 24) & 0x000000ff );
|
||||
}
|
||||
static inline 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 // It is possible to define XXH_CPU_LITTLE_ENDIAN 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
154
src/beast/beast/hash/impl/xxhash.h
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef BEAST_CONTAINER_XXHASH_H_INCLUDED
|
||||
#define BEAST_CONTAINER_XXHASH_H_INCLUDED
|
||||
|
||||
/*****************************
|
||||
Includes
|
||||
*****************************/
|
||||
#include <stddef.h> /* size_t */
|
||||
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
/*****************************
|
||||
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().
|
||||
*/
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
59
src/beast/beast/hash/siphash.h
Normal file
@@ -0,0 +1,59 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2014, Howard Hinnant <howard.hinnant@gmail.com>,
|
||||
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_HASH_SIPHASH_H_INCLUDED
|
||||
#define BEAST_HASH_SIPHASH_H_INCLUDED
|
||||
|
||||
#include <beast/utility/noexcept.h>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace beast {
|
||||
|
||||
// See https://131002.net/siphash/
|
||||
class siphash
|
||||
{
|
||||
private:
|
||||
std::uint64_t v0_ = 0x736f6d6570736575ULL;
|
||||
std::uint64_t v1_ = 0x646f72616e646f6dULL;
|
||||
std::uint64_t v2_ = 0x6c7967656e657261ULL;
|
||||
std::uint64_t v3_ = 0x7465646279746573ULL;
|
||||
unsigned char buf_[8];
|
||||
unsigned bufsize_ = 0;
|
||||
unsigned total_length_ = 0;
|
||||
|
||||
public:
|
||||
using result_type = std::size_t;
|
||||
|
||||
siphash() = default;
|
||||
|
||||
explicit
|
||||
siphash (std::uint64_t k0, std::uint64_t k1 = 0) noexcept;
|
||||
|
||||
void
|
||||
append (void const* key, std::size_t len) noexcept;
|
||||
|
||||
explicit
|
||||
operator std::size_t() noexcept;
|
||||
};
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,8 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
Copyright 2014, Howard Hinnant <howard.hinnant@gmail.com>,
|
||||
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
|
||||
@@ -17,30 +18,42 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_BOOST_GET_POINTER_H_INCLUDED
|
||||
#define BEAST_BOOST_GET_POINTER_H_INCLUDED
|
||||
#ifndef BEAST_HASH_SPOOKY_H_INCLUDED
|
||||
#define BEAST_HASH_SPOOKY_H_INCLUDED
|
||||
|
||||
#include <boost/get_pointer.hpp>
|
||||
#include <beast/hash/impl/spookyv2.h>
|
||||
|
||||
// Boost 1.55 incorrectly defines BOOST_NO_CXX11_SMART_PTR
|
||||
// when building with clang 3.4 and earlier. This workaround
|
||||
// gives beast its own overloads.
|
||||
|
||||
#ifdef BOOST_NO_CXX11_SMART_PTR
|
||||
#include <memory>
|
||||
namespace beast {
|
||||
template <class T>
|
||||
T* get_pointer (std::unique_ptr<T> const& p)
|
||||
{
|
||||
return p.get();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T* get_pointer (std::shared_ptr<T> const& p)
|
||||
// See http://burtleburtle.net/bob/hash/spooky.html
|
||||
class spooky
|
||||
{
|
||||
return p.get();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
private:
|
||||
SpookyHash state_;
|
||||
|
||||
public:
|
||||
using result_type = std::size_t;
|
||||
|
||||
spooky (std::size_t seed1 = 1, std::size_t seed2 = 2) noexcept
|
||||
{
|
||||
state_.Init (seed1, seed2);
|
||||
}
|
||||
|
||||
void
|
||||
append (void const* key, std::size_t len) noexcept
|
||||
{
|
||||
state_.Update (key, len);
|
||||
}
|
||||
|
||||
explicit
|
||||
operator std::size_t() noexcept
|
||||
{
|
||||
std::uint64_t h1, h2;
|
||||
state_.Final (&h1, &h2);
|
||||
return static_cast <std::size_t> (h1);
|
||||
}
|
||||
};
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -17,21 +17,15 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
// MODULES: ../impl/spookyv2.cpp
|
||||
|
||||
#if BEAST_INCLUDE_BEASTCONFIG
|
||||
#include <BeastConfig.h>
|
||||
#endif
|
||||
|
||||
#include <beast/container/tests/hash_metrics.h>
|
||||
|
||||
#include <beast/container/hash_append.h>
|
||||
#include <beast/container/impl/spookyv2.h>
|
||||
|
||||
#include <beast/hash/tests/hash_metrics.h>
|
||||
#include <beast/hash/hash_append.h>
|
||||
#include <beast/chrono/chrono_io.h>
|
||||
#include <beast/unit_test/suite.h>
|
||||
#include <beast/utility/type_name.h>
|
||||
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
@@ -40,8 +34,6 @@
|
||||
|
||||
namespace beast {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class Block, class Derived>
|
||||
class block_stream
|
||||
{
|
||||
86
src/beast/beast/hash/tests/hash_speed_test.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, 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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#if BEAST_INCLUDE_BEASTCONFIG
|
||||
#include <BeastConfig.h>
|
||||
#endif
|
||||
#include <beast/hash/fnv1a.h>
|
||||
#include <beast/hash/siphash.h>
|
||||
#include <beast/hash/xxhasher.h>
|
||||
#include <beast/chrono/chrono_io.h>
|
||||
#include <beast/random/rngfill.h>
|
||||
#include <beast/random/xor_shift_engine.h>
|
||||
#include <beast/unit_test/suite.h>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
#include <random>
|
||||
|
||||
namespace beast {
|
||||
|
||||
class hash_speed_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
using clock_type =
|
||||
std::chrono::high_resolution_clock;
|
||||
template <class Hasher, std::size_t KeySize>
|
||||
void
|
||||
test (std::string const& what, std::size_t n)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
xor_shift_engine g(1);
|
||||
array<std::uint8_t, KeySize> key;
|
||||
auto const start = clock_type::now();
|
||||
while(n--)
|
||||
{
|
||||
rngfill (key, g);
|
||||
Hasher h;
|
||||
h.append(key.data(), KeySize);
|
||||
volatile size_t temp =
|
||||
static_cast<std::size_t>(h);
|
||||
(void)temp;
|
||||
}
|
||||
auto const elapsed = clock_type::now() - start;
|
||||
log << setw(12) << what << " " <<
|
||||
duration<double>(elapsed) << "s";
|
||||
}
|
||||
|
||||
void
|
||||
run()
|
||||
{
|
||||
enum
|
||||
{
|
||||
N = 100000000
|
||||
};
|
||||
|
||||
#if ! BEAST_NO_XXHASH
|
||||
test<xxhasher,32> ("xxhash", N);
|
||||
#endif
|
||||
test<fnv1a,32> ("fnv1a", N);
|
||||
test<siphash,32> ("siphash", N);
|
||||
pass();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE_MANUAL(hash_speed,container,beast);
|
||||
|
||||
} // beast
|
||||
@@ -1,7 +1,8 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
Copyright 2014, Howard Hinnant <howard.hinnant@gmail.com>,
|
||||
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
|
||||
@@ -17,21 +18,29 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_CHRONO_ABSTRACT_CLOCK_IO_H_INCLUDED
|
||||
#define BEAST_CHRONO_ABSTRACT_CLOCK_IO_H_INCLUDED
|
||||
#ifndef BEAST_HASH_UHASH_H_INCLUDED
|
||||
#define BEAST_HASH_UHASH_H_INCLUDED
|
||||
|
||||
#include <beast/chrono/chrono_io.h>
|
||||
#include <beast/hash/spooky.h>
|
||||
|
||||
namespace beast {
|
||||
|
||||
template <class CharT, class Traits, class Duration, class Resolution>
|
||||
std::basic_ostream <CharT, Traits>&
|
||||
operator<< (std::basic_ostream <CharT, Traits>& os,
|
||||
std::chrono::time_point <abstract_clock <Resolution>, Duration> const& tp)
|
||||
// Universal hash function
|
||||
template <class Hasher = spooky>
|
||||
struct uhash
|
||||
{
|
||||
return os << tp.time_since_epoch() << " since epoch";
|
||||
}
|
||||
using result_type = typename Hasher::result_type;
|
||||
|
||||
}
|
||||
template <class T>
|
||||
result_type
|
||||
operator()(T const& t) const noexcept
|
||||
{
|
||||
Hasher h;
|
||||
hash_append (h, t);
|
||||
return static_cast<result_type>(h);
|
||||
}
|
||||
};
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
86
src/beast/beast/hash/xxhasher.h
Normal file
@@ -0,0 +1,86 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_HASH_XXHASHER_H_INCLUDED
|
||||
#define BEAST_HASH_XXHASHER_H_INCLUDED
|
||||
|
||||
#ifndef BEAST_NO_XXHASH
|
||||
#define BEAST_NO_XXHASH 0
|
||||
#endif
|
||||
|
||||
#if ! BEAST_NO_XXHASH
|
||||
|
||||
#include <beast/hash/impl/xxhash.h>
|
||||
#include <beast/utility/noexcept.h>
|
||||
#include <beast/cxx14/type_traits.h> // <type_traits>
|
||||
#include <cstddef>
|
||||
|
||||
namespace beast {
|
||||
|
||||
class xxhasher
|
||||
{
|
||||
private:
|
||||
// requires 64-bit std::size_t
|
||||
static_assert(sizeof(std::size_t)==8, "");
|
||||
|
||||
detail::XXH64_state_t state_;
|
||||
|
||||
public:
|
||||
using result_type = std::size_t;
|
||||
|
||||
xxhasher() noexcept
|
||||
{
|
||||
detail::XXH64_reset (&state_, 1);
|
||||
}
|
||||
|
||||
template <class Seed,
|
||||
std::enable_if_t<
|
||||
std::is_unsigned<Seed>::value>* = nullptr>
|
||||
explicit
|
||||
xxhasher (Seed seed)
|
||||
{
|
||||
detail::XXH64_reset (&state_, seed);
|
||||
}
|
||||
|
||||
template <class Seed,
|
||||
std::enable_if_t<
|
||||
std::is_unsigned<Seed>::value>* = nullptr>
|
||||
xxhasher (Seed seed, Seed)
|
||||
{
|
||||
detail::XXH64_reset (&state_, seed);
|
||||
}
|
||||
|
||||
void
|
||||
append (void const* key, std::size_t len) noexcept
|
||||
{
|
||||
detail::XXH64_update (&state_, key, len);
|
||||
}
|
||||
|
||||
explicit
|
||||
operator std::size_t() noexcept
|
||||
{
|
||||
return detail::XXH64_digest(&state_);
|
||||
}
|
||||
};
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <beast/http/impl/raw_parser.cpp>
|
||||
#include <beast/http/impl/URL.cpp>
|
||||
|
||||
#include <beast/http/tests/chunked_encoder.test.cpp>
|
||||
#include <beast/http/tests/parser.test.cpp>
|
||||
#include <beast/http/tests/rfc2616.test.cpp>
|
||||
#include <beast/http/tests/URL.test.cpp>
|
||||
|
||||
@@ -50,17 +50,16 @@ public:
|
||||
body (body const&) = delete;
|
||||
body& operator= (body const&) = delete;
|
||||
|
||||
template <class = void>
|
||||
void
|
||||
clear();
|
||||
|
||||
void
|
||||
write (void const* data, std::size_t bytes);
|
||||
|
||||
template <class ConstBufferSequence>
|
||||
void
|
||||
write (ConstBufferSequence const& buffers)
|
||||
{
|
||||
for (auto const& buffer : buffers)
|
||||
write (boost::asio::buffer_cast <void const*> (buffer),
|
||||
boost::asio::buffer_size (buffer));
|
||||
}
|
||||
write (ConstBufferSequence const& buffers);
|
||||
|
||||
std::size_t
|
||||
size() const;
|
||||
@@ -92,8 +91,9 @@ body::body()
|
||||
|
||||
inline
|
||||
body::body (body&& other)
|
||||
: buf_ (std::move(other.buf_))
|
||||
{
|
||||
buf_ = std::move(other.buf_);
|
||||
other.clear();
|
||||
}
|
||||
|
||||
inline
|
||||
@@ -101,9 +101,17 @@ body&
|
||||
body::operator= (body&& other)
|
||||
{
|
||||
buf_ = std::move(other.buf_);
|
||||
other.clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class>
|
||||
void
|
||||
body::clear()
|
||||
{
|
||||
buf_ = std::make_unique <buffer_type>();
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
body::write (void const* data, std::size_t bytes)
|
||||
@@ -112,6 +120,15 @@ body::write (void const* data, std::size_t bytes)
|
||||
boost::asio::const_buffers_1 (data, bytes)));
|
||||
}
|
||||
|
||||
template <class ConstBufferSequence>
|
||||
void
|
||||
body::write (ConstBufferSequence const& buffers)
|
||||
{
|
||||
for (auto const& buffer : buffers)
|
||||
write (boost::asio::buffer_cast <void const*> (buffer),
|
||||
boost::asio::buffer_size (buffer));
|
||||
}
|
||||
|
||||
inline
|
||||
std::size_t
|
||||
body::size() const
|
||||
|
||||
285
src/beast/beast/http/chunk_encode.h
Normal file
@@ -0,0 +1,285 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, 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_HTTP_CHUNK_ENCODE_H_INCLUDED
|
||||
#define BEAST_HTTP_CHUNK_ENCODE_H_INCLUDED
|
||||
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <beast/cxx14/type_traits.h> // <type_traits>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class Buffers>
|
||||
class chunk_encoded_buffers
|
||||
{
|
||||
private:
|
||||
using const_buffer = boost::asio::const_buffer;
|
||||
|
||||
Buffers buffers_;
|
||||
const_buffer head_;
|
||||
const_buffer tail_;
|
||||
|
||||
// Storage for the longest hex string we might need, plus delimiters.
|
||||
std::array<char, 2 * sizeof(std::size_t) + 2> data_;
|
||||
|
||||
public:
|
||||
using value_type = boost::asio::const_buffer;
|
||||
|
||||
class const_iterator;
|
||||
|
||||
chunk_encoded_buffers() = delete;
|
||||
chunk_encoded_buffers (chunk_encoded_buffers const&) = default;
|
||||
chunk_encoded_buffers& operator= (chunk_encoded_buffers const&) = default;
|
||||
|
||||
chunk_encoded_buffers (Buffers const& buffers, bool final_chunk);
|
||||
|
||||
const_iterator
|
||||
begin() const
|
||||
{
|
||||
return const_iterator(*this, false);
|
||||
}
|
||||
|
||||
const_iterator
|
||||
end() const
|
||||
{
|
||||
return const_iterator(*this, true);
|
||||
}
|
||||
|
||||
private:
|
||||
// Unchecked conversion of unsigned to hex string
|
||||
template<class OutIter, class Unsigned>
|
||||
static
|
||||
std::enable_if_t<std::is_unsigned<Unsigned>::value, OutIter>
|
||||
to_hex(OutIter const first, OutIter const last, Unsigned n);
|
||||
};
|
||||
|
||||
template <class Buffers>
|
||||
class chunk_encoded_buffers<Buffers>::const_iterator
|
||||
: public std::iterator<std::bidirectional_iterator_tag, const_buffer>
|
||||
{
|
||||
private:
|
||||
using iterator = typename Buffers::const_iterator;
|
||||
enum class Where { head, input, end };
|
||||
chunk_encoded_buffers const* buffers_;
|
||||
Where where_;
|
||||
iterator iter_;
|
||||
|
||||
public:
|
||||
const_iterator();
|
||||
const_iterator (const_iterator const&) = default;
|
||||
const_iterator& operator= (const_iterator const&) = default;
|
||||
bool operator== (const_iterator const& other) const;
|
||||
bool operator!= (const_iterator const& other) const;
|
||||
const_iterator& operator++();
|
||||
const_iterator& operator--();
|
||||
const_iterator operator++(int) const;
|
||||
const_iterator operator--(int) const;
|
||||
const_buffer operator*() const;
|
||||
|
||||
private:
|
||||
friend class chunk_encoded_buffers;
|
||||
const_iterator(chunk_encoded_buffers const& buffers, bool past_the_end);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class Buffers>
|
||||
chunk_encoded_buffers<Buffers>::chunk_encoded_buffers (
|
||||
Buffers const& buffers, bool final_chunk)
|
||||
: buffers_(buffers)
|
||||
{
|
||||
auto const size = boost::asio::buffer_size(buffers);
|
||||
data_[data_.size() - 2] = '\r';
|
||||
data_[data_.size() - 1] = '\n';
|
||||
auto pos = to_hex(data_.begin(), data_.end() - 2, size);
|
||||
head_ = const_buffer(&*pos,
|
||||
std::distance(pos, data_.end()));
|
||||
if (size > 0 && final_chunk)
|
||||
tail_ = const_buffer("\r\n0\r\n\r\n", 7);
|
||||
else
|
||||
tail_ = const_buffer("\r\n", 2);
|
||||
}
|
||||
|
||||
template <class Buffers>
|
||||
template <class OutIter, class Unsigned>
|
||||
std::enable_if_t<std::is_unsigned<Unsigned>::value, OutIter>
|
||||
chunk_encoded_buffers<Buffers>::to_hex(
|
||||
OutIter const first, OutIter const last, Unsigned n)
|
||||
{
|
||||
assert(first != last);
|
||||
OutIter iter = last;
|
||||
if(n == 0)
|
||||
{
|
||||
*--iter = '0';
|
||||
return iter;
|
||||
}
|
||||
while(n)
|
||||
{
|
||||
assert(iter != first);
|
||||
*--iter = "0123456789abcdef"[n&0xf];
|
||||
n>>=4;
|
||||
}
|
||||
return iter;
|
||||
}
|
||||
|
||||
template <class Buffers>
|
||||
chunk_encoded_buffers<Buffers>::const_iterator::const_iterator()
|
||||
: where_(Where::end)
|
||||
, buffers_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
template <class Buffers>
|
||||
bool
|
||||
chunk_encoded_buffers<Buffers>::const_iterator::operator==(
|
||||
const_iterator const& other) const
|
||||
{
|
||||
return buffers_ == other.buffers_ &&
|
||||
where_ == other.where_ && iter_ == other.iter_;
|
||||
}
|
||||
|
||||
template <class Buffers>
|
||||
bool
|
||||
chunk_encoded_buffers<Buffers>::const_iterator::operator!=(
|
||||
const_iterator const& other) const
|
||||
{
|
||||
return buffers_ != other.buffers_ ||
|
||||
where_ != other.where_ || iter_ != other.iter_;
|
||||
}
|
||||
|
||||
template <class Buffers>
|
||||
auto
|
||||
chunk_encoded_buffers<Buffers>::const_iterator::operator++() ->
|
||||
const_iterator&
|
||||
{
|
||||
assert(buffers_);
|
||||
assert(where_ != Where::end);
|
||||
if (where_ == Where::head)
|
||||
where_ = Where::input;
|
||||
else if (iter_ != buffers_->buffers_.end())
|
||||
++iter_;
|
||||
else
|
||||
where_ = Where::end;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class Buffers>
|
||||
auto
|
||||
chunk_encoded_buffers<Buffers>::const_iterator::operator--() ->
|
||||
const_iterator&
|
||||
{
|
||||
assert(buffers_);
|
||||
assert(where_ != Where::begin);
|
||||
if (where_ == Where::end)
|
||||
where_ = Where::input;
|
||||
else if (iter_ != buffers_->buffers_.begin())
|
||||
--iter_;
|
||||
else
|
||||
where_ = Where::head;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class Buffers>
|
||||
auto
|
||||
chunk_encoded_buffers<Buffers>::const_iterator::operator++(int) const ->
|
||||
const_iterator
|
||||
{
|
||||
auto iter = *this;
|
||||
++iter;
|
||||
return iter;
|
||||
}
|
||||
|
||||
template <class Buffers>
|
||||
auto
|
||||
chunk_encoded_buffers<Buffers>::const_iterator::operator--(int) const ->
|
||||
const_iterator
|
||||
{
|
||||
auto iter = *this;
|
||||
--iter;
|
||||
return iter;
|
||||
}
|
||||
|
||||
template <class Buffers>
|
||||
auto
|
||||
chunk_encoded_buffers<Buffers>::const_iterator::operator*() const ->
|
||||
const_buffer
|
||||
{
|
||||
assert(buffers_);
|
||||
assert(where_ != Where::end);
|
||||
if (where_ == Where::head)
|
||||
return buffers_->head_;
|
||||
if (iter_ != buffers_->buffers_.end())
|
||||
return *iter_;
|
||||
return buffers_->tail_;
|
||||
}
|
||||
|
||||
template <class Buffers>
|
||||
chunk_encoded_buffers<Buffers>::const_iterator::const_iterator(
|
||||
chunk_encoded_buffers const& buffers, bool past_the_end)
|
||||
: buffers_(&buffers)
|
||||
, where_(past_the_end ? Where::end : Where::head)
|
||||
, iter_(past_the_end ? buffers_->buffers_.end() :
|
||||
buffers_->buffers_.begin())
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Returns a chunk-encoded BufferSequence.
|
||||
|
||||
See:
|
||||
http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1
|
||||
|
||||
@tparam Buffers A type meeting the requirements of BufferSequence.
|
||||
@param buffers The input buffer sequence.
|
||||
@param final_chunk `true` If this should include a final-chunk.
|
||||
@return A chunk-encoded ConstBufferSeqeunce representing the input.
|
||||
*/
|
||||
/** @{ */
|
||||
template <class Buffers>
|
||||
detail::chunk_encoded_buffers<Buffers>
|
||||
chunk_encode (Buffers const& buffers,
|
||||
bool final_chunk = false)
|
||||
{
|
||||
return detail::chunk_encoded_buffers<
|
||||
Buffers>(buffers, final_chunk);
|
||||
}
|
||||
|
||||
// Returns a chunked encoding final chunk.
|
||||
inline
|
||||
boost::asio::const_buffers_1
|
||||
chunk_encode_final()
|
||||
{
|
||||
return boost::asio::const_buffers_1(
|
||||
"0\r\n\r\n", 5);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -38,11 +38,7 @@ namespace http {
|
||||
class headers
|
||||
{
|
||||
public:
|
||||
struct value_type
|
||||
{
|
||||
std::string field;
|
||||
std::string value;
|
||||
};
|
||||
using value_type = std::pair<std::string, std::string>;
|
||||
|
||||
private:
|
||||
struct element
|
||||
@@ -139,6 +135,13 @@ public:
|
||||
void
|
||||
clear() noexcept;
|
||||
|
||||
/** Remove a field.
|
||||
@return The number of fields removed.
|
||||
*/
|
||||
template <class = void>
|
||||
std::size_t
|
||||
erase (std::string const& field);
|
||||
|
||||
/** Append a field value.
|
||||
If a field value already exists the new value will be
|
||||
extended as per RFC2616 Section 4.2.
|
||||
@@ -164,8 +167,8 @@ template <class>
|
||||
headers::element::element (
|
||||
std::string const& f, std::string const& v)
|
||||
{
|
||||
data.field = f;
|
||||
data.value = v;
|
||||
data.first = f;
|
||||
data.second = v;
|
||||
}
|
||||
|
||||
template <class String>
|
||||
@@ -173,7 +176,7 @@ bool
|
||||
headers::less::operator() (
|
||||
String const& lhs, element const& rhs) const
|
||||
{
|
||||
return beast::ci_less::operator() (lhs, rhs.data.field);
|
||||
return beast::ci_less::operator() (lhs, rhs.data.first);
|
||||
}
|
||||
|
||||
template <class String>
|
||||
@@ -181,7 +184,7 @@ bool
|
||||
headers::less::operator() (
|
||||
element const& lhs, String const& rhs) const
|
||||
{
|
||||
return beast::ci_less::operator() (lhs.data.field, rhs);
|
||||
return beast::ci_less::operator() (lhs.data.first, rhs);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -210,7 +213,7 @@ inline
|
||||
headers::headers (headers const& other)
|
||||
{
|
||||
for (auto const& e : other.list_)
|
||||
append (e.data.field, e.data.value);
|
||||
append (e.data.first, e.data.second);
|
||||
}
|
||||
|
||||
inline
|
||||
@@ -219,7 +222,7 @@ headers::operator= (headers const& other)
|
||||
{
|
||||
clear();
|
||||
for (auto const& e : other.list_)
|
||||
append (e.data.field, e.data.value);
|
||||
append (e.data.first, e.data.second);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -269,7 +272,7 @@ headers::operator[] (std::string const& field) const
|
||||
auto const found (find (field));
|
||||
if (found == end())
|
||||
return none;
|
||||
return found->value;
|
||||
return found->second;
|
||||
}
|
||||
|
||||
template <class>
|
||||
@@ -280,6 +283,20 @@ headers::clear() noexcept
|
||||
delete &(*iter++);
|
||||
}
|
||||
|
||||
template <class>
|
||||
std::size_t
|
||||
headers::erase (std::string const& field)
|
||||
{
|
||||
auto const iter = set_.find(field, less{});
|
||||
if (iter == set_.end())
|
||||
return 0;
|
||||
element& e = *iter;
|
||||
set_.erase(set_.iterator_to(e));
|
||||
list_.erase(list_.iterator_to(e));
|
||||
delete &e;
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <class>
|
||||
void
|
||||
headers::append (std::string const& field,
|
||||
@@ -296,7 +313,7 @@ headers::append (std::string const& field,
|
||||
}
|
||||
// If field already exists, append comma
|
||||
// separated value as per RFC2616 section 4.2
|
||||
auto& cur (result.first->data.value);
|
||||
auto& cur (result.first->data.second);
|
||||
cur.reserve (cur.size() + 1 + value.size());
|
||||
cur.append (1, ',');
|
||||
cur.append (value);
|
||||
@@ -304,6 +321,36 @@ headers::append (std::string const& field,
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class Streambuf>
|
||||
void
|
||||
write (Streambuf& stream, std::string const& s)
|
||||
{
|
||||
stream.commit (boost::asio::buffer_copy (
|
||||
stream.prepare (s.size()), boost::asio::buffer(s)));
|
||||
}
|
||||
|
||||
template <class Streambuf>
|
||||
void
|
||||
write (Streambuf& stream, char const* s)
|
||||
{
|
||||
auto const len (::strlen(s));
|
||||
stream.commit (boost::asio::buffer_copy (
|
||||
stream.prepare (len), boost::asio::buffer (s, len)));
|
||||
}
|
||||
|
||||
template <class Streambuf>
|
||||
void
|
||||
write (Streambuf& stream, headers const& h)
|
||||
{
|
||||
for (auto const& _ : h)
|
||||
{
|
||||
write (stream, _.first);
|
||||
write (stream, ": ");
|
||||
write (stream, _.second);
|
||||
write (stream, "\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
template <class>
|
||||
std::string
|
||||
to_string (headers const& h)
|
||||
@@ -311,13 +358,13 @@ to_string (headers const& h)
|
||||
std::string s;
|
||||
std::size_t n (0);
|
||||
for (auto const& e : h)
|
||||
n += e.field.size() + 2 + e.value.size() + 2;
|
||||
n += e.first.size() + 2 + e.second.size() + 2;
|
||||
s.reserve (n);
|
||||
for (auto const& e : h)
|
||||
{
|
||||
s.append (e.field);
|
||||
s.append (e.first);
|
||||
s.append (": ");
|
||||
s.append (e.value);
|
||||
s.append (e.second);
|
||||
s.append ("\r\n");
|
||||
}
|
||||
return s;
|
||||
@@ -338,10 +385,10 @@ build_map (headers const& h)
|
||||
std::map <std::string, std::string> c;
|
||||
for (auto const& e : h)
|
||||
{
|
||||
auto key (e.field);
|
||||
auto key (e.first);
|
||||
// TODO Replace with safe C++14 version
|
||||
std::transform (key.begin(), key.end(), key.begin(), ::tolower);
|
||||
c [key] = e.value;
|
||||
c [key] = e.second;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#define BEAST_HTTP_MESSAGE_H_INCLUDED
|
||||
|
||||
#include <beast/http/basic_parser.h>
|
||||
#include <beast/http/body.h>
|
||||
#include <beast/http/method.h>
|
||||
#include <beast/http/headers.h>
|
||||
#include <beast/utility/ci_char_traits.h>
|
||||
@@ -31,11 +30,26 @@
|
||||
#include <cctype>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
inline
|
||||
std::pair<int, int>
|
||||
http_1_0()
|
||||
{
|
||||
return std::pair<int, int>(1, 0);
|
||||
}
|
||||
|
||||
inline
|
||||
std::pair<int, int>
|
||||
http_1_1()
|
||||
{
|
||||
return std::pair<int, int>(1, 1);
|
||||
}
|
||||
|
||||
class message
|
||||
{
|
||||
private:
|
||||
@@ -72,9 +86,8 @@ public:
|
||||
|
||||
#endif
|
||||
|
||||
// Memberspaces
|
||||
// Memberspace
|
||||
beast::http::headers headers;
|
||||
beast::http::body body;
|
||||
|
||||
bool
|
||||
request() const
|
||||
@@ -180,6 +193,12 @@ public:
|
||||
version_ = std::make_pair (major, minor);
|
||||
}
|
||||
|
||||
void
|
||||
version (std::pair<int, int> p)
|
||||
{
|
||||
version_ = p;
|
||||
}
|
||||
|
||||
std::pair<int, int>
|
||||
version() const
|
||||
{
|
||||
@@ -213,7 +232,6 @@ message::message (message&& other)
|
||||
, keep_alive_ (other.keep_alive_)
|
||||
, upgrade_ (other.upgrade_)
|
||||
, headers (std::move(other.headers))
|
||||
, body (std::move(other.body))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -230,33 +248,15 @@ message::operator= (message&& other)
|
||||
keep_alive_ = other.keep_alive_;
|
||||
upgrade_ = other.upgrade_;
|
||||
headers = std::move(other.headers);
|
||||
body = std::move(other.body);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class AsioStreamBuf>
|
||||
template <class Streambuf>
|
||||
void
|
||||
write (AsioStreamBuf& stream, std::string const& s)
|
||||
{
|
||||
stream.commit (boost::asio::buffer_copy (
|
||||
stream.prepare (s.size()), boost::asio::buffer(s)));
|
||||
}
|
||||
|
||||
template <class AsioStreamBuf>
|
||||
void
|
||||
write (AsioStreamBuf& stream, char const* s)
|
||||
{
|
||||
auto const len (::strlen(s));
|
||||
stream.commit (boost::asio::buffer_copy (
|
||||
stream.prepare (len), boost::asio::buffer (s, len)));
|
||||
}
|
||||
|
||||
template <class AsioStreamBuf>
|
||||
void
|
||||
write (AsioStreamBuf& stream, message const& m)
|
||||
write (Streambuf& stream, message const& m)
|
||||
{
|
||||
if (m.request())
|
||||
{
|
||||
@@ -280,13 +280,7 @@ write (AsioStreamBuf& stream, message const& m)
|
||||
write (stream, m.reason());
|
||||
}
|
||||
write (stream, "\r\n");
|
||||
for (auto const& header : m.headers)
|
||||
{
|
||||
write (stream, header.field);
|
||||
write (stream, ": ");
|
||||
write (stream, header.value);
|
||||
write (stream, "\r\n");
|
||||
}
|
||||
write(stream, m.headers);
|
||||
write (stream, "\r\n");
|
||||
}
|
||||
|
||||
@@ -311,4 +305,4 @@ to_string (message const& m)
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#define BEAST_HTTP_PARSER_H_INCLUDED
|
||||
|
||||
#include <beast/http/message.h>
|
||||
#include <beast/http/body.h>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
@@ -34,15 +36,33 @@ class parser : public beast::http::basic_parser
|
||||
{
|
||||
private:
|
||||
std::reference_wrapper <message> message_;
|
||||
std::function<void(void const*, std::size_t)> write_body_;
|
||||
|
||||
public:
|
||||
/** Construct a parser for HTTP request or response.
|
||||
The result is stored in the passed message.
|
||||
The headers plus request or status line are stored in message.
|
||||
The content-body, if any, is passed as a series of calls to
|
||||
the write_body function. Transfer encodings are applied before
|
||||
any data is passed to the write_body function.
|
||||
*/
|
||||
parser (message& m, bool request)
|
||||
parser (std::function<void(void const*, std::size_t)> write_body,
|
||||
message& m, bool request)
|
||||
: beast::http::basic_parser (request)
|
||||
, message_(m)
|
||||
, write_body_(std::move(write_body))
|
||||
{
|
||||
message_.get().request(request);
|
||||
}
|
||||
|
||||
parser (message& m, body& b, bool request)
|
||||
: beast::http::basic_parser (request)
|
||||
, message_(m)
|
||||
{
|
||||
write_body_ = [&b](void const* data, std::size_t size)
|
||||
{
|
||||
b.write(data, size);
|
||||
};
|
||||
|
||||
message_.get().request(request);
|
||||
}
|
||||
|
||||
@@ -135,7 +155,7 @@ parser::operator= (parser&& other)
|
||||
|
||||
template <class>
|
||||
void
|
||||
parser::do_start ()
|
||||
parser::do_start()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -176,7 +196,7 @@ template <class>
|
||||
void
|
||||
parser::do_body (void const* data, std::size_t bytes)
|
||||
{
|
||||
message_.get().body.write (data, bytes);
|
||||
write_body_(data, bytes);
|
||||
}
|
||||
|
||||
template <class>
|
||||
|
||||
@@ -20,12 +20,14 @@
|
||||
#ifndef BEAST_HTTP_RFC2616_H_INCLUDED
|
||||
#define BEAST_HTTP_RFC2616_H_INCLUDED
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
/** Routines for performing RFC2616 compliance.
|
||||
RFC2616:
|
||||
@@ -129,8 +131,8 @@ trim (String const& s)
|
||||
{
|
||||
using std::begin;
|
||||
using std::end;
|
||||
auto first (begin(s));
|
||||
auto last (end(s));
|
||||
auto first = begin(s);
|
||||
auto last = end(s);
|
||||
std::tie (first, last) = trim (first, last);
|
||||
return { first, last };
|
||||
}
|
||||
@@ -154,21 +156,25 @@ trim (std::string const& s)
|
||||
return trim <std::string> (s);
|
||||
}
|
||||
|
||||
/** Call a functor for each comma delimited element.
|
||||
Quotes and escape sequences will be parsed and converted appropriately.
|
||||
Excess white space, commas, double quotes, and empty elements are not
|
||||
passed to func.
|
||||
/** Parse a character sequence of values separated by commas.
|
||||
Double quotes and escape sequences will be converted. Excess white
|
||||
space, commas, double quotes, and empty elements are not copied.
|
||||
Format:
|
||||
#(token|quoted-string)
|
||||
Reference:
|
||||
http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2
|
||||
*/
|
||||
template <class FwdIter, class Function>
|
||||
void
|
||||
for_each_element (FwdIter first, FwdIter last, Function func)
|
||||
template <class FwdIt,
|
||||
class Result = std::vector<
|
||||
std::basic_string<typename FwdIt::value_type>>,
|
||||
class Char>
|
||||
Result
|
||||
split(FwdIt first, FwdIt last, Char delim)
|
||||
{
|
||||
FwdIter iter (first);
|
||||
std::string e;
|
||||
Result result;
|
||||
using string = typename Result::value_type;
|
||||
FwdIt iter = first;
|
||||
string e;
|
||||
while (iter != last)
|
||||
{
|
||||
if (*iter == '"')
|
||||
@@ -198,16 +204,16 @@ for_each_element (FwdIter first, FwdIter last, Function func)
|
||||
}
|
||||
if (! e.empty())
|
||||
{
|
||||
func (e);
|
||||
result.emplace_back(std::move(e));
|
||||
e.clear();
|
||||
}
|
||||
}
|
||||
else if (*iter == ',')
|
||||
else if (*iter == delim)
|
||||
{
|
||||
e = trim_right (e);
|
||||
if (! e.empty())
|
||||
{
|
||||
func (e);
|
||||
result.emplace_back(std::move(e));
|
||||
e.clear();
|
||||
}
|
||||
++iter;
|
||||
@@ -226,13 +232,29 @@ for_each_element (FwdIter first, FwdIter last, Function func)
|
||||
{
|
||||
e = trim_right (e);
|
||||
if (! e.empty())
|
||||
func (e);
|
||||
result.emplace_back(std::move(e));
|
||||
}
|
||||
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)
|
||||
{
|
||||
return split_commas(s.begin(), s.end());
|
||||
}
|
||||
|
||||
} // rfc2616
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
|
||||
151
src/beast/beast/http/tests/chunked_encoder.test.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, 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/asio/streambuf.h>
|
||||
#include <beast/http/chunk_encode.h>
|
||||
#include <beast/unit_test/suite.h>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
class chunk_encode_test : public unit_test::suite
|
||||
{
|
||||
public:
|
||||
// Convert CR LF to printables for display
|
||||
static
|
||||
std::string
|
||||
encode (std::string const& s)
|
||||
{
|
||||
std::string result;
|
||||
for(auto const c : s)
|
||||
{
|
||||
if (c == '\r')
|
||||
result += "\\r";
|
||||
else if (c== '\n')
|
||||
result += "\\n";
|
||||
else
|
||||
result += c;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Print the contents of a ConstBufferSequence to the log
|
||||
template <class ConstBufferSequence, class Log>
|
||||
static
|
||||
void
|
||||
print (ConstBufferSequence const& buffers, Log log)
|
||||
{
|
||||
for(auto const& buf : buffers)
|
||||
log << encode (std::string(
|
||||
boost::asio::buffer_cast<char const*>(buf),
|
||||
boost::asio::buffer_size(buf)));
|
||||
}
|
||||
|
||||
// Convert a ConstBufferSequence to a string
|
||||
template <class ConstBufferSequence>
|
||||
static
|
||||
std::string
|
||||
buffer_to_string (ConstBufferSequence const& b)
|
||||
{
|
||||
std::string s;
|
||||
auto const n = boost::asio::buffer_size(b);
|
||||
s.resize(n);
|
||||
boost::asio::buffer_copy(
|
||||
boost::asio::buffer(&s[0], n), b);
|
||||
return s;
|
||||
}
|
||||
|
||||
// Append a ConstBufferSequence to an existing string
|
||||
template <class ConstBufferSequence>
|
||||
static
|
||||
void
|
||||
buffer_append (std::string& s, ConstBufferSequence const& b)
|
||||
{
|
||||
s += buffer_to_string(b);
|
||||
}
|
||||
|
||||
// Convert the input sequence of the stream to a
|
||||
// chunked-encoded string. The input sequence is consumed.
|
||||
template <class Streambuf>
|
||||
static
|
||||
std::string
|
||||
streambuf_to_string (Streambuf& sb,
|
||||
bool final_chunk = false)
|
||||
{
|
||||
std::string s;
|
||||
buffer_append(s, chunk_encode(sb.data(), final_chunk));
|
||||
return s;
|
||||
}
|
||||
|
||||
// Check an input against the correct chunk encoded version
|
||||
void
|
||||
check (std::string const& in, std::string const& answer,
|
||||
bool final_chunk = true)
|
||||
{
|
||||
asio::streambuf sb(3);
|
||||
sb << in;
|
||||
auto const out = streambuf_to_string (sb, final_chunk);
|
||||
if (! expect (out == answer))
|
||||
log << "expected\n" << encode(answer) <<
|
||||
"\ngot\n" << encode(out);
|
||||
}
|
||||
|
||||
void testStreambuf()
|
||||
{
|
||||
asio::streambuf sb(3);
|
||||
std::string const s =
|
||||
"0123456789012345678901234567890123456789012345678901234567890123456789"
|
||||
"0123456789012345678901234567890123456789012345678901234567890123456789"
|
||||
"0123456789012345678901234567890123456789012345678901234567890123456789";
|
||||
sb << s;
|
||||
expect(buffer_to_string(sb.data()) == s);
|
||||
}
|
||||
|
||||
void
|
||||
testEncoder()
|
||||
{
|
||||
check("", "0\r\n\r\n");
|
||||
check("x", "1\r\nx\r\n0\r\n\r\n");
|
||||
check("abcd", "4\r\nabcd\r\n0\r\n\r\n");
|
||||
check("x", "1\r\nx\r\n", false);
|
||||
check(
|
||||
"0123456789012345678901234567890123456789012345678901234567890123456789"
|
||||
"0123456789012345678901234567890123456789012345678901234567890123456789"
|
||||
"0123456789012345678901234567890123456789012345678901234567890123456789"
|
||||
,
|
||||
"d2\r\n"
|
||||
"0123456789012345678901234567890123456789012345678901234567890123456789"
|
||||
"0123456789012345678901234567890123456789012345678901234567890123456789"
|
||||
"0123456789012345678901234567890123456789012345678901234567890123456789"
|
||||
"\r\n"
|
||||
"0\r\n\r\n");
|
||||
}
|
||||
|
||||
void
|
||||
run()
|
||||
{
|
||||
testStreambuf();
|
||||
testEncoder();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(chunk_encode,http,beast);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <beast/http/message.h>
|
||||
#include <beast/http/parser.h>
|
||||
#include <beast/unit_test/suite.h>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
@@ -31,7 +32,8 @@ public:
|
||||
request (std::string const& text)
|
||||
{
|
||||
message m;
|
||||
parser p (m, true);
|
||||
body b;
|
||||
parser p (m, b, true);
|
||||
auto result (p.write (boost::asio::buffer(text)));
|
||||
p.write_eof();
|
||||
return std::make_pair (std::move(m), result.first);
|
||||
@@ -56,16 +58,27 @@ public:
|
||||
log << "|" << result.first.headers["Field"] << "|";
|
||||
}
|
||||
|
||||
void
|
||||
test_headers()
|
||||
{
|
||||
headers h;
|
||||
h.append("Field", "Value");
|
||||
expect (h.erase("Field") == 1);
|
||||
}
|
||||
|
||||
void
|
||||
run()
|
||||
{
|
||||
test_headers();
|
||||
|
||||
{
|
||||
std::string const text =
|
||||
"GET / HTTP/1.1\r\n"
|
||||
"\r\n"
|
||||
;
|
||||
message m;
|
||||
parser p (m, true);
|
||||
body b;
|
||||
parser p (m, b, true);
|
||||
auto result (p.write (boost::asio::buffer(text)));
|
||||
expect (! result.first);
|
||||
auto result2 (p.write_eof());
|
||||
@@ -80,7 +93,8 @@ public:
|
||||
"\r\n"
|
||||
;
|
||||
message m;
|
||||
parser p (m, true);
|
||||
body b;
|
||||
parser p (m, b, true);
|
||||
auto result = p.write (boost::asio::buffer(text));
|
||||
if (expect (result.first))
|
||||
expect (result.first.message() == "invalid HTTP method");
|
||||
|
||||
@@ -27,62 +27,56 @@
|
||||
#include <vector>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
namespace rfc2616 {
|
||||
|
||||
class rfc2616_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
void
|
||||
check (std::string const& value,
|
||||
check (std::string const& s,
|
||||
std::vector <std::string> const& expected)
|
||||
{
|
||||
std::vector <std::string> parsed;
|
||||
for_each_element (value.begin(), value.end(),
|
||||
[&](std::string const& element)
|
||||
{
|
||||
parsed.push_back (element);
|
||||
});
|
||||
auto const parsed = split_commas(s.begin(), s.end());
|
||||
expect (parsed == expected);
|
||||
}
|
||||
|
||||
void test_split_commas()
|
||||
{
|
||||
testcase("split_commas");
|
||||
check ("", {});
|
||||
check (" ", {});
|
||||
check (" ", {});
|
||||
check ("\t", {});
|
||||
check (" \t ", {});
|
||||
check (",", {});
|
||||
check (",,", {});
|
||||
check (" ,", {});
|
||||
check (" , ,", {});
|
||||
check ("x", {"x"});
|
||||
check (" x", {"x"});
|
||||
check (" \t x", {"x"});
|
||||
check ("x ", {"x"});
|
||||
check ("x \t", {"x"});
|
||||
check (" \t x \t ", {"x"});
|
||||
check ("\"\"", {});
|
||||
check (" \"\"", {});
|
||||
check ("\"\" ", {});
|
||||
check ("\"x\"", {"x"});
|
||||
check ("\" \"", {" "});
|
||||
check ("\" x\"", {" x"});
|
||||
check ("\"x \"", {"x "});
|
||||
check ("\" x \"", {" x "});
|
||||
check ("\"\tx \"", {"\tx "});
|
||||
check ("x,y", { "x", "y" });
|
||||
check ("x ,\ty ", { "x", "y" });
|
||||
check ("x, y, z", {"x","y","z"});
|
||||
check ("x, \"y\", z", {"x","y","z"});
|
||||
}
|
||||
|
||||
void
|
||||
run()
|
||||
{
|
||||
check ("", {});
|
||||
check (" ", {});
|
||||
check (" ", {});
|
||||
check ("\t", {});
|
||||
check (" \t ", {});
|
||||
|
||||
check (",", {});
|
||||
check (",,", {});
|
||||
check (" ,", {});
|
||||
check (" , ,", {});
|
||||
|
||||
check ("x", {"x"});
|
||||
check (" x", {"x"});
|
||||
check (" \t x", {"x"});
|
||||
check ("x ", {"x"});
|
||||
check ("x \t", {"x"});
|
||||
check (" \t x \t ", {"x"});
|
||||
|
||||
check ("\"\"", {});
|
||||
check (" \"\"", {});
|
||||
check ("\"\" ", {});
|
||||
|
||||
check ("\"x\"", {"x"});
|
||||
check ("\" \"", {" "});
|
||||
check ("\" x\"", {" x"});
|
||||
check ("\"x \"", {"x "});
|
||||
check ("\" x \"", {" x "});
|
||||
check ("\"\tx \"", {"\tx "});
|
||||
|
||||
check ("x,y", { "x", "y" });
|
||||
check ("x ,\ty ", { "x", "y" });
|
||||
|
||||
check ("x, y, z", {"x","y","z"});
|
||||
check ("x, \"y\", z", {"x","y","z"});
|
||||
test_split_commas();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -90,4 +84,3 @@ BEAST_DEFINE_TESTSUITE(rfc2616,http,beast);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
//==============================================================================
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include <beast/cxx14/memory.h>
|
||||
#include <beast/hash/uhash.h>
|
||||
#include <beast/cxx14/memory.h> // <memory>
|
||||
|
||||
namespace beast {
|
||||
namespace insight {
|
||||
|
||||
@@ -83,8 +83,8 @@ public:
|
||||
|
||||
void removeReference ()
|
||||
{
|
||||
if (--m_pending)
|
||||
(static_cast <Derived *> (this))->asyncHandlersComplete ();
|
||||
if (--m_pending == 0)
|
||||
(static_cast<Derived*>(this))->asyncHandlersComplete();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -24,8 +24,9 @@
|
||||
#ifndef BEAST_ELEMENTCOMPARATOR_H_INCLUDED
|
||||
#define BEAST_ELEMENTCOMPARATOR_H_INCLUDED
|
||||
|
||||
namespace beast
|
||||
{
|
||||
#include <algorithm>
|
||||
|
||||
namespace beast {
|
||||
|
||||
#ifndef DOXYGEN
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
|
||||
// New header-only library modeled more closely according to boost
|
||||
#include <beast/SmartPtr.h>
|
||||
#include <beast/Atomic.h>
|
||||
#include <beast/Arithmetic.h>
|
||||
#include <beast/ByteOrder.h>
|
||||
#include <beast/HeapBlock.h>
|
||||
|
||||
@@ -18,111 +18,58 @@
|
||||
//==============================================================================
|
||||
|
||||
#include <beast/module/core/diagnostic/FatalError.h>
|
||||
#include <beast/unit_test/suite.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
|
||||
namespace beast {
|
||||
|
||||
//
|
||||
// FatalError::Reporter
|
||||
//
|
||||
void FatalError::Reporter::onFatalError (
|
||||
char const* message,
|
||||
char const* backtrace,
|
||||
char const* filePath,
|
||||
int lineNumber)
|
||||
{
|
||||
reportMessage (formatMessage (message, backtrace, filePath, lineNumber));
|
||||
}
|
||||
|
||||
void FatalError::Reporter::reportMessage (std::string const& message)
|
||||
{
|
||||
std::cerr << message << std::endl;
|
||||
}
|
||||
|
||||
std::string FatalError::Reporter::formatMessage (
|
||||
char const* message,
|
||||
char const* backtrace,
|
||||
char const* filePath,
|
||||
int lineNumber)
|
||||
{
|
||||
std::string output;
|
||||
output.reserve (16 * 1024);
|
||||
|
||||
output.append (message);
|
||||
|
||||
if (filePath != nullptr && filePath [0] != 0)
|
||||
{
|
||||
output.append (", in ");
|
||||
output.append (formatFilePath (filePath));
|
||||
output.append (" line ");
|
||||
output.append (std::to_string (lineNumber));
|
||||
}
|
||||
|
||||
output.append ("\n");
|
||||
|
||||
if (backtrace != nullptr && backtrace[0] != 0)
|
||||
{
|
||||
output.append ("Stack:\n");
|
||||
output.append (backtrace);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
std::string FatalError::Reporter::formatFilePath (char const* filePath)
|
||||
{
|
||||
return filePath;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
FatalError::Reporter *FatalError::s_reporter;
|
||||
|
||||
/** Returns the current fatal error reporter. */
|
||||
FatalError::Reporter* FatalError::getReporter ()
|
||||
void
|
||||
FatalError (char const* message, char const* file, int line)
|
||||
{
|
||||
return s_reporter;
|
||||
}
|
||||
static std::atomic <int> error_count (0);
|
||||
static std::recursive_mutex gate;
|
||||
|
||||
FatalError::Reporter* FatalError::setReporter (Reporter* reporter)
|
||||
{
|
||||
Reporter* const previous (s_reporter);
|
||||
s_reporter = reporter;
|
||||
return previous;
|
||||
}
|
||||
// We only allow one thread to report a fatal error. Other threads that
|
||||
// encounter fatal errors while we are reporting get blocked here.
|
||||
std::lock_guard<std::recursive_mutex> lock(gate);
|
||||
|
||||
FatalError::FatalError (char const* message, char const* fileName, int lineNumber)
|
||||
{
|
||||
typedef CriticalSection LockType;
|
||||
// If we encounter a recursive fatal error, then we want to terminate
|
||||
// unconditionally.
|
||||
if (error_count++ != 0)
|
||||
return std::terminate ();
|
||||
|
||||
static LockType s_mutex;
|
||||
|
||||
std::lock_guard <LockType> lock (s_mutex);
|
||||
|
||||
auto const backtrace = SystemStats::getStackBacktrace ();
|
||||
|
||||
Reporter* const reporter = s_reporter;
|
||||
|
||||
if (reporter != nullptr)
|
||||
// We protect this entire block of code since writing to cerr might trigger
|
||||
// exceptions.
|
||||
try
|
||||
{
|
||||
reporter->onFatalError (message, backtrace.c_str (), fileName, lineNumber);
|
||||
std::cerr << "An error has occurred. The application will terminate.\n";
|
||||
|
||||
if (message != nullptr && message [0] != 0)
|
||||
std::cerr << "Message: " << message << '\n';
|
||||
|
||||
if (file != nullptr && file [0] != 0)
|
||||
std::cerr << " File: " << file << ":" << line << '\n';
|
||||
|
||||
auto const backtrace = SystemStats::getStackBacktrace ();
|
||||
|
||||
if (!backtrace.empty ())
|
||||
{
|
||||
std::cerr << " Stack:" << std::endl;
|
||||
|
||||
for (auto const& frame : backtrace)
|
||||
std::cerr << " " << frame << '\n';
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// nothing we can do - just fall through and terminate
|
||||
}
|
||||
|
||||
Process::terminate ();
|
||||
return std::terminate ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class FatalError_test : public unit_test::suite
|
||||
{
|
||||
public:
|
||||
void run ()
|
||||
{
|
||||
int shouldBeZero (1);
|
||||
check_invariant (shouldBeZero == 0);
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE_MANUAL(FatalError,beast_core,beast);
|
||||
|
||||
} // beast
|
||||
|
||||
@@ -32,128 +32,11 @@ namespace beast
|
||||
would be to protect data integrity, prevent valuable resources from being
|
||||
wasted, or to ensure that the user does not experience undefined behavior.
|
||||
|
||||
This function will end the process with exit code EXIT_FAILURE. Before
|
||||
the process is terminated, a listener object gets notified so that the
|
||||
client application can perform logging or emit further diagnostics.
|
||||
If multiple threads raise an error, only one will succeed while the others
|
||||
will be blocked before the process terminates.
|
||||
*/
|
||||
class FatalError
|
||||
{
|
||||
public:
|
||||
struct Reporter
|
||||
{
|
||||
virtual ~Reporter() = default;
|
||||
|
||||
/** Called when a fatal error is raised.
|
||||
|
||||
Because the program is likely in an inconsistent state, it is a
|
||||
good idea to do as little as possible from within this function.
|
||||
It will be called from the thread that raised the fatal error.
|
||||
|
||||
The default implementation of this function first calls
|
||||
formatMessage to produce the string, then calls reportMessage
|
||||
to report the results.
|
||||
|
||||
You can override this to perform custom formatting.
|
||||
|
||||
@note filePath may be a zero length string if identifying
|
||||
information was stripped from the executable for security.
|
||||
|
||||
@note stackBacktrace will be a string with zero characters for
|
||||
platforms for which which don't support stack crawls, or
|
||||
when symbolic information is missing from the executable.
|
||||
|
||||
@param message The error message.
|
||||
@param stackBackTrace The stack of the thread that raised the error.
|
||||
@param filePath A full or partial path to the source file that raised the error.
|
||||
@param lineNumber The line number in the source file.
|
||||
*/
|
||||
virtual void onFatalError (char const* message,
|
||||
char const* backtrace,
|
||||
char const* filePath,
|
||||
int lineNumber);
|
||||
|
||||
/** Called to report the message.
|
||||
|
||||
The default implementation simply writes this to standard error.
|
||||
You can override this to perform additional things like logging
|
||||
to a file or sending the message to another process.
|
||||
|
||||
@param formattedMessage The message to report.
|
||||
*/
|
||||
virtual void reportMessage (std::string const& formattedMessage);
|
||||
|
||||
protected:
|
||||
/** Called to format the message.
|
||||
|
||||
The default implementation calls formatFilePath to produce
|
||||
a formatted file name, and then creates a suitable string
|
||||
containing all of the information.
|
||||
|
||||
You can override this function to format your own messages.
|
||||
|
||||
@param message The message from the report.
|
||||
@param stackBacktrace The stack backtrace from the report.
|
||||
@param filePath The file path from the report.
|
||||
@param lineNumber The line number from the report
|
||||
*/
|
||||
virtual std::string formatMessage (
|
||||
char const* message,
|
||||
char const* backtrace,
|
||||
char const* filePath,
|
||||
int lineNumber);
|
||||
|
||||
/** Call to reformat the file path.
|
||||
|
||||
Usually the file is a full path, which we really don't care
|
||||
to see and can also be a security hole.
|
||||
|
||||
The default implementation removes most of the useless
|
||||
directory components from the front.
|
||||
|
||||
You can override this to do a custom format on the file path.
|
||||
*/
|
||||
virtual std::string formatFilePath (char const* filePath);
|
||||
};
|
||||
|
||||
/** Returns the current fatal error reporter. */
|
||||
static Reporter* getReporter ();
|
||||
|
||||
/** Set the fatal error reporter.
|
||||
|
||||
Note that if a fatal error is raised during the construction of
|
||||
objects with static storage duration, it might not be possible to
|
||||
set the reporter before the error is raised. The solution is not
|
||||
to use objects with static storage duration that have non-trivial
|
||||
constructors, use SharedSingleton instead.
|
||||
|
||||
The default behavior when no reporter is set is to invoke
|
||||
the base class version of Reporter::onFatalError.
|
||||
|
||||
If a reporter was previously set, this routine will do nothing.
|
||||
|
||||
@return The previous Reporter (Which may be null).
|
||||
|
||||
@see SharedSingleton, Reporter
|
||||
*/
|
||||
static Reporter* setReporter (Reporter* reporter);
|
||||
|
||||
/** Raise a fatal error.
|
||||
|
||||
If multiple threads raise an error, only one will succeed. The
|
||||
other threads will be blocked before the process terminates.
|
||||
|
||||
@param message A null terminated string, which should come from a constant.
|
||||
@param filePath Pass __FILE__ here.
|
||||
@param lineNumber Pass __LINE__ here.
|
||||
*/
|
||||
FatalError (char const* message, char const* filePath, int lineNumber);
|
||||
|
||||
FatalError(FatalError const&) = delete;
|
||||
FatalError& operator= (FatalError const&) = delete;
|
||||
|
||||
private:
|
||||
static Reporter* s_reporter;
|
||||
};
|
||||
void
|
||||
FatalError (char const* message, char const* file = nullptr, int line = 0);
|
||||
|
||||
} // beast
|
||||
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
#ifndef BEAST_UNITTESTUTILITIES_H_INCLUDED
|
||||
#define BEAST_UNITTESTUTILITIES_H_INCLUDED
|
||||
|
||||
#include <beast/module/core/files/File.h>
|
||||
#include <beast/module/core/maths/Random.h>
|
||||
|
||||
namespace beast {
|
||||
namespace UnitTestUtilities {
|
||||
|
||||
@@ -99,6 +102,31 @@ public:
|
||||
HeapBlock <char> data;
|
||||
};
|
||||
|
||||
class TempDirectory
|
||||
{
|
||||
public:
|
||||
explicit TempDirectory (std::string const& root)
|
||||
: directory (File::createTempFile (root))
|
||||
{
|
||||
}
|
||||
|
||||
~TempDirectory()
|
||||
{
|
||||
directory.deleteRecursively();
|
||||
}
|
||||
|
||||
String const& getFullPathName() const
|
||||
{
|
||||
return directory.getFullPathName();
|
||||
}
|
||||
|
||||
TempDirectory(const TempDirectory&) = delete;
|
||||
TempDirectory& operator=(const TempDirectory&) = delete;
|
||||
|
||||
private:
|
||||
File const directory;
|
||||
};
|
||||
|
||||
} // UnitTestUtilities
|
||||
} // beast
|
||||
|
||||
|
||||
@@ -24,8 +24,10 @@
|
||||
#ifndef BEAST_RANDOM_H_INCLUDED
|
||||
#define BEAST_RANDOM_H_INCLUDED
|
||||
|
||||
namespace beast
|
||||
{
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace beast {
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#include <beast/smart_ptr/SharedPtr.h>
|
||||
#include <beast/module/core/time/AtExitHook.h>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace beast
|
||||
{
|
||||
|
||||
@@ -99,7 +101,7 @@ public:
|
||||
bassert (lifetime == SingletonLifetime::createOnDemand || ! staticData.destructorCalled);
|
||||
staticData.instance = &staticData.object;
|
||||
new (staticData.instance) SharedSingleton (lifetime);
|
||||
memoryBarrier();
|
||||
std::atomic_thread_fence (std::memory_order_seq_cst);
|
||||
instance = staticData.instance;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
|
||||
// Some basic tests, to keep an eye on things and make sure these types work ok
|
||||
// on all platforms.
|
||||
|
||||
@@ -48,20 +52,22 @@ SystemStats::getBeastVersion()
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
std::string
|
||||
std::vector <std::string>
|
||||
SystemStats::getStackBacktrace()
|
||||
{
|
||||
std::string result;
|
||||
std::vector <std::string> result;
|
||||
|
||||
#if BEAST_ANDROID || BEAST_MINGW || BEAST_BSD
|
||||
#if BEAST_ANDROID || BEAST_MINGW || BEAST_BSD
|
||||
bassertfalse; // sorry, not implemented yet!
|
||||
|
||||
#elif BEAST_WINDOWS
|
||||
#elif BEAST_WINDOWS
|
||||
HANDLE process = GetCurrentProcess();
|
||||
SymInitialize (process, nullptr, TRUE);
|
||||
|
||||
void* stack[128];
|
||||
int frames = (int) CaptureStackBackTrace (0, numElementsInArray (stack), stack, nullptr);
|
||||
int frames = (int) CaptureStackBackTrace (0,
|
||||
std::distance(std::begin(stack), std::end(stack)),
|
||||
stack, nullptr);
|
||||
|
||||
HeapBlock<SYMBOL_INFO> symbol;
|
||||
symbol.calloc (sizeof (SYMBOL_INFO) + 256, 1);
|
||||
@@ -74,7 +80,9 @@ SystemStats::getStackBacktrace()
|
||||
|
||||
if (SymFromAddr (process, (DWORD64) stack[i], &displacement, symbol))
|
||||
{
|
||||
result.append (std::to_string (i) + ": ");
|
||||
std::string frame;
|
||||
|
||||
frame.append (std::to_string (i) + ": ");
|
||||
|
||||
IMAGEHLP_MODULE64 moduleInfo;
|
||||
zerostruct (moduleInfo);
|
||||
@@ -82,35 +90,33 @@ SystemStats::getStackBacktrace()
|
||||
|
||||
if (::SymGetModuleInfo64 (process, symbol->ModBase, &moduleInfo))
|
||||
{
|
||||
result.append (moduleInfo.ModuleName);
|
||||
result.append (": ");
|
||||
frame.append (moduleInfo.ModuleName);
|
||||
frame.append (": ");
|
||||
}
|
||||
|
||||
result.append (symbol->Name);
|
||||
frame.append (symbol->Name);
|
||||
|
||||
if (displacement)
|
||||
{
|
||||
result.append ("+");
|
||||
result.append (std::to_string (displacement));
|
||||
frame.append ("+");
|
||||
frame.append (std::to_string (displacement));
|
||||
}
|
||||
|
||||
result.append ("\r\n");
|
||||
result.push_back (frame);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
#else
|
||||
void* stack[128];
|
||||
int frames = backtrace (stack, numElementsInArray (stack));
|
||||
char** frameStrings = backtrace_symbols (stack, frames);
|
||||
int frames = backtrace (stack,
|
||||
std::distance(std::begin(stack), std::end(stack)));
|
||||
|
||||
std::unique_ptr<char*[], void(*)(void*)> frame (
|
||||
backtrace_symbols (stack, frames), std::free);
|
||||
|
||||
for (int i = 0; i < frames; ++i)
|
||||
{
|
||||
result.append (frameStrings[i]);
|
||||
result.append ("\n");
|
||||
}
|
||||
|
||||
::free (frameStrings);
|
||||
#endif
|
||||
result.push_back (frame[i]);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,8 @@ namespace SystemStats
|
||||
The usefulness of the result will depend on the level of debug symbols
|
||||
that are available in the executable.
|
||||
*/
|
||||
std::string getStackBacktrace();
|
||||
std::vector <std::string>
|
||||
getStackBacktrace();
|
||||
|
||||
/** A void() function type, used by setApplicationCrashHandler(). */
|
||||
typedef void (*CrashHandlerFunction)();
|
||||
|
||||
@@ -21,16 +21,17 @@
|
||||
#define BEAST_LEXICALCAST_H_INCLUDED
|
||||
|
||||
#include <beast/Config.h>
|
||||
#include <beast/cxx14/type_traits.h> // <type_traits>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <beast/cxx14/type_traits.h> // <type_traits>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace beast {
|
||||
|
||||
namespace detail {
|
||||
@@ -169,14 +170,14 @@ struct LexicalCast <Out, std::string>
|
||||
std::enable_if_t <std::is_unsigned <Integral>::value, bool>
|
||||
operator () (Integral& out, std::string const& in) const
|
||||
{
|
||||
return parseUnsigned (out, std::begin(in), std::end(in));
|
||||
return parseUnsigned (out, in.begin(), in.end());
|
||||
}
|
||||
|
||||
template <class Integral = Out>
|
||||
std::enable_if_t <std::is_signed <Integral>::value, bool>
|
||||
operator () (Integral& out, std::string const& in) const
|
||||
{
|
||||
return parseSigned (out, std::begin(in), std::end(in));
|
||||
return parseSigned (out, in.begin(), in.end());
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#define BEAST_STRINGPAIRARRAY_H_INCLUDED
|
||||
|
||||
#include <beast/module/core/text/StringArray.h>
|
||||
#include <beast/utility/LeakChecked.h>
|
||||
|
||||
namespace beast {
|
||||
|
||||
@@ -35,7 +34,7 @@ namespace beast {
|
||||
|
||||
@see StringArray
|
||||
*/
|
||||
class StringPairArray : LeakChecked <StringPairArray>
|
||||
class StringPairArray
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
|
||||
@@ -141,7 +141,7 @@ void Workers::deleteWorkers (LockFreeStack <Worker>& stack)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Workers::Worker::Worker (Workers& workers, String const& threadName)
|
||||
Workers::Worker::Worker (Workers& workers, std::string const& threadName)
|
||||
: Thread (threadName)
|
||||
, m_workers (workers)
|
||||
{
|
||||
@@ -232,7 +232,6 @@ void Workers::Worker::run ()
|
||||
class Workers_test : public unit_test::suite
|
||||
{
|
||||
public:
|
||||
|
||||
struct TestCallback : Workers::Callback
|
||||
{
|
||||
explicit TestCallback (int count_)
|
||||
@@ -251,13 +250,6 @@ public:
|
||||
std::atomic <int> count;
|
||||
};
|
||||
|
||||
template <class T1, class T2>
|
||||
bool
|
||||
expectEquals (T1 const& t1, T2 const& t2)
|
||||
{
|
||||
return expect (t1 == t2);
|
||||
}
|
||||
|
||||
void testThreads (int const threadCount)
|
||||
{
|
||||
testcase ("threadCount = " + std::to_string (threadCount));
|
||||
@@ -276,14 +268,12 @@ public:
|
||||
// 10 seconds should be enough to finish on any system
|
||||
//
|
||||
bool signaled = cb.finished.wait (10 * 1000);
|
||||
|
||||
expect (signaled, "timed out");
|
||||
|
||||
w.pauseAllThreadsAndWait ();
|
||||
|
||||
int const count (cb.count.load ());
|
||||
|
||||
expectEquals (count, 0);
|
||||
// We had better finished all our work!
|
||||
expect (cb.count.load () == 0, "Did not complete task!");
|
||||
}
|
||||
|
||||
void run ()
|
||||
|
||||
@@ -122,7 +122,7 @@ private:
|
||||
, public Thread
|
||||
{
|
||||
public:
|
||||
Worker (Workers& workers, String const& threadName);
|
||||
Worker (Workers& workers, std::string const& threadName);
|
||||
|
||||
~Worker ();
|
||||
|
||||
@@ -138,7 +138,7 @@ private:
|
||||
|
||||
private:
|
||||
Callback& m_callback;
|
||||
String m_threadNames; // The name to give each thread
|
||||
std::string m_threadNames; // The name to give each thread
|
||||
WaitableEvent m_allPaused; // signaled when all threads paused
|
||||
semaphore m_semaphore; // each pending task is 1 resource
|
||||
int m_numberOfThreads; // how many we want active now
|
||||
|
||||
@@ -247,31 +247,6 @@ std::uint32_t Time::getApproximateMillisecondCounter() noexcept
|
||||
return TimeHelpers::lastMSCounterValue;
|
||||
}
|
||||
|
||||
void Time::waitForMillisecondCounter (const std::uint32_t targetTime) noexcept
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
const std::uint32_t now = getMillisecondCounter();
|
||||
|
||||
if (now >= targetTime)
|
||||
break;
|
||||
|
||||
const int toWait = (int) (targetTime - now);
|
||||
|
||||
if (toWait > 2)
|
||||
{
|
||||
Thread::sleep (std::min (20, toWait >> 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
// xxx should consider using mutex_pause on the mac as it apparently
|
||||
// makes it seem less like a spinlock and avoids lowering the thread pri.
|
||||
for (int i = 10; --i >= 0;)
|
||||
std::this_thread::yield();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
double Time::highResolutionTicksToSeconds (const std::int64_t ticks) noexcept
|
||||
{
|
||||
|
||||
@@ -324,12 +324,6 @@ public:
|
||||
*/
|
||||
static double getMillisecondCounterHiRes() noexcept;
|
||||
|
||||
/** Waits until the getMillisecondCounter() reaches a given value.
|
||||
|
||||
This will make the thread sleep as efficiently as it can while it's waiting.
|
||||
*/
|
||||
static void waitForMillisecondCounter (std::uint32_t targetTime) noexcept;
|
||||
|
||||
/** Less-accurate but faster version of getMillisecondCounter().
|
||||
|
||||
This will return the last value that getMillisecondCounter() returned, so doesn't
|
||||
|
||||
@@ -22,10 +22,11 @@
|
||||
|
||||
#include <beast/net/IPAddressV4.h>
|
||||
#include <beast/net/IPAddressV6.h>
|
||||
#include <beast/container/hash_append.h>
|
||||
|
||||
#include <beast/hash/hash_append.h>
|
||||
#include <beast/hash/uhash.h>
|
||||
#include <beast/utility/noexcept.h>
|
||||
#include <boost/functional/hash.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <ios>
|
||||
#include <string>
|
||||
@@ -102,14 +103,14 @@ public:
|
||||
|
||||
/** Returns `true` if this address represents an IPv4 address. */
|
||||
bool
|
||||
is_v4 () const
|
||||
is_v4 () const noexcept
|
||||
{
|
||||
return m_type == ipv4;
|
||||
}
|
||||
|
||||
/** Returns `true` if this address represents an IPv6 address. */
|
||||
bool
|
||||
is_v6() const
|
||||
is_v6() const noexcept
|
||||
{
|
||||
return m_type == ipv6;
|
||||
}
|
||||
@@ -121,12 +122,11 @@ public:
|
||||
AddressV4 const&
|
||||
to_v4 () const
|
||||
{
|
||||
if (m_type != ipv4)
|
||||
if (!is_v4 ())
|
||||
throw std::bad_cast();
|
||||
return m_v4;
|
||||
}
|
||||
|
||||
|
||||
/** Returns the IPv6 address.
|
||||
Precondition:
|
||||
is_v6() == `true`
|
||||
@@ -134,7 +134,7 @@ public:
|
||||
AddressV6 const&
|
||||
to_v6 () const
|
||||
{
|
||||
if (m_type != ipv6)
|
||||
if (!is_v6 ())
|
||||
throw std::bad_cast();
|
||||
return m_v6;
|
||||
}
|
||||
@@ -142,13 +142,15 @@ public:
|
||||
template <class Hasher>
|
||||
friend
|
||||
void
|
||||
hash_append(Hasher& h, Address const& addr)
|
||||
hash_append(Hasher& h, Address const& addr) noexcept
|
||||
{
|
||||
using beast::hash_append;
|
||||
if (addr.is_v4 ())
|
||||
hash_append(h, addr.to_v4 ());
|
||||
else
|
||||
else if (addr.is_v6 ())
|
||||
hash_append(h, addr.to_v6 ());
|
||||
else
|
||||
assert (false);
|
||||
}
|
||||
|
||||
/** Arithmetic comparison. */
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#ifndef BEAST_NET_IPADDRESSV4_H_INCLUDED
|
||||
#define BEAST_NET_IPADDRESSV4_H_INCLUDED
|
||||
|
||||
#include <beast/container/hash_append.h>
|
||||
#include <beast/hash/hash_append.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
@@ -140,7 +140,7 @@ struct AddressV4
|
||||
|
||||
Proxy <true> operator[] (std::size_t index) const;
|
||||
Proxy <false> operator[] (std::size_t index);
|
||||
/** @{ */
|
||||
/** @} */
|
||||
|
||||
/** The value as a 32 bit unsigned. */
|
||||
std::uint32_t value;
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
#define BEAST_NET_IPENDPOINT_H_INCLUDED
|
||||
|
||||
#include <beast/net/IPAddress.h>
|
||||
#include <beast/container/hash_append.h>
|
||||
|
||||
#include <beast/hash/hash_append.h>
|
||||
#include <beast/hash/uhash.h>
|
||||
#include <cstdint>
|
||||
#include <ios>
|
||||
#include <string>
|
||||
|
||||
32
src/beast/beast/nudb.h
Normal file
@@ -0,0 +1,32 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_H_INCLUDED
|
||||
#define BEAST_NUDB_H_INCLUDED
|
||||
|
||||
#include <beast/nudb/api.h>
|
||||
#include <beast/nudb/create.h>
|
||||
#include <beast/nudb/common.h>
|
||||
#include <beast/nudb/file.h>
|
||||
#include <beast/nudb/recover.h>
|
||||
#include <beast/nudb/store.h>
|
||||
#include <beast/nudb/verify.h>
|
||||
#include <beast/nudb/visit.h>
|
||||
|
||||
#endif
|
||||
283
src/beast/beast/nudb/README.md
Normal file
@@ -0,0 +1,283 @@
|
||||
# NuDB: A Key/Value Store For Decentralized Systems
|
||||
|
||||
The new breed of decentralized systems such as Ripple or Bitcoin
|
||||
that use embedded key/value databases place different demands on
|
||||
these database than what is traditional. NuDB provides highly
|
||||
optimized and concurrent atomic, durable, and isolated fetch and
|
||||
insert operations to secondary storage, along with these features:
|
||||
|
||||
* Low memory footprint
|
||||
* Values are immutable
|
||||
* Value sizes from 1 2^48 bytes (281TB)
|
||||
* All keys are the same size
|
||||
* Performance independent of growth
|
||||
* Optimized for concurrent fetch
|
||||
* Key file can be rebuilt if needed
|
||||
* Inserts are atomic and consistent
|
||||
* Data file may be iterated, index rebuilt.
|
||||
* Key and data files may be on different volumes
|
||||
* Hardened against algorithmic complexity attacks
|
||||
* Header-only, nothing to build or link
|
||||
|
||||
Three files are used. The data file holds keys and values stored
|
||||
sequentially and size-prefixed. The key file holds a series of
|
||||
fixed-size bucket records forming an on-disk hash table. The log file
|
||||
stores bookkeeping information used to restore consistency when an
|
||||
external failure occurs. In typical cases a fetch costs one I/O to
|
||||
consult the key file and if the key is present, one I/O to read the
|
||||
value.
|
||||
|
||||
## Usage
|
||||
|
||||
Callers define these parameters when a database is created:
|
||||
|
||||
* KeySize: The size of a key in bytes
|
||||
* BlockSize: The physical size of a key file record
|
||||
* LoadFactor: The desired fraction of bucket occupancy
|
||||
|
||||
The ideal block size matches the sector size or block size of the
|
||||
underlying physical media that holds the key file. Functions are
|
||||
provided to return a best estimate of this value for a particular
|
||||
device, but a default of 4096 should work for typical installations.
|
||||
The implementation tries to fit as many entries as possible in a key
|
||||
file record, to maximize the amount of useful work performed per I/O.
|
||||
|
||||
The load factor is chosen to make bucket overflows unlikely without
|
||||
sacrificing bucket occupancy. A value of 0.50 seems to work well with
|
||||
a good hash function.
|
||||
|
||||
Callers also provide these parameters when a database is opened:
|
||||
|
||||
* Appnum: An application-defined integer constant
|
||||
* AllocSize: A significant multiple of the average data size
|
||||
|
||||
To improve performance, memory is recycled. NuDB needs a hint about
|
||||
the average size of the data being inserted. For an average data
|
||||
size of 1KB (one kilobyte), AllocSize of sixteen megabytes (16MB) is
|
||||
sufficient. If the AllocSize is too low, the memory recycler will
|
||||
not make efficient use of allocated blocks.
|
||||
|
||||
Two operations are defined, fetch and insert.
|
||||
|
||||
### Fetch
|
||||
|
||||
The fetch operation retrieves a variable length value given the
|
||||
key. The caller supplies a factory used to provide a buffer for storing
|
||||
the value. This interface allows custom memory allocation strategies.
|
||||
|
||||
### Insert
|
||||
|
||||
Insert adds a key/value pair to the store. Value data must contain at
|
||||
least one byte. Duplicate keys are disallowed. Insertions are serialized.
|
||||
|
||||
## Implementation
|
||||
|
||||
All insertions are buffered in memory, with inserted values becoming
|
||||
immediately discoverable in subsequent or concurrent calls to fetch.
|
||||
Periodically, buffered data is safely committed to disk files using
|
||||
a separate dedicated thread associated with the database. This commit
|
||||
process takes place at least once per second, or more often during
|
||||
a detected surge in insertion activity. In the commit process the
|
||||
key/value pairs receive the following treatment:
|
||||
|
||||
An insertion is performed by appending a value record to the data file.
|
||||
The value record has some header information including the size of the
|
||||
data and a copy of the key; the data file is iteratable without the key
|
||||
file. The value data follows the header. The data file is append-only
|
||||
and immutable: once written, bytes are never changed.
|
||||
|
||||
Initially the hash table in the key file consists of a single bucket.
|
||||
After the load factor is exceeded from insertions, the hash table grows
|
||||
in size by one bucket by doing a "split". The split operation is the
|
||||
linear hashing algorithm as described by Litwin and Larson:
|
||||
|
||||
http://en.wikipedia.org/wiki/Linear_hashing
|
||||
|
||||
When a bucket is split, each key is rehashed and either remains in the
|
||||
original bucket or gets moved to the new bucket appended to the end of
|
||||
the key file.
|
||||
|
||||
An insertion on a full bucket first triggers the "spill" algorithm:
|
||||
First, a spill record is appended to the data file. The spill record
|
||||
contains header information followed by the entire bucket record. Then,
|
||||
the bucket's size is set to zero and the offset of the spill record is
|
||||
stored in the bucket. At this point the insertion may proceed normally,
|
||||
since the bucket is empty. Spilled buckets in the data file are always
|
||||
full.
|
||||
|
||||
Because every bucket holds the offset of the next spill record in the
|
||||
data file, each bucket forms a linked list. In practice, careful
|
||||
selection of capacity and load factor will keep the percentage of
|
||||
buckets with one spill record to a minimum, with no bucket requiring
|
||||
two spill records.
|
||||
|
||||
The implementation of fetch is straightforward: first the bucket in the
|
||||
key file is checked, then each spill record in the linked list of
|
||||
spill records is checked, until the key is found or there are no more
|
||||
records. As almost all buckets have no spill records, the average
|
||||
fetch requires one I/O (not including reading the value).
|
||||
|
||||
One complication in the scheme is when a split occurs on a bucket that
|
||||
has one or more spill records. In this case, both the bucket being split
|
||||
and the new bucket may overflow. This is handled by performing the
|
||||
spill algorithm for each overflow that occurs. The new buckets may have
|
||||
one or more spill records each, depending on the number of keys that
|
||||
were originally present.
|
||||
|
||||
Because the data file is immutable, a bucket's original spill records
|
||||
are no longer referenced after the bucket is split. These blocks of data
|
||||
in the data file are unrecoverable wasted space. Correctly configured
|
||||
databases can have a typical waste factor of 1%, which is acceptable.
|
||||
These unused bytes can be removed by visiting each value in the value
|
||||
file using an off-line process and inserting it into a new database,
|
||||
then delete the old database and use the new one instead.
|
||||
|
||||
## Recovery
|
||||
|
||||
To provide atomicity and consistency, a log file associated with the
|
||||
database stores information used to roll back partial commits.
|
||||
|
||||
## Iteration
|
||||
|
||||
Each record in the data file is prefixed with a header identifying
|
||||
whether it is a value record or a spill record, along with the size of
|
||||
the record in bytes and a copy of the key if its a value record.
|
||||
Therefore, values may be iterated. A key file can be regenerated from
|
||||
just the data file by iterating the values and performing the key
|
||||
insertion algorithm.
|
||||
|
||||
## Concurrency
|
||||
|
||||
Locks are never held during disk reads and writes. Fetches are fully
|
||||
concurrent, while inserts are serialized. Inserts prevent duplicate
|
||||
keys. Inserts are atomic, they either succeed immediately or fail.
|
||||
After an insert, the key is immediately visible to subsequent fetches.
|
||||
|
||||
## Formats
|
||||
|
||||
All integer values are stored as big endian. The uint48_t format
|
||||
consists of 6 bytes.
|
||||
|
||||
### Key File
|
||||
|
||||
The Key File contains the Header followed by one or more
|
||||
fixed-length Bucket Records.
|
||||
|
||||
#### Header (104 bytes)
|
||||
|
||||
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 BlockSize Size of a file block in bytes
|
||||
|
||||
uint16 LoadFactor Target fraction in 65536ths
|
||||
|
||||
uint8[56] Reserved Zeroes
|
||||
uint8[] Reserved Zero-pad to block size
|
||||
|
||||
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
|
||||
the hash function. Appnum is an application defined constant
|
||||
set when the database is created. It can be used for anything,
|
||||
for example to distinguish between different data formats.
|
||||
|
||||
Pepper is computed by hashing the salt using a hash function
|
||||
seeded with the salt. This is used to fingerprint the hash
|
||||
function used. If a database is opened and the fingerprint
|
||||
does not match the hash calculation performed using the template
|
||||
argument provided when constructing the store, an exception
|
||||
is thrown.
|
||||
|
||||
The header for the key file contains the File Header followed by
|
||||
the information above. The Capacity is the number of keys per
|
||||
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, including
|
||||
the Appnum.
|
||||
|
||||
#### Bucket Record (fixed-length)
|
||||
|
||||
uint16 Count Number of keys in this bucket
|
||||
uint48 Spill Offset of the next spill record or 0
|
||||
BucketEntry[] Entries The bucket entries
|
||||
|
||||
#### Bucket Entry
|
||||
|
||||
uint48 Offset Offset in data file of the data
|
||||
uint48 Size The size of the value in bytes
|
||||
uint48 Hash The hash of the key
|
||||
|
||||
### Data File
|
||||
|
||||
The Data File contains the Header followed by zero or more
|
||||
variable-length Value Records and Spill Records.
|
||||
|
||||
#### Header (92 bytes)
|
||||
|
||||
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
|
||||
uint16 KeySize Key size in bytes
|
||||
|
||||
uint8[64] Reserved Zeroes
|
||||
|
||||
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)
|
||||
|
||||
uint48 Size Size of the value in bytes
|
||||
uint8[KeySize] Key The key.
|
||||
uint8[Size] Data The value data.
|
||||
|
||||
#### Spill Record (fixed-length)
|
||||
|
||||
uint48 Zero All zero, identifies a spill record
|
||||
uint16 Size Bytes in spill bucket (for skipping)
|
||||
Bucket SpillBucket Bucket Record
|
||||
|
||||
### 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 (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 BlockSize Size of a file block in bytes
|
||||
|
||||
uint64 KeyFileSize Size of key file.
|
||||
uint64 DataFileSize Size of data file.
|
||||
|
||||
#### Log Record
|
||||
|
||||
uint64_t Index Bucket index (0-based)
|
||||
Bucket Bucket Compact Bucket record
|
||||
|
||||
Compact buckets include only Size entries. These are primarily
|
||||
used to minimize the volume of writes to the log 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
|
||||
123
src/beast/beast/nudb/common.h
Normal file
@@ -0,0 +1,123 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_COMMON_H_INCLUDED
|
||||
#define BEAST_NUDB_COMMON_H_INCLUDED
|
||||
|
||||
#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::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 (String const& s)
|
||||
: runtime_error(s)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/** Thrown when file bytes read are less than requested. */
|
||||
struct file_short_read_error : file_error
|
||||
{
|
||||
file_short_read_error()
|
||||
: file_error (
|
||||
"nudb: short read")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/** Thrown when file bytes written are less than requested. */
|
||||
struct file_short_write_error : file_error
|
||||
{
|
||||
file_short_write_error()
|
||||
: file_error (
|
||||
"nudb: short write")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/** 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 (String const& s)
|
||||
: runtime_error(s)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/** Thrown when corruption in a file is detected. */
|
||||
class store_corrupt_error : public store_error
|
||||
{
|
||||
public:
|
||||
template <class String>
|
||||
explicit
|
||||
store_corrupt_error (String const& s)
|
||||
: store_error(s)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // nudb
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
164
src/beast/beast/nudb/create.h
Normal file
@@ -0,0 +1,164 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_CREATE_H_INCLUDED
|
||||
#define BEAST_NUDB_CREATE_H_INCLUDED
|
||||
|
||||
#include <beast/nudb/file.h>
|
||||
#include <beast/nudb/detail/bucket.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
|
||||
Throws:
|
||||
|
||||
@param args Arguments passed to File constructors
|
||||
@return `false` if any file could not be created.
|
||||
*/
|
||||
template <
|
||||
class Hasher,
|
||||
class Codec,
|
||||
class File,
|
||||
class... Args
|
||||
>
|
||||
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)
|
||||
{
|
||||
using namespace detail;
|
||||
if (key_size < 1)
|
||||
throw std::domain_error(
|
||||
"invalid key size");
|
||||
if (block_size > field<std::uint16_t>::max)
|
||||
throw std::domain_error(
|
||||
"nudb: block size too large");
|
||||
if (load_factor <= 0.f)
|
||||
throw std::domain_error(
|
||||
"nudb: load factor too small");
|
||||
if (load_factor >= 1.f)
|
||||
throw std::domain_error(
|
||||
"nudb: load factor too large");
|
||||
auto const capacity =
|
||||
bucket_capacity(block_size);
|
||||
if (capacity < 1)
|
||||
throw std::domain_error(
|
||||
"nudb: block size too small");
|
||||
File df(args...);
|
||||
File kf(args...);
|
||||
File lf(args...);
|
||||
if (df.create(
|
||||
file_mode::append, dat_path))
|
||||
{
|
||||
if (kf.create (
|
||||
file_mode::append, key_path))
|
||||
{
|
||||
if (lf.create(
|
||||
file_mode::append, log_path))
|
||||
goto success;
|
||||
File::erase (dat_path);
|
||||
}
|
||||
File::erase (key_path);
|
||||
}
|
||||
return false;
|
||||
success:
|
||||
dat_file_header dh;
|
||||
dh.version = currentVersion;
|
||||
dh.uid = make_uid();
|
||||
dh.appnum = appnum;
|
||||
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.block_size = block_size;
|
||||
// VFALCO Should it be 65536?
|
||||
// How do we set the min?
|
||||
kh.load_factor = std::min<std::size_t>(
|
||||
65536.0 * load_factor, 65535);
|
||||
write (df, dh);
|
||||
write (kf, kh);
|
||||
buffer buf(block_size);
|
||||
std::memset(buf.get(), 0, block_size);
|
||||
bucket b (block_size, buf.get(), empty);
|
||||
b.write (kf, block_size);
|
||||
// VFALCO Leave log file empty?
|
||||
df.sync();
|
||||
kf.sync();
|
||||
lf.sync();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // nudb
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
246
src/beast/beast/nudb/detail/arena.h
Normal file
@@ -0,0 +1,246 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ARENA_H_INCLUDED
|
||||
#define BEAST_NUDB_ARENA_H_INCLUDED
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
namespace beast {
|
||||
namespace nudb {
|
||||
namespace detail {
|
||||
|
||||
/* Custom memory manager that allocates in large blocks.
|
||||
|
||||
No limit is placed on the size of an allocation but
|
||||
alloc_size should be tuned upon construction to be a
|
||||
significant multiple of the average allocation size.
|
||||
|
||||
When the arena is cleared, allocated memory is placed
|
||||
on a free list for re-use, avoiding future system calls.
|
||||
*/
|
||||
template <class = void>
|
||||
class arena_t
|
||||
{
|
||||
private:
|
||||
class element;
|
||||
|
||||
std::size_t alloc_size_;
|
||||
element* used_ = nullptr;
|
||||
element* free_ = nullptr;
|
||||
|
||||
public:
|
||||
arena_t (arena_t const&);
|
||||
arena_t& operator= (arena_t const&);
|
||||
|
||||
~arena_t();
|
||||
|
||||
explicit
|
||||
arena_t (std::size_t alloc_size);
|
||||
|
||||
arena_t& operator= (arena_t&& other);
|
||||
|
||||
// Makes used blocks free
|
||||
void
|
||||
clear();
|
||||
|
||||
// deletes free blocks
|
||||
void
|
||||
shrink_to_fit();
|
||||
|
||||
std::uint8_t*
|
||||
alloc (std::size_t n);
|
||||
|
||||
template <class U>
|
||||
friend
|
||||
void
|
||||
swap (arena_t<U>& lhs, arena_t<U>& rhs);
|
||||
|
||||
private:
|
||||
void
|
||||
dealloc (element*& list);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class _>
|
||||
class arena_t<_>::element
|
||||
{
|
||||
private:
|
||||
std::size_t const capacity_;
|
||||
std::size_t used_ = 0;
|
||||
|
||||
public:
|
||||
element* next = nullptr;
|
||||
|
||||
explicit
|
||||
element (std::size_t alloc_size)
|
||||
: capacity_ (
|
||||
alloc_size - sizeof(*this))
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
clear()
|
||||
{
|
||||
used_ = 0;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
remain() const
|
||||
{
|
||||
return capacity_ - used_;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
capacity() const
|
||||
{
|
||||
return capacity_;
|
||||
}
|
||||
|
||||
std::uint8_t*
|
||||
alloc (std::size_t n);
|
||||
};
|
||||
|
||||
template <class _>
|
||||
std::uint8_t*
|
||||
arena_t<_>::element::alloc (std::size_t n)
|
||||
{
|
||||
if (n > capacity_ - used_)
|
||||
return nullptr;
|
||||
auto const p = const_cast<std::uint8_t*>(
|
||||
reinterpret_cast<uint8_t const*>(this + 1)
|
||||
) + used_;
|
||||
used_ += n;
|
||||
return p;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class _>
|
||||
arena_t<_>::arena_t (std::size_t alloc_size)
|
||||
: alloc_size_ (alloc_size)
|
||||
{
|
||||
if (alloc_size <= sizeof(element))
|
||||
throw std::domain_error(
|
||||
"arena: bad alloc size");
|
||||
}
|
||||
|
||||
template <class _>
|
||||
arena_t<_>::~arena_t()
|
||||
{
|
||||
dealloc (used_);
|
||||
dealloc (free_);
|
||||
}
|
||||
|
||||
template <class _>
|
||||
arena_t<_>&
|
||||
arena_t<_>::operator= (arena_t&& other)
|
||||
{
|
||||
dealloc (used_);
|
||||
dealloc (free_);
|
||||
alloc_size_ = other.alloc_size_;
|
||||
used_ = other.used_;
|
||||
free_ = other.free_;
|
||||
other.used_ = nullptr;
|
||||
other.free_ = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class _>
|
||||
void
|
||||
arena_t<_>::clear()
|
||||
{
|
||||
while (used_)
|
||||
{
|
||||
auto const e = used_;
|
||||
used_ = used_->next;
|
||||
e->clear();
|
||||
e->next = free_;
|
||||
free_ = e;
|
||||
}
|
||||
}
|
||||
|
||||
template <class _>
|
||||
void
|
||||
arena_t<_>::shrink_to_fit()
|
||||
{
|
||||
dealloc (free_);
|
||||
}
|
||||
|
||||
template <class _>
|
||||
std::uint8_t*
|
||||
arena_t<_>::alloc (std::size_t n)
|
||||
{
|
||||
// Undefined behavior: Zero byte allocations
|
||||
assert(n != 0);
|
||||
n = 8 * ((n + 7) / 8);
|
||||
if (used_ && used_->remain() >= n)
|
||||
return used_->alloc(n);
|
||||
if (free_ && free_->remain() >= n)
|
||||
{
|
||||
auto const e = free_;
|
||||
free_ = free_->next;
|
||||
e->next = used_;
|
||||
used_ = e;
|
||||
return used_->alloc(n);
|
||||
}
|
||||
std::size_t const size = std::max(
|
||||
alloc_size_, sizeof(element) + n);
|
||||
element* const e = reinterpret_cast<element*>(
|
||||
new std::uint8_t[size]);
|
||||
::new(e) element(size);
|
||||
e->next = used_;
|
||||
used_ = e;
|
||||
return used_->alloc(n);
|
||||
}
|
||||
|
||||
template <class _>
|
||||
void
|
||||
swap (arena_t<_>& lhs, arena_t<_>& rhs)
|
||||
{
|
||||
using std::swap;
|
||||
swap(lhs.alloc_size_, rhs.alloc_size_);
|
||||
swap(lhs.used_, rhs.used_);
|
||||
swap(lhs.free_, rhs.free_);
|
||||
}
|
||||
|
||||
template <class _>
|
||||
void
|
||||
arena_t<_>::dealloc (element*& list)
|
||||
{
|
||||
while (list)
|
||||
{
|
||||
auto const e = list;
|
||||
list = list->next;
|
||||
e->~element();
|
||||
delete[] reinterpret_cast<std::uint8_t*>(e);
|
||||
}
|
||||
}
|
||||
|
||||
using arena = arena_t<>;
|
||||
|
||||
} // detail
|
||||
} // nudb
|
||||
} // beast
|
||||
|
||||
#endif
|
||||