From a846570ebbf988e59a841116e9da1e32d5afb613 Mon Sep 17 00:00:00 2001 From: tqcq <99722391+tqcq@users.noreply.github.com> Date: Fri, 26 Jan 2024 11:22:30 +0800 Subject: [PATCH] feat support lazy --- 3party/nonstd/ulib/lazy.h | 965 ++++++++++++++++++++++++++ CMakeLists.txt | 3 +- src/ulib/utils/utils.cpp | 19 + src/ulib/utils/utils.h | 7 + tests/3party/nonstd/lazy_unittest.cpp | 16 + tests/CMakeLists.txt | 6 +- 6 files changed, 1011 insertions(+), 5 deletions(-) create mode 100644 3party/nonstd/ulib/lazy.h create mode 100644 tests/3party/nonstd/lazy_unittest.cpp diff --git a/3party/nonstd/ulib/lazy.h b/3party/nonstd/ulib/lazy.h new file mode 100644 index 0000000..eb046a8 --- /dev/null +++ b/3party/nonstd/ulib/lazy.h @@ -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 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 . + * Copyright (c) 2016 Matthew Rodusek + * + * 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 +#include +#include +#include + +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 +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 +using index_sequence = integer_sequence; + +/// \brief type-trait helper to build an integer sequence +template +struct build_index_sequence + : public build_index_sequence {}; + +template +struct build_index_sequence { + typedef index_sequence type; +}; + +/// \brief type-trait helper to build an index sequence from 0 to N +template +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 +using index_sequence_for = make_index_sequence; + +template +using boolean_constant = std::integral_constant; + +/// \brief Type-trait for identities (always defines \c T as \c type) +/// +/// This aliases \c T as \c ::type +template +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 +struct arg_tuple + : public identity< + typename std::tuple_element>::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::type +template +struct function_traits_identity { + static constexpr std::size_t arity = sizeof...(Args);/// Number of arguments + + typedef Ret result_type;/// Return type + + template + using arg = arg_tuple;/// 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::type +template +struct function_traits_impl { + static_assert(std::is_function::value, "T must be function type!"); +}; + +template +struct function_traits_impl + : public function_traits_identity {}; + +template +struct function_traits_impl + : public function_traits_identity {}; + +//------------------------------------------------------------------------ + +/// \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::type +template +struct member_function_traits_impl { + static_assert(std::is_member_function_pointer::value, + "T must be member function pointer!"); +}; + +template +struct member_function_traits_impl + : public function_traits_identity {}; + +template +struct member_function_traits_impl + : public function_traits_identity {}; + +template +struct member_function_traits_impl + : public function_traits_identity {}; + +template +struct member_function_traits_impl + : public function_traits_identity {}; + +//------------------------------------------------------------------------ + +/// \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::type +template +struct functor_traits_impl + : public member_function_traits_impl { + static_assert(std::is_class::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::type +/// +/// \tparam T the function to retrieve types for +template +struct function_traits + : public std::conditional< + std::is_class::value, + functor_traits_impl, + typename std::conditional::value, + member_function_traits_impl, + function_traits_impl>::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 +class is_functor { + typedef char yes_type; + typedef char (&no_type)[2]; + + template + static yes_type test(decltype(&C::operator())); + template + static no_type(&test(...)); + +public: + static constexpr bool value = sizeof(test(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 +struct is_tuple : public std::false_type {}; + +template +struct is_tuple> : public std::true_type {}; + +template +struct is_tuple> : public std::true_type {}; + +//------------------------------------------------------------------------ + +/// \brief type-trait that behaves like \c std::is_constructible, +/// 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 +struct is_tuple_constructible : public std::false_type {}; + +template +struct is_tuple_constructible> + : public std::is_constructible {}; + +template +struct is_tuple_constructible> + : public std::is_constructible {}; + +/// \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 +struct is_callable + : std::conditional< + std::is_class::value, + detail::is_functor, + typename std::conditional::value, + std::is_member_function_pointer, + std::is_function>::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 +class Lazy final { + //------------------------------------------------------------------------ + // Public Member Types + //------------------------------------------------------------------------ +public: + using this_type = Lazy;///< 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::value>::type, + typename = + typename std::enable_if::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 &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 &&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 &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::type *; + using ctor_function_type = std::function; + using dtor_function_type = std::function; + + using storage_type = + typename std::aligned_storage::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 + 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 + 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 + void construct(const std::tuple &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 + void tuple_construct(const std::tuple &args, + const detail::index_sequence &unused) const + noexcept(std::is_nothrow_constructible::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::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::value); + + //------------------------------------------------------------------------ + // Friends + //------------------------------------------------------------------------ + + template + friend Lazy 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 +Lazy 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 +void swap(Lazy &lhs, Lazy &rhs) noexcept; + +//-------------------------------------------------------------------------- +// Constructors / Destructor / Assignment +//-------------------------------------------------------------------------- + +template +inline Lazy::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::value, + "No matching default constructor for type T"); +} + +template +template +inline Lazy::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::result_type; + + static_assert(detail::is_tuple::value, + "Lazy-construction functions must return tuples containing " + "constructor arguments"); + static_assert(detail::is_tuple_constructible::value, + "No matching constructor for type T with given arguments"); +} + +template +inline Lazy::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::value, + "No matching copy constructor for type T"); + + if (rhs.m_is_initialized) { construct(*rhs); } +} + +template +inline Lazy::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::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 +inline Lazy::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::value, + "No matching copy constructor for type T"); +} + +template +inline Lazy::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::value, + "No matching move constructor for type T"); +} + +//-------------------------------------------------------------------------- + +template +inline Lazy::~Lazy() +{ + destruct(); +} + +//-------------------------------------------------------------------------- + +template +inline Lazy & +Lazy::operator=(const this_type &rhs) +{ + static_assert(std::is_copy_assignable::value, + "No matching copy assignment operator for type T"); + static_assert(std::is_copy_constructible::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 +inline typename Lazy::this_type & +Lazy::operator=(this_type &&rhs) +{ + static_assert(std::is_move_assignable::value, + "No matching move assignment operator for type T"); + static_assert(std::is_move_constructible::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 +inline typename Lazy::value_type & +Lazy::operator=(const value_type &rhs) +{ + static_assert(std::is_copy_assignable::value, + "No matching copy assignment operator for type T"); + + lazy_construct(); + assign(rhs); + + return *ptr(); +} + +template +inline typename Lazy::value_type & +Lazy::operator=(value_type &&rhs) +{ + static_assert(std::is_move_assignable::value, + "No matching move assignment operator for type T"); + + lazy_construct(); + assign(std::forward(rhs)); + + return *ptr(); +} + +//-------------------------------------------------------------------------- +// Casting +//-------------------------------------------------------------------------- + +template +inline Lazy::operator reference() const +{ + lazy_construct(); + return *ptr(); +} + +template +inline Lazy::operator bool() const noexcept +{ + return m_is_initialized; +} + +//-------------------------------------------------------------------------- +// Operators +//-------------------------------------------------------------------------- + +template +inline void +Lazy::swap(Lazy &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 +inline bool +Lazy::is_initialized() const noexcept +{ + return m_is_initialized; +} + +template +inline typename Lazy::pointer +Lazy::get() const +{ + lazy_construct(); + return ptr(); +} + +template +inline typename Lazy::reference +Lazy::operator*() const +{ + lazy_construct(); + return *ptr(); +} + +template +inline typename Lazy::pointer +Lazy::operator->() const +{ + lazy_construct(); + return ptr(); +} + +//-------------------------------------------------------------------------- +// Private Static Member Functions +//-------------------------------------------------------------------------- + +template +inline void +Lazy::default_destructor(value_type &) noexcept +{} + +//-------------------------------------------------------------------------- +// Private Constructors +//-------------------------------------------------------------------------- + +template +template +inline Lazy::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::value, + "No matching constructor for type T with given arguments"); +} + +//-------------------------------------------------------------------------- +// Private Member Functions +//-------------------------------------------------------------------------- + +template +inline typename Lazy::unqualified_pointer +Lazy::ptr() const noexcept +{ + // address-of idiom (https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Address_Of) + return reinterpret_cast(&const_cast( + reinterpret_cast(m_storage))); +} + +template +inline void +Lazy::lazy_construct() const +{ + if (!m_is_initialized) { + m_constructor(); + m_is_initialized = true; + } +} + +template +inline void +Lazy::construct(const value_type &x) const +{ + destruct(); + new (ptr()) value_type(x); + m_is_initialized = true; +} + +template +inline void +Lazy::construct(value_type &&x) const +{ + destruct(); + new (ptr()) value_type(std::forward(x)); + m_is_initialized = true; +} + +template +template +inline void +Lazy::construct(ctor_va_args_tag, Args &&...args) const +{ + destruct(); + new (ptr()) value_type(std::forward(args)...); + m_is_initialized = true; +} + +template +template +inline void +Lazy::construct(const std::tuple &args) const +{ + destruct(); + tuple_construct(args, detail::index_sequence_for()); + m_is_initialized = true; +} + +template +template +inline void +Lazy::tuple_construct(const std::tuple &args, + const detail::index_sequence &) const + noexcept(std::is_nothrow_constructible::value) +{ + static_assert(std::is_constructible::value, + "No matching constructor for type T with given arguments"); + + new (ptr()) T(std::get(args)...); +} + +template +inline void +Lazy::destruct() const +{ + if (m_is_initialized) { + if (m_destructor) { m_destructor(*ptr()); } + ptr()->~T(); + m_is_initialized = false; + } +} + +template +inline void +Lazy::assign(const value_type &rhs) const + noexcept(std::is_nothrow_copy_assignable::value) +{ + (*ptr()) = rhs; +} + +template +inline void +Lazy::assign(value_type &&rhs) const + noexcept(std::is_nothrow_move_assignable::value) +{ + (*ptr()) = std::forward(rhs); +} + +//-------------------------------------------------------------------------- +// Utilities +//-------------------------------------------------------------------------- + +template +Lazy +make_lazy(Args &&...args) +{ + return Lazy(typename Lazy::ctor_va_args_tag(), + std::forward(args)...); +} + +template +void +swap(Lazy &lhs, Lazy &rhs) noexcept +{ + lhs.swap(rhs); +} + +}// namespace lazy + +// +namespace ulib { +template +using Lazy = lazy::Lazy; +using lazy::make_lazy; +using lazy::swap; + +}// namespace ulib + +#endif /* LAZYLAZY_HPP_ */ diff --git a/CMakeLists.txt b/CMakeLists.txt index e9bfca7..bdae3b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/src/ulib/utils/utils.cpp b/src/ulib/utils/utils.cpp index 948d97d..d219167 100644 --- a/src/ulib/utils/utils.cpp +++ b/src/ulib/utils/utils.cpp @@ -35,4 +35,23 @@ StrJoin(const std::vector &vec, delimiter, ignore_empty_str); } +std::vector +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 +StrSplit(std::string &str, nonstd::string_view delimiter, bool ignore_empty_str) +{ + return StrSplit(str, delimiter, ignore_empty_str); +} + }// namespace ulib diff --git a/src/ulib/utils/utils.h b/src/ulib/utils/utils.h index 5e90e99..1979b89 100644 --- a/src/ulib/utils/utils.h +++ b/src/ulib/utils/utils.h @@ -28,5 +28,12 @@ std::string StrJoin(const std::vector &vec, nonstd::string_view delimiter = ",", bool ignore_empty_str = true); +std::vector StrSplit(nonstd::string_view vec, + nonstd::string_view delimiter = ",", + bool ignore_empty_str = true); + +std::vector StrSplit(const std::string &vec, + nonstd::string_view delimiter = ",", + bool ignore_empty_str = true); }// namespace ulib #endif// ULIB_SRC_ULIB_UTILS_UTILS_H_ diff --git a/tests/3party/nonstd/lazy_unittest.cpp b/tests/3party/nonstd/lazy_unittest.cpp new file mode 100644 index 0000000..458479c --- /dev/null +++ b/tests/3party/nonstd/lazy_unittest.cpp @@ -0,0 +1,16 @@ +#include +#include + +TEST(Lazy, Base) +{ + bool flag = false; + int cnt = 0; + auto lazy = ulib::Lazy([&]() { + flag = true; + ++cnt; + return std::make_tuple(cnt); + }); + EXPECT_EQ(flag, false); + EXPECT_EQ(*lazy, 1); + EXPECT_EQ(flag, true); +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d0f15a7..386431a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -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)