mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-19 18:45:52 +00:00
Rearrange sources (#4997)
This commit is contained in:
committed by
John Freeman
parent
2e902dee53
commit
e416ee72ca
41
include/xrpl/basics/Archive.h
Normal file
41
include/xrpl/basics/Archive.h
Normal file
@@ -0,0 +1,41 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2018 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_ARCHIVE_H_INCLUDED
|
||||
#define RIPPLE_BASICS_ARCHIVE_H_INCLUDED
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** Extract a tar archive compressed with lz4
|
||||
|
||||
@param src the path of the archive to be extracted
|
||||
@param dst the directory to extract to
|
||||
|
||||
@throws runtime_error
|
||||
*/
|
||||
void
|
||||
extractTarLz4(
|
||||
boost::filesystem::path const& src,
|
||||
boost::filesystem::path const& dst);
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
402
include/xrpl/basics/BasicConfig.h
Normal file
402
include/xrpl/basics/BasicConfig.h
Normal file
@@ -0,0 +1,402 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_BASICCONFIG_H_INCLUDED
|
||||
#define RIPPLE_BASICS_BASICCONFIG_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <boost/beast/core/string.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
using IniFileSections = std::map<std::string, std::vector<std::string>>;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Holds a collection of configuration values.
|
||||
A configuration file contains zero or more sections.
|
||||
*/
|
||||
class Section
|
||||
{
|
||||
private:
|
||||
std::string name_;
|
||||
std::map<std::string, std::string> lookup_;
|
||||
std::vector<std::string> lines_;
|
||||
std::vector<std::string> values_;
|
||||
bool had_trailing_comments_ = false;
|
||||
|
||||
using const_iterator = decltype(lookup_)::const_iterator;
|
||||
|
||||
public:
|
||||
/** Create an empty section. */
|
||||
explicit Section(std::string const& name = "");
|
||||
|
||||
/** Returns the name of this section. */
|
||||
std::string const&
|
||||
name() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
/** Returns all the lines in the section.
|
||||
This includes everything.
|
||||
*/
|
||||
std::vector<std::string> const&
|
||||
lines() const
|
||||
{
|
||||
return lines_;
|
||||
}
|
||||
|
||||
/** Returns all the values in the section.
|
||||
Values are non-empty lines which are not key/value pairs.
|
||||
*/
|
||||
std::vector<std::string> const&
|
||||
values() const
|
||||
{
|
||||
return values_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the legacy value for this section.
|
||||
*/
|
||||
void
|
||||
legacy(std::string value)
|
||||
{
|
||||
if (lines_.empty())
|
||||
lines_.emplace_back(std::move(value));
|
||||
else
|
||||
lines_[0] = std::move(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the legacy value for this section.
|
||||
*
|
||||
* @return The retrieved value. A section with an empty legacy value returns
|
||||
an empty string.
|
||||
*/
|
||||
std::string
|
||||
legacy() const
|
||||
{
|
||||
if (lines_.empty())
|
||||
return "";
|
||||
if (lines_.size() > 1)
|
||||
Throw<std::runtime_error>(
|
||||
"A legacy value must have exactly one line. Section: " + name_);
|
||||
return lines_[0];
|
||||
}
|
||||
|
||||
/** Set a key/value pair.
|
||||
The previous value is discarded.
|
||||
*/
|
||||
void
|
||||
set(std::string const& key, std::string const& value);
|
||||
|
||||
/** Append a set of lines to this section.
|
||||
Lines containing key/value pairs are added to the map,
|
||||
else they are added to the values list. Everything is
|
||||
added to the lines list.
|
||||
*/
|
||||
void
|
||||
append(std::vector<std::string> const& lines);
|
||||
|
||||
/** Append a line to this section. */
|
||||
void
|
||||
append(std::string const& line)
|
||||
{
|
||||
append(std::vector<std::string>{line});
|
||||
}
|
||||
|
||||
/** Returns `true` if a key with the given name exists. */
|
||||
bool
|
||||
exists(std::string const& name) const;
|
||||
|
||||
template <class T = std::string>
|
||||
std::optional<T>
|
||||
get(std::string const& name) const
|
||||
{
|
||||
auto const iter = lookup_.find(name);
|
||||
if (iter == lookup_.end())
|
||||
return std::nullopt;
|
||||
return boost::lexical_cast<T>(iter->second);
|
||||
}
|
||||
|
||||
/// Returns a value if present, else another value.
|
||||
template <class T>
|
||||
T
|
||||
value_or(std::string const& name, T const& other) const
|
||||
{
|
||||
auto const v = get<T>(name);
|
||||
return v.has_value() ? *v : other;
|
||||
}
|
||||
|
||||
// indicates if trailing comments were seen
|
||||
// during the appending of any lines/values
|
||||
bool
|
||||
had_trailing_comments() const
|
||||
{
|
||||
return had_trailing_comments_;
|
||||
}
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream&, Section const& section);
|
||||
|
||||
// Returns `true` if there are no key/value pairs.
|
||||
bool
|
||||
empty() const
|
||||
{
|
||||
return lookup_.empty();
|
||||
}
|
||||
|
||||
// Returns the number of key/value pairs.
|
||||
std::size_t
|
||||
size() const
|
||||
{
|
||||
return lookup_.size();
|
||||
}
|
||||
|
||||
// For iteration of key/value pairs.
|
||||
const_iterator
|
||||
begin() const
|
||||
{
|
||||
return lookup_.cbegin();
|
||||
}
|
||||
|
||||
// For iteration of key/value pairs.
|
||||
const_iterator
|
||||
cbegin() const
|
||||
{
|
||||
return lookup_.cbegin();
|
||||
}
|
||||
|
||||
// For iteration of key/value pairs.
|
||||
const_iterator
|
||||
end() const
|
||||
{
|
||||
return lookup_.cend();
|
||||
}
|
||||
|
||||
// For iteration of key/value pairs.
|
||||
const_iterator
|
||||
cend() const
|
||||
{
|
||||
return lookup_.cend();
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Holds unparsed configuration information.
|
||||
The raw data sections are processed with intermediate parsers specific
|
||||
to each module instead of being all parsed in a central location.
|
||||
*/
|
||||
class BasicConfig
|
||||
{
|
||||
private:
|
||||
std::map<std::string, Section, boost::beast::iless> map_;
|
||||
|
||||
public:
|
||||
/** Returns `true` if a section with the given name exists. */
|
||||
bool
|
||||
exists(std::string const& name) const;
|
||||
|
||||
/** Returns the section with the given name.
|
||||
If the section does not exist, an empty section is returned.
|
||||
*/
|
||||
/** @{ */
|
||||
Section&
|
||||
section(std::string const& name);
|
||||
|
||||
Section const&
|
||||
section(std::string const& name) const;
|
||||
|
||||
Section const&
|
||||
operator[](std::string const& name) const
|
||||
{
|
||||
return section(name);
|
||||
}
|
||||
|
||||
Section&
|
||||
operator[](std::string const& name)
|
||||
{
|
||||
return section(name);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Overwrite a key/value pair with a command line argument
|
||||
If the section does not exist it is created.
|
||||
The previous value, if any, is overwritten.
|
||||
*/
|
||||
void
|
||||
overwrite(
|
||||
std::string const& section,
|
||||
std::string const& key,
|
||||
std::string const& value);
|
||||
|
||||
/** Remove all the key/value pairs from the section.
|
||||
*/
|
||||
void
|
||||
deprecatedClearSection(std::string const& section);
|
||||
|
||||
/**
|
||||
* Set a value that is not a key/value pair.
|
||||
*
|
||||
* The value is stored as the section's first value and may be retrieved
|
||||
* through section::legacy.
|
||||
*
|
||||
* @param section Name of the section to modify.
|
||||
* @param value Contents of the legacy value.
|
||||
*/
|
||||
void
|
||||
legacy(std::string const& section, std::string value);
|
||||
|
||||
/**
|
||||
* Get the legacy value of a section. A section with a
|
||||
* single-line value may be retrieved as a legacy value.
|
||||
*
|
||||
* @param sectionName Retrieve the contents of this section's
|
||||
* legacy value.
|
||||
* @return Contents of the legacy value.
|
||||
*/
|
||||
std::string
|
||||
legacy(std::string const& sectionName) const;
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& ss, BasicConfig const& c);
|
||||
|
||||
// indicates if trailing comments were seen
|
||||
// in any loaded Sections
|
||||
bool
|
||||
had_trailing_comments() const
|
||||
{
|
||||
return std::any_of(map_.cbegin(), map_.cend(), [](auto s) {
|
||||
return s.second.had_trailing_comments();
|
||||
});
|
||||
}
|
||||
|
||||
protected:
|
||||
void
|
||||
build(IniFileSections const& ifs);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Set a value from a configuration Section
|
||||
If the named value is not found or doesn't parse as a T,
|
||||
the variable is unchanged.
|
||||
@return `true` if value was set.
|
||||
*/
|
||||
template <class T>
|
||||
bool
|
||||
set(T& target, std::string const& name, Section const& section)
|
||||
{
|
||||
bool found_and_valid = false;
|
||||
try
|
||||
{
|
||||
auto const val = section.get<T>(name);
|
||||
if ((found_and_valid = val.has_value()))
|
||||
target = *val;
|
||||
}
|
||||
catch (boost::bad_lexical_cast&)
|
||||
{
|
||||
}
|
||||
return found_and_valid;
|
||||
}
|
||||
|
||||
/** Set a value from a configuration Section
|
||||
If the named value is not found or doesn't cast to T,
|
||||
the variable is assigned the default.
|
||||
@return `true` if the named value was found and is valid.
|
||||
*/
|
||||
template <class T>
|
||||
bool
|
||||
set(T& target,
|
||||
T const& defaultValue,
|
||||
std::string const& name,
|
||||
Section const& section)
|
||||
{
|
||||
bool found_and_valid = set<T>(target, name, section);
|
||||
if (!found_and_valid)
|
||||
target = defaultValue;
|
||||
return found_and_valid;
|
||||
}
|
||||
|
||||
/** Retrieve a key/value pair from a section.
|
||||
@return The value string converted to T if it exists
|
||||
and can be parsed, or else defaultValue.
|
||||
*/
|
||||
// NOTE This routine might be more clumsy than the previous two
|
||||
template <class T = std::string>
|
||||
T
|
||||
get(Section const& section,
|
||||
std::string const& name,
|
||||
T const& defaultValue = T{})
|
||||
{
|
||||
try
|
||||
{
|
||||
return section.value_or<T>(name, defaultValue);
|
||||
}
|
||||
catch (boost::bad_lexical_cast&)
|
||||
{
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
inline std::string
|
||||
get(Section const& section, std::string const& name, const char* defaultValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto const val = section.get(name);
|
||||
if (val.has_value())
|
||||
return *val;
|
||||
}
|
||||
catch (boost::bad_lexical_cast&)
|
||||
{
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
get_if_exists(Section const& section, std::string const& name, T& v)
|
||||
{
|
||||
return set<T>(v, name, section);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool
|
||||
get_if_exists<bool>(Section const& section, std::string const& name, bool& v)
|
||||
{
|
||||
int intVal = 0;
|
||||
auto stat = get_if_exists(section, name, intVal);
|
||||
if (stat)
|
||||
v = bool(intVal);
|
||||
return stat;
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
34
include/xrpl/basics/Blob.h
Normal file
34
include/xrpl/basics/Blob.h
Normal file
@@ -0,0 +1,34 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_BLOB_H_INCLUDED
|
||||
#define RIPPLE_BASICS_BLOB_H_INCLUDED
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** Storage for linear binary data.
|
||||
Blocks of binary data appear often in various idioms and structures.
|
||||
*/
|
||||
using Blob = std::vector<unsigned char>;
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
238
include/xrpl/basics/Buffer.h
Normal file
238
include/xrpl/basics/Buffer.h
Normal file
@@ -0,0 +1,238 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_BUFFER_H_INCLUDED
|
||||
#define RIPPLE_BASICS_BUFFER_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/Slice.h>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** Like std::vector<char> but better.
|
||||
Meets the requirements of BufferFactory.
|
||||
*/
|
||||
class Buffer
|
||||
{
|
||||
private:
|
||||
std::unique_ptr<std::uint8_t[]> p_;
|
||||
std::size_t size_ = 0;
|
||||
|
||||
public:
|
||||
using const_iterator = std::uint8_t const*;
|
||||
|
||||
Buffer() = default;
|
||||
|
||||
/** Create an uninitialized buffer with the given size. */
|
||||
explicit Buffer(std::size_t size)
|
||||
: p_(size ? new std::uint8_t[size] : nullptr), size_(size)
|
||||
{
|
||||
}
|
||||
|
||||
/** Create a buffer as a copy of existing memory.
|
||||
|
||||
@param data a pointer to the existing memory. If
|
||||
size is non-zero, it must not be null.
|
||||
@param size size of the existing memory block.
|
||||
*/
|
||||
Buffer(void const* data, std::size_t size) : Buffer(size)
|
||||
{
|
||||
if (size)
|
||||
std::memcpy(p_.get(), data, size);
|
||||
}
|
||||
|
||||
/** Copy-construct */
|
||||
Buffer(Buffer const& other) : Buffer(other.p_.get(), other.size_)
|
||||
{
|
||||
}
|
||||
|
||||
/** Copy assign */
|
||||
Buffer&
|
||||
operator=(Buffer const& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
if (auto p = alloc(other.size_))
|
||||
std::memcpy(p, other.p_.get(), size_);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Move-construct.
|
||||
The other buffer is reset.
|
||||
*/
|
||||
Buffer(Buffer&& other) noexcept
|
||||
: p_(std::move(other.p_)), size_(other.size_)
|
||||
{
|
||||
other.size_ = 0;
|
||||
}
|
||||
|
||||
/** Move-assign.
|
||||
The other buffer is reset.
|
||||
*/
|
||||
Buffer&
|
||||
operator=(Buffer&& other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
p_ = std::move(other.p_);
|
||||
size_ = other.size_;
|
||||
other.size_ = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Construct from a slice */
|
||||
explicit Buffer(Slice s) : Buffer(s.data(), s.size())
|
||||
{
|
||||
}
|
||||
|
||||
/** Assign from slice */
|
||||
Buffer&
|
||||
operator=(Slice s)
|
||||
{
|
||||
// Ensure the slice isn't a subset of the buffer.
|
||||
assert(
|
||||
s.size() == 0 || size_ == 0 || s.data() < p_.get() ||
|
||||
s.data() >= p_.get() + size_);
|
||||
|
||||
if (auto p = alloc(s.size()))
|
||||
std::memcpy(p, s.data(), s.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Returns the number of bytes in the buffer. */
|
||||
std::size_t
|
||||
size() const noexcept
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
bool
|
||||
empty() const noexcept
|
||||
{
|
||||
return 0 == size_;
|
||||
}
|
||||
|
||||
operator Slice() const noexcept
|
||||
{
|
||||
if (!size_)
|
||||
return Slice{};
|
||||
return Slice{p_.get(), size_};
|
||||
}
|
||||
|
||||
/** Return a pointer to beginning of the storage.
|
||||
@note The return type is guaranteed to be a pointer
|
||||
to a single byte, to facilitate pointer arithmetic.
|
||||
*/
|
||||
/** @{ */
|
||||
std::uint8_t const*
|
||||
data() const noexcept
|
||||
{
|
||||
return p_.get();
|
||||
}
|
||||
|
||||
std::uint8_t*
|
||||
data() noexcept
|
||||
{
|
||||
return p_.get();
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Reset the buffer.
|
||||
All memory is deallocated. The resulting size is 0.
|
||||
*/
|
||||
void
|
||||
clear() noexcept
|
||||
{
|
||||
p_.reset();
|
||||
size_ = 0;
|
||||
}
|
||||
|
||||
/** Reallocate the storage.
|
||||
Existing data, if any, is discarded.
|
||||
*/
|
||||
std::uint8_t*
|
||||
alloc(std::size_t n)
|
||||
{
|
||||
if (n != size_)
|
||||
{
|
||||
p_.reset(n ? new std::uint8_t[n] : nullptr);
|
||||
size_ = n;
|
||||
}
|
||||
return p_.get();
|
||||
}
|
||||
|
||||
// Meet the requirements of BufferFactory
|
||||
void*
|
||||
operator()(std::size_t n)
|
||||
{
|
||||
return alloc(n);
|
||||
}
|
||||
|
||||
const_iterator
|
||||
begin() const noexcept
|
||||
{
|
||||
return p_.get();
|
||||
}
|
||||
|
||||
const_iterator
|
||||
cbegin() const noexcept
|
||||
{
|
||||
return p_.get();
|
||||
}
|
||||
|
||||
const_iterator
|
||||
end() const noexcept
|
||||
{
|
||||
return p_.get() + size_;
|
||||
}
|
||||
|
||||
const_iterator
|
||||
cend() const noexcept
|
||||
{
|
||||
return p_.get() + size_;
|
||||
}
|
||||
};
|
||||
|
||||
inline bool
|
||||
operator==(Buffer const& lhs, Buffer const& rhs) noexcept
|
||||
{
|
||||
if (lhs.size() != rhs.size())
|
||||
return false;
|
||||
|
||||
if (lhs.size() == 0)
|
||||
return true;
|
||||
|
||||
return std::memcmp(lhs.data(), rhs.data(), lhs.size()) == 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator!=(Buffer const& lhs, Buffer const& rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
43
include/xrpl/basics/ByteUtilities.h
Normal file
43
include/xrpl/basics/ByteUtilities.h
Normal file
@@ -0,0 +1,43 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2018 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_BYTEUTILITIES_H_INCLUDED
|
||||
#define RIPPLE_BASICS_BYTEUTILITIES_H_INCLUDED
|
||||
|
||||
namespace ripple {
|
||||
|
||||
template <class T>
|
||||
constexpr auto
|
||||
kilobytes(T value) noexcept
|
||||
{
|
||||
return value * 1024;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr auto
|
||||
megabytes(T value) noexcept
|
||||
{
|
||||
return kilobytes(kilobytes(value));
|
||||
}
|
||||
|
||||
static_assert(kilobytes(2) == 2048, "kilobytes(2) == 2048");
|
||||
static_assert(megabytes(3) == 3145728, "megabytes(3) == 3145728");
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
166
include/xrpl/basics/CompressionAlgorithms.h
Normal file
166
include/xrpl/basics/CompressionAlgorithms.h
Normal file
@@ -0,0 +1,166 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2020 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLED_COMPRESSIONALGORITHMS_H_INCLUDED
|
||||
#define RIPPLED_COMPRESSIONALGORITHMS_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <lz4.h>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
namespace compression_algorithms {
|
||||
|
||||
/** LZ4 block compression.
|
||||
* @tparam BufferFactory Callable object or lambda.
|
||||
* Takes the requested buffer size and returns allocated buffer pointer.
|
||||
* @param in Data to compress
|
||||
* @param inSize Size of the data
|
||||
* @param bf Compressed buffer allocator
|
||||
* @return Size of compressed data, or zero if failed to compress
|
||||
*/
|
||||
template <typename BufferFactory>
|
||||
std::size_t
|
||||
lz4Compress(void const* in, std::size_t inSize, BufferFactory&& bf)
|
||||
{
|
||||
if (inSize > UINT32_MAX)
|
||||
Throw<std::runtime_error>("lz4 compress: invalid size");
|
||||
|
||||
auto const outCapacity = LZ4_compressBound(inSize);
|
||||
|
||||
// Request the caller to allocate and return the buffer to hold compressed
|
||||
// data
|
||||
auto compressed = bf(outCapacity);
|
||||
|
||||
auto compressedSize = LZ4_compress_default(
|
||||
reinterpret_cast<const char*>(in),
|
||||
reinterpret_cast<char*>(compressed),
|
||||
inSize,
|
||||
outCapacity);
|
||||
if (compressedSize == 0)
|
||||
Throw<std::runtime_error>("lz4 compress: failed");
|
||||
|
||||
return compressedSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param in Compressed data
|
||||
* @param inSizeUnchecked Size of compressed data
|
||||
* @param decompressed Buffer to hold decompressed data
|
||||
* @param decompressedSizeUnchecked Size of the decompressed buffer
|
||||
* @return size of the decompressed data
|
||||
*/
|
||||
inline std::size_t
|
||||
lz4Decompress(
|
||||
std::uint8_t const* in,
|
||||
std::size_t inSizeUnchecked,
|
||||
std::uint8_t* decompressed,
|
||||
std::size_t decompressedSizeUnchecked)
|
||||
{
|
||||
int const inSize = static_cast<int>(inSizeUnchecked);
|
||||
int const decompressedSize = static_cast<int>(decompressedSizeUnchecked);
|
||||
|
||||
if (inSize <= 0)
|
||||
Throw<std::runtime_error>("lz4Decompress: integer overflow (input)");
|
||||
|
||||
if (decompressedSize <= 0)
|
||||
Throw<std::runtime_error>("lz4Decompress: integer overflow (output)");
|
||||
|
||||
if (LZ4_decompress_safe(
|
||||
reinterpret_cast<const char*>(in),
|
||||
reinterpret_cast<char*>(decompressed),
|
||||
inSize,
|
||||
decompressedSize) != decompressedSize)
|
||||
Throw<std::runtime_error>("lz4Decompress: failed");
|
||||
|
||||
return decompressedSize;
|
||||
}
|
||||
|
||||
/** LZ4 block decompression.
|
||||
* @tparam InputStream ZeroCopyInputStream
|
||||
* @param in Input source stream
|
||||
* @param inSize Size of compressed data
|
||||
* @param decompressed Buffer to hold decompressed data
|
||||
* @param decompressedSize Size of the decompressed buffer
|
||||
* @return size of the decompressed data
|
||||
*/
|
||||
template <typename InputStream>
|
||||
std::size_t
|
||||
lz4Decompress(
|
||||
InputStream& in,
|
||||
std::size_t inSize,
|
||||
std::uint8_t* decompressed,
|
||||
std::size_t decompressedSize)
|
||||
{
|
||||
std::vector<std::uint8_t> compressed;
|
||||
std::uint8_t const* chunk = nullptr;
|
||||
int chunkSize = 0;
|
||||
int copiedInSize = 0;
|
||||
auto const currentBytes = in.ByteCount();
|
||||
|
||||
// Use the first chunk if it is >= inSize bytes of the compressed message.
|
||||
// Otherwise copy inSize bytes of chunks into compressed buffer and
|
||||
// use the buffer to decompress.
|
||||
while (in.Next(reinterpret_cast<void const**>(&chunk), &chunkSize))
|
||||
{
|
||||
if (copiedInSize == 0)
|
||||
{
|
||||
if (chunkSize >= inSize)
|
||||
{
|
||||
copiedInSize = inSize;
|
||||
break;
|
||||
}
|
||||
compressed.resize(inSize);
|
||||
}
|
||||
|
||||
chunkSize = chunkSize < (inSize - copiedInSize)
|
||||
? chunkSize
|
||||
: (inSize - copiedInSize);
|
||||
|
||||
std::copy(chunk, chunk + chunkSize, compressed.data() + copiedInSize);
|
||||
|
||||
copiedInSize += chunkSize;
|
||||
|
||||
if (copiedInSize == inSize)
|
||||
{
|
||||
chunk = compressed.data();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Put back unused bytes
|
||||
if (in.ByteCount() > (currentBytes + copiedInSize))
|
||||
in.BackUp(in.ByteCount() - currentBytes - copiedInSize);
|
||||
|
||||
if ((copiedInSize == 0 && chunkSize < inSize) ||
|
||||
(copiedInSize > 0 && copiedInSize != inSize))
|
||||
Throw<std::runtime_error>("lz4 decompress: insufficient input size");
|
||||
|
||||
return lz4Decompress(chunk, inSize, decompressed, decompressedSize);
|
||||
}
|
||||
|
||||
} // namespace compression_algorithms
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif // RIPPLED_COMPRESSIONALGORITHMS_H_INCLUDED
|
||||
156
include/xrpl/basics/CountedObject.h
Normal file
156
include/xrpl/basics/CountedObject.h
Normal file
@@ -0,0 +1,156 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_COUNTEDOBJECT_H_INCLUDED
|
||||
#define RIPPLE_BASICS_COUNTEDOBJECT_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/type_name.h>
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** Manages all counted object types. */
|
||||
class CountedObjects
|
||||
{
|
||||
public:
|
||||
static CountedObjects&
|
||||
getInstance() noexcept;
|
||||
|
||||
using Entry = std::pair<std::string, int>;
|
||||
using List = std::vector<Entry>;
|
||||
|
||||
List
|
||||
getCounts(int minimumThreshold) const;
|
||||
|
||||
public:
|
||||
/** Implementation for @ref CountedObject.
|
||||
|
||||
@internal
|
||||
*/
|
||||
class Counter
|
||||
{
|
||||
public:
|
||||
Counter(std::string name) noexcept : name_(std::move(name)), count_(0)
|
||||
{
|
||||
// Insert ourselves at the front of the lock-free linked list
|
||||
CountedObjects& instance = CountedObjects::getInstance();
|
||||
Counter* head;
|
||||
|
||||
do
|
||||
{
|
||||
head = instance.m_head.load();
|
||||
next_ = head;
|
||||
} while (instance.m_head.exchange(this) != head);
|
||||
|
||||
++instance.m_count;
|
||||
}
|
||||
|
||||
~Counter() noexcept = default;
|
||||
|
||||
int
|
||||
increment() noexcept
|
||||
{
|
||||
return ++count_;
|
||||
}
|
||||
|
||||
int
|
||||
decrement() noexcept
|
||||
{
|
||||
return --count_;
|
||||
}
|
||||
|
||||
int
|
||||
getCount() const noexcept
|
||||
{
|
||||
return count_.load();
|
||||
}
|
||||
|
||||
Counter*
|
||||
getNext() const noexcept
|
||||
{
|
||||
return next_;
|
||||
}
|
||||
|
||||
std::string const&
|
||||
getName() const noexcept
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string const name_;
|
||||
std::atomic<int> count_;
|
||||
Counter* next_;
|
||||
};
|
||||
|
||||
private:
|
||||
CountedObjects() noexcept;
|
||||
~CountedObjects() noexcept = default;
|
||||
|
||||
private:
|
||||
std::atomic<int> m_count;
|
||||
std::atomic<Counter*> m_head;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Tracks the number of instances of an object.
|
||||
|
||||
Derived classes have their instances counted automatically. This is used
|
||||
for reporting purposes.
|
||||
|
||||
@ingroup ripple_basics
|
||||
*/
|
||||
template <class Object>
|
||||
class CountedObject
|
||||
{
|
||||
private:
|
||||
static auto&
|
||||
getCounter() noexcept
|
||||
{
|
||||
static CountedObjects::Counter c{beast::type_name<Object>()};
|
||||
return c;
|
||||
}
|
||||
|
||||
public:
|
||||
CountedObject() noexcept
|
||||
{
|
||||
getCounter().increment();
|
||||
}
|
||||
|
||||
CountedObject(CountedObject const&) noexcept
|
||||
{
|
||||
getCounter().increment();
|
||||
}
|
||||
|
||||
CountedObject&
|
||||
operator=(CountedObject const&) noexcept = default;
|
||||
|
||||
~CountedObject() noexcept
|
||||
{
|
||||
getCounter().decrement();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
155
include/xrpl/basics/DecayingSample.h
Normal file
155
include/xrpl/basics/DecayingSample.h
Normal file
@@ -0,0 +1,155 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_DECAYINGSAMPLE_H_INCLUDED
|
||||
#define RIPPLE_BASICS_DECAYINGSAMPLE_H_INCLUDED
|
||||
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** Sampling function using exponential decay to provide a continuous value.
|
||||
@tparam The number of seconds in the decay window.
|
||||
*/
|
||||
template <int Window, typename Clock>
|
||||
class DecayingSample
|
||||
{
|
||||
public:
|
||||
using value_type = typename Clock::duration::rep;
|
||||
using time_point = typename Clock::time_point;
|
||||
|
||||
DecayingSample() = delete;
|
||||
|
||||
/**
|
||||
@param now Start time of DecayingSample.
|
||||
*/
|
||||
explicit DecayingSample(time_point now) : m_value(value_type()), m_when(now)
|
||||
{
|
||||
}
|
||||
|
||||
/** Add a new sample.
|
||||
The value is first aged according to the specified time.
|
||||
*/
|
||||
value_type
|
||||
add(value_type value, time_point now)
|
||||
{
|
||||
decay(now);
|
||||
m_value += value;
|
||||
return m_value / Window;
|
||||
}
|
||||
|
||||
/** Retrieve the current value in normalized units.
|
||||
The samples are first aged according to the specified time.
|
||||
*/
|
||||
value_type
|
||||
value(time_point now)
|
||||
{
|
||||
decay(now);
|
||||
return m_value / Window;
|
||||
}
|
||||
|
||||
private:
|
||||
// Apply exponential decay based on the specified time.
|
||||
void
|
||||
decay(time_point now)
|
||||
{
|
||||
if (now == m_when)
|
||||
return;
|
||||
|
||||
if (m_value != value_type())
|
||||
{
|
||||
std::size_t elapsed =
|
||||
std::chrono::duration_cast<std::chrono::seconds>(now - m_when)
|
||||
.count();
|
||||
|
||||
// A span larger than four times the window decays the
|
||||
// value to an insignificant amount so just reset it.
|
||||
//
|
||||
if (elapsed > 4 * Window)
|
||||
{
|
||||
m_value = value_type();
|
||||
}
|
||||
else
|
||||
{
|
||||
while (elapsed--)
|
||||
m_value -= (m_value + Window - 1) / Window;
|
||||
}
|
||||
}
|
||||
|
||||
m_when = now;
|
||||
}
|
||||
|
||||
// Current value in exponential units
|
||||
value_type m_value;
|
||||
|
||||
// Last time the aging function was applied
|
||||
time_point m_when;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Sampling function using exponential decay to provide a continuous value.
|
||||
@tparam HalfLife The half life of a sample, in seconds.
|
||||
*/
|
||||
template <int HalfLife, class Clock>
|
||||
class DecayWindow
|
||||
{
|
||||
public:
|
||||
using time_point = typename Clock::time_point;
|
||||
|
||||
explicit DecayWindow(time_point now) : value_(0), when_(now)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
add(double value, time_point now)
|
||||
{
|
||||
decay(now);
|
||||
value_ += value;
|
||||
}
|
||||
|
||||
double
|
||||
value(time_point now)
|
||||
{
|
||||
decay(now);
|
||||
return value_ / HalfLife;
|
||||
}
|
||||
|
||||
private:
|
||||
static_assert(HalfLife > 0, "half life must be positive");
|
||||
|
||||
void
|
||||
decay(time_point now)
|
||||
{
|
||||
if (now <= when_)
|
||||
return;
|
||||
using namespace std::chrono;
|
||||
auto const elapsed = duration<double>(now - when_).count();
|
||||
value_ *= std::pow(2.0, -elapsed / HalfLife);
|
||||
when_ = now;
|
||||
}
|
||||
|
||||
double value_;
|
||||
time_point when_;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
245
include/xrpl/basics/Expected.h
Normal file
245
include/xrpl/basics/Expected.h
Normal file
@@ -0,0 +1,245 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2021 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_EXPECTED_H_INCLUDED
|
||||
#define RIPPLE_BASICS_EXPECTED_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/contract.h>
|
||||
|
||||
#include <boost/outcome.hpp>
|
||||
|
||||
#include <concepts>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** Expected is an approximation of std::expected (hoped for in C++23)
|
||||
|
||||
See: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0323r10.html
|
||||
|
||||
The implementation is entirely based on boost::outcome_v2::result.
|
||||
*/
|
||||
|
||||
// Exception thrown by an invalid access to Expected.
|
||||
struct bad_expected_access : public std::runtime_error
|
||||
{
|
||||
bad_expected_access() : runtime_error("bad expected access")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Custom policy for Expected. Always throw on an invalid access.
|
||||
struct throw_policy : public boost::outcome_v2::policy::base
|
||||
{
|
||||
template <class Impl>
|
||||
static constexpr void
|
||||
wide_value_check(Impl&& self)
|
||||
{
|
||||
if (!base::_has_value(std::forward<Impl>(self)))
|
||||
Throw<bad_expected_access>();
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
static constexpr void
|
||||
wide_error_check(Impl&& self)
|
||||
{
|
||||
if (!base::_has_error(std::forward<Impl>(self)))
|
||||
Throw<bad_expected_access>();
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
static constexpr void
|
||||
wide_exception_check(Impl&& self)
|
||||
{
|
||||
if (!base::_has_exception(std::forward<Impl>(self)))
|
||||
Throw<bad_expected_access>();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// Definition of Unexpected, which is used to construct the unexpected
|
||||
// return type of an Expected.
|
||||
template <class E>
|
||||
class Unexpected
|
||||
{
|
||||
public:
|
||||
static_assert(!std::is_same<E, void>::value, "E must not be void");
|
||||
|
||||
Unexpected() = delete;
|
||||
|
||||
constexpr explicit Unexpected(E const& e) : val_(e)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr explicit Unexpected(E&& e) : val_(std::move(e))
|
||||
{
|
||||
}
|
||||
|
||||
constexpr const E&
|
||||
value() const&
|
||||
{
|
||||
return val_;
|
||||
}
|
||||
|
||||
constexpr E&
|
||||
value() &
|
||||
{
|
||||
return val_;
|
||||
}
|
||||
|
||||
constexpr E&&
|
||||
value() &&
|
||||
{
|
||||
return std::move(val_);
|
||||
}
|
||||
|
||||
constexpr const E&&
|
||||
value() const&&
|
||||
{
|
||||
return std::move(val_);
|
||||
}
|
||||
|
||||
private:
|
||||
E val_;
|
||||
};
|
||||
|
||||
// Unexpected deduction guide that converts array to const*.
|
||||
template <typename E, std::size_t N>
|
||||
Unexpected(E (&)[N]) -> Unexpected<E const*>;
|
||||
|
||||
// Definition of Expected. All of the machinery comes from boost::result.
|
||||
template <class T, class E>
|
||||
class [[nodiscard]] Expected
|
||||
: private boost::outcome_v2::result<T, E, detail::throw_policy>
|
||||
{
|
||||
using Base = boost::outcome_v2::result<T, E, detail::throw_policy>;
|
||||
|
||||
public:
|
||||
template <typename U>
|
||||
requires std::convertible_to<U, T> constexpr Expected(U && r)
|
||||
: Base(T(std::forward<U>(r)))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
requires std::convertible_to<U, E> &&
|
||||
(!std::is_reference_v<U>)constexpr Expected(Unexpected<U> e)
|
||||
: Base(E(std::move(e.value())))
|
||||
{
|
||||
}
|
||||
|
||||
constexpr bool has_value() const
|
||||
{
|
||||
return Base::has_value();
|
||||
}
|
||||
|
||||
constexpr T const& value() const
|
||||
{
|
||||
return Base::value();
|
||||
}
|
||||
|
||||
constexpr T& value()
|
||||
{
|
||||
return Base::value();
|
||||
}
|
||||
|
||||
constexpr E const& error() const
|
||||
{
|
||||
return Base::error();
|
||||
}
|
||||
|
||||
constexpr E& error()
|
||||
{
|
||||
return Base::error();
|
||||
}
|
||||
|
||||
constexpr explicit operator bool() const
|
||||
{
|
||||
return has_value();
|
||||
}
|
||||
|
||||
// Add operator* and operator-> so the Expected API looks a bit more like
|
||||
// what std::expected is likely to look like. See:
|
||||
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0323r10.html
|
||||
[[nodiscard]] constexpr T& operator*()
|
||||
{
|
||||
return this->value();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr T const& operator*() const
|
||||
{
|
||||
return this->value();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr T* operator->()
|
||||
{
|
||||
return &this->value();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr T const* operator->() const
|
||||
{
|
||||
return &this->value();
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization of Expected<void, E>. Allows returning either success
|
||||
// (without a value) or the reason for the failure.
|
||||
template <class E>
|
||||
class [[nodiscard]] Expected<void, E>
|
||||
: private boost::outcome_v2::result<void, E, detail::throw_policy>
|
||||
{
|
||||
using Base = boost::outcome_v2::result<void, E, detail::throw_policy>;
|
||||
|
||||
public:
|
||||
// The default constructor makes a successful Expected<void, E>.
|
||||
// This aligns with std::expected behavior proposed in P0323R10.
|
||||
constexpr Expected() : Base(boost::outcome_v2::success())
|
||||
{
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
requires std::convertible_to<U, E> &&
|
||||
(!std::is_reference_v<U>)constexpr Expected(Unexpected<U> e)
|
||||
: Base(E(std::move(e.value())))
|
||||
{
|
||||
}
|
||||
|
||||
constexpr E const& error() const
|
||||
{
|
||||
return Base::error();
|
||||
}
|
||||
|
||||
constexpr E& error()
|
||||
{
|
||||
return Base::error();
|
||||
}
|
||||
|
||||
constexpr explicit operator bool() const
|
||||
{
|
||||
return Base::has_value();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif // RIPPLE_BASICS_EXPECTED_H_INCLUDED
|
||||
556
include/xrpl/basics/FeeUnits.h
Normal file
556
include/xrpl/basics/FeeUnits.h
Normal file
@@ -0,0 +1,556 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2019 Ripple Labs Inc.
|
||||
|
||||
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 BASICS_FEES_H_INCLUDED
|
||||
#define BASICS_FEES_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/XRPAmount.h>
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <ios>
|
||||
#include <iosfwd>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
namespace feeunit {
|
||||
|
||||
/** "fee units" calculations are a not-really-unitless value that is used
|
||||
to express the cost of a given transaction vs. a reference transaction.
|
||||
They are primarily used by the Transactor classes. */
|
||||
struct feeunitTag;
|
||||
/** "fee levels" are used by the transaction queue to compare the relative
|
||||
cost of transactions that require different levels of effort to process.
|
||||
See also: src/ripple/app/misc/FeeEscalation.md#fee-level */
|
||||
struct feelevelTag;
|
||||
/** unitless values are plain scalars wrapped in a TaggedFee. They are
|
||||
used for calculations in this header. */
|
||||
struct unitlessTag;
|
||||
|
||||
template <class T>
|
||||
using enable_if_unit_t = typename std::enable_if_t<
|
||||
std::is_class_v<T> && std::is_object_v<typename T::unit_type> &&
|
||||
std::is_object_v<typename T::value_type>>;
|
||||
|
||||
/** `is_usable_unit_v` is checked to ensure that only values with
|
||||
known valid type tags can be used (sometimes transparently) in
|
||||
non-fee contexts. At the time of implementation, this includes
|
||||
all known tags, but more may be added in the future, and they
|
||||
should not be added automatically unless determined to be
|
||||
appropriate.
|
||||
*/
|
||||
template <class T, class = enable_if_unit_t<T>>
|
||||
constexpr bool is_usable_unit_v =
|
||||
std::is_same_v<typename T::unit_type, feeunitTag> ||
|
||||
std::is_same_v<typename T::unit_type, feelevelTag> ||
|
||||
std::is_same_v<typename T::unit_type, unitlessTag> ||
|
||||
std::is_same_v<typename T::unit_type, dropTag>;
|
||||
|
||||
template <class UnitTag, class T>
|
||||
class TaggedFee : private boost::totally_ordered<TaggedFee<UnitTag, T>>,
|
||||
private boost::additive<TaggedFee<UnitTag, T>>,
|
||||
private boost::equality_comparable<TaggedFee<UnitTag, T>, T>,
|
||||
private boost::dividable<TaggedFee<UnitTag, T>, T>,
|
||||
private boost::modable<TaggedFee<UnitTag, T>, T>,
|
||||
private boost::unit_steppable<TaggedFee<UnitTag, T>>
|
||||
{
|
||||
public:
|
||||
using unit_type = UnitTag;
|
||||
using value_type = T;
|
||||
|
||||
private:
|
||||
value_type fee_;
|
||||
|
||||
protected:
|
||||
template <class Other>
|
||||
static constexpr bool is_compatible_v =
|
||||
std::is_arithmetic_v<Other>&& std::is_arithmetic_v<value_type>&&
|
||||
std::is_convertible_v<Other, value_type>;
|
||||
|
||||
template <class OtherFee, class = enable_if_unit_t<OtherFee>>
|
||||
static constexpr bool is_compatiblefee_v =
|
||||
is_compatible_v<typename OtherFee::value_type>&&
|
||||
std::is_same_v<UnitTag, typename OtherFee::unit_type>;
|
||||
|
||||
template <class Other>
|
||||
using enable_if_compatible_t =
|
||||
typename std::enable_if_t<is_compatible_v<Other>>;
|
||||
|
||||
template <class OtherFee>
|
||||
using enable_if_compatiblefee_t =
|
||||
typename std::enable_if_t<is_compatiblefee_v<OtherFee>>;
|
||||
|
||||
public:
|
||||
TaggedFee() = default;
|
||||
constexpr TaggedFee(TaggedFee const& other) = default;
|
||||
constexpr TaggedFee&
|
||||
operator=(TaggedFee const& other) = default;
|
||||
|
||||
constexpr explicit TaggedFee(beast::Zero) : fee_(0)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr TaggedFee& operator=(beast::Zero)
|
||||
{
|
||||
fee_ = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr explicit TaggedFee(value_type fee) : fee_(fee)
|
||||
{
|
||||
}
|
||||
|
||||
TaggedFee&
|
||||
operator=(value_type fee)
|
||||
{
|
||||
fee_ = fee;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Instances with the same unit, and a type that is
|
||||
"safe" to convert to this one can be converted
|
||||
implicitly */
|
||||
template <
|
||||
class Other,
|
||||
class = std::enable_if_t<
|
||||
is_compatible_v<Other> &&
|
||||
is_safetocasttovalue_v<value_type, Other>>>
|
||||
constexpr TaggedFee(TaggedFee<unit_type, Other> const& fee)
|
||||
: TaggedFee(safe_cast<value_type>(fee.fee()))
|
||||
{
|
||||
}
|
||||
|
||||
constexpr TaggedFee
|
||||
operator*(value_type const& rhs) const
|
||||
{
|
||||
return TaggedFee{fee_ * rhs};
|
||||
}
|
||||
|
||||
friend constexpr TaggedFee
|
||||
operator*(value_type lhs, TaggedFee const& rhs)
|
||||
{
|
||||
// multiplication is commutative
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
constexpr value_type
|
||||
operator/(TaggedFee const& rhs) const
|
||||
{
|
||||
return fee_ / rhs.fee_;
|
||||
}
|
||||
|
||||
TaggedFee&
|
||||
operator+=(TaggedFee const& other)
|
||||
{
|
||||
fee_ += other.fee();
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedFee&
|
||||
operator-=(TaggedFee const& other)
|
||||
{
|
||||
fee_ -= other.fee();
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedFee&
|
||||
operator++()
|
||||
{
|
||||
++fee_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedFee&
|
||||
operator--()
|
||||
{
|
||||
--fee_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedFee&
|
||||
operator*=(value_type const& rhs)
|
||||
{
|
||||
fee_ *= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedFee&
|
||||
operator/=(value_type const& rhs)
|
||||
{
|
||||
fee_ /= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class transparent = value_type>
|
||||
std::enable_if_t<std::is_integral_v<transparent>, TaggedFee&>
|
||||
operator%=(value_type const& rhs)
|
||||
{
|
||||
fee_ %= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedFee
|
||||
operator-() const
|
||||
{
|
||||
static_assert(
|
||||
std::is_signed_v<T>, "- operator illegal on unsigned fee types");
|
||||
return TaggedFee{-fee_};
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(TaggedFee const& other) const
|
||||
{
|
||||
return fee_ == other.fee_;
|
||||
}
|
||||
|
||||
template <class Other, class = enable_if_compatible_t<Other>>
|
||||
bool
|
||||
operator==(TaggedFee<unit_type, Other> const& other) const
|
||||
{
|
||||
return fee_ == other.fee();
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(value_type other) const
|
||||
{
|
||||
return fee_ == other;
|
||||
}
|
||||
|
||||
template <class Other, class = enable_if_compatible_t<Other>>
|
||||
bool
|
||||
operator!=(TaggedFee<unit_type, Other> const& other) const
|
||||
{
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
bool
|
||||
operator<(TaggedFee const& other) const
|
||||
{
|
||||
return fee_ < other.fee_;
|
||||
}
|
||||
|
||||
/** Returns true if the amount is not zero */
|
||||
explicit constexpr operator bool() const noexcept
|
||||
{
|
||||
return fee_ != 0;
|
||||
}
|
||||
|
||||
/** Return the sign of the amount */
|
||||
constexpr int
|
||||
signum() const noexcept
|
||||
{
|
||||
return (fee_ < 0) ? -1 : (fee_ ? 1 : 0);
|
||||
}
|
||||
|
||||
/** Returns the number of drops */
|
||||
constexpr value_type
|
||||
fee() const
|
||||
{
|
||||
return fee_;
|
||||
}
|
||||
|
||||
template <class Other>
|
||||
constexpr double
|
||||
decimalFromReference(TaggedFee<unit_type, Other> reference) const
|
||||
{
|
||||
return static_cast<double>(fee_) / reference.fee();
|
||||
}
|
||||
|
||||
// `is_usable_unit_v` is checked to ensure that only values with
|
||||
// known valid type tags can be converted to JSON. At the time
|
||||
// of implementation, that includes all known tags, but more may
|
||||
// be added in the future.
|
||||
std::enable_if_t<is_usable_unit_v<TaggedFee>, Json::Value>
|
||||
jsonClipped() const
|
||||
{
|
||||
if constexpr (std::is_integral_v<value_type>)
|
||||
{
|
||||
using jsontype = std::conditional_t<
|
||||
std::is_signed_v<value_type>,
|
||||
Json::Int,
|
||||
Json::UInt>;
|
||||
|
||||
constexpr auto min = std::numeric_limits<jsontype>::min();
|
||||
constexpr auto max = std::numeric_limits<jsontype>::max();
|
||||
|
||||
if (fee_ < min)
|
||||
return min;
|
||||
if (fee_ > max)
|
||||
return max;
|
||||
return static_cast<jsontype>(fee_);
|
||||
}
|
||||
else
|
||||
{
|
||||
return fee_;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the underlying value. Code SHOULD NOT call this
|
||||
function unless the type has been abstracted away,
|
||||
e.g. in a templated function.
|
||||
*/
|
||||
constexpr value_type
|
||||
value() const
|
||||
{
|
||||
return fee_;
|
||||
}
|
||||
|
||||
friend std::istream&
|
||||
operator>>(std::istream& s, TaggedFee& val)
|
||||
{
|
||||
s >> val.fee_;
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
// Output Fees as just their numeric value.
|
||||
template <class Char, class Traits, class UnitTag, class T>
|
||||
std::basic_ostream<Char, Traits>&
|
||||
operator<<(std::basic_ostream<Char, Traits>& os, const TaggedFee<UnitTag, T>& q)
|
||||
{
|
||||
return os << q.value();
|
||||
}
|
||||
|
||||
template <class UnitTag, class T>
|
||||
std::string
|
||||
to_string(TaggedFee<UnitTag, T> const& amount)
|
||||
{
|
||||
return std::to_string(amount.fee());
|
||||
}
|
||||
|
||||
template <class Source, class = enable_if_unit_t<Source>>
|
||||
constexpr bool can_muldiv_source_v =
|
||||
std::is_convertible_v<typename Source::value_type, std::uint64_t>;
|
||||
|
||||
template <class Dest, class = enable_if_unit_t<Dest>>
|
||||
constexpr bool can_muldiv_dest_v =
|
||||
can_muldiv_source_v<Dest>&& // Dest is also a source
|
||||
std::is_convertible_v<std::uint64_t, typename Dest::value_type> &&
|
||||
sizeof(typename Dest::value_type) >= sizeof(std::uint64_t);
|
||||
|
||||
template <
|
||||
class Source1,
|
||||
class Source2,
|
||||
class = enable_if_unit_t<Source1>,
|
||||
class = enable_if_unit_t<Source2>>
|
||||
constexpr bool can_muldiv_sources_v =
|
||||
can_muldiv_source_v<Source1>&& can_muldiv_source_v<Source2>&& std::
|
||||
is_same_v<typename Source1::unit_type, typename Source2::unit_type>;
|
||||
|
||||
template <
|
||||
class Source1,
|
||||
class Source2,
|
||||
class Dest,
|
||||
class = enable_if_unit_t<Source1>,
|
||||
class = enable_if_unit_t<Source2>,
|
||||
class = enable_if_unit_t<Dest>>
|
||||
constexpr bool can_muldiv_v =
|
||||
can_muldiv_sources_v<Source1, Source2>&& can_muldiv_dest_v<Dest>;
|
||||
// Source and Dest can be the same by default
|
||||
|
||||
template <
|
||||
class Source1,
|
||||
class Source2,
|
||||
class Dest,
|
||||
class = enable_if_unit_t<Source1>,
|
||||
class = enable_if_unit_t<Source2>,
|
||||
class = enable_if_unit_t<Dest>>
|
||||
constexpr bool can_muldiv_commute_v = can_muldiv_v<Source1, Source2, Dest> &&
|
||||
!std::is_same_v<typename Source1::unit_type, typename Dest::unit_type>;
|
||||
|
||||
template <class T>
|
||||
using enable_muldiv_source_t =
|
||||
typename std::enable_if_t<can_muldiv_source_v<T>>;
|
||||
|
||||
template <class T>
|
||||
using enable_muldiv_dest_t = typename std::enable_if_t<can_muldiv_dest_v<T>>;
|
||||
|
||||
template <class Source1, class Source2>
|
||||
using enable_muldiv_sources_t =
|
||||
typename std::enable_if_t<can_muldiv_sources_v<Source1, Source2>>;
|
||||
|
||||
template <class Source1, class Source2, class Dest>
|
||||
using enable_muldiv_t =
|
||||
typename std::enable_if_t<can_muldiv_v<Source1, Source2, Dest>>;
|
||||
|
||||
template <class Source1, class Source2, class Dest>
|
||||
using enable_muldiv_commute_t =
|
||||
typename std::enable_if_t<can_muldiv_commute_v<Source1, Source2, Dest>>;
|
||||
|
||||
template <class T>
|
||||
TaggedFee<unitlessTag, T>
|
||||
scalar(T value)
|
||||
{
|
||||
return TaggedFee<unitlessTag, T>{value};
|
||||
}
|
||||
|
||||
template <
|
||||
class Source1,
|
||||
class Source2,
|
||||
class Dest,
|
||||
class = enable_muldiv_t<Source1, Source2, Dest>>
|
||||
std::optional<Dest>
|
||||
mulDivU(Source1 value, Dest mul, Source2 div)
|
||||
{
|
||||
// Fees can never be negative in any context.
|
||||
if (value.value() < 0 || mul.value() < 0 || div.value() < 0)
|
||||
{
|
||||
// split the asserts so if one hits, the user can tell which
|
||||
// without a debugger.
|
||||
assert(value.value() >= 0);
|
||||
assert(mul.value() >= 0);
|
||||
assert(div.value() >= 0);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
using desttype = typename Dest::value_type;
|
||||
constexpr auto max = std::numeric_limits<desttype>::max();
|
||||
|
||||
// Shortcuts, since these happen a lot in the real world
|
||||
if (value == div)
|
||||
return mul;
|
||||
if (mul.value() == div.value())
|
||||
{
|
||||
if (value.value() > max)
|
||||
return std::nullopt;
|
||||
return Dest{static_cast<desttype>(value.value())};
|
||||
}
|
||||
|
||||
using namespace boost::multiprecision;
|
||||
|
||||
uint128_t product;
|
||||
product = multiply(
|
||||
product,
|
||||
static_cast<std::uint64_t>(value.value()),
|
||||
static_cast<std::uint64_t>(mul.value()));
|
||||
|
||||
auto quotient = product / div.value();
|
||||
|
||||
if (quotient > max)
|
||||
return std::nullopt;
|
||||
|
||||
return Dest{static_cast<desttype>(quotient)};
|
||||
}
|
||||
|
||||
} // namespace feeunit
|
||||
|
||||
template <class T>
|
||||
using FeeLevel = feeunit::TaggedFee<feeunit::feelevelTag, T>;
|
||||
using FeeLevel64 = FeeLevel<std::uint64_t>;
|
||||
using FeeLevelDouble = FeeLevel<double>;
|
||||
|
||||
template <
|
||||
class Source1,
|
||||
class Source2,
|
||||
class Dest,
|
||||
class = feeunit::enable_muldiv_t<Source1, Source2, Dest>>
|
||||
std::optional<Dest>
|
||||
mulDiv(Source1 value, Dest mul, Source2 div)
|
||||
{
|
||||
return feeunit::mulDivU(value, mul, div);
|
||||
}
|
||||
|
||||
template <
|
||||
class Source1,
|
||||
class Source2,
|
||||
class Dest,
|
||||
class = feeunit::enable_muldiv_commute_t<Source1, Source2, Dest>>
|
||||
std::optional<Dest>
|
||||
mulDiv(Dest value, Source1 mul, Source2 div)
|
||||
{
|
||||
// Multiplication is commutative
|
||||
return feeunit::mulDivU(mul, value, div);
|
||||
}
|
||||
|
||||
template <class Dest, class = feeunit::enable_muldiv_dest_t<Dest>>
|
||||
std::optional<Dest>
|
||||
mulDiv(std::uint64_t value, Dest mul, std::uint64_t div)
|
||||
{
|
||||
// Give the scalars a non-tag so the
|
||||
// unit-handling version gets called.
|
||||
return feeunit::mulDivU(feeunit::scalar(value), mul, feeunit::scalar(div));
|
||||
}
|
||||
|
||||
template <class Dest, class = feeunit::enable_muldiv_dest_t<Dest>>
|
||||
std::optional<Dest>
|
||||
mulDiv(Dest value, std::uint64_t mul, std::uint64_t div)
|
||||
{
|
||||
// Multiplication is commutative
|
||||
return mulDiv(mul, value, div);
|
||||
}
|
||||
|
||||
template <
|
||||
class Source1,
|
||||
class Source2,
|
||||
class = feeunit::enable_muldiv_sources_t<Source1, Source2>>
|
||||
std::optional<std::uint64_t>
|
||||
mulDiv(Source1 value, std::uint64_t mul, Source2 div)
|
||||
{
|
||||
// Give the scalars a dimensionless unit so the
|
||||
// unit-handling version gets called.
|
||||
auto unitresult = feeunit::mulDivU(value, feeunit::scalar(mul), div);
|
||||
|
||||
if (!unitresult)
|
||||
return std::nullopt;
|
||||
|
||||
return unitresult->value();
|
||||
}
|
||||
|
||||
template <
|
||||
class Source1,
|
||||
class Source2,
|
||||
class = feeunit::enable_muldiv_sources_t<Source1, Source2>>
|
||||
std::optional<std::uint64_t>
|
||||
mulDiv(std::uint64_t value, Source1 mul, Source2 div)
|
||||
{
|
||||
// Multiplication is commutative
|
||||
return mulDiv(mul, value, div);
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
constexpr std::enable_if_t<
|
||||
std::is_same_v<typename Dest::unit_type, typename Src::unit_type> &&
|
||||
std::is_integral_v<typename Dest::value_type> &&
|
||||
std::is_integral_v<typename Src::value_type>,
|
||||
Dest>
|
||||
safe_cast(Src s) noexcept
|
||||
{
|
||||
// Dest may not have an explicit value constructor
|
||||
return Dest{safe_cast<typename Dest::value_type>(s.value())};
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
constexpr std::enable_if_t<
|
||||
std::is_same_v<typename Dest::unit_type, typename Src::unit_type> &&
|
||||
std::is_integral_v<typename Dest::value_type> &&
|
||||
std::is_integral_v<typename Src::value_type>,
|
||||
Dest>
|
||||
unsafe_cast(Src s) noexcept
|
||||
{
|
||||
// Dest may not have an explicit value constructor
|
||||
return Dest{unsafe_cast<typename Dest::value_type>(s.value())};
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif // BASICS_FEES_H_INCLUDED
|
||||
44
include/xrpl/basics/FileUtilities.h
Normal file
44
include/xrpl/basics/FileUtilities.h
Normal file
@@ -0,0 +1,44 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2018 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_FILEUTILITIES_H_INCLUDED
|
||||
#define RIPPLE_BASICS_FILEUTILITIES_H_INCLUDED
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
std::string
|
||||
getFileContents(
|
||||
boost::system::error_code& ec,
|
||||
boost::filesystem::path const& sourcePath,
|
||||
std::optional<std::size_t> maxSize = std::nullopt);
|
||||
|
||||
void
|
||||
writeFileContents(
|
||||
boost::system::error_code& ec,
|
||||
boost::filesystem::path const& destPath,
|
||||
std::string const& contents);
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
223
include/xrpl/basics/IOUAmount.h
Normal file
223
include/xrpl/basics/IOUAmount.h
Normal file
@@ -0,0 +1,223 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_IOUAMOUNT_H_INCLUDED
|
||||
#define RIPPLE_BASICS_IOUAMOUNT_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/LocalValue.h>
|
||||
#include <ripple/basics/Number.h>
|
||||
#include <ripple/beast/utility/Zero.h>
|
||||
#include <boost/operators.hpp>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** Floating point representation of amounts with high dynamic range
|
||||
|
||||
Amounts are stored as a normalized signed mantissa and an exponent. The
|
||||
range of the normalized exponent is [-96,80] and the range of the absolute
|
||||
value of the normalized mantissa is [1000000000000000, 9999999999999999].
|
||||
|
||||
Arithmetic operations can throw std::overflow_error during normalization
|
||||
if the amount exceeds the largest representable amount, but underflows
|
||||
will silently trunctate to zero.
|
||||
*/
|
||||
class IOUAmount : private boost::totally_ordered<IOUAmount>,
|
||||
private boost::additive<IOUAmount>
|
||||
{
|
||||
private:
|
||||
std::int64_t mantissa_;
|
||||
int exponent_;
|
||||
|
||||
/** Adjusts the mantissa and exponent to the proper range.
|
||||
|
||||
This can throw if the amount cannot be normalized, or is larger than
|
||||
the largest value that can be represented as an IOU amount. Amounts
|
||||
that are too small to be represented normalize to 0.
|
||||
*/
|
||||
void
|
||||
normalize();
|
||||
|
||||
public:
|
||||
IOUAmount() = default;
|
||||
explicit IOUAmount(Number const& other);
|
||||
IOUAmount(beast::Zero);
|
||||
IOUAmount(std::int64_t mantissa, int exponent);
|
||||
|
||||
IOUAmount& operator=(beast::Zero);
|
||||
|
||||
operator Number() const;
|
||||
|
||||
IOUAmount&
|
||||
operator+=(IOUAmount const& other);
|
||||
|
||||
IOUAmount&
|
||||
operator-=(IOUAmount const& other);
|
||||
|
||||
IOUAmount
|
||||
operator-() const;
|
||||
|
||||
bool
|
||||
operator==(IOUAmount const& other) const;
|
||||
|
||||
bool
|
||||
operator<(IOUAmount const& other) const;
|
||||
|
||||
/** Returns true if the amount is not zero */
|
||||
explicit operator bool() const noexcept;
|
||||
|
||||
/** Return the sign of the amount */
|
||||
int
|
||||
signum() const noexcept;
|
||||
|
||||
int
|
||||
exponent() const noexcept;
|
||||
|
||||
std::int64_t
|
||||
mantissa() const noexcept;
|
||||
|
||||
static IOUAmount
|
||||
minPositiveAmount();
|
||||
};
|
||||
|
||||
inline IOUAmount::IOUAmount(beast::Zero)
|
||||
{
|
||||
*this = beast::zero;
|
||||
}
|
||||
|
||||
inline IOUAmount::IOUAmount(std::int64_t mantissa, int exponent)
|
||||
: mantissa_(mantissa), exponent_(exponent)
|
||||
{
|
||||
normalize();
|
||||
}
|
||||
|
||||
inline IOUAmount& IOUAmount::operator=(beast::Zero)
|
||||
{
|
||||
// The -100 is used to allow 0 to sort less than small positive values
|
||||
// which will have a large negative exponent.
|
||||
mantissa_ = 0;
|
||||
exponent_ = -100;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline IOUAmount::operator Number() const
|
||||
{
|
||||
return Number{mantissa_, exponent_};
|
||||
}
|
||||
|
||||
inline IOUAmount&
|
||||
IOUAmount::operator-=(IOUAmount const& other)
|
||||
{
|
||||
*this += -other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline IOUAmount
|
||||
IOUAmount::operator-() const
|
||||
{
|
||||
return {-mantissa_, exponent_};
|
||||
}
|
||||
|
||||
inline bool
|
||||
IOUAmount::operator==(IOUAmount const& other) const
|
||||
{
|
||||
return exponent_ == other.exponent_ && mantissa_ == other.mantissa_;
|
||||
}
|
||||
|
||||
inline bool
|
||||
IOUAmount::operator<(IOUAmount const& other) const
|
||||
{
|
||||
return Number{*this} < Number{other};
|
||||
}
|
||||
|
||||
inline IOUAmount::operator bool() const noexcept
|
||||
{
|
||||
return mantissa_ != 0;
|
||||
}
|
||||
|
||||
inline int
|
||||
IOUAmount::signum() const noexcept
|
||||
{
|
||||
return (mantissa_ < 0) ? -1 : (mantissa_ ? 1 : 0);
|
||||
}
|
||||
|
||||
inline int
|
||||
IOUAmount::exponent() const noexcept
|
||||
{
|
||||
return exponent_;
|
||||
}
|
||||
|
||||
inline std::int64_t
|
||||
IOUAmount::mantissa() const noexcept
|
||||
{
|
||||
return mantissa_;
|
||||
}
|
||||
|
||||
std::string
|
||||
to_string(IOUAmount const& amount);
|
||||
|
||||
/* Return num*amt/den
|
||||
This function keeps more precision than computing
|
||||
num*amt, storing the result in an IOUAmount, then
|
||||
dividing by den.
|
||||
*/
|
||||
IOUAmount
|
||||
mulRatio(
|
||||
IOUAmount const& amt,
|
||||
std::uint32_t num,
|
||||
std::uint32_t den,
|
||||
bool roundUp);
|
||||
|
||||
// Since many uses of the number class do not have access to a ledger,
|
||||
// getSTNumberSwitchover needs to be globally accessible.
|
||||
|
||||
bool
|
||||
getSTNumberSwitchover();
|
||||
|
||||
void
|
||||
setSTNumberSwitchover(bool v);
|
||||
|
||||
/** RAII class to set and restore the Number switchover.
|
||||
*/
|
||||
|
||||
class NumberSO
|
||||
{
|
||||
bool saved_;
|
||||
|
||||
public:
|
||||
~NumberSO()
|
||||
{
|
||||
setSTNumberSwitchover(saved_);
|
||||
}
|
||||
|
||||
NumberSO(NumberSO const&) = delete;
|
||||
NumberSO&
|
||||
operator=(NumberSO const&) = delete;
|
||||
|
||||
explicit NumberSO(bool v) : saved_(getSTNumberSwitchover())
|
||||
{
|
||||
setSTNumberSwitchover(v);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
32
include/xrpl/basics/KeyCache.h
Normal file
32
include/xrpl/basics/KeyCache.h
Normal file
@@ -0,0 +1,32 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2021 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_KEYCACHE_H
|
||||
#define RIPPLE_BASICS_KEYCACHE_H
|
||||
|
||||
#include <ripple/basics/TaggedCache.h>
|
||||
#include <ripple/basics/base_uint.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
using KeyCache = TaggedCache<uint256, int, true>;
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif // RIPPLE_BASICS_KEYCACHE_H
|
||||
132
include/xrpl/basics/LocalValue.h
Normal file
132
include/xrpl/basics/LocalValue.h
Normal file
@@ -0,0 +1,132 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_LOCALVALUE_H_INCLUDED
|
||||
#define RIPPLE_BASICS_LOCALVALUE_H_INCLUDED
|
||||
|
||||
#include <boost/thread/tss.hpp>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct LocalValues
|
||||
{
|
||||
explicit LocalValues() = default;
|
||||
|
||||
bool onCoro = true;
|
||||
|
||||
struct BasicValue
|
||||
{
|
||||
virtual ~BasicValue() = default;
|
||||
virtual void*
|
||||
get() = 0;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct Value : BasicValue
|
||||
{
|
||||
T t_;
|
||||
|
||||
Value() = default;
|
||||
explicit Value(T const& t) : t_(t)
|
||||
{
|
||||
}
|
||||
|
||||
void*
|
||||
get() override
|
||||
{
|
||||
return &t_;
|
||||
}
|
||||
};
|
||||
|
||||
// Keys are the address of a LocalValue.
|
||||
std::unordered_map<void const*, std::unique_ptr<BasicValue>> values;
|
||||
|
||||
static inline void
|
||||
cleanup(LocalValues* lvs)
|
||||
{
|
||||
if (lvs && !lvs->onCoro)
|
||||
delete lvs;
|
||||
}
|
||||
};
|
||||
|
||||
template <class = void>
|
||||
boost::thread_specific_ptr<detail::LocalValues>&
|
||||
getLocalValues()
|
||||
{
|
||||
static boost::thread_specific_ptr<detail::LocalValues> tsp(
|
||||
&detail::LocalValues::cleanup);
|
||||
return tsp;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class T>
|
||||
class LocalValue
|
||||
{
|
||||
public:
|
||||
template <class... Args>
|
||||
LocalValue(Args&&... args) : t_(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
/** Stores instance of T specific to the calling coroutine or thread. */
|
||||
T&
|
||||
operator*();
|
||||
|
||||
/** Stores instance of T specific to the calling coroutine or thread. */
|
||||
T*
|
||||
operator->()
|
||||
{
|
||||
return &**this;
|
||||
}
|
||||
|
||||
private:
|
||||
T t_;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
T&
|
||||
LocalValue<T>::operator*()
|
||||
{
|
||||
auto lvs = detail::getLocalValues().get();
|
||||
if (!lvs)
|
||||
{
|
||||
lvs = new detail::LocalValues();
|
||||
lvs->onCoro = false;
|
||||
detail::getLocalValues().reset(lvs);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const iter = lvs->values.find(this);
|
||||
if (iter != lvs->values.end())
|
||||
return *reinterpret_cast<T*>(iter->second->get());
|
||||
}
|
||||
|
||||
return *reinterpret_cast<T*>(
|
||||
lvs->values
|
||||
.emplace(this, std::make_unique<detail::LocalValues::Value<T>>(t_))
|
||||
.first->second->get());
|
||||
}
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
280
include/xrpl/basics/Log.h
Normal file
280
include/xrpl/basics/Log.h
Normal file
@@ -0,0 +1,280 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_LOG_H_INCLUDED
|
||||
#define RIPPLE_BASICS_LOG_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/UnorderedContainers.h>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
#include <boost/beast/core/string.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
// DEPRECATED use beast::severities::Severity instead
|
||||
enum LogSeverity {
|
||||
lsINVALID = -1, // used to indicate an invalid severity
|
||||
lsTRACE = 0, // Very low-level progress information, details inside
|
||||
// an operation
|
||||
lsDEBUG = 1, // Function-level progress information, operations
|
||||
lsINFO = 2, // Server-level progress information, major operations
|
||||
lsWARNING = 3, // Conditions that warrant human attention, may indicate
|
||||
// a problem
|
||||
lsERROR = 4, // A condition that indicates a problem
|
||||
lsFATAL = 5 // A severe condition that indicates a server problem
|
||||
};
|
||||
|
||||
/** Manages partitions for logging. */
|
||||
class Logs
|
||||
{
|
||||
private:
|
||||
class Sink : public beast::Journal::Sink
|
||||
{
|
||||
private:
|
||||
Logs& logs_;
|
||||
std::string partition_;
|
||||
|
||||
public:
|
||||
Sink(
|
||||
std::string const& partition,
|
||||
beast::severities::Severity thresh,
|
||||
Logs& logs);
|
||||
|
||||
Sink(Sink const&) = delete;
|
||||
Sink&
|
||||
operator=(Sink const&) = delete;
|
||||
|
||||
void
|
||||
write(beast::severities::Severity level, std::string const& text)
|
||||
override;
|
||||
};
|
||||
|
||||
/** Manages a system file containing logged output.
|
||||
The system file remains open during program execution. Interfaces
|
||||
are provided for interoperating with standard log management
|
||||
tools like logrotate(8):
|
||||
http://linuxcommand.org/man_pages/logrotate8.html
|
||||
@note None of the listed interfaces are thread-safe.
|
||||
*/
|
||||
class File
|
||||
{
|
||||
public:
|
||||
/** Construct with no associated system file.
|
||||
A system file may be associated later with @ref open.
|
||||
@see open
|
||||
*/
|
||||
File();
|
||||
|
||||
/** Destroy the object.
|
||||
If a system file is associated, it will be flushed and closed.
|
||||
*/
|
||||
~File() = default;
|
||||
|
||||
/** Determine if a system file is associated with the log.
|
||||
@return `true` if a system file is associated and opened for
|
||||
writing.
|
||||
*/
|
||||
bool
|
||||
isOpen() const noexcept;
|
||||
|
||||
/** Associate a system file with the log.
|
||||
If the file does not exist an attempt is made to create it
|
||||
and open it for writing. If the file already exists an attempt is
|
||||
made to open it for appending.
|
||||
If a system file is already associated with the log, it is closed
|
||||
first.
|
||||
@return `true` if the file was opened.
|
||||
*/
|
||||
bool
|
||||
open(boost::filesystem::path const& path);
|
||||
|
||||
/** Close and re-open the system file associated with the log
|
||||
This assists in interoperating with external log management tools.
|
||||
@return `true` if the file was opened.
|
||||
*/
|
||||
bool
|
||||
closeAndReopen();
|
||||
|
||||
/** Close the system file if it is open. */
|
||||
void
|
||||
close();
|
||||
|
||||
/** write to the log file.
|
||||
Does nothing if there is no associated system file.
|
||||
*/
|
||||
void
|
||||
write(char const* text);
|
||||
|
||||
/** write to the log file and append an end of line marker.
|
||||
Does nothing if there is no associated system file.
|
||||
*/
|
||||
void
|
||||
writeln(char const* text);
|
||||
|
||||
/** Write to the log file using std::string. */
|
||||
/** @{ */
|
||||
void
|
||||
write(std::string const& str)
|
||||
{
|
||||
write(str.c_str());
|
||||
}
|
||||
|
||||
void
|
||||
writeln(std::string const& str)
|
||||
{
|
||||
writeln(str.c_str());
|
||||
}
|
||||
/** @} */
|
||||
|
||||
private:
|
||||
std::unique_ptr<std::ofstream> m_stream;
|
||||
boost::filesystem::path m_path;
|
||||
};
|
||||
|
||||
std::mutex mutable mutex_;
|
||||
std::map<
|
||||
std::string,
|
||||
std::unique_ptr<beast::Journal::Sink>,
|
||||
boost::beast::iless>
|
||||
sinks_;
|
||||
beast::severities::Severity thresh_;
|
||||
File file_;
|
||||
bool silent_ = false;
|
||||
|
||||
public:
|
||||
Logs(beast::severities::Severity level);
|
||||
|
||||
Logs(Logs const&) = delete;
|
||||
Logs&
|
||||
operator=(Logs const&) = delete;
|
||||
|
||||
virtual ~Logs() = default;
|
||||
|
||||
bool
|
||||
open(boost::filesystem::path const& pathToLogFile);
|
||||
|
||||
beast::Journal::Sink&
|
||||
get(std::string const& name);
|
||||
|
||||
beast::Journal::Sink&
|
||||
operator[](std::string const& name);
|
||||
|
||||
beast::Journal
|
||||
journal(std::string const& name);
|
||||
|
||||
beast::severities::Severity
|
||||
threshold() const;
|
||||
|
||||
void
|
||||
threshold(beast::severities::Severity thresh);
|
||||
|
||||
std::vector<std::pair<std::string, std::string>>
|
||||
partition_severities() const;
|
||||
|
||||
void
|
||||
write(
|
||||
beast::severities::Severity level,
|
||||
std::string const& partition,
|
||||
std::string const& text,
|
||||
bool console);
|
||||
|
||||
std::string
|
||||
rotate();
|
||||
|
||||
/**
|
||||
* Set flag to write logs to stderr (false) or not (true).
|
||||
*
|
||||
* @param bSilent Set flag accordingly.
|
||||
*/
|
||||
void
|
||||
silent(bool bSilent)
|
||||
{
|
||||
silent_ = bSilent;
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<beast::Journal::Sink>
|
||||
makeSink(
|
||||
std::string const& partition,
|
||||
beast::severities::Severity startingLevel);
|
||||
|
||||
public:
|
||||
static LogSeverity
|
||||
fromSeverity(beast::severities::Severity level);
|
||||
|
||||
static beast::severities::Severity
|
||||
toSeverity(LogSeverity level);
|
||||
|
||||
static std::string
|
||||
toString(LogSeverity s);
|
||||
|
||||
static LogSeverity
|
||||
fromString(std::string const& s);
|
||||
|
||||
private:
|
||||
enum {
|
||||
// Maximum line length for log messages.
|
||||
// If the message exceeds this length it will be truncated with elipses.
|
||||
maximumMessageCharacters = 12 * 1024
|
||||
};
|
||||
|
||||
static void
|
||||
format(
|
||||
std::string& output,
|
||||
std::string const& message,
|
||||
beast::severities::Severity severity,
|
||||
std::string const& partition);
|
||||
};
|
||||
|
||||
// Wraps a Journal::Stream to skip evaluation of
|
||||
// expensive argument lists if the stream is not active.
|
||||
#ifndef JLOG
|
||||
#define JLOG(x) \
|
||||
if (!x) \
|
||||
{ \
|
||||
} \
|
||||
else \
|
||||
x
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Debug logging:
|
||||
|
||||
/** Set the sink for the debug journal.
|
||||
|
||||
@param sink unique_ptr to new debug Sink.
|
||||
@return unique_ptr to the previous Sink. nullptr if there was no Sink.
|
||||
*/
|
||||
std::unique_ptr<beast::Journal::Sink>
|
||||
setDebugLogSink(std::unique_ptr<beast::Journal::Sink> sink);
|
||||
|
||||
/** Returns a debug journal.
|
||||
The journal may drain to a null sink, so its output
|
||||
may never be seen. Never use it for critical
|
||||
information.
|
||||
*/
|
||||
beast::Journal
|
||||
debugLog();
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
68
include/xrpl/basics/MathUtilities.h
Normal file
68
include/xrpl/basics/MathUtilities.h
Normal file
@@ -0,0 +1,68 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2020 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_MATHUTILITIES_H_INCLUDED
|
||||
#define RIPPLE_BASICS_MATHUTILITIES_H_INCLUDED
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** Calculate one number divided by another number in percentage.
|
||||
* The result is rounded up to the next integer, and capped in the range [0,100]
|
||||
* E.g. calculatePercent(1, 100) = 1 because 1/100 = 0.010000
|
||||
* calculatePercent(1, 99) = 2 because 1/99 = 0.010101
|
||||
* calculatePercent(0, 100) = 0
|
||||
* calculatePercent(100, 100) = 100
|
||||
* calculatePercent(200, 100) = 100 because the result is capped to 100
|
||||
*
|
||||
* @param count dividend
|
||||
* @param total divisor
|
||||
* @return the percentage, in [0, 100]
|
||||
*
|
||||
* @note total cannot be zero.
|
||||
* */
|
||||
constexpr std::size_t
|
||||
calculatePercent(std::size_t count, std::size_t total)
|
||||
{
|
||||
assert(total != 0);
|
||||
return ((std::min(count, total) * 100) + total - 1) / total;
|
||||
}
|
||||
|
||||
// unit tests
|
||||
static_assert(calculatePercent(1, 2) == 50);
|
||||
static_assert(calculatePercent(0, 100) == 0);
|
||||
static_assert(calculatePercent(100, 100) == 100);
|
||||
static_assert(calculatePercent(200, 100) == 100);
|
||||
static_assert(calculatePercent(1, 100) == 1);
|
||||
static_assert(calculatePercent(1, 99) == 2);
|
||||
static_assert(calculatePercent(6, 14) == 43);
|
||||
static_assert(calculatePercent(29, 33) == 88);
|
||||
static_assert(calculatePercent(1, 64) == 2);
|
||||
static_assert(calculatePercent(0, 100'000'000) == 0);
|
||||
static_assert(calculatePercent(1, 100'000'000) == 1);
|
||||
static_assert(calculatePercent(50'000'000, 100'000'000) == 50);
|
||||
static_assert(calculatePercent(50'000'001, 100'000'000) == 51);
|
||||
static_assert(calculatePercent(99'999'999, 100'000'000) == 100);
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
412
include/xrpl/basics/Number.h
Normal file
412
include/xrpl/basics/Number.h
Normal file
@@ -0,0 +1,412 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2022 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_NUMBER_H_INCLUDED
|
||||
#define RIPPLE_BASICS_NUMBER_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/XRPAmount.h>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class Number;
|
||||
|
||||
std::string
|
||||
to_string(Number const& amount);
|
||||
|
||||
class Number
|
||||
{
|
||||
using rep = std::int64_t;
|
||||
rep mantissa_{0};
|
||||
int exponent_{std::numeric_limits<int>::lowest()};
|
||||
|
||||
public:
|
||||
struct unchecked
|
||||
{
|
||||
explicit unchecked() = default;
|
||||
};
|
||||
|
||||
explicit constexpr Number() = default;
|
||||
|
||||
Number(rep mantissa);
|
||||
explicit Number(rep mantissa, int exponent);
|
||||
explicit constexpr Number(rep mantissa, int exponent, unchecked) noexcept;
|
||||
|
||||
Number(XRPAmount const& x);
|
||||
|
||||
constexpr rep
|
||||
mantissa() const noexcept;
|
||||
constexpr int
|
||||
exponent() const noexcept;
|
||||
|
||||
constexpr Number
|
||||
operator+() const noexcept;
|
||||
constexpr Number
|
||||
operator-() const noexcept;
|
||||
Number&
|
||||
operator++();
|
||||
Number
|
||||
operator++(int);
|
||||
Number&
|
||||
operator--();
|
||||
Number
|
||||
operator--(int);
|
||||
|
||||
Number&
|
||||
operator+=(Number const& x);
|
||||
Number&
|
||||
operator-=(Number const& x);
|
||||
|
||||
Number&
|
||||
operator*=(Number const& x);
|
||||
Number&
|
||||
operator/=(Number const& x);
|
||||
|
||||
static constexpr Number
|
||||
min() noexcept;
|
||||
static constexpr Number
|
||||
max() noexcept;
|
||||
static constexpr Number
|
||||
lowest() noexcept;
|
||||
|
||||
explicit operator XRPAmount() const; // round to nearest, even on tie
|
||||
explicit operator rep() const; // round to nearest, even on tie
|
||||
|
||||
friend constexpr bool
|
||||
operator==(Number const& x, Number const& y) noexcept
|
||||
{
|
||||
return x.mantissa_ == y.mantissa_ && x.exponent_ == y.exponent_;
|
||||
}
|
||||
|
||||
friend constexpr bool
|
||||
operator!=(Number const& x, Number const& y) noexcept
|
||||
{
|
||||
return !(x == y);
|
||||
}
|
||||
|
||||
friend constexpr bool
|
||||
operator<(Number const& x, Number const& y) noexcept
|
||||
{
|
||||
// If the two amounts have different signs (zero is treated as positive)
|
||||
// then the comparison is true iff the left is negative.
|
||||
bool const lneg = x.mantissa_ < 0;
|
||||
bool const rneg = y.mantissa_ < 0;
|
||||
|
||||
if (lneg != rneg)
|
||||
return lneg;
|
||||
|
||||
// Both have same sign and the left is zero: the right must be
|
||||
// greater than 0.
|
||||
if (x.mantissa_ == 0)
|
||||
return y.mantissa_ > 0;
|
||||
|
||||
// Both have same sign, the right is zero and the left is non-zero.
|
||||
if (y.mantissa_ == 0)
|
||||
return false;
|
||||
|
||||
// Both have the same sign, compare by exponents:
|
||||
if (x.exponent_ > y.exponent_)
|
||||
return lneg;
|
||||
if (x.exponent_ < y.exponent_)
|
||||
return !lneg;
|
||||
|
||||
// If equal exponents, compare mantissas
|
||||
return x.mantissa_ < y.mantissa_;
|
||||
}
|
||||
|
||||
/** Return the sign of the amount */
|
||||
constexpr int
|
||||
signum() const noexcept
|
||||
{
|
||||
return (mantissa_ < 0) ? -1 : (mantissa_ ? 1 : 0);
|
||||
}
|
||||
|
||||
friend constexpr bool
|
||||
operator>(Number const& x, Number const& y) noexcept
|
||||
{
|
||||
return y < x;
|
||||
}
|
||||
|
||||
friend constexpr bool
|
||||
operator<=(Number const& x, Number const& y) noexcept
|
||||
{
|
||||
return !(y < x);
|
||||
}
|
||||
|
||||
friend constexpr bool
|
||||
operator>=(Number const& x, Number const& y) noexcept
|
||||
{
|
||||
return !(x < y);
|
||||
}
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& os, Number const& x)
|
||||
{
|
||||
return os << to_string(x);
|
||||
}
|
||||
|
||||
// Thread local rounding control. Default is to_nearest
|
||||
enum rounding_mode { to_nearest, towards_zero, downward, upward };
|
||||
static rounding_mode
|
||||
getround();
|
||||
// Returns previously set mode
|
||||
static rounding_mode
|
||||
setround(rounding_mode mode);
|
||||
|
||||
private:
|
||||
static thread_local rounding_mode mode_;
|
||||
|
||||
void
|
||||
normalize();
|
||||
constexpr bool
|
||||
isnormal() const noexcept;
|
||||
|
||||
// The range for the mantissa when normalized
|
||||
constexpr static std::int64_t minMantissa = 1'000'000'000'000'000LL;
|
||||
constexpr static std::int64_t maxMantissa = 9'999'999'999'999'999LL;
|
||||
|
||||
// The range for the exponent when normalized
|
||||
constexpr static int minExponent = -32768;
|
||||
constexpr static int maxExponent = 32768;
|
||||
|
||||
class Guard;
|
||||
};
|
||||
|
||||
inline constexpr Number::Number(rep mantissa, int exponent, unchecked) noexcept
|
||||
: mantissa_{mantissa}, exponent_{exponent}
|
||||
{
|
||||
}
|
||||
|
||||
inline Number::Number(rep mantissa, int exponent)
|
||||
: mantissa_{mantissa}, exponent_{exponent}
|
||||
{
|
||||
normalize();
|
||||
}
|
||||
|
||||
inline Number::Number(rep mantissa) : Number{mantissa, 0}
|
||||
{
|
||||
}
|
||||
|
||||
inline Number::Number(XRPAmount const& x) : Number{x.drops()}
|
||||
{
|
||||
}
|
||||
|
||||
inline constexpr Number::rep
|
||||
Number::mantissa() const noexcept
|
||||
{
|
||||
return mantissa_;
|
||||
}
|
||||
|
||||
inline constexpr int
|
||||
Number::exponent() const noexcept
|
||||
{
|
||||
return exponent_;
|
||||
}
|
||||
|
||||
inline constexpr Number
|
||||
Number::operator+() const noexcept
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline constexpr Number
|
||||
Number::operator-() const noexcept
|
||||
{
|
||||
auto x = *this;
|
||||
x.mantissa_ = -x.mantissa_;
|
||||
return x;
|
||||
}
|
||||
|
||||
inline Number&
|
||||
Number::operator++()
|
||||
{
|
||||
*this += Number{1000000000000000, -15, unchecked{}};
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Number
|
||||
Number::operator++(int)
|
||||
{
|
||||
auto x = *this;
|
||||
++(*this);
|
||||
return x;
|
||||
}
|
||||
|
||||
inline Number&
|
||||
Number::operator--()
|
||||
{
|
||||
*this -= Number{1000000000000000, -15, unchecked{}};
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Number
|
||||
Number::operator--(int)
|
||||
{
|
||||
auto x = *this;
|
||||
--(*this);
|
||||
return x;
|
||||
}
|
||||
|
||||
inline Number&
|
||||
Number::operator-=(Number const& x)
|
||||
{
|
||||
return *this += -x;
|
||||
}
|
||||
|
||||
inline Number
|
||||
operator+(Number const& x, Number const& y)
|
||||
{
|
||||
auto z = x;
|
||||
z += y;
|
||||
return z;
|
||||
}
|
||||
|
||||
inline Number
|
||||
operator-(Number const& x, Number const& y)
|
||||
{
|
||||
auto z = x;
|
||||
z -= y;
|
||||
return z;
|
||||
}
|
||||
|
||||
inline Number
|
||||
operator*(Number const& x, Number const& y)
|
||||
{
|
||||
auto z = x;
|
||||
z *= y;
|
||||
return z;
|
||||
}
|
||||
|
||||
inline Number
|
||||
operator/(Number const& x, Number const& y)
|
||||
{
|
||||
auto z = x;
|
||||
z /= y;
|
||||
return z;
|
||||
}
|
||||
|
||||
inline constexpr Number
|
||||
Number::min() noexcept
|
||||
{
|
||||
return Number{minMantissa, minExponent, unchecked{}};
|
||||
}
|
||||
|
||||
inline constexpr Number
|
||||
Number::max() noexcept
|
||||
{
|
||||
return Number{maxMantissa, maxExponent, unchecked{}};
|
||||
}
|
||||
|
||||
inline constexpr Number
|
||||
Number::lowest() noexcept
|
||||
{
|
||||
return -Number{maxMantissa, maxExponent, unchecked{}};
|
||||
}
|
||||
|
||||
inline constexpr bool
|
||||
Number::isnormal() const noexcept
|
||||
{
|
||||
auto const abs_m = mantissa_ < 0 ? -mantissa_ : mantissa_;
|
||||
return minMantissa <= abs_m && abs_m <= maxMantissa &&
|
||||
minExponent <= exponent_ && exponent_ <= maxExponent;
|
||||
}
|
||||
|
||||
inline constexpr Number
|
||||
abs(Number x) noexcept
|
||||
{
|
||||
if (x < Number{})
|
||||
x = -x;
|
||||
return x;
|
||||
}
|
||||
|
||||
// Returns f^n
|
||||
// Uses a log_2(n) number of multiplications
|
||||
|
||||
Number
|
||||
power(Number const& f, unsigned n);
|
||||
|
||||
// Returns f^(1/d)
|
||||
// Uses Newton–Raphson iterations until the result stops changing
|
||||
// to find the root of the polynomial g(x) = x^d - f
|
||||
|
||||
Number
|
||||
root(Number f, unsigned d);
|
||||
|
||||
Number
|
||||
root2(Number f);
|
||||
|
||||
// Returns f^(n/d)
|
||||
|
||||
Number
|
||||
power(Number const& f, unsigned n, unsigned d);
|
||||
|
||||
// Return 0 if abs(x) < limit, else returns x
|
||||
|
||||
inline constexpr Number
|
||||
squelch(Number const& x, Number const& limit) noexcept
|
||||
{
|
||||
if (abs(x) < limit)
|
||||
return Number{};
|
||||
return x;
|
||||
}
|
||||
|
||||
class saveNumberRoundMode
|
||||
{
|
||||
Number::rounding_mode mode_;
|
||||
|
||||
public:
|
||||
~saveNumberRoundMode()
|
||||
{
|
||||
Number::setround(mode_);
|
||||
}
|
||||
explicit saveNumberRoundMode(Number::rounding_mode mode) noexcept
|
||||
: mode_{mode}
|
||||
{
|
||||
}
|
||||
saveNumberRoundMode(saveNumberRoundMode const&) = delete;
|
||||
saveNumberRoundMode&
|
||||
operator=(saveNumberRoundMode const&) = delete;
|
||||
};
|
||||
|
||||
// saveNumberRoundMode doesn't do quite enough for us. What we want is a
|
||||
// Number::RoundModeGuard that sets the new mode and restores the old mode
|
||||
// when it leaves scope. Since Number doesn't have that facility, we'll
|
||||
// build it here.
|
||||
class NumberRoundModeGuard
|
||||
{
|
||||
saveNumberRoundMode saved_;
|
||||
|
||||
public:
|
||||
explicit NumberRoundModeGuard(Number::rounding_mode mode) noexcept
|
||||
: saved_{Number::setround(mode)}
|
||||
{
|
||||
}
|
||||
|
||||
NumberRoundModeGuard(NumberRoundModeGuard const&) = delete;
|
||||
|
||||
NumberRoundModeGuard&
|
||||
operator=(NumberRoundModeGuard const&) = delete;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif // RIPPLE_BASICS_NUMBER_H_INCLUDED
|
||||
40
include/xrpl/basics/README.md
Normal file
40
include/xrpl/basics/README.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Basics
|
||||
|
||||
Utility functions and classes.
|
||||
|
||||
ripple/basic should contain no dependencies on other modules.
|
||||
|
||||
|
||||
Choosing a rippled container.
|
||||
=============================
|
||||
|
||||
* `std::vector`
|
||||
* For ordered containers with most insertions or erases at the end.
|
||||
|
||||
* `std::deque`
|
||||
* For ordered containers with most insertions or erases at the start or end.
|
||||
|
||||
* `std::list`
|
||||
* For ordered containers with inserts and erases to the middle.
|
||||
* For containers with iterators stable over insert and erase.
|
||||
* Generally slower and bigger than `std::vector` or `std::deque` except for
|
||||
those cases.
|
||||
|
||||
* `std::set`
|
||||
* For sorted containers.
|
||||
|
||||
* `ripple::hash_set`
|
||||
* Where inserts and contains need to be O(1).
|
||||
* For "small" sets, `std::set` might be faster and smaller.
|
||||
|
||||
* `ripple::hardened_hash_set`
|
||||
* For data sets where the key could be manipulated by an attacker
|
||||
in an attempt to mount an algorithmic complexity attack: see
|
||||
http://en.wikipedia.org/wiki/Algorithmic_complexity_attack
|
||||
|
||||
|
||||
The following container is deprecated
|
||||
|
||||
* `std::unordered_set`
|
||||
* Use `ripple::hash_set` instead, which uses a better hashing algorithm.
|
||||
* Or use `ripple::hardened_hash_set` to prevent algorithmic complexity attacks.
|
||||
196
include/xrpl/basics/RangeSet.h
Normal file
196
include/xrpl/basics/RangeSet.h
Normal file
@@ -0,0 +1,196 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_RANGESET_H_INCLUDED
|
||||
#define RIPPLE_BASICS_RANGESET_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/core/LexicalCast.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/icl/closed_interval.hpp>
|
||||
#include <boost/icl/interval_set.hpp>
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** A closed interval over the domain T.
|
||||
|
||||
For an instance ClosedInterval c, this represents the closed interval
|
||||
(c.first(), c.last()). A single element interval has c.first() == c.last().
|
||||
|
||||
This is simply a type-alias for boost interval container library interval
|
||||
set, so users should consult that documentation for available supporting
|
||||
member and free functions.
|
||||
*/
|
||||
template <class T>
|
||||
using ClosedInterval = boost::icl::closed_interval<T>;
|
||||
|
||||
/** Create a closed range interval
|
||||
|
||||
Helper function to create a closed range interval without having to qualify
|
||||
the template argument.
|
||||
*/
|
||||
template <class T>
|
||||
ClosedInterval<T>
|
||||
range(T low, T high)
|
||||
{
|
||||
return ClosedInterval<T>(low, high);
|
||||
}
|
||||
|
||||
/** A set of closed intervals over the domain T.
|
||||
|
||||
Represents a set of values of the domain T using the minimum number
|
||||
of disjoint ClosedInterval<T>. This is useful to represent ranges of
|
||||
T where a few instances are missing, e.g. the set 1-5,8-9,11-14.
|
||||
|
||||
This is simply a type-alias for boost interval container library interval
|
||||
set, so users should consult that documentation for available supporting
|
||||
member and free functions.
|
||||
*/
|
||||
template <class T>
|
||||
using RangeSet = boost::icl::interval_set<T, std::less, ClosedInterval<T>>;
|
||||
|
||||
/** Convert a ClosedInterval to a styled string
|
||||
|
||||
The styled string is
|
||||
"c.first()-c.last()" if c.first() != c.last()
|
||||
"c.first()" if c.first() == c.last()
|
||||
|
||||
@param ci The closed interval to convert
|
||||
@return The style string
|
||||
*/
|
||||
template <class T>
|
||||
std::string
|
||||
to_string(ClosedInterval<T> const& ci)
|
||||
{
|
||||
if (ci.first() == ci.last())
|
||||
return std::to_string(ci.first());
|
||||
return std::to_string(ci.first()) + "-" + std::to_string(ci.last());
|
||||
}
|
||||
|
||||
/** Convert the given RangeSet to a styled string.
|
||||
|
||||
The styled string representation is the set of disjoint intervals joined
|
||||
by commas. The string "empty" is returned if the set is empty.
|
||||
|
||||
@param rs The rangeset to convert
|
||||
@return The styled string
|
||||
*/
|
||||
template <class T>
|
||||
std::string
|
||||
to_string(RangeSet<T> const& rs)
|
||||
{
|
||||
if (rs.empty())
|
||||
return "empty";
|
||||
|
||||
std::string s;
|
||||
for (auto const& interval : rs)
|
||||
s += ripple::to_string(interval) + ",";
|
||||
s.pop_back();
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/** Convert the given styled string to a RangeSet.
|
||||
|
||||
The styled string representation is the set
|
||||
of disjoint intervals joined by commas.
|
||||
|
||||
@param rs The set to be populated
|
||||
@param s The styled string to convert
|
||||
@return True on successfully converting styled string
|
||||
*/
|
||||
template <class T>
|
||||
[[nodiscard]] bool
|
||||
from_string(RangeSet<T>& rs, std::string const& s)
|
||||
{
|
||||
std::vector<std::string> intervals;
|
||||
std::vector<std::string> tokens;
|
||||
bool result{true};
|
||||
|
||||
rs.clear();
|
||||
boost::split(tokens, s, boost::algorithm::is_any_of(","));
|
||||
for (auto const& t : tokens)
|
||||
{
|
||||
boost::split(intervals, t, boost::algorithm::is_any_of("-"));
|
||||
switch (intervals.size())
|
||||
{
|
||||
case 1: {
|
||||
T front;
|
||||
if (!beast::lexicalCastChecked(front, intervals.front()))
|
||||
result = false;
|
||||
else
|
||||
rs.insert(front);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
T front;
|
||||
if (!beast::lexicalCastChecked(front, intervals.front()))
|
||||
result = false;
|
||||
else
|
||||
{
|
||||
T back;
|
||||
if (!beast::lexicalCastChecked(back, intervals.back()))
|
||||
result = false;
|
||||
else
|
||||
rs.insert(range(front, back));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (!result)
|
||||
break;
|
||||
intervals.clear();
|
||||
}
|
||||
|
||||
if (!result)
|
||||
rs.clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Find the largest value not in the set that is less than a given value.
|
||||
|
||||
@param rs The set of interest
|
||||
@param t The value that must be larger than the result
|
||||
@param minVal (Default is 0) The smallest allowed value
|
||||
@return The largest v such that minV <= v < t and !contains(rs, v) or
|
||||
std::nullopt if no such v exists.
|
||||
*/
|
||||
template <class T>
|
||||
std::optional<T>
|
||||
prevMissing(RangeSet<T> const& rs, T t, T minVal = 0)
|
||||
{
|
||||
if (rs.empty() || t == minVal)
|
||||
return std::nullopt;
|
||||
RangeSet<T> tgt{ClosedInterval<T>{minVal, t - 1}};
|
||||
tgt -= rs;
|
||||
if (tgt.empty())
|
||||
return std::nullopt;
|
||||
return boost::icl::last(tgt);
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
71
include/xrpl/basics/Resolver.h
Normal file
71
include/xrpl/basics/Resolver.h
Normal file
@@ -0,0 +1,71 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_RESOLVER_H_INCLUDED
|
||||
#define RIPPLE_BASICS_RESOLVER_H_INCLUDED
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include <ripple/beast/net/IPEndpoint.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class Resolver
|
||||
{
|
||||
public:
|
||||
using HandlerType =
|
||||
std::function<void(std::string, std::vector<beast::IP::Endpoint>)>;
|
||||
|
||||
virtual ~Resolver() = 0;
|
||||
|
||||
/** Issue an asynchronous stop request. */
|
||||
virtual void
|
||||
stop_async() = 0;
|
||||
|
||||
/** Issue a synchronous stop request. */
|
||||
virtual void
|
||||
stop() = 0;
|
||||
|
||||
/** Issue a synchronous start request. */
|
||||
virtual void
|
||||
start() = 0;
|
||||
|
||||
/** resolve all hostnames on the list
|
||||
@param names the names to be resolved
|
||||
@param handler the handler to call
|
||||
*/
|
||||
/** @{ */
|
||||
template <class Handler>
|
||||
void
|
||||
resolve(std::vector<std::string> const& names, Handler handler)
|
||||
{
|
||||
resolve(names, HandlerType(handler));
|
||||
}
|
||||
|
||||
virtual void
|
||||
resolve(
|
||||
std::vector<std::string> const& names,
|
||||
HandlerType const& handler) = 0;
|
||||
/** @} */
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
40
include/xrpl/basics/ResolverAsio.h
Normal file
40
include/xrpl/basics/ResolverAsio.h
Normal file
@@ -0,0 +1,40 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_RESOLVERASIO_H_INCLUDED
|
||||
#define RIPPLE_BASICS_RESOLVERASIO_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/Resolver.h>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class ResolverAsio : public Resolver
|
||||
{
|
||||
public:
|
||||
explicit ResolverAsio() = default;
|
||||
|
||||
static std::unique_ptr<ResolverAsio>
|
||||
New(boost::asio::io_service&, beast::Journal);
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
113
include/xrpl/basics/SHAMapHash.h
Normal file
113
include/xrpl/basics/SHAMapHash.h
Normal file
@@ -0,0 +1,113 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2021 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_SHAMAP_HASH_H_INCLUDED
|
||||
#define RIPPLE_BASICS_SHAMAP_HASH_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/base_uint.h>
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
// A SHAMapHash is the hash of a node in a SHAMap, and also the
|
||||
// type of the hash of the entire SHAMap.
|
||||
|
||||
class SHAMapHash
|
||||
{
|
||||
uint256 hash_;
|
||||
|
||||
public:
|
||||
SHAMapHash() = default;
|
||||
explicit SHAMapHash(uint256 const& hash) : hash_(hash)
|
||||
{
|
||||
}
|
||||
|
||||
uint256 const&
|
||||
as_uint256() const
|
||||
{
|
||||
return hash_;
|
||||
}
|
||||
uint256&
|
||||
as_uint256()
|
||||
{
|
||||
return hash_;
|
||||
}
|
||||
bool
|
||||
isZero() const
|
||||
{
|
||||
return hash_.isZero();
|
||||
}
|
||||
bool
|
||||
isNonZero() const
|
||||
{
|
||||
return hash_.isNonZero();
|
||||
}
|
||||
int
|
||||
signum() const
|
||||
{
|
||||
return hash_.signum();
|
||||
}
|
||||
void
|
||||
zero()
|
||||
{
|
||||
hash_.zero();
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator==(SHAMapHash const& x, SHAMapHash const& y)
|
||||
{
|
||||
return x.hash_ == y.hash_;
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator<(SHAMapHash const& x, SHAMapHash const& y)
|
||||
{
|
||||
return x.hash_ < y.hash_;
|
||||
}
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& os, SHAMapHash const& x)
|
||||
{
|
||||
return os << x.hash_;
|
||||
}
|
||||
|
||||
friend std::string
|
||||
to_string(SHAMapHash const& x)
|
||||
{
|
||||
return to_string(x.hash_);
|
||||
}
|
||||
|
||||
template <class H>
|
||||
friend void
|
||||
hash_append(H& h, SHAMapHash const& x)
|
||||
{
|
||||
hash_append(h, x.hash_);
|
||||
}
|
||||
};
|
||||
|
||||
inline bool
|
||||
operator!=(SHAMapHash const& x, SHAMapHash const& y)
|
||||
{
|
||||
return !(x == y);
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif // RIPPLE_BASICS_SHAMAP_HASH_H_INCLUDED
|
||||
432
include/xrpl/basics/SlabAllocator.h
Normal file
432
include/xrpl/basics/SlabAllocator.h
Normal file
@@ -0,0 +1,432 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright 2022, Nikolaos D. Bougalis <nikb@bougalis.net>
|
||||
|
||||
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 RIPPLE_BASICS_SLABALLOCATOR_H_INCLUDED
|
||||
#define RIPPLE_BASICS_SLABALLOCATOR_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/type_name.h>
|
||||
|
||||
#include <boost/align.hpp>
|
||||
#include <boost/container/static_vector.hpp>
|
||||
#include <boost/predef.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
|
||||
#if BOOST_OS_LINUX
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
namespace ripple {
|
||||
|
||||
template <typename Type>
|
||||
class SlabAllocator
|
||||
{
|
||||
static_assert(
|
||||
sizeof(Type) >= sizeof(std::uint8_t*),
|
||||
"SlabAllocator: the requested object must be larger than a pointer.");
|
||||
|
||||
static_assert(alignof(Type) == 8 || alignof(Type) == 4);
|
||||
|
||||
/** A block of memory that is owned by a slab allocator */
|
||||
struct SlabBlock
|
||||
{
|
||||
// A mutex to protect the freelist for this block:
|
||||
std::mutex m_;
|
||||
|
||||
// A linked list of appropriately sized free buffers:
|
||||
std::uint8_t* l_ = nullptr;
|
||||
|
||||
// The next memory block
|
||||
SlabBlock* next_;
|
||||
|
||||
// The underlying memory block:
|
||||
std::uint8_t const* const p_ = nullptr;
|
||||
|
||||
// The extent of the underlying memory block:
|
||||
std::size_t const size_;
|
||||
|
||||
SlabBlock(
|
||||
SlabBlock* next,
|
||||
std::uint8_t* data,
|
||||
std::size_t size,
|
||||
std::size_t item)
|
||||
: next_(next), p_(data), size_(size)
|
||||
{
|
||||
// We don't need to grab the mutex here, since we're the only
|
||||
// ones with access at this moment.
|
||||
|
||||
while (data + item <= p_ + size_)
|
||||
{
|
||||
// Use memcpy to avoid unaligned UB
|
||||
// (will optimize to equivalent code)
|
||||
std::memcpy(data, &l_, sizeof(std::uint8_t*));
|
||||
l_ = data;
|
||||
data += item;
|
||||
}
|
||||
}
|
||||
|
||||
~SlabBlock()
|
||||
{
|
||||
// Calling this destructor will release the allocated memory but
|
||||
// will not properly destroy any objects that are constructed in
|
||||
// the block itself.
|
||||
}
|
||||
|
||||
SlabBlock(SlabBlock const& other) = delete;
|
||||
SlabBlock&
|
||||
operator=(SlabBlock const& other) = delete;
|
||||
|
||||
SlabBlock(SlabBlock&& other) = delete;
|
||||
SlabBlock&
|
||||
operator=(SlabBlock&& other) = delete;
|
||||
|
||||
/** Determines whether the given pointer belongs to this allocator */
|
||||
bool
|
||||
own(std::uint8_t const* p) const noexcept
|
||||
{
|
||||
return (p >= p_) && (p < p_ + size_);
|
||||
}
|
||||
|
||||
std::uint8_t*
|
||||
allocate() noexcept
|
||||
{
|
||||
std::uint8_t* ret;
|
||||
|
||||
{
|
||||
std::lock_guard l(m_);
|
||||
|
||||
ret = l_;
|
||||
|
||||
if (ret)
|
||||
{
|
||||
// Use memcpy to avoid unaligned UB
|
||||
// (will optimize to equivalent code)
|
||||
std::memcpy(&l_, ret, sizeof(std::uint8_t*));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Return an item to this allocator's freelist.
|
||||
|
||||
@param ptr The pointer to the chunk of memory being deallocated.
|
||||
|
||||
@note This is a dangerous, private interface; the item being
|
||||
returned should belong to this allocator. Debug builds
|
||||
will check and assert if this is not the case. Release
|
||||
builds will not.
|
||||
*/
|
||||
void
|
||||
deallocate(std::uint8_t* ptr) noexcept
|
||||
{
|
||||
assert(own(ptr));
|
||||
|
||||
std::lock_guard l(m_);
|
||||
|
||||
// Use memcpy to avoid unaligned UB
|
||||
// (will optimize to equivalent code)
|
||||
std::memcpy(ptr, &l_, sizeof(std::uint8_t*));
|
||||
l_ = ptr;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
// A linked list of slabs
|
||||
std::atomic<SlabBlock*> slabs_ = nullptr;
|
||||
|
||||
// The alignment requirements of the item we're allocating:
|
||||
std::size_t const itemAlignment_;
|
||||
|
||||
// The size of an item, including the extra bytes requested and
|
||||
// any padding needed for alignment purposes:
|
||||
std::size_t const itemSize_;
|
||||
|
||||
// The size of each individual slab:
|
||||
std::size_t const slabSize_;
|
||||
|
||||
public:
|
||||
/** Constructs a slab allocator able to allocate objects of a fixed size
|
||||
|
||||
@param count the number of items the slab allocator can allocate; note
|
||||
that a count of 0 is valid and means that the allocator
|
||||
is, effectively, disabled. This can be very useful in some
|
||||
contexts (e.g. when mimimal memory usage is needed) and
|
||||
allows for graceful failure.
|
||||
*/
|
||||
constexpr explicit SlabAllocator(
|
||||
std::size_t extra,
|
||||
std::size_t alloc = 0,
|
||||
std::size_t align = 0)
|
||||
: itemAlignment_(align ? align : alignof(Type))
|
||||
, itemSize_(
|
||||
boost::alignment::align_up(sizeof(Type) + extra, itemAlignment_))
|
||||
, slabSize_(alloc)
|
||||
{
|
||||
assert((itemAlignment_ & (itemAlignment_ - 1)) == 0);
|
||||
}
|
||||
|
||||
SlabAllocator(SlabAllocator const& other) = delete;
|
||||
SlabAllocator&
|
||||
operator=(SlabAllocator const& other) = delete;
|
||||
|
||||
SlabAllocator(SlabAllocator&& other) = delete;
|
||||
SlabAllocator&
|
||||
operator=(SlabAllocator&& other) = delete;
|
||||
|
||||
~SlabAllocator()
|
||||
{
|
||||
// FIXME: We can't destroy the memory blocks we've allocated, because
|
||||
// we can't be sure that they are not being used. Cleaning the
|
||||
// shutdown process up could make this possible.
|
||||
}
|
||||
|
||||
/** Returns the size of the memory block this allocator returns. */
|
||||
constexpr std::size_t
|
||||
size() const noexcept
|
||||
{
|
||||
return itemSize_;
|
||||
}
|
||||
|
||||
/** Returns a suitably aligned pointer, if one is available.
|
||||
|
||||
@return a pointer to a block of memory from the allocator, or
|
||||
nullptr if the allocator can't satisfy this request.
|
||||
*/
|
||||
std::uint8_t*
|
||||
allocate() noexcept
|
||||
{
|
||||
auto slab = slabs_.load();
|
||||
|
||||
while (slab != nullptr)
|
||||
{
|
||||
if (auto ret = slab->allocate())
|
||||
return ret;
|
||||
|
||||
slab = slab->next_;
|
||||
}
|
||||
|
||||
// No slab can satisfy our request, so we attempt to allocate a new
|
||||
// one here:
|
||||
std::size_t size = slabSize_;
|
||||
|
||||
// We want to allocate the memory at a 2 MiB boundary, to make it
|
||||
// possible to use hugepage mappings on Linux:
|
||||
auto buf =
|
||||
boost::alignment::aligned_alloc(megabytes(std::size_t(2)), size);
|
||||
|
||||
// clang-format off
|
||||
if (!buf) [[unlikely]]
|
||||
return nullptr;
|
||||
// clang-format on
|
||||
|
||||
#if BOOST_OS_LINUX
|
||||
// When allocating large blocks, attempt to leverage Linux's
|
||||
// transparent hugepage support. It is unclear and difficult
|
||||
// to accurately determine if doing this impacts performance
|
||||
// enough to justify using platform-specific tricks.
|
||||
if (size >= megabytes(std::size_t(4)))
|
||||
madvise(buf, size, MADV_HUGEPAGE);
|
||||
#endif
|
||||
|
||||
// We need to carve out a bit of memory for the slab header
|
||||
// and then align the rest appropriately:
|
||||
auto slabData = reinterpret_cast<void*>(
|
||||
reinterpret_cast<std::uint8_t*>(buf) + sizeof(SlabBlock));
|
||||
auto slabSize = size - sizeof(SlabBlock);
|
||||
|
||||
// This operation is essentially guaranteed not to fail but
|
||||
// let's be careful anyways.
|
||||
if (!boost::alignment::align(
|
||||
itemAlignment_, itemSize_, slabData, slabSize))
|
||||
{
|
||||
boost::alignment::aligned_free(buf);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
slab = new (buf) SlabBlock(
|
||||
slabs_.load(),
|
||||
reinterpret_cast<std::uint8_t*>(slabData),
|
||||
slabSize,
|
||||
itemSize_);
|
||||
|
||||
// Link the new slab
|
||||
while (!slabs_.compare_exchange_weak(
|
||||
slab->next_,
|
||||
slab,
|
||||
std::memory_order_release,
|
||||
std::memory_order_relaxed))
|
||||
{
|
||||
; // Nothing to do
|
||||
}
|
||||
|
||||
return slab->allocate();
|
||||
}
|
||||
|
||||
/** Returns the memory block to the allocator.
|
||||
|
||||
@param ptr A pointer to a memory block.
|
||||
@param size If non-zero, a hint as to the size of the block.
|
||||
@return true if this memory block belonged to the allocator and has
|
||||
been released; false otherwise.
|
||||
*/
|
||||
bool
|
||||
deallocate(std::uint8_t* ptr) noexcept
|
||||
{
|
||||
assert(ptr);
|
||||
|
||||
for (auto slab = slabs_.load(); slab != nullptr; slab = slab->next_)
|
||||
{
|
||||
if (slab->own(ptr))
|
||||
{
|
||||
slab->deallocate(ptr);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/** A collection of slab allocators of various sizes for a given type. */
|
||||
template <typename Type>
|
||||
class SlabAllocatorSet
|
||||
{
|
||||
private:
|
||||
// The list of allocators that belong to this set
|
||||
boost::container::static_vector<SlabAllocator<Type>, 64> allocators_;
|
||||
|
||||
std::size_t maxSize_ = 0;
|
||||
|
||||
public:
|
||||
class SlabConfig
|
||||
{
|
||||
friend class SlabAllocatorSet;
|
||||
|
||||
private:
|
||||
std::size_t extra;
|
||||
std::size_t alloc;
|
||||
std::size_t align;
|
||||
|
||||
public:
|
||||
constexpr SlabConfig(
|
||||
std::size_t extra_,
|
||||
std::size_t alloc_ = 0,
|
||||
std::size_t align_ = alignof(Type))
|
||||
: extra(extra_), alloc(alloc_), align(align_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
constexpr SlabAllocatorSet(std::vector<SlabConfig> cfg)
|
||||
{
|
||||
// Ensure that the specified allocators are sorted from smallest to
|
||||
// largest by size:
|
||||
std::sort(
|
||||
std::begin(cfg),
|
||||
std::end(cfg),
|
||||
[](SlabConfig const& a, SlabConfig const& b) {
|
||||
return a.extra < b.extra;
|
||||
});
|
||||
|
||||
// We should never have two slabs of the same size
|
||||
if (std::adjacent_find(
|
||||
std::begin(cfg),
|
||||
std::end(cfg),
|
||||
[](SlabConfig const& a, SlabConfig const& b) {
|
||||
return a.extra == b.extra;
|
||||
}) != cfg.end())
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"SlabAllocatorSet<" + beast::type_name<Type>() +
|
||||
">: duplicate slab size");
|
||||
}
|
||||
|
||||
for (auto const& c : cfg)
|
||||
{
|
||||
auto& a = allocators_.emplace_back(c.extra, c.alloc, c.align);
|
||||
|
||||
if (a.size() > maxSize_)
|
||||
maxSize_ = a.size();
|
||||
}
|
||||
}
|
||||
|
||||
SlabAllocatorSet(SlabAllocatorSet const& other) = delete;
|
||||
SlabAllocatorSet&
|
||||
operator=(SlabAllocatorSet const& other) = delete;
|
||||
|
||||
SlabAllocatorSet(SlabAllocatorSet&& other) = delete;
|
||||
SlabAllocatorSet&
|
||||
operator=(SlabAllocatorSet&& other) = delete;
|
||||
|
||||
~SlabAllocatorSet()
|
||||
{
|
||||
}
|
||||
|
||||
/** Returns a suitably aligned pointer, if one is available.
|
||||
|
||||
@param extra The number of extra bytes, above and beyond the size of
|
||||
the object, that should be returned by the allocator.
|
||||
|
||||
@return a pointer to a block of memory, or nullptr if the allocator
|
||||
can't satisfy this request.
|
||||
*/
|
||||
std::uint8_t*
|
||||
allocate(std::size_t extra) noexcept
|
||||
{
|
||||
if (auto const size = sizeof(Type) + extra; size <= maxSize_)
|
||||
{
|
||||
for (auto& a : allocators_)
|
||||
{
|
||||
if (a.size() >= size)
|
||||
return a.allocate();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/** Returns the memory block to the allocator.
|
||||
|
||||
@param ptr A pointer to a memory block.
|
||||
|
||||
@return true if this memory block belonged to one of the allocators
|
||||
in this set and has been released; false otherwise.
|
||||
*/
|
||||
bool
|
||||
deallocate(std::uint8_t* ptr) noexcept
|
||||
{
|
||||
for (auto& a : allocators_)
|
||||
{
|
||||
if (a.deallocate(ptr))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif // RIPPLE_BASICS_SLABALLOCATOR_H_INCLUDED
|
||||
264
include/xrpl/basics/Slice.h
Normal file
264
include/xrpl/basics/Slice.h
Normal file
@@ -0,0 +1,264 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_SLICE_H_INCLUDED
|
||||
#define RIPPLE_BASICS_SLICE_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <ripple/basics/strHex.h>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** An immutable linear range of bytes.
|
||||
|
||||
A fully constructed Slice is guaranteed to be in a valid state.
|
||||
A Slice is lightweight and copyable, it retains no ownership
|
||||
of the underlying memory.
|
||||
*/
|
||||
class Slice
|
||||
{
|
||||
private:
|
||||
std::uint8_t const* data_ = nullptr;
|
||||
std::size_t size_ = 0;
|
||||
|
||||
public:
|
||||
using value_type = std::uint8_t;
|
||||
using const_iterator = value_type const*;
|
||||
|
||||
/** Default constructed Slice has length 0. */
|
||||
Slice() noexcept = default;
|
||||
|
||||
Slice(Slice const&) noexcept = default;
|
||||
Slice&
|
||||
operator=(Slice const&) noexcept = default;
|
||||
|
||||
/** Create a slice pointing to existing memory. */
|
||||
Slice(void const* data, std::size_t size) noexcept
|
||||
: data_(reinterpret_cast<std::uint8_t const*>(data)), size_(size)
|
||||
{
|
||||
}
|
||||
|
||||
/** Return `true` if the byte range is empty. */
|
||||
[[nodiscard]] bool
|
||||
empty() const noexcept
|
||||
{
|
||||
return size_ == 0;
|
||||
}
|
||||
|
||||
/** Returns the number of bytes in the storage.
|
||||
|
||||
This may be zero for an empty range.
|
||||
*/
|
||||
/** @{ */
|
||||
[[nodiscard]] std::size_t
|
||||
size() const noexcept
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::size_t
|
||||
length() const noexcept
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Return a pointer to beginning of the storage.
|
||||
@note The return type is guaranteed to be a pointer
|
||||
to a single byte, to facilitate pointer arithmetic.
|
||||
*/
|
||||
std::uint8_t const*
|
||||
data() const noexcept
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
/** Access raw bytes. */
|
||||
std::uint8_t
|
||||
operator[](std::size_t i) const noexcept
|
||||
{
|
||||
assert(i < size_);
|
||||
return data_[i];
|
||||
}
|
||||
|
||||
/** Advance the buffer. */
|
||||
/** @{ */
|
||||
Slice&
|
||||
operator+=(std::size_t n)
|
||||
{
|
||||
if (n > size_)
|
||||
Throw<std::domain_error>("too small");
|
||||
data_ += n;
|
||||
size_ -= n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Slice
|
||||
operator+(std::size_t n) const
|
||||
{
|
||||
Slice temp = *this;
|
||||
return temp += n;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Shrinks the slice by moving its start forward by n characters. */
|
||||
void
|
||||
remove_prefix(std::size_t n)
|
||||
{
|
||||
data_ += n;
|
||||
size_ -= n;
|
||||
}
|
||||
|
||||
/** Shrinks the slice by moving its end backward by n characters. */
|
||||
void
|
||||
remove_suffix(std::size_t n)
|
||||
{
|
||||
size_ -= n;
|
||||
}
|
||||
|
||||
const_iterator
|
||||
begin() const noexcept
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
const_iterator
|
||||
cbegin() const noexcept
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
const_iterator
|
||||
end() const noexcept
|
||||
{
|
||||
return data_ + size_;
|
||||
}
|
||||
|
||||
const_iterator
|
||||
cend() const noexcept
|
||||
{
|
||||
return data_ + size_;
|
||||
}
|
||||
|
||||
/** Return a "sub slice" of given length starting at the given position
|
||||
|
||||
Note that the subslice encompasses the range [pos, pos + rcount),
|
||||
where rcount is the smaller of count and size() - pos.
|
||||
|
||||
@param pos position of the first character
|
||||
@count requested length
|
||||
|
||||
@returns The requested subslice, if the request is valid.
|
||||
@throws std::out_of_range if pos > size()
|
||||
*/
|
||||
Slice
|
||||
substr(
|
||||
std::size_t pos,
|
||||
std::size_t count = std::numeric_limits<std::size_t>::max()) const
|
||||
{
|
||||
if (pos > size())
|
||||
throw std::out_of_range("Requested sub-slice is out of bounds");
|
||||
|
||||
return {data_ + pos, std::min(count, size() - pos)};
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class Hasher>
|
||||
inline void
|
||||
hash_append(Hasher& h, Slice const& v)
|
||||
{
|
||||
h(v.data(), v.size());
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator==(Slice const& lhs, Slice const& rhs) noexcept
|
||||
{
|
||||
if (lhs.size() != rhs.size())
|
||||
return false;
|
||||
|
||||
if (lhs.size() == 0)
|
||||
return true;
|
||||
|
||||
return std::memcmp(lhs.data(), rhs.data(), lhs.size()) == 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator!=(Slice const& lhs, Slice const& rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator<(Slice const& lhs, Slice const& rhs) noexcept
|
||||
{
|
||||
return std::lexicographical_compare(
|
||||
lhs.data(),
|
||||
lhs.data() + lhs.size(),
|
||||
rhs.data(),
|
||||
rhs.data() + rhs.size());
|
||||
}
|
||||
|
||||
template <class Stream>
|
||||
Stream&
|
||||
operator<<(Stream& s, Slice const& v)
|
||||
{
|
||||
s << strHex(v);
|
||||
return s;
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
std::enable_if_t<
|
||||
std::is_same<T, char>::value || std::is_same<T, unsigned char>::value,
|
||||
Slice>
|
||||
makeSlice(std::array<T, N> const& a)
|
||||
{
|
||||
return Slice(a.data(), a.size());
|
||||
}
|
||||
|
||||
template <class T, class Alloc>
|
||||
std::enable_if_t<
|
||||
std::is_same<T, char>::value || std::is_same<T, unsigned char>::value,
|
||||
Slice>
|
||||
makeSlice(std::vector<T, Alloc> const& v)
|
||||
{
|
||||
return Slice(v.data(), v.size());
|
||||
}
|
||||
|
||||
template <class Traits, class Alloc>
|
||||
Slice
|
||||
makeSlice(std::basic_string<char, Traits, Alloc> const& s)
|
||||
{
|
||||
return Slice(s.data(), s.size());
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
157
include/xrpl/basics/StringUtilities.h
Normal file
157
include/xrpl/basics/StringUtilities.h
Normal file
@@ -0,0 +1,157 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_STRINGUTILITIES_H_INCLUDED
|
||||
#define RIPPLE_BASICS_STRINGUTILITIES_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/Blob.h>
|
||||
#include <ripple/basics/strHex.h>
|
||||
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/utility/string_view.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** Format arbitrary binary data as an SQLite "blob literal".
|
||||
|
||||
In SQLite, blob literals must be encoded when used in a query. Per
|
||||
https://sqlite.org/lang_expr.html#literal_values_constants_ they are
|
||||
encoded as string literals containing hexadecimal data and preceded
|
||||
by a single 'X' character.
|
||||
|
||||
@param blob An arbitrary blob of binary data
|
||||
@return The input, encoded as a blob literal.
|
||||
*/
|
||||
std::string
|
||||
sqlBlobLiteral(Blob const& blob);
|
||||
|
||||
template <class Iterator>
|
||||
std::optional<Blob>
|
||||
strUnHex(std::size_t strSize, Iterator begin, Iterator end)
|
||||
{
|
||||
static constexpr std::array<int, 256> const unxtab = []() {
|
||||
std::array<int, 256> t{};
|
||||
|
||||
for (auto& x : t)
|
||||
x = -1;
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
t['0' + i] = i;
|
||||
|
||||
for (int i = 0; i < 6; ++i)
|
||||
{
|
||||
t['A' + i] = 10 + i;
|
||||
t['a' + i] = 10 + i;
|
||||
}
|
||||
|
||||
return t;
|
||||
}();
|
||||
|
||||
Blob out;
|
||||
|
||||
out.reserve((strSize + 1) / 2);
|
||||
|
||||
auto iter = begin;
|
||||
|
||||
if (strSize & 1)
|
||||
{
|
||||
int c = unxtab[*iter++];
|
||||
|
||||
if (c < 0)
|
||||
return {};
|
||||
|
||||
out.push_back(c);
|
||||
}
|
||||
|
||||
while (iter != end)
|
||||
{
|
||||
int cHigh = unxtab[*iter++];
|
||||
|
||||
if (cHigh < 0)
|
||||
return {};
|
||||
|
||||
int cLow = unxtab[*iter++];
|
||||
|
||||
if (cLow < 0)
|
||||
return {};
|
||||
|
||||
out.push_back(static_cast<unsigned char>((cHigh << 4) | cLow));
|
||||
}
|
||||
|
||||
return {std::move(out)};
|
||||
}
|
||||
|
||||
inline std::optional<Blob>
|
||||
strUnHex(std::string const& strSrc)
|
||||
{
|
||||
return strUnHex(strSrc.size(), strSrc.cbegin(), strSrc.cend());
|
||||
}
|
||||
|
||||
inline std::optional<Blob>
|
||||
strViewUnHex(std::string_view strSrc)
|
||||
{
|
||||
return strUnHex(strSrc.size(), strSrc.cbegin(), strSrc.cend());
|
||||
}
|
||||
|
||||
struct parsedURL
|
||||
{
|
||||
explicit parsedURL() = default;
|
||||
|
||||
std::string scheme;
|
||||
std::string username;
|
||||
std::string password;
|
||||
std::string domain;
|
||||
std::optional<std::uint16_t> port;
|
||||
std::string path;
|
||||
|
||||
bool
|
||||
operator==(parsedURL const& other) const
|
||||
{
|
||||
return scheme == other.scheme && domain == other.domain &&
|
||||
port == other.port && path == other.path;
|
||||
}
|
||||
};
|
||||
|
||||
bool
|
||||
parseUrl(parsedURL& pUrl, std::string const& strUrl);
|
||||
|
||||
std::string
|
||||
trim_whitespace(std::string str);
|
||||
|
||||
std::optional<std::uint64_t>
|
||||
to_uint64(std::string const& s);
|
||||
|
||||
/** Determines if the given string looks like a TOML-file hosting domain.
|
||||
|
||||
Do not use this function to determine if a particular string is a valid
|
||||
domain, as this function may reject domains that are otherwise valid and
|
||||
doesn't check whether the TLD is valid.
|
||||
*/
|
||||
bool
|
||||
isProperlyFormedTomlDomain(std::string_view domain);
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
798
include/xrpl/basics/TaggedCache.h
Normal file
798
include/xrpl/basics/TaggedCache.h
Normal file
@@ -0,0 +1,798 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_TAGGEDCACHE_H_INCLUDED
|
||||
#define RIPPLE_BASICS_TAGGEDCACHE_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/basics/UnorderedContainers.h>
|
||||
#include <ripple/basics/hardened_hash.h>
|
||||
#include <ripple/beast/clock/abstract_clock.h>
|
||||
#include <ripple/beast/insight/Insight.h>
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** Map/cache combination.
|
||||
This class implements a cache and a map. The cache keeps objects alive
|
||||
in the map. The map allows multiple code paths that reference objects
|
||||
with the same tag to get the same actual object.
|
||||
|
||||
So long as data is in the cache, it will stay in memory.
|
||||
If it stays in memory even after it is ejected from the cache,
|
||||
the map will track it.
|
||||
|
||||
@note Callers must not modify data objects that are stored in the cache
|
||||
unless they hold their own lock over all cache operations.
|
||||
*/
|
||||
template <
|
||||
class Key,
|
||||
class T,
|
||||
bool IsKeyCache = false,
|
||||
class Hash = hardened_hash<>,
|
||||
class KeyEqual = std::equal_to<Key>,
|
||||
class Mutex = std::recursive_mutex>
|
||||
class TaggedCache
|
||||
{
|
||||
public:
|
||||
using mutex_type = Mutex;
|
||||
using key_type = Key;
|
||||
using mapped_type = T;
|
||||
using clock_type = beast::abstract_clock<std::chrono::steady_clock>;
|
||||
|
||||
public:
|
||||
TaggedCache(
|
||||
std::string const& name,
|
||||
int size,
|
||||
clock_type::duration expiration,
|
||||
clock_type& clock,
|
||||
beast::Journal journal,
|
||||
beast::insight::Collector::ptr const& collector =
|
||||
beast::insight::NullCollector::New())
|
||||
: m_journal(journal)
|
||||
, m_clock(clock)
|
||||
, m_stats(
|
||||
name,
|
||||
std::bind(&TaggedCache::collect_metrics, this),
|
||||
collector)
|
||||
, m_name(name)
|
||||
, m_target_size(size)
|
||||
, m_target_age(expiration)
|
||||
, m_cache_count(0)
|
||||
, m_hits(0)
|
||||
, m_misses(0)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
/** Return the clock associated with the cache. */
|
||||
clock_type&
|
||||
clock()
|
||||
{
|
||||
return m_clock;
|
||||
}
|
||||
|
||||
/** Returns the number of items in the container. */
|
||||
std::size_t
|
||||
size() const
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
return m_cache.size();
|
||||
}
|
||||
|
||||
void
|
||||
setTargetSize(int s)
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
m_target_size = s;
|
||||
|
||||
if (s > 0)
|
||||
{
|
||||
for (auto& partition : m_cache.map())
|
||||
{
|
||||
partition.rehash(static_cast<std::size_t>(
|
||||
(s + (s >> 2)) /
|
||||
(partition.max_load_factor() * m_cache.partitions()) +
|
||||
1));
|
||||
}
|
||||
}
|
||||
|
||||
JLOG(m_journal.debug()) << m_name << " target size set to " << s;
|
||||
}
|
||||
|
||||
clock_type::duration
|
||||
getTargetAge() const
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
return m_target_age;
|
||||
}
|
||||
|
||||
void
|
||||
setTargetAge(clock_type::duration s)
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
m_target_age = s;
|
||||
JLOG(m_journal.debug())
|
||||
<< m_name << " target age set to " << m_target_age.count();
|
||||
}
|
||||
|
||||
int
|
||||
getCacheSize() const
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
return m_cache_count;
|
||||
}
|
||||
|
||||
int
|
||||
getTrackSize() const
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
return m_cache.size();
|
||||
}
|
||||
|
||||
float
|
||||
getHitRate()
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
auto const total = static_cast<float>(m_hits + m_misses);
|
||||
return m_hits * (100.0f / std::max(1.0f, total));
|
||||
}
|
||||
|
||||
void
|
||||
clear()
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
m_cache.clear();
|
||||
m_cache_count = 0;
|
||||
}
|
||||
|
||||
void
|
||||
reset()
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
m_cache.clear();
|
||||
m_cache_count = 0;
|
||||
m_hits = 0;
|
||||
m_misses = 0;
|
||||
}
|
||||
|
||||
/** Refresh the last access time on a key if present.
|
||||
@return `true` If the key was found.
|
||||
*/
|
||||
template <class KeyComparable>
|
||||
bool
|
||||
touch_if_exists(KeyComparable const& key)
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
auto const iter(m_cache.find(key));
|
||||
if (iter == m_cache.end())
|
||||
{
|
||||
++m_stats.misses;
|
||||
return false;
|
||||
}
|
||||
iter->second.touch(m_clock.now());
|
||||
++m_stats.hits;
|
||||
return true;
|
||||
}
|
||||
|
||||
using SweptPointersVector = std::pair<
|
||||
std::vector<std::shared_ptr<mapped_type>>,
|
||||
std::vector<std::weak_ptr<mapped_type>>>;
|
||||
|
||||
void
|
||||
sweep()
|
||||
{
|
||||
// Keep references to all the stuff we sweep
|
||||
// For performance, each worker thread should exit before the swept data
|
||||
// is destroyed but still within the main cache lock.
|
||||
std::vector<SweptPointersVector> allStuffToSweep(m_cache.partitions());
|
||||
|
||||
clock_type::time_point const now(m_clock.now());
|
||||
clock_type::time_point when_expire;
|
||||
|
||||
auto const start = std::chrono::steady_clock::now();
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
if (m_target_size == 0 ||
|
||||
(static_cast<int>(m_cache.size()) <= m_target_size))
|
||||
{
|
||||
when_expire = now - m_target_age;
|
||||
}
|
||||
else
|
||||
{
|
||||
when_expire =
|
||||
now - m_target_age * m_target_size / m_cache.size();
|
||||
|
||||
clock_type::duration const minimumAge(std::chrono::seconds(1));
|
||||
if (when_expire > (now - minimumAge))
|
||||
when_expire = now - minimumAge;
|
||||
|
||||
JLOG(m_journal.trace())
|
||||
<< m_name << " is growing fast " << m_cache.size() << " of "
|
||||
<< m_target_size << " aging at "
|
||||
<< (now - when_expire).count() << " of "
|
||||
<< m_target_age.count();
|
||||
}
|
||||
|
||||
std::vector<std::thread> workers;
|
||||
workers.reserve(m_cache.partitions());
|
||||
std::atomic<int> allRemovals = 0;
|
||||
|
||||
for (std::size_t p = 0; p < m_cache.partitions(); ++p)
|
||||
{
|
||||
workers.push_back(sweepHelper(
|
||||
when_expire,
|
||||
now,
|
||||
m_cache.map()[p],
|
||||
allStuffToSweep[p],
|
||||
allRemovals,
|
||||
lock));
|
||||
}
|
||||
for (std::thread& worker : workers)
|
||||
worker.join();
|
||||
|
||||
m_cache_count -= allRemovals;
|
||||
}
|
||||
// At this point allStuffToSweep will go out of scope outside the lock
|
||||
// and decrement the reference count on each strong pointer.
|
||||
JLOG(m_journal.debug())
|
||||
<< m_name << " TaggedCache sweep lock duration "
|
||||
<< std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - start)
|
||||
.count()
|
||||
<< "ms";
|
||||
}
|
||||
|
||||
bool
|
||||
del(const key_type& key, bool valid)
|
||||
{
|
||||
// Remove from cache, if !valid, remove from map too. Returns true if
|
||||
// removed from cache
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
auto cit = m_cache.find(key);
|
||||
|
||||
if (cit == m_cache.end())
|
||||
return false;
|
||||
|
||||
Entry& entry = cit->second;
|
||||
|
||||
bool ret = false;
|
||||
|
||||
if (entry.isCached())
|
||||
{
|
||||
--m_cache_count;
|
||||
entry.ptr.reset();
|
||||
ret = true;
|
||||
}
|
||||
|
||||
if (!valid || entry.isExpired())
|
||||
m_cache.erase(cit);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Replace aliased objects with originals.
|
||||
|
||||
Due to concurrency it is possible for two separate objects with
|
||||
the same content and referring to the same unique "thing" to exist.
|
||||
This routine eliminates the duplicate and performs a replacement
|
||||
on the callers shared pointer if needed.
|
||||
|
||||
@param key The key corresponding to the object
|
||||
@param data A shared pointer to the data corresponding to the object.
|
||||
@param replace Function that decides if cache should be replaced
|
||||
|
||||
@return `true` If the key already existed.
|
||||
*/
|
||||
public:
|
||||
bool
|
||||
canonicalize(
|
||||
const key_type& key,
|
||||
std::shared_ptr<T>& data,
|
||||
std::function<bool(std::shared_ptr<T> const&)>&& replace)
|
||||
{
|
||||
// Return canonical value, store if needed, refresh in cache
|
||||
// Return values: true=we had the data already
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
auto cit = m_cache.find(key);
|
||||
|
||||
if (cit == m_cache.end())
|
||||
{
|
||||
m_cache.emplace(
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(key),
|
||||
std::forward_as_tuple(m_clock.now(), data));
|
||||
++m_cache_count;
|
||||
return false;
|
||||
}
|
||||
|
||||
Entry& entry = cit->second;
|
||||
entry.touch(m_clock.now());
|
||||
|
||||
if (entry.isCached())
|
||||
{
|
||||
if (replace(entry.ptr))
|
||||
{
|
||||
entry.ptr = data;
|
||||
entry.weak_ptr = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
data = entry.ptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
auto cachedData = entry.lock();
|
||||
|
||||
if (cachedData)
|
||||
{
|
||||
if (replace(entry.ptr))
|
||||
{
|
||||
entry.ptr = data;
|
||||
entry.weak_ptr = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry.ptr = cachedData;
|
||||
data = cachedData;
|
||||
}
|
||||
|
||||
++m_cache_count;
|
||||
return true;
|
||||
}
|
||||
|
||||
entry.ptr = data;
|
||||
entry.weak_ptr = data;
|
||||
++m_cache_count;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
canonicalize_replace_cache(
|
||||
const key_type& key,
|
||||
std::shared_ptr<T> const& data)
|
||||
{
|
||||
return canonicalize(
|
||||
key,
|
||||
const_cast<std::shared_ptr<T>&>(data),
|
||||
[](std::shared_ptr<T> const&) { return true; });
|
||||
}
|
||||
|
||||
bool
|
||||
canonicalize_replace_client(const key_type& key, std::shared_ptr<T>& data)
|
||||
{
|
||||
return canonicalize(
|
||||
key, data, [](std::shared_ptr<T> const&) { return false; });
|
||||
}
|
||||
|
||||
std::shared_ptr<T>
|
||||
fetch(const key_type& key)
|
||||
{
|
||||
std::lock_guard<mutex_type> l(m_mutex);
|
||||
auto ret = initialFetch(key, l);
|
||||
if (!ret)
|
||||
++m_misses;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Insert the element into the container.
|
||||
If the key already exists, nothing happens.
|
||||
@return `true` If the element was inserted
|
||||
*/
|
||||
template <class ReturnType = bool>
|
||||
auto
|
||||
insert(key_type const& key, T const& value)
|
||||
-> std::enable_if_t<!IsKeyCache, ReturnType>
|
||||
{
|
||||
auto p = std::make_shared<T>(std::cref(value));
|
||||
return canonicalize_replace_client(key, p);
|
||||
}
|
||||
|
||||
template <class ReturnType = bool>
|
||||
auto
|
||||
insert(key_type const& key) -> std::enable_if_t<IsKeyCache, ReturnType>
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
clock_type::time_point const now(m_clock.now());
|
||||
auto [it, inserted] = m_cache.emplace(
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(key),
|
||||
std::forward_as_tuple(now));
|
||||
if (!inserted)
|
||||
it->second.last_access = now;
|
||||
return inserted;
|
||||
}
|
||||
|
||||
// VFALCO NOTE It looks like this returns a copy of the data in
|
||||
// the output parameter 'data'. This could be expensive.
|
||||
// Perhaps it should work like standard containers, which
|
||||
// simply return an iterator.
|
||||
//
|
||||
bool
|
||||
retrieve(const key_type& key, T& data)
|
||||
{
|
||||
// retrieve the value of the stored data
|
||||
auto entry = fetch(key);
|
||||
|
||||
if (!entry)
|
||||
return false;
|
||||
|
||||
data = *entry;
|
||||
return true;
|
||||
}
|
||||
|
||||
mutex_type&
|
||||
peekMutex()
|
||||
{
|
||||
return m_mutex;
|
||||
}
|
||||
|
||||
std::vector<key_type>
|
||||
getKeys() const
|
||||
{
|
||||
std::vector<key_type> v;
|
||||
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
v.reserve(m_cache.size());
|
||||
for (auto const& _ : m_cache)
|
||||
v.push_back(_.first);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
// CachedSLEs functions.
|
||||
/** Returns the fraction of cache hits. */
|
||||
double
|
||||
rate() const
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
auto const tot = m_hits + m_misses;
|
||||
if (tot == 0)
|
||||
return 0;
|
||||
return double(m_hits) / tot;
|
||||
}
|
||||
|
||||
/** Fetch an item from the cache.
|
||||
If the digest was not found, Handler
|
||||
will be called with this signature:
|
||||
std::shared_ptr<SLE const>(void)
|
||||
*/
|
||||
template <class Handler>
|
||||
std::shared_ptr<T>
|
||||
fetch(key_type const& digest, Handler const& h)
|
||||
{
|
||||
{
|
||||
std::lock_guard l(m_mutex);
|
||||
if (auto ret = initialFetch(digest, l))
|
||||
return ret;
|
||||
}
|
||||
|
||||
auto sle = h();
|
||||
if (!sle)
|
||||
return {};
|
||||
|
||||
std::lock_guard l(m_mutex);
|
||||
++m_misses;
|
||||
auto const [it, inserted] =
|
||||
m_cache.emplace(digest, Entry(m_clock.now(), std::move(sle)));
|
||||
if (!inserted)
|
||||
it->second.touch(m_clock.now());
|
||||
return it->second.ptr;
|
||||
}
|
||||
// End CachedSLEs functions.
|
||||
|
||||
private:
|
||||
std::shared_ptr<T>
|
||||
initialFetch(key_type const& key, std::lock_guard<mutex_type> const& l)
|
||||
{
|
||||
auto cit = m_cache.find(key);
|
||||
if (cit == m_cache.end())
|
||||
return {};
|
||||
|
||||
Entry& entry = cit->second;
|
||||
if (entry.isCached())
|
||||
{
|
||||
++m_hits;
|
||||
entry.touch(m_clock.now());
|
||||
return entry.ptr;
|
||||
}
|
||||
entry.ptr = entry.lock();
|
||||
if (entry.isCached())
|
||||
{
|
||||
// independent of cache size, so not counted as a hit
|
||||
++m_cache_count;
|
||||
entry.touch(m_clock.now());
|
||||
return entry.ptr;
|
||||
}
|
||||
|
||||
m_cache.erase(cit);
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
collect_metrics()
|
||||
{
|
||||
m_stats.size.set(getCacheSize());
|
||||
|
||||
{
|
||||
beast::insight::Gauge::value_type hit_rate(0);
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
auto const total(m_hits + m_misses);
|
||||
if (total != 0)
|
||||
hit_rate = (m_hits * 100) / total;
|
||||
}
|
||||
m_stats.hit_rate.set(hit_rate);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
struct Stats
|
||||
{
|
||||
template <class Handler>
|
||||
Stats(
|
||||
std::string const& prefix,
|
||||
Handler const& handler,
|
||||
beast::insight::Collector::ptr const& collector)
|
||||
: hook(collector->make_hook(handler))
|
||||
, size(collector->make_gauge(prefix, "size"))
|
||||
, hit_rate(collector->make_gauge(prefix, "hit_rate"))
|
||||
, hits(0)
|
||||
, misses(0)
|
||||
{
|
||||
}
|
||||
|
||||
beast::insight::Hook hook;
|
||||
beast::insight::Gauge size;
|
||||
beast::insight::Gauge hit_rate;
|
||||
|
||||
std::size_t hits;
|
||||
std::size_t misses;
|
||||
};
|
||||
|
||||
class KeyOnlyEntry
|
||||
{
|
||||
public:
|
||||
clock_type::time_point last_access;
|
||||
|
||||
explicit KeyOnlyEntry(clock_type::time_point const& last_access_)
|
||||
: last_access(last_access_)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
touch(clock_type::time_point const& now)
|
||||
{
|
||||
last_access = now;
|
||||
}
|
||||
};
|
||||
|
||||
class ValueEntry
|
||||
{
|
||||
public:
|
||||
std::shared_ptr<mapped_type> ptr;
|
||||
std::weak_ptr<mapped_type> weak_ptr;
|
||||
clock_type::time_point last_access;
|
||||
|
||||
ValueEntry(
|
||||
clock_type::time_point const& last_access_,
|
||||
std::shared_ptr<mapped_type> const& ptr_)
|
||||
: ptr(ptr_), weak_ptr(ptr_), last_access(last_access_)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
isWeak() const
|
||||
{
|
||||
return ptr == nullptr;
|
||||
}
|
||||
bool
|
||||
isCached() const
|
||||
{
|
||||
return ptr != nullptr;
|
||||
}
|
||||
bool
|
||||
isExpired() const
|
||||
{
|
||||
return weak_ptr.expired();
|
||||
}
|
||||
std::shared_ptr<mapped_type>
|
||||
lock()
|
||||
{
|
||||
return weak_ptr.lock();
|
||||
}
|
||||
void
|
||||
touch(clock_type::time_point const& now)
|
||||
{
|
||||
last_access = now;
|
||||
}
|
||||
};
|
||||
|
||||
typedef
|
||||
typename std::conditional<IsKeyCache, KeyOnlyEntry, ValueEntry>::type
|
||||
Entry;
|
||||
|
||||
using KeyOnlyCacheType =
|
||||
hardened_partitioned_hash_map<key_type, KeyOnlyEntry, Hash, KeyEqual>;
|
||||
|
||||
using KeyValueCacheType =
|
||||
hardened_partitioned_hash_map<key_type, ValueEntry, Hash, KeyEqual>;
|
||||
|
||||
using cache_type =
|
||||
hardened_partitioned_hash_map<key_type, Entry, Hash, KeyEqual>;
|
||||
|
||||
[[nodiscard]] std::thread
|
||||
sweepHelper(
|
||||
clock_type::time_point const& when_expire,
|
||||
[[maybe_unused]] clock_type::time_point const& now,
|
||||
typename KeyValueCacheType::map_type& partition,
|
||||
SweptPointersVector& stuffToSweep,
|
||||
std::atomic<int>& allRemovals,
|
||||
std::lock_guard<std::recursive_mutex> const&)
|
||||
{
|
||||
return std::thread([&, this]() {
|
||||
int cacheRemovals = 0;
|
||||
int mapRemovals = 0;
|
||||
|
||||
// Keep references to all the stuff we sweep
|
||||
// so that we can destroy them outside the lock.
|
||||
stuffToSweep.first.reserve(partition.size());
|
||||
stuffToSweep.second.reserve(partition.size());
|
||||
{
|
||||
auto cit = partition.begin();
|
||||
while (cit != partition.end())
|
||||
{
|
||||
if (cit->second.isWeak())
|
||||
{
|
||||
// weak
|
||||
if (cit->second.isExpired())
|
||||
{
|
||||
stuffToSweep.second.push_back(
|
||||
std::move(cit->second.weak_ptr));
|
||||
++mapRemovals;
|
||||
cit = partition.erase(cit);
|
||||
}
|
||||
else
|
||||
{
|
||||
++cit;
|
||||
}
|
||||
}
|
||||
else if (cit->second.last_access <= when_expire)
|
||||
{
|
||||
// strong, expired
|
||||
++cacheRemovals;
|
||||
if (cit->second.ptr.use_count() == 1)
|
||||
{
|
||||
stuffToSweep.first.push_back(
|
||||
std::move(cit->second.ptr));
|
||||
++mapRemovals;
|
||||
cit = partition.erase(cit);
|
||||
}
|
||||
else
|
||||
{
|
||||
// remains weakly cached
|
||||
cit->second.ptr.reset();
|
||||
++cit;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// strong, not expired
|
||||
++cit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mapRemovals || cacheRemovals)
|
||||
{
|
||||
JLOG(m_journal.debug())
|
||||
<< "TaggedCache partition sweep " << m_name
|
||||
<< ": cache = " << partition.size() << "-" << cacheRemovals
|
||||
<< ", map-=" << mapRemovals;
|
||||
}
|
||||
|
||||
allRemovals += cacheRemovals;
|
||||
});
|
||||
}
|
||||
|
||||
[[nodiscard]] std::thread
|
||||
sweepHelper(
|
||||
clock_type::time_point const& when_expire,
|
||||
clock_type::time_point const& now,
|
||||
typename KeyOnlyCacheType::map_type& partition,
|
||||
SweptPointersVector&,
|
||||
std::atomic<int>& allRemovals,
|
||||
std::lock_guard<std::recursive_mutex> const&)
|
||||
{
|
||||
return std::thread([&, this]() {
|
||||
int cacheRemovals = 0;
|
||||
int mapRemovals = 0;
|
||||
|
||||
// Keep references to all the stuff we sweep
|
||||
// so that we can destroy them outside the lock.
|
||||
{
|
||||
auto cit = partition.begin();
|
||||
while (cit != partition.end())
|
||||
{
|
||||
if (cit->second.last_access > now)
|
||||
{
|
||||
cit->second.last_access = now;
|
||||
++cit;
|
||||
}
|
||||
else if (cit->second.last_access <= when_expire)
|
||||
{
|
||||
cit = partition.erase(cit);
|
||||
}
|
||||
else
|
||||
{
|
||||
++cit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mapRemovals || cacheRemovals)
|
||||
{
|
||||
JLOG(m_journal.debug())
|
||||
<< "TaggedCache partition sweep " << m_name
|
||||
<< ": cache = " << partition.size() << "-" << cacheRemovals
|
||||
<< ", map-=" << mapRemovals;
|
||||
}
|
||||
|
||||
allRemovals += cacheRemovals;
|
||||
});
|
||||
};
|
||||
|
||||
beast::Journal m_journal;
|
||||
clock_type& m_clock;
|
||||
Stats m_stats;
|
||||
|
||||
mutex_type mutable m_mutex;
|
||||
|
||||
// Used for logging
|
||||
std::string m_name;
|
||||
|
||||
// Desired number of cache entries (0 = ignore)
|
||||
int m_target_size;
|
||||
|
||||
// Desired maximum cache age
|
||||
clock_type::duration m_target_age;
|
||||
|
||||
// Number of items cached
|
||||
int m_cache_count;
|
||||
cache_type m_cache; // Hold strong reference to recent objects
|
||||
std::uint64_t m_hits;
|
||||
std::uint64_t m_misses;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
63
include/xrpl/basics/ThreadSafetyAnalysis.h
Normal file
63
include/xrpl/basics/ThreadSafetyAnalysis.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#ifndef RIPPLE_BASICS_THREAD_SAFTY_ANALYSIS_H_INCLUDED
|
||||
#define RIPPLE_BASICS_THREAD_SAFTY_ANALYSIS_H_INCLUDED
|
||||
|
||||
#ifdef RIPPLE_ENABLE_THREAD_SAFETY_ANNOTATIONS
|
||||
#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
|
||||
#else
|
||||
#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
|
||||
#endif
|
||||
|
||||
#define CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
|
||||
|
||||
#define SCOPED_CAPABILITY THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
|
||||
|
||||
#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
|
||||
|
||||
#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
|
||||
|
||||
#define ACQUIRED_BEFORE(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
|
||||
|
||||
#define ACQUIRED_AFTER(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
|
||||
|
||||
#define REQUIRES(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
|
||||
|
||||
#define REQUIRES_SHARED(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define ACQUIRE(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
|
||||
|
||||
#define ACQUIRE_SHARED(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define RELEASE(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
|
||||
|
||||
#define RELEASE_SHARED(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define RELEASE_GENERIC(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(release_generic_capability(__VA_ARGS__))
|
||||
|
||||
#define TRY_ACQUIRE(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
|
||||
|
||||
#define TRY_ACQUIRE_SHARED(...) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define EXCLUDES(...) THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
|
||||
|
||||
#define ASSERT_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
|
||||
|
||||
#define ASSERT_SHARED_CAPABILITY(x) \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
|
||||
|
||||
#define RETURN_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
|
||||
|
||||
#define NO_THREAD_SAFETY_ANALYSIS \
|
||||
THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
|
||||
|
||||
#endif
|
||||
67
include/xrpl/basics/ToString.h
Normal file
67
include/xrpl/basics/ToString.h
Normal file
@@ -0,0 +1,67 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_TOSTRING_H_INCLUDED
|
||||
#define RIPPLE_BASICS_TOSTRING_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** to_string() generalizes std::to_string to handle bools, chars, and strings.
|
||||
|
||||
It's also possible to provide implementation of to_string for a class
|
||||
which needs a string implementation.
|
||||
*/
|
||||
|
||||
template <class T>
|
||||
typename std::enable_if<std::is_arithmetic<T>::value, std::string>::type
|
||||
to_string(T t)
|
||||
{
|
||||
return std::to_string(t);
|
||||
}
|
||||
|
||||
inline std::string
|
||||
to_string(bool b)
|
||||
{
|
||||
return b ? "true" : "false";
|
||||
}
|
||||
|
||||
inline std::string
|
||||
to_string(char c)
|
||||
{
|
||||
return std::string(1, c);
|
||||
}
|
||||
|
||||
inline std::string
|
||||
to_string(std::string s)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
inline std::string
|
||||
to_string(char const* s)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
125
include/xrpl/basics/UnorderedContainers.h
Normal file
125
include/xrpl/basics/UnorderedContainers.h
Normal file
@@ -0,0 +1,125 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_UNORDEREDCONTAINERS_H_INCLUDED
|
||||
#define RIPPLE_BASICS_UNORDEREDCONTAINERS_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/hardened_hash.h>
|
||||
#include <ripple/basics/partitioned_unordered_map.h>
|
||||
#include <ripple/beast/hash/hash_append.h>
|
||||
#include <ripple/beast/hash/uhash.h>
|
||||
#include <ripple/beast/hash/xxhasher.h>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
/**
|
||||
* Use hash_* containers for keys that do not need a cryptographically secure
|
||||
* hashing algorithm.
|
||||
*
|
||||
* Use hardened_hash_* containers for keys that do need a secure hashing
|
||||
* algorithm.
|
||||
*
|
||||
* The cryptographic security of containers where a hash function is used as a
|
||||
* template parameter depends entirely on that hash function and not at all on
|
||||
* what container it is.
|
||||
*/
|
||||
|
||||
namespace ripple {
|
||||
|
||||
// hash containers
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class Value,
|
||||
class Hash = beast::uhash<>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, Value>>>
|
||||
using hash_map = std::unordered_map<Key, Value, Hash, Pred, Allocator>;
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class Value,
|
||||
class Hash = beast::uhash<>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, Value>>>
|
||||
using hash_multimap =
|
||||
std::unordered_multimap<Key, Value, Hash, Pred, Allocator>;
|
||||
|
||||
template <
|
||||
class Value,
|
||||
class Hash = beast::uhash<>,
|
||||
class Pred = std::equal_to<Value>,
|
||||
class Allocator = std::allocator<Value>>
|
||||
using hash_set = std::unordered_set<Value, Hash, Pred, Allocator>;
|
||||
|
||||
template <
|
||||
class Value,
|
||||
class Hash = beast::uhash<>,
|
||||
class Pred = std::equal_to<Value>,
|
||||
class Allocator = std::allocator<Value>>
|
||||
using hash_multiset = std::unordered_multiset<Value, Hash, Pred, Allocator>;
|
||||
|
||||
// hardened_hash containers
|
||||
|
||||
using strong_hash = beast::xxhasher;
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class Value,
|
||||
class Hash = hardened_hash<strong_hash>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, Value>>>
|
||||
using hardened_hash_map = std::unordered_map<Key, Value, Hash, Pred, Allocator>;
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class Value,
|
||||
class Hash = hardened_hash<strong_hash>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, Value>>>
|
||||
using hardened_partitioned_hash_map =
|
||||
partitioned_unordered_map<Key, Value, Hash, Pred, Allocator>;
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class Value,
|
||||
class Hash = hardened_hash<strong_hash>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, Value>>>
|
||||
using hardened_hash_multimap =
|
||||
std::unordered_multimap<Key, Value, Hash, Pred, Allocator>;
|
||||
|
||||
template <
|
||||
class Value,
|
||||
class Hash = hardened_hash<strong_hash>,
|
||||
class Pred = std::equal_to<Value>,
|
||||
class Allocator = std::allocator<Value>>
|
||||
using hardened_hash_set = std::unordered_set<Value, Hash, Pred, Allocator>;
|
||||
|
||||
template <
|
||||
class Value,
|
||||
class Hash = hardened_hash<strong_hash>,
|
||||
class Pred = std::equal_to<Value>,
|
||||
class Allocator = std::allocator<Value>>
|
||||
using hardened_hash_multiset =
|
||||
std::unordered_multiset<Value, Hash, Pred, Allocator>;
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
69
include/xrpl/basics/UptimeClock.h
Normal file
69
include/xrpl/basics/UptimeClock.h
Normal file
@@ -0,0 +1,69 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_UPTIMETIMER_H_INCLUDED
|
||||
#define RIPPLE_BASICS_UPTIMETIMER_H_INCLUDED
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <ratio>
|
||||
#include <thread>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** Tracks program uptime to seconds precision.
|
||||
|
||||
The timer caches the current time as a performance optimization.
|
||||
This allows clients to query the current time thousands of times
|
||||
per second.
|
||||
*/
|
||||
|
||||
class UptimeClock
|
||||
{
|
||||
public:
|
||||
using rep = int;
|
||||
using period = std::ratio<1>;
|
||||
using duration = std::chrono::duration<rep, period>;
|
||||
using time_point = std::chrono::time_point<UptimeClock>;
|
||||
static constexpr bool is_steady = std::chrono::system_clock::is_steady;
|
||||
|
||||
explicit UptimeClock() = default;
|
||||
|
||||
static time_point
|
||||
now(); // seconds since rippled program start
|
||||
|
||||
private:
|
||||
static std::atomic<rep> now_;
|
||||
static std::atomic<bool> stop_;
|
||||
|
||||
struct update_thread : private std::thread
|
||||
{
|
||||
~update_thread();
|
||||
update_thread(update_thread&&) = default;
|
||||
|
||||
using std::thread::thread;
|
||||
};
|
||||
|
||||
static update_thread
|
||||
start_clock();
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
302
include/xrpl/basics/XRPAmount.h
Normal file
302
include/xrpl/basics/XRPAmount.h
Normal file
@@ -0,0 +1,302 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_XRPAMOUNT_H_INCLUDED
|
||||
#define RIPPLE_BASICS_XRPAMOUNT_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <ripple/basics/safe_cast.h>
|
||||
#include <ripple/beast/utility/Zero.h>
|
||||
#include <ripple/json/json_value.h>
|
||||
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
#include <boost/operators.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
namespace feeunit {
|
||||
|
||||
/** "drops" are the smallest divisible amount of XRP. This is what most
|
||||
of the code uses. */
|
||||
struct dropTag;
|
||||
|
||||
} // namespace feeunit
|
||||
|
||||
class XRPAmount : private boost::totally_ordered<XRPAmount>,
|
||||
private boost::additive<XRPAmount>,
|
||||
private boost::equality_comparable<XRPAmount, std::int64_t>,
|
||||
private boost::additive<XRPAmount, std::int64_t>
|
||||
{
|
||||
public:
|
||||
using unit_type = feeunit::dropTag;
|
||||
using value_type = std::int64_t;
|
||||
|
||||
private:
|
||||
value_type drops_;
|
||||
|
||||
public:
|
||||
XRPAmount() = default;
|
||||
constexpr XRPAmount(XRPAmount const& other) = default;
|
||||
constexpr XRPAmount&
|
||||
operator=(XRPAmount const& other) = default;
|
||||
|
||||
constexpr XRPAmount(beast::Zero) : drops_(0)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr XRPAmount& operator=(beast::Zero)
|
||||
{
|
||||
drops_ = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr explicit XRPAmount(value_type drops) : drops_(drops)
|
||||
{
|
||||
}
|
||||
|
||||
XRPAmount&
|
||||
operator=(value_type drops)
|
||||
{
|
||||
drops_ = drops;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr XRPAmount
|
||||
operator*(value_type const& rhs) const
|
||||
{
|
||||
return XRPAmount{drops_ * rhs};
|
||||
}
|
||||
|
||||
friend constexpr XRPAmount
|
||||
operator*(value_type lhs, XRPAmount const& rhs)
|
||||
{
|
||||
// multiplication is commutative
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
XRPAmount&
|
||||
operator+=(XRPAmount const& other)
|
||||
{
|
||||
drops_ += other.drops();
|
||||
return *this;
|
||||
}
|
||||
|
||||
XRPAmount&
|
||||
operator-=(XRPAmount const& other)
|
||||
{
|
||||
drops_ -= other.drops();
|
||||
return *this;
|
||||
}
|
||||
|
||||
XRPAmount&
|
||||
operator+=(value_type const& rhs)
|
||||
{
|
||||
drops_ += rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
XRPAmount&
|
||||
operator-=(value_type const& rhs)
|
||||
{
|
||||
drops_ -= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
XRPAmount&
|
||||
operator*=(value_type const& rhs)
|
||||
{
|
||||
drops_ *= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
XRPAmount
|
||||
operator-() const
|
||||
{
|
||||
return XRPAmount{-drops_};
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(XRPAmount const& other) const
|
||||
{
|
||||
return drops_ == other.drops_;
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(value_type other) const
|
||||
{
|
||||
return drops_ == other;
|
||||
}
|
||||
|
||||
bool
|
||||
operator<(XRPAmount const& other) const
|
||||
{
|
||||
return drops_ < other.drops_;
|
||||
}
|
||||
|
||||
/** Returns true if the amount is not zero */
|
||||
explicit constexpr operator bool() const noexcept
|
||||
{
|
||||
return drops_ != 0;
|
||||
}
|
||||
|
||||
/** Return the sign of the amount */
|
||||
constexpr int
|
||||
signum() const noexcept
|
||||
{
|
||||
return (drops_ < 0) ? -1 : (drops_ ? 1 : 0);
|
||||
}
|
||||
|
||||
/** Returns the number of drops */
|
||||
constexpr value_type
|
||||
drops() const
|
||||
{
|
||||
return drops_;
|
||||
}
|
||||
|
||||
constexpr double
|
||||
decimalXRP() const;
|
||||
|
||||
template <class Dest>
|
||||
std::optional<Dest>
|
||||
dropsAs() const
|
||||
{
|
||||
if ((drops_ > std::numeric_limits<Dest>::max()) ||
|
||||
(!std::numeric_limits<Dest>::is_signed && drops_ < 0) ||
|
||||
(std::numeric_limits<Dest>::is_signed &&
|
||||
drops_ < std::numeric_limits<Dest>::lowest()))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
return static_cast<Dest>(drops_);
|
||||
}
|
||||
|
||||
template <class Dest>
|
||||
Dest
|
||||
dropsAs(Dest defaultValue) const
|
||||
{
|
||||
return dropsAs<Dest>().value_or(defaultValue);
|
||||
}
|
||||
|
||||
template <class Dest>
|
||||
Dest
|
||||
dropsAs(XRPAmount defaultValue) const
|
||||
{
|
||||
return dropsAs<Dest>().value_or(defaultValue.drops());
|
||||
}
|
||||
|
||||
Json::Value
|
||||
jsonClipped() const
|
||||
{
|
||||
static_assert(
|
||||
std::is_signed_v<value_type> && std::is_integral_v<value_type>,
|
||||
"Expected XRPAmount to be a signed integral type");
|
||||
|
||||
constexpr auto min = std::numeric_limits<Json::Int>::min();
|
||||
constexpr auto max = std::numeric_limits<Json::Int>::max();
|
||||
|
||||
if (drops_ < min)
|
||||
return min;
|
||||
if (drops_ > max)
|
||||
return max;
|
||||
return static_cast<Json::Int>(drops_);
|
||||
}
|
||||
|
||||
/** Returns the underlying value. Code SHOULD NOT call this
|
||||
function unless the type has been abstracted away,
|
||||
e.g. in a templated function.
|
||||
*/
|
||||
constexpr value_type
|
||||
value() const
|
||||
{
|
||||
return drops_;
|
||||
}
|
||||
|
||||
friend std::istream&
|
||||
operator>>(std::istream& s, XRPAmount& val)
|
||||
{
|
||||
s >> val.drops_;
|
||||
return s;
|
||||
}
|
||||
|
||||
static XRPAmount
|
||||
minPositiveAmount()
|
||||
{
|
||||
return XRPAmount{1};
|
||||
}
|
||||
};
|
||||
|
||||
/** Number of drops per 1 XRP */
|
||||
constexpr XRPAmount DROPS_PER_XRP{1'000'000};
|
||||
|
||||
constexpr double
|
||||
XRPAmount::decimalXRP() const
|
||||
{
|
||||
return static_cast<double>(drops_) / DROPS_PER_XRP.drops();
|
||||
}
|
||||
|
||||
// Output XRPAmount as just the drops value.
|
||||
template <class Char, class Traits>
|
||||
std::basic_ostream<Char, Traits>&
|
||||
operator<<(std::basic_ostream<Char, Traits>& os, const XRPAmount& q)
|
||||
{
|
||||
return os << q.drops();
|
||||
}
|
||||
|
||||
inline std::string
|
||||
to_string(XRPAmount const& amount)
|
||||
{
|
||||
return std::to_string(amount.drops());
|
||||
}
|
||||
|
||||
inline XRPAmount
|
||||
mulRatio(
|
||||
XRPAmount const& amt,
|
||||
std::uint32_t num,
|
||||
std::uint32_t den,
|
||||
bool roundUp)
|
||||
{
|
||||
using namespace boost::multiprecision;
|
||||
|
||||
if (!den)
|
||||
Throw<std::runtime_error>("division by zero");
|
||||
|
||||
int128_t const amt128(amt.drops());
|
||||
auto const neg = amt.drops() < 0;
|
||||
auto const m = amt128 * num;
|
||||
auto r = m / den;
|
||||
if (m % den)
|
||||
{
|
||||
if (!neg && roundUp)
|
||||
r += 1;
|
||||
if (neg && !roundUp)
|
||||
r -= 1;
|
||||
}
|
||||
if (r > std::numeric_limits<XRPAmount::value_type>::max())
|
||||
Throw<std::overflow_error>("XRP mulRatio overflow");
|
||||
return XRPAmount(r.convert_to<XRPAmount::value_type>());
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif // RIPPLE_BASICS_XRPAMOUNT_H_INCLUDED
|
||||
120
include/xrpl/basics/algorithm.h
Normal file
120
include/xrpl/basics/algorithm.h
Normal file
@@ -0,0 +1,120 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2019 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_ALGORITHM_H_INCLUDED
|
||||
#define RIPPLE_ALGORITHM_H_INCLUDED
|
||||
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
// Requires: [first1, last1) and [first2, last2) are ordered ranges according to
|
||||
// comp.
|
||||
|
||||
// Effects: For each pair of elements {i, j} in the intersection of the sorted
|
||||
// sequences [first1, last1) and [first2, last2), perform action(i, j).
|
||||
|
||||
// Note: This algorithm is evolved from std::set_intersection.
|
||||
template <class InputIter1, class InputIter2, class Action, class Comp>
|
||||
void
|
||||
generalized_set_intersection(
|
||||
InputIter1 first1,
|
||||
InputIter1 last1,
|
||||
InputIter2 first2,
|
||||
InputIter2 last2,
|
||||
Action action,
|
||||
Comp comp)
|
||||
{
|
||||
while (first1 != last1 && first2 != last2)
|
||||
{
|
||||
if (comp(*first1, *first2)) // if *first1 < *first2
|
||||
++first1; // then reduce first range
|
||||
else
|
||||
{
|
||||
if (!comp(*first2, *first1)) // if *first1 == *first2
|
||||
{ // then this is an intersection
|
||||
action(*first1, *first2); // do the action
|
||||
++first1; // reduce first range
|
||||
}
|
||||
++first2; // Reduce second range because *first2 <= *first1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Requires: [first1, last1) and [first2, last2) are ordered ranges according to
|
||||
// comp.
|
||||
|
||||
// Effects: Eliminates all the elements i in the range [first1, last1) which are
|
||||
// equivalent to some value in [first2, last2) or for which pred(i) returns
|
||||
// true.
|
||||
|
||||
// Returns: A FwdIter1 E such that [first1, E) is the range of elements not
|
||||
// removed by this algorithm.
|
||||
|
||||
// Note: This algorithm is evolved from std::remove_if and
|
||||
// std::set_intersection.
|
||||
template <class FwdIter1, class InputIter2, class Pred, class Comp>
|
||||
FwdIter1
|
||||
remove_if_intersect_or_match(
|
||||
FwdIter1 first1,
|
||||
FwdIter1 last1,
|
||||
InputIter2 first2,
|
||||
InputIter2 last2,
|
||||
Pred pred,
|
||||
Comp comp)
|
||||
{
|
||||
// [original-first1, current-first1) is the set of elements to be preserved.
|
||||
// [current-first1, i) is the set of elements that have been removed.
|
||||
// [i, last1) is the set of elements not tested yet.
|
||||
|
||||
// Test each *i in [first1, last1) against [first2, last2) and pred
|
||||
for (auto i = first1; i != last1;)
|
||||
{
|
||||
// if (*i is not in [first2, last2)
|
||||
if (first2 == last2 || comp(*i, *first2))
|
||||
{
|
||||
if (!pred(*i))
|
||||
{
|
||||
// *i should not be removed, so append it to the preserved set
|
||||
if (i != first1)
|
||||
*first1 = std::move(*i);
|
||||
++first1;
|
||||
}
|
||||
// *i has been fully tested, prepare for next i by
|
||||
// appending i to the removed set, whether or not
|
||||
// it has been moved from above.
|
||||
++i;
|
||||
}
|
||||
else // *i might be in [first2, last2) because *i >= *first2
|
||||
{
|
||||
if (!comp(*first2, *i)) // if *i == *first2
|
||||
++i; // then append *i to the removed set
|
||||
// All elements in [i, last1) are known to be greater than *first2,
|
||||
// so reduce the second range.
|
||||
++first2;
|
||||
}
|
||||
// Continue to test *i against [first2, last2) and pred
|
||||
}
|
||||
return first1;
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
80
include/xrpl/basics/base64.h
Normal file
80
include/xrpl/basics/base64.h
Normal file
@@ -0,0 +1,80 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012-2018 Ripple Labs Inc.
|
||||
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
//
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
/*
|
||||
Portions from http://www.adp-gmbh.ch/cpp/common/base64.html
|
||||
Copyright notice:
|
||||
|
||||
base64.cpp and base64.h
|
||||
|
||||
Copyright (C) 2004-2008 René Nyffenegger
|
||||
|
||||
This source code is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the author be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this source code must not be misrepresented; you must not
|
||||
claim that you wrote the original source code. If you use this source code
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original source code.
|
||||
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
|
||||
|
||||
*/
|
||||
|
||||
#ifndef RIPPLE_BASICS_BASE64_H_INCLUDED
|
||||
#define RIPPLE_BASICS_BASE64_H_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
std::string
|
||||
base64_encode(std::uint8_t const* data, std::size_t len);
|
||||
|
||||
inline std::string
|
||||
base64_encode(std::string const& s)
|
||||
{
|
||||
return base64_encode(
|
||||
reinterpret_cast<std::uint8_t const*>(s.data()), s.size());
|
||||
}
|
||||
|
||||
std::string
|
||||
base64_decode(std::string_view data);
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
652
include/xrpl/basics/base_uint.h
Normal file
652
include/xrpl/basics/base_uint.h
Normal file
@@ -0,0 +1,652 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2011 The Bitcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef RIPPLE_BASICS_BASE_UINT_H_INCLUDED
|
||||
#define RIPPLE_BASICS_BASE_UINT_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/Expected.h>
|
||||
#include <ripple/basics/Slice.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <ripple/basics/hardened_hash.h>
|
||||
#include <ripple/basics/strHex.h>
|
||||
#include <ripple/beast/utility/Zero.h>
|
||||
#include <boost/endian/conversion.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class Container, class = std::void_t<>>
|
||||
struct is_contiguous_container : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class Container>
|
||||
struct is_contiguous_container<
|
||||
Container,
|
||||
std::void_t<
|
||||
decltype(std::declval<Container const>().size()),
|
||||
decltype(std::declval<Container const>().data()),
|
||||
typename Container::value_type>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <>
|
||||
struct is_contiguous_container<Slice> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/** Integers of any length that is a multiple of 32-bits
|
||||
|
||||
@note This class stores its values internally in big-endian
|
||||
form and that internal representation is part of the
|
||||
binary protocol of the XRP Ledger and cannot be changed
|
||||
arbitrarily without causing breakage.
|
||||
|
||||
@tparam Bits The number of bits this integer should have; must
|
||||
be at least 64 and a multiple of 32.
|
||||
@tparam Tag An arbitrary type that functions as a tag and allows
|
||||
the instantiation of "distinct" types that the same
|
||||
number of bits.
|
||||
*/
|
||||
template <std::size_t Bits, class Tag = void>
|
||||
class base_uint
|
||||
{
|
||||
static_assert(
|
||||
(Bits % 32) == 0,
|
||||
"The length of a base_uint in bits must be a multiple of 32.");
|
||||
|
||||
static_assert(
|
||||
Bits >= 64,
|
||||
"The length of a base_uint in bits must be at least 64.");
|
||||
|
||||
static constexpr std::size_t WIDTH = Bits / 32;
|
||||
|
||||
// This is really big-endian in byte order.
|
||||
// We sometimes use std::uint32_t for speed.
|
||||
|
||||
std::array<std::uint32_t, WIDTH> data_;
|
||||
|
||||
public:
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// STL Container Interface
|
||||
//
|
||||
|
||||
static std::size_t constexpr bytes = Bits / 8;
|
||||
static_assert(sizeof(data_) == bytes, "");
|
||||
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = unsigned char;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
using const_pointer = value_type const*;
|
||||
using const_reference = value_type const&;
|
||||
using iterator = pointer;
|
||||
using const_iterator = const_pointer;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
using tag_type = Tag;
|
||||
|
||||
pointer
|
||||
data()
|
||||
{
|
||||
return reinterpret_cast<pointer>(data_.data());
|
||||
}
|
||||
const_pointer
|
||||
data() const
|
||||
{
|
||||
return reinterpret_cast<const_pointer>(data_.data());
|
||||
}
|
||||
|
||||
iterator
|
||||
begin()
|
||||
{
|
||||
return data();
|
||||
}
|
||||
iterator
|
||||
end()
|
||||
{
|
||||
return data() + bytes;
|
||||
}
|
||||
const_iterator
|
||||
begin() const
|
||||
{
|
||||
return data();
|
||||
}
|
||||
const_iterator
|
||||
end() const
|
||||
{
|
||||
return data() + bytes;
|
||||
}
|
||||
const_iterator
|
||||
cbegin() const
|
||||
{
|
||||
return data();
|
||||
}
|
||||
const_iterator
|
||||
cend() const
|
||||
{
|
||||
return data() + bytes;
|
||||
}
|
||||
|
||||
/** Value hashing function.
|
||||
The seed prevents crafted inputs from causing degenerate parent
|
||||
containers.
|
||||
*/
|
||||
using hasher = hardened_hash<>;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
/** Construct from a raw pointer.
|
||||
The buffer pointed to by `data` must be at least Bits/8 bytes.
|
||||
|
||||
@note the structure is used to disambiguate this from the std::uint64_t
|
||||
constructor: something like base_uint(0) is ambiguous.
|
||||
*/
|
||||
// NIKB TODO Remove the need for this constructor.
|
||||
struct VoidHelper
|
||||
{
|
||||
explicit VoidHelper() = default;
|
||||
};
|
||||
|
||||
explicit base_uint(void const* data, VoidHelper)
|
||||
{
|
||||
memcpy(data_.data(), data, bytes);
|
||||
}
|
||||
|
||||
// Helper function to initialize a base_uint from a std::string_view.
|
||||
enum class ParseResult {
|
||||
okay,
|
||||
badLength,
|
||||
badChar,
|
||||
};
|
||||
|
||||
constexpr Expected<decltype(data_), ParseResult>
|
||||
parseFromStringView(std::string_view sv) noexcept
|
||||
{
|
||||
// Local lambda that converts a single hex char to four bits and
|
||||
// ORs those bits into a uint32_t.
|
||||
auto hexCharToUInt = [](char c,
|
||||
std::uint32_t shift,
|
||||
std::uint32_t& accum) -> ParseResult {
|
||||
std::uint32_t nibble = 0xFFu;
|
||||
if (c < '0' || c > 'f')
|
||||
return ParseResult::badChar;
|
||||
|
||||
if (c >= 'a')
|
||||
nibble = static_cast<std::uint32_t>(c - 'a' + 0xA);
|
||||
else if (c >= 'A')
|
||||
nibble = static_cast<std::uint32_t>(c - 'A' + 0xA);
|
||||
else if (c <= '9')
|
||||
nibble = static_cast<std::uint32_t>(c - '0');
|
||||
|
||||
if (nibble > 0xFu)
|
||||
return ParseResult::badChar;
|
||||
|
||||
accum |= (nibble << shift);
|
||||
|
||||
return ParseResult::okay;
|
||||
};
|
||||
|
||||
decltype(data_) ret{};
|
||||
|
||||
if (sv == "0")
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (sv.size() != size() * 2)
|
||||
return Unexpected(ParseResult::badLength);
|
||||
|
||||
std::size_t i = 0u;
|
||||
auto in = sv.begin();
|
||||
while (in != sv.end())
|
||||
{
|
||||
std::uint32_t accum = {};
|
||||
for (std::uint32_t shift : {4u, 0u, 12u, 8u, 20u, 16u, 28u, 24u})
|
||||
{
|
||||
if (auto const result = hexCharToUInt(*in++, shift, accum);
|
||||
result != ParseResult::okay)
|
||||
return Unexpected(result);
|
||||
}
|
||||
ret[i++] = accum;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
constexpr decltype(data_)
|
||||
parseFromStringViewThrows(std::string_view sv) noexcept(false)
|
||||
{
|
||||
auto const result = parseFromStringView(sv);
|
||||
if (!result)
|
||||
{
|
||||
if (result.error() == ParseResult::badLength)
|
||||
Throw<std::invalid_argument>("invalid length for hex string");
|
||||
|
||||
Throw<std::range_error>("invalid hex character");
|
||||
}
|
||||
return *result;
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr base_uint() : data_{}
|
||||
{
|
||||
}
|
||||
|
||||
constexpr base_uint(beast::Zero) : data_{}
|
||||
{
|
||||
}
|
||||
|
||||
explicit base_uint(std::uint64_t b)
|
||||
{
|
||||
*this = b;
|
||||
}
|
||||
|
||||
// This constructor is intended to be used at compile time since it might
|
||||
// throw at runtime. Consider declaring this constructor consteval once
|
||||
// we get to C++23.
|
||||
explicit constexpr base_uint(std::string_view sv) noexcept(false)
|
||||
: data_(parseFromStringViewThrows(sv))
|
||||
{
|
||||
}
|
||||
|
||||
template <
|
||||
class Container,
|
||||
class = std::enable_if_t<
|
||||
detail::is_contiguous_container<Container>::value &&
|
||||
std::is_trivially_copyable<typename Container::value_type>::value>>
|
||||
explicit base_uint(Container const& c)
|
||||
{
|
||||
assert(c.size() * sizeof(typename Container::value_type) == size());
|
||||
std::memcpy(data_.data(), c.data(), size());
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
std::enable_if_t<
|
||||
detail::is_contiguous_container<Container>::value &&
|
||||
std::is_trivially_copyable<typename Container::value_type>::value,
|
||||
base_uint&>
|
||||
operator=(Container const& c)
|
||||
{
|
||||
assert(c.size() * sizeof(typename Container::value_type) == size());
|
||||
std::memcpy(data_.data(), c.data(), size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* Construct from a raw pointer.
|
||||
The buffer pointed to by `data` must be at least Bits/8 bytes.
|
||||
*/
|
||||
static base_uint
|
||||
fromVoid(void const* data)
|
||||
{
|
||||
return base_uint(data, VoidHelper());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static std::optional<base_uint>
|
||||
fromVoidChecked(T const& from)
|
||||
{
|
||||
if (from.size() != size())
|
||||
return {};
|
||||
return fromVoid(from.data());
|
||||
}
|
||||
|
||||
constexpr int
|
||||
signum() const
|
||||
{
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
if (data_[i] != 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
operator!() const
|
||||
{
|
||||
return *this == beast::zero;
|
||||
}
|
||||
|
||||
constexpr base_uint
|
||||
operator~() const
|
||||
{
|
||||
base_uint ret;
|
||||
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
ret.data_[i] = ~data_[i];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
base_uint&
|
||||
operator=(std::uint64_t uHost)
|
||||
{
|
||||
*this = beast::zero;
|
||||
union
|
||||
{
|
||||
unsigned u[2];
|
||||
std::uint64_t ul;
|
||||
};
|
||||
// Put in least significant bits.
|
||||
ul = boost::endian::native_to_big(uHost);
|
||||
data_[WIDTH - 2] = u[0];
|
||||
data_[WIDTH - 1] = u[1];
|
||||
return *this;
|
||||
}
|
||||
|
||||
base_uint&
|
||||
operator^=(const base_uint& b)
|
||||
{
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
data_[i] ^= b.data_[i];
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
base_uint&
|
||||
operator&=(const base_uint& b)
|
||||
{
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
data_[i] &= b.data_[i];
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
base_uint&
|
||||
operator|=(const base_uint& b)
|
||||
{
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
data_[i] |= b.data_[i];
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
base_uint&
|
||||
operator++()
|
||||
{
|
||||
// prefix operator
|
||||
for (int i = WIDTH - 1; i >= 0; --i)
|
||||
{
|
||||
data_[i] = boost::endian::native_to_big(
|
||||
boost::endian::big_to_native(data_[i]) + 1);
|
||||
if (data_[i] != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const base_uint
|
||||
operator++(int)
|
||||
{
|
||||
// postfix operator
|
||||
const base_uint ret = *this;
|
||||
++(*this);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
base_uint&
|
||||
operator--()
|
||||
{
|
||||
for (int i = WIDTH - 1; i >= 0; --i)
|
||||
{
|
||||
auto prev = data_[i];
|
||||
data_[i] = boost::endian::native_to_big(
|
||||
boost::endian::big_to_native(data_[i]) - 1);
|
||||
|
||||
if (prev != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const base_uint
|
||||
operator--(int)
|
||||
{
|
||||
// postfix operator
|
||||
const base_uint ret = *this;
|
||||
--(*this);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
base_uint
|
||||
next() const
|
||||
{
|
||||
auto ret = *this;
|
||||
return ++ret;
|
||||
}
|
||||
|
||||
base_uint
|
||||
prev() const
|
||||
{
|
||||
auto ret = *this;
|
||||
return --ret;
|
||||
}
|
||||
|
||||
base_uint&
|
||||
operator+=(const base_uint& b)
|
||||
{
|
||||
std::uint64_t carry = 0;
|
||||
|
||||
for (int i = WIDTH; i--;)
|
||||
{
|
||||
std::uint64_t n = carry + boost::endian::big_to_native(data_[i]) +
|
||||
boost::endian::big_to_native(b.data_[i]);
|
||||
|
||||
data_[i] =
|
||||
boost::endian::native_to_big(static_cast<std::uint32_t>(n));
|
||||
carry = n >> 32;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class Hasher>
|
||||
friend void
|
||||
hash_append(Hasher& h, base_uint const& a) noexcept
|
||||
{
|
||||
// Do not allow any endian transformations on this memory
|
||||
h(a.data_.data(), sizeof(a.data_));
|
||||
}
|
||||
|
||||
/** Parse a hex string into a base_uint
|
||||
|
||||
The input must be precisely `2 * bytes` hexadecimal characters
|
||||
long, with one exception: the value '0'.
|
||||
|
||||
@param sv A null-terminated string of hexadecimal characters
|
||||
@return true if the input was parsed properly; false otherwise.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool
|
||||
parseHex(std::string_view sv)
|
||||
{
|
||||
auto const result = parseFromStringView(sv);
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
data_ = *result;
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool
|
||||
parseHex(const char* str)
|
||||
{
|
||||
return parseHex(std::string_view{str});
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
parseHex(std::string const& str)
|
||||
{
|
||||
return parseHex(std::string_view{str});
|
||||
}
|
||||
|
||||
constexpr static std::size_t
|
||||
size()
|
||||
{
|
||||
return bytes;
|
||||
}
|
||||
|
||||
base_uint<Bits, Tag>& operator=(beast::Zero)
|
||||
{
|
||||
data_.fill(0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Deprecated.
|
||||
bool
|
||||
isZero() const
|
||||
{
|
||||
return *this == beast::zero;
|
||||
}
|
||||
bool
|
||||
isNonZero() const
|
||||
{
|
||||
return *this != beast::zero;
|
||||
}
|
||||
void
|
||||
zero()
|
||||
{
|
||||
*this = beast::zero;
|
||||
}
|
||||
};
|
||||
|
||||
using uint128 = base_uint<128>;
|
||||
using uint160 = base_uint<160>;
|
||||
using uint256 = base_uint<256>;
|
||||
|
||||
template <std::size_t Bits, class Tag>
|
||||
[[nodiscard]] inline constexpr std::strong_ordering
|
||||
operator<=>(base_uint<Bits, Tag> const& lhs, base_uint<Bits, Tag> const& rhs)
|
||||
{
|
||||
// This comparison might seem wrong on a casual inspection because it
|
||||
// compares data internally stored as std::uint32_t byte-by-byte. But
|
||||
// note that the underlying data is stored in big endian, even if the
|
||||
// plaform is little endian. This makes the comparison correct.
|
||||
//
|
||||
// FIXME: use std::lexicographical_compare_three_way once support is
|
||||
// added to MacOS.
|
||||
|
||||
auto const ret = std::mismatch(lhs.cbegin(), lhs.cend(), rhs.cbegin());
|
||||
|
||||
// a == b
|
||||
if (ret.first == lhs.cend())
|
||||
return std::strong_ordering::equivalent;
|
||||
|
||||
return (*ret.first > *ret.second) ? std::strong_ordering::greater
|
||||
: std::strong_ordering::less;
|
||||
}
|
||||
|
||||
template <std::size_t Bits, typename Tag>
|
||||
[[nodiscard]] inline constexpr bool
|
||||
operator==(base_uint<Bits, Tag> const& lhs, base_uint<Bits, Tag> const& rhs)
|
||||
{
|
||||
return (lhs <=> rhs) == 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <std::size_t Bits, class Tag>
|
||||
inline constexpr bool
|
||||
operator==(base_uint<Bits, Tag> const& a, std::uint64_t b)
|
||||
{
|
||||
return a == base_uint<Bits, Tag>(b);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <std::size_t Bits, class Tag>
|
||||
inline constexpr base_uint<Bits, Tag>
|
||||
operator^(base_uint<Bits, Tag> const& a, base_uint<Bits, Tag> const& b)
|
||||
{
|
||||
return base_uint<Bits, Tag>(a) ^= b;
|
||||
}
|
||||
|
||||
template <std::size_t Bits, class Tag>
|
||||
inline constexpr base_uint<Bits, Tag>
|
||||
operator&(base_uint<Bits, Tag> const& a, base_uint<Bits, Tag> const& b)
|
||||
{
|
||||
return base_uint<Bits, Tag>(a) &= b;
|
||||
}
|
||||
|
||||
template <std::size_t Bits, class Tag>
|
||||
inline constexpr base_uint<Bits, Tag>
|
||||
operator|(base_uint<Bits, Tag> const& a, base_uint<Bits, Tag> const& b)
|
||||
{
|
||||
return base_uint<Bits, Tag>(a) |= b;
|
||||
}
|
||||
|
||||
template <std::size_t Bits, class Tag>
|
||||
inline constexpr base_uint<Bits, Tag>
|
||||
operator+(base_uint<Bits, Tag> const& a, base_uint<Bits, Tag> const& b)
|
||||
{
|
||||
return base_uint<Bits, Tag>(a) += b;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <std::size_t Bits, class Tag>
|
||||
inline std::string
|
||||
to_string(base_uint<Bits, Tag> const& a)
|
||||
{
|
||||
return strHex(a.cbegin(), a.cend());
|
||||
}
|
||||
|
||||
template <std::size_t Bits, class Tag>
|
||||
inline std::ostream&
|
||||
operator<<(std::ostream& out, base_uint<Bits, Tag> const& u)
|
||||
{
|
||||
return out << to_string(u);
|
||||
}
|
||||
|
||||
#ifndef __INTELLISENSE__
|
||||
static_assert(sizeof(uint128) == 128 / 8, "There should be no padding bytes");
|
||||
static_assert(sizeof(uint160) == 160 / 8, "There should be no padding bytes");
|
||||
static_assert(sizeof(uint256) == 256 / 8, "There should be no padding bytes");
|
||||
#endif
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
namespace beast {
|
||||
|
||||
template <std::size_t Bits, class Tag>
|
||||
struct is_uniquely_represented<ripple::base_uint<Bits, Tag>>
|
||||
: public std::true_type
|
||||
{
|
||||
explicit is_uniquely_represented() = default;
|
||||
};
|
||||
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
129
include/xrpl/basics/chrono.h
Normal file
129
include/xrpl/basics/chrono.h
Normal file
@@ -0,0 +1,129 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_CHRONO_H_INCLUDED
|
||||
#define RIPPLE_BASICS_CHRONO_H_INCLUDED
|
||||
|
||||
#include <date/date.h>
|
||||
|
||||
#include <ripple/beast/clock/abstract_clock.h>
|
||||
#include <ripple/beast/clock/basic_seconds_clock.h>
|
||||
#include <ripple/beast/clock/manual_clock.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <ratio>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
// A few handy aliases
|
||||
|
||||
using days = std::chrono::duration<
|
||||
int,
|
||||
std::ratio_multiply<std::chrono::hours::period, std::ratio<24>>>;
|
||||
|
||||
using weeks = std::chrono::
|
||||
duration<int, std::ratio_multiply<days::period, std::ratio<7>>>;
|
||||
|
||||
/** Clock for measuring the network time.
|
||||
|
||||
The epoch is January 1, 2000
|
||||
|
||||
epoch_offset
|
||||
= date(2000-01-01) - date(1970-0-01)
|
||||
= days(10957)
|
||||
= seconds(946684800)
|
||||
*/
|
||||
|
||||
constexpr static std::chrono::seconds epoch_offset =
|
||||
date::sys_days{date::year{2000} / 1 / 1} -
|
||||
date::sys_days{date::year{1970} / 1 / 1};
|
||||
|
||||
static_assert(epoch_offset.count() == 946684800);
|
||||
|
||||
class NetClock
|
||||
{
|
||||
public:
|
||||
explicit NetClock() = default;
|
||||
|
||||
using rep = std::uint32_t;
|
||||
using period = std::ratio<1>;
|
||||
using duration = std::chrono::duration<rep, period>;
|
||||
using time_point = std::chrono::time_point<NetClock>;
|
||||
|
||||
static bool const is_steady = false;
|
||||
};
|
||||
|
||||
template <class Duration>
|
||||
std::string
|
||||
to_string(date::sys_time<Duration> tp)
|
||||
{
|
||||
return date::format("%Y-%b-%d %T %Z", tp);
|
||||
}
|
||||
|
||||
inline std::string
|
||||
to_string(NetClock::time_point tp)
|
||||
{
|
||||
// 2000-01-01 00:00:00 UTC is 946684800s from 1970-01-01 00:00:00 UTC
|
||||
using namespace std::chrono;
|
||||
return to_string(
|
||||
system_clock::time_point{tp.time_since_epoch() + epoch_offset});
|
||||
}
|
||||
|
||||
template <class Duration>
|
||||
std::string
|
||||
to_string_iso(date::sys_time<Duration> tp)
|
||||
{
|
||||
using namespace std::chrono;
|
||||
return date::format("%FT%TZ", tp);
|
||||
}
|
||||
|
||||
inline std::string
|
||||
to_string_iso(NetClock::time_point tp)
|
||||
{
|
||||
// 2000-01-01 00:00:00 UTC is 946684800s from 1970-01-01 00:00:00 UTC
|
||||
// Note, NetClock::duration is seconds, as checked by static_assert
|
||||
static_assert(std::is_same_v<NetClock::duration::period, std::ratio<1>>);
|
||||
return to_string_iso(date::sys_time<NetClock::duration>{
|
||||
tp.time_since_epoch() + epoch_offset});
|
||||
}
|
||||
|
||||
/** A clock for measuring elapsed time.
|
||||
|
||||
The epoch is unspecified.
|
||||
*/
|
||||
using Stopwatch = beast::abstract_clock<std::chrono::steady_clock>;
|
||||
|
||||
/** A manual Stopwatch for unit tests. */
|
||||
using TestStopwatch = beast::manual_clock<std::chrono::steady_clock>;
|
||||
|
||||
/** Returns an instance of a wall clock. */
|
||||
inline Stopwatch&
|
||||
stopwatch()
|
||||
{
|
||||
using Clock = beast::basic_seconds_clock;
|
||||
using Facade = Clock::Clock;
|
||||
return beast::get_abstract_clock<Facade, Clock>();
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
76
include/xrpl/basics/comparators.h
Normal file
76
include/xrpl/basics/comparators.h
Normal file
@@ -0,0 +1,76 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_COMPARATORS_H_INCLUDED
|
||||
#define RIPPLE_BASICS_COMPARATORS_H_INCLUDED
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
/*
|
||||
* MSVC 2019 version 16.9.0 added [[nodiscard]] to the std comparison
|
||||
* operator() functions. boost::bimap checks that the comparitor is a
|
||||
* BinaryFunction, in part by calling the function and ignoring the value.
|
||||
* These two things don't play well together. These wrapper classes simply
|
||||
* strip [[nodiscard]] from operator() for use in boost::bimap.
|
||||
*
|
||||
* See also:
|
||||
* https://www.boost.org/doc/libs/1_75_0/libs/bimap/doc/html/boost_bimap/the_tutorial/controlling_collection_types.html
|
||||
*/
|
||||
|
||||
template <class T = void>
|
||||
struct less
|
||||
{
|
||||
using result_type = bool;
|
||||
|
||||
constexpr bool
|
||||
operator()(const T& left, const T& right) const
|
||||
{
|
||||
return std::less<T>()(left, right);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T = void>
|
||||
struct equal_to
|
||||
{
|
||||
using result_type = bool;
|
||||
|
||||
constexpr bool
|
||||
operator()(const T& left, const T& right) const
|
||||
{
|
||||
return std::equal_to<T>()(left, right);
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
template <class T = void>
|
||||
using less = std::less<T>;
|
||||
|
||||
template <class T = void>
|
||||
using equal_to = std::equal_to<T>;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
76
include/xrpl/basics/contract.h
Normal file
76
include/xrpl/basics/contract.h
Normal file
@@ -0,0 +1,76 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2014 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_CONTRACT_H_INCLUDED
|
||||
#define RIPPLE_BASICS_CONTRACT_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/type_name.h>
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/* Programming By Contract
|
||||
|
||||
This routines are used when checking
|
||||
preconditions, postconditions, and invariants.
|
||||
*/
|
||||
|
||||
/** Generates and logs a call stack */
|
||||
void
|
||||
LogThrow(std::string const& title);
|
||||
|
||||
/** Rethrow the exception currently being handled.
|
||||
|
||||
When called from within a catch block, it will pass
|
||||
control to the next matching exception handler, if any.
|
||||
Otherwise, std::terminate will be called.
|
||||
*/
|
||||
[[noreturn]] inline void
|
||||
Rethrow()
|
||||
{
|
||||
LogThrow("Re-throwing exception");
|
||||
throw;
|
||||
}
|
||||
|
||||
template <class E, class... Args>
|
||||
[[noreturn]] inline void
|
||||
Throw(Args&&... args)
|
||||
{
|
||||
static_assert(
|
||||
std::is_convertible<E*, std::exception*>::value,
|
||||
"Exception must derive from std::exception.");
|
||||
|
||||
E e(std::forward<Args>(args)...);
|
||||
LogThrow(
|
||||
std::string(
|
||||
"Throwing exception of type " + beast::type_name<E>() + ": ") +
|
||||
e.what());
|
||||
throw e;
|
||||
}
|
||||
|
||||
/** Called when faulty logic causes a broken invariant. */
|
||||
[[noreturn]] void
|
||||
LogicError(std::string const& how) noexcept;
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
120
include/xrpl/basics/hardened_hash.h
Normal file
120
include/xrpl/basics/hardened_hash.h
Normal file
@@ -0,0 +1,120 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2014 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_HARDENED_HASH_H_INCLUDED
|
||||
#define RIPPLE_BASICS_HARDENED_HASH_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/hash/hash_append.h>
|
||||
#include <ripple/beast/hash/xxhasher.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
namespace detail {
|
||||
|
||||
using seed_pair = std::pair<std::uint64_t, std::uint64_t>;
|
||||
|
||||
template <bool = true>
|
||||
seed_pair
|
||||
make_seed_pair() noexcept
|
||||
{
|
||||
struct state_t
|
||||
{
|
||||
std::mutex mutex;
|
||||
std::random_device rng;
|
||||
std::mt19937_64 gen;
|
||||
std::uniform_int_distribution<std::uint64_t> dist;
|
||||
|
||||
state_t() : gen(rng())
|
||||
{
|
||||
}
|
||||
// state_t(state_t const&) = delete;
|
||||
// state_t& operator=(state_t const&) = delete;
|
||||
};
|
||||
static state_t state;
|
||||
std::lock_guard lock(state.mutex);
|
||||
return {state.dist(state.gen), state.dist(state.gen)};
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* Seed functor once per construction
|
||||
|
||||
A std compatible hash adapter that resists adversarial inputs.
|
||||
For this to work, T must implement in its own namespace:
|
||||
|
||||
@code
|
||||
|
||||
template <class Hasher>
|
||||
void
|
||||
hash_append (Hasher& h, T const& t) noexcept
|
||||
{
|
||||
// hash_append each base and member that should
|
||||
// participate in forming the hash
|
||||
using beast::hash_append;
|
||||
hash_append (h, static_cast<T::base1 const&>(t));
|
||||
hash_append (h, static_cast<T::base2 const&>(t));
|
||||
// ...
|
||||
hash_append (h, t.member1);
|
||||
hash_append (h, t.member2);
|
||||
// ...
|
||||
}
|
||||
|
||||
@endcode
|
||||
|
||||
Do not use any version of Murmur or CityHash for the Hasher
|
||||
template parameter (the hashing algorithm). For details
|
||||
see https://131002.net/siphash/#at
|
||||
*/
|
||||
|
||||
template <class HashAlgorithm = beast::xxhasher>
|
||||
class hardened_hash
|
||||
{
|
||||
private:
|
||||
detail::seed_pair m_seeds;
|
||||
|
||||
public:
|
||||
using result_type = typename HashAlgorithm::result_type;
|
||||
|
||||
hardened_hash() : m_seeds(detail::make_seed_pair<>())
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
result_type
|
||||
operator()(T const& t) const noexcept
|
||||
{
|
||||
HashAlgorithm h(m_seeds.first, m_seeds.second);
|
||||
hash_append(h, t);
|
||||
return static_cast<result_type>(h);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
108
include/xrpl/basics/join.h
Normal file
108
include/xrpl/basics/join.h
Normal file
@@ -0,0 +1,108 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2022 Ripple Labs Inc.
|
||||
|
||||
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 JOIN_H_INCLUDED
|
||||
#define JOIN_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
template <class Stream, class Iter>
|
||||
Stream&
|
||||
join(Stream& s, Iter iter, Iter end, std::string const& delimiter)
|
||||
{
|
||||
if (iter == end)
|
||||
return s;
|
||||
s << *iter;
|
||||
for (++iter; iter != end; ++iter)
|
||||
s << delimiter << *iter;
|
||||
return s;
|
||||
}
|
||||
|
||||
template <class Collection>
|
||||
class CollectionAndDelimiter
|
||||
{
|
||||
public:
|
||||
Collection const& collection;
|
||||
std::string const delimiter;
|
||||
|
||||
explicit CollectionAndDelimiter(Collection const& c, std::string delim)
|
||||
: collection(c), delimiter(std::move(delim))
|
||||
{
|
||||
}
|
||||
|
||||
template <class Stream>
|
||||
friend Stream&
|
||||
operator<<(Stream& s, CollectionAndDelimiter const& cd)
|
||||
{
|
||||
return join(
|
||||
s,
|
||||
std::begin(cd.collection),
|
||||
std::end(cd.collection),
|
||||
cd.delimiter);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Collection, std::size_t N>
|
||||
class CollectionAndDelimiter<Collection[N]>
|
||||
{
|
||||
public:
|
||||
Collection const* collection;
|
||||
std::string const delimiter;
|
||||
|
||||
explicit CollectionAndDelimiter(Collection const c[N], std::string delim)
|
||||
: collection(c), delimiter(std::move(delim))
|
||||
{
|
||||
}
|
||||
|
||||
template <class Stream>
|
||||
friend Stream&
|
||||
operator<<(Stream& s, CollectionAndDelimiter const& cd)
|
||||
{
|
||||
return join(s, cd.collection, cd.collection + N, cd.delimiter);
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization for const char* strings
|
||||
template <std::size_t N>
|
||||
class CollectionAndDelimiter<char[N]>
|
||||
{
|
||||
public:
|
||||
char const* collection;
|
||||
std::string const delimiter;
|
||||
|
||||
explicit CollectionAndDelimiter(char const c[N], std::string delim)
|
||||
: collection(c), delimiter(std::move(delim))
|
||||
{
|
||||
}
|
||||
|
||||
template <class Stream>
|
||||
friend Stream&
|
||||
operator<<(Stream& s, CollectionAndDelimiter const& cd)
|
||||
{
|
||||
auto end = cd.collection + N;
|
||||
if (N > 0 && *(end - 1) == '\0')
|
||||
--end;
|
||||
return join(s, cd.collection, end, cd.delimiter);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
42
include/xrpl/basics/make_SSLContext.h
Normal file
42
include/xrpl/basics/make_SSLContext.h
Normal file
@@ -0,0 +1,42 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_MAKE_SSLCONTEXT_H_INCLUDED
|
||||
#define RIPPLE_BASICS_MAKE_SSLCONTEXT_H_INCLUDED
|
||||
|
||||
#include <boost/asio/ssl/context.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** Create a self-signed SSL context that allows anonymous Diffie Hellman. */
|
||||
std::shared_ptr<boost::asio::ssl::context>
|
||||
make_SSLContext(std::string const& cipherList);
|
||||
|
||||
/** Create an authenticated SSL context using the specified files. */
|
||||
std::shared_ptr<boost::asio::ssl::context>
|
||||
make_SSLContextAuthed(
|
||||
std::string const& keyFile,
|
||||
std::string const& certFile,
|
||||
std::string const& chainFile,
|
||||
std::string const& cipherList);
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
46
include/xrpl/basics/mulDiv.h
Normal file
46
include/xrpl/basics/mulDiv.h
Normal file
@@ -0,0 +1,46 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012-2015 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_MULDIV_H_INCLUDED
|
||||
#define RIPPLE_BASICS_MULDIV_H_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple {
|
||||
auto constexpr muldiv_max = std::numeric_limits<std::uint64_t>::max();
|
||||
|
||||
/** Return value*mul/div accurately.
|
||||
Computes the result of the multiplication and division in
|
||||
a single step, avoiding overflow and retaining precision.
|
||||
Throws:
|
||||
None
|
||||
Returns:
|
||||
`std::optional`:
|
||||
`std::nullopt` if the calculation overflows. Otherwise, `value * mul
|
||||
/ div`.
|
||||
*/
|
||||
std::optional<std::uint64_t>
|
||||
mulDiv(std::uint64_t value, std::uint64_t mul, std::uint64_t div);
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
409
include/xrpl/basics/partitioned_unordered_map.h
Normal file
409
include/xrpl/basics/partitioned_unordered_map.h
Normal file
@@ -0,0 +1,409 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2021 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_PARTITIONED_UNORDERED_MAP_H
|
||||
#define RIPPLE_BASICS_PARTITIONED_UNORDERED_MAP_H
|
||||
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
template <typename Key>
|
||||
std::size_t
|
||||
partitioner(Key const& key, std::size_t const numPartitions);
|
||||
|
||||
template <
|
||||
typename Key,
|
||||
typename Value,
|
||||
typename Hash,
|
||||
typename Pred = std::equal_to<Key>,
|
||||
typename Alloc = std::allocator<std::pair<const Key, Value>>>
|
||||
class partitioned_unordered_map
|
||||
{
|
||||
std::size_t partitions_;
|
||||
|
||||
public:
|
||||
using key_type = Key;
|
||||
using mapped_type = Value;
|
||||
using value_type = std::pair<Key const, mapped_type>;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::size_t;
|
||||
using hasher = Hash;
|
||||
using key_equal = Pred;
|
||||
using allocator_type = Alloc;
|
||||
using reference = value_type&;
|
||||
using const_reference = value_type const&;
|
||||
using pointer = value_type*;
|
||||
using const_pointer = value_type const*;
|
||||
using map_type = std::
|
||||
unordered_map<key_type, mapped_type, hasher, key_equal, allocator_type>;
|
||||
using partition_map_type = std::vector<map_type>;
|
||||
|
||||
struct iterator
|
||||
{
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
partition_map_type* map_{nullptr};
|
||||
typename partition_map_type::iterator ait_;
|
||||
typename map_type::iterator mit_;
|
||||
|
||||
iterator() = default;
|
||||
|
||||
iterator(partition_map_type* map) : map_(map)
|
||||
{
|
||||
}
|
||||
|
||||
reference
|
||||
operator*() const
|
||||
{
|
||||
return *mit_;
|
||||
}
|
||||
|
||||
pointer
|
||||
operator->() const
|
||||
{
|
||||
return &(*mit_);
|
||||
}
|
||||
|
||||
void
|
||||
inc()
|
||||
{
|
||||
++mit_;
|
||||
while (mit_ == ait_->end())
|
||||
{
|
||||
++ait_;
|
||||
if (ait_ == map_->end())
|
||||
return;
|
||||
mit_ = ait_->begin();
|
||||
}
|
||||
}
|
||||
|
||||
// ++it
|
||||
iterator&
|
||||
operator++()
|
||||
{
|
||||
inc();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// it++
|
||||
iterator
|
||||
operator++(int)
|
||||
{
|
||||
iterator tmp(*this);
|
||||
inc();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator==(iterator const& lhs, iterator const& rhs)
|
||||
{
|
||||
return lhs.map_ == rhs.map_ && lhs.ait_ == rhs.ait_ &&
|
||||
lhs.mit_ == rhs.mit_;
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator!=(iterator const& lhs, iterator const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
};
|
||||
|
||||
struct const_iterator
|
||||
{
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
partition_map_type* map_{nullptr};
|
||||
typename partition_map_type::iterator ait_;
|
||||
typename map_type::iterator mit_;
|
||||
|
||||
const_iterator() = default;
|
||||
|
||||
const_iterator(partition_map_type* map) : map_(map)
|
||||
{
|
||||
}
|
||||
|
||||
const_iterator(iterator const& orig)
|
||||
{
|
||||
map_ = orig.map_;
|
||||
ait_ = orig.ait_;
|
||||
mit_ = orig.mit_;
|
||||
}
|
||||
|
||||
const_reference
|
||||
operator*() const
|
||||
{
|
||||
return *mit_;
|
||||
}
|
||||
|
||||
const_pointer
|
||||
operator->() const
|
||||
{
|
||||
return &(*mit_);
|
||||
}
|
||||
|
||||
void
|
||||
inc()
|
||||
{
|
||||
++mit_;
|
||||
while (mit_ == ait_->end())
|
||||
{
|
||||
++ait_;
|
||||
if (ait_ == map_->end())
|
||||
return;
|
||||
mit_ = ait_->begin();
|
||||
}
|
||||
}
|
||||
|
||||
// ++it
|
||||
const_iterator&
|
||||
operator++()
|
||||
{
|
||||
inc();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// it++
|
||||
const_iterator
|
||||
operator++(int)
|
||||
{
|
||||
const_iterator tmp(*this);
|
||||
inc();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator==(const_iterator const& lhs, const_iterator const& rhs)
|
||||
{
|
||||
return lhs.map_ == rhs.map_ && lhs.ait_ == rhs.ait_ &&
|
||||
lhs.mit_ == rhs.mit_;
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator!=(const_iterator const& lhs, const_iterator const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
std::size_t
|
||||
partitioner(Key const& key) const
|
||||
{
|
||||
return ripple::partitioner(key, partitions_);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void
|
||||
end(T& it)
|
||||
{
|
||||
it.ait_ = it.map_->end();
|
||||
it.mit_ = it.map_->back().end();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void
|
||||
begin(T& it)
|
||||
{
|
||||
for (it.ait_ = it.map_->begin(); it.ait_ != it.map_->end(); ++it.ait_)
|
||||
{
|
||||
if (it.ait_->begin() == it.ait_->end())
|
||||
continue;
|
||||
it.mit_ = it.ait_->begin();
|
||||
return;
|
||||
}
|
||||
end(it);
|
||||
}
|
||||
|
||||
public:
|
||||
partitioned_unordered_map(
|
||||
std::optional<std::size_t> partitions = std::nullopt)
|
||||
{
|
||||
// Set partitions to the number of hardware threads if the parameter
|
||||
// is either empty or set to 0.
|
||||
partitions_ = partitions && *partitions
|
||||
? *partitions
|
||||
: std::thread::hardware_concurrency();
|
||||
map_.resize(partitions_);
|
||||
assert(partitions_);
|
||||
}
|
||||
|
||||
std::size_t
|
||||
partitions() const
|
||||
{
|
||||
return partitions_;
|
||||
}
|
||||
|
||||
partition_map_type&
|
||||
map()
|
||||
{
|
||||
return map_;
|
||||
}
|
||||
|
||||
iterator
|
||||
begin()
|
||||
{
|
||||
iterator it(&map_);
|
||||
begin(it);
|
||||
return it;
|
||||
}
|
||||
|
||||
const_iterator
|
||||
cbegin() const
|
||||
{
|
||||
const_iterator it(&map_);
|
||||
begin(it);
|
||||
return it;
|
||||
}
|
||||
|
||||
const_iterator
|
||||
begin() const
|
||||
{
|
||||
return cbegin();
|
||||
}
|
||||
|
||||
iterator
|
||||
end()
|
||||
{
|
||||
iterator it(&map_);
|
||||
end(it);
|
||||
return it;
|
||||
}
|
||||
|
||||
const_iterator
|
||||
cend() const
|
||||
{
|
||||
const_iterator it(&map_);
|
||||
end(it);
|
||||
return it;
|
||||
}
|
||||
|
||||
const_iterator
|
||||
end() const
|
||||
{
|
||||
return cend();
|
||||
}
|
||||
|
||||
private:
|
||||
template <class T>
|
||||
void
|
||||
find(key_type const& key, T& it) const
|
||||
{
|
||||
it.ait_ = it.map_->begin() + partitioner(key);
|
||||
it.mit_ = it.ait_->find(key);
|
||||
if (it.mit_ == it.ait_->end())
|
||||
end(it);
|
||||
}
|
||||
|
||||
public:
|
||||
iterator
|
||||
find(key_type const& key)
|
||||
{
|
||||
iterator it(&map_);
|
||||
find(key, it);
|
||||
return it;
|
||||
}
|
||||
|
||||
const_iterator
|
||||
find(key_type const& key) const
|
||||
{
|
||||
const_iterator it(&map_);
|
||||
find(key, it);
|
||||
return it;
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
std::pair<iterator, bool>
|
||||
emplace(std::piecewise_construct_t const&, T&& keyTuple, U&& valueTuple)
|
||||
{
|
||||
auto const& key = std::get<0>(keyTuple);
|
||||
iterator it(&map_);
|
||||
it.ait_ = it.map_->begin() + partitioner(key);
|
||||
auto [eit, inserted] = it.ait_->emplace(
|
||||
std::piecewise_construct,
|
||||
std::forward<T>(keyTuple),
|
||||
std::forward<U>(valueTuple));
|
||||
it.mit_ = eit;
|
||||
return {it, inserted};
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
std::pair<iterator, bool>
|
||||
emplace(T&& key, U&& val)
|
||||
{
|
||||
iterator it(&map_);
|
||||
it.ait_ = it.map_->begin() + partitioner(key);
|
||||
auto [eit, inserted] =
|
||||
it.ait_->emplace(std::forward<T>(key), std::forward<U>(val));
|
||||
it.mit_ = eit;
|
||||
return {it, inserted};
|
||||
}
|
||||
|
||||
void
|
||||
clear()
|
||||
{
|
||||
for (auto& p : map_)
|
||||
p.clear();
|
||||
}
|
||||
|
||||
iterator
|
||||
erase(const_iterator position)
|
||||
{
|
||||
iterator it(&map_);
|
||||
it.ait_ = position.ait_;
|
||||
it.mit_ = position.ait_->erase(position.mit_);
|
||||
|
||||
while (it.mit_ == it.ait_->end())
|
||||
{
|
||||
++it.ait_;
|
||||
if (it.ait_ == it.map_->end())
|
||||
break;
|
||||
it.mit_ = it.ait_->begin();
|
||||
}
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
size() const
|
||||
{
|
||||
std::size_t ret = 0;
|
||||
for (auto& p : map_)
|
||||
ret += p.size();
|
||||
return ret;
|
||||
}
|
||||
|
||||
Value&
|
||||
operator[](Key const& key)
|
||||
{
|
||||
return map_[partitioner(key)][key];
|
||||
}
|
||||
|
||||
private:
|
||||
mutable partition_map_type map_{};
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif // RIPPLE_BASICS_PARTITIONED_UNORDERED_MAP_H
|
||||
210
include/xrpl/basics/random.h
Normal file
210
include/xrpl/basics/random.h
Normal file
@@ -0,0 +1,210 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_RANDOM_H_INCLUDED
|
||||
#define RIPPLE_BASICS_RANDOM_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/xor_shift_engine.h>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
#include <type_traits>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
#ifndef __INTELLISENSE__
|
||||
static_assert(
|
||||
std::is_integral<beast::xor_shift_engine::result_type>::value &&
|
||||
std::is_unsigned<beast::xor_shift_engine::result_type>::value,
|
||||
"The Ripple default PRNG engine must return an unsigned integral type.");
|
||||
|
||||
static_assert(
|
||||
std::numeric_limits<beast::xor_shift_engine::result_type>::max() >=
|
||||
std::numeric_limits<std::uint64_t>::max(),
|
||||
"The Ripple default PRNG engine return must be at least 64 bits wide.");
|
||||
#endif
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Determines if a type can be called like an Engine
|
||||
template <class Engine, class Result = typename Engine::result_type>
|
||||
using is_engine = std::is_invocable_r<Result, Engine>;
|
||||
} // namespace detail
|
||||
|
||||
/** Return the default random engine.
|
||||
|
||||
This engine is guaranteed to be deterministic, but by
|
||||
default will be randomly seeded. It is NOT cryptographically
|
||||
secure and MUST NOT be used to generate randomness that
|
||||
will be used for keys, secure cookies, IVs, padding, etc.
|
||||
|
||||
Each thread gets its own instance of the engine which
|
||||
will be randomly seeded.
|
||||
*/
|
||||
inline beast::xor_shift_engine&
|
||||
default_prng()
|
||||
{
|
||||
// This is used to seed the thread-specific PRNGs on demand
|
||||
static beast::xor_shift_engine seeder = [] {
|
||||
std::random_device rng;
|
||||
std::uniform_int_distribution<std::uint64_t> distribution{1};
|
||||
return beast::xor_shift_engine(distribution(rng));
|
||||
}();
|
||||
|
||||
// This protects the seeder
|
||||
static std::mutex m;
|
||||
|
||||
// The thread-specific PRNGs:
|
||||
thread_local beast::xor_shift_engine engine = [] {
|
||||
std::uint64_t seed;
|
||||
{
|
||||
std::lock_guard lk(m);
|
||||
std::uniform_int_distribution<std::uint64_t> distribution{1};
|
||||
seed = distribution(seeder);
|
||||
}
|
||||
return beast::xor_shift_engine{seed};
|
||||
}();
|
||||
|
||||
return engine;
|
||||
}
|
||||
|
||||
/** Return a uniformly distributed random integer.
|
||||
|
||||
@param min The smallest value to return. If not specified
|
||||
the value defaults to 0.
|
||||
@param max The largest value to return. If not specified
|
||||
the value defaults to the largest value that
|
||||
can be represented.
|
||||
|
||||
The randomness is generated by the specified engine (or
|
||||
the default engine if one is not specified). The result
|
||||
is cryptographically secure only when the engine passed
|
||||
into the function is cryptographically secure.
|
||||
|
||||
@note The range is always a closed interval, so calling
|
||||
rand_int(-5, 15) can return any integer in the
|
||||
closed interval [-5, 15]; similarly, calling
|
||||
rand_int(7) can return any integer in the closed
|
||||
interval [0, 7].
|
||||
*/
|
||||
/** @{ */
|
||||
template <class Engine, class Integral>
|
||||
std::enable_if_t<
|
||||
std::is_integral<Integral>::value && detail::is_engine<Engine>::value,
|
||||
Integral>
|
||||
rand_int(Engine& engine, Integral min, Integral max)
|
||||
{
|
||||
assert(max > min);
|
||||
|
||||
// This should have no state and constructing it should
|
||||
// be very cheap. If that turns out not to be the case
|
||||
// it could be hand-optimized.
|
||||
return std::uniform_int_distribution<Integral>(min, max)(engine);
|
||||
}
|
||||
|
||||
template <class Integral>
|
||||
std::enable_if_t<std::is_integral<Integral>::value, Integral>
|
||||
rand_int(Integral min, Integral max)
|
||||
{
|
||||
return rand_int(default_prng(), min, max);
|
||||
}
|
||||
|
||||
template <class Engine, class Integral>
|
||||
std::enable_if_t<
|
||||
std::is_integral<Integral>::value && detail::is_engine<Engine>::value,
|
||||
Integral>
|
||||
rand_int(Engine& engine, Integral max)
|
||||
{
|
||||
return rand_int(engine, Integral(0), max);
|
||||
}
|
||||
|
||||
template <class Integral>
|
||||
std::enable_if_t<std::is_integral<Integral>::value, Integral>
|
||||
rand_int(Integral max)
|
||||
{
|
||||
return rand_int(default_prng(), max);
|
||||
}
|
||||
|
||||
template <class Integral, class Engine>
|
||||
std::enable_if_t<
|
||||
std::is_integral<Integral>::value && detail::is_engine<Engine>::value,
|
||||
Integral>
|
||||
rand_int(Engine& engine)
|
||||
{
|
||||
return rand_int(engine, std::numeric_limits<Integral>::max());
|
||||
}
|
||||
|
||||
template <class Integral = int>
|
||||
std::enable_if_t<std::is_integral<Integral>::value, Integral>
|
||||
rand_int()
|
||||
{
|
||||
return rand_int(default_prng(), std::numeric_limits<Integral>::max());
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Return a random byte */
|
||||
/** @{ */
|
||||
template <class Byte, class Engine>
|
||||
std::enable_if_t<
|
||||
(std::is_same<Byte, unsigned char>::value ||
|
||||
std::is_same<Byte, std::uint8_t>::value) &&
|
||||
detail::is_engine<Engine>::value,
|
||||
Byte>
|
||||
rand_byte(Engine& engine)
|
||||
{
|
||||
return static_cast<Byte>(rand_int<Engine, std::uint32_t>(
|
||||
engine,
|
||||
std::numeric_limits<Byte>::min(),
|
||||
std::numeric_limits<Byte>::max()));
|
||||
}
|
||||
|
||||
template <class Byte = std::uint8_t>
|
||||
std::enable_if_t<
|
||||
(std::is_same<Byte, unsigned char>::value ||
|
||||
std::is_same<Byte, std::uint8_t>::value),
|
||||
Byte>
|
||||
rand_byte()
|
||||
{
|
||||
return rand_byte<Byte>(default_prng());
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Return a random boolean value */
|
||||
/** @{ */
|
||||
template <class Engine>
|
||||
inline bool
|
||||
rand_bool(Engine& engine)
|
||||
{
|
||||
return rand_int(engine, 1) == 1;
|
||||
}
|
||||
|
||||
inline bool
|
||||
rand_bool()
|
||||
{
|
||||
return rand_bool(default_prng());
|
||||
}
|
||||
/** @} */
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif // RIPPLE_BASICS_RANDOM_H_INCLUDED
|
||||
105
include/xrpl/basics/safe_cast.h
Normal file
105
include/xrpl/basics/safe_cast.h
Normal file
@@ -0,0 +1,105 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2018 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_SAFE_CAST_H_INCLUDED
|
||||
#define RIPPLE_BASICS_SAFE_CAST_H_INCLUDED
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
// safe_cast adds compile-time checks to a static_cast to ensure that
|
||||
// the destination can hold all values of the source. This is particularly
|
||||
// handy when the source or destination is an enumeration type.
|
||||
|
||||
template <class Dest, class Src>
|
||||
static constexpr bool is_safetocasttovalue_v =
|
||||
(std::is_integral_v<Src> && std::is_integral_v<Dest>)&&(
|
||||
std::is_signed<Src>::value || std::is_unsigned<Dest>::value) &&
|
||||
(std::is_signed<Src>::value != std::is_signed<Dest>::value
|
||||
? sizeof(Dest) > sizeof(Src)
|
||||
: sizeof(Dest) >= sizeof(Src));
|
||||
|
||||
template <class Dest, class Src>
|
||||
inline constexpr std::
|
||||
enable_if_t<std::is_integral_v<Dest> && std::is_integral_v<Src>, Dest>
|
||||
safe_cast(Src s) noexcept
|
||||
{
|
||||
static_assert(
|
||||
std::is_signed_v<Dest> || std::is_unsigned_v<Src>,
|
||||
"Cannot cast signed to unsigned");
|
||||
constexpr unsigned not_same =
|
||||
std::is_signed_v<Dest> != std::is_signed_v<Src>;
|
||||
static_assert(
|
||||
sizeof(Dest) >= sizeof(Src) + not_same,
|
||||
"Destination is too small to hold all values of source");
|
||||
return static_cast<Dest>(s);
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
inline constexpr std::
|
||||
enable_if_t<std::is_enum_v<Dest> && std::is_integral_v<Src>, Dest>
|
||||
safe_cast(Src s) noexcept
|
||||
{
|
||||
return static_cast<Dest>(safe_cast<std::underlying_type_t<Dest>>(s));
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
inline constexpr std::
|
||||
enable_if_t<std::is_integral_v<Dest> && std::is_enum_v<Src>, Dest>
|
||||
safe_cast(Src s) noexcept
|
||||
{
|
||||
return safe_cast<Dest>(static_cast<std::underlying_type_t<Src>>(s));
|
||||
}
|
||||
|
||||
// unsafe_cast explicitly flags a static_cast as not necessarily able to hold
|
||||
// all values of the source. It includes a compile-time check so that if
|
||||
// underlying types become safe, it can be converted to a safe_cast.
|
||||
|
||||
template <class Dest, class Src>
|
||||
inline constexpr std::
|
||||
enable_if_t<std::is_integral_v<Dest> && std::is_integral_v<Src>, Dest>
|
||||
unsafe_cast(Src s) noexcept
|
||||
{
|
||||
static_assert(
|
||||
!is_safetocasttovalue_v<Dest, Src>,
|
||||
"Only unsafe if casting signed to unsigned or "
|
||||
"destination is too small");
|
||||
return static_cast<Dest>(s);
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
inline constexpr std::
|
||||
enable_if_t<std::is_enum_v<Dest> && std::is_integral_v<Src>, Dest>
|
||||
unsafe_cast(Src s) noexcept
|
||||
{
|
||||
return static_cast<Dest>(unsafe_cast<std::underlying_type_t<Dest>>(s));
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
inline constexpr std::
|
||||
enable_if_t<std::is_integral_v<Dest> && std::is_enum_v<Src>, Dest>
|
||||
unsafe_cast(Src s) noexcept
|
||||
{
|
||||
return unsafe_cast<Dest>(static_cast<std::underlying_type_t<Src>>(s));
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
191
include/xrpl/basics/scope.h
Normal file
191
include/xrpl/basics/scope.h
Normal file
@@ -0,0 +1,191 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2021 Ripple Inc.
|
||||
|
||||
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 RIPPLE_BASICS_SCOPE_H_INCLUDED
|
||||
#define RIPPLE_BASICS_SCOPE_H_INCLUDED
|
||||
|
||||
#include <exception>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
// RAII scope helpers. As specified in Library Fundamental, Version 3
|
||||
// Basic design of idea: https://www.youtube.com/watch?v=WjTrfoiB0MQ
|
||||
// Specification:
|
||||
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/n4873.html#scopeguard
|
||||
|
||||
// This implementation deviates from the spec slightly:
|
||||
// The scope_exit and scope_fail constructors taking a functor are not
|
||||
// permitted to throw an exception. This was done because some compilers
|
||||
// did not like the superfluous try/catch in the common instantiations
|
||||
// where the construction was noexcept. Instead a static_assert is used
|
||||
// to enforce this restriction.
|
||||
|
||||
template <class EF>
|
||||
class scope_exit
|
||||
{
|
||||
EF exit_function_;
|
||||
bool execute_on_destruction_{true};
|
||||
|
||||
public:
|
||||
~scope_exit()
|
||||
{
|
||||
if (execute_on_destruction_)
|
||||
exit_function_();
|
||||
}
|
||||
|
||||
scope_exit(scope_exit&& rhs) noexcept(
|
||||
std::is_nothrow_move_constructible_v<EF> ||
|
||||
std::is_nothrow_copy_constructible_v<EF>)
|
||||
: exit_function_{std::forward<EF>(rhs.exit_function_)}
|
||||
, execute_on_destruction_{rhs.execute_on_destruction_}
|
||||
{
|
||||
rhs.release();
|
||||
}
|
||||
|
||||
scope_exit&
|
||||
operator=(scope_exit&&) = delete;
|
||||
|
||||
template <class EFP>
|
||||
explicit scope_exit(
|
||||
EFP&& f,
|
||||
std::enable_if_t<
|
||||
!std::is_same_v<std::remove_cv_t<EFP>, scope_exit> &&
|
||||
std::is_constructible_v<EF, EFP>>* = 0) noexcept
|
||||
: exit_function_{std::forward<EFP>(f)}
|
||||
{
|
||||
static_assert(
|
||||
std::
|
||||
is_nothrow_constructible_v<EF, decltype(std::forward<EFP>(f))>);
|
||||
}
|
||||
|
||||
void
|
||||
release() noexcept
|
||||
{
|
||||
execute_on_destruction_ = false;
|
||||
}
|
||||
};
|
||||
|
||||
template <class EF>
|
||||
scope_exit(EF) -> scope_exit<EF>;
|
||||
|
||||
template <class EF>
|
||||
class scope_fail
|
||||
{
|
||||
EF exit_function_;
|
||||
bool execute_on_destruction_{true};
|
||||
int uncaught_on_creation_{std::uncaught_exceptions()};
|
||||
|
||||
public:
|
||||
~scope_fail()
|
||||
{
|
||||
if (execute_on_destruction_ &&
|
||||
std::uncaught_exceptions() > uncaught_on_creation_)
|
||||
exit_function_();
|
||||
}
|
||||
|
||||
scope_fail(scope_fail&& rhs) noexcept(
|
||||
std::is_nothrow_move_constructible_v<EF> ||
|
||||
std::is_nothrow_copy_constructible_v<EF>)
|
||||
: exit_function_{std::forward<EF>(rhs.exit_function_)}
|
||||
, execute_on_destruction_{rhs.execute_on_destruction_}
|
||||
, uncaught_on_creation_{rhs.uncaught_on_creation_}
|
||||
{
|
||||
rhs.release();
|
||||
}
|
||||
|
||||
scope_fail&
|
||||
operator=(scope_fail&&) = delete;
|
||||
|
||||
template <class EFP>
|
||||
explicit scope_fail(
|
||||
EFP&& f,
|
||||
std::enable_if_t<
|
||||
!std::is_same_v<std::remove_cv_t<EFP>, scope_fail> &&
|
||||
std::is_constructible_v<EF, EFP>>* = 0) noexcept
|
||||
: exit_function_{std::forward<EFP>(f)}
|
||||
{
|
||||
static_assert(
|
||||
std::
|
||||
is_nothrow_constructible_v<EF, decltype(std::forward<EFP>(f))>);
|
||||
}
|
||||
|
||||
void
|
||||
release() noexcept
|
||||
{
|
||||
execute_on_destruction_ = false;
|
||||
}
|
||||
};
|
||||
|
||||
template <class EF>
|
||||
scope_fail(EF) -> scope_fail<EF>;
|
||||
|
||||
template <class EF>
|
||||
class scope_success
|
||||
{
|
||||
EF exit_function_;
|
||||
bool execute_on_destruction_{true};
|
||||
int uncaught_on_creation_{std::uncaught_exceptions()};
|
||||
|
||||
public:
|
||||
~scope_success() noexcept(noexcept(exit_function_()))
|
||||
{
|
||||
if (execute_on_destruction_ &&
|
||||
std::uncaught_exceptions() <= uncaught_on_creation_)
|
||||
exit_function_();
|
||||
}
|
||||
|
||||
scope_success(scope_success&& rhs) noexcept(
|
||||
std::is_nothrow_move_constructible_v<EF> ||
|
||||
std::is_nothrow_copy_constructible_v<EF>)
|
||||
: exit_function_{std::forward<EF>(rhs.exit_function_)}
|
||||
, execute_on_destruction_{rhs.execute_on_destruction_}
|
||||
, uncaught_on_creation_{rhs.uncaught_on_creation_}
|
||||
{
|
||||
rhs.release();
|
||||
}
|
||||
|
||||
scope_success&
|
||||
operator=(scope_success&&) = delete;
|
||||
|
||||
template <class EFP>
|
||||
explicit scope_success(
|
||||
EFP&& f,
|
||||
std::enable_if_t<
|
||||
!std::is_same_v<std::remove_cv_t<EFP>, scope_success> &&
|
||||
std::is_constructible_v<EF, EFP>>* =
|
||||
0) noexcept(std::is_nothrow_constructible_v<EF, EFP> || std::is_nothrow_constructible_v<EF, EFP&>)
|
||||
: exit_function_{std::forward<EFP>(f)}
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
release() noexcept
|
||||
{
|
||||
execute_on_destruction_ = false;
|
||||
}
|
||||
};
|
||||
|
||||
template <class EF>
|
||||
scope_success(EF) -> scope_success<EF>;
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
223
include/xrpl/basics/spinlock.h
Normal file
223
include/xrpl/basics/spinlock.h
Normal file
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright 2022, Nikolaos D. Bougalis <nikb@bougalis.net>
|
||||
|
||||
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 RIPPLE_BASICS_SPINLOCK_H_INCLUDED
|
||||
#define RIPPLE_BASICS_SPINLOCK_H_INCLUDED
|
||||
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
#ifndef __aarch64__
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
namespace ripple {
|
||||
|
||||
namespace detail {
|
||||
/** Inform the processor that we are in a tight spin-wait loop.
|
||||
|
||||
Spinlocks caught in tight loops can result in the processor's pipeline
|
||||
filling up with comparison operations, resulting in a misprediction at
|
||||
the time the lock is finally acquired, necessitating pipeline flushing
|
||||
which is ridiculously expensive and results in very high latency.
|
||||
|
||||
This function instructs the processor to "pause" for some architecture
|
||||
specific amount of time, to prevent this.
|
||||
*/
|
||||
inline void
|
||||
spin_pause() noexcept
|
||||
{
|
||||
#ifdef __aarch64__
|
||||
asm volatile("yield");
|
||||
#else
|
||||
_mm_pause();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/** @{ */
|
||||
/** Classes to handle arrays of spinlocks packed into a single atomic integer:
|
||||
|
||||
Packed spinlocks allow for tremendously space-efficient lock-sharding
|
||||
but they come at a cost.
|
||||
|
||||
First, the implementation is necessarily low-level and uses advanced
|
||||
features like memory ordering and highly platform-specific tricks to
|
||||
maximize performance. This imposes a significant and ongoing cost to
|
||||
developers.
|
||||
|
||||
Second, and perhaps most important, is that the packing of multiple
|
||||
locks into a single integer which, albeit space-efficient, also has
|
||||
performance implications stemming from data dependencies, increased
|
||||
cache-coherency traffic between processors and heavier loads on the
|
||||
processor's load/store units.
|
||||
|
||||
To be sure, these locks can have advantages but they are definitely
|
||||
not general purpose locks and should not be thought of or used that
|
||||
way. The use cases for them are likely few and far between; without
|
||||
a compelling reason to use them, backed by profiling data, it might
|
||||
be best to use one of the standard locking primitives instead. Note
|
||||
that in most common platforms, `std::mutex` is so heavily optimized
|
||||
that it can, usually, outperform spinlocks.
|
||||
|
||||
@tparam T An unsigned integral type (e.g. std::uint16_t)
|
||||
*/
|
||||
|
||||
/** A class that grabs a single packed spinlock from an atomic integer.
|
||||
|
||||
This class meets the requirements of Lockable:
|
||||
https://en.cppreference.com/w/cpp/named_req/Lockable
|
||||
*/
|
||||
template <class T>
|
||||
class packed_spinlock
|
||||
{
|
||||
// clang-format off
|
||||
static_assert(std::is_unsigned_v<T>);
|
||||
static_assert(std::atomic<T>::is_always_lock_free);
|
||||
static_assert(
|
||||
std::is_same_v<decltype(std::declval<std::atomic<T>&>().fetch_or(0)), T> &&
|
||||
std::is_same_v<decltype(std::declval<std::atomic<T>&>().fetch_and(0)), T>,
|
||||
"std::atomic<T>::fetch_and(T) and std::atomic<T>::fetch_and(T) are required by packed_spinlock");
|
||||
// clang-format on
|
||||
|
||||
private:
|
||||
std::atomic<T>& bits_;
|
||||
T const mask_;
|
||||
|
||||
public:
|
||||
packed_spinlock(packed_spinlock const&) = delete;
|
||||
packed_spinlock&
|
||||
operator=(packed_spinlock const&) = delete;
|
||||
|
||||
/** A single spinlock packed inside the specified atomic
|
||||
|
||||
@param lock The atomic integer inside which the spinlock is packed.
|
||||
@param index The index of the spinlock this object acquires.
|
||||
|
||||
@note For performance reasons, you should strive to have `lock` be
|
||||
on a cacheline by itself.
|
||||
*/
|
||||
packed_spinlock(std::atomic<T>& lock, int index)
|
||||
: bits_(lock), mask_(static_cast<T>(1) << index)
|
||||
{
|
||||
assert(index >= 0 && (mask_ != 0));
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
try_lock()
|
||||
{
|
||||
return (bits_.fetch_or(mask_, std::memory_order_acquire) & mask_) == 0;
|
||||
}
|
||||
|
||||
void
|
||||
lock()
|
||||
{
|
||||
while (!try_lock())
|
||||
{
|
||||
// The use of relaxed memory ordering here is intentional and
|
||||
// serves to help reduce cache coherency traffic during times
|
||||
// of contention by avoiding writes that would definitely not
|
||||
// result in the lock being acquired.
|
||||
while ((bits_.load(std::memory_order_relaxed) & mask_) != 0)
|
||||
detail::spin_pause();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
unlock()
|
||||
{
|
||||
bits_.fetch_and(~mask_, std::memory_order_release);
|
||||
}
|
||||
};
|
||||
|
||||
/** A spinlock implemented on top of an atomic integer.
|
||||
|
||||
@note Using `packed_spinlock` and `spinlock` against the same underlying
|
||||
atomic integer can result in `spinlock` not being able to actually
|
||||
acquire the lock during periods of high contention, because of how
|
||||
the two locks operate: `spinlock` will spin trying to grab all the
|
||||
bits at once, whereas any given `packed_spinlock` will only try to
|
||||
grab one bit at a time. Caveat emptor.
|
||||
|
||||
This class meets the requirements of Lockable:
|
||||
https://en.cppreference.com/w/cpp/named_req/Lockable
|
||||
*/
|
||||
template <class T>
|
||||
class spinlock
|
||||
{
|
||||
static_assert(std::is_unsigned_v<T>);
|
||||
static_assert(std::atomic<T>::is_always_lock_free);
|
||||
|
||||
private:
|
||||
std::atomic<T>& lock_;
|
||||
|
||||
public:
|
||||
spinlock(spinlock const&) = delete;
|
||||
spinlock&
|
||||
operator=(spinlock const&) = delete;
|
||||
|
||||
/** Grabs the
|
||||
|
||||
@param lock The atomic integer to spin against.
|
||||
|
||||
@note For performance reasons, you should strive to have `lock` be
|
||||
on a cacheline by itself.
|
||||
*/
|
||||
spinlock(std::atomic<T>& lock) : lock_(lock)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
try_lock()
|
||||
{
|
||||
T expected = 0;
|
||||
|
||||
return lock_.compare_exchange_weak(
|
||||
expected,
|
||||
std::numeric_limits<T>::max(),
|
||||
std::memory_order_acquire,
|
||||
std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void
|
||||
lock()
|
||||
{
|
||||
while (!try_lock())
|
||||
{
|
||||
// The use of relaxed memory ordering here is intentional and
|
||||
// serves to help reduce cache coherency traffic during times
|
||||
// of contention by avoiding writes that would definitely not
|
||||
// result in the lock being acquired.
|
||||
while (lock_.load(std::memory_order_relaxed) != 0)
|
||||
detail::spin_pause();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
unlock()
|
||||
{
|
||||
lock_.store(0, std::memory_order_release);
|
||||
}
|
||||
};
|
||||
/** @} */
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
52
include/xrpl/basics/strHex.h
Normal file
52
include/xrpl/basics/strHex.h
Normal file
@@ -0,0 +1,52 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
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 RIPPLE_BASICS_STRHEX_H_INCLUDED
|
||||
#define RIPPLE_BASICS_STRHEX_H_INCLUDED
|
||||
|
||||
#include <boost/algorithm/hex.hpp>
|
||||
#include <boost/endian/conversion.hpp>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
template <class FwdIt>
|
||||
std::string
|
||||
strHex(FwdIt begin, FwdIt end)
|
||||
{
|
||||
static_assert(
|
||||
std::is_convertible<
|
||||
typename std::iterator_traits<FwdIt>::iterator_category,
|
||||
std::forward_iterator_tag>::value,
|
||||
"FwdIt must be a forward iterator");
|
||||
std::string result;
|
||||
result.reserve(2 * std::distance(begin, end));
|
||||
boost::algorithm::hex(begin, end, std::back_inserter(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T, class = decltype(std::declval<T>().begin())>
|
||||
std::string
|
||||
strHex(T const& from)
|
||||
{
|
||||
return strHex(from.begin(), from.end());
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
227
include/xrpl/basics/tagged_integer.h
Normal file
227
include/xrpl/basics/tagged_integer.h
Normal file
@@ -0,0 +1,227 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright 2014, Nikolaos D. Bougalis <nikb@bougalis.net>
|
||||
|
||||
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_UTILITY_TAGGED_INTEGER_H_INCLUDED
|
||||
#define BEAST_UTILITY_TAGGED_INTEGER_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/hash/hash_append.h>
|
||||
#include <boost/operators.hpp>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** A type-safe wrap around standard integral types
|
||||
|
||||
The tag is used to implement type safety, catching mismatched types at
|
||||
compile time. Multiple instantiations wrapping the same underlying integral
|
||||
type are distinct types (distinguished by tag) and will not interoperate. A
|
||||
tagged_integer supports all the usual assignment, arithmetic, comparison and
|
||||
shifting operations defined for the underlying type
|
||||
|
||||
The tag is not meant as a unit, which would require restricting the set of
|
||||
allowed arithmetic operations.
|
||||
*/
|
||||
template <class Int, class Tag>
|
||||
class tagged_integer
|
||||
: boost::totally_ordered<
|
||||
tagged_integer<Int, Tag>,
|
||||
boost::integer_arithmetic<
|
||||
tagged_integer<Int, Tag>,
|
||||
boost::bitwise<
|
||||
tagged_integer<Int, Tag>,
|
||||
boost::unit_steppable<
|
||||
tagged_integer<Int, Tag>,
|
||||
boost::shiftable<tagged_integer<Int, Tag>>>>>>
|
||||
{
|
||||
private:
|
||||
Int m_value;
|
||||
|
||||
public:
|
||||
using value_type = Int;
|
||||
using tag_type = Tag;
|
||||
|
||||
tagged_integer() = default;
|
||||
|
||||
template <
|
||||
class OtherInt,
|
||||
class = typename std::enable_if<
|
||||
std::is_integral<OtherInt>::value &&
|
||||
sizeof(OtherInt) <= sizeof(Int)>::type>
|
||||
explicit constexpr tagged_integer(OtherInt value) noexcept : m_value(value)
|
||||
{
|
||||
static_assert(
|
||||
sizeof(tagged_integer) == sizeof(Int),
|
||||
"tagged_integer is adding padding");
|
||||
}
|
||||
|
||||
bool
|
||||
operator<(const tagged_integer& rhs) const noexcept
|
||||
{
|
||||
return m_value < rhs.m_value;
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(const tagged_integer& rhs) const noexcept
|
||||
{
|
||||
return m_value == rhs.m_value;
|
||||
}
|
||||
|
||||
tagged_integer&
|
||||
operator+=(tagged_integer const& rhs) noexcept
|
||||
{
|
||||
m_value += rhs.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
tagged_integer&
|
||||
operator-=(tagged_integer const& rhs) noexcept
|
||||
{
|
||||
m_value -= rhs.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
tagged_integer&
|
||||
operator*=(tagged_integer const& rhs) noexcept
|
||||
{
|
||||
m_value *= rhs.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
tagged_integer&
|
||||
operator/=(tagged_integer const& rhs) noexcept
|
||||
{
|
||||
m_value /= rhs.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
tagged_integer&
|
||||
operator%=(tagged_integer const& rhs) noexcept
|
||||
{
|
||||
m_value %= rhs.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
tagged_integer&
|
||||
operator|=(tagged_integer const& rhs) noexcept
|
||||
{
|
||||
m_value |= rhs.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
tagged_integer&
|
||||
operator&=(tagged_integer const& rhs) noexcept
|
||||
{
|
||||
m_value &= rhs.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
tagged_integer&
|
||||
operator^=(tagged_integer const& rhs) noexcept
|
||||
{
|
||||
m_value ^= rhs.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
tagged_integer&
|
||||
operator<<=(const tagged_integer& rhs) noexcept
|
||||
{
|
||||
m_value <<= rhs.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
tagged_integer&
|
||||
operator>>=(const tagged_integer& rhs) noexcept
|
||||
{
|
||||
m_value >>= rhs.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
tagged_integer
|
||||
operator~() const noexcept
|
||||
{
|
||||
return tagged_integer{~m_value};
|
||||
}
|
||||
|
||||
tagged_integer
|
||||
operator+() const noexcept
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
tagged_integer
|
||||
operator-() const noexcept
|
||||
{
|
||||
return tagged_integer{-m_value};
|
||||
}
|
||||
|
||||
tagged_integer&
|
||||
operator++() noexcept
|
||||
{
|
||||
++m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
tagged_integer&
|
||||
operator--() noexcept
|
||||
{
|
||||
--m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit operator Int() const noexcept
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& s, tagged_integer const& t)
|
||||
{
|
||||
s << t.m_value;
|
||||
return s;
|
||||
}
|
||||
|
||||
friend std::istream&
|
||||
operator>>(std::istream& s, tagged_integer& t)
|
||||
{
|
||||
s >> t.m_value;
|
||||
return s;
|
||||
}
|
||||
|
||||
friend std::string
|
||||
to_string(tagged_integer const& t)
|
||||
{
|
||||
return std::to_string(t.m_value);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
namespace beast {
|
||||
template <class Int, class Tag, class HashAlgorithm>
|
||||
struct is_contiguously_hashable<ripple::tagged_integer<Int, Tag>, HashAlgorithm>
|
||||
: public is_contiguously_hashable<Int, HashAlgorithm>
|
||||
{
|
||||
explicit is_contiguously_hashable() = default;
|
||||
};
|
||||
|
||||
} // namespace beast
|
||||
#endif
|
||||
256
include/xrpl/beast/asio/io_latency_probe.h
Normal file
256
include/xrpl/beast/asio/io_latency_probe.h
Normal file
@@ -0,0 +1,256 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_IO_LATENCY_PROBE_H_INCLUDED
|
||||
#define BEAST_ASIO_IO_LATENCY_PROBE_H_INCLUDED
|
||||
|
||||
#include <boost/asio/basic_waitable_timer.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** Measures handler latency on an io_service queue. */
|
||||
template <class Clock>
|
||||
class io_latency_probe
|
||||
{
|
||||
private:
|
||||
using duration = typename Clock::duration;
|
||||
using time_point = typename Clock::time_point;
|
||||
|
||||
std::recursive_mutex m_mutex;
|
||||
std::condition_variable_any m_cond;
|
||||
std::size_t m_count;
|
||||
duration const m_period;
|
||||
boost::asio::io_service& m_ios;
|
||||
boost::asio::basic_waitable_timer<std::chrono::steady_clock> m_timer;
|
||||
bool m_cancel;
|
||||
|
||||
public:
|
||||
io_latency_probe(duration const& period, boost::asio::io_service& ios)
|
||||
: m_count(1)
|
||||
, m_period(period)
|
||||
, m_ios(ios)
|
||||
, m_timer(m_ios)
|
||||
, m_cancel(false)
|
||||
{
|
||||
}
|
||||
|
||||
~io_latency_probe()
|
||||
{
|
||||
std::unique_lock<decltype(m_mutex)> lock(m_mutex);
|
||||
cancel(lock, true);
|
||||
}
|
||||
|
||||
/** Return the io_service associated with the latency probe. */
|
||||
/** @{ */
|
||||
boost::asio::io_service&
|
||||
get_io_service()
|
||||
{
|
||||
return m_ios;
|
||||
}
|
||||
|
||||
boost::asio::io_service const&
|
||||
get_io_service() const
|
||||
{
|
||||
return m_ios;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Cancel all pending i/o.
|
||||
Any handlers which have already been queued will still be called.
|
||||
*/
|
||||
/** @{ */
|
||||
void
|
||||
cancel()
|
||||
{
|
||||
std::unique_lock<decltype(m_mutex)> lock(m_mutex);
|
||||
cancel(lock, true);
|
||||
}
|
||||
|
||||
void
|
||||
cancel_async()
|
||||
{
|
||||
std::unique_lock<decltype(m_mutex)> lock(m_mutex);
|
||||
cancel(lock, false);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Measure one sample of i/o latency.
|
||||
Handler will be called with this signature:
|
||||
void Handler (Duration d);
|
||||
*/
|
||||
template <class Handler>
|
||||
void
|
||||
sample_one(Handler&& handler)
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
if (m_cancel)
|
||||
throw std::logic_error("io_latency_probe is canceled");
|
||||
m_ios.post(sample_op<Handler>(
|
||||
std::forward<Handler>(handler), Clock::now(), false, this));
|
||||
}
|
||||
|
||||
/** Initiate continuous i/o latency sampling.
|
||||
Handler will be called with this signature:
|
||||
void Handler (std::chrono::milliseconds);
|
||||
*/
|
||||
template <class Handler>
|
||||
void
|
||||
sample(Handler&& handler)
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
if (m_cancel)
|
||||
throw std::logic_error("io_latency_probe is canceled");
|
||||
m_ios.post(sample_op<Handler>(
|
||||
std::forward<Handler>(handler), Clock::now(), true, this));
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
cancel(std::unique_lock<decltype(m_mutex)>& lock, bool wait)
|
||||
{
|
||||
if (!m_cancel)
|
||||
{
|
||||
--m_count;
|
||||
m_cancel = true;
|
||||
}
|
||||
|
||||
if (wait)
|
||||
m_cond.wait(lock, [this] { return this->m_count == 0; });
|
||||
}
|
||||
|
||||
void
|
||||
addref()
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
++m_count;
|
||||
}
|
||||
|
||||
void
|
||||
release()
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
if (--m_count == 0)
|
||||
m_cond.notify_all();
|
||||
}
|
||||
|
||||
template <class Handler>
|
||||
struct sample_op
|
||||
{
|
||||
Handler m_handler;
|
||||
time_point m_start;
|
||||
bool m_repeat;
|
||||
io_latency_probe* m_probe;
|
||||
|
||||
sample_op(
|
||||
Handler const& handler,
|
||||
time_point const& start,
|
||||
bool repeat,
|
||||
io_latency_probe* probe)
|
||||
: m_handler(handler)
|
||||
, m_start(start)
|
||||
, m_repeat(repeat)
|
||||
, m_probe(probe)
|
||||
{
|
||||
assert(m_probe);
|
||||
m_probe->addref();
|
||||
}
|
||||
|
||||
sample_op(sample_op&& from) noexcept
|
||||
: m_handler(std::move(from.m_handler))
|
||||
, m_start(from.m_start)
|
||||
, m_repeat(from.m_repeat)
|
||||
, m_probe(from.m_probe)
|
||||
{
|
||||
assert(m_probe);
|
||||
from.m_probe = nullptr;
|
||||
}
|
||||
|
||||
sample_op(sample_op const&) = delete;
|
||||
sample_op
|
||||
operator=(sample_op const&) = delete;
|
||||
sample_op&
|
||||
operator=(sample_op&&) = delete;
|
||||
|
||||
~sample_op()
|
||||
{
|
||||
if (m_probe)
|
||||
m_probe->release();
|
||||
}
|
||||
|
||||
void
|
||||
operator()() const
|
||||
{
|
||||
if (!m_probe)
|
||||
return;
|
||||
typename Clock::time_point const now(Clock::now());
|
||||
typename Clock::duration const elapsed(now - m_start);
|
||||
|
||||
m_handler(elapsed);
|
||||
|
||||
{
|
||||
std::lock_guard lock(m_probe->m_mutex);
|
||||
if (m_probe->m_cancel)
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_repeat)
|
||||
{
|
||||
// Calculate when we want to sample again, and
|
||||
// adjust for the expected latency.
|
||||
//
|
||||
typename Clock::time_point const when(
|
||||
now + m_probe->m_period - 2 * elapsed);
|
||||
|
||||
if (when <= now)
|
||||
{
|
||||
// The latency is too high to maintain the desired
|
||||
// period so don't bother with a timer.
|
||||
//
|
||||
m_probe->m_ios.post(
|
||||
sample_op<Handler>(m_handler, now, m_repeat, m_probe));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_probe->m_timer.expires_from_now(when - now);
|
||||
m_probe->m_timer.async_wait(
|
||||
sample_op<Handler>(m_handler, now, m_repeat, m_probe));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
operator()(boost::system::error_code const& ec)
|
||||
{
|
||||
if (!m_probe)
|
||||
return;
|
||||
typename Clock::time_point const now(Clock::now());
|
||||
m_probe->m_ios.post(
|
||||
sample_op<Handler>(m_handler, now, m_repeat, m_probe));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
115
include/xrpl/beast/clock/abstract_clock.h
Normal file
115
include/xrpl/beast/clock/abstract_clock.h
Normal file
@@ -0,0 +1,115 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_CHRONO_ABSTRACT_CLOCK_H_INCLUDED
|
||||
#define BEAST_CHRONO_ABSTRACT_CLOCK_H_INCLUDED
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** Abstract interface to a clock.
|
||||
|
||||
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:
|
||||
|
||||
@code
|
||||
|
||||
struct Implementation
|
||||
{
|
||||
using clock_type = abstract_clock <std::chrono::steady_clock>;
|
||||
clock_type& clock_;
|
||||
explicit Implementation (clock_type& clock)
|
||||
: clock_(clock)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@endcode
|
||||
|
||||
@tparam Clock A type meeting these requirements:
|
||||
http://en.cppreference.com/w/cpp/concept/Clock
|
||||
*/
|
||||
template <class Clock>
|
||||
class abstract_clock
|
||||
{
|
||||
public:
|
||||
using rep = typename Clock::rep;
|
||||
using period = typename Clock::period;
|
||||
using duration = typename Clock::duration;
|
||||
using time_point = typename Clock::time_point;
|
||||
using clock_type = Clock;
|
||||
|
||||
static bool const is_steady = Clock::is_steady;
|
||||
|
||||
virtual ~abstract_clock() = default;
|
||||
abstract_clock() = default;
|
||||
abstract_clock(abstract_clock const&) = default;
|
||||
|
||||
/** Returns the current time. */
|
||||
[[nodiscard]] virtual time_point
|
||||
now() const = 0;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class Facade, class Clock>
|
||||
struct abstract_clock_wrapper : public abstract_clock<Facade>
|
||||
{
|
||||
explicit abstract_clock_wrapper() = default;
|
||||
|
||||
using typename abstract_clock<Facade>::duration;
|
||||
using typename abstract_clock<Facade>::time_point;
|
||||
|
||||
time_point
|
||||
now() const override
|
||||
{
|
||||
return Clock::now();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** 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 Facade, class Clock = Facade>
|
||||
abstract_clock<Facade>&
|
||||
get_abstract_clock()
|
||||
{
|
||||
static detail::abstract_clock_wrapper<Facade, Clock> clock;
|
||||
return clock;
|
||||
}
|
||||
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
56
include/xrpl/beast/clock/basic_seconds_clock.h
Normal file
56
include/xrpl/beast/clock/basic_seconds_clock.h
Normal file
@@ -0,0 +1,56 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_CHRONO_BASIC_SECONDS_CLOCK_H_INCLUDED
|
||||
#define BEAST_CHRONO_BASIC_SECONDS_CLOCK_H_INCLUDED
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** 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 Clock A type meeting these requirements:
|
||||
http://en.cppreference.com/w/cpp/concept/Clock
|
||||
*/
|
||||
class basic_seconds_clock
|
||||
{
|
||||
public:
|
||||
using Clock = std::chrono::steady_clock;
|
||||
|
||||
explicit basic_seconds_clock() = default;
|
||||
|
||||
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 = Clock::is_steady;
|
||||
|
||||
static time_point
|
||||
now();
|
||||
};
|
||||
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
96
include/xrpl/beast/clock/manual_clock.h
Normal file
96
include/xrpl/beast/clock/manual_clock.h
Normal file
@@ -0,0 +1,96 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_CHRONO_MANUAL_CLOCK_H_INCLUDED
|
||||
#define BEAST_CHRONO_MANUAL_CLOCK_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/clock/abstract_clock.h>
|
||||
#include <cassert>
|
||||
|
||||
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 Clock A type meeting these requirements:
|
||||
http://en.cppreference.com/w/cpp/concept/Clock
|
||||
*/
|
||||
template <class Clock>
|
||||
class manual_clock : public abstract_clock<Clock>
|
||||
{
|
||||
public:
|
||||
using typename abstract_clock<Clock>::rep;
|
||||
using typename abstract_clock<Clock>::duration;
|
||||
using typename abstract_clock<Clock>::time_point;
|
||||
|
||||
private:
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
35
include/xrpl/beast/container/aged_container.h
Normal file
35
include/xrpl/beast/container/aged_container.h
Normal file
@@ -0,0 +1,35 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_CONTAINER_AGED_CONTAINER_H_INCLUDED
|
||||
#define BEAST_CONTAINER_AGED_CONTAINER_H_INCLUDED
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
|
||||
template <class T>
|
||||
struct is_aged_container : std::false_type
|
||||
{
|
||||
explicit is_aged_container() = default;
|
||||
};
|
||||
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
48
include/xrpl/beast/container/aged_container_utility.h
Normal file
48
include/xrpl/beast/container/aged_container_utility.h
Normal file
@@ -0,0 +1,48 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_CONTAINER_AGED_CONTAINER_UTILITY_H_INCLUDED
|
||||
#define BEAST_CONTAINER_AGED_CONTAINER_UTILITY_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/container/aged_container.h>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** Expire aged container items past the specified age. */
|
||||
template <class AgedContainer, class Rep, class Period>
|
||||
typename std::enable_if<is_aged_container<AgedContainer>::value, std::size_t>::
|
||||
type
|
||||
expire(AgedContainer& c, std::chrono::duration<Rep, Period> const& age)
|
||||
{
|
||||
std::size_t n(0);
|
||||
auto const expired(c.clock().now() - age);
|
||||
for (auto iter(c.chronological.cbegin());
|
||||
iter != c.chronological.cend() && iter.when() <= expired;)
|
||||
{
|
||||
iter = c.erase(iter);
|
||||
++n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
42
include/xrpl/beast/container/aged_map.h
Normal file
42
include/xrpl/beast/container/aged_map.h
Normal file
@@ -0,0 +1,42 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_CONTAINER_AGED_MAP_H_INCLUDED
|
||||
#define BEAST_CONTAINER_AGED_MAP_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/container/detail/aged_ordered_container.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace beast {
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class T,
|
||||
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, Clock, Compare, Allocator>;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
42
include/xrpl/beast/container/aged_multimap.h
Normal file
42
include/xrpl/beast/container/aged_multimap.h
Normal file
@@ -0,0 +1,42 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_CONTAINER_AGED_MULTIMAP_H_INCLUDED
|
||||
#define BEAST_CONTAINER_AGED_MULTIMAP_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/container/detail/aged_ordered_container.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace beast {
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class T,
|
||||
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, Clock, Compare, Allocator>;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
41
include/xrpl/beast/container/aged_multiset.h
Normal file
41
include/xrpl/beast/container/aged_multiset.h
Normal file
@@ -0,0 +1,41 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_CONTAINER_AGED_MULTISET_H_INCLUDED
|
||||
#define BEAST_CONTAINER_AGED_MULTISET_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/container/detail/aged_ordered_container.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace beast {
|
||||
|
||||
template <
|
||||
class Key,
|
||||
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, Clock, Compare, Allocator>;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
41
include/xrpl/beast/container/aged_set.h
Normal file
41
include/xrpl/beast/container/aged_set.h
Normal file
@@ -0,0 +1,41 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_CONTAINER_AGED_SET_H_INCLUDED
|
||||
#define BEAST_CONTAINER_AGED_SET_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/container/detail/aged_ordered_container.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace beast {
|
||||
|
||||
template <
|
||||
class Key,
|
||||
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, Clock, Compare, Allocator>;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
50
include/xrpl/beast/container/aged_unordered_map.h
Normal file
50
include/xrpl/beast/container/aged_unordered_map.h
Normal file
@@ -0,0 +1,50 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_CONTAINER_AGED_UNORDERED_MAP_H_INCLUDED
|
||||
#define BEAST_CONTAINER_AGED_UNORDERED_MAP_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/container/detail/aged_unordered_container.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace beast {
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class T,
|
||||
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,
|
||||
Clock,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Allocator>;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
50
include/xrpl/beast/container/aged_unordered_multimap.h
Normal file
50
include/xrpl/beast/container/aged_unordered_multimap.h
Normal file
@@ -0,0 +1,50 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_CONTAINER_AGED_UNORDERED_MULTIMAP_H_INCLUDED
|
||||
#define BEAST_CONTAINER_AGED_UNORDERED_MULTIMAP_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/container/detail/aged_unordered_container.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace beast {
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class T,
|
||||
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,
|
||||
Clock,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Allocator>;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
49
include/xrpl/beast/container/aged_unordered_multiset.h
Normal file
49
include/xrpl/beast/container/aged_unordered_multiset.h
Normal file
@@ -0,0 +1,49 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_CONTAINER_AGED_UNORDERED_MULTISET_H_INCLUDED
|
||||
#define BEAST_CONTAINER_AGED_UNORDERED_MULTISET_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/container/detail/aged_unordered_container.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace beast {
|
||||
|
||||
template <
|
||||
class Key,
|
||||
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,
|
||||
Clock,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Allocator>;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
49
include/xrpl/beast/container/aged_unordered_set.h
Normal file
49
include/xrpl/beast/container/aged_unordered_set.h
Normal file
@@ -0,0 +1,49 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_CONTAINER_AGED_UNORDERED_SET_H_INCLUDED
|
||||
#define BEAST_CONTAINER_AGED_UNORDERED_SET_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/container/detail/aged_unordered_container.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace beast {
|
||||
|
||||
template <
|
||||
class Key,
|
||||
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,
|
||||
Clock,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Allocator>;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,58 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_CONTAINER_DETAIL_AGED_ASSOCIATIVE_CONTAINER_H_INCLUDED
|
||||
#define BEAST_CONTAINER_DETAIL_AGED_ASSOCIATIVE_CONTAINER_H_INCLUDED
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
// Extracts the key portion of value
|
||||
template <bool maybe_map>
|
||||
struct aged_associative_container_extract_t
|
||||
{
|
||||
explicit aged_associative_container_extract_t() = default;
|
||||
|
||||
template <class Value>
|
||||
decltype(Value::first) const&
|
||||
operator()(Value const& value) const
|
||||
{
|
||||
return value.first;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct aged_associative_container_extract_t<false>
|
||||
{
|
||||
explicit aged_associative_container_extract_t() = default;
|
||||
|
||||
template <class Value>
|
||||
Value const&
|
||||
operator()(Value const& value) const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
182
include/xrpl/beast/container/detail/aged_container_iterator.h
Normal file
182
include/xrpl/beast/container/detail/aged_container_iterator.h
Normal file
@@ -0,0 +1,182 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_CONTAINER_DETAIL_AGED_CONTAINER_ITERATOR_H_INCLUDED
|
||||
#define BEAST_CONTAINER_DETAIL_AGED_CONTAINER_ITERATOR_H_INCLUDED
|
||||
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
|
||||
template <bool, bool, class, class, class, class, class>
|
||||
class aged_ordered_container;
|
||||
|
||||
namespace detail {
|
||||
|
||||
// If Iterator is SCARY then this iterator will be as well.
|
||||
template <bool is_const, class Iterator>
|
||||
class aged_container_iterator
|
||||
{
|
||||
public:
|
||||
using iterator_category =
|
||||
typename std::iterator_traits<Iterator>::iterator_category;
|
||||
using value_type = typename std::conditional<
|
||||
is_const,
|
||||
typename Iterator::value_type::stashed::value_type const,
|
||||
typename Iterator::value_type::stashed::value_type>::type;
|
||||
using difference_type =
|
||||
typename std::iterator_traits<Iterator>::difference_type;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
using time_point = typename Iterator::value_type::stashed::time_point;
|
||||
|
||||
aged_container_iterator() = default;
|
||||
|
||||
// Disable constructing a const_iterator from a non-const_iterator.
|
||||
// Converting between reverse and non-reverse iterators should be explicit.
|
||||
template <
|
||||
bool other_is_const,
|
||||
class OtherIterator,
|
||||
class = typename std::enable_if<
|
||||
(other_is_const == false || is_const == true) &&
|
||||
std::is_same<Iterator, OtherIterator>::value == false>::type>
|
||||
explicit aged_container_iterator(
|
||||
aged_container_iterator<other_is_const, OtherIterator> const& other)
|
||||
: m_iter(other.m_iter)
|
||||
{
|
||||
}
|
||||
|
||||
// Disable constructing a const_iterator from a non-const_iterator.
|
||||
template <
|
||||
bool other_is_const,
|
||||
class = typename std::enable_if<
|
||||
other_is_const == false || is_const == true>::type>
|
||||
aged_container_iterator(
|
||||
aged_container_iterator<other_is_const, Iterator> const& other)
|
||||
: m_iter(other.m_iter)
|
||||
{
|
||||
}
|
||||
|
||||
// Disable assigning a const_iterator to a non-const iterator
|
||||
template <bool other_is_const, class OtherIterator>
|
||||
auto
|
||||
operator=(
|
||||
aged_container_iterator<other_is_const, OtherIterator> const& other) ->
|
||||
typename std::enable_if<
|
||||
other_is_const == false || is_const == true,
|
||||
aged_container_iterator&>::type
|
||||
{
|
||||
m_iter = other.m_iter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <bool other_is_const, class OtherIterator>
|
||||
bool
|
||||
operator==(aged_container_iterator<other_is_const, OtherIterator> const&
|
||||
other) const
|
||||
{
|
||||
return m_iter == other.m_iter;
|
||||
}
|
||||
|
||||
template <bool other_is_const, class OtherIterator>
|
||||
bool
|
||||
operator!=(aged_container_iterator<other_is_const, OtherIterator> const&
|
||||
other) const
|
||||
{
|
||||
return m_iter != other.m_iter;
|
||||
}
|
||||
|
||||
aged_container_iterator&
|
||||
operator++()
|
||||
{
|
||||
++m_iter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
aged_container_iterator
|
||||
operator++(int)
|
||||
{
|
||||
aged_container_iterator const prev(*this);
|
||||
++m_iter;
|
||||
return prev;
|
||||
}
|
||||
|
||||
aged_container_iterator&
|
||||
operator--()
|
||||
{
|
||||
--m_iter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
aged_container_iterator
|
||||
operator--(int)
|
||||
{
|
||||
aged_container_iterator const prev(*this);
|
||||
--m_iter;
|
||||
return prev;
|
||||
}
|
||||
|
||||
reference
|
||||
operator*() const
|
||||
{
|
||||
return m_iter->value;
|
||||
}
|
||||
|
||||
pointer
|
||||
operator->() const
|
||||
{
|
||||
return &m_iter->value;
|
||||
}
|
||||
|
||||
time_point const&
|
||||
when() const
|
||||
{
|
||||
return m_iter->when;
|
||||
}
|
||||
|
||||
private:
|
||||
template <bool, bool, class, class, class, class, class>
|
||||
friend class aged_ordered_container;
|
||||
|
||||
template <bool, bool, class, class, class, class, class, class>
|
||||
friend class aged_unordered_container;
|
||||
|
||||
template <bool, class>
|
||||
friend class aged_container_iterator;
|
||||
|
||||
template <class OtherIterator>
|
||||
aged_container_iterator(OtherIterator const& iter) : m_iter(iter)
|
||||
{
|
||||
}
|
||||
|
||||
Iterator const&
|
||||
iterator() const
|
||||
{
|
||||
return m_iter;
|
||||
}
|
||||
|
||||
Iterator m_iter;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
2294
include/xrpl/beast/container/detail/aged_ordered_container.h
Normal file
2294
include/xrpl/beast/container/detail/aged_ordered_container.h
Normal file
File diff suppressed because it is too large
Load Diff
3441
include/xrpl/beast/container/detail/aged_unordered_container.h
Normal file
3441
include/xrpl/beast/container/detail/aged_unordered_container.h
Normal file
File diff suppressed because it is too large
Load Diff
100
include/xrpl/beast/container/detail/empty_base_optimization.h
Normal file
100
include/xrpl/beast/container/detail/empty_base_optimization.h
Normal file
@@ -0,0 +1,100 @@
|
||||
//
|
||||
// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/beast
|
||||
//
|
||||
|
||||
#ifndef BEAST_CONTAINER_DETAIL_EMPTY_BASE_OPTIMIZATION_H_INCLUDED
|
||||
#define BEAST_CONTAINER_DETAIL_EMPTY_BASE_OPTIMIZATION_H_INCLUDED
|
||||
|
||||
#include <boost/type_traits/is_final.hpp>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
template <class T>
|
||||
struct is_empty_base_optimization_derived
|
||||
: std::integral_constant<
|
||||
bool,
|
||||
std::is_empty<T>::value && !boost::is_final<T>::value>
|
||||
{
|
||||
};
|
||||
|
||||
template <
|
||||
class T,
|
||||
int UniqueID = 0,
|
||||
bool isDerived = is_empty_base_optimization_derived<T>::value>
|
||||
class empty_base_optimization : private T
|
||||
{
|
||||
public:
|
||||
empty_base_optimization() = default;
|
||||
empty_base_optimization(empty_base_optimization&&) = default;
|
||||
empty_base_optimization(empty_base_optimization const&) = default;
|
||||
empty_base_optimization&
|
||||
operator=(empty_base_optimization&&) = default;
|
||||
empty_base_optimization&
|
||||
operator=(empty_base_optimization const&) = default;
|
||||
|
||||
template <class Arg1, class... ArgN>
|
||||
explicit empty_base_optimization(Arg1&& arg1, ArgN&&... argn)
|
||||
: T(std::forward<Arg1>(arg1), std::forward<ArgN>(argn)...)
|
||||
{
|
||||
}
|
||||
|
||||
T&
|
||||
member() noexcept
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
T const&
|
||||
member() const noexcept
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class T, int UniqueID>
|
||||
class empty_base_optimization<T, UniqueID, false>
|
||||
{
|
||||
T t_;
|
||||
|
||||
public:
|
||||
empty_base_optimization() = default;
|
||||
empty_base_optimization(empty_base_optimization&&) = default;
|
||||
empty_base_optimization(empty_base_optimization const&) = default;
|
||||
empty_base_optimization&
|
||||
operator=(empty_base_optimization&&) = default;
|
||||
empty_base_optimization&
|
||||
operator=(empty_base_optimization const&) = default;
|
||||
|
||||
template <class Arg1, class... ArgN>
|
||||
explicit empty_base_optimization(Arg1&& arg1, ArgN&&... argn)
|
||||
: t_(std::forward<Arg1>(arg1), std::forward<ArgN>(argn)...)
|
||||
{
|
||||
}
|
||||
|
||||
T&
|
||||
member() noexcept
|
||||
{
|
||||
return t_;
|
||||
}
|
||||
|
||||
T const&
|
||||
member() const noexcept
|
||||
{
|
||||
return t_;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
51
include/xrpl/beast/core/CurrentThreadName.h
Normal file
51
include/xrpl/beast/core/CurrentThreadName.h
Normal file
@@ -0,0 +1,51 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_CORE_CURRENT_THREAD_NAME_H_INCLUDED
|
||||
#define BEAST_CORE_CURRENT_THREAD_NAME_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** Changes the name of the caller thread.
|
||||
Different OSes may place different length or content limits on this name.
|
||||
*/
|
||||
void
|
||||
setCurrentThreadName(std::string_view newThreadName);
|
||||
|
||||
/** Returns the name of the caller thread.
|
||||
|
||||
The name returned is the name as set by a call to setCurrentThreadName().
|
||||
If the thread name is set by an external force, then that name change
|
||||
will not be reported.
|
||||
|
||||
If no name has ever been set, then the empty string is returned.
|
||||
*/
|
||||
std::string
|
||||
getCurrentThreadName();
|
||||
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
237
include/xrpl/beast/core/LexicalCast.h
Normal file
237
include/xrpl/beast/core/LexicalCast.h
Normal file
@@ -0,0 +1,237 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_MODULE_CORE_TEXT_LEXICALCAST_H_INCLUDED
|
||||
#define BEAST_MODULE_CORE_TEXT_LEXICALCAST_H_INCLUDED
|
||||
|
||||
#include <boost/core/detail/string_view.hpp>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
#include <charconv>
|
||||
#include <cstdlib>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
|
||||
namespace detail {
|
||||
|
||||
// These specializatons get called by the non-member functions to do the work
|
||||
template <class Out, class In>
|
||||
struct LexicalCast;
|
||||
|
||||
// conversion to std::string
|
||||
template <class In>
|
||||
struct LexicalCast<std::string, In>
|
||||
{
|
||||
explicit LexicalCast() = default;
|
||||
|
||||
template <class Arithmetic = In>
|
||||
std::enable_if_t<std::is_arithmetic_v<Arithmetic>, bool>
|
||||
operator()(std::string& out, Arithmetic in)
|
||||
{
|
||||
out = std::to_string(in);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Enumeration = In>
|
||||
std::enable_if_t<std::is_enum_v<Enumeration>, bool>
|
||||
operator()(std::string& out, Enumeration in)
|
||||
{
|
||||
out = std::to_string(
|
||||
static_cast<std::underlying_type_t<Enumeration>>(in));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Parse a std::string_view into a number
|
||||
template <typename Out>
|
||||
struct LexicalCast<Out, std::string_view>
|
||||
{
|
||||
explicit LexicalCast() = default;
|
||||
|
||||
static_assert(
|
||||
std::is_integral_v<Out>,
|
||||
"beast::LexicalCast can only be used with integral types");
|
||||
|
||||
template <class Integral = Out>
|
||||
std::enable_if_t<
|
||||
std::is_integral_v<Integral> && !std::is_same_v<Integral, bool>,
|
||||
bool>
|
||||
operator()(Integral& out, std::string_view in) const
|
||||
{
|
||||
auto first = in.data();
|
||||
auto last = in.data() + in.size();
|
||||
|
||||
if (first != last && *first == '+')
|
||||
++first;
|
||||
|
||||
auto ret = std::from_chars(first, last, out);
|
||||
|
||||
return ret.ec == std::errc() && ret.ptr == last;
|
||||
}
|
||||
|
||||
bool
|
||||
operator()(bool& out, std::string_view in) const
|
||||
{
|
||||
std::string result;
|
||||
|
||||
// Convert the input to lowercase
|
||||
std::transform(
|
||||
in.begin(), in.end(), std::back_inserter(result), [](auto c) {
|
||||
return std::tolower(static_cast<unsigned char>(c));
|
||||
});
|
||||
|
||||
if (result == "1" || result == "true")
|
||||
{
|
||||
out = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (result == "0" || result == "false")
|
||||
{
|
||||
out = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Parse boost library's string_view to number or boolean value
|
||||
// Note: As of Jan 2024, Boost contains three different types of string_view
|
||||
// (boost::core::basic_string_view<char>, boost::string_ref and
|
||||
// boost::string_view). The below template specialization is included because
|
||||
// it is used in the handshake.cpp file
|
||||
template <class Out>
|
||||
struct LexicalCast<Out, boost::core::basic_string_view<char>>
|
||||
{
|
||||
explicit LexicalCast() = default;
|
||||
|
||||
bool
|
||||
operator()(Out& out, boost::core::basic_string_view<char> in) const
|
||||
{
|
||||
return LexicalCast<Out, std::string_view>()(out, in);
|
||||
}
|
||||
};
|
||||
|
||||
// Parse std::string to number or boolean value
|
||||
template <class Out>
|
||||
struct LexicalCast<Out, std::string>
|
||||
{
|
||||
explicit LexicalCast() = default;
|
||||
|
||||
bool
|
||||
operator()(Out& out, std::string in) const
|
||||
{
|
||||
return LexicalCast<Out, std::string_view>()(out, in);
|
||||
}
|
||||
};
|
||||
|
||||
// Conversion from null terminated char const*
|
||||
template <class Out>
|
||||
struct LexicalCast<Out, char const*>
|
||||
{
|
||||
explicit LexicalCast() = default;
|
||||
|
||||
bool
|
||||
operator()(Out& out, char const* in) const
|
||||
{
|
||||
assert(in);
|
||||
return LexicalCast<Out, std::string_view>()(out, in);
|
||||
}
|
||||
};
|
||||
|
||||
// Conversion from null terminated char*
|
||||
// The string is not modified.
|
||||
template <class Out>
|
||||
struct LexicalCast<Out, char*>
|
||||
{
|
||||
explicit LexicalCast() = default;
|
||||
|
||||
bool
|
||||
operator()(Out& out, char* in) const
|
||||
{
|
||||
assert(in);
|
||||
return LexicalCast<Out, std::string_view>()(out, in);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Thrown when a conversion is not possible with LexicalCast.
|
||||
Only used in the throw variants of lexicalCast.
|
||||
*/
|
||||
struct BadLexicalCast : public std::bad_cast
|
||||
{
|
||||
explicit BadLexicalCast() = default;
|
||||
};
|
||||
|
||||
/** Intelligently convert from one type to another.
|
||||
@return `false` if there was a parsing or range error
|
||||
*/
|
||||
template <class Out, class In>
|
||||
bool
|
||||
lexicalCastChecked(Out& out, In in)
|
||||
{
|
||||
return detail::LexicalCast<Out, In>()(out, in);
|
||||
}
|
||||
|
||||
/** Convert from one type to another, throw on error
|
||||
|
||||
An exception of type BadLexicalCast is thrown if the conversion fails.
|
||||
|
||||
@return The new type.
|
||||
*/
|
||||
template <class Out, class In>
|
||||
Out
|
||||
lexicalCastThrow(In in)
|
||||
{
|
||||
if (Out out; lexicalCastChecked(out, in))
|
||||
return out;
|
||||
|
||||
throw BadLexicalCast();
|
||||
}
|
||||
|
||||
/** Convert from one type to another.
|
||||
|
||||
@param defaultValue The value returned if parsing fails
|
||||
@return The new type.
|
||||
*/
|
||||
template <class Out, class In>
|
||||
Out
|
||||
lexicalCast(In in, Out defaultValue = Out())
|
||||
{
|
||||
if (Out out; lexicalCastChecked(out, in))
|
||||
return out;
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
599
include/xrpl/beast/core/List.h
Normal file
599
include/xrpl/beast/core/List.h
Normal file
@@ -0,0 +1,599 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_INTRUSIVE_LIST_H_INCLUDED
|
||||
#define BEAST_INTRUSIVE_LIST_H_INCLUDED
|
||||
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
|
||||
template <typename, typename>
|
||||
class List;
|
||||
|
||||
namespace detail {
|
||||
|
||||
/** Copy `const` attribute from T to U if present. */
|
||||
/** @{ */
|
||||
template <typename T, typename U>
|
||||
struct CopyConst
|
||||
{
|
||||
explicit CopyConst() = default;
|
||||
|
||||
using type = typename std::remove_const<U>::type;
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
struct CopyConst<T const, U>
|
||||
{
|
||||
explicit CopyConst() = default;
|
||||
|
||||
using type = typename std::remove_const<U>::type const;
|
||||
};
|
||||
/** @} */
|
||||
|
||||
// This is the intrusive portion of the doubly linked list.
|
||||
// One derivation per list that the object may appear on
|
||||
// concurrently is required.
|
||||
//
|
||||
template <typename T, typename Tag>
|
||||
class ListNode
|
||||
{
|
||||
private:
|
||||
using value_type = T;
|
||||
|
||||
friend class List<T, Tag>;
|
||||
|
||||
template <typename>
|
||||
friend class ListIterator;
|
||||
|
||||
ListNode* m_next;
|
||||
ListNode* m_prev;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <typename N>
|
||||
class ListIterator
|
||||
{
|
||||
public:
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using value_type =
|
||||
typename beast::detail::CopyConst<N, typename N::value_type>::type;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
using size_type = std::size_t;
|
||||
|
||||
ListIterator(N* node = nullptr) noexcept : m_node(node)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename M>
|
||||
ListIterator(ListIterator<M> const& other) noexcept : m_node(other.m_node)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename M>
|
||||
bool
|
||||
operator==(ListIterator<M> const& other) const noexcept
|
||||
{
|
||||
return m_node == other.m_node;
|
||||
}
|
||||
|
||||
template <typename M>
|
||||
bool
|
||||
operator!=(ListIterator<M> const& other) const noexcept
|
||||
{
|
||||
return !((*this) == other);
|
||||
}
|
||||
|
||||
reference
|
||||
operator*() const noexcept
|
||||
{
|
||||
return dereference();
|
||||
}
|
||||
|
||||
pointer
|
||||
operator->() const noexcept
|
||||
{
|
||||
return &dereference();
|
||||
}
|
||||
|
||||
ListIterator&
|
||||
operator++() noexcept
|
||||
{
|
||||
increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ListIterator
|
||||
operator++(int) noexcept
|
||||
{
|
||||
ListIterator result(*this);
|
||||
increment();
|
||||
return result;
|
||||
}
|
||||
|
||||
ListIterator&
|
||||
operator--() noexcept
|
||||
{
|
||||
decrement();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ListIterator
|
||||
operator--(int) noexcept
|
||||
{
|
||||
ListIterator result(*this);
|
||||
decrement();
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
reference
|
||||
dereference() const noexcept
|
||||
{
|
||||
return static_cast<reference>(*m_node);
|
||||
}
|
||||
|
||||
void
|
||||
increment() noexcept
|
||||
{
|
||||
m_node = m_node->m_next;
|
||||
}
|
||||
|
||||
void
|
||||
decrement() noexcept
|
||||
{
|
||||
m_node = m_node->m_prev;
|
||||
}
|
||||
|
||||
N* m_node;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/** Intrusive doubly linked list.
|
||||
|
||||
This intrusive List is a container similar in operation to std::list in the
|
||||
Standard Template Library (STL). Like all @ref intrusive containers, List
|
||||
requires you to first derive your class from List<>::Node:
|
||||
|
||||
@code
|
||||
|
||||
struct Object : List <Object>::Node
|
||||
{
|
||||
explicit Object (int value) : m_value (value)
|
||||
{
|
||||
}
|
||||
|
||||
int m_value;
|
||||
};
|
||||
|
||||
@endcode
|
||||
|
||||
Now we define the list, and add a couple of items.
|
||||
|
||||
@code
|
||||
|
||||
List <Object> list;
|
||||
|
||||
list.push_back (* (new Object (1)));
|
||||
list.push_back (* (new Object (2)));
|
||||
|
||||
@endcode
|
||||
|
||||
For compatibility with the standard containers, push_back() expects a
|
||||
reference to the object. Unlike the standard container, however, push_back()
|
||||
places the actual object in the list and not a copy-constructed duplicate.
|
||||
|
||||
Iterating over the list follows the same idiom as the STL:
|
||||
|
||||
@code
|
||||
|
||||
for (List <Object>::iterator iter = list.begin(); iter != list.end; ++iter)
|
||||
std::cout << iter->m_value;
|
||||
|
||||
@endcode
|
||||
|
||||
You can even use BOOST_FOREACH, or range based for loops:
|
||||
|
||||
@code
|
||||
|
||||
BOOST_FOREACH (Object& object, list) // boost only
|
||||
std::cout << object.m_value;
|
||||
|
||||
for (Object& object : list) // C++11 only
|
||||
std::cout << object.m_value;
|
||||
|
||||
@endcode
|
||||
|
||||
Because List is mostly STL compliant, it can be passed into STL algorithms:
|
||||
e.g. `std::for_each()` or `std::find_first_of()`.
|
||||
|
||||
In general, objects placed into a List should be dynamically allocated
|
||||
although this cannot be enforced at compile time. Since the caller provides
|
||||
the storage for the object, the caller is also responsible for deleting the
|
||||
object. An object still exists after being removed from a List, until the
|
||||
caller deletes it. This means an element can be moved from one List to
|
||||
another with practically no overhead.
|
||||
|
||||
Unlike the standard containers, an object may only exist in one list at a
|
||||
time, unless special preparations are made. The Tag template parameter is
|
||||
used to distinguish between different list types for the same object,
|
||||
allowing the object to exist in more than one list simultaneously.
|
||||
|
||||
For example, consider an actor system where a global list of actors is
|
||||
maintained, so that they can each be periodically receive processing
|
||||
time. We wish to also maintain a list of the subset of actors that require
|
||||
a domain-dependent update. To achieve this, we declare two tags, the
|
||||
associated list types, and the list element thusly:
|
||||
|
||||
@code
|
||||
|
||||
struct Actor; // Forward declaration required
|
||||
|
||||
struct ProcessTag { };
|
||||
struct UpdateTag { };
|
||||
|
||||
using ProcessList = List <Actor, ProcessTag>;
|
||||
using UpdateList = List <Actor, UpdateTag>;
|
||||
|
||||
// Derive from both node types so we can be in each list at once.
|
||||
//
|
||||
struct Actor : ProcessList::Node, UpdateList::Node
|
||||
{
|
||||
bool process (); // returns true if we need an update
|
||||
void update ();
|
||||
};
|
||||
|
||||
@endcode
|
||||
|
||||
@tparam T The base type of element which the list will store
|
||||
pointers to.
|
||||
|
||||
@tparam Tag An optional unique type name used to distinguish lists and
|
||||
nodes, when the object can exist in multiple lists simultaneously.
|
||||
|
||||
@ingroup beast_core intrusive
|
||||
*/
|
||||
template <typename T, typename Tag = void>
|
||||
class List
|
||||
{
|
||||
public:
|
||||
using Node = typename detail::ListNode<T, Tag>;
|
||||
|
||||
using value_type = T;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
using const_pointer = value_type const*;
|
||||
using const_reference = value_type const&;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
using iterator = detail::ListIterator<Node>;
|
||||
using const_iterator = detail::ListIterator<Node const>;
|
||||
|
||||
/** Create an empty list. */
|
||||
List()
|
||||
{
|
||||
m_head.m_prev = nullptr; // identifies the head
|
||||
m_tail.m_next = nullptr; // identifies the tail
|
||||
clear();
|
||||
}
|
||||
|
||||
List(List const&) = delete;
|
||||
List&
|
||||
operator=(List const&) = delete;
|
||||
|
||||
/** Determine if the list is empty.
|
||||
@return `true` if the list is empty.
|
||||
*/
|
||||
bool
|
||||
empty() const noexcept
|
||||
{
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
/** Returns the number of elements in the list. */
|
||||
size_type
|
||||
size() const noexcept
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
/** Obtain a reference to the first element.
|
||||
@invariant The list may not be empty.
|
||||
@return A reference to the first element.
|
||||
*/
|
||||
reference
|
||||
front() noexcept
|
||||
{
|
||||
return element_from(m_head.m_next);
|
||||
}
|
||||
|
||||
/** Obtain a const reference to the first element.
|
||||
@invariant The list may not be empty.
|
||||
@return A const reference to the first element.
|
||||
*/
|
||||
const_reference
|
||||
front() const noexcept
|
||||
{
|
||||
return element_from(m_head.m_next);
|
||||
}
|
||||
|
||||
/** Obtain a reference to the last element.
|
||||
@invariant The list may not be empty.
|
||||
@return A reference to the last element.
|
||||
*/
|
||||
reference
|
||||
back() noexcept
|
||||
{
|
||||
return element_from(m_tail.m_prev);
|
||||
}
|
||||
|
||||
/** Obtain a const reference to the last element.
|
||||
@invariant The list may not be empty.
|
||||
@return A const reference to the last element.
|
||||
*/
|
||||
const_reference
|
||||
back() const noexcept
|
||||
{
|
||||
return element_from(m_tail.m_prev);
|
||||
}
|
||||
|
||||
/** Obtain an iterator to the beginning of the list.
|
||||
@return An iterator pointing to the beginning of the list.
|
||||
*/
|
||||
iterator
|
||||
begin() noexcept
|
||||
{
|
||||
return iterator(m_head.m_next);
|
||||
}
|
||||
|
||||
/** Obtain a const iterator to the beginning of the list.
|
||||
@return A const iterator pointing to the beginning of the list.
|
||||
*/
|
||||
const_iterator
|
||||
begin() const noexcept
|
||||
{
|
||||
return const_iterator(m_head.m_next);
|
||||
}
|
||||
|
||||
/** Obtain a const iterator to the beginning of the list.
|
||||
@return A const iterator pointing to the beginning of the list.
|
||||
*/
|
||||
const_iterator
|
||||
cbegin() const noexcept
|
||||
{
|
||||
return const_iterator(m_head.m_next);
|
||||
}
|
||||
|
||||
/** Obtain a iterator to the end of the list.
|
||||
@return An iterator pointing to the end of the list.
|
||||
*/
|
||||
iterator
|
||||
end() noexcept
|
||||
{
|
||||
return iterator(&m_tail);
|
||||
}
|
||||
|
||||
/** Obtain a const iterator to the end of the list.
|
||||
@return A constiterator pointing to the end of the list.
|
||||
*/
|
||||
const_iterator
|
||||
end() const noexcept
|
||||
{
|
||||
return const_iterator(&m_tail);
|
||||
}
|
||||
|
||||
/** Obtain a const iterator to the end of the list
|
||||
@return A constiterator pointing to the end of the list.
|
||||
*/
|
||||
const_iterator
|
||||
cend() const noexcept
|
||||
{
|
||||
return const_iterator(&m_tail);
|
||||
}
|
||||
|
||||
/** Clear the list.
|
||||
@note This does not free the elements.
|
||||
*/
|
||||
void
|
||||
clear() noexcept
|
||||
{
|
||||
m_head.m_next = &m_tail;
|
||||
m_tail.m_prev = &m_head;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
/** Insert an element.
|
||||
@invariant The element must not already be in the list.
|
||||
@param pos The location to insert after.
|
||||
@param element The element to insert.
|
||||
@return An iterator pointing to the newly inserted element.
|
||||
*/
|
||||
iterator
|
||||
insert(iterator pos, T& element) noexcept
|
||||
{
|
||||
Node* node = static_cast<Node*>(&element);
|
||||
node->m_next = &*pos;
|
||||
node->m_prev = node->m_next->m_prev;
|
||||
node->m_next->m_prev = node;
|
||||
node->m_prev->m_next = node;
|
||||
++m_size;
|
||||
return iterator(node);
|
||||
}
|
||||
|
||||
/** Insert another list into this one.
|
||||
The other list is cleared.
|
||||
@param pos The location to insert after.
|
||||
@param other The list to insert.
|
||||
*/
|
||||
void
|
||||
insert(iterator pos, List& other) noexcept
|
||||
{
|
||||
if (!other.empty())
|
||||
{
|
||||
Node* before = &*pos;
|
||||
other.m_head.m_next->m_prev = before->m_prev;
|
||||
before->m_prev->m_next = other.m_head.m_next;
|
||||
other.m_tail.m_prev->m_next = before;
|
||||
before->m_prev = other.m_tail.m_prev;
|
||||
m_size += other.m_size;
|
||||
other.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/** Remove an element.
|
||||
@invariant The element must exist in the list.
|
||||
@param pos An iterator pointing to the element to remove.
|
||||
@return An iterator pointing to the next element after the one removed.
|
||||
*/
|
||||
iterator
|
||||
erase(iterator pos) noexcept
|
||||
{
|
||||
Node* node = &*pos;
|
||||
++pos;
|
||||
node->m_next->m_prev = node->m_prev;
|
||||
node->m_prev->m_next = node->m_next;
|
||||
--m_size;
|
||||
return pos;
|
||||
}
|
||||
|
||||
/** Insert an element at the beginning of the list.
|
||||
@invariant The element must not exist in the list.
|
||||
@param element The element to insert.
|
||||
*/
|
||||
iterator
|
||||
push_front(T& element) noexcept
|
||||
{
|
||||
return insert(begin(), element);
|
||||
}
|
||||
|
||||
/** Remove the element at the beginning of the list.
|
||||
@invariant The list must not be empty.
|
||||
@return A reference to the popped element.
|
||||
*/
|
||||
T&
|
||||
pop_front() noexcept
|
||||
{
|
||||
T& element(front());
|
||||
erase(begin());
|
||||
return element;
|
||||
}
|
||||
|
||||
/** Append an element at the end of the list.
|
||||
@invariant The element must not exist in the list.
|
||||
@param element The element to append.
|
||||
*/
|
||||
iterator
|
||||
push_back(T& element) noexcept
|
||||
{
|
||||
return insert(end(), element);
|
||||
}
|
||||
|
||||
/** Remove the element at the end of the list.
|
||||
@invariant The list must not be empty.
|
||||
@return A reference to the popped element.
|
||||
*/
|
||||
T&
|
||||
pop_back() noexcept
|
||||
{
|
||||
T& element(back());
|
||||
erase(--end());
|
||||
return element;
|
||||
}
|
||||
|
||||
/** Swap contents with another list. */
|
||||
void
|
||||
swap(List& other) noexcept
|
||||
{
|
||||
List temp;
|
||||
temp.append(other);
|
||||
other.append(*this);
|
||||
append(temp);
|
||||
}
|
||||
|
||||
/** Insert another list at the beginning of this list.
|
||||
The other list is cleared.
|
||||
@param list The other list to insert.
|
||||
*/
|
||||
iterator
|
||||
prepend(List& list) noexcept
|
||||
{
|
||||
return insert(begin(), list);
|
||||
}
|
||||
|
||||
/** Append another list at the end of this list.
|
||||
The other list is cleared.
|
||||
@param list the other list to append.
|
||||
*/
|
||||
iterator
|
||||
append(List& list) noexcept
|
||||
{
|
||||
return insert(end(), list);
|
||||
}
|
||||
|
||||
/** Obtain an iterator from an element.
|
||||
@invariant The element must exist in the list.
|
||||
@param element The element to obtain an iterator for.
|
||||
@return An iterator to the element.
|
||||
*/
|
||||
iterator
|
||||
iterator_to(T& element) const noexcept
|
||||
{
|
||||
return iterator(static_cast<Node*>(&element));
|
||||
}
|
||||
|
||||
/** Obtain a const iterator from an element.
|
||||
@invariant The element must exist in the list.
|
||||
@param element The element to obtain an iterator for.
|
||||
@return A const iterator to the element.
|
||||
*/
|
||||
const_iterator
|
||||
const_iterator_to(T const& element) const noexcept
|
||||
{
|
||||
return const_iterator(static_cast<Node const*>(&element));
|
||||
}
|
||||
|
||||
private:
|
||||
reference
|
||||
element_from(Node* node) noexcept
|
||||
{
|
||||
return *(static_cast<pointer>(node));
|
||||
}
|
||||
|
||||
const_reference
|
||||
element_from(Node const* node) const noexcept
|
||||
{
|
||||
return *(static_cast<const_pointer>(node));
|
||||
}
|
||||
|
||||
private:
|
||||
size_type m_size;
|
||||
Node m_head;
|
||||
Node m_tail;
|
||||
};
|
||||
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
307
include/xrpl/beast/core/LockFreeStack.h
Normal file
307
include/xrpl/beast/core/LockFreeStack.h
Normal file
@@ -0,0 +1,307 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_INTRUSIVE_LOCKFREESTACK_H_INCLUDED
|
||||
#define BEAST_INTRUSIVE_LOCKFREESTACK_H_INCLUDED
|
||||
|
||||
#include <atomic>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class Container, bool IsConst>
|
||||
class LockFreeStackIterator
|
||||
{
|
||||
protected:
|
||||
using Node = typename Container::Node;
|
||||
using NodePtr =
|
||||
typename std::conditional<IsConst, Node const*, Node*>::type;
|
||||
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = typename Container::value_type;
|
||||
using difference_type = typename Container::difference_type;
|
||||
using pointer = typename std::conditional<
|
||||
IsConst,
|
||||
typename Container::const_pointer,
|
||||
typename Container::pointer>::type;
|
||||
using reference = typename std::conditional<
|
||||
IsConst,
|
||||
typename Container::const_reference,
|
||||
typename Container::reference>::type;
|
||||
|
||||
LockFreeStackIterator() : m_node()
|
||||
{
|
||||
}
|
||||
|
||||
LockFreeStackIterator(NodePtr node) : m_node(node)
|
||||
{
|
||||
}
|
||||
|
||||
template <bool OtherIsConst>
|
||||
explicit LockFreeStackIterator(
|
||||
LockFreeStackIterator<Container, OtherIsConst> const& other)
|
||||
: m_node(other.m_node)
|
||||
{
|
||||
}
|
||||
|
||||
LockFreeStackIterator&
|
||||
operator=(NodePtr node)
|
||||
{
|
||||
m_node = node;
|
||||
return static_cast<LockFreeStackIterator&>(*this);
|
||||
}
|
||||
|
||||
LockFreeStackIterator&
|
||||
operator++()
|
||||
{
|
||||
m_node = m_node->m_next.load();
|
||||
return static_cast<LockFreeStackIterator&>(*this);
|
||||
}
|
||||
|
||||
LockFreeStackIterator
|
||||
operator++(int)
|
||||
{
|
||||
LockFreeStackIterator result(*this);
|
||||
m_node = m_node->m_next;
|
||||
return result;
|
||||
}
|
||||
|
||||
NodePtr
|
||||
node() const
|
||||
{
|
||||
return m_node;
|
||||
}
|
||||
|
||||
reference
|
||||
operator*() const
|
||||
{
|
||||
return *this->operator->();
|
||||
}
|
||||
|
||||
pointer
|
||||
operator->() const
|
||||
{
|
||||
return static_cast<pointer>(m_node);
|
||||
}
|
||||
|
||||
private:
|
||||
NodePtr m_node;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class Container, bool LhsIsConst, bool RhsIsConst>
|
||||
bool
|
||||
operator==(
|
||||
LockFreeStackIterator<Container, LhsIsConst> const& lhs,
|
||||
LockFreeStackIterator<Container, RhsIsConst> const& rhs)
|
||||
{
|
||||
return lhs.node() == rhs.node();
|
||||
}
|
||||
|
||||
template <class Container, bool LhsIsConst, bool RhsIsConst>
|
||||
bool
|
||||
operator!=(
|
||||
LockFreeStackIterator<Container, LhsIsConst> const& lhs,
|
||||
LockFreeStackIterator<Container, RhsIsConst> const& rhs)
|
||||
{
|
||||
return lhs.node() != rhs.node();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Multiple Producer, Multiple Consumer (MPMC) intrusive stack.
|
||||
|
||||
This stack is implemented using the same intrusive interface as List.
|
||||
All mutations are lock-free.
|
||||
|
||||
The caller is responsible for preventing the "ABA" problem:
|
||||
http://en.wikipedia.org/wiki/ABA_problem
|
||||
|
||||
@param Tag A type name used to distinguish lists and nodes, for
|
||||
putting objects in multiple lists. If this parameter is
|
||||
omitted, the default tag is used.
|
||||
*/
|
||||
template <class Element, class Tag = void>
|
||||
class LockFreeStack
|
||||
{
|
||||
public:
|
||||
class Node
|
||||
{
|
||||
public:
|
||||
Node() : m_next(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
explicit Node(Node* next) : m_next(next)
|
||||
{
|
||||
}
|
||||
|
||||
Node(Node const&) = delete;
|
||||
Node&
|
||||
operator=(Node const&) = delete;
|
||||
|
||||
private:
|
||||
friend class LockFreeStack;
|
||||
|
||||
template <class Container, bool IsConst>
|
||||
friend class LockFreeStackIterator;
|
||||
|
||||
std::atomic<Node*> m_next;
|
||||
};
|
||||
|
||||
public:
|
||||
using value_type = Element;
|
||||
using pointer = Element*;
|
||||
using reference = Element&;
|
||||
using const_pointer = Element const*;
|
||||
using const_reference = Element const&;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator = LockFreeStackIterator<LockFreeStack<Element, Tag>, false>;
|
||||
using const_iterator =
|
||||
LockFreeStackIterator<LockFreeStack<Element, Tag>, true>;
|
||||
|
||||
LockFreeStack() : m_end(nullptr), m_head(&m_end)
|
||||
{
|
||||
}
|
||||
|
||||
LockFreeStack(LockFreeStack const&) = delete;
|
||||
LockFreeStack&
|
||||
operator=(LockFreeStack const&) = delete;
|
||||
|
||||
/** Returns true if the stack is empty. */
|
||||
bool
|
||||
empty() const
|
||||
{
|
||||
return m_head.load() == &m_end;
|
||||
}
|
||||
|
||||
/** Push a node onto the stack.
|
||||
The caller is responsible for preventing the ABA problem.
|
||||
This operation is lock-free.
|
||||
Thread safety:
|
||||
Safe to call from any thread.
|
||||
|
||||
@param node The node to push.
|
||||
|
||||
@return `true` if the stack was previously empty. If multiple threads
|
||||
are attempting to push, only one will receive `true`.
|
||||
*/
|
||||
// VFALCO NOTE Fix this, shouldn't it be a reference like intrusive list?
|
||||
bool
|
||||
push_front(Node* node)
|
||||
{
|
||||
bool first;
|
||||
Node* old_head = m_head.load(std::memory_order_relaxed);
|
||||
do
|
||||
{
|
||||
first = (old_head == &m_end);
|
||||
node->m_next = old_head;
|
||||
} while (!m_head.compare_exchange_strong(
|
||||
old_head,
|
||||
node,
|
||||
std::memory_order_release,
|
||||
std::memory_order_relaxed));
|
||||
return first;
|
||||
}
|
||||
|
||||
/** Pop an element off the stack.
|
||||
The caller is responsible for preventing the ABA problem.
|
||||
This operation is lock-free.
|
||||
Thread safety:
|
||||
Safe to call from any thread.
|
||||
|
||||
@return The element that was popped, or `nullptr` if the stack
|
||||
was empty.
|
||||
*/
|
||||
Element*
|
||||
pop_front()
|
||||
{
|
||||
Node* node = m_head.load();
|
||||
Node* new_head;
|
||||
do
|
||||
{
|
||||
if (node == &m_end)
|
||||
return nullptr;
|
||||
new_head = node->m_next.load();
|
||||
} while (!m_head.compare_exchange_strong(
|
||||
node,
|
||||
new_head,
|
||||
std::memory_order_release,
|
||||
std::memory_order_relaxed));
|
||||
return static_cast<Element*>(node);
|
||||
}
|
||||
|
||||
/** Return a forward iterator to the beginning or end of the stack.
|
||||
Undefined behavior results if push_front or pop_front is called
|
||||
while an iteration is in progress.
|
||||
Thread safety:
|
||||
Caller is responsible for synchronization.
|
||||
*/
|
||||
/** @{ */
|
||||
iterator
|
||||
begin()
|
||||
{
|
||||
return iterator(m_head.load());
|
||||
}
|
||||
|
||||
iterator
|
||||
end()
|
||||
{
|
||||
return iterator(&m_end);
|
||||
}
|
||||
|
||||
const_iterator
|
||||
begin() const
|
||||
{
|
||||
return const_iterator(m_head.load());
|
||||
}
|
||||
|
||||
const_iterator
|
||||
end() const
|
||||
{
|
||||
return const_iterator(&m_end);
|
||||
}
|
||||
|
||||
const_iterator
|
||||
cbegin() const
|
||||
{
|
||||
return const_iterator(m_head.load());
|
||||
}
|
||||
|
||||
const_iterator
|
||||
cend() const
|
||||
{
|
||||
return const_iterator(&m_end);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
private:
|
||||
Node m_end;
|
||||
std::atomic<Node*> m_head;
|
||||
};
|
||||
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
118
include/xrpl/beast/core/SemanticVersion.h
Normal file
118
include/xrpl/beast/core/SemanticVersion.h
Normal file
@@ -0,0 +1,118 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_MODULE_CORE_DIAGNOSTIC_SEMANTICVERSION_H_INCLUDED
|
||||
#define BEAST_MODULE_CORE_DIAGNOSTIC_SEMANTICVERSION_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** A Semantic Version number.
|
||||
|
||||
Identifies the build of a particular version of software using
|
||||
the Semantic Versioning Specification described here:
|
||||
|
||||
http://semver.org/
|
||||
*/
|
||||
class SemanticVersion
|
||||
{
|
||||
public:
|
||||
using identifier_list = std::vector<std::string>;
|
||||
|
||||
int majorVersion;
|
||||
int minorVersion;
|
||||
int patchVersion;
|
||||
|
||||
identifier_list preReleaseIdentifiers;
|
||||
identifier_list metaData;
|
||||
|
||||
SemanticVersion();
|
||||
|
||||
SemanticVersion(std::string const& version);
|
||||
|
||||
/** Parse a semantic version string.
|
||||
The parsing is as strict as possible.
|
||||
@return `true` if the string was parsed.
|
||||
*/
|
||||
bool
|
||||
parse(std::string const& input);
|
||||
|
||||
/** Produce a string from semantic version components. */
|
||||
std::string
|
||||
print() const;
|
||||
|
||||
inline bool
|
||||
isRelease() const noexcept
|
||||
{
|
||||
return preReleaseIdentifiers.empty();
|
||||
}
|
||||
inline bool
|
||||
isPreRelease() const noexcept
|
||||
{
|
||||
return !isRelease();
|
||||
}
|
||||
};
|
||||
|
||||
/** Compare two SemanticVersions against each other.
|
||||
The comparison follows the rules as per the specification.
|
||||
*/
|
||||
int
|
||||
compare(SemanticVersion const& lhs, SemanticVersion const& rhs);
|
||||
|
||||
inline bool
|
||||
operator==(SemanticVersion const& lhs, SemanticVersion const& rhs)
|
||||
{
|
||||
return compare(lhs, rhs) == 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator!=(SemanticVersion const& lhs, SemanticVersion const& rhs)
|
||||
{
|
||||
return compare(lhs, rhs) != 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator>=(SemanticVersion const& lhs, SemanticVersion const& rhs)
|
||||
{
|
||||
return compare(lhs, rhs) >= 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator<=(SemanticVersion const& lhs, SemanticVersion const& rhs)
|
||||
{
|
||||
return compare(lhs, rhs) <= 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator>(SemanticVersion const& lhs, SemanticVersion const& rhs)
|
||||
{
|
||||
return compare(lhs, rhs) > 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator<(SemanticVersion const& lhs, SemanticVersion const& rhs)
|
||||
{
|
||||
return compare(lhs, rhs) < 0;
|
||||
}
|
||||
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
505
include/xrpl/beast/hash/hash_append.h
Normal file
505
include/xrpl/beast/hash/hash_append.h
Normal file
@@ -0,0 +1,505 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_HASH_APPEND_H_INCLUDED
|
||||
#define BEAST_HASH_HASH_APPEND_H_INCLUDED
|
||||
|
||||
#include <boost/container/flat_set.hpp>
|
||||
#include <boost/endian/conversion.hpp>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace beast {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class T>
|
||||
/*constexpr*/
|
||||
inline void
|
||||
reverse_bytes(T& t)
|
||||
{
|
||||
unsigned char* bytes = static_cast<unsigned char*>(
|
||||
std::memmove(std::addressof(t), std::addressof(t), sizeof(T)));
|
||||
for (unsigned i = 0; i < sizeof(T) / 2; ++i)
|
||||
std::swap(bytes[i], bytes[sizeof(T) - 1 - i]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
/*constexpr*/
|
||||
inline void
|
||||
maybe_reverse_bytes(T& t, std::false_type)
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
/*constexpr*/
|
||||
inline void
|
||||
maybe_reverse_bytes(T& t, std::true_type)
|
||||
{
|
||||
reverse_bytes(t);
|
||||
}
|
||||
|
||||
template <class T, class Hasher>
|
||||
/*constexpr*/
|
||||
inline void
|
||||
maybe_reverse_bytes(T& t, Hasher&)
|
||||
{
|
||||
maybe_reverse_bytes(
|
||||
t,
|
||||
std::integral_constant<
|
||||
bool,
|
||||
Hasher::endian != boost::endian::order::native>{});
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// is_uniquely_represented<T>
|
||||
|
||||
// A type T is contiguously hashable if for all combinations of two values of
|
||||
// a type, say x and y, if x == y, then it must also be true that
|
||||
// memcmp(addressof(x), addressof(y), sizeof(T)) == 0. I.e. if x == y,
|
||||
// then x and y have the same bit pattern representation.
|
||||
|
||||
template <class T>
|
||||
struct is_uniquely_represented
|
||||
: public std::integral_constant<
|
||||
bool,
|
||||
std::is_integral<T>::value || std::is_enum<T>::value ||
|
||||
std::is_pointer<T>::value>
|
||||
{
|
||||
explicit is_uniquely_represented() = default;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_uniquely_represented<T const> : public is_uniquely_represented<T>
|
||||
{
|
||||
explicit is_uniquely_represented() = default;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_uniquely_represented<T volatile> : public is_uniquely_represented<T>
|
||||
{
|
||||
explicit is_uniquely_represented() = default;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_uniquely_represented<T const volatile>
|
||||
: public is_uniquely_represented<T>
|
||||
{
|
||||
explicit is_uniquely_represented() = default;
|
||||
};
|
||||
|
||||
// is_uniquely_represented<std::pair<T, U>>
|
||||
|
||||
template <class T, class U>
|
||||
struct is_uniquely_represented<std::pair<T, U>>
|
||||
: public std::integral_constant<
|
||||
bool,
|
||||
is_uniquely_represented<T>::value &&
|
||||
is_uniquely_represented<U>::value &&
|
||||
sizeof(T) + sizeof(U) == sizeof(std::pair<T, U>)>
|
||||
{
|
||||
explicit is_uniquely_represented() = default;
|
||||
};
|
||||
|
||||
// is_uniquely_represented<std::tuple<T...>>
|
||||
|
||||
template <class... T>
|
||||
struct is_uniquely_represented<std::tuple<T...>>
|
||||
: public std::integral_constant<
|
||||
bool,
|
||||
std::conjunction_v<is_uniquely_represented<T>...> &&
|
||||
sizeof(std::tuple<T...>) == (sizeof(T) + ...)>
|
||||
{
|
||||
explicit is_uniquely_represented() = default;
|
||||
};
|
||||
|
||||
// is_uniquely_represented<T[N]>
|
||||
|
||||
template <class T, std::size_t N>
|
||||
struct is_uniquely_represented<T[N]> : public is_uniquely_represented<T>
|
||||
{
|
||||
explicit is_uniquely_represented() = default;
|
||||
};
|
||||
|
||||
// is_uniquely_represented<std::array<T, N>>
|
||||
|
||||
template <class T, std::size_t N>
|
||||
struct is_uniquely_represented<std::array<T, N>>
|
||||
: public std::integral_constant<
|
||||
bool,
|
||||
is_uniquely_represented<T>::value &&
|
||||
sizeof(T) * N == sizeof(std::array<T, N>)>
|
||||
{
|
||||
explicit is_uniquely_represented() = default;
|
||||
};
|
||||
|
||||
/** Metafunction returning `true` if the type can be hashed in one call.
|
||||
|
||||
For `is_contiguously_hashable<T>::value` to be true, then for every
|
||||
combination of possible values of `T` held in `x` and `y`,
|
||||
if `x == y`, then it must be true that `memcmp(&x, &y, sizeof(T))`
|
||||
return 0; i.e. that `x` and `y` are represented by the same bit pattern.
|
||||
|
||||
For example: A two's complement `int` should be contiguously hashable.
|
||||
Every bit pattern produces a unique value that does not compare equal to
|
||||
any other bit pattern's value. A IEEE floating point should not be
|
||||
contiguously hashable because -0. and 0. have different bit patterns,
|
||||
though they compare equal.
|
||||
*/
|
||||
/** @{ */
|
||||
template <class T, class HashAlgorithm>
|
||||
struct is_contiguously_hashable
|
||||
: public std::integral_constant<
|
||||
bool,
|
||||
is_uniquely_represented<T>::value &&
|
||||
(sizeof(T) == 1 ||
|
||||
HashAlgorithm::endian == boost::endian::order::native)>
|
||||
{
|
||||
explicit is_contiguously_hashable() = default;
|
||||
};
|
||||
|
||||
template <class T, std::size_t N, class HashAlgorithm>
|
||||
struct is_contiguously_hashable<T[N], HashAlgorithm>
|
||||
: public std::integral_constant<
|
||||
bool,
|
||||
is_uniquely_represented<T[N]>::value &&
|
||||
(sizeof(T) == 1 ||
|
||||
HashAlgorithm::endian == boost::endian::order::native)>
|
||||
{
|
||||
explicit is_contiguously_hashable() = default;
|
||||
};
|
||||
/** @} */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Logically concatenate input data to a `Hasher`.
|
||||
|
||||
Hasher requirements:
|
||||
|
||||
`X` is the type `Hasher`
|
||||
`h` is a value of type `x`
|
||||
`p` is a value convertible to `void const*`
|
||||
`n` is a value of type `std::size_t`, greater than zero
|
||||
|
||||
Expression:
|
||||
`h.append (p, n);`
|
||||
Throws:
|
||||
Never
|
||||
Effect:
|
||||
Adds the input data to the hasher state.
|
||||
|
||||
Expression:
|
||||
`static_cast<std::size_t>(j)`
|
||||
Throws:
|
||||
Never
|
||||
Effect:
|
||||
Returns the reslting hash of all the input data.
|
||||
*/
|
||||
/** @{ */
|
||||
|
||||
// scalars
|
||||
|
||||
template <class Hasher, class T>
|
||||
inline std::enable_if_t<is_contiguously_hashable<T, Hasher>::value>
|
||||
hash_append(Hasher& h, T const& t) noexcept
|
||||
{
|
||||
h(std::addressof(t), sizeof(t));
|
||||
}
|
||||
|
||||
template <class Hasher, class T>
|
||||
inline std::enable_if_t<
|
||||
!is_contiguously_hashable<T, Hasher>::value &&
|
||||
(std::is_integral<T>::value || std::is_pointer<T>::value ||
|
||||
std::is_enum<T>::value)>
|
||||
hash_append(Hasher& h, T t) noexcept
|
||||
{
|
||||
detail::reverse_bytes(t);
|
||||
h(std::addressof(t), sizeof(t));
|
||||
}
|
||||
|
||||
template <class Hasher, class T>
|
||||
inline std::enable_if_t<std::is_floating_point<T>::value>
|
||||
hash_append(Hasher& h, T t) noexcept
|
||||
{
|
||||
if (t == 0)
|
||||
t = 0;
|
||||
detail::maybe_reverse_bytes(t, h);
|
||||
h(&t, sizeof(t));
|
||||
}
|
||||
|
||||
template <class Hasher>
|
||||
inline void
|
||||
hash_append(Hasher& h, std::nullptr_t) noexcept
|
||||
{
|
||||
void const* p = nullptr;
|
||||
detail::maybe_reverse_bytes(p, h);
|
||||
h(&p, sizeof(p));
|
||||
}
|
||||
|
||||
// Forward declarations for ADL purposes
|
||||
|
||||
template <class Hasher, class T, std::size_t N>
|
||||
std::enable_if_t<!is_contiguously_hashable<T, Hasher>::value>
|
||||
hash_append(Hasher& h, T (&a)[N]) noexcept;
|
||||
|
||||
template <class Hasher, class CharT, class Traits, class Alloc>
|
||||
std::enable_if_t<!is_contiguously_hashable<CharT, Hasher>::value>
|
||||
hash_append(
|
||||
Hasher& h,
|
||||
std::basic_string<CharT, Traits, Alloc> const& s) noexcept;
|
||||
|
||||
template <class Hasher, class CharT, class Traits, class Alloc>
|
||||
std::enable_if_t<is_contiguously_hashable<CharT, Hasher>::value>
|
||||
hash_append(
|
||||
Hasher& h,
|
||||
std::basic_string<CharT, Traits, Alloc> const& s) noexcept;
|
||||
|
||||
template <class Hasher, class T, class U>
|
||||
std::enable_if_t<!is_contiguously_hashable<std::pair<T, U>, Hasher>::value>
|
||||
hash_append(Hasher& h, std::pair<T, U> const& p) noexcept;
|
||||
|
||||
template <class Hasher, class T, class Alloc>
|
||||
std::enable_if_t<!is_contiguously_hashable<T, Hasher>::value>
|
||||
hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
|
||||
|
||||
template <class Hasher, class T, class Alloc>
|
||||
std::enable_if_t<is_contiguously_hashable<T, Hasher>::value>
|
||||
hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
|
||||
|
||||
template <class Hasher, class T, std::size_t N>
|
||||
std::enable_if_t<!is_contiguously_hashable<std::array<T, N>, Hasher>::value>
|
||||
hash_append(Hasher& h, std::array<T, N> const& a) noexcept;
|
||||
|
||||
template <class Hasher, class... T>
|
||||
std::enable_if_t<!is_contiguously_hashable<std::tuple<T...>, Hasher>::value>
|
||||
hash_append(Hasher& h, std::tuple<T...> const& t) noexcept;
|
||||
|
||||
template <class Hasher, class Key, class T, class Hash, class Pred, class Alloc>
|
||||
void
|
||||
hash_append(Hasher& h, std::unordered_map<Key, T, Hash, Pred, Alloc> const& m);
|
||||
|
||||
template <class Hasher, class Key, class Hash, class Pred, class Alloc>
|
||||
void
|
||||
hash_append(Hasher& h, std::unordered_set<Key, Hash, Pred, Alloc> const& s);
|
||||
|
||||
template <class Hasher, class Key, class Compare, class Alloc>
|
||||
std::enable_if_t<!is_contiguously_hashable<Key, Hasher>::value>
|
||||
hash_append(
|
||||
Hasher& h,
|
||||
boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
|
||||
template <class Hasher, class Key, class Compare, class Alloc>
|
||||
std::enable_if_t<is_contiguously_hashable<Key, Hasher>::value>
|
||||
hash_append(
|
||||
Hasher& h,
|
||||
boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
|
||||
template <class Hasher, class T0, class T1, class... T>
|
||||
void
|
||||
hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept;
|
||||
|
||||
// c-array
|
||||
|
||||
template <class Hasher, class T, std::size_t N>
|
||||
std::enable_if_t<!is_contiguously_hashable<T, Hasher>::value>
|
||||
hash_append(Hasher& h, T (&a)[N]) noexcept
|
||||
{
|
||||
for (auto const& t : a)
|
||||
hash_append(h, t);
|
||||
}
|
||||
|
||||
// basic_string
|
||||
|
||||
template <class Hasher, class CharT, class Traits, class Alloc>
|
||||
inline std::enable_if_t<!is_contiguously_hashable<CharT, Hasher>::value>
|
||||
hash_append(
|
||||
Hasher& h,
|
||||
std::basic_string<CharT, Traits, Alloc> const& s) noexcept
|
||||
{
|
||||
for (auto c : s)
|
||||
hash_append(h, c);
|
||||
hash_append(h, s.size());
|
||||
}
|
||||
|
||||
template <class Hasher, class CharT, class Traits, class Alloc>
|
||||
inline std::enable_if_t<is_contiguously_hashable<CharT, Hasher>::value>
|
||||
hash_append(
|
||||
Hasher& h,
|
||||
std::basic_string<CharT, Traits, Alloc> const& s) noexcept
|
||||
{
|
||||
h(s.data(), s.size() * sizeof(CharT));
|
||||
hash_append(h, s.size());
|
||||
}
|
||||
|
||||
// pair
|
||||
|
||||
template <class Hasher, class T, class U>
|
||||
inline std::enable_if_t<
|
||||
!is_contiguously_hashable<std::pair<T, U>, Hasher>::value>
|
||||
hash_append(Hasher& h, std::pair<T, U> const& p) noexcept
|
||||
{
|
||||
hash_append(h, p.first, p.second);
|
||||
}
|
||||
|
||||
// vector
|
||||
|
||||
template <class Hasher, class T, class Alloc>
|
||||
inline std::enable_if_t<!is_contiguously_hashable<T, Hasher>::value>
|
||||
hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
|
||||
{
|
||||
for (auto const& t : v)
|
||||
hash_append(h, t);
|
||||
hash_append(h, v.size());
|
||||
}
|
||||
|
||||
template <class Hasher, class T, class Alloc>
|
||||
inline std::enable_if_t<is_contiguously_hashable<T, Hasher>::value>
|
||||
hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
|
||||
{
|
||||
h(v.data(), v.size() * sizeof(T));
|
||||
hash_append(h, v.size());
|
||||
}
|
||||
|
||||
// array
|
||||
|
||||
template <class Hasher, class T, std::size_t N>
|
||||
std::enable_if_t<!is_contiguously_hashable<std::array<T, N>, Hasher>::value>
|
||||
hash_append(Hasher& h, std::array<T, N> const& a) noexcept
|
||||
{
|
||||
for (auto const& t : a)
|
||||
hash_append(h, t);
|
||||
}
|
||||
|
||||
template <class Hasher, class Key, class Compare, class Alloc>
|
||||
std::enable_if_t<!is_contiguously_hashable<Key, Hasher>::value>
|
||||
hash_append(
|
||||
Hasher& h,
|
||||
boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
|
||||
{
|
||||
for (auto const& t : v)
|
||||
hash_append(h, t);
|
||||
}
|
||||
template <class Hasher, class Key, class Compare, class Alloc>
|
||||
std::enable_if_t<is_contiguously_hashable<Key, Hasher>::value>
|
||||
hash_append(
|
||||
Hasher& h,
|
||||
boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
|
||||
{
|
||||
h(&(v.begin()), v.size() * sizeof(Key));
|
||||
}
|
||||
// tuple
|
||||
|
||||
namespace detail {
|
||||
|
||||
inline void
|
||||
for_each_item(...) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
template <class Hasher, class T>
|
||||
inline int
|
||||
hash_one(Hasher& h, T const& t) noexcept
|
||||
{
|
||||
hash_append(h, t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class Hasher, class... T, std::size_t... I>
|
||||
inline void
|
||||
tuple_hash(
|
||||
Hasher& h,
|
||||
std::tuple<T...> const& t,
|
||||
std::index_sequence<I...>) noexcept
|
||||
{
|
||||
for_each_item(hash_one(h, std::get<I>(t))...);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class Hasher, class... T>
|
||||
inline std::enable_if_t<
|
||||
!is_contiguously_hashable<std::tuple<T...>, Hasher>::value>
|
||||
hash_append(Hasher& h, std::tuple<T...> const& t) noexcept
|
||||
{
|
||||
detail::tuple_hash(h, t, std::index_sequence_for<T...>{});
|
||||
}
|
||||
|
||||
// shared_ptr
|
||||
|
||||
template <class Hasher, class T>
|
||||
inline void
|
||||
hash_append(Hasher& h, std::shared_ptr<T> const& p) noexcept
|
||||
{
|
||||
hash_append(h, p.get());
|
||||
}
|
||||
|
||||
// chrono
|
||||
|
||||
template <class Hasher, class Rep, class Period>
|
||||
inline void
|
||||
hash_append(Hasher& h, std::chrono::duration<Rep, Period> const& d) noexcept
|
||||
{
|
||||
hash_append(h, d.count());
|
||||
}
|
||||
|
||||
template <class Hasher, class Clock, class Duration>
|
||||
inline void
|
||||
hash_append(
|
||||
Hasher& h,
|
||||
std::chrono::time_point<Clock, Duration> const& tp) noexcept
|
||||
{
|
||||
hash_append(h, tp.time_since_epoch());
|
||||
}
|
||||
|
||||
// variadic
|
||||
|
||||
template <class Hasher, class T0, class T1, class... T>
|
||||
inline void
|
||||
hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept
|
||||
{
|
||||
hash_append(h, t0);
|
||||
hash_append(h, t1, t...);
|
||||
}
|
||||
|
||||
// error_code
|
||||
|
||||
template <class HashAlgorithm>
|
||||
inline void
|
||||
hash_append(HashAlgorithm& h, std::error_code const& ec)
|
||||
{
|
||||
hash_append(h, ec.value(), &ec.category());
|
||||
}
|
||||
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
49
include/xrpl/beast/hash/uhash.h
Normal file
49
include/xrpl/beast/hash/uhash.h
Normal file
@@ -0,0 +1,49 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_UHASH_H_INCLUDED
|
||||
#define BEAST_HASH_UHASH_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/hash/hash_append.h>
|
||||
#include <ripple/beast/hash/xxhasher.h>
|
||||
|
||||
namespace beast {
|
||||
|
||||
// Universal hash function
|
||||
template <class Hasher = xxhasher>
|
||||
struct uhash
|
||||
{
|
||||
explicit uhash() = default;
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
101
include/xrpl/beast/hash/xxhasher.h
Normal file
101
include/xrpl/beast/hash/xxhasher.h
Normal file
@@ -0,0 +1,101 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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
|
||||
|
||||
#include <boost/endian/conversion.hpp>
|
||||
#include <xxhash.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
|
||||
class xxhasher
|
||||
{
|
||||
private:
|
||||
// requires 64-bit std::size_t
|
||||
static_assert(sizeof(std::size_t) == 8, "");
|
||||
|
||||
XXH3_state_t* state_;
|
||||
|
||||
static XXH3_state_t*
|
||||
allocState()
|
||||
{
|
||||
auto ret = XXH3_createState();
|
||||
if (ret == nullptr)
|
||||
throw std::bad_alloc();
|
||||
return ret;
|
||||
}
|
||||
|
||||
public:
|
||||
using result_type = std::size_t;
|
||||
|
||||
static constexpr auto const endian = boost::endian::order::native;
|
||||
|
||||
xxhasher(xxhasher const&) = delete;
|
||||
xxhasher&
|
||||
operator=(xxhasher const&) = delete;
|
||||
|
||||
xxhasher()
|
||||
{
|
||||
state_ = allocState();
|
||||
XXH3_64bits_reset(state_);
|
||||
}
|
||||
|
||||
~xxhasher() noexcept
|
||||
{
|
||||
XXH3_freeState(state_);
|
||||
}
|
||||
|
||||
template <
|
||||
class Seed,
|
||||
std::enable_if_t<std::is_unsigned<Seed>::value>* = nullptr>
|
||||
explicit xxhasher(Seed seed)
|
||||
{
|
||||
state_ = allocState();
|
||||
XXH3_64bits_reset_withSeed(state_, seed);
|
||||
}
|
||||
|
||||
template <
|
||||
class Seed,
|
||||
std::enable_if_t<std::is_unsigned<Seed>::value>* = nullptr>
|
||||
xxhasher(Seed seed, Seed)
|
||||
{
|
||||
state_ = allocState();
|
||||
XXH3_64bits_reset_withSeed(state_, seed);
|
||||
}
|
||||
|
||||
void
|
||||
operator()(void const* key, std::size_t len) noexcept
|
||||
{
|
||||
XXH3_64bits_update(state_, key, len);
|
||||
}
|
||||
|
||||
explicit operator std::size_t() noexcept
|
||||
{
|
||||
return XXH3_64bits_digest(state_);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
143
include/xrpl/beast/insight/Collector.h
Normal file
143
include/xrpl/beast/insight/Collector.h
Normal file
@@ -0,0 +1,143 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_INSIGHT_COLLECTOR_H_INCLUDED
|
||||
#define BEAST_INSIGHT_COLLECTOR_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/insight/Counter.h>
|
||||
#include <ripple/beast/insight/Event.h>
|
||||
#include <ripple/beast/insight/Gauge.h>
|
||||
#include <ripple/beast/insight/Hook.h>
|
||||
#include <ripple/beast/insight/Meter.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
namespace insight {
|
||||
|
||||
/** Interface for a manager that allows collection of metrics.
|
||||
|
||||
To export metrics from a class, pass and save a shared_ptr to this
|
||||
interface in the class constructor. Create the metric objects
|
||||
as desired (counters, events, gauges, meters, and an optional hook)
|
||||
using the interface.
|
||||
|
||||
@see Counter, Event, Gauge, Hook, Meter
|
||||
@see NullCollector, StatsDCollector
|
||||
*/
|
||||
class Collector
|
||||
{
|
||||
public:
|
||||
using ptr = std::shared_ptr<Collector>;
|
||||
|
||||
virtual ~Collector() = 0;
|
||||
|
||||
/** Create a hook.
|
||||
|
||||
A hook is called at each collection interval, on an implementation
|
||||
defined thread. This is a convenience facility for gathering metrics
|
||||
in the polling style. The typical usage is to update all the metrics
|
||||
of interest in the handler.
|
||||
|
||||
Handler will be called with this signature:
|
||||
void handler (void)
|
||||
|
||||
@see Hook
|
||||
*/
|
||||
/** @{ */
|
||||
template <class Handler>
|
||||
Hook
|
||||
make_hook(Handler handler)
|
||||
{
|
||||
return make_hook(HookImpl::HandlerType(handler));
|
||||
}
|
||||
|
||||
virtual Hook
|
||||
make_hook(HookImpl::HandlerType const& handler) = 0;
|
||||
/** @} */
|
||||
|
||||
/** Create a counter with the specified name.
|
||||
@see Counter
|
||||
*/
|
||||
/** @{ */
|
||||
virtual Counter
|
||||
make_counter(std::string const& name) = 0;
|
||||
|
||||
Counter
|
||||
make_counter(std::string const& prefix, std::string const& name)
|
||||
{
|
||||
if (prefix.empty())
|
||||
return make_counter(name);
|
||||
return make_counter(prefix + "." + name);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Create an event with the specified name.
|
||||
@see Event
|
||||
*/
|
||||
/** @{ */
|
||||
virtual Event
|
||||
make_event(std::string const& name) = 0;
|
||||
|
||||
Event
|
||||
make_event(std::string const& prefix, std::string const& name)
|
||||
{
|
||||
if (prefix.empty())
|
||||
return make_event(name);
|
||||
return make_event(prefix + "." + name);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Create a gauge with the specified name.
|
||||
@see Gauge
|
||||
*/
|
||||
/** @{ */
|
||||
virtual Gauge
|
||||
make_gauge(std::string const& name) = 0;
|
||||
|
||||
Gauge
|
||||
make_gauge(std::string const& prefix, std::string const& name)
|
||||
{
|
||||
if (prefix.empty())
|
||||
return make_gauge(name);
|
||||
return make_gauge(prefix + "." + name);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Create a meter with the specified name.
|
||||
@see Meter
|
||||
*/
|
||||
/** @{ */
|
||||
virtual Meter
|
||||
make_meter(std::string const& name) = 0;
|
||||
|
||||
Meter
|
||||
make_meter(std::string const& prefix, std::string const& name)
|
||||
{
|
||||
if (prefix.empty())
|
||||
return make_meter(name);
|
||||
return make_meter(prefix + "." + name);
|
||||
}
|
||||
/** @} */
|
||||
};
|
||||
|
||||
} // namespace insight
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
117
include/xrpl/beast/insight/Counter.h
Normal file
117
include/xrpl/beast/insight/Counter.h
Normal file
@@ -0,0 +1,117 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_INSIGHT_COUNTER_H_INCLUDED
|
||||
#define BEAST_INSIGHT_COUNTER_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/insight/CounterImpl.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace beast {
|
||||
namespace insight {
|
||||
|
||||
/** A metric for measuring an integral value.
|
||||
|
||||
A counter is a gauge calculated at the server. The owner of the counter
|
||||
may increment and decrement the value by an amount.
|
||||
|
||||
This is a lightweight reference wrapper which is cheap to copy and assign.
|
||||
When the last reference goes away, the metric is no longer collected.
|
||||
*/
|
||||
class Counter final
|
||||
{
|
||||
public:
|
||||
using value_type = CounterImpl::value_type;
|
||||
|
||||
/** Create a null metric.
|
||||
A null metric reports no information.
|
||||
*/
|
||||
Counter()
|
||||
{
|
||||
}
|
||||
|
||||
/** Create the metric reference the specified implementation.
|
||||
Normally this won't be called directly. Instead, call the appropriate
|
||||
factory function in the Collector interface.
|
||||
@see Collector.
|
||||
*/
|
||||
explicit Counter(std::shared_ptr<CounterImpl> const& impl) : m_impl(impl)
|
||||
{
|
||||
}
|
||||
|
||||
/** Increment the counter. */
|
||||
/** @{ */
|
||||
void
|
||||
increment(value_type amount) const
|
||||
{
|
||||
if (m_impl)
|
||||
m_impl->increment(amount);
|
||||
}
|
||||
|
||||
Counter const&
|
||||
operator+=(value_type amount) const
|
||||
{
|
||||
increment(amount);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Counter const&
|
||||
operator-=(value_type amount) const
|
||||
{
|
||||
increment(-amount);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Counter const&
|
||||
operator++() const
|
||||
{
|
||||
increment(1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Counter const&
|
||||
operator++(int) const
|
||||
{
|
||||
increment(1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Counter const&
|
||||
operator--() const
|
||||
{
|
||||
increment(-1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Counter const&
|
||||
operator--(int) const
|
||||
{
|
||||
increment(-1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<CounterImpl> m_impl;
|
||||
};
|
||||
|
||||
} // namespace insight
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
44
include/xrpl/beast/insight/CounterImpl.h
Normal file
44
include/xrpl/beast/insight/CounterImpl.h
Normal file
@@ -0,0 +1,44 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_INSIGHT_COUNTERIMPL_H_INCLUDED
|
||||
#define BEAST_INSIGHT_COUNTERIMPL_H_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
namespace beast {
|
||||
namespace insight {
|
||||
|
||||
class Counter;
|
||||
|
||||
class CounterImpl : public std::enable_shared_from_this<CounterImpl>
|
||||
{
|
||||
public:
|
||||
using value_type = std::int64_t;
|
||||
|
||||
virtual ~CounterImpl() = 0;
|
||||
virtual void
|
||||
increment(value_type amount) = 0;
|
||||
};
|
||||
|
||||
} // namespace insight
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
84
include/xrpl/beast/insight/Event.h
Normal file
84
include/xrpl/beast/insight/Event.h
Normal file
@@ -0,0 +1,84 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_INSIGHT_EVENT_H_INCLUDED
|
||||
#define BEAST_INSIGHT_EVENT_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/insight/EventImpl.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
namespace beast {
|
||||
namespace insight {
|
||||
|
||||
/** A metric for reporting event timing.
|
||||
|
||||
An event is an operation that has an associated millisecond time, or
|
||||
other integral value. Because events happen at a specific moment, the
|
||||
metric only supports a push-style interface.
|
||||
|
||||
This is a lightweight reference wrapper which is cheap to copy and assign.
|
||||
When the last reference goes away, the metric is no longer collected.
|
||||
*/
|
||||
class Event final
|
||||
{
|
||||
public:
|
||||
using value_type = EventImpl::value_type;
|
||||
|
||||
/** Create a null metric.
|
||||
A null metric reports no information.
|
||||
*/
|
||||
Event()
|
||||
{
|
||||
}
|
||||
|
||||
/** Create the metric reference the specified implementation.
|
||||
Normally this won't be called directly. Instead, call the appropriate
|
||||
factory function in the Collector interface.
|
||||
@see Collector.
|
||||
*/
|
||||
explicit Event(std::shared_ptr<EventImpl> const& impl) : m_impl(impl)
|
||||
{
|
||||
}
|
||||
|
||||
/** Push an event notification. */
|
||||
template <class Rep, class Period>
|
||||
void
|
||||
notify(std::chrono::duration<Rep, Period> const& value) const
|
||||
{
|
||||
using namespace std::chrono;
|
||||
if (m_impl)
|
||||
m_impl->notify(ceil<value_type>(value));
|
||||
}
|
||||
|
||||
std::shared_ptr<EventImpl> const&
|
||||
impl() const
|
||||
{
|
||||
return m_impl;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<EventImpl> m_impl;
|
||||
};
|
||||
|
||||
} // namespace insight
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
44
include/xrpl/beast/insight/EventImpl.h
Normal file
44
include/xrpl/beast/insight/EventImpl.h
Normal file
@@ -0,0 +1,44 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_INSIGHT_EVENTIMPL_H_INCLUDED
|
||||
#define BEAST_INSIGHT_EVENTIMPL_H_INCLUDED
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
namespace beast {
|
||||
namespace insight {
|
||||
|
||||
class Event;
|
||||
|
||||
class EventImpl : public std::enable_shared_from_this<EventImpl>
|
||||
{
|
||||
public:
|
||||
using value_type = std::chrono::milliseconds;
|
||||
|
||||
virtual ~EventImpl() = 0;
|
||||
virtual void
|
||||
notify(value_type const& value) = 0;
|
||||
};
|
||||
|
||||
} // namespace insight
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
147
include/xrpl/beast/insight/Gauge.h
Normal file
147
include/xrpl/beast/insight/Gauge.h
Normal file
@@ -0,0 +1,147 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_INSIGHT_GAUGE_H_INCLUDED
|
||||
#define BEAST_INSIGHT_GAUGE_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/insight/GaugeImpl.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace beast {
|
||||
namespace insight {
|
||||
|
||||
/** A metric for measuring an integral value.
|
||||
|
||||
A gauge is an instantaneous measurement of a value, like the gas gauge
|
||||
in a car. The caller directly sets the value, or adjusts it by a
|
||||
specified amount. The value is kept in the client rather than the collector.
|
||||
|
||||
This is a lightweight reference wrapper which is cheap to copy and assign.
|
||||
When the last reference goes away, the metric is no longer collected.
|
||||
*/
|
||||
class Gauge final
|
||||
{
|
||||
public:
|
||||
using value_type = GaugeImpl::value_type;
|
||||
using difference_type = GaugeImpl::difference_type;
|
||||
|
||||
/** Create a null metric.
|
||||
A null metric reports no information.
|
||||
*/
|
||||
Gauge()
|
||||
{
|
||||
}
|
||||
|
||||
/** Create the metric reference the specified implementation.
|
||||
Normally this won't be called directly. Instead, call the appropriate
|
||||
factory function in the Collector interface.
|
||||
@see Collector.
|
||||
*/
|
||||
explicit Gauge(std::shared_ptr<GaugeImpl> const& impl) : m_impl(impl)
|
||||
{
|
||||
}
|
||||
|
||||
/** Set the value on the gauge.
|
||||
A Collector implementation should combine multiple calls to value
|
||||
changes into a single change if the calls occur within a single
|
||||
collection interval.
|
||||
*/
|
||||
/** @{ */
|
||||
void
|
||||
set(value_type value) const
|
||||
{
|
||||
if (m_impl)
|
||||
m_impl->set(value);
|
||||
}
|
||||
|
||||
Gauge const&
|
||||
operator=(value_type value) const
|
||||
{
|
||||
set(value);
|
||||
return *this;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Adjust the value of the gauge. */
|
||||
/** @{ */
|
||||
void
|
||||
increment(difference_type amount) const
|
||||
{
|
||||
if (m_impl)
|
||||
m_impl->increment(amount);
|
||||
}
|
||||
|
||||
Gauge const&
|
||||
operator+=(difference_type amount) const
|
||||
{
|
||||
increment(amount);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Gauge const&
|
||||
operator-=(difference_type amount) const
|
||||
{
|
||||
increment(-amount);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Gauge const&
|
||||
operator++() const
|
||||
{
|
||||
increment(1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Gauge const&
|
||||
operator++(int) const
|
||||
{
|
||||
increment(1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Gauge const&
|
||||
operator--() const
|
||||
{
|
||||
increment(-1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Gauge const&
|
||||
operator--(int) const
|
||||
{
|
||||
increment(-1);
|
||||
return *this;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
std::shared_ptr<GaugeImpl> const&
|
||||
impl() const
|
||||
{
|
||||
return m_impl;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<GaugeImpl> m_impl;
|
||||
};
|
||||
|
||||
} // namespace insight
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
47
include/xrpl/beast/insight/GaugeImpl.h
Normal file
47
include/xrpl/beast/insight/GaugeImpl.h
Normal file
@@ -0,0 +1,47 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_INSIGHT_GAUGEIMPL_H_INCLUDED
|
||||
#define BEAST_INSIGHT_GAUGEIMPL_H_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
namespace beast {
|
||||
namespace insight {
|
||||
|
||||
class Gauge;
|
||||
|
||||
class GaugeImpl : public std::enable_shared_from_this<GaugeImpl>
|
||||
{
|
||||
public:
|
||||
using value_type = std::uint64_t;
|
||||
using difference_type = std::int64_t;
|
||||
|
||||
virtual ~GaugeImpl() = 0;
|
||||
virtual void
|
||||
set(value_type value) = 0;
|
||||
virtual void
|
||||
increment(difference_type amount) = 0;
|
||||
};
|
||||
|
||||
} // namespace insight
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
45
include/xrpl/beast/insight/Group.h
Normal file
45
include/xrpl/beast/insight/Group.h
Normal file
@@ -0,0 +1,45 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_INSIGHT_GROUP_H_INCLUDED
|
||||
#define BEAST_INSIGHT_GROUP_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/insight/Collector.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
namespace insight {
|
||||
|
||||
/** A collector front-end that manages a group of metrics. */
|
||||
class Group : public Collector
|
||||
{
|
||||
public:
|
||||
using ptr = std::shared_ptr<Group>;
|
||||
|
||||
/** Returns the name of this group, for diagnostics. */
|
||||
virtual std::string const&
|
||||
name() const = 0;
|
||||
};
|
||||
|
||||
} // namespace insight
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
58
include/xrpl/beast/insight/Groups.h
Normal file
58
include/xrpl/beast/insight/Groups.h
Normal file
@@ -0,0 +1,58 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_INSIGHT_GROUPS_H_INCLUDED
|
||||
#define BEAST_INSIGHT_GROUPS_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/insight/Collector.h>
|
||||
#include <ripple/beast/insight/Group.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
namespace insight {
|
||||
|
||||
/** A container for managing a set of metric groups. */
|
||||
class Groups
|
||||
{
|
||||
public:
|
||||
virtual ~Groups() = 0;
|
||||
|
||||
/** Find or create a new collector with a given name. */
|
||||
/** @{ */
|
||||
virtual Group::ptr const&
|
||||
get(std::string const& name) = 0;
|
||||
|
||||
Group::ptr const&
|
||||
operator[](std::string const& name)
|
||||
{
|
||||
return get(name);
|
||||
}
|
||||
/** @} */
|
||||
};
|
||||
|
||||
/** Create a group container that uses the specified collector. */
|
||||
std::unique_ptr<Groups>
|
||||
make_Groups(Collector::ptr const& collector);
|
||||
|
||||
} // namespace insight
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
63
include/xrpl/beast/insight/Hook.h
Normal file
63
include/xrpl/beast/insight/Hook.h
Normal file
@@ -0,0 +1,63 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_INSIGHT_HOOK_H_INCLUDED
|
||||
#define BEAST_INSIGHT_HOOK_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/insight/HookImpl.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace beast {
|
||||
namespace insight {
|
||||
|
||||
/** A reference to a handler for performing polled collection. */
|
||||
class Hook final
|
||||
{
|
||||
public:
|
||||
/** Create a null hook.
|
||||
A null hook has no associated handler.
|
||||
*/
|
||||
Hook()
|
||||
{
|
||||
}
|
||||
|
||||
/** Create a hook referencing the specified implementation.
|
||||
Normally this won't be called directly. Instead, call the appropriate
|
||||
factory function in the Collector interface.
|
||||
@see Collector.
|
||||
*/
|
||||
explicit Hook(std::shared_ptr<HookImpl> const& impl) : m_impl(impl)
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<HookImpl> const&
|
||||
impl() const
|
||||
{
|
||||
return m_impl;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<HookImpl> m_impl;
|
||||
};
|
||||
|
||||
} // namespace insight
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
40
include/xrpl/beast/insight/HookImpl.h
Normal file
40
include/xrpl/beast/insight/HookImpl.h
Normal file
@@ -0,0 +1,40 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_INSIGHT_HOOKIMPL_H_INCLUDED
|
||||
#define BEAST_INSIGHT_HOOKIMPL_H_INCLUDED
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace beast {
|
||||
namespace insight {
|
||||
|
||||
class HookImpl : public std::enable_shared_from_this<HookImpl>
|
||||
{
|
||||
public:
|
||||
using HandlerType = std::function<void(void)>;
|
||||
|
||||
virtual ~HookImpl() = 0;
|
||||
};
|
||||
|
||||
} // namespace insight
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
37
include/xrpl/beast/insight/Insight.h
Normal file
37
include/xrpl/beast/insight/Insight.h
Normal file
@@ -0,0 +1,37 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_INSIGHT_H_INCLUDED
|
||||
#define BEAST_INSIGHT_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/insight/Collector.h>
|
||||
#include <ripple/beast/insight/Counter.h>
|
||||
#include <ripple/beast/insight/CounterImpl.h>
|
||||
#include <ripple/beast/insight/Event.h>
|
||||
#include <ripple/beast/insight/EventImpl.h>
|
||||
#include <ripple/beast/insight/Gauge.h>
|
||||
#include <ripple/beast/insight/GaugeImpl.h>
|
||||
#include <ripple/beast/insight/Group.h>
|
||||
#include <ripple/beast/insight/Groups.h>
|
||||
#include <ripple/beast/insight/Hook.h>
|
||||
#include <ripple/beast/insight/HookImpl.h>
|
||||
#include <ripple/beast/insight/NullCollector.h>
|
||||
#include <ripple/beast/insight/StatsDCollector.h>
|
||||
|
||||
#endif
|
||||
102
include/xrpl/beast/insight/Meter.h
Normal file
102
include/xrpl/beast/insight/Meter.h
Normal file
@@ -0,0 +1,102 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_INSIGHT_METER_H_INCLUDED
|
||||
#define BEAST_INSIGHT_METER_H_INCLUDED
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <ripple/beast/insight/MeterImpl.h>
|
||||
|
||||
namespace beast {
|
||||
namespace insight {
|
||||
|
||||
/** A metric for measuring an integral value.
|
||||
|
||||
A meter may be thought of as an increment-only counter.
|
||||
|
||||
This is a lightweight reference wrapper which is cheap to copy and assign.
|
||||
When the last reference goes away, the metric is no longer collected.
|
||||
*/
|
||||
class Meter final
|
||||
{
|
||||
public:
|
||||
using value_type = MeterImpl::value_type;
|
||||
|
||||
/** Create a null metric.
|
||||
A null metric reports no information.
|
||||
*/
|
||||
Meter()
|
||||
{
|
||||
}
|
||||
|
||||
/** Create the metric reference the specified implementation.
|
||||
Normally this won't be called directly. Instead, call the appropriate
|
||||
factory function in the Collector interface.
|
||||
@see Collector.
|
||||
*/
|
||||
explicit Meter(std::shared_ptr<MeterImpl> const& impl) : m_impl(impl)
|
||||
{
|
||||
}
|
||||
|
||||
/** Increment the meter. */
|
||||
/** @{ */
|
||||
void
|
||||
increment(value_type amount) const
|
||||
{
|
||||
if (m_impl)
|
||||
m_impl->increment(amount);
|
||||
}
|
||||
|
||||
Meter const&
|
||||
operator+=(value_type amount) const
|
||||
{
|
||||
increment(amount);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Meter const&
|
||||
operator++() const
|
||||
{
|
||||
increment(1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Meter const&
|
||||
operator++(int) const
|
||||
{
|
||||
increment(1);
|
||||
return *this;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
std::shared_ptr<MeterImpl> const&
|
||||
impl() const
|
||||
{
|
||||
return m_impl;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<MeterImpl> m_impl;
|
||||
};
|
||||
|
||||
} // namespace insight
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
44
include/xrpl/beast/insight/MeterImpl.h
Normal file
44
include/xrpl/beast/insight/MeterImpl.h
Normal file
@@ -0,0 +1,44 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_INSIGHT_METERIMPL_H_INCLUDED
|
||||
#define BEAST_INSIGHT_METERIMPL_H_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
namespace beast {
|
||||
namespace insight {
|
||||
|
||||
class Meter;
|
||||
|
||||
class MeterImpl : public std::enable_shared_from_this<MeterImpl>
|
||||
{
|
||||
public:
|
||||
using value_type = std::uint64_t;
|
||||
|
||||
virtual ~MeterImpl() = 0;
|
||||
virtual void
|
||||
increment(value_type amount) = 0;
|
||||
};
|
||||
|
||||
} // namespace insight
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
41
include/xrpl/beast/insight/NullCollector.h
Normal file
41
include/xrpl/beast/insight/NullCollector.h
Normal file
@@ -0,0 +1,41 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_INSIGHT_NULLCOLLECTOR_H_INCLUDED
|
||||
#define BEAST_INSIGHT_NULLCOLLECTOR_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/insight/Collector.h>
|
||||
|
||||
namespace beast {
|
||||
namespace insight {
|
||||
|
||||
/** A Collector which does not collect metrics. */
|
||||
class NullCollector : public Collector
|
||||
{
|
||||
public:
|
||||
explicit NullCollector() = default;
|
||||
|
||||
static std::shared_ptr<Collector>
|
||||
New();
|
||||
};
|
||||
|
||||
} // namespace insight
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
54
include/xrpl/beast/insight/StatsDCollector.h
Normal file
54
include/xrpl/beast/insight/StatsDCollector.h
Normal file
@@ -0,0 +1,54 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_INSIGHT_STATSDCOLLECTOR_H_INCLUDED
|
||||
#define BEAST_INSIGHT_STATSDCOLLECTOR_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/insight/Collector.h>
|
||||
|
||||
#include <ripple/beast/net/IPEndpoint.h>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
|
||||
namespace beast {
|
||||
namespace insight {
|
||||
|
||||
/** A Collector that reports metrics to a StatsD server.
|
||||
Reference:
|
||||
https://github.com/b/statsd_spec
|
||||
*/
|
||||
class StatsDCollector : public Collector
|
||||
{
|
||||
public:
|
||||
explicit StatsDCollector() = default;
|
||||
|
||||
/** Create a StatsD collector.
|
||||
@param address The IP address and port of the StatsD server.
|
||||
@param prefix A string pre-pended before each metric name.
|
||||
@param journal Destination for logging output.
|
||||
*/
|
||||
static std::shared_ptr<StatsDCollector>
|
||||
New(IP::Endpoint const& address,
|
||||
std::string const& prefix,
|
||||
Journal journal);
|
||||
};
|
||||
|
||||
} // namespace insight
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
117
include/xrpl/beast/net/IPAddress.h
Normal file
117
include/xrpl/beast/net/IPAddress.h
Normal file
@@ -0,0 +1,117 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_NET_IPADDRESS_H_INCLUDED
|
||||
#define BEAST_NET_IPADDRESS_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/hash/hash_append.h>
|
||||
#include <ripple/beast/hash/uhash.h>
|
||||
#include <ripple/beast/net/IPAddressV4.h>
|
||||
#include <ripple/beast/net/IPAddressV6.h>
|
||||
#include <boost/asio/ip/address.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <ios>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace beast {
|
||||
namespace IP {
|
||||
|
||||
using Address = boost::asio::ip::address;
|
||||
|
||||
/** Returns the address represented as a string. */
|
||||
inline std::string
|
||||
to_string(Address const& addr)
|
||||
{
|
||||
return addr.to_string();
|
||||
}
|
||||
|
||||
/** Returns `true` if this is a loopback address. */
|
||||
inline bool
|
||||
is_loopback(Address const& addr)
|
||||
{
|
||||
return addr.is_loopback();
|
||||
}
|
||||
|
||||
/** Returns `true` if the address is unspecified. */
|
||||
inline bool
|
||||
is_unspecified(Address const& addr)
|
||||
{
|
||||
return addr.is_unspecified();
|
||||
}
|
||||
|
||||
/** Returns `true` if the address is a multicast address. */
|
||||
inline bool
|
||||
is_multicast(Address const& addr)
|
||||
{
|
||||
return addr.is_multicast();
|
||||
}
|
||||
|
||||
/** Returns `true` if the address is a private unroutable address. */
|
||||
inline bool
|
||||
is_private(Address const& addr)
|
||||
{
|
||||
return (addr.is_v4()) ? is_private(addr.to_v4()) : is_private(addr.to_v6());
|
||||
}
|
||||
|
||||
/** Returns `true` if the address is a public routable address. */
|
||||
inline bool
|
||||
is_public(Address const& addr)
|
||||
{
|
||||
return (addr.is_v4()) ? is_public(addr.to_v4()) : is_public(addr.to_v6());
|
||||
}
|
||||
|
||||
} // namespace IP
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class Hasher>
|
||||
void
|
||||
hash_append(Hasher& h, beast::IP::Address const& addr) noexcept
|
||||
{
|
||||
using beast::hash_append;
|
||||
if (addr.is_v4())
|
||||
hash_append(h, addr.to_v4().to_bytes());
|
||||
else if (addr.is_v6())
|
||||
hash_append(h, addr.to_v6().to_bytes());
|
||||
else
|
||||
assert(false);
|
||||
}
|
||||
} // namespace beast
|
||||
|
||||
namespace boost {
|
||||
template <>
|
||||
struct hash<::beast::IP::Address>
|
||||
{
|
||||
explicit hash() = default;
|
||||
|
||||
std::size_t
|
||||
operator()(::beast::IP::Address const& addr) const
|
||||
{
|
||||
return ::beast::uhash<>{}(addr);
|
||||
}
|
||||
};
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
86
include/xrpl/beast/net/IPAddressConversion.h
Normal file
86
include/xrpl/beast/net/IPAddressConversion.h
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_NET_IPADDRESSCONVERSION_H_INCLUDED
|
||||
#define BEAST_NET_IPADDRESSCONVERSION_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/net/IPEndpoint.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace IP {
|
||||
|
||||
/** Convert to Endpoint.
|
||||
The port is set to zero.
|
||||
*/
|
||||
Endpoint
|
||||
from_asio(boost::asio::ip::address const& address);
|
||||
|
||||
/** Convert to Endpoint. */
|
||||
Endpoint
|
||||
from_asio(boost::asio::ip::tcp::endpoint const& endpoint);
|
||||
|
||||
/** Convert to asio::ip::address.
|
||||
The port is ignored.
|
||||
*/
|
||||
boost::asio::ip::address
|
||||
to_asio_address(Endpoint const& endpoint);
|
||||
|
||||
/** Convert to asio::ip::tcp::endpoint. */
|
||||
boost::asio::ip::tcp::endpoint
|
||||
to_asio_endpoint(Endpoint const& endpoint);
|
||||
|
||||
} // namespace IP
|
||||
} // namespace beast
|
||||
|
||||
namespace beast {
|
||||
|
||||
// DEPRECATED
|
||||
struct IPAddressConversion
|
||||
{
|
||||
explicit IPAddressConversion() = default;
|
||||
|
||||
static IP::Endpoint
|
||||
from_asio(boost::asio::ip::address const& address)
|
||||
{
|
||||
return IP::from_asio(address);
|
||||
}
|
||||
static IP::Endpoint
|
||||
from_asio(boost::asio::ip::tcp::endpoint const& endpoint)
|
||||
{
|
||||
return IP::from_asio(endpoint);
|
||||
}
|
||||
static boost::asio::ip::address
|
||||
to_asio_address(IP::Endpoint const& address)
|
||||
{
|
||||
return IP::to_asio_address(address);
|
||||
}
|
||||
static boost::asio::ip::tcp::endpoint
|
||||
to_asio_endpoint(IP::Endpoint const& address)
|
||||
{
|
||||
return IP::to_asio_endpoint(address);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
53
include/xrpl/beast/net/IPAddressV4.h
Normal file
53
include/xrpl/beast/net/IPAddressV4.h
Normal file
@@ -0,0 +1,53 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_NET_IPADDRESSV4_H_INCLUDED
|
||||
#define BEAST_NET_IPADDRESSV4_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/hash/hash_append.h>
|
||||
#include <boost/asio/ip/address_v4.hpp>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <ios>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace IP {
|
||||
|
||||
using AddressV4 = boost::asio::ip::address_v4;
|
||||
|
||||
/** Returns `true` if the address is a private unroutable address. */
|
||||
bool
|
||||
is_private(AddressV4 const& addr);
|
||||
|
||||
/** Returns `true` if the address is a public routable address. */
|
||||
bool
|
||||
is_public(AddressV4 const& addr);
|
||||
|
||||
/** Returns the address class for the given address.
|
||||
@note Class 'D' represents multicast addresses (224.*.*.*).
|
||||
*/
|
||||
char
|
||||
get_class(AddressV4 const& address);
|
||||
|
||||
} // namespace IP
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
47
include/xrpl/beast/net/IPAddressV6.h
Normal file
47
include/xrpl/beast/net/IPAddressV6.h
Normal file
@@ -0,0 +1,47 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_NET_IPADDRESSV6_H_INCLUDED
|
||||
#define BEAST_NET_IPADDRESSV6_H_INCLUDED
|
||||
|
||||
#include <boost/asio/ip/address_v6.hpp>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <ios>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace IP {
|
||||
|
||||
using AddressV6 = boost::asio::ip::address_v6;
|
||||
|
||||
/** Returns `true` if the address is a private unroutable address. */
|
||||
bool
|
||||
is_private(AddressV6 const& addr);
|
||||
|
||||
/** Returns `true` if the address is a public routable address. */
|
||||
bool
|
||||
is_public(AddressV6 const& addr);
|
||||
|
||||
} // namespace IP
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
243
include/xrpl/beast/net/IPEndpoint.h
Normal file
243
include/xrpl/beast/net/IPEndpoint.h
Normal file
@@ -0,0 +1,243 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_NET_IPENDPOINT_H_INCLUDED
|
||||
#define BEAST_NET_IPENDPOINT_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/hash/hash_append.h>
|
||||
#include <ripple/beast/hash/uhash.h>
|
||||
#include <ripple/beast/net/IPAddress.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <ios>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
namespace IP {
|
||||
|
||||
using Port = std::uint16_t;
|
||||
|
||||
/** A version-independent IP address and port combination. */
|
||||
class Endpoint
|
||||
{
|
||||
public:
|
||||
/** Create an unspecified endpoint. */
|
||||
Endpoint();
|
||||
|
||||
/** Create an endpoint from the address and optional port. */
|
||||
explicit Endpoint(Address const& addr, Port port = 0);
|
||||
|
||||
/** Create an Endpoint from a string.
|
||||
If the port is omitted, the endpoint will have a zero port.
|
||||
@return An optional endpoint; will be `std::nullopt` on failure
|
||||
*/
|
||||
static std::optional<Endpoint>
|
||||
from_string_checked(std::string const& s);
|
||||
static Endpoint
|
||||
from_string(std::string const& s);
|
||||
|
||||
/** Returns a string representing the endpoint. */
|
||||
std::string
|
||||
to_string() const;
|
||||
|
||||
/** Returns the port number on the endpoint. */
|
||||
Port
|
||||
port() const
|
||||
{
|
||||
return m_port;
|
||||
}
|
||||
|
||||
/** Returns a new Endpoint with a different port. */
|
||||
Endpoint
|
||||
at_port(Port port) const
|
||||
{
|
||||
return Endpoint(m_addr, port);
|
||||
}
|
||||
|
||||
/** Returns the address portion of this endpoint. */
|
||||
Address const&
|
||||
address() const
|
||||
{
|
||||
return m_addr;
|
||||
}
|
||||
|
||||
/** Convenience accessors for the address part. */
|
||||
/** @{ */
|
||||
bool
|
||||
is_v4() const
|
||||
{
|
||||
return m_addr.is_v4();
|
||||
}
|
||||
bool
|
||||
is_v6() const
|
||||
{
|
||||
return m_addr.is_v6();
|
||||
}
|
||||
AddressV4 const
|
||||
to_v4() const
|
||||
{
|
||||
return m_addr.to_v4();
|
||||
}
|
||||
AddressV6 const
|
||||
to_v6() const
|
||||
{
|
||||
return m_addr.to_v6();
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Arithmetic comparison. */
|
||||
/** @{ */
|
||||
friend bool
|
||||
operator==(Endpoint const& lhs, Endpoint const& rhs);
|
||||
friend bool
|
||||
operator<(Endpoint const& lhs, Endpoint const& rhs);
|
||||
|
||||
friend bool
|
||||
operator!=(Endpoint const& lhs, Endpoint const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
friend bool
|
||||
operator>(Endpoint const& lhs, Endpoint const& rhs)
|
||||
{
|
||||
return rhs < lhs;
|
||||
}
|
||||
friend bool
|
||||
operator<=(Endpoint const& lhs, Endpoint const& rhs)
|
||||
{
|
||||
return !(lhs > rhs);
|
||||
}
|
||||
friend bool
|
||||
operator>=(Endpoint const& lhs, Endpoint const& rhs)
|
||||
{
|
||||
return !(rhs > lhs);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
template <class Hasher>
|
||||
friend void
|
||||
hash_append(Hasher& h, Endpoint const& endpoint)
|
||||
{
|
||||
using ::beast::hash_append;
|
||||
hash_append(h, endpoint.m_addr, endpoint.m_port);
|
||||
}
|
||||
|
||||
private:
|
||||
Address m_addr;
|
||||
Port m_port;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Properties
|
||||
|
||||
/** Returns `true` if the endpoint is a loopback address. */
|
||||
inline bool
|
||||
is_loopback(Endpoint const& endpoint)
|
||||
{
|
||||
return is_loopback(endpoint.address());
|
||||
}
|
||||
|
||||
/** Returns `true` if the endpoint is unspecified. */
|
||||
inline bool
|
||||
is_unspecified(Endpoint const& endpoint)
|
||||
{
|
||||
return is_unspecified(endpoint.address());
|
||||
}
|
||||
|
||||
/** Returns `true` if the endpoint is a multicast address. */
|
||||
inline bool
|
||||
is_multicast(Endpoint const& endpoint)
|
||||
{
|
||||
return is_multicast(endpoint.address());
|
||||
}
|
||||
|
||||
/** Returns `true` if the endpoint is a private unroutable address. */
|
||||
inline bool
|
||||
is_private(Endpoint const& endpoint)
|
||||
{
|
||||
return is_private(endpoint.address());
|
||||
}
|
||||
|
||||
/** Returns `true` if the endpoint is a public routable address. */
|
||||
inline bool
|
||||
is_public(Endpoint const& endpoint)
|
||||
{
|
||||
return is_public(endpoint.address());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Returns the endpoint represented as a string. */
|
||||
inline std::string
|
||||
to_string(Endpoint const& endpoint)
|
||||
{
|
||||
return endpoint.to_string();
|
||||
}
|
||||
|
||||
/** Output stream conversion. */
|
||||
template <typename OutputStream>
|
||||
OutputStream&
|
||||
operator<<(OutputStream& os, Endpoint const& endpoint)
|
||||
{
|
||||
os << to_string(endpoint);
|
||||
return os;
|
||||
}
|
||||
|
||||
/** Input stream conversion. */
|
||||
std::istream&
|
||||
operator>>(std::istream& is, Endpoint& endpoint);
|
||||
|
||||
} // namespace IP
|
||||
} // namespace beast
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace std {
|
||||
/** std::hash support. */
|
||||
template <>
|
||||
struct hash<::beast::IP::Endpoint>
|
||||
{
|
||||
explicit hash() = default;
|
||||
|
||||
std::size_t
|
||||
operator()(::beast::IP::Endpoint const& endpoint) const
|
||||
{
|
||||
return ::beast::uhash<>{}(endpoint);
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
namespace boost {
|
||||
/** boost::hash support. */
|
||||
template <>
|
||||
struct hash<::beast::IP::Endpoint>
|
||||
{
|
||||
explicit hash() = default;
|
||||
|
||||
std::size_t
|
||||
operator()(::beast::IP::Endpoint const& endpoint) const
|
||||
{
|
||||
return ::beast::uhash<>{}(endpoint);
|
||||
}
|
||||
};
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
405
include/xrpl/beast/rfc2616.h
Normal file
405
include/xrpl/beast/rfc2616.h
Normal file
@@ -0,0 +1,405 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_RFC2616_HPP
|
||||
#define BEAST_RFC2616_HPP
|
||||
|
||||
// TODO: This include <cstdint> is a workaround for beast compilation bug.
|
||||
// Remove when fix https://github.com/boostorg/beast/pull/2682/ is available.
|
||||
#include <cstdint>
|
||||
|
||||
#include <boost/beast/http/message.hpp>
|
||||
#include <boost/beast/http/rfc7230.hpp>
|
||||
#include <boost/range/algorithm/equal.hpp>
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace beast {
|
||||
namespace rfc2616 {
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct ci_equal_pred
|
||||
{
|
||||
explicit ci_equal_pred() = default;
|
||||
|
||||
bool
|
||||
operator()(char c1, char c2)
|
||||
{
|
||||
// VFALCO TODO Use a table lookup here
|
||||
return std::tolower(static_cast<unsigned char>(c1)) ==
|
||||
std::tolower(static_cast<unsigned char>(c2));
|
||||
}
|
||||
};
|
||||
|
||||
/** Returns `true` if `c` is linear white space.
|
||||
|
||||
This excludes the CRLF sequence allowed for line continuations.
|
||||
*/
|
||||
inline bool
|
||||
is_lws(char c)
|
||||
{
|
||||
return c == ' ' || c == '\t';
|
||||
}
|
||||
|
||||
/** Returns `true` if `c` is any whitespace character. */
|
||||
inline bool
|
||||
is_white(char c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case ' ':
|
||||
case '\f':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\t':
|
||||
case '\v':
|
||||
return true;
|
||||
};
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class FwdIter>
|
||||
FwdIter
|
||||
trim_right(FwdIter first, FwdIter last)
|
||||
{
|
||||
if (first == last)
|
||||
return last;
|
||||
do
|
||||
{
|
||||
--last;
|
||||
if (!is_white(*last))
|
||||
return ++last;
|
||||
} while (last != first);
|
||||
return first;
|
||||
}
|
||||
|
||||
template <class String>
|
||||
String
|
||||
trim_right(String const& s)
|
||||
{
|
||||
using std::begin;
|
||||
using std::end;
|
||||
auto first(begin(s));
|
||||
auto last(end(s));
|
||||
last = trim_right(first, last);
|
||||
return {first, last};
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/** 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 FwdIt,
|
||||
class Result = std::vector<
|
||||
std::basic_string<typename std::iterator_traits<FwdIt>::value_type>>,
|
||||
class Char>
|
||||
Result
|
||||
split(FwdIt first, FwdIt last, Char delim)
|
||||
{
|
||||
using namespace detail;
|
||||
using string = typename Result::value_type;
|
||||
|
||||
Result result;
|
||||
|
||||
FwdIt iter = first;
|
||||
string e;
|
||||
while (iter != last)
|
||||
{
|
||||
if (*iter == '"')
|
||||
{
|
||||
// quoted-string
|
||||
++iter;
|
||||
while (iter != last)
|
||||
{
|
||||
if (*iter == '"')
|
||||
{
|
||||
++iter;
|
||||
break;
|
||||
}
|
||||
|
||||
if (*iter == '\\')
|
||||
{
|
||||
// quoted-pair
|
||||
++iter;
|
||||
if (iter != last)
|
||||
e.append(1, *iter++);
|
||||
}
|
||||
else
|
||||
{
|
||||
// qdtext
|
||||
e.append(1, *iter++);
|
||||
}
|
||||
}
|
||||
if (!e.empty())
|
||||
{
|
||||
result.emplace_back(std::move(e));
|
||||
e.clear();
|
||||
}
|
||||
}
|
||||
else if (*iter == delim)
|
||||
{
|
||||
e = trim_right(e);
|
||||
if (!e.empty())
|
||||
{
|
||||
result.emplace_back(std::move(e));
|
||||
e.clear();
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
else if (is_lws(*iter))
|
||||
{
|
||||
++iter;
|
||||
}
|
||||
else
|
||||
{
|
||||
e.append(1, *iter++);
|
||||
}
|
||||
}
|
||||
|
||||
if (!e.empty())
|
||||
{
|
||||
e = trim_right(e);
|
||||
if (!e.empty())
|
||||
result.emplace_back(std::move(e));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <
|
||||
class FwdIt,
|
||||
class Result = std::vector<
|
||||
std::basic_string<typename std::iterator_traits<FwdIt>::value_type>>>
|
||||
Result
|
||||
split_commas(FwdIt first, FwdIt last)
|
||||
{
|
||||
return split(first, last, ',');
|
||||
}
|
||||
|
||||
template <class Result = std::vector<std::string>>
|
||||
Result
|
||||
split_commas(boost::beast::string_view const& s)
|
||||
{
|
||||
return split_commas(s.begin(), s.end());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Iterates through a comma separated list.
|
||||
|
||||
Meets the requirements of ForwardIterator.
|
||||
|
||||
List defined in rfc2616 2.1.
|
||||
|
||||
@note Values returned may contain backslash escapes.
|
||||
*/
|
||||
class list_iterator
|
||||
{
|
||||
using iter_type = boost::string_ref::const_iterator;
|
||||
|
||||
iter_type it_;
|
||||
iter_type end_;
|
||||
boost::string_ref value_;
|
||||
|
||||
public:
|
||||
using value_type = boost::string_ref;
|
||||
using pointer = value_type const*;
|
||||
using reference = value_type const&;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
list_iterator(iter_type begin, iter_type end) : it_(begin), end_(end)
|
||||
{
|
||||
if (it_ != end_)
|
||||
increment();
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(list_iterator const& other) const
|
||||
{
|
||||
return other.it_ == it_ && other.end_ == end_ &&
|
||||
other.value_.size() == value_.size();
|
||||
}
|
||||
|
||||
bool
|
||||
operator!=(list_iterator const& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
reference
|
||||
operator*() const
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
pointer
|
||||
operator->() const
|
||||
{
|
||||
return &*(*this);
|
||||
}
|
||||
|
||||
list_iterator&
|
||||
operator++()
|
||||
{
|
||||
increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
list_iterator
|
||||
operator++(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
++(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
private:
|
||||
template <class = void>
|
||||
void
|
||||
increment();
|
||||
};
|
||||
|
||||
template <class>
|
||||
void
|
||||
list_iterator::increment()
|
||||
{
|
||||
using namespace detail;
|
||||
value_.clear();
|
||||
while (it_ != end_)
|
||||
{
|
||||
if (*it_ == '"')
|
||||
{
|
||||
// quoted-string
|
||||
++it_;
|
||||
if (it_ == end_)
|
||||
return;
|
||||
if (*it_ != '"')
|
||||
{
|
||||
auto start = it_;
|
||||
for (;;)
|
||||
{
|
||||
++it_;
|
||||
if (it_ == end_)
|
||||
{
|
||||
value_ = boost::string_ref(
|
||||
&*start, std::distance(start, it_));
|
||||
return;
|
||||
}
|
||||
if (*it_ == '"')
|
||||
{
|
||||
value_ = boost::string_ref(
|
||||
&*start, std::distance(start, it_));
|
||||
++it_;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
++it_;
|
||||
}
|
||||
else if (*it_ == ',')
|
||||
{
|
||||
it_++;
|
||||
continue;
|
||||
}
|
||||
else if (is_lws(*it_))
|
||||
{
|
||||
++it_;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto start = it_;
|
||||
for (;;)
|
||||
{
|
||||
++it_;
|
||||
if (it_ == end_ || *it_ == ',' || is_lws(*it_))
|
||||
{
|
||||
value_ =
|
||||
boost::string_ref(&*start, std::distance(start, it_));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/** Returns true if two strings are equal.
|
||||
|
||||
A case-insensitive comparison is used.
|
||||
*/
|
||||
inline bool
|
||||
ci_equal(boost::string_ref s1, boost::string_ref s2)
|
||||
{
|
||||
return boost::range::equal(s1, s2, detail::ci_equal_pred{});
|
||||
}
|
||||
|
||||
/** Returns a range representing the list. */
|
||||
inline boost::iterator_range<list_iterator>
|
||||
make_list(boost::string_ref const& field)
|
||||
{
|
||||
return boost::iterator_range<list_iterator>{
|
||||
list_iterator{field.begin(), field.end()},
|
||||
list_iterator{field.end(), field.end()}};
|
||||
}
|
||||
|
||||
/** Returns true if the specified token exists in the list.
|
||||
|
||||
A case-insensitive comparison is used.
|
||||
*/
|
||||
template <class = void>
|
||||
bool
|
||||
token_in_list(boost::string_ref const& value, boost::string_ref const& token)
|
||||
{
|
||||
for (auto const& item : make_list(value))
|
||||
if (ci_equal(item, token))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
template <bool isRequest, class Body, class Fields>
|
||||
bool
|
||||
is_keep_alive(boost::beast::http::message<isRequest, Body, Fields> const& m)
|
||||
{
|
||||
if (m.version() <= 10)
|
||||
return boost::beast::http::token_list{
|
||||
m[boost::beast::http::field::connection]}
|
||||
.exists("keep-alive");
|
||||
return !boost::beast::http::token_list{
|
||||
m[boost::beast::http::field::connection]}
|
||||
.exists("close");
|
||||
}
|
||||
|
||||
} // namespace rfc2616
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
160
include/xrpl/beast/test/fail_counter.h
Normal file
160
include/xrpl/beast/test/fail_counter.h
Normal file
@@ -0,0 +1,160 @@
|
||||
//
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_TEST_FAIL_COUNTER_HPP
|
||||
#define BEAST_TEST_FAIL_COUNTER_HPP
|
||||
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <beast/core/error.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace test {
|
||||
|
||||
enum class error { fail_error = 1 };
|
||||
|
||||
namespace detail {
|
||||
|
||||
class fail_error_category : public boost::system::error_category
|
||||
{
|
||||
public:
|
||||
const char*
|
||||
name() const noexcept override
|
||||
{
|
||||
return "test";
|
||||
}
|
||||
|
||||
std::string
|
||||
message(int ev) const override
|
||||
{
|
||||
switch (static_cast<error>(ev))
|
||||
{
|
||||
default:
|
||||
case error::fail_error:
|
||||
return "test error";
|
||||
}
|
||||
}
|
||||
|
||||
boost::system::error_condition
|
||||
default_error_condition(int ev) const noexcept override
|
||||
{
|
||||
return boost::system::error_condition{ev, *this};
|
||||
}
|
||||
|
||||
bool
|
||||
equivalent(int ev, boost::system::error_condition const& condition)
|
||||
const noexcept override
|
||||
{
|
||||
return condition.value() == ev && &condition.category() == this;
|
||||
}
|
||||
|
||||
bool
|
||||
equivalent(error_code const& error, int ev) const noexcept override
|
||||
{
|
||||
return error.value() == ev && &error.category() == this;
|
||||
}
|
||||
};
|
||||
|
||||
inline boost::system::error_category const&
|
||||
get_error_category()
|
||||
{
|
||||
static fail_error_category const cat{};
|
||||
return cat;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
inline error_code
|
||||
make_error_code(error ev)
|
||||
{
|
||||
return error_code{
|
||||
static_cast<std::underlying_type<error>::type>(ev),
|
||||
detail::get_error_category()};
|
||||
}
|
||||
|
||||
/** An error code with an error set on default construction
|
||||
|
||||
Default constructed versions of this object will have
|
||||
an error code set right away. This helps tests find code
|
||||
which forgets to clear the error code on success.
|
||||
*/
|
||||
struct fail_error_code : error_code
|
||||
{
|
||||
fail_error_code() : error_code(make_error_code(error::fail_error))
|
||||
{
|
||||
}
|
||||
|
||||
template <class Arg0, class... ArgN>
|
||||
fail_error_code(Arg0&& arg0, ArgN&&... argn)
|
||||
: error_code(arg0, std::forward<ArgN>(argn)...)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/** A countdown to simulated failure.
|
||||
|
||||
On the Nth operation, the class will fail with the specified
|
||||
error code, or the default error code of @ref error::fail_error.
|
||||
*/
|
||||
class fail_counter
|
||||
{
|
||||
std::size_t n_;
|
||||
error_code ec_;
|
||||
|
||||
public:
|
||||
fail_counter(fail_counter&&) = default;
|
||||
|
||||
/** Construct a counter.
|
||||
|
||||
@param The 0-based index of the operation to fail on or after.
|
||||
*/
|
||||
explicit fail_counter(
|
||||
std::size_t n,
|
||||
error_code ev = make_error_code(error::fail_error))
|
||||
: n_(n), ec_(ev)
|
||||
{
|
||||
}
|
||||
|
||||
/// Throw an exception on the Nth failure
|
||||
void
|
||||
fail()
|
||||
{
|
||||
if (n_ > 0)
|
||||
--n_;
|
||||
if (!n_)
|
||||
BOOST_THROW_EXCEPTION(system_error{ec_});
|
||||
}
|
||||
|
||||
/// Set an error code on the Nth failure
|
||||
bool
|
||||
fail(error_code& ec)
|
||||
{
|
||||
if (n_ > 0)
|
||||
--n_;
|
||||
if (!n_)
|
||||
{
|
||||
ec = ec_;
|
||||
return true;
|
||||
}
|
||||
ec.assign(0, ec.category());
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
} // namespace beast
|
||||
|
||||
namespace boost {
|
||||
namespace system {
|
||||
template <>
|
||||
struct is_error_code_enum<beast::test::error>
|
||||
{
|
||||
static bool const value = true;
|
||||
};
|
||||
} // namespace system
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
182
include/xrpl/beast/test/fail_stream.h
Normal file
182
include/xrpl/beast/test/fail_stream.h
Normal file
@@ -0,0 +1,182 @@
|
||||
//
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_TEST_FAIL_STREAM_HPP
|
||||
#define BEAST_TEST_FAIL_STREAM_HPP
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
#include <beast/core/async_result.hpp>
|
||||
#include <beast/core/bind_handler.hpp>
|
||||
#include <beast/core/detail/type_traits.hpp>
|
||||
#include <beast/core/error.hpp>
|
||||
#include <beast/test/fail_counter.hpp>
|
||||
#include <beast/websocket/teardown.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace test {
|
||||
|
||||
/** A stream wrapper that fails.
|
||||
|
||||
On the Nth operation, the stream will fail with the specified
|
||||
error code, or the default error code of invalid_argument.
|
||||
*/
|
||||
template <class NextLayer>
|
||||
class fail_stream
|
||||
{
|
||||
boost::optional<fail_counter> fc_;
|
||||
fail_counter* pfc_;
|
||||
NextLayer next_layer_;
|
||||
|
||||
public:
|
||||
using next_layer_type = typename std::remove_reference<NextLayer>::type;
|
||||
|
||||
using lowest_layer_type = typename get_lowest_layer<next_layer_type>::type;
|
||||
|
||||
fail_stream(fail_stream&&) = delete;
|
||||
fail_stream(fail_stream const&) = delete;
|
||||
fail_stream&
|
||||
operator=(fail_stream&&) = delete;
|
||||
fail_stream&
|
||||
operator=(fail_stream const&) = delete;
|
||||
|
||||
template <class... Args>
|
||||
explicit fail_stream(std::size_t n, Args&&... args)
|
||||
: fc_(n), pfc_(&*fc_), next_layer_(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
explicit fail_stream(fail_counter& fc, Args&&... args)
|
||||
: pfc_(&fc), next_layer_(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
next_layer_type&
|
||||
next_layer()
|
||||
{
|
||||
return next_layer_;
|
||||
}
|
||||
|
||||
lowest_layer_type&
|
||||
lowest_layer()
|
||||
{
|
||||
return next_layer_.lowest_layer();
|
||||
}
|
||||
|
||||
lowest_layer_type const&
|
||||
lowest_layer() const
|
||||
{
|
||||
return next_layer_.lowest_layer();
|
||||
}
|
||||
|
||||
boost::asio::io_service&
|
||||
get_io_service()
|
||||
{
|
||||
return next_layer_.get_io_service();
|
||||
}
|
||||
|
||||
template <class MutableBufferSequence>
|
||||
std::size_t
|
||||
read_some(MutableBufferSequence const& buffers)
|
||||
{
|
||||
pfc_->fail();
|
||||
return next_layer_.read_some(buffers);
|
||||
}
|
||||
|
||||
template <class MutableBufferSequence>
|
||||
std::size_t
|
||||
read_some(MutableBufferSequence const& buffers, error_code& ec)
|
||||
{
|
||||
if (pfc_->fail(ec))
|
||||
return 0;
|
||||
return next_layer_.read_some(buffers, ec);
|
||||
}
|
||||
|
||||
template <class MutableBufferSequence, class ReadHandler>
|
||||
async_return_type<ReadHandler, void(error_code, std::size_t)>
|
||||
async_read_some(MutableBufferSequence const& buffers, ReadHandler&& handler)
|
||||
{
|
||||
error_code ec;
|
||||
if (pfc_->fail(ec))
|
||||
{
|
||||
async_completion<ReadHandler, void(error_code, std::size_t)> init{
|
||||
handler};
|
||||
next_layer_.get_io_service().post(
|
||||
bind_handler(init.completion_handler, ec, 0));
|
||||
return init.result.get();
|
||||
}
|
||||
return next_layer_.async_read_some(
|
||||
buffers, std::forward<ReadHandler>(handler));
|
||||
}
|
||||
|
||||
template <class ConstBufferSequence>
|
||||
std::size_t
|
||||
write_some(ConstBufferSequence const& buffers)
|
||||
{
|
||||
pfc_->fail();
|
||||
return next_layer_.write_some(buffers);
|
||||
}
|
||||
|
||||
template <class ConstBufferSequence>
|
||||
std::size_t
|
||||
write_some(ConstBufferSequence const& buffers, error_code& ec)
|
||||
{
|
||||
if (pfc_->fail(ec))
|
||||
return 0;
|
||||
return next_layer_.write_some(buffers, ec);
|
||||
}
|
||||
|
||||
template <class ConstBufferSequence, class WriteHandler>
|
||||
async_return_type<WriteHandler, void(error_code, std::size_t)>
|
||||
async_write_some(ConstBufferSequence const& buffers, WriteHandler&& handler)
|
||||
{
|
||||
error_code ec;
|
||||
if (pfc_->fail(ec))
|
||||
{
|
||||
async_completion<WriteHandler, void(error_code, std::size_t)> init{
|
||||
handler};
|
||||
next_layer_.get_io_service().post(
|
||||
bind_handler(init.completion_handler, ec, 0));
|
||||
return init.result.get();
|
||||
}
|
||||
return next_layer_.async_write_some(
|
||||
buffers, std::forward<WriteHandler>(handler));
|
||||
}
|
||||
|
||||
friend void
|
||||
teardown(
|
||||
websocket::teardown_tag,
|
||||
fail_stream<NextLayer>& stream,
|
||||
boost::system::error_code& ec)
|
||||
{
|
||||
if (stream.pfc_->fail(ec))
|
||||
return;
|
||||
beast::websocket_helpers::call_teardown(stream.next_layer(), ec);
|
||||
}
|
||||
|
||||
template <class TeardownHandler>
|
||||
friend void
|
||||
async_teardown(
|
||||
websocket::teardown_tag,
|
||||
fail_stream<NextLayer>& stream,
|
||||
TeardownHandler&& handler)
|
||||
{
|
||||
error_code ec;
|
||||
if (stream.pfc_->fail(ec))
|
||||
{
|
||||
stream.get_io_service().post(bind_handler(std::move(handler), ec));
|
||||
return;
|
||||
}
|
||||
beast::websocket_helpers::call_async_teardown(
|
||||
stream.next_layer(), std::forward<TeardownHandler>(handler));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
482
include/xrpl/beast/test/pipe_stream.h
Normal file
482
include/xrpl/beast/test/pipe_stream.h
Normal file
@@ -0,0 +1,482 @@
|
||||
//
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_TEST_PIPE_STREAM_HPP
|
||||
#define BEAST_TEST_PIPE_STREAM_HPP
|
||||
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <beast/core/async_result.hpp>
|
||||
#include <beast/core/bind_handler.hpp>
|
||||
#include <beast/core/flat_buffer.hpp>
|
||||
#include <beast/core/string.hpp>
|
||||
#include <beast/core/type_traits.hpp>
|
||||
#include <beast/test/fail_counter.hpp>
|
||||
#include <beast/websocket/teardown.hpp>
|
||||
#include <condition_variable>
|
||||
#include <limits>
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace test {
|
||||
|
||||
/** A bidirectional in-memory communication channel
|
||||
|
||||
An instance of this class provides a client and server
|
||||
endpoint that are automatically connected to each other
|
||||
similarly to a connected socket.
|
||||
|
||||
Test pipes are used to facilitate writing unit tests
|
||||
where the behavior of the transport is tightly controlled
|
||||
to help illuminate all code paths (for code coverage)
|
||||
*/
|
||||
class pipe
|
||||
{
|
||||
public:
|
||||
using buffer_type = flat_buffer;
|
||||
|
||||
private:
|
||||
struct read_op
|
||||
{
|
||||
virtual ~read_op() = default;
|
||||
virtual void
|
||||
operator()() = 0;
|
||||
};
|
||||
|
||||
struct state
|
||||
{
|
||||
std::mutex m;
|
||||
buffer_type b;
|
||||
std::condition_variable cv;
|
||||
std::unique_ptr<read_op> op;
|
||||
bool eof = false;
|
||||
};
|
||||
|
||||
state s_[2];
|
||||
|
||||
public:
|
||||
/** Represents an endpoint.
|
||||
|
||||
Each pipe has a client stream and a server stream.
|
||||
*/
|
||||
class stream
|
||||
{
|
||||
friend class pipe;
|
||||
|
||||
template <class Handler, class Buffers>
|
||||
class read_op_impl;
|
||||
|
||||
state& in_;
|
||||
state& out_;
|
||||
boost::asio::io_service& ios_;
|
||||
fail_counter* fc_ = nullptr;
|
||||
std::size_t read_max_ = (std::numeric_limits<std::size_t>::max)();
|
||||
std::size_t write_max_ = (std::numeric_limits<std::size_t>::max)();
|
||||
|
||||
stream(state& in, state& out, boost::asio::io_service& ios)
|
||||
: in_(in), out_(out), ios_(ios), buffer(in_.b)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
using buffer_type = pipe::buffer_type;
|
||||
|
||||
/// Direct access to the underlying buffer
|
||||
buffer_type& buffer;
|
||||
|
||||
/// Counts the number of read calls
|
||||
std::size_t nread = 0;
|
||||
|
||||
/// Counts the number of write calls
|
||||
std::size_t nwrite = 0;
|
||||
|
||||
~stream() = default;
|
||||
stream(stream&&) = default;
|
||||
|
||||
/// Set the fail counter on the object
|
||||
void
|
||||
fail(fail_counter& fc)
|
||||
{
|
||||
fc_ = &fc;
|
||||
}
|
||||
|
||||
/// Return the `io_service` associated with the object
|
||||
boost::asio::io_service&
|
||||
get_io_service()
|
||||
{
|
||||
return ios_;
|
||||
}
|
||||
|
||||
/// Set the maximum number of bytes returned by read_some
|
||||
void
|
||||
read_size(std::size_t n)
|
||||
{
|
||||
read_max_ = n;
|
||||
}
|
||||
|
||||
/// Set the maximum number of bytes returned by write_some
|
||||
void
|
||||
write_size(std::size_t n)
|
||||
{
|
||||
write_max_ = n;
|
||||
}
|
||||
|
||||
/// Returns a string representing the pending input data
|
||||
string_view
|
||||
str() const
|
||||
{
|
||||
using boost::asio::buffer_cast;
|
||||
using boost::asio::buffer_size;
|
||||
return {
|
||||
buffer_cast<char const*>(*in_.b.data().begin()),
|
||||
buffer_size(*in_.b.data().begin())};
|
||||
}
|
||||
|
||||
/// Clear the buffer holding the input data
|
||||
void
|
||||
clear()
|
||||
{
|
||||
in_.b.consume((std::numeric_limits<std::size_t>::max)());
|
||||
}
|
||||
|
||||
/** Close the stream.
|
||||
|
||||
The other end of the pipe will see
|
||||
`boost::asio::error::eof` on read.
|
||||
*/
|
||||
template <class = void>
|
||||
void
|
||||
close();
|
||||
|
||||
template <class MutableBufferSequence>
|
||||
std::size_t
|
||||
read_some(MutableBufferSequence const& buffers);
|
||||
|
||||
template <class MutableBufferSequence>
|
||||
std::size_t
|
||||
read_some(MutableBufferSequence const& buffers, error_code& ec);
|
||||
|
||||
template <class MutableBufferSequence, class ReadHandler>
|
||||
async_return_type<ReadHandler, void(error_code, std::size_t)>
|
||||
async_read_some(
|
||||
MutableBufferSequence const& buffers,
|
||||
ReadHandler&& handler);
|
||||
|
||||
template <class ConstBufferSequence>
|
||||
std::size_t
|
||||
write_some(ConstBufferSequence const& buffers);
|
||||
|
||||
template <class ConstBufferSequence>
|
||||
std::size_t
|
||||
write_some(ConstBufferSequence const& buffers, error_code&);
|
||||
|
||||
template <class ConstBufferSequence, class WriteHandler>
|
||||
async_return_type<WriteHandler, void(error_code, std::size_t)>
|
||||
async_write_some(
|
||||
ConstBufferSequence const& buffers,
|
||||
WriteHandler&& handler);
|
||||
|
||||
friend void
|
||||
teardown(
|
||||
websocket::teardown_tag,
|
||||
stream&,
|
||||
boost::system::error_code& ec)
|
||||
{
|
||||
ec.assign(0, ec.category());
|
||||
}
|
||||
|
||||
template <class TeardownHandler>
|
||||
friend void
|
||||
async_teardown(
|
||||
websocket::teardown_tag,
|
||||
stream& s,
|
||||
TeardownHandler&& handler)
|
||||
{
|
||||
s.get_io_service().post(
|
||||
bind_handler(std::move(handler), error_code{}));
|
||||
}
|
||||
};
|
||||
|
||||
/** Constructor.
|
||||
|
||||
The client and server endpoints will use the same `io_service`.
|
||||
*/
|
||||
explicit pipe(boost::asio::io_service& ios)
|
||||
: client(s_[0], s_[1], ios), server(s_[1], s_[0], ios)
|
||||
{
|
||||
}
|
||||
|
||||
/** Constructor.
|
||||
|
||||
The client and server endpoints will different `io_service` objects.
|
||||
*/
|
||||
explicit pipe(boost::asio::io_service& ios1, boost::asio::io_service& ios2)
|
||||
: client(s_[0], s_[1], ios1), server(s_[1], s_[0], ios2)
|
||||
{
|
||||
}
|
||||
|
||||
/// Represents the client endpoint
|
||||
stream client;
|
||||
|
||||
/// Represents the server endpoint
|
||||
stream server;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class Handler, class Buffers>
|
||||
class pipe::stream::read_op_impl : public pipe::read_op
|
||||
{
|
||||
stream& s_;
|
||||
Buffers b_;
|
||||
Handler h_;
|
||||
|
||||
public:
|
||||
read_op_impl(stream& s, Buffers const& b, Handler&& h)
|
||||
: s_(s), b_(b), h_(std::move(h))
|
||||
{
|
||||
}
|
||||
|
||||
read_op_impl(stream& s, Buffers const& b, Handler const& h)
|
||||
: s_(s), b_(b), h_(h)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()() override;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class Handler, class Buffers>
|
||||
void
|
||||
pipe::stream::read_op_impl<Handler, Buffers>::operator()()
|
||||
{
|
||||
using boost::asio::buffer_copy;
|
||||
using boost::asio::buffer_size;
|
||||
s_.ios_.post([&]() {
|
||||
BOOST_ASSERT(s_.in_.op);
|
||||
std::unique_lock<std::mutex> lock{s_.in_.m};
|
||||
if (s_.in_.b.size() > 0)
|
||||
{
|
||||
auto const bytes_transferred =
|
||||
buffer_copy(b_, s_.in_.b.data(), s_.read_max_);
|
||||
s_.in_.b.consume(bytes_transferred);
|
||||
auto& s = s_;
|
||||
Handler h{std::move(h_)};
|
||||
lock.unlock();
|
||||
s.in_.op.reset(nullptr);
|
||||
++s.nread;
|
||||
s.ios_.post(
|
||||
bind_handler(std::move(h), error_code{}, bytes_transferred));
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(s_.in_.eof);
|
||||
auto& s = s_;
|
||||
Handler h{std::move(h_)};
|
||||
lock.unlock();
|
||||
s.in_.op.reset(nullptr);
|
||||
++s.nread;
|
||||
s.ios_.post(bind_handler(std::move(h), boost::asio::error::eof, 0));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class>
|
||||
void
|
||||
pipe::stream::close()
|
||||
{
|
||||
std::lock_guard lock{out_.m};
|
||||
out_.eof = true;
|
||||
if (out_.op)
|
||||
out_.op.get()->operator()();
|
||||
else
|
||||
out_.cv.notify_all();
|
||||
}
|
||||
|
||||
template <class MutableBufferSequence>
|
||||
std::size_t
|
||||
pipe::stream::read_some(MutableBufferSequence const& buffers)
|
||||
{
|
||||
static_assert(
|
||||
is_mutable_buffer_sequence<MutableBufferSequence>::value,
|
||||
"MutableBufferSequence requirements not met");
|
||||
error_code ec;
|
||||
auto const n = read_some(buffers, ec);
|
||||
if (ec)
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
return n;
|
||||
}
|
||||
|
||||
template <class MutableBufferSequence>
|
||||
std::size_t
|
||||
pipe::stream::read_some(MutableBufferSequence const& buffers, error_code& ec)
|
||||
{
|
||||
static_assert(
|
||||
is_mutable_buffer_sequence<MutableBufferSequence>::value,
|
||||
"MutableBufferSequence requirements not met");
|
||||
using boost::asio::buffer_copy;
|
||||
using boost::asio::buffer_size;
|
||||
BOOST_ASSERT(!in_.op);
|
||||
BOOST_ASSERT(buffer_size(buffers) > 0);
|
||||
if (fc_ && fc_->fail(ec))
|
||||
return 0;
|
||||
std::unique_lock<std::mutex> lock{in_.m};
|
||||
in_.cv.wait(lock, [&]() { return in_.b.size() > 0 || in_.eof; });
|
||||
std::size_t bytes_transferred;
|
||||
if (in_.b.size() > 0)
|
||||
{
|
||||
ec.assign(0, ec.category());
|
||||
bytes_transferred = buffer_copy(buffers, in_.b.data(), read_max_);
|
||||
in_.b.consume(bytes_transferred);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(in_.eof);
|
||||
bytes_transferred = 0;
|
||||
ec = boost::asio::error::eof;
|
||||
}
|
||||
++nread;
|
||||
return bytes_transferred;
|
||||
}
|
||||
|
||||
template <class MutableBufferSequence, class ReadHandler>
|
||||
async_return_type<ReadHandler, void(error_code, std::size_t)>
|
||||
pipe::stream::async_read_some(
|
||||
MutableBufferSequence const& buffers,
|
||||
ReadHandler&& handler)
|
||||
{
|
||||
static_assert(
|
||||
is_mutable_buffer_sequence<MutableBufferSequence>::value,
|
||||
"MutableBufferSequence requirements not met");
|
||||
using boost::asio::buffer_copy;
|
||||
using boost::asio::buffer_size;
|
||||
BOOST_ASSERT(!in_.op);
|
||||
BOOST_ASSERT(buffer_size(buffers) > 0);
|
||||
async_completion<ReadHandler, void(error_code, std::size_t)> init{handler};
|
||||
if (fc_)
|
||||
{
|
||||
error_code ec;
|
||||
if (fc_->fail(ec))
|
||||
return ios_.post(bind_handler(init.completion_handler, ec, 0));
|
||||
}
|
||||
{
|
||||
std::unique_lock<std::mutex> lock{in_.m};
|
||||
if (in_.eof)
|
||||
{
|
||||
lock.unlock();
|
||||
++nread;
|
||||
ios_.post(bind_handler(
|
||||
init.completion_handler, boost::asio::error::eof, 0));
|
||||
}
|
||||
else if (buffer_size(buffers) == 0 || buffer_size(in_.b.data()) > 0)
|
||||
{
|
||||
auto const bytes_transferred =
|
||||
buffer_copy(buffers, in_.b.data(), read_max_);
|
||||
in_.b.consume(bytes_transferred);
|
||||
lock.unlock();
|
||||
++nread;
|
||||
ios_.post(bind_handler(
|
||||
init.completion_handler, error_code{}, bytes_transferred));
|
||||
}
|
||||
else
|
||||
{
|
||||
in_.op.reset(
|
||||
new read_op_impl<
|
||||
handler_type<ReadHandler, void(error_code, std::size_t)>,
|
||||
MutableBufferSequence>{
|
||||
*this, buffers, init.completion_handler});
|
||||
}
|
||||
}
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
template <class ConstBufferSequence>
|
||||
std::size_t
|
||||
pipe::stream::write_some(ConstBufferSequence const& buffers)
|
||||
{
|
||||
static_assert(
|
||||
is_const_buffer_sequence<ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
BOOST_ASSERT(!out_.eof);
|
||||
error_code ec;
|
||||
auto const bytes_transferred = write_some(buffers, ec);
|
||||
if (ec)
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
return bytes_transferred;
|
||||
}
|
||||
|
||||
template <class ConstBufferSequence>
|
||||
std::size_t
|
||||
pipe::stream::write_some(ConstBufferSequence const& buffers, error_code& ec)
|
||||
{
|
||||
static_assert(
|
||||
is_const_buffer_sequence<ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
using boost::asio::buffer_copy;
|
||||
using boost::asio::buffer_size;
|
||||
BOOST_ASSERT(!out_.eof);
|
||||
if (fc_ && fc_->fail(ec))
|
||||
return 0;
|
||||
auto const n = (std::min)(buffer_size(buffers), write_max_);
|
||||
std::unique_lock<std::mutex> lock{out_.m};
|
||||
auto const bytes_transferred = buffer_copy(out_.b.prepare(n), buffers);
|
||||
out_.b.commit(bytes_transferred);
|
||||
lock.unlock();
|
||||
if (out_.op)
|
||||
out_.op.get()->operator()();
|
||||
else
|
||||
out_.cv.notify_all();
|
||||
++nwrite;
|
||||
ec.assign(0, ec.category());
|
||||
return bytes_transferred;
|
||||
}
|
||||
|
||||
template <class ConstBufferSequence, class WriteHandler>
|
||||
async_return_type<WriteHandler, void(error_code, std::size_t)>
|
||||
pipe::stream::async_write_some(
|
||||
ConstBufferSequence const& buffers,
|
||||
WriteHandler&& handler)
|
||||
{
|
||||
static_assert(
|
||||
is_const_buffer_sequence<ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
using boost::asio::buffer_copy;
|
||||
using boost::asio::buffer_size;
|
||||
BOOST_ASSERT(!out_.eof);
|
||||
async_completion<WriteHandler, void(error_code, std::size_t)> init{handler};
|
||||
if (fc_)
|
||||
{
|
||||
error_code ec;
|
||||
if (fc_->fail(ec))
|
||||
return ios_.post(bind_handler(init.completion_handler, ec, 0));
|
||||
}
|
||||
auto const n = (std::min)(buffer_size(buffers), write_max_);
|
||||
std::unique_lock<std::mutex> lock{out_.m};
|
||||
auto const bytes_transferred = buffer_copy(out_.b.prepare(n), buffers);
|
||||
out_.b.commit(bytes_transferred);
|
||||
lock.unlock();
|
||||
if (out_.op)
|
||||
out_.op.get()->operator()();
|
||||
else
|
||||
out_.cv.notify_all();
|
||||
++nwrite;
|
||||
ios_.post(
|
||||
bind_handler(init.completion_handler, error_code{}, bytes_transferred));
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace beast
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user