feat support lazy
All checks were successful
rpcrypto-build / build (Debug, himix200.toolchain.cmake) (push) Successful in 1m4s
rpcrypto-build / build (Debug, hisiv510.toolchain.cmake) (push) Successful in 1m6s
rpcrypto-build / build (Release, himix200.toolchain.cmake) (push) Successful in 1m16s
rpcrypto-build / build (Release, hisiv510.toolchain.cmake) (push) Successful in 1m16s
linux-hisiv500-gcc / linux-gcc-hisiv500 (push) Successful in 1m21s
linux-mips64-gcc / linux-gcc-mips64el (push) Successful in 1m24s
linux-x64-gcc / linux-gcc (push) Successful in 1m32s
All checks were successful
rpcrypto-build / build (Debug, himix200.toolchain.cmake) (push) Successful in 1m4s
rpcrypto-build / build (Debug, hisiv510.toolchain.cmake) (push) Successful in 1m6s
rpcrypto-build / build (Release, himix200.toolchain.cmake) (push) Successful in 1m16s
rpcrypto-build / build (Release, hisiv510.toolchain.cmake) (push) Successful in 1m16s
linux-hisiv500-gcc / linux-gcc-hisiv500 (push) Successful in 1m21s
linux-mips64-gcc / linux-gcc-mips64el (push) Successful in 1m24s
linux-x64-gcc / linux-gcc (push) Successful in 1m32s
This commit is contained in:
parent
076464f1d4
commit
a846570ebb
965
3party/nonstd/ulib/lazy.h
Normal file
965
3party/nonstd/ulib/lazy.h
Normal file
@ -0,0 +1,965 @@
|
||||
/**
|
||||
* \file Lazy.hpp
|
||||
*
|
||||
* \brief This is the main include file for the \c Lazy library.
|
||||
*
|
||||
* Including this gives access to \c lazy::Lazy<T> and the utility
|
||||
* \c lazy::make_lazy functions.
|
||||
*
|
||||
*
|
||||
* \author Matthew Rodusek (matthew.rodusek@gmail.com)
|
||||
* \copyright Matthew Rodusek
|
||||
*/
|
||||
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
* Copyright (c) 2016 Matthew Rodusek <http://rodusek.me>
|
||||
*
|
||||
* 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 LAZY_LAZY_HPP_
|
||||
#define LAZY_LAZY_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace lazy {
|
||||
|
||||
namespace detail {
|
||||
|
||||
// c++14 index sequence
|
||||
|
||||
/// \brief type-trait to expand into a sequence of integers
|
||||
///
|
||||
/// \note This is included in c++14 under 'utility', but not in c++11
|
||||
template<typename T, T... Ints>
|
||||
class integer_sequence {
|
||||
static constexpr std::size_t size() { return sizeof...(Ints); }
|
||||
};
|
||||
|
||||
/// \brief Type alias of the common-case for integer sequences of std::size_t
|
||||
template<std::size_t... Ints>
|
||||
using index_sequence = integer_sequence<std::size_t, Ints...>;
|
||||
|
||||
/// \brief type-trait helper to build an integer sequence
|
||||
template<std::size_t Start, std::size_t N, std::size_t... Ints>
|
||||
struct build_index_sequence
|
||||
: public build_index_sequence<Start, N - 1, N - 1, Ints...> {};
|
||||
|
||||
template<std::size_t Start, std::size_t... Ints>
|
||||
struct build_index_sequence<Start, Start, Ints...> {
|
||||
typedef index_sequence<Ints...> type;
|
||||
};
|
||||
|
||||
/// \brief type-trait helper to build an index sequence from 0 to N
|
||||
template<std::size_t N>
|
||||
using make_index_sequence = typename build_index_sequence<0, N>::type;
|
||||
|
||||
/// \brief type-trait helper to build an index sequence of 0 to Args indices
|
||||
template<typename... Args>
|
||||
using index_sequence_for = make_index_sequence<sizeof...(Args)>;
|
||||
|
||||
template<bool b>
|
||||
using boolean_constant = std::integral_constant<bool, b>;
|
||||
|
||||
/// \brief Type-trait for identities (always defines \c T as \c type)
|
||||
///
|
||||
/// This aliases \c T as \c ::type
|
||||
template<typename T>
|
||||
struct identity {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
/// \brief Type trait for getting the nth argument type from a variadic
|
||||
/// template.
|
||||
///
|
||||
/// This is used for composition in \c function_traits
|
||||
///
|
||||
/// The result is aliased as \c ::type
|
||||
template<std::size_t n, typename... Args>
|
||||
struct arg_tuple
|
||||
: public identity<
|
||||
typename std::tuple_element<n, std::tuple<Args...>>::type> {
|
||||
static_assert(n >= sizeof...(Args), "Index out of range");
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
/// \brief Identity type-trait for all function traits to inherit from
|
||||
///
|
||||
/// This type is only used in composition.
|
||||
///
|
||||
/// This aliases the following common types:
|
||||
/// - The number of arguments to the function as \c ::arity
|
||||
/// - The type of the return as \c ::result_type
|
||||
/// - The nth argument as \c ::arg<n>::type
|
||||
template<typename Ret, typename... Args>
|
||||
struct function_traits_identity {
|
||||
static constexpr std::size_t arity = sizeof...(Args);/// Number of arguments
|
||||
|
||||
typedef Ret result_type;/// Return type
|
||||
|
||||
template<std::size_t n>
|
||||
using arg = arg_tuple<n, Args...>;/// Alias of the nth arg
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
/// \brief Type traits for retrieving various parts of a function
|
||||
///
|
||||
/// This aliases the following
|
||||
/// - The number of arguments to the function as \c ::arity
|
||||
/// - The type of the return as \c ::result_type
|
||||
/// - The nth argument as \c ::arg<n>::type
|
||||
template<typename T>
|
||||
struct function_traits_impl {
|
||||
static_assert(std::is_function<T>::value, "T must be function type!");
|
||||
};
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
struct function_traits_impl<Ret(Args...)>
|
||||
: public function_traits_identity<Ret, Args...> {};
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
struct function_traits_impl<Ret (*)(Args...)>
|
||||
: public function_traits_identity<Ret, Args...> {};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
/// \brief Type traits for retrieving various parts of a member function
|
||||
///
|
||||
/// This aliases the following
|
||||
/// - The number of arguments to the function as \c ::arity
|
||||
/// - The type of the return as \c ::result_type
|
||||
/// - The nth argument as \c ::arg<n>::type
|
||||
template<typename T>
|
||||
struct member_function_traits_impl {
|
||||
static_assert(std::is_member_function_pointer<T>::value,
|
||||
"T must be member function pointer!");
|
||||
};
|
||||
|
||||
template<typename C, typename Ret, typename... Args>
|
||||
struct member_function_traits_impl<Ret (C::*)(Args...)>
|
||||
: public function_traits_identity<Ret, Args...> {};
|
||||
|
||||
template<typename C, typename Ret, typename... Args>
|
||||
struct member_function_traits_impl<Ret (C::*)(Args...) const>
|
||||
: public function_traits_identity<Ret, Args...> {};
|
||||
|
||||
template<typename C, typename Ret, typename... Args>
|
||||
struct member_function_traits_impl<Ret (C::*)(Args...) volatile>
|
||||
: public function_traits_identity<Ret, Args...> {};
|
||||
|
||||
template<typename C, typename Ret, typename... Args>
|
||||
struct member_function_traits_impl<Ret (C::*)(Args...) const volatile>
|
||||
: public function_traits_identity<Ret, Args...> {};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
/// \brief Type trait for retrieving various parts of a functor
|
||||
///
|
||||
/// This aliases the following
|
||||
/// - The number of arguments to the function as \c ::arity
|
||||
/// - The type of the return as \c ::result_type
|
||||
/// - The nth argument as \c ::arg<n>::type
|
||||
template<typename T>
|
||||
struct functor_traits_impl
|
||||
: public member_function_traits_impl<decltype(&T::operator())> {
|
||||
static_assert(std::is_class<T>::value, "T must be a class type!");
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
/// \brief Type traits to retrieve the various parts of a callable
|
||||
/// function-like object
|
||||
///
|
||||
/// This aliases the following
|
||||
/// - The number of arguments to the function as \c ::arity
|
||||
/// - The type of the return as \c ::result_type
|
||||
/// - The nth argument as \c ::arg<n>::type
|
||||
///
|
||||
/// \tparam T the function to retrieve types for
|
||||
template<typename T>
|
||||
struct function_traits
|
||||
: public std::conditional<
|
||||
std::is_class<T>::value,
|
||||
functor_traits_impl<T>,
|
||||
typename std::conditional<std::is_member_function_pointer<T>::value,
|
||||
member_function_traits_impl<T>,
|
||||
function_traits_impl<T>>::type>::type {};
|
||||
|
||||
/// \brief Type trait for determining whether the given type is a functor
|
||||
///
|
||||
/// This only works for normal, non-templated operator() types
|
||||
///
|
||||
/// This aliases the result as \c ::value
|
||||
template<typename T>
|
||||
class is_functor {
|
||||
typedef char yes_type;
|
||||
typedef char (&no_type)[2];
|
||||
|
||||
template<typename C>
|
||||
static yes_type test(decltype(&C::operator()));
|
||||
template<typename C>
|
||||
static no_type(&test(...));
|
||||
|
||||
public:
|
||||
static constexpr bool value = sizeof(test<T>(0)) == sizeof(yes_type);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
/// \brief type-trait to determine if a type provided is a \c std::tuple
|
||||
///
|
||||
/// \note this also detects \c std::pair
|
||||
///
|
||||
/// The result is aliased as \c ::value
|
||||
template<typename T>
|
||||
struct is_tuple : public std::false_type {};
|
||||
|
||||
template<typename... Args>
|
||||
struct is_tuple<std::tuple<Args...>> : public std::true_type {};
|
||||
|
||||
template<typename... Args>
|
||||
struct is_tuple<std::pair<Args...>> : public std::true_type {};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
/// \brief type-trait that behaves like \c std::is_constructible<T>,
|
||||
/// but determines whether a tuple contains argument types
|
||||
/// that allow construction of the supplied type \c T
|
||||
///
|
||||
/// The result is aliased as \c ::value
|
||||
template<typename T, typename Tuple>
|
||||
struct is_tuple_constructible : public std::false_type {};
|
||||
|
||||
template<typename T, typename... Args>
|
||||
struct is_tuple_constructible<T, std::tuple<Args...>>
|
||||
: public std::is_constructible<T, Args...> {};
|
||||
|
||||
template<typename T, typename... Args>
|
||||
struct is_tuple_constructible<T, std::pair<Args...>>
|
||||
: public std::is_constructible<T, Args...> {};
|
||||
|
||||
/// \brief Type trait to determine whether or not the type \c T is
|
||||
/// a callable (function, member function, functor)
|
||||
///
|
||||
/// The result is aliased as \c ::type
|
||||
template<typename T>
|
||||
struct is_callable
|
||||
: std::conditional<
|
||||
std::is_class<T>::value,
|
||||
detail::is_functor<T>,
|
||||
typename std::conditional<std::is_member_function_pointer<T>::value,
|
||||
std::is_member_function_pointer<T>,
|
||||
std::is_function<T>>::type>::type {};
|
||||
|
||||
}// namespace detail
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief Lazy class used for lazy-loading any type
|
||||
///
|
||||
/// The stored lazy-loaded class, \c T, will always be instantiated
|
||||
/// before being accessed, and destructed when put out of scope.
|
||||
///
|
||||
/// \tparam T the type contained within this \c Lazy
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
template<typename T>
|
||||
class Lazy final {
|
||||
//------------------------------------------------------------------------
|
||||
// Public Member Types
|
||||
//------------------------------------------------------------------------
|
||||
public:
|
||||
using this_type = Lazy<T>;///< Instance of this type
|
||||
|
||||
using value_type = T; ///< The underlying type of this Lazy
|
||||
using pointer = T *; ///< The pointer type of the Lazy
|
||||
using reference = T &;///< The reference type of the Lazy
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Construction / Destruction / Assignment
|
||||
//------------------------------------------------------------------------
|
||||
public:
|
||||
/// \brief Default constructor; no initialization takes place
|
||||
Lazy();
|
||||
|
||||
/// \brief Constructs a \c Lazy given the \p constructor and \p destructor
|
||||
/// functions
|
||||
///
|
||||
/// \note The \p constructor function must return a \c std::tuple containing
|
||||
/// the arguments to pass to \c T's constructor for lazy-construction
|
||||
///
|
||||
/// \param constructor function to use for construction
|
||||
/// \param destructor function to use prior to destruction
|
||||
template<
|
||||
typename CtorFunc,
|
||||
typename DtorFunc = void(value_type &),
|
||||
typename =
|
||||
typename std::enable_if<detail::is_callable<CtorFunc>::value>::type,
|
||||
typename =
|
||||
typename std::enable_if<detail::is_callable<DtorFunc>::value>::type>
|
||||
explicit Lazy(const CtorFunc &constructor,
|
||||
const DtorFunc &destructor = default_destructor);
|
||||
|
||||
/// \brief Constructs a \c Lazy by copying another \c Lazy
|
||||
///
|
||||
/// \note If \p rhs is initialized, then this copy will also be initialized
|
||||
///
|
||||
/// \param rhs the \c Lazy to copy
|
||||
Lazy(const Lazy<T> &rhs);
|
||||
|
||||
/// \brief Constructs a \c Lazy by moving another \c Lazy
|
||||
///
|
||||
/// \note If \p rhs is initialized, then this moved version will
|
||||
/// also be initialized
|
||||
///
|
||||
/// \param rhs the \c Lazy to move
|
||||
Lazy(Lazy<T> &&rhs);
|
||||
|
||||
/// \brief Constructs a \c Lazy by calling \c T's copy constructor
|
||||
///
|
||||
/// \note This does not initialize the \c Lazy. Instead, it stores this value as
|
||||
/// a copy and move-constructs it later, if necessary
|
||||
///
|
||||
/// \param rhs the \c T to copy
|
||||
explicit Lazy(const value_type &rhs);
|
||||
|
||||
/// \brief Constructs a \c Lazy from a given rvalue \c T
|
||||
///
|
||||
/// \note This does not initialize the \c Lazy. Instead, it stores this value as
|
||||
/// a copy and move-constructs it later, if necessary
|
||||
///
|
||||
/// \param rhs the \c T to move
|
||||
explicit Lazy(value_type &&rhs);
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
/// \brief Destructs this \c Lazy and it's \c T
|
||||
~Lazy();
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
/// \brief Assigns a \c Lazy to this \c Lazy
|
||||
///
|
||||
/// \note This will construct a new \c T if the \c Lazy is not already
|
||||
/// initialized, otherwise it will assign
|
||||
///
|
||||
/// \param rhs the \c Lazy on the right-side of the assignment
|
||||
/// \return reference to (*this)
|
||||
this_type &operator=(const this_type &rhs);
|
||||
|
||||
/// \brief Assigns a \c Lazy to this \c Lazy
|
||||
///
|
||||
/// \note This will construct a new \c T if the \c Lazy is not already
|
||||
/// initialized, otherwise it will assign
|
||||
///
|
||||
/// \param rhs the rvalue \c Lazy on the right-side of the assignment
|
||||
/// \return reference to (*this)
|
||||
this_type &operator=(this_type &&rhs);
|
||||
|
||||
/// \brief Assigns a \c T to this \c Lazy
|
||||
///
|
||||
/// \note This will construct a new \c T if the \c Lazy is not already
|
||||
/// initialized, otherwise it will assign
|
||||
///
|
||||
/// \param rhs the \c T on the right-side of the assignment
|
||||
/// \return reference to (\c ptr())
|
||||
value_type &operator=(const value_type &rhs);
|
||||
|
||||
/// \brief Assigns an rvalue \c T to this \c Lazy
|
||||
///
|
||||
/// \note This will construct a new \c T if the \c Lazy is not already
|
||||
/// initialized, otherwise it will assign
|
||||
///
|
||||
/// \param rhs the \c T on the right-side of the assignment
|
||||
/// \return reference to (\c ptr())
|
||||
value_type &operator=(value_type &&rhs);
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Casting
|
||||
//------------------------------------------------------------------------
|
||||
public:
|
||||
/// \brief Converts this \c Lazy into a reference
|
||||
///
|
||||
/// \return the reference to the lazy-loaded object
|
||||
explicit operator reference() const;
|
||||
|
||||
/// \brief Checks whether this \c Lazy has an instantiated object
|
||||
///
|
||||
/// \return \c true if this lazy has an instantiated object
|
||||
explicit operator bool() const noexcept;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Operators
|
||||
//------------------------------------------------------------------------
|
||||
public:
|
||||
/// \brief Swapperator class for no-exception swapping
|
||||
///
|
||||
/// \param rhs the rhs to swap
|
||||
void swap(Lazy<T> &rhs) noexcept;
|
||||
|
||||
/// \brief Boolean to check if this \c Lazy is initialized.
|
||||
///
|
||||
/// \return \c true if the underlying type \c T is initialized.
|
||||
bool is_initialized() const noexcept;
|
||||
|
||||
/// \brief Gets a pointer to the underlying type
|
||||
///
|
||||
/// \note This has been added to have a similar API to smart pointers
|
||||
///
|
||||
/// \return the pointer to the underlying type
|
||||
pointer get() const;
|
||||
|
||||
/// \brief Dereferences this \c Lazy object into the lazy-loaded object
|
||||
///
|
||||
/// \return a constant reference to the lazy-loaded object
|
||||
reference operator*() const;
|
||||
|
||||
/// \brief Dereferences this \c Lazy object into the lazy-loaded object
|
||||
///
|
||||
/// \return a pointer to the lazy-loaded object
|
||||
pointer operator->() const;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Private Member Types
|
||||
//------------------------------------------------------------------------
|
||||
private:
|
||||
/// \brief Constructor tag for tag-dispatching VA Arguments
|
||||
struct ctor_va_args_tag {};
|
||||
|
||||
using unqualified_pointer = typename std::remove_cv<T>::type *;
|
||||
using ctor_function_type = std::function<void()>;
|
||||
using dtor_function_type = std::function<void(T &)>;
|
||||
|
||||
using storage_type =
|
||||
typename std::aligned_storage<sizeof(T), alignof(T)>::type;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Private Members
|
||||
//------------------------------------------------------------------------
|
||||
private:
|
||||
mutable storage_type m_storage; ///< The storage to hold the lazy type
|
||||
mutable bool m_is_initialized; ///< Is the type initialized?
|
||||
ctor_function_type m_constructor;///< The construction function
|
||||
dtor_function_type m_destructor; ///< The destruction function
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Private Static Member Functions
|
||||
//------------------------------------------------------------------------
|
||||
private:
|
||||
/// \brief A default destructor function for this Lazy object
|
||||
///
|
||||
/// \param x the \c T type to be destructed
|
||||
static void default_destructor(value_type &x) noexcept;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Private Constructor
|
||||
//------------------------------------------------------------------------
|
||||
private:
|
||||
/// \brief Constructs a \c Lazy by constructing it's \c T with its constructor
|
||||
///
|
||||
/// \param tag unused tag for dispatching to VA constructor
|
||||
/// \param args arguments to \c T's constructor
|
||||
template<typename... Args>
|
||||
explicit Lazy(ctor_va_args_tag tag, Args &&...args);
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Private Member Functions
|
||||
//------------------------------------------------------------------------
|
||||
private:
|
||||
/// \brief Gets a pointer to the data stored in this \c Laz
|
||||
///
|
||||
/// \return the constant pointer to the object
|
||||
unqualified_pointer ptr() const noexcept;
|
||||
|
||||
/// \brief Forcibly initializes the \c Lazy
|
||||
void lazy_construct() const;
|
||||
|
||||
/// \brief Constructs a \c Lazy object using \c T's copy constructor
|
||||
///
|
||||
/// \param x Instance of \c T to copy.
|
||||
void construct(const value_type &x) const;
|
||||
|
||||
/// \brief Constructs a \c Lazy object using \c T's move constructor
|
||||
///
|
||||
/// \param x Instance of rvalue \c T to copy
|
||||
void construct(value_type &&x) const;
|
||||
|
||||
/// \brief Constructs a \c Lazy object using the arguments for \c T's constructor
|
||||
///
|
||||
/// \param tag tag to dispatch to this VA args constructor
|
||||
/// \param args the arguments to forward to the constructor
|
||||
template<typename... Args>
|
||||
void construct(ctor_va_args_tag tag, Args &&...args) const;
|
||||
|
||||
/// \brief Constructs a \c Lazy object using the arguments provided in a
|
||||
/// \c std::tuple for \c T's constructor
|
||||
///
|
||||
/// \param tag the tag for tag-dispatching
|
||||
/// \param args the arguments to forward to the constructor
|
||||
template<typename... Args>
|
||||
void construct(const std::tuple<Args...> &args) const;
|
||||
|
||||
/// \brief Constructs a \c lazy object by passing all values stored in a
|
||||
/// \c std::tuple to \c T's constructor
|
||||
///
|
||||
/// \param unused unused parameter for getting index list
|
||||
template<typename... Args, std::size_t... Is>
|
||||
void tuple_construct(const std::tuple<Args...> &args,
|
||||
const detail::index_sequence<Is...> &unused) const
|
||||
noexcept(std::is_nothrow_constructible<T, Args...>::value);
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
/// \brief Destructs the \c Lazy object
|
||||
void destruct() const;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
/// \brief Copy-assigns type at \c rhs
|
||||
///
|
||||
/// \param rhs the value to assign
|
||||
void assign(const value_type &rhs) const
|
||||
noexcept(std::is_nothrow_copy_assignable<T>::value);
|
||||
|
||||
/// \brief Copy-assigns type at \c rhs
|
||||
///
|
||||
/// \param rhs the value to assign
|
||||
void assign(value_type &&rhs) const
|
||||
noexcept(std::is_nothrow_move_assignable<T>::value);
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Friends
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
template<typename U, typename... Args>
|
||||
friend Lazy<U> make_lazy(Args &&...args);
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Utilities
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/// \brief Convenience utility to construct a \c Lazy object by specifying
|
||||
/// \c T's constructor signature.
|
||||
///
|
||||
/// The arguments are stored by copy until the object is constructed in order
|
||||
/// to avoid dangling references.
|
||||
///
|
||||
/// \param args the arguments to the constructor
|
||||
/// \return an instance of the \c Lazy object
|
||||
template<typename T, typename... Args>
|
||||
Lazy<T> make_lazy(Args &&...args);
|
||||
|
||||
/// \brief Implementation of \c swap for custom swapperations using ADL
|
||||
///
|
||||
/// \param lhs the left-hand \c Lazy object
|
||||
/// \param rhs the right-hand \c Lazy object
|
||||
template<typename T>
|
||||
void swap(Lazy<T> &lhs, Lazy<T> &rhs) noexcept;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Constructors / Destructor / Assignment
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
inline Lazy<T>::Lazy()
|
||||
: m_storage(),
|
||||
m_is_initialized(false),
|
||||
m_constructor([this]() { this->construct(ctor_va_args_tag()); }),
|
||||
m_destructor(default_destructor)
|
||||
{
|
||||
static_assert(std::is_default_constructible<T>::value,
|
||||
"No matching default constructor for type T");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename CtorFunc, typename DtorFunc, typename, typename>
|
||||
inline Lazy<T>::Lazy(const CtorFunc &constructor, const DtorFunc &destructor)
|
||||
: m_storage(),
|
||||
m_is_initialized(false),
|
||||
m_constructor([this, constructor]() { this->construct(constructor()); }),
|
||||
m_destructor(destructor)
|
||||
{
|
||||
using return_type = typename detail::function_traits<CtorFunc>::result_type;
|
||||
|
||||
static_assert(detail::is_tuple<return_type>::value,
|
||||
"Lazy-construction functions must return tuples containing "
|
||||
"constructor arguments");
|
||||
static_assert(detail::is_tuple_constructible<T, return_type>::value,
|
||||
"No matching constructor for type T with given arguments");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline Lazy<T>::Lazy(const this_type &rhs)
|
||||
: m_storage(),
|
||||
m_is_initialized(false),
|
||||
m_constructor(rhs.m_constructor),
|
||||
m_destructor(rhs.m_destructor)
|
||||
{
|
||||
static_assert(std::is_copy_constructible<T>::value,
|
||||
"No matching copy constructor for type T");
|
||||
|
||||
if (rhs.m_is_initialized) { construct(*rhs); }
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline Lazy<T>::Lazy(this_type &&rhs)
|
||||
: m_storage(),
|
||||
m_is_initialized(false),
|
||||
m_constructor(std::move(rhs.m_constructor)),
|
||||
m_destructor(std::move(rhs.m_destructor))
|
||||
{
|
||||
static_assert(std::is_move_constructible<T>::value,
|
||||
"No matching move constructor for type T");
|
||||
|
||||
if (rhs.m_is_initialized) { construct(std::move(*rhs)); }
|
||||
rhs.m_constructor = nullptr;
|
||||
rhs.m_destructor = nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline Lazy<T>::Lazy(const value_type &rhs)
|
||||
: m_storage(),
|
||||
m_is_initialized(false),
|
||||
m_constructor([this, rhs]() { this->construct(std::move(rhs)); }),
|
||||
m_destructor(default_destructor)
|
||||
{
|
||||
static_assert(std::is_copy_constructible<T>::value,
|
||||
"No matching copy constructor for type T");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline Lazy<T>::Lazy(value_type &&rhs)
|
||||
: m_storage(),
|
||||
m_is_initialized(false),
|
||||
m_constructor([this, rhs]() { this->construct(std::move(rhs)); }),
|
||||
m_destructor(default_destructor)
|
||||
{
|
||||
static_assert(std::is_move_constructible<T>::value,
|
||||
"No matching move constructor for type T");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
inline Lazy<T>::~Lazy()
|
||||
{
|
||||
destruct();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
inline Lazy<T> &
|
||||
Lazy<T>::operator=(const this_type &rhs)
|
||||
{
|
||||
static_assert(std::is_copy_assignable<T>::value,
|
||||
"No matching copy assignment operator for type T");
|
||||
static_assert(std::is_copy_constructible<T>::value,
|
||||
"No matching copy constructor for type T");
|
||||
|
||||
if (rhs.m_is_initialized) {
|
||||
lazy_construct();
|
||||
assign(*rhs);
|
||||
} else {
|
||||
m_constructor = rhs.m_constructor;
|
||||
}
|
||||
m_destructor = rhs.m_destructor;
|
||||
|
||||
return (*this);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline typename Lazy<T>::this_type &
|
||||
Lazy<T>::operator=(this_type &&rhs)
|
||||
{
|
||||
static_assert(std::is_move_assignable<T>::value,
|
||||
"No matching move assignment operator for type T");
|
||||
static_assert(std::is_move_constructible<T>::value,
|
||||
"No matching move constructor for type T");
|
||||
|
||||
if (rhs.m_is_initialized) {
|
||||
lazy_construct();
|
||||
assign(std::move(*rhs));
|
||||
} else {
|
||||
m_constructor = std::move(rhs.m_constructor);
|
||||
rhs.m_constructor = nullptr;
|
||||
}
|
||||
m_destructor = std::move(rhs.m_destructor);
|
||||
rhs.m_destructor = nullptr;
|
||||
|
||||
return (*this);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline typename Lazy<T>::value_type &
|
||||
Lazy<T>::operator=(const value_type &rhs)
|
||||
{
|
||||
static_assert(std::is_copy_assignable<T>::value,
|
||||
"No matching copy assignment operator for type T");
|
||||
|
||||
lazy_construct();
|
||||
assign(rhs);
|
||||
|
||||
return *ptr();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline typename Lazy<T>::value_type &
|
||||
Lazy<T>::operator=(value_type &&rhs)
|
||||
{
|
||||
static_assert(std::is_move_assignable<T>::value,
|
||||
"No matching move assignment operator for type T");
|
||||
|
||||
lazy_construct();
|
||||
assign(std::forward<value_type>(rhs));
|
||||
|
||||
return *ptr();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Casting
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
inline Lazy<T>::operator reference() const
|
||||
{
|
||||
lazy_construct();
|
||||
return *ptr();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline Lazy<T>::operator bool() const noexcept
|
||||
{
|
||||
return m_is_initialized;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Operators
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
inline void
|
||||
Lazy<T>::swap(Lazy<T> &rhs) noexcept
|
||||
{
|
||||
using std::swap;// for ADL
|
||||
|
||||
swap(m_constructor, rhs.m_constructor);
|
||||
swap(m_destructor, rhs.m_destructor);
|
||||
swap(m_is_initialized, rhs.m_is_initialized);
|
||||
swap((*ptr()), (*rhs.ptr()));// Swap the values of the T types
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool
|
||||
Lazy<T>::is_initialized() const noexcept
|
||||
{
|
||||
return m_is_initialized;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline typename Lazy<T>::pointer
|
||||
Lazy<T>::get() const
|
||||
{
|
||||
lazy_construct();
|
||||
return ptr();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline typename Lazy<T>::reference
|
||||
Lazy<T>::operator*() const
|
||||
{
|
||||
lazy_construct();
|
||||
return *ptr();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline typename Lazy<T>::pointer
|
||||
Lazy<T>::operator->() const
|
||||
{
|
||||
lazy_construct();
|
||||
return ptr();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private Static Member Functions
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
inline void
|
||||
Lazy<T>::default_destructor(value_type &) noexcept
|
||||
{}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private Constructors
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
template<typename... Args>
|
||||
inline Lazy<T>::Lazy(ctor_va_args_tag, Args &&...args)
|
||||
: m_is_initialized(false),
|
||||
m_constructor([this, args...]() {
|
||||
this->construct(ctor_va_args_tag(), std::move(args)...);
|
||||
}),
|
||||
m_destructor(default_destructor)
|
||||
{
|
||||
static_assert(std::is_constructible<T, Args...>::value,
|
||||
"No matching constructor for type T with given arguments");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private Member Functions
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
inline typename Lazy<T>::unqualified_pointer
|
||||
Lazy<T>::ptr() const noexcept
|
||||
{
|
||||
// address-of idiom (https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Address_Of)
|
||||
return reinterpret_cast<unqualified_pointer>(&const_cast<char &>(
|
||||
reinterpret_cast<const volatile char &>(m_storage)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void
|
||||
Lazy<T>::lazy_construct() const
|
||||
{
|
||||
if (!m_is_initialized) {
|
||||
m_constructor();
|
||||
m_is_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void
|
||||
Lazy<T>::construct(const value_type &x) const
|
||||
{
|
||||
destruct();
|
||||
new (ptr()) value_type(x);
|
||||
m_is_initialized = true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void
|
||||
Lazy<T>::construct(value_type &&x) const
|
||||
{
|
||||
destruct();
|
||||
new (ptr()) value_type(std::forward<value_type>(x));
|
||||
m_is_initialized = true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename... Args>
|
||||
inline void
|
||||
Lazy<T>::construct(ctor_va_args_tag, Args &&...args) const
|
||||
{
|
||||
destruct();
|
||||
new (ptr()) value_type(std::forward<Args>(args)...);
|
||||
m_is_initialized = true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename... Args>
|
||||
inline void
|
||||
Lazy<T>::construct(const std::tuple<Args...> &args) const
|
||||
{
|
||||
destruct();
|
||||
tuple_construct(args, detail::index_sequence_for<Args...>());
|
||||
m_is_initialized = true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename... Args, std::size_t... Ints>
|
||||
inline void
|
||||
Lazy<T>::tuple_construct(const std::tuple<Args...> &args,
|
||||
const detail::index_sequence<Ints...> &) const
|
||||
noexcept(std::is_nothrow_constructible<T, Args...>::value)
|
||||
{
|
||||
static_assert(std::is_constructible<T, Args...>::value,
|
||||
"No matching constructor for type T with given arguments");
|
||||
|
||||
new (ptr()) T(std::get<Ints>(args)...);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void
|
||||
Lazy<T>::destruct() const
|
||||
{
|
||||
if (m_is_initialized) {
|
||||
if (m_destructor) { m_destructor(*ptr()); }
|
||||
ptr()->~T();
|
||||
m_is_initialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void
|
||||
Lazy<T>::assign(const value_type &rhs) const
|
||||
noexcept(std::is_nothrow_copy_assignable<T>::value)
|
||||
{
|
||||
(*ptr()) = rhs;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void
|
||||
Lazy<T>::assign(value_type &&rhs) const
|
||||
noexcept(std::is_nothrow_move_assignable<T>::value)
|
||||
{
|
||||
(*ptr()) = std::forward<value_type>(rhs);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Utilities
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
template<typename T, typename... Args>
|
||||
Lazy<T>
|
||||
make_lazy(Args &&...args)
|
||||
{
|
||||
return Lazy<T>(typename Lazy<T>::ctor_va_args_tag(),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void
|
||||
swap(Lazy<T> &lhs, Lazy<T> &rhs) noexcept
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
}// namespace lazy
|
||||
|
||||
//
|
||||
namespace ulib {
|
||||
template<typename T>
|
||||
using Lazy = lazy::Lazy<T>;
|
||||
using lazy::make_lazy;
|
||||
using lazy::swap;
|
||||
|
||||
}// namespace ulib
|
||||
|
||||
#endif /* LAZYLAZY_HPP_ */
|
@ -27,10 +27,9 @@ if(ULIB_SHARED_LIB)
|
||||
add_library(${PROJECT_NAME} SHARED "")
|
||||
else()
|
||||
add_library(${PROJECT_NAME} STATIC "")
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
endif()
|
||||
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
target_sources(
|
||||
${PROJECT_NAME}
|
||||
PRIVATE 3party/mongoose/mongoose.c
|
||||
|
@ -35,4 +35,23 @@ StrJoin(const std::vector<std::string> &vec,
|
||||
delimiter, ignore_empty_str);
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
StrSplit(nonstd::string_view str,
|
||||
nonstd::string_view delimiter,
|
||||
bool ignore_empty_str)
|
||||
{
|
||||
int pos = 0;
|
||||
do {
|
||||
int next_pos = str.find_first_of(delimiter);
|
||||
size_t len;
|
||||
} while (0);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
StrSplit(std::string &str, nonstd::string_view delimiter, bool ignore_empty_str)
|
||||
{
|
||||
return StrSplit(str, delimiter, ignore_empty_str);
|
||||
}
|
||||
|
||||
}// namespace ulib
|
||||
|
@ -28,5 +28,12 @@ std::string StrJoin(const std::vector<std::string> &vec,
|
||||
nonstd::string_view delimiter = ",",
|
||||
bool ignore_empty_str = true);
|
||||
|
||||
std::vector<std::string> StrSplit(nonstd::string_view vec,
|
||||
nonstd::string_view delimiter = ",",
|
||||
bool ignore_empty_str = true);
|
||||
|
||||
std::vector<std::string> StrSplit(const std::string &vec,
|
||||
nonstd::string_view delimiter = ",",
|
||||
bool ignore_empty_str = true);
|
||||
}// namespace ulib
|
||||
#endif// ULIB_SRC_ULIB_UTILS_UTILS_H_
|
||||
|
16
tests/3party/nonstd/lazy_unittest.cpp
Normal file
16
tests/3party/nonstd/lazy_unittest.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <lazy.h>
|
||||
|
||||
TEST(Lazy, Base)
|
||||
{
|
||||
bool flag = false;
|
||||
int cnt = 0;
|
||||
auto lazy = ulib::Lazy<int>([&]() {
|
||||
flag = true;
|
||||
++cnt;
|
||||
return std::make_tuple(cnt);
|
||||
});
|
||||
EXPECT_EQ(flag, false);
|
||||
EXPECT_EQ(*lazy, 1);
|
||||
EXPECT_EQ(flag, true);
|
||||
}
|
@ -7,7 +7,8 @@ set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
add_executable(
|
||||
ulib_test
|
||||
3party/eventbus/eventbus_unittest.cpp
|
||||
3party/nonstd/optional_unittest.cpp
|
||||
3party/nonstd/any_unittest.cpp
|
||||
3party/nonstd/lazy_unittest.cpp
|
||||
3party/nonstd/optional_unittest.cpp
|
||||
3party/sqlpp11/sqlpp11_unittest.cpp
|
||||
ulib/base/location_unittest.cpp
|
||||
@ -22,8 +23,7 @@ add_executable(
|
||||
ulib/system/timer_unittest.cpp
|
||||
ulib/utils/defer_unittest.cpp
|
||||
ulib/utils/fsm_unittest.cpp
|
||||
ulib/utils/utils_unittest.cpp
|
||||
)
|
||||
ulib/utils/utils_unittest.cpp)
|
||||
target_link_libraries(ulib_test PRIVATE ulib gtest gtest_main)
|
||||
|
||||
add_test(NAME ulib_test COMMAND ulib_test)
|
||||
|
Loading…
x
Reference in New Issue
Block a user