commit
b540bf5f72
@ -1,668 +0,0 @@
|
|||||||
#ifndef CHRONO_IO_H
|
|
||||||
#define CHRONO_IO_H
|
|
||||||
|
|
||||||
// The MIT License (MIT)
|
|
||||||
//
|
|
||||||
// Copyright (c) 2016 Howard Hinnant
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
// Our apologies. When the previous paragraph was written, lowercase had not yet
|
|
||||||
// been invented (that woud involve another several millennia of evolution).
|
|
||||||
// We did not mean to shout.
|
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <iosfwd>
|
|
||||||
#include <ratio>
|
|
||||||
#include <string>
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
namespace date
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
|
|
||||||
#if __cplusplus >= 201402
|
|
||||||
|
|
||||||
template <class CharT, std::size_t N>
|
|
||||||
class string_literal
|
|
||||||
{
|
|
||||||
CharT p_[N];
|
|
||||||
|
|
||||||
public:
|
|
||||||
using const_iterator = const CharT*;
|
|
||||||
|
|
||||||
string_literal(string_literal const&) = default;
|
|
||||||
string_literal& operator=(string_literal const&) = delete;
|
|
||||||
|
|
||||||
template <std::size_t N1 = 2,
|
|
||||||
class = std::enable_if_t<N1 == N>>
|
|
||||||
constexpr string_literal(CharT c) noexcept
|
|
||||||
: p_{c}
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr string_literal(const CharT(&a)[N]) noexcept
|
|
||||||
: p_{}
|
|
||||||
{
|
|
||||||
for (std::size_t i = 0; i < N; ++i)
|
|
||||||
p_[i] = a[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class U = CharT, class = std::enable_if_t<1 < sizeof(U)>>
|
|
||||||
constexpr string_literal(const char(&a)[N]) noexcept
|
|
||||||
: p_{}
|
|
||||||
{
|
|
||||||
for (std::size_t i = 0; i < N; ++i)
|
|
||||||
p_[i] = a[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT2, class = std::enable_if_t<!std::is_same<CharT2, CharT>{}>>
|
|
||||||
constexpr string_literal(string_literal<CharT2, N> const& a) noexcept
|
|
||||||
: p_{}
|
|
||||||
{
|
|
||||||
for (std::size_t i = 0; i < N; ++i)
|
|
||||||
p_[i] = a[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
template <std::size_t N1, std::size_t N2,
|
|
||||||
class = std::enable_if_t<N1 + N2 - 1 == N>>
|
|
||||||
constexpr string_literal(const string_literal<CharT, N1>& x,
|
|
||||||
const string_literal<CharT, N2>& y) noexcept
|
|
||||||
: p_{}
|
|
||||||
{
|
|
||||||
std::size_t i = 0;
|
|
||||||
for (; i < N1-1; ++i)
|
|
||||||
p_[i] = x[i];
|
|
||||||
for (std::size_t j = 0; j < N2; ++j, ++i)
|
|
||||||
p_[i] = y[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr const CharT* data() const noexcept {return p_;}
|
|
||||||
constexpr std::size_t size() const noexcept {return N-1;}
|
|
||||||
|
|
||||||
constexpr const_iterator begin() const noexcept {return p_;}
|
|
||||||
constexpr const_iterator end() const noexcept {return p_ + N-1;}
|
|
||||||
|
|
||||||
constexpr CharT const& operator[](std::size_t n) const noexcept
|
|
||||||
{
|
|
||||||
return p_[n];
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Traits>
|
|
||||||
friend
|
|
||||||
std::basic_ostream<CharT, Traits>&
|
|
||||||
operator<<(std::basic_ostream<CharT, Traits>& os, const string_literal& s)
|
|
||||||
{
|
|
||||||
return os << s.p_;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class CharT1, class CharT2, std::size_t N1, std::size_t N2>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
string_literal<std::conditional_t<sizeof(CharT2) <= sizeof(CharT1), CharT1, CharT2>,
|
|
||||||
N1 + N2 - 1>
|
|
||||||
operator+(const string_literal<CharT1, N1>& x, const string_literal<CharT2, N2>& y) noexcept
|
|
||||||
{
|
|
||||||
using CharT = std::conditional_t<sizeof(CharT2) <= sizeof(CharT1), CharT1, CharT2>;
|
|
||||||
return string_literal<CharT, N1 + N2 - 1>{string_literal<CharT, N1>{x},
|
|
||||||
string_literal<CharT, N2>{y}};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT, std::size_t N>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
string_literal<CharT, N>
|
|
||||||
msl(const CharT(&a)[N]) noexcept
|
|
||||||
{
|
|
||||||
return string_literal<CharT, N>{a};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT,
|
|
||||||
class = std::enable_if_t<std::is_same<CharT, char>{} ||
|
|
||||||
std::is_same<CharT, wchar_t>{} ||
|
|
||||||
std::is_same<CharT, char16_t>{} ||
|
|
||||||
std::is_same<CharT, char32_t>{}>>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
string_literal<CharT, 2>
|
|
||||||
msl(CharT c) noexcept
|
|
||||||
{
|
|
||||||
return string_literal<CharT, 2>{c};
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr
|
|
||||||
std::size_t
|
|
||||||
to_string_len(std::intmax_t i)
|
|
||||||
{
|
|
||||||
std::size_t r = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
i /= 10;
|
|
||||||
++r;
|
|
||||||
} while (i > 0);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <std::intmax_t N>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
std::enable_if_t
|
|
||||||
<
|
|
||||||
N < 10,
|
|
||||||
string_literal<char, to_string_len(N)+1>
|
|
||||||
>
|
|
||||||
msl() noexcept
|
|
||||||
{
|
|
||||||
return msl(char(N % 10 + '0'));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <std::intmax_t N>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
std::enable_if_t
|
|
||||||
<
|
|
||||||
10 <= N,
|
|
||||||
string_literal<char, to_string_len(N)+1>
|
|
||||||
>
|
|
||||||
msl() noexcept
|
|
||||||
{
|
|
||||||
return msl<N/10>() + msl(char(N % 10 + '0'));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT, std::intmax_t N, std::intmax_t D>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
std::enable_if_t
|
|
||||||
<
|
|
||||||
std::ratio<N, D>::type::den != 1,
|
|
||||||
string_literal<CharT, to_string_len(std::ratio<N, D>::type::num) +
|
|
||||||
to_string_len(std::ratio<N, D>::type::den) + 4>
|
|
||||||
>
|
|
||||||
msl(std::ratio<N, D>) noexcept
|
|
||||||
{
|
|
||||||
using R = typename std::ratio<N, D>::type;
|
|
||||||
return msl(CharT{'['}) + msl<R::num>() + msl(CharT{'/'}) +
|
|
||||||
msl<R::den>() + msl(CharT{']'});
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT, std::intmax_t N, std::intmax_t D>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
std::enable_if_t
|
|
||||||
<
|
|
||||||
std::ratio<N, D>::type::den == 1,
|
|
||||||
string_literal<CharT, to_string_len(std::ratio<N, D>::type::num) + 3>
|
|
||||||
>
|
|
||||||
msl(std::ratio<N, D>) noexcept
|
|
||||||
{
|
|
||||||
using R = typename std::ratio<N, D>::type;
|
|
||||||
return msl(CharT{'['}) + msl<R::num>() + msl(CharT{']'});
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
auto
|
|
||||||
msl(std::atto) noexcept
|
|
||||||
{
|
|
||||||
return msl(CharT{'a'});
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
auto
|
|
||||||
msl(std::femto) noexcept
|
|
||||||
{
|
|
||||||
return msl(CharT{'f'});
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
auto
|
|
||||||
msl(std::pico) noexcept
|
|
||||||
{
|
|
||||||
return msl(CharT{'p'});
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
auto
|
|
||||||
msl(std::nano) noexcept
|
|
||||||
{
|
|
||||||
return msl(CharT{'n'});
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
std::enable_if_t
|
|
||||||
<
|
|
||||||
std::is_same<CharT, char>{},
|
|
||||||
string_literal<char, 3>
|
|
||||||
>
|
|
||||||
msl(std::micro) noexcept
|
|
||||||
{
|
|
||||||
return string_literal<char, 3>{"\xC2\xB5"};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
std::enable_if_t
|
|
||||||
<
|
|
||||||
!std::is_same<CharT, char>{},
|
|
||||||
string_literal<CharT, 2>
|
|
||||||
>
|
|
||||||
msl(std::micro) noexcept
|
|
||||||
{
|
|
||||||
return string_literal<CharT, 2>{CharT{static_cast<unsigned char>('\xB5')}};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
auto
|
|
||||||
msl(std::milli) noexcept
|
|
||||||
{
|
|
||||||
return msl(CharT{'m'});
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
auto
|
|
||||||
msl(std::centi) noexcept
|
|
||||||
{
|
|
||||||
return msl(CharT{'c'});
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
auto
|
|
||||||
msl(std::deci) noexcept
|
|
||||||
{
|
|
||||||
return msl(CharT{'d'});
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
auto
|
|
||||||
msl(std::deca) noexcept
|
|
||||||
{
|
|
||||||
return string_literal<CharT, 3>{"da"};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
auto
|
|
||||||
msl(std::hecto) noexcept
|
|
||||||
{
|
|
||||||
return msl(CharT{'h'});
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
auto
|
|
||||||
msl(std::kilo) noexcept
|
|
||||||
{
|
|
||||||
return msl(CharT{'k'});
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
auto
|
|
||||||
msl(std::mega) noexcept
|
|
||||||
{
|
|
||||||
return msl(CharT{'M'});
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
auto
|
|
||||||
msl(std::giga) noexcept
|
|
||||||
{
|
|
||||||
return msl(CharT{'G'});
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
auto
|
|
||||||
msl(std::tera) noexcept
|
|
||||||
{
|
|
||||||
return msl(CharT{'T'});
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
auto
|
|
||||||
msl(std::peta) noexcept
|
|
||||||
{
|
|
||||||
return msl(CharT{'P'});
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
auto
|
|
||||||
msl(std::exa) noexcept
|
|
||||||
{
|
|
||||||
return msl(CharT{'E'});
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT, class Period>
|
|
||||||
constexpr
|
|
||||||
auto
|
|
||||||
get_units(Period p)
|
|
||||||
{
|
|
||||||
return msl<CharT>(p) + string_literal<CharT, 2>{"s"};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
auto
|
|
||||||
get_units(std::ratio<1>)
|
|
||||||
{
|
|
||||||
return string_literal<CharT, 2>{"s"};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
auto
|
|
||||||
get_units(std::ratio<60>)
|
|
||||||
{
|
|
||||||
return string_literal<CharT, 4>{"min"};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
auto
|
|
||||||
get_units(std::ratio<3600>)
|
|
||||||
{
|
|
||||||
return string_literal<CharT, 2>{"h"};
|
|
||||||
}
|
|
||||||
|
|
||||||
#else // __cplusplus < 201402
|
|
||||||
|
|
||||||
inline
|
|
||||||
std::string
|
|
||||||
to_string(std::uint64_t x)
|
|
||||||
{
|
|
||||||
return std::to_string(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
std::basic_string<CharT>
|
|
||||||
to_string(std::uint64_t x)
|
|
||||||
{
|
|
||||||
auto y = std::to_string(x);
|
|
||||||
return std::basic_string<CharT>(y.begin(), y.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT, std::intmax_t N, std::intmax_t D>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
typename std::enable_if
|
|
||||||
<
|
|
||||||
std::ratio<N, D>::type::den != 1,
|
|
||||||
std::basic_string<CharT>
|
|
||||||
>::type
|
|
||||||
msl(std::ratio<N, D>) noexcept
|
|
||||||
{
|
|
||||||
using R = typename std::ratio<N, D>::type;
|
|
||||||
return std::basic_string<CharT>(1, '[') + to_string<CharT>(R::num) + CharT{'/'} +
|
|
||||||
to_string<CharT>(R::den) + CharT{']'};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT, std::intmax_t N, std::intmax_t D>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
typename std::enable_if
|
|
||||||
<
|
|
||||||
std::ratio<N, D>::type::den == 1,
|
|
||||||
std::basic_string<CharT>
|
|
||||||
>::type
|
|
||||||
msl(std::ratio<N, D>) noexcept
|
|
||||||
{
|
|
||||||
using R = typename std::ratio<N, D>::type;
|
|
||||||
return std::basic_string<CharT>(1, '[') + to_string<CharT>(R::num) + CharT{']'};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
std::basic_string<CharT>
|
|
||||||
msl(std::atto) noexcept
|
|
||||||
{
|
|
||||||
return {'a'};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
std::basic_string<CharT>
|
|
||||||
msl(std::femto) noexcept
|
|
||||||
{
|
|
||||||
return {'f'};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
std::basic_string<CharT>
|
|
||||||
msl(std::pico) noexcept
|
|
||||||
{
|
|
||||||
return {'p'};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
std::basic_string<CharT>
|
|
||||||
msl(std::nano) noexcept
|
|
||||||
{
|
|
||||||
return {'n'};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
typename std::enable_if
|
|
||||||
<
|
|
||||||
std::is_same<CharT, char>::value,
|
|
||||||
std::string
|
|
||||||
>::type
|
|
||||||
msl(std::micro) noexcept
|
|
||||||
{
|
|
||||||
return "\xC2\xB5";
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
typename std::enable_if
|
|
||||||
<
|
|
||||||
!std::is_same<CharT, char>::value,
|
|
||||||
std::basic_string<CharT>
|
|
||||||
>::type
|
|
||||||
msl(std::micro) noexcept
|
|
||||||
{
|
|
||||||
return {CharT(static_cast<unsigned char>('\xB5'))};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
std::basic_string<CharT>
|
|
||||||
msl(std::milli) noexcept
|
|
||||||
{
|
|
||||||
return {'m'};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
std::basic_string<CharT>
|
|
||||||
msl(std::centi) noexcept
|
|
||||||
{
|
|
||||||
return {'c'};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
std::basic_string<CharT>
|
|
||||||
msl(std::deci) noexcept
|
|
||||||
{
|
|
||||||
return {'d'};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
std::basic_string<CharT>
|
|
||||||
msl(std::deca) noexcept
|
|
||||||
{
|
|
||||||
return {'d', 'a'};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
std::basic_string<CharT>
|
|
||||||
msl(std::hecto) noexcept
|
|
||||||
{
|
|
||||||
return {'h'};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
std::basic_string<CharT>
|
|
||||||
msl(std::kilo) noexcept
|
|
||||||
{
|
|
||||||
return {'k'};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
std::basic_string<CharT>
|
|
||||||
msl(std::mega) noexcept
|
|
||||||
{
|
|
||||||
return {'M'};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
std::basic_string<CharT>
|
|
||||||
msl(std::giga) noexcept
|
|
||||||
{
|
|
||||||
return {'G'};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
std::basic_string<CharT>
|
|
||||||
msl(std::tera) noexcept
|
|
||||||
{
|
|
||||||
return {'T'};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
std::basic_string<CharT>
|
|
||||||
msl(std::peta) noexcept
|
|
||||||
{
|
|
||||||
return {'P'};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
constexpr
|
|
||||||
inline
|
|
||||||
std::basic_string<CharT>
|
|
||||||
msl(std::exa) noexcept
|
|
||||||
{
|
|
||||||
return {'E'};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT, class Period>
|
|
||||||
std::basic_string<CharT>
|
|
||||||
get_units(Period p)
|
|
||||||
{
|
|
||||||
return msl<CharT>(p) + CharT{'s'};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
std::basic_string<CharT>
|
|
||||||
get_units(std::ratio<1>)
|
|
||||||
{
|
|
||||||
return {'s'};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
std::basic_string<CharT>
|
|
||||||
get_units(std::ratio<60>)
|
|
||||||
{
|
|
||||||
return {'m', 'i', 'n'};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class CharT>
|
|
||||||
std::basic_string<CharT>
|
|
||||||
get_units(std::ratio<3600>)
|
|
||||||
{
|
|
||||||
return {'h'};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // __cplusplus >= 201402
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template <class CharT, class Traits, class Rep, class Period>
|
|
||||||
inline
|
|
||||||
std::basic_ostream<CharT, Traits>&
|
|
||||||
operator<<(std::basic_ostream<CharT, Traits>& os,
|
|
||||||
const std::chrono::duration<Rep, Period>& d)
|
|
||||||
{
|
|
||||||
using namespace std::chrono;
|
|
||||||
return os << d.count()
|
|
||||||
<< detail::get_units<CharT>(typename Period::type{});
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace date
|
|
||||||
|
|
||||||
#endif // CHRONO_IO_H
|
|
File diff suppressed because it is too large
Load Diff
@ -1,49 +0,0 @@
|
|||||||
//
|
|
||||||
// ios.h
|
|
||||||
// DateTimeLib
|
|
||||||
//
|
|
||||||
// The MIT License (MIT)
|
|
||||||
//
|
|
||||||
// Copyright (c) 2016 Alexander Kormanovsky
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
|
|
||||||
#ifndef ios_hpp
|
|
||||||
#define ios_hpp
|
|
||||||
|
|
||||||
#if __APPLE__
|
|
||||||
# include <TargetConditionals.h>
|
|
||||||
# if TARGET_OS_IPHONE
|
|
||||||
# include <string>
|
|
||||||
|
|
||||||
namespace date
|
|
||||||
{
|
|
||||||
namespace iOSUtils
|
|
||||||
{
|
|
||||||
|
|
||||||
std::string get_tzdata_path();
|
|
||||||
|
|
||||||
} // namespace iOSUtils
|
|
||||||
} // namespace date
|
|
||||||
|
|
||||||
# endif // TARGET_OS_IPHONE
|
|
||||||
#else // !__APPLE__
|
|
||||||
# define TARGET_OS_IPHONE 0
|
|
||||||
#endif // !__APPLE__
|
|
||||||
#endif // ios_hpp
|
|
@ -1,405 +0,0 @@
|
|||||||
//
|
|
||||||
// The MIT License (MIT)
|
|
||||||
//
|
|
||||||
// Copyright (c) 2016 Alexander Kormanovsky
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "ios.h"
|
|
||||||
|
|
||||||
#if TARGET_OS_IPHONE
|
|
||||||
|
|
||||||
#include <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <zlib.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#ifndef TAR_DEBUG
|
|
||||||
# define TAR_DEBUG 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define INTERNAL_DIR "Library/tzdata"
|
|
||||||
#define TARGZ_EXTENSION "tar.gz"
|
|
||||||
|
|
||||||
#define TAR_BLOCK_SIZE 512
|
|
||||||
#define TAR_TYPE_POSITION 156
|
|
||||||
#define TAR_NAME_POSITION 0
|
|
||||||
#define TAR_NAME_SIZE 100
|
|
||||||
#define TAR_SIZE_POSITION 124
|
|
||||||
#define TAR_SIZE_SIZE 12
|
|
||||||
|
|
||||||
namespace date
|
|
||||||
{
|
|
||||||
namespace iOSUtils
|
|
||||||
{
|
|
||||||
|
|
||||||
struct TarInfo
|
|
||||||
{
|
|
||||||
char objType;
|
|
||||||
std::string objName;
|
|
||||||
int64_t realContentSize; // writable size without padding zeroes
|
|
||||||
int64_t blocksContentSize; // adjusted size to 512 bytes blocks
|
|
||||||
bool success;
|
|
||||||
};
|
|
||||||
|
|
||||||
char* convertCFStringRefPathToCStringPath(CFStringRef ref);
|
|
||||||
bool extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath);
|
|
||||||
TarInfo getTarObjectInfo(CFReadStreamRef readStream, int64_t location);
|
|
||||||
std::string getTarObject(CFReadStreamRef readStream, int64_t size);
|
|
||||||
bool writeFile(CFURLRef tzdataUrl, std::string fileName, std::string data,
|
|
||||||
int64_t realContentSize);
|
|
||||||
|
|
||||||
std::string
|
|
||||||
date::iOSUtils::get_tzdata_path()
|
|
||||||
{
|
|
||||||
CFURLRef ref = CFCopyHomeDirectoryURL();
|
|
||||||
CFStringRef homePath = CFURLCopyPath(CFCopyHomeDirectoryURL());
|
|
||||||
std::string tzdata_path(std::string(convertCFStringRefPathToCStringPath(homePath)) +
|
|
||||||
INTERNAL_DIR);
|
|
||||||
|
|
||||||
if (access(tzdata_path.c_str(), F_OK) == 0)
|
|
||||||
{
|
|
||||||
#if TAR_DEBUG
|
|
||||||
printf("tzdata exists\n");
|
|
||||||
#endif
|
|
||||||
return tzdata_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
CFBundleRef mainBundle = CFBundleGetMainBundle();
|
|
||||||
CFArrayRef paths = CFBundleCopyResourceURLsOfType(mainBundle, CFSTR(TARGZ_EXTENSION),
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (CFArrayGetCount(paths) != 0)
|
|
||||||
{
|
|
||||||
// get archive path, assume there is no other tar.gz in bundle
|
|
||||||
CFURLRef archiveUrl = static_cast<CFURLRef>(CFArrayGetValueAtIndex(paths, 0));
|
|
||||||
CFStringRef archiveName= CFURLCopyPath(archiveUrl);
|
|
||||||
archiveUrl = CFBundleCopyResourceURL(mainBundle, archiveName, NULL, NULL);
|
|
||||||
|
|
||||||
extractTzdata(CFCopyHomeDirectoryURL(), archiveUrl, tzdata_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tzdata_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
char*
|
|
||||||
convertCFStringRefPathToCStringPath(CFStringRef ref)
|
|
||||||
{
|
|
||||||
CFIndex bufferSize = CFStringGetMaximumSizeOfFileSystemRepresentation(ref);
|
|
||||||
char *buffer = new char[bufferSize];
|
|
||||||
CFStringGetFileSystemRepresentation(ref, buffer, bufferSize);
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath)
|
|
||||||
{
|
|
||||||
const char *TAR_TMP_PATH = "/tmp.tar";
|
|
||||||
|
|
||||||
// create Library path
|
|
||||||
CFStringRef libraryStr = CFStringCreateWithCString(NULL, "Library",
|
|
||||||
CFStringGetSystemEncoding());
|
|
||||||
CFURLRef libraryUrl = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault,
|
|
||||||
homeUrl, libraryStr,
|
|
||||||
false);
|
|
||||||
|
|
||||||
// create tzdata path
|
|
||||||
CFStringRef tzdataPathRef = CFStringCreateWithCString(NULL, INTERNAL_DIR,
|
|
||||||
CFStringGetSystemEncoding());
|
|
||||||
CFURLRef tzdataPathUrl = CFURLCreateCopyAppendingPathComponent(NULL, homeUrl,
|
|
||||||
tzdataPathRef, false);
|
|
||||||
|
|
||||||
// create src archive path
|
|
||||||
CFStringRef archivePath = CFURLCopyPath(archiveUrl);
|
|
||||||
gzFile tarFile = gzopen(convertCFStringRefPathToCStringPath(archivePath), "rb");
|
|
||||||
|
|
||||||
// create tar unpacking path
|
|
||||||
CFStringRef tarName = CFStringCreateWithCString(NULL, TAR_TMP_PATH,
|
|
||||||
CFStringGetSystemEncoding());
|
|
||||||
CFURLRef tarUrl = CFURLCreateCopyAppendingPathComponent(NULL, libraryUrl, tarName,
|
|
||||||
false);
|
|
||||||
const char *tarPath = convertCFStringRefPathToCStringPath(CFURLCopyPath(tarUrl));
|
|
||||||
|
|
||||||
// create tzdata directory
|
|
||||||
mkdir(destPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
|
||||||
|
|
||||||
// create stream
|
|
||||||
CFWriteStreamRef writeStream = CFWriteStreamCreateWithFile(NULL, tarUrl);
|
|
||||||
bool success = true;
|
|
||||||
|
|
||||||
if (!CFWriteStreamOpen(writeStream))
|
|
||||||
{
|
|
||||||
CFStreamError err = CFWriteStreamGetError(writeStream);
|
|
||||||
|
|
||||||
if (err.domain == kCFStreamErrorDomainPOSIX)
|
|
||||||
{
|
|
||||||
printf("kCFStreamErrorDomainPOSIX %i\n", err.error);
|
|
||||||
}
|
|
||||||
else if(err.domain == kCFStreamErrorDomainMacOSStatus)
|
|
||||||
{
|
|
||||||
printf("kCFStreamErrorDomainMacOSStatus %i\n", err.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!success)
|
|
||||||
{
|
|
||||||
remove(tarPath);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ======= extract tar ========
|
|
||||||
|
|
||||||
unsigned int bufferLength = 1024 * 256; // 256Kb
|
|
||||||
void *buffer = malloc(bufferLength);
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
int readBytes = gzread(tarFile, buffer, bufferLength);
|
|
||||||
|
|
||||||
if (readBytes > 0)
|
|
||||||
{
|
|
||||||
CFIndex writtenBytes = CFWriteStreamWrite(writeStream, (unsigned char*)buffer,
|
|
||||||
readBytes);
|
|
||||||
|
|
||||||
if (writtenBytes < 0)
|
|
||||||
{
|
|
||||||
CFStreamError err = CFWriteStreamGetError(writeStream);
|
|
||||||
printf("write stream error %i\n", err.error);
|
|
||||||
success = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (readBytes == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (readBytes == -1)
|
|
||||||
{
|
|
||||||
printf("decompression failed\n");
|
|
||||||
success = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("unexpected zlib state\n");
|
|
||||||
success = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CFWriteStreamClose(writeStream);
|
|
||||||
CFRelease(writeStream);
|
|
||||||
free(buffer);
|
|
||||||
gzclose(tarFile);
|
|
||||||
|
|
||||||
if (!success)
|
|
||||||
{
|
|
||||||
remove(tarPath);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ======== extract files =========
|
|
||||||
|
|
||||||
uint64_t location = 0; // Position in the file
|
|
||||||
|
|
||||||
// get file size
|
|
||||||
struct stat stat_buf;
|
|
||||||
int res = stat(tarPath, &stat_buf);
|
|
||||||
if (res != 0)
|
|
||||||
{
|
|
||||||
printf("error file size\n");
|
|
||||||
remove(tarPath);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int64_t tarSize = stat_buf.st_size;
|
|
||||||
|
|
||||||
// create read stream
|
|
||||||
CFReadStreamRef readStream = CFReadStreamCreateWithFile(kCFAllocatorDefault, tarUrl);
|
|
||||||
|
|
||||||
if (!CFReadStreamOpen(readStream))
|
|
||||||
{
|
|
||||||
CFStreamError err = CFReadStreamGetError(readStream);
|
|
||||||
|
|
||||||
if (err.domain == kCFStreamErrorDomainPOSIX)
|
|
||||||
{
|
|
||||||
printf("kCFStreamErrorDomainPOSIX %i", err.error);
|
|
||||||
}
|
|
||||||
else if(err.domain == kCFStreamErrorDomainMacOSStatus)
|
|
||||||
{
|
|
||||||
printf("kCFStreamErrorDomainMacOSStatus %i", err.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!success)
|
|
||||||
{
|
|
||||||
CFRelease(readStream);
|
|
||||||
remove(tarPath);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
long size = 0;
|
|
||||||
|
|
||||||
// process files
|
|
||||||
while (location < tarSize)
|
|
||||||
{
|
|
||||||
TarInfo info = getTarObjectInfo(readStream, location);
|
|
||||||
|
|
||||||
if (!info.success || info.realContentSize == 0)
|
|
||||||
{
|
|
||||||
break; // something wrong or all files are read
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (info.objType)
|
|
||||||
{
|
|
||||||
case '0': // file
|
|
||||||
case '\0': //
|
|
||||||
{
|
|
||||||
std::string obj = getTarObject(readStream, info.blocksContentSize);
|
|
||||||
#if TAR_DEBUG
|
|
||||||
size += info.realContentSize;
|
|
||||||
printf("#%i %s file size %lld written total %ld from %lld\n", ++count,
|
|
||||||
info.objName.c_str(), info.realContentSize, size, tarSize);
|
|
||||||
#endif
|
|
||||||
writeFile(tzdataPathUrl, info.objName, obj, info.realContentSize);
|
|
||||||
location += info.blocksContentSize;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CFReadStreamClose(readStream);
|
|
||||||
CFRelease(readStream);
|
|
||||||
|
|
||||||
remove(tarPath);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
TarInfo
|
|
||||||
getTarObjectInfo(CFReadStreamRef readStream, int64_t location)
|
|
||||||
{
|
|
||||||
int64_t length = TAR_BLOCK_SIZE;
|
|
||||||
uint8_t buffer[length];
|
|
||||||
|
|
||||||
char type;
|
|
||||||
char name[TAR_NAME_SIZE + 1];
|
|
||||||
char sizeBuf[TAR_SIZE_SIZE + 1];
|
|
||||||
CFIndex bytesRead;
|
|
||||||
|
|
||||||
bool avail = CFReadStreamHasBytesAvailable(readStream);
|
|
||||||
|
|
||||||
bytesRead = CFReadStreamRead(readStream, buffer, length);
|
|
||||||
|
|
||||||
if (bytesRead < 0)
|
|
||||||
{
|
|
||||||
CFStreamError err = CFReadStreamGetError(readStream);
|
|
||||||
printf("error reading tar object info %i", err.error);
|
|
||||||
return {false};
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(&type, &buffer[TAR_TYPE_POSITION], 1);
|
|
||||||
|
|
||||||
memset(&name, '\0', TAR_NAME_SIZE + 1);
|
|
||||||
memcpy(&name, &buffer[TAR_NAME_POSITION], TAR_NAME_SIZE);
|
|
||||||
|
|
||||||
memset(&sizeBuf, '\0', TAR_SIZE_SIZE + 1);
|
|
||||||
memcpy(&sizeBuf, &buffer[TAR_SIZE_POSITION], TAR_SIZE_SIZE);
|
|
||||||
int64_t realSize = strtol(sizeBuf, NULL, 8);
|
|
||||||
int64_t blocksSize = realSize + (TAR_BLOCK_SIZE - (realSize % TAR_BLOCK_SIZE));
|
|
||||||
|
|
||||||
return {type, std::string(name), realSize, blocksSize, true};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
|
||||||
getTarObject(CFReadStreamRef readStream, int64_t size)
|
|
||||||
{
|
|
||||||
uint8_t buffer[size];
|
|
||||||
|
|
||||||
CFIndex bytesRead = CFReadStreamRead(readStream, buffer, size);
|
|
||||||
|
|
||||||
if (bytesRead < 0)
|
|
||||||
{
|
|
||||||
CFStreamError err = CFReadStreamGetError(readStream);
|
|
||||||
printf("error reading tar object info %i", err.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::string((char *)buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
writeFile(CFURLRef tzdataUrl, std::string fileName, std::string data,
|
|
||||||
int64_t realContentSize)
|
|
||||||
{
|
|
||||||
// create stream
|
|
||||||
CFStringRef fileNameRef = CFStringCreateWithCString(NULL, fileName.c_str(),
|
|
||||||
CFStringGetSystemEncoding());
|
|
||||||
CFURLRef url = CFURLCreateCopyAppendingPathComponent(NULL, tzdataUrl, fileNameRef,
|
|
||||||
false);
|
|
||||||
CFWriteStreamRef writeStream = CFWriteStreamCreateWithFile(NULL, url);
|
|
||||||
|
|
||||||
// open stream
|
|
||||||
if (!CFWriteStreamOpen(writeStream))
|
|
||||||
{
|
|
||||||
CFStreamError err = CFWriteStreamGetError(writeStream);
|
|
||||||
|
|
||||||
if (err.domain == kCFStreamErrorDomainPOSIX)
|
|
||||||
{
|
|
||||||
printf("kCFStreamErrorDomainPOSIX %i\n", err.error);
|
|
||||||
}
|
|
||||||
else if(err.domain == kCFStreamErrorDomainMacOSStatus)
|
|
||||||
{
|
|
||||||
printf("kCFStreamErrorDomainMacOSStatus %i\n", err.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
CFRelease(writeStream);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// trim empty space
|
|
||||||
uint8_t trimmedData[realContentSize + 1];
|
|
||||||
memset(&trimmedData, '\0', realContentSize);
|
|
||||||
memcpy(&trimmedData, data.c_str(), realContentSize);
|
|
||||||
|
|
||||||
// write
|
|
||||||
CFIndex writtenBytes = CFWriteStreamWrite(writeStream, trimmedData, realContentSize);
|
|
||||||
|
|
||||||
if (writtenBytes < 0)
|
|
||||||
{
|
|
||||||
CFStreamError err = CFWriteStreamGetError(writeStream);
|
|
||||||
printf("write stream error %i\n", err.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
CFWriteStreamClose(writeStream);
|
|
||||||
CFRelease(writeStream);
|
|
||||||
writeStream = NULL;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace iOSUtils
|
|
||||||
} // namespace date
|
|
||||||
|
|
||||||
#endif // TARGET_OS_IPHONE
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,265 +0,0 @@
|
|||||||
#ifndef TZ_PRIVATE_H
|
|
||||||
#define TZ_PRIVATE_H
|
|
||||||
|
|
||||||
// The MIT License (MIT)
|
|
||||||
//
|
|
||||||
// Copyright (c) 2015, 2016 Howard Hinnant
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
// Our apologies. When the previous paragraph was written, lowercase had not yet
|
|
||||||
// been invented (that woud involve another several millennia of evolution).
|
|
||||||
// We did not mean to shout.
|
|
||||||
|
|
||||||
#if !defined(_MSC_VER) || (_MSC_VER >= 1900)
|
|
||||||
#include "tz.h"
|
|
||||||
#else
|
|
||||||
#include "date.h"
|
|
||||||
#include <vector>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace date
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
|
|
||||||
enum class tz {utc, local, standard};
|
|
||||||
|
|
||||||
//forward declare to avoid warnings in gcc 6.2
|
|
||||||
class MonthDayTime;
|
|
||||||
std::istream& operator>>(std::istream& is, MonthDayTime& x);
|
|
||||||
std::ostream& operator<<(std::ostream& os, const MonthDayTime& x);
|
|
||||||
|
|
||||||
|
|
||||||
class MonthDayTime
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
struct pair
|
|
||||||
{
|
|
||||||
#if defined(_MSC_VER) && (_MSC_VER < 1900)
|
|
||||||
pair() : month_day_(date::jan / 1), weekday_(0U) {}
|
|
||||||
|
|
||||||
pair(const date::month_day& month_day, const date::weekday& weekday)
|
|
||||||
: month_day_(month_day), weekday_(weekday) {}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
date::month_day month_day_;
|
|
||||||
date::weekday weekday_;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Type {month_day, month_last_dow, lteq, gteq};
|
|
||||||
|
|
||||||
Type type_{month_day};
|
|
||||||
|
|
||||||
#if !defined(_MSC_VER) || (_MSC_VER >= 1900)
|
|
||||||
union U
|
|
||||||
#else
|
|
||||||
struct U
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
date::month_day month_day_;
|
|
||||||
date::month_weekday_last month_weekday_last_;
|
|
||||||
pair month_day_weekday_;
|
|
||||||
|
|
||||||
#if !defined(_MSC_VER) || (_MSC_VER >= 1900)
|
|
||||||
U() : month_day_{date::jan/1} {}
|
|
||||||
#else
|
|
||||||
U() :
|
|
||||||
month_day_(date::jan/1),
|
|
||||||
month_weekday_last_(date::month(0U), date::weekday_last(date::weekday(0U)))
|
|
||||||
{}
|
|
||||||
|
|
||||||
#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900)
|
|
||||||
|
|
||||||
U& operator=(const date::month_day& x);
|
|
||||||
U& operator=(const date::month_weekday_last& x);
|
|
||||||
U& operator=(const pair& x);
|
|
||||||
} u;
|
|
||||||
|
|
||||||
std::chrono::hours h_{0};
|
|
||||||
std::chrono::minutes m_{0};
|
|
||||||
std::chrono::seconds s_{0};
|
|
||||||
tz zone_{tz::local};
|
|
||||||
|
|
||||||
public:
|
|
||||||
MonthDayTime() = default;
|
|
||||||
MonthDayTime(local_seconds tp, tz timezone);
|
|
||||||
MonthDayTime(const date::month_day& md, tz timezone);
|
|
||||||
|
|
||||||
date::day day() const;
|
|
||||||
date::month month() const;
|
|
||||||
tz zone() const {return zone_;}
|
|
||||||
|
|
||||||
void canonicalize(date::year y);
|
|
||||||
|
|
||||||
sys_seconds
|
|
||||||
to_sys(date::year y, std::chrono::seconds offset, std::chrono::seconds save) const;
|
|
||||||
sys_days to_sys_days(date::year y) const;
|
|
||||||
|
|
||||||
sys_seconds to_time_point(date::year y) const;
|
|
||||||
int compare(date::year y, const MonthDayTime& x, date::year yx,
|
|
||||||
std::chrono::seconds offset, std::chrono::minutes prev_save) const;
|
|
||||||
|
|
||||||
friend std::istream& operator>>(std::istream& is, MonthDayTime& x);
|
|
||||||
friend std::ostream& operator<<(std::ostream& os, const MonthDayTime& x);
|
|
||||||
};
|
|
||||||
|
|
||||||
// A Rule specifies one or more set of datetimes without using an offset.
|
|
||||||
// Multiple dates are specified with multiple years. The years in effect
|
|
||||||
// go from starting_year_ to ending_year_, inclusive. starting_year_ <=
|
|
||||||
// ending_year_. save_ is ineffect for times from the specified time
|
|
||||||
// onward, including the specified time. When the specified time is
|
|
||||||
// local, it uses the save_ from the chronologically previous Rule, or if
|
|
||||||
// there is none, 0.
|
|
||||||
|
|
||||||
//forward declare to avoid warnings in gcc 6.2
|
|
||||||
class Rule;
|
|
||||||
bool operator==(const Rule& x, const Rule& y);
|
|
||||||
bool operator<(const Rule& x, const Rule& y);
|
|
||||||
bool operator==(const Rule& x, const date::year& y);
|
|
||||||
bool operator<(const Rule& x, const date::year& y);
|
|
||||||
bool operator==(const date::year& x, const Rule& y);
|
|
||||||
bool operator<(const date::year& x, const Rule& y);
|
|
||||||
bool operator==(const Rule& x, const std::string& y);
|
|
||||||
bool operator<(const Rule& x, const std::string& y);
|
|
||||||
bool operator==(const std::string& x, const Rule& y);
|
|
||||||
bool operator<(const std::string& x, const Rule& y);
|
|
||||||
std::ostream& operator<<(std::ostream& os, const Rule& r);
|
|
||||||
|
|
||||||
class Rule
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
std::string name_;
|
|
||||||
date::year starting_year_{0};
|
|
||||||
date::year ending_year_{0};
|
|
||||||
MonthDayTime starting_at_;
|
|
||||||
std::chrono::minutes save_{0};
|
|
||||||
std::string abbrev_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Rule() = default;
|
|
||||||
explicit Rule(const std::string& s);
|
|
||||||
Rule(const Rule& r, date::year starting_year, date::year ending_year);
|
|
||||||
|
|
||||||
const std::string& name() const {return name_;}
|
|
||||||
const std::string& abbrev() const {return abbrev_;}
|
|
||||||
|
|
||||||
const MonthDayTime& mdt() const {return starting_at_;}
|
|
||||||
const date::year& starting_year() const {return starting_year_;}
|
|
||||||
const date::year& ending_year() const {return ending_year_;}
|
|
||||||
const std::chrono::minutes& save() const {return save_;}
|
|
||||||
|
|
||||||
static void split_overlaps(std::vector<Rule>& rules);
|
|
||||||
|
|
||||||
friend bool operator==(const Rule& x, const Rule& y);
|
|
||||||
friend bool operator<(const Rule& x, const Rule& y);
|
|
||||||
friend bool operator==(const Rule& x, const date::year& y);
|
|
||||||
friend bool operator<(const Rule& x, const date::year& y);
|
|
||||||
friend bool operator==(const date::year& x, const Rule& y);
|
|
||||||
friend bool operator<(const date::year& x, const Rule& y);
|
|
||||||
friend bool operator==(const Rule& x, const std::string& y);
|
|
||||||
friend bool operator<(const Rule& x, const std::string& y);
|
|
||||||
friend bool operator==(const std::string& x, const Rule& y);
|
|
||||||
friend bool operator<(const std::string& x, const Rule& y);
|
|
||||||
|
|
||||||
friend std::ostream& operator<<(std::ostream& os, const Rule& r);
|
|
||||||
|
|
||||||
private:
|
|
||||||
date::day day() const;
|
|
||||||
date::month month() const;
|
|
||||||
static void split_overlaps(std::vector<Rule>& rules, std::size_t i, std::size_t& e);
|
|
||||||
static bool overlaps(const Rule& x, const Rule& y);
|
|
||||||
static void split(std::vector<Rule>& rules, std::size_t i, std::size_t k,
|
|
||||||
std::size_t& e);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline bool operator!=(const Rule& x, const Rule& y) {return !(x == y);}
|
|
||||||
inline bool operator> (const Rule& x, const Rule& y) {return y < x;}
|
|
||||||
inline bool operator<=(const Rule& x, const Rule& y) {return !(y < x);}
|
|
||||||
inline bool operator>=(const Rule& x, const Rule& y) {return !(x < y);}
|
|
||||||
|
|
||||||
inline bool operator!=(const Rule& x, const date::year& y) {return !(x == y);}
|
|
||||||
inline bool operator> (const Rule& x, const date::year& y) {return y < x;}
|
|
||||||
inline bool operator<=(const Rule& x, const date::year& y) {return !(y < x);}
|
|
||||||
inline bool operator>=(const Rule& x, const date::year& y) {return !(x < y);}
|
|
||||||
|
|
||||||
inline bool operator!=(const date::year& x, const Rule& y) {return !(x == y);}
|
|
||||||
inline bool operator> (const date::year& x, const Rule& y) {return y < x;}
|
|
||||||
inline bool operator<=(const date::year& x, const Rule& y) {return !(y < x);}
|
|
||||||
inline bool operator>=(const date::year& x, const Rule& y) {return !(x < y);}
|
|
||||||
|
|
||||||
inline bool operator!=(const Rule& x, const std::string& y) {return !(x == y);}
|
|
||||||
inline bool operator> (const Rule& x, const std::string& y) {return y < x;}
|
|
||||||
inline bool operator<=(const Rule& x, const std::string& y) {return !(y < x);}
|
|
||||||
inline bool operator>=(const Rule& x, const std::string& y) {return !(x < y);}
|
|
||||||
|
|
||||||
inline bool operator!=(const std::string& x, const Rule& y) {return !(x == y);}
|
|
||||||
inline bool operator> (const std::string& x, const Rule& y) {return y < x;}
|
|
||||||
inline bool operator<=(const std::string& x, const Rule& y) {return !(y < x);}
|
|
||||||
inline bool operator>=(const std::string& x, const Rule& y) {return !(x < y);}
|
|
||||||
|
|
||||||
struct zonelet
|
|
||||||
{
|
|
||||||
enum tag {has_rule, has_save, is_empty};
|
|
||||||
|
|
||||||
std::chrono::seconds gmtoff_;
|
|
||||||
tag tag_ = has_rule;
|
|
||||||
|
|
||||||
#if !defined(_MSC_VER) || (_MSC_VER >= 1900)
|
|
||||||
union U
|
|
||||||
#else
|
|
||||||
struct U
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
std::string rule_;
|
|
||||||
std::chrono::minutes save_;
|
|
||||||
|
|
||||||
~U() {}
|
|
||||||
U() {}
|
|
||||||
U(const U&) {}
|
|
||||||
U& operator=(const U&) = delete;
|
|
||||||
} u;
|
|
||||||
|
|
||||||
std::string format_;
|
|
||||||
date::year until_year_{0};
|
|
||||||
MonthDayTime until_date_;
|
|
||||||
sys_seconds until_utc_;
|
|
||||||
local_seconds until_std_;
|
|
||||||
local_seconds until_loc_;
|
|
||||||
std::chrono::minutes initial_save_{};
|
|
||||||
std::string initial_abbrev_;
|
|
||||||
std::pair<const Rule*, date::year> first_rule_{nullptr, date::year::min()};
|
|
||||||
std::pair<const Rule*, date::year> last_rule_{nullptr, date::year::max()};
|
|
||||||
|
|
||||||
~zonelet();
|
|
||||||
zonelet();
|
|
||||||
zonelet(const zonelet& i);
|
|
||||||
zonelet& operator=(const zonelet&) = delete;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
} // namespace date
|
|
||||||
|
|
||||||
#if defined(_MSC_VER) && (_MSC_VER < 1900)
|
|
||||||
#include "tz.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // TZ_PRIVATE_H
|
|
@ -0,0 +1,138 @@
|
|||||||
|
#ifndef CACHE_HPP
|
||||||
|
#define CACHE_HPP
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <limits>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include "cache_policy.hpp"
|
||||||
|
|
||||||
|
namespace caches
|
||||||
|
{
|
||||||
|
|
||||||
|
// Base class for caching algorithms
|
||||||
|
template <typename Key, typename Value, typename Policy = NoCachePolicy<Key>>
|
||||||
|
class fixed_sized_cache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
using iterator = typename std::unordered_map<Key, Value>::iterator;
|
||||||
|
|
||||||
|
using const_iterator =
|
||||||
|
typename std::unordered_map<Key, Value>::const_iterator;
|
||||||
|
|
||||||
|
using operation_guard = typename std::lock_guard<std::mutex>;
|
||||||
|
|
||||||
|
fixed_sized_cache(
|
||||||
|
size_t max_size,
|
||||||
|
const Policy& policy = Policy())
|
||||||
|
: max_cache_size{max_size},
|
||||||
|
cache_policy(policy)
|
||||||
|
{
|
||||||
|
if (max_cache_size == 0)
|
||||||
|
{
|
||||||
|
max_cache_size = std::numeric_limits<size_t>::max();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Put(const Key& key, const Value& value)
|
||||||
|
{
|
||||||
|
operation_guard{safe_op};
|
||||||
|
auto elem_it = FindElem(key);
|
||||||
|
|
||||||
|
if (elem_it == cache_items_map.end())
|
||||||
|
{
|
||||||
|
// add new element to the cache
|
||||||
|
if (Size() + 1 > max_cache_size)
|
||||||
|
{
|
||||||
|
auto disp_candidate_key = cache_policy.ReplCandidate();
|
||||||
|
|
||||||
|
Erase(disp_candidate_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
Insert(key, value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// update previous value
|
||||||
|
Update(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Contains(const Key& key)
|
||||||
|
{
|
||||||
|
operation_guard{safe_op};
|
||||||
|
auto elem_it = FindElem(key);
|
||||||
|
return elem_it != cache_items_map.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const Value& Get(const Key& key) const
|
||||||
|
{
|
||||||
|
operation_guard{safe_op};
|
||||||
|
auto elem_it = FindElem(key);
|
||||||
|
|
||||||
|
if (elem_it == cache_items_map.end())
|
||||||
|
{
|
||||||
|
throw std::range_error{"No such element in the cache"};
|
||||||
|
}
|
||||||
|
cache_policy.Touch(key);
|
||||||
|
|
||||||
|
return elem_it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t Size() const
|
||||||
|
{
|
||||||
|
operation_guard{safe_op};
|
||||||
|
|
||||||
|
return cache_items_map.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// return a key of a displacement candidate
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
operation_guard{safe_op};
|
||||||
|
|
||||||
|
cache_policy.Clear();
|
||||||
|
cache_items_map.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void Insert(const Key& key, const Value& value)
|
||||||
|
{
|
||||||
|
cache_policy.Insert(key);
|
||||||
|
cache_items_map.emplace(std::make_pair(key, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Erase(const Key& key)
|
||||||
|
{
|
||||||
|
cache_policy.Erase(key);
|
||||||
|
cache_items_map.erase(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Update(const Key& key, const Value& value)
|
||||||
|
{
|
||||||
|
cache_policy.Touch(key);
|
||||||
|
cache_items_map[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator FindElem(const Key& key) const
|
||||||
|
{
|
||||||
|
return cache_items_map.find(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::unordered_map<Key, Value> cache_items_map;
|
||||||
|
|
||||||
|
mutable Policy cache_policy;
|
||||||
|
mutable std::mutex safe_op;
|
||||||
|
|
||||||
|
size_t max_cache_size;
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CACHE_HPP
|
@ -0,0 +1,77 @@
|
|||||||
|
#ifndef CACHE_POLICY_HPP
|
||||||
|
#define CACHE_POLICY_HPP
|
||||||
|
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
namespace caches
|
||||||
|
{
|
||||||
|
|
||||||
|
template <typename Key>
|
||||||
|
|
||||||
|
class ICachePolicy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual ~ICachePolicy() {}
|
||||||
|
|
||||||
|
// handle element insertion in a cache
|
||||||
|
virtual void Insert(const Key& key) = 0;
|
||||||
|
|
||||||
|
// handle request to the key-element in a cache
|
||||||
|
virtual void Touch(const Key& key) = 0;
|
||||||
|
|
||||||
|
// handle element deletion from a cache
|
||||||
|
virtual void Erase(const Key& key) = 0;
|
||||||
|
|
||||||
|
// return a key of a replacement candidate
|
||||||
|
virtual const Key& ReplCandidate() const = 0;
|
||||||
|
|
||||||
|
// clear the cache
|
||||||
|
virtual void Clear() = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Key>
|
||||||
|
class NoCachePolicy : public ICachePolicy<Key>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
NoCachePolicy() = default;
|
||||||
|
|
||||||
|
~NoCachePolicy() override = default;
|
||||||
|
|
||||||
|
void Insert(const Key& key) override
|
||||||
|
{
|
||||||
|
key_storage.emplace(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Touch(const Key& key) override
|
||||||
|
{
|
||||||
|
// do not do anything
|
||||||
|
}
|
||||||
|
|
||||||
|
void Erase(const Key& key) override
|
||||||
|
{
|
||||||
|
key_storage.erase(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return a key of a displacement candidate
|
||||||
|
const Key& ReplCandidate() const override
|
||||||
|
{
|
||||||
|
return *key_storage.crbegin();
|
||||||
|
}
|
||||||
|
|
||||||
|
// return a key of a displacement candidate
|
||||||
|
void Clear() override
|
||||||
|
{
|
||||||
|
key_storage.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::unordered_set<Key> key_storage;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace caches
|
||||||
|
|
||||||
|
#endif // CACHE_POLICY_HPP
|
@ -0,0 +1,53 @@
|
|||||||
|
#ifndef FIFO_CACHE_POLICY_HPP
|
||||||
|
#define FIFO_CACHE_POLICY_HPP
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include "cache_policy.hpp"
|
||||||
|
|
||||||
|
namespace caches
|
||||||
|
{
|
||||||
|
|
||||||
|
template <typename Key>
|
||||||
|
class FIFOCachePolicy : public ICachePolicy<Key>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
FIFOCachePolicy() = default;
|
||||||
|
~FIFOCachePolicy() = default;
|
||||||
|
|
||||||
|
void Insert(const Key& key) override
|
||||||
|
{
|
||||||
|
fifo_queue.emplace_front(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle request to the key-element in a cache
|
||||||
|
void Touch(const Key& key) override
|
||||||
|
{
|
||||||
|
// nothing to do here in the FIFO strategy
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle element deletion from a cache
|
||||||
|
void Erase(const Key& key) override
|
||||||
|
{
|
||||||
|
fifo_queue.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// return a key of a replacement candidate
|
||||||
|
const Key& ReplCandidate() const override
|
||||||
|
{
|
||||||
|
return fifo_queue.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// return a key of a displacement candidate
|
||||||
|
void Clear() override
|
||||||
|
{
|
||||||
|
fifo_queue.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::list<Key> fifo_queue;
|
||||||
|
};
|
||||||
|
} // namespace caches
|
||||||
|
|
||||||
|
#endif // FIFO_CACHE_POLICY_HPP
|
@ -0,0 +1,76 @@
|
|||||||
|
#ifndef LFU_CACHE_POLICY_HPP
|
||||||
|
#define LFU_CACHE_POLICY_HPP
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <map>
|
||||||
|
#include <iostream>
|
||||||
|
#include "cache_policy.hpp"
|
||||||
|
|
||||||
|
namespace caches
|
||||||
|
{
|
||||||
|
template <typename Key>
|
||||||
|
class LFUCachePolicy : public ICachePolicy<Key>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
using lfu_iterator = typename std::multimap<std::size_t, Key>::iterator;
|
||||||
|
|
||||||
|
LFUCachePolicy() = default;
|
||||||
|
|
||||||
|
~LFUCachePolicy() override = default;
|
||||||
|
|
||||||
|
void Insert(const Key& key) override
|
||||||
|
{
|
||||||
|
constexpr std::size_t INIT_VAL = 1;
|
||||||
|
|
||||||
|
// all new value initialized with the frequency 1
|
||||||
|
lfu_storage[key] = frequency_storage.emplace_hint(
|
||||||
|
frequency_storage.cbegin(), INIT_VAL, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Touch(const Key& key) override
|
||||||
|
{
|
||||||
|
// get the previous frequency value of a key
|
||||||
|
auto elem_for_update = lfu_storage[key];
|
||||||
|
|
||||||
|
auto updated_elem = std::make_pair(
|
||||||
|
elem_for_update->first + 1, elem_for_update->second);
|
||||||
|
|
||||||
|
// update the previous value
|
||||||
|
frequency_storage.erase(elem_for_update);
|
||||||
|
|
||||||
|
lfu_storage[key] = frequency_storage.emplace_hint(
|
||||||
|
frequency_storage.cend(), std::move(updated_elem));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Erase(const Key& key) override
|
||||||
|
{
|
||||||
|
frequency_storage.erase(lfu_storage[key]);
|
||||||
|
lfu_storage.erase(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Key& ReplCandidate() const override
|
||||||
|
{
|
||||||
|
// at the beginning of the frequency_storage we have the
|
||||||
|
// least frequency used value
|
||||||
|
return frequency_storage.cbegin()->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return a key of a displacement candidate
|
||||||
|
void Clear() override
|
||||||
|
{
|
||||||
|
frequency_storage.clear();
|
||||||
|
lfu_storage.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::multimap<std::size_t, Key> frequency_storage;
|
||||||
|
|
||||||
|
std::unordered_map<Key, lfu_iterator> lfu_storage;
|
||||||
|
};
|
||||||
|
} // namespace caches
|
||||||
|
|
||||||
|
#endif // LFU_CACHE_POLICY_HPP
|
@ -0,0 +1,63 @@
|
|||||||
|
#ifndef LRU_CACHE_POLICY_HPP
|
||||||
|
#define LRU_CACHE_POLICY_HPP
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include "cache_policy.hpp"
|
||||||
|
|
||||||
|
namespace caches
|
||||||
|
{
|
||||||
|
template <typename Key>
|
||||||
|
class LRUCachePolicy : public ICachePolicy<Key>
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
using lru_iterator = typename std::list<Key>::const_iterator;
|
||||||
|
|
||||||
|
LRUCachePolicy() = default;
|
||||||
|
~LRUCachePolicy() = default;
|
||||||
|
|
||||||
|
void Insert(const Key& key) override
|
||||||
|
{
|
||||||
|
lru_queue.emplace_front(key);
|
||||||
|
key_finder[key] = lru_queue.cbegin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Touch(const Key& key) override
|
||||||
|
{
|
||||||
|
// move the touched element at the beginning of the lru_queue
|
||||||
|
lru_queue.splice(lru_queue.cbegin(), lru_queue, key_finder[key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Erase(const Key& key) override
|
||||||
|
{
|
||||||
|
// remove the least recently used element
|
||||||
|
key_finder.erase(lru_queue.back());
|
||||||
|
|
||||||
|
lru_queue.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// return a key of a displacement candidate
|
||||||
|
const Key& ReplCandidate() const override
|
||||||
|
{
|
||||||
|
return lru_queue.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// return a key of a displacement candidate
|
||||||
|
void Clear() override
|
||||||
|
{
|
||||||
|
lru_queue.clear();
|
||||||
|
key_finder.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::list<Key> lru_queue;
|
||||||
|
|
||||||
|
std::unordered_map<Key, lru_iterator> key_finder;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace caches
|
||||||
|
|
||||||
|
#endif // LRU_CACHE_POLICY_HPP
|
Binary file not shown.
Before Width: | Height: | Size: 575 KiB |
@ -1,755 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by mwo on 27/04/16.
|
|
||||||
//
|
|
||||||
#ifndef XMRLMDBCPP_MYLMDB_H
|
|
||||||
#define XMRLMDBCPP_MYLMDB_H
|
|
||||||
|
|
||||||
#include "../ext/lmdb++.h"
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace xmreg
|
|
||||||
{
|
|
||||||
|
|
||||||
using epee::string_tools::pod_to_hex;
|
|
||||||
using epee::string_tools::hex_to_pod;
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores info about outputs useful
|
|
||||||
* for checking which ouputs belong to a
|
|
||||||
* given address and viewkey
|
|
||||||
*/
|
|
||||||
struct output_info
|
|
||||||
{
|
|
||||||
crypto::public_key out_pub_key;
|
|
||||||
crypto::hash tx_hash;
|
|
||||||
crypto::public_key tx_pub_key;
|
|
||||||
uint64_t amount;
|
|
||||||
uint64_t index_in_tx;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, const output_info& out_info)
|
|
||||||
{
|
|
||||||
os << ", out_pub_key: " << out_info.out_pub_key
|
|
||||||
<< ", tx_hash: " << out_info.tx_hash
|
|
||||||
<< ", tx_pub_key: " << out_info.tx_pub_key
|
|
||||||
<< ", amount: " << XMR_AMOUNT(out_info.amount)
|
|
||||||
<< ", index_in_tx: " << out_info.index_in_tx;
|
|
||||||
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyLMDB
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
static const uint64_t DEFAULT_MAPSIZE = 30UL * 1024UL * 1024UL * 1024UL; /* 30 GiB */
|
|
||||||
static const uint64_t DEFAULT_NO_DBs = 10;
|
|
||||||
|
|
||||||
|
|
||||||
string m_db_path;
|
|
||||||
|
|
||||||
uint64_t m_mapsize;
|
|
||||||
uint64_t m_no_dbs;
|
|
||||||
|
|
||||||
lmdb::env m_env;
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
MyLMDB(string _path,
|
|
||||||
uint64_t _mapsize = DEFAULT_MAPSIZE,
|
|
||||||
uint64_t _no_dbs = DEFAULT_NO_DBs)
|
|
||||||
: m_db_path {_path},
|
|
||||||
m_mapsize {_mapsize},
|
|
||||||
m_no_dbs {_no_dbs},
|
|
||||||
m_env {nullptr}
|
|
||||||
{
|
|
||||||
create_and_open_env();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
create_and_open_env()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{ m_env = lmdb::env::create();
|
|
||||||
m_env.set_mapsize(m_mapsize);
|
|
||||||
m_env.set_max_dbs(m_no_dbs);
|
|
||||||
m_env.open(m_db_path.c_str(), MDB_CREATE, 0664);
|
|
||||||
}
|
|
||||||
catch (lmdb::error& e )
|
|
||||||
{
|
|
||||||
cerr << e.what() << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
write_key_images(const transaction& tx)
|
|
||||||
{
|
|
||||||
crypto::hash tx_hash = get_transaction_hash(tx);
|
|
||||||
|
|
||||||
string tx_hash_str = pod_to_hex(tx_hash);
|
|
||||||
|
|
||||||
vector<cryptonote::txin_to_key> key_images
|
|
||||||
= xmreg::get_key_images(tx);
|
|
||||||
|
|
||||||
lmdb::txn wtxn {nullptr};
|
|
||||||
lmdb::dbi wdbi {0};
|
|
||||||
|
|
||||||
unsigned int flags = MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
wtxn = lmdb::txn::begin(m_env);
|
|
||||||
wdbi = lmdb::dbi::open(wtxn, "key_images", flags);
|
|
||||||
}
|
|
||||||
catch (lmdb::error& e )
|
|
||||||
{
|
|
||||||
cerr << e.what() << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const cryptonote::txin_to_key& key_image: key_images)
|
|
||||||
{
|
|
||||||
string key_img_str = pod_to_hex(key_image.k_image);
|
|
||||||
|
|
||||||
lmdb::val key_img_val {key_img_str};
|
|
||||||
lmdb::val tx_hash_val {tx_hash_str};
|
|
||||||
|
|
||||||
wdbi.put(wtxn, key_img_val, tx_hash_val);
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
wtxn.commit();
|
|
||||||
}
|
|
||||||
catch (lmdb::error& e )
|
|
||||||
{
|
|
||||||
cerr << e.what() << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
write_output_public_keys(const transaction& tx, const block& blk)
|
|
||||||
{
|
|
||||||
crypto::hash tx_hash = get_transaction_hash(tx);
|
|
||||||
|
|
||||||
crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx);
|
|
||||||
|
|
||||||
string tx_hash_str = pod_to_hex(tx_hash);
|
|
||||||
|
|
||||||
vector<tuple<txout_to_key, uint64_t, uint64_t>> outputs =
|
|
||||||
xmreg::get_ouputs_tuple(tx);
|
|
||||||
|
|
||||||
lmdb::txn wtxn {nullptr};
|
|
||||||
lmdb::dbi wdbi1 {0};
|
|
||||||
lmdb::dbi wdbi2 {0};
|
|
||||||
lmdb::dbi wdbi3 {0};
|
|
||||||
|
|
||||||
unsigned int flags = MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
wtxn = lmdb::txn::begin(m_env);
|
|
||||||
wdbi1 = lmdb::dbi::open(wtxn, "output_public_keys", flags);
|
|
||||||
wdbi2 = lmdb::dbi::open(wtxn, "output_amounts", flags);
|
|
||||||
wdbi3 = lmdb::dbi::open(wtxn, "output_info",
|
|
||||||
flags | MDB_INTEGERKEY | MDB_INTEGERDUP);
|
|
||||||
}
|
|
||||||
catch (lmdb::error& e )
|
|
||||||
{
|
|
||||||
cerr << e.what() << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& output: outputs)
|
|
||||||
{
|
|
||||||
|
|
||||||
public_key out_pub_key = std::get<0>(output).key;
|
|
||||||
|
|
||||||
string public_key_str = pod_to_hex(out_pub_key);
|
|
||||||
|
|
||||||
lmdb::val public_key_val {public_key_str};
|
|
||||||
lmdb::val tx_hash_val {tx_hash_str};
|
|
||||||
|
|
||||||
uint64_t amount = std::get<1>(output);
|
|
||||||
|
|
||||||
lmdb::val amount_val {static_cast<void*>(&amount), sizeof(amount)};
|
|
||||||
|
|
||||||
uint64_t index_in_tx = std::get<2>(output);
|
|
||||||
|
|
||||||
output_info out_info {out_pub_key, tx_hash,
|
|
||||||
tx_pub_key, amount,
|
|
||||||
index_in_tx};
|
|
||||||
|
|
||||||
uint64_t out_timestamp = blk.timestamp;
|
|
||||||
|
|
||||||
lmdb::val out_timestamp_val {static_cast<void*>(&out_timestamp),
|
|
||||||
sizeof(out_timestamp)};
|
|
||||||
lmdb::val out_info_val {static_cast<void*>(&out_info),
|
|
||||||
sizeof(out_info)};
|
|
||||||
|
|
||||||
wdbi1.put(wtxn, public_key_val, tx_hash_val);
|
|
||||||
wdbi2.put(wtxn, public_key_val, amount_val);
|
|
||||||
wdbi3.put(wtxn, out_timestamp_val, out_info_val);
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
wtxn.commit();
|
|
||||||
}
|
|
||||||
catch (lmdb::error& e )
|
|
||||||
{
|
|
||||||
cerr << e.what() << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
write_tx_public_key(const transaction& tx)
|
|
||||||
{
|
|
||||||
crypto::hash tx_hash = get_transaction_hash(tx);
|
|
||||||
|
|
||||||
string tx_hash_str = pod_to_hex(tx_hash);
|
|
||||||
|
|
||||||
unsigned int flags = MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED;
|
|
||||||
|
|
||||||
public_key pk = get_tx_pub_key_from_extra(tx);
|
|
||||||
|
|
||||||
string pk_str = pod_to_hex(pk);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
lmdb::txn wtxn = lmdb::txn::begin(m_env);
|
|
||||||
lmdb::dbi wdbi = lmdb::dbi::open(wtxn, "tx_public_keys", flags);
|
|
||||||
|
|
||||||
//cout << "Saving public_key: " << pk_str << endl;
|
|
||||||
|
|
||||||
lmdb::val public_key_val {pk_str};
|
|
||||||
lmdb::val tx_hash_val {tx_hash_str};
|
|
||||||
|
|
||||||
wdbi.put(wtxn, public_key_val, tx_hash_val);
|
|
||||||
|
|
||||||
wtxn.commit();
|
|
||||||
}
|
|
||||||
catch (lmdb::error& e)
|
|
||||||
{
|
|
||||||
cerr << e.what() << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
write_payment_id(const transaction& tx)
|
|
||||||
{
|
|
||||||
crypto::hash tx_hash = get_transaction_hash(tx);
|
|
||||||
|
|
||||||
string tx_hash_str = pod_to_hex(tx_hash);
|
|
||||||
|
|
||||||
crypto::hash payment_id;
|
|
||||||
crypto::hash8 payment_id8;
|
|
||||||
|
|
||||||
get_payment_id(tx, payment_id, payment_id8);
|
|
||||||
|
|
||||||
if (payment_id == null_hash)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int flags = MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED;
|
|
||||||
|
|
||||||
string payment_id_str = pod_to_hex(payment_id);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
lmdb::txn wtxn = lmdb::txn::begin(m_env);
|
|
||||||
lmdb::dbi wdbi = lmdb::dbi::open(wtxn, "payments_id", flags);
|
|
||||||
|
|
||||||
//cout << "Saving payiment_id: " << payment_id_str << endl;
|
|
||||||
|
|
||||||
lmdb::val payment_id_val {payment_id_str};
|
|
||||||
lmdb::val tx_hash_val {tx_hash_str};
|
|
||||||
|
|
||||||
wdbi.put(wtxn, payment_id_val, tx_hash_val);
|
|
||||||
|
|
||||||
wtxn.commit();
|
|
||||||
}
|
|
||||||
catch (lmdb::error& e)
|
|
||||||
{
|
|
||||||
cerr << e.what() << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
write_encrypted_payment_id(const transaction& tx)
|
|
||||||
{
|
|
||||||
crypto::hash tx_hash = get_transaction_hash(tx);
|
|
||||||
|
|
||||||
string tx_hash_str = pod_to_hex(tx_hash);
|
|
||||||
|
|
||||||
crypto::hash payment_id;
|
|
||||||
crypto::hash8 payment_id8;
|
|
||||||
|
|
||||||
get_payment_id(tx, payment_id, payment_id8);
|
|
||||||
|
|
||||||
if (payment_id8 == null_hash8)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int flags = MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED;
|
|
||||||
|
|
||||||
string payment_id_str = pod_to_hex(payment_id8);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
lmdb::txn wtxn = lmdb::txn::begin(m_env);
|
|
||||||
lmdb::dbi wdbi = lmdb::dbi::open(wtxn, "encrypted_payments_id", flags);
|
|
||||||
|
|
||||||
//cout << "Saving encrypted payiment_id: " << payment_id_str << endl;
|
|
||||||
//string wait_for_enter;
|
|
||||||
//cin >> wait_for_enter;
|
|
||||||
|
|
||||||
lmdb::val payment_id_val {payment_id_str};
|
|
||||||
lmdb::val tx_hash_val {tx_hash_str};
|
|
||||||
|
|
||||||
wdbi.put(wtxn, payment_id_val, tx_hash_val);
|
|
||||||
|
|
||||||
wtxn.commit();
|
|
||||||
}
|
|
||||||
catch (lmdb::error& e)
|
|
||||||
{
|
|
||||||
cerr << e.what() << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// // this seems to be not needed as outputs are written based on timestamps
|
|
||||||
//
|
|
||||||
// bool
|
|
||||||
// write_block_timestamp(uint64_t& blk_timestamp, uint64_t& blk_height)
|
|
||||||
// {
|
|
||||||
//
|
|
||||||
// unsigned int flags = MDB_CREATE | MDB_INTEGERKEY;
|
|
||||||
//
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// lmdb::txn wtxn = lmdb::txn::begin(m_env);
|
|
||||||
// lmdb::dbi wdbi = lmdb::dbi::open(wtxn, "block_timestamps", flags);
|
|
||||||
//
|
|
||||||
// lmdb::val blk_timestamp_val {static_cast<void*>(&blk_timestamp),
|
|
||||||
// sizeof(blk_timestamp)};
|
|
||||||
// lmdb::val blk_height_val {static_cast<void*>(&blk_height),
|
|
||||||
// sizeof(blk_height)};
|
|
||||||
//
|
|
||||||
// wdbi.put(wtxn, blk_timestamp_val, blk_height_val);
|
|
||||||
//
|
|
||||||
// wtxn.commit();
|
|
||||||
// }
|
|
||||||
// catch (lmdb::error& e)
|
|
||||||
// {
|
|
||||||
// cerr << e.what() << endl;
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
bool
|
|
||||||
search(const string& key,
|
|
||||||
vector<string>& found_tx_hashes,
|
|
||||||
const string& db_name = "key_images")
|
|
||||||
{
|
|
||||||
unsigned int flags = MDB_DUPSORT | MDB_DUPFIXED;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
lmdb::txn rtxn = lmdb::txn::begin(m_env, nullptr, MDB_RDONLY);
|
|
||||||
lmdb::dbi rdbi = lmdb::dbi::open(rtxn, db_name.c_str(), flags);
|
|
||||||
lmdb::cursor cr = lmdb::cursor::open(rtxn, rdbi);
|
|
||||||
|
|
||||||
lmdb::val key_to_find{key};
|
|
||||||
lmdb::val tx_hash_val;
|
|
||||||
|
|
||||||
// set cursor the the first item
|
|
||||||
if (cr.get(key_to_find, tx_hash_val, MDB_SET))
|
|
||||||
{
|
|
||||||
//cout << key_val_to_str(key_to_find, tx_hash_val) << endl;
|
|
||||||
found_tx_hashes.push_back(string(tx_hash_val.data(), tx_hash_val.size()));
|
|
||||||
|
|
||||||
// process other values for the same key
|
|
||||||
while (cr.get(key_to_find, tx_hash_val, MDB_NEXT_DUP))
|
|
||||||
{
|
|
||||||
//cout << key_val_to_str(key_to_find, tx_hash_val) << endl;
|
|
||||||
found_tx_hashes.push_back(string(tx_hash_val.data(), tx_hash_val.size()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
cr.close();
|
|
||||||
rtxn.abort();
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (lmdb::error& e)
|
|
||||||
{
|
|
||||||
cerr << e.what() << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
get_output_amount(const string& key,
|
|
||||||
uint64_t& amount,
|
|
||||||
const string& db_name = "output_amounts")
|
|
||||||
{
|
|
||||||
|
|
||||||
unsigned int flags = 0;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
lmdb::txn rtxn = lmdb::txn::begin(m_env, nullptr, MDB_RDONLY);
|
|
||||||
lmdb::dbi rdbi = lmdb::dbi::open(rtxn, db_name.c_str(), flags);
|
|
||||||
|
|
||||||
lmdb::val key_to_find{key};
|
|
||||||
lmdb::val amount_val;
|
|
||||||
|
|
||||||
if(!rdbi.get(rtxn, key_to_find, amount_val))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
amount = *(amount_val.data<uint64_t>());
|
|
||||||
|
|
||||||
rtxn.abort();
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (lmdb::error& e)
|
|
||||||
{
|
|
||||||
cerr << e.what() << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
get_output_info(uint64_t key_timestamp,
|
|
||||||
vector<output_info>& out_infos,
|
|
||||||
const string& db_name = "output_info")
|
|
||||||
{
|
|
||||||
|
|
||||||
unsigned int flags = 0;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
lmdb::txn rtxn = lmdb::txn::begin(m_env, nullptr, MDB_RDONLY);
|
|
||||||
lmdb::dbi rdbi = lmdb::dbi::open(rtxn, db_name.c_str(), flags);
|
|
||||||
|
|
||||||
lmdb::val key_to_find{static_cast<void*>(&key_timestamp),
|
|
||||||
sizeof(key_timestamp)};
|
|
||||||
lmdb::val info_val;
|
|
||||||
|
|
||||||
lmdb::cursor cr = lmdb::cursor::open(rtxn, rdbi);
|
|
||||||
|
|
||||||
// set cursor the the first item
|
|
||||||
if (cr.get(key_to_find, info_val, MDB_SET_RANGE))
|
|
||||||
{
|
|
||||||
out_infos.push_back(*(info_val.data<output_info>()));
|
|
||||||
|
|
||||||
// process other values for the same key
|
|
||||||
while (cr.get(key_to_find, info_val, MDB_NEXT_DUP))
|
|
||||||
{
|
|
||||||
//cout << key_val_to_str(key_to_find, tx_hash_val) << endl;
|
|
||||||
out_infos.push_back(*(info_val.data<output_info>()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
rtxn.abort();
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (lmdb::error& e)
|
|
||||||
{
|
|
||||||
cerr << e.what() << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
get_output_info_range(uint64_t key_timestamp_start,
|
|
||||||
uint64_t key_timestamp_end,
|
|
||||||
vector<pair<uint64_t, output_info>>& out_infos,
|
|
||||||
const string& db_name = "output_info")
|
|
||||||
{
|
|
||||||
|
|
||||||
unsigned int flags = 0;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
lmdb::txn rtxn = lmdb::txn::begin(m_env, nullptr, MDB_RDONLY);
|
|
||||||
lmdb::dbi rdbi = lmdb::dbi::open(rtxn, db_name.c_str(), flags);
|
|
||||||
|
|
||||||
lmdb::val key_to_find{static_cast<void*>(&key_timestamp_start),
|
|
||||||
sizeof(key_timestamp_start)};
|
|
||||||
lmdb::val info_val;
|
|
||||||
|
|
||||||
lmdb::cursor cr = lmdb::cursor::open(rtxn, rdbi);
|
|
||||||
|
|
||||||
uint64_t current_timestamp = key_timestamp_start;
|
|
||||||
|
|
||||||
// set cursor the the first item
|
|
||||||
if (cr.get(key_to_find, info_val, MDB_SET_RANGE))
|
|
||||||
{
|
|
||||||
|
|
||||||
current_timestamp = *key_to_find.data<uint64_t>();
|
|
||||||
|
|
||||||
if (current_timestamp > key_timestamp_end)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
out_infos.push_back(make_pair(
|
|
||||||
current_timestamp,
|
|
||||||
*(info_val.data<output_info>())));
|
|
||||||
|
|
||||||
// process other values for the same key
|
|
||||||
while (cr.get(key_to_find, info_val, MDB_NEXT))
|
|
||||||
{
|
|
||||||
current_timestamp = *key_to_find.data<uint64_t>();
|
|
||||||
|
|
||||||
if (current_timestamp > key_timestamp_end)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
out_infos.push_back(make_pair(
|
|
||||||
current_timestamp,
|
|
||||||
*(info_val.data<output_info>())));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
rtxn.abort();
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (lmdb::error& e)
|
|
||||||
{
|
|
||||||
cerr << e.what() << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns sorted and unique tx hashes withing a
|
|
||||||
* given timestamp range
|
|
||||||
*
|
|
||||||
* @param key_timestamp_start
|
|
||||||
* @param key_timestamp_end
|
|
||||||
* @param out_txs
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
bool
|
|
||||||
get_txs_from_timestamp_range(uint64_t key_timestamp_start,
|
|
||||||
uint64_t key_timestamp_end,
|
|
||||||
vector<crypto::hash>& out_txs)
|
|
||||||
{
|
|
||||||
using output_pair = pair<uint64_t, output_info>;
|
|
||||||
|
|
||||||
auto sort_by_timestamp = [](const output_pair& l,
|
|
||||||
const output_pair& r)
|
|
||||||
{
|
|
||||||
return l.first < r.first;
|
|
||||||
};
|
|
||||||
|
|
||||||
vector<output_pair> out_infos;
|
|
||||||
|
|
||||||
if (get_output_info_range(key_timestamp_start,
|
|
||||||
key_timestamp_end,
|
|
||||||
out_infos))
|
|
||||||
{
|
|
||||||
|
|
||||||
set<output_pair, decltype(sort_by_timestamp)> unique_txs(sort_by_timestamp);
|
|
||||||
|
|
||||||
for (auto oi: out_infos)
|
|
||||||
unique_txs.insert(oi);
|
|
||||||
|
|
||||||
for (auto ut: unique_txs)
|
|
||||||
out_txs.push_back(ut.second.tx_hash);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
for_all_outputs(
|
|
||||||
std::function<bool(public_key& out_pubkey,
|
|
||||||
output_info& out_info)> f)
|
|
||||||
{
|
|
||||||
unsigned int flags = MDB_DUPSORT | MDB_DUPFIXED;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
lmdb::txn rtxn = lmdb::txn::begin(m_env, nullptr, MDB_RDONLY);
|
|
||||||
lmdb::dbi rdbi = lmdb::dbi::open(rtxn, "output_info", flags);
|
|
||||||
lmdb::cursor cr = lmdb::cursor::open(rtxn, rdbi);
|
|
||||||
|
|
||||||
lmdb::val key_to_find;
|
|
||||||
lmdb::val amount_val;
|
|
||||||
|
|
||||||
|
|
||||||
// process all values for the same key
|
|
||||||
while (cr.get(key_to_find, amount_val, MDB_NEXT))
|
|
||||||
{
|
|
||||||
public_key pub_key;
|
|
||||||
|
|
||||||
hex_to_pod(string(key_to_find.data(), key_to_find.size()),
|
|
||||||
pub_key);
|
|
||||||
|
|
||||||
output_info out_info = *(amount_val.data<output_info>());
|
|
||||||
|
|
||||||
if (f(pub_key, out_info) == false)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cr.close();
|
|
||||||
rtxn.abort();
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (lmdb::error& e)
|
|
||||||
{
|
|
||||||
cerr << e.what() << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
print_all(const string& db_name)
|
|
||||||
{
|
|
||||||
unsigned int flags = MDB_DUPSORT | MDB_DUPFIXED;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
lmdb::txn rtxn = lmdb::txn::begin(m_env, nullptr, MDB_RDONLY);
|
|
||||||
lmdb::dbi rdbi = lmdb::dbi::open(rtxn, db_name.c_str(), flags);
|
|
||||||
lmdb::cursor cr = lmdb::cursor::open(rtxn, rdbi);
|
|
||||||
|
|
||||||
lmdb::val key_to_find;
|
|
||||||
lmdb::val tx_hash_val;
|
|
||||||
|
|
||||||
|
|
||||||
// process other values for the same key
|
|
||||||
while (cr.get(key_to_find, tx_hash_val, MDB_NEXT))
|
|
||||||
{
|
|
||||||
cout << key_val_to_str(key_to_find, tx_hash_val) << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
cr.close();
|
|
||||||
rtxn.abort();
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (lmdb::error& e)
|
|
||||||
{
|
|
||||||
cerr << e.what() << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t
|
|
||||||
get_blockchain_height(string blk_path = "/home/mwo/.blockchain/lmdb")
|
|
||||||
{
|
|
||||||
uint64_t height {0};
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
auto env = lmdb::env::create();
|
|
||||||
env.set_mapsize(DEFAULT_MAPSIZE * 3);
|
|
||||||
env.set_max_dbs(20);
|
|
||||||
env.open(blk_path.c_str(), MDB_CREATE, 0664);
|
|
||||||
|
|
||||||
//auto rtxn = lmdb::txn::begin(env, nullptr, MDB_RDONLY);
|
|
||||||
auto rtxn = lmdb::txn::begin(env, nullptr);
|
|
||||||
auto rdbi = lmdb::dbi::open(rtxn, "blocks");
|
|
||||||
|
|
||||||
MDB_stat stats = rdbi.stat(rtxn);
|
|
||||||
|
|
||||||
height = static_cast<uint64_t>(stats.ms_entries);
|
|
||||||
|
|
||||||
rtxn.abort();
|
|
||||||
}
|
|
||||||
catch (lmdb::error& e)
|
|
||||||
{
|
|
||||||
cerr << e.what() << endl;
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
catch (exception& e)
|
|
||||||
{
|
|
||||||
cerr << e.what() << endl;
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
//cout << height << endl;
|
|
||||||
|
|
||||||
return height;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
string
|
|
||||||
key_val_to_str(const lmdb::val& key, const lmdb::val& val)
|
|
||||||
{
|
|
||||||
return "key: " + string(key.data(), key.size())
|
|
||||||
+ ", val: " + string(val.data(), val.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //XMRLMDBCPP_MYLMDB_H
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue