Bump deps: Switch to polymorphic value and latest robin_hood_hash(#220)
* bump robin_hood hashing dep to 3.11.3 * bump value-ptr-lite to latest version * switch to polymorphic_value * implement comparisons * fix build: add operator!= * polymorphic_value into jinja2cpp integration * introduce ValuePtr and MoveValuePtr aliasesmaster
parent
4b86a7cecb
commit
6092f44df1
|
@ -75,7 +75,7 @@ jobs:
|
|||
mkdir -p .build
|
||||
cd .build
|
||||
cmake .. -G "%INPUT_GENERATOR%" -DCMAKE_BUILD_TYPE=%INPUT_BUILD_CONFIG% -DJINJA2CPP_MSVC_RUNTIME_TYPE="%INPUT_BUILD_RUNTIME%" -DJINJA2CPP_DEPS_MODE=internal -DJINJA2CPP_BUILD_SHARED=%INPUT_BUILD_SHARED% %INPUT_BASE_FLAGS% %INPUT_EXTRA_FLAGS%
|
||||
cmake --build . --config %INPUT_BUILD_CONFIG%
|
||||
cmake --build . --config %INPUT_BUILD_CONFIG% --verbose
|
||||
|
||||
- name: Test
|
||||
shell: cmd
|
||||
|
|
|
@ -33,3 +33,4 @@
|
|||
build/
|
||||
dist/
|
||||
|
||||
compile_commands.json
|
||||
|
|
|
@ -90,7 +90,7 @@ if (UNIX)
|
|||
endif ()
|
||||
else ()
|
||||
set(GCC_CXX_FLAGS ${GCC_CXX_FLAGS} "-Wa,-mbig-obj" -O1)
|
||||
if (${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
endif ()
|
||||
add_definitions(-DBOOST_ALL_NO_LIB)
|
||||
|
@ -193,11 +193,11 @@ if (JINJA2CPP_STRICT_WARNINGS)
|
|||
endif ()
|
||||
endif ()
|
||||
|
||||
if (${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
target_compile_options(${LIB_TARGET_NAME} PRIVATE ${GCC_CXX_FLAGS})
|
||||
elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
target_compile_options(${LIB_TARGET_NAME} PRIVATE ${CLANG_CXX_FLAGS})
|
||||
elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "MSVC")
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
target_compile_options(${LIB_TARGET_NAME} PRIVATE ${MSVC_CXX_FLAGS})
|
||||
endif ()
|
||||
|
||||
|
@ -233,7 +233,7 @@ if (JINJA2CPP_BUILD_TESTS)
|
|||
CXX_STANDARD ${JINJA2CPP_CXX_STANDARD}
|
||||
CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
if (MSVC)
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
target_compile_options(jinja2cpp_tests PRIVATE /bigobj)
|
||||
endif ()
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace jinja2
|
|||
namespace detail
|
||||
{
|
||||
|
||||
class NLohmannJsonObjectAccessor : public MapItemAccessor, public ReflectedDataHolder<nlohmann::json>
|
||||
class NLohmannJsonObjectAccessor : public IMapItemAccessor, public ReflectedDataHolder<nlohmann::json>
|
||||
{
|
||||
public:
|
||||
using ReflectedDataHolder<nlohmann::json>::ReflectedDataHolder;
|
||||
|
@ -50,10 +50,18 @@ public:
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IsEqual(const IComparable& other) const override
|
||||
{
|
||||
auto* val = dynamic_cast<const NLohmannJsonObjectAccessor*>(&other);
|
||||
if (!val)
|
||||
return false;
|
||||
return GetValue() == val->GetValue();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct NLohmannJsonArrayAccessor : ListItemAccessor, IndexBasedAccessor, ReflectedDataHolder<nlohmann::json>
|
||||
struct NLohmannJsonArrayAccessor : IListItemAccessor, IIndexBasedAccessor, ReflectedDataHolder<nlohmann::json>
|
||||
{
|
||||
using ReflectedDataHolder<nlohmann::json>::ReflectedDataHolder;
|
||||
|
||||
|
@ -62,7 +70,8 @@ struct NLohmannJsonArrayAccessor : ListItemAccessor, IndexBasedAccessor, Reflect
|
|||
auto j = this->GetValue();
|
||||
return j ? j->size() : nonstd::optional<size_t>();
|
||||
}
|
||||
const IndexBasedAccessor* GetIndexer() const override
|
||||
|
||||
const IIndexBasedAccessor* GetIndexer() const override
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
@ -72,9 +81,9 @@ struct NLohmannJsonArrayAccessor : ListItemAccessor, IndexBasedAccessor, Reflect
|
|||
using Enum = Enumerator<typename nlohmann::json::const_iterator>;
|
||||
auto j = this->GetValue();
|
||||
if (!j)
|
||||
jinja2::ListEnumeratorPtr(nullptr, Enum::Deleter);
|
||||
return jinja2::ListEnumeratorPtr();
|
||||
|
||||
return jinja2::ListEnumeratorPtr(new Enum(j->begin(), j->end()), Enum::Deleter);
|
||||
return jinja2::ListEnumeratorPtr(new Enum(j->begin(), j->end()));
|
||||
}
|
||||
|
||||
Value GetItemByIndex(int64_t idx) const override
|
||||
|
@ -85,6 +94,14 @@ struct NLohmannJsonArrayAccessor : ListItemAccessor, IndexBasedAccessor, Reflect
|
|||
|
||||
return Reflect((*j)[idx]);
|
||||
}
|
||||
|
||||
bool IsEqual(const IComparable& other) const override
|
||||
{
|
||||
auto* val = dynamic_cast<const NLohmannJsonArrayAccessor*>(&other);
|
||||
if (!val)
|
||||
return false;
|
||||
return GetValue() == val->GetValue();
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <jinja2cpp/reflected_value.h>
|
||||
#include <jinja2cpp/string_helpers.h>
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/rapidjson.h>
|
||||
|
||||
|
@ -27,11 +28,12 @@ struct RapidJsonNameConverter<wchar_t>
|
|||
};
|
||||
|
||||
template<typename T>
|
||||
class RapidJsonObjectAccessor : public MapItemAccessor, public ReflectedDataHolder<T, false>
|
||||
class RapidJsonObjectAccessor : public IMapItemAccessor, public ReflectedDataHolder<T, false>
|
||||
{
|
||||
public:
|
||||
using ReflectedDataHolder<T, false>::ReflectedDataHolder;
|
||||
using NameCvt = RapidJsonNameConverter<typename T::Ch>;
|
||||
using ThisType = RapidJsonObjectAccessor<T>;
|
||||
~RapidJsonObjectAccessor() override = default;
|
||||
|
||||
size_t GetSize() const override
|
||||
|
@ -69,22 +71,38 @@ public:
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IsEqual(const IComparable& other) const override
|
||||
{
|
||||
auto* val = dynamic_cast<const ThisType*>(&other);
|
||||
if (!val)
|
||||
return false;
|
||||
auto enumerator = this->GetValue();
|
||||
auto otherEnum = val->GetValue();
|
||||
if (enumerator && otherEnum && enumerator != otherEnum)
|
||||
return false;
|
||||
if ((enumerator && !otherEnum) || (!enumerator && otherEnum))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Enc>
|
||||
struct RapidJsonArrayAccessor
|
||||
: ListItemAccessor
|
||||
, IndexBasedAccessor
|
||||
: IListItemAccessor
|
||||
, IIndexBasedAccessor
|
||||
, ReflectedDataHolder<rapidjson::GenericValue<Enc>, false>
|
||||
{
|
||||
using ReflectedDataHolder<rapidjson::GenericValue<Enc>, false>::ReflectedDataHolder;
|
||||
using ThisType = RapidJsonArrayAccessor<Enc>;
|
||||
|
||||
nonstd::optional<size_t> GetSize() const override
|
||||
{
|
||||
auto j = this->GetValue();
|
||||
return j ? j->Size() : nonstd::optional<size_t>();
|
||||
}
|
||||
const IndexBasedAccessor* GetIndexer() const override
|
||||
|
||||
const IIndexBasedAccessor* GetIndexer() const override
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
@ -94,9 +112,9 @@ struct RapidJsonArrayAccessor
|
|||
using Enum = Enumerator<typename rapidjson::GenericValue<Enc>::ConstValueIterator>;
|
||||
auto j = this->GetValue();
|
||||
if (!j)
|
||||
jinja2::ListEnumeratorPtr(nullptr, Enum::Deleter);
|
||||
return jinja2::ListEnumeratorPtr();
|
||||
|
||||
return jinja2::ListEnumeratorPtr(new Enum(j->Begin(), j->End()), Enum::Deleter);
|
||||
return jinja2::ListEnumeratorPtr(new Enum(j->Begin(), j->End()));
|
||||
}
|
||||
|
||||
Value GetItemByIndex(int64_t idx) const override
|
||||
|
@ -107,6 +125,20 @@ struct RapidJsonArrayAccessor
|
|||
|
||||
return Reflect((*j)[static_cast<rapidjson::SizeType>(idx)]);
|
||||
}
|
||||
|
||||
bool IsEqual(const IComparable& other) const override
|
||||
{
|
||||
auto* val = dynamic_cast<const ThisType*>(&other);
|
||||
if (!val)
|
||||
return false;
|
||||
auto enumerator = this->GetValue();
|
||||
auto otherEnum = val->GetValue();
|
||||
if (enumerator && otherEnum && enumerator != otherEnum)
|
||||
return false;
|
||||
if ((enumerator && !otherEnum) || (!enumerator && otherEnum))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Enc>
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include <jinja2cpp/utils/i_comparable.h>
|
||||
|
||||
#include <nonstd/optional.hpp>
|
||||
#include <nonstd/variant.hpp>
|
||||
|
||||
|
@ -28,7 +30,7 @@ using WCharFileStreamPtr = FileStreamPtr<wchar_t>;
|
|||
* So, the exact type (ex. `ifstream`, `istringstream` etc.) of input stream is unspecified. In order to delete stream object correctly returned pointer
|
||||
* provide the custom deleter which should properly delete the stream object.
|
||||
*/
|
||||
class JINJA2CPP_EXPORT IFilesystemHandler
|
||||
class JINJA2CPP_EXPORT IFilesystemHandler : public IComparable
|
||||
{
|
||||
public:
|
||||
//! Destructor
|
||||
|
@ -101,11 +103,27 @@ public:
|
|||
WCharFileStreamPtr OpenWStream(const std::string& name) const override;
|
||||
nonstd::optional<std::chrono::system_clock::time_point> GetLastModificationDate(const std::string& name) const override;
|
||||
|
||||
/*!
|
||||
* \brief Compares to an object of the same type
|
||||
*
|
||||
* return true if equal
|
||||
*/
|
||||
bool IsEqual(const IComparable& other) const override;
|
||||
private:
|
||||
struct FileContent
|
||||
{
|
||||
nonstd::optional<std::string> narrowContent;
|
||||
nonstd::optional<std::wstring> wideContent;
|
||||
bool operator==(const FileContent& other) const
|
||||
{
|
||||
if (narrowContent != other.narrowContent)
|
||||
return false;
|
||||
return wideContent == other.wideContent;
|
||||
}
|
||||
bool operator!=(const FileContent& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
mutable std::unordered_map<std::string, FileContent> m_filesMap;
|
||||
};
|
||||
|
@ -168,6 +186,13 @@ public:
|
|||
CharFileStreamPtr OpenByteStream(const std::string& name) const;
|
||||
nonstd::optional<std::chrono::system_clock::time_point> GetLastModificationDate(const std::string& name) const override;
|
||||
|
||||
/*!
|
||||
* \brief Compares to an object of the same type
|
||||
*
|
||||
* return true if equal
|
||||
*/
|
||||
bool IsEqual(const IComparable& other) const override;
|
||||
|
||||
private:
|
||||
std::string m_rootFolder;
|
||||
};
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#ifndef JINJA2CPP_GENERIC_LIST_H
|
||||
#define JINJA2CPP_GENERIC_LIST_H
|
||||
|
||||
#include <jinja2cpp/utils/i_comparable.h>
|
||||
#include <jinja2cpp/value_ptr.h>
|
||||
|
||||
#include <nonstd/optional.hpp>
|
||||
|
||||
#include <iterator>
|
||||
|
@ -16,8 +19,9 @@ class Value;
|
|||
*
|
||||
* This interface should provided by the particular list implementation in case of support index-based access to the items.
|
||||
*/
|
||||
struct IndexBasedAccessor
|
||||
struct IIndexBasedAccessor : virtual IComparable
|
||||
{
|
||||
virtual ~IIndexBasedAccessor() = default;
|
||||
/*!
|
||||
* \brief This method is called to get the item by the specified index
|
||||
*
|
||||
|
@ -28,12 +32,12 @@ struct IndexBasedAccessor
|
|||
virtual Value GetItemByIndex(int64_t idx) const = 0;
|
||||
};
|
||||
|
||||
struct ListEnumerator;
|
||||
using ListEnumeratorPtr = std::unique_ptr<ListEnumerator, void (*)(ListEnumerator*)>;
|
||||
struct IListEnumerator;
|
||||
using ListEnumeratorPtr = types::ValuePtr<IListEnumerator>;
|
||||
|
||||
inline auto MakeEmptyListEnumeratorPtr()
|
||||
{
|
||||
return ListEnumeratorPtr(nullptr, [](ListEnumerator*) {});
|
||||
return ListEnumeratorPtr();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -45,10 +49,10 @@ inline auto MakeEmptyListEnumeratorPtr()
|
|||
* enumerator to the first element end returns `true` or moves enumerator to the end and returns `false` in case of empty list. Each call of \ref GetCurrent
|
||||
* method should return the current enumerable item.
|
||||
*/
|
||||
struct ListEnumerator
|
||||
struct IListEnumerator : virtual IComparable
|
||||
{
|
||||
//! Destructor
|
||||
virtual ~ListEnumerator() = default;
|
||||
virtual ~IListEnumerator() = default;
|
||||
|
||||
/*!
|
||||
* \brief Method is called to reset enumerator to the initial state ('before the first element') if applicable.
|
||||
|
@ -103,9 +107,9 @@ struct ListEnumerator
|
|||
*
|
||||
* It's assumed that indexer interface is a part of list implementation.
|
||||
*/
|
||||
struct ListItemAccessor
|
||||
struct IListItemAccessor : virtual IComparable
|
||||
{
|
||||
virtual ~ListItemAccessor() = default;
|
||||
virtual ~IListItemAccessor() = default;
|
||||
|
||||
/*!
|
||||
* \brief Called to get pointer to indexer interface implementation (if applicable)
|
||||
|
@ -117,7 +121,7 @@ struct ListItemAccessor
|
|||
*
|
||||
* @return Pointer to the indexer interface implementation or null if indexing isn't supported for the list
|
||||
*/
|
||||
virtual const IndexBasedAccessor* GetIndexer() const = 0;
|
||||
virtual const IIndexBasedAccessor* GetIndexer() const = 0;
|
||||
|
||||
/*!
|
||||
* \brief Called to get enumerator of the particular list
|
||||
|
@ -154,6 +158,7 @@ struct ListItemAccessor
|
|||
static ListEnumeratorPtr MakeEnumerator(Args&&... args);
|
||||
};
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
class GenericListIterator;
|
||||
|
@ -174,7 +179,7 @@ class GenericListIterator;
|
|||
* };
|
||||
* ```
|
||||
*/
|
||||
class GenericList
|
||||
class JINJA2CPP_EXPORT GenericList
|
||||
{
|
||||
public:
|
||||
//! Default constructor
|
||||
|
@ -183,7 +188,7 @@ public:
|
|||
/*!
|
||||
* \brief Initializing constructor
|
||||
*
|
||||
* This constructor is only one way to create the valid GenericList object. `accessor` is a functional object which provides access to the \ref ListItemAccessor
|
||||
* This constructor is only one way to create the valid GenericList object. `accessor` is a functional object which provides access to the \ref IListItemAccessor
|
||||
* interface. The most common way of GenericList creation is to initialize it with lambda which simultaniously holds and and provide access to the
|
||||
* generic list implementation:
|
||||
*
|
||||
|
@ -196,7 +201,7 @@ public:
|
|||
*
|
||||
* @param accessor Functional object which provides access to the particular generic list implementation
|
||||
*/
|
||||
explicit GenericList(std::function<const ListItemAccessor*()> accessor)
|
||||
explicit GenericList(std::function<const IListItemAccessor*()> accessor)
|
||||
: m_accessor(std::move(accessor))
|
||||
{
|
||||
}
|
||||
|
@ -257,15 +262,26 @@ public:
|
|||
*/
|
||||
auto cend() const;
|
||||
|
||||
std::function<const ListItemAccessor*()> m_accessor;
|
||||
/*!
|
||||
* \brief Compares with the objects of same type
|
||||
*
|
||||
* @return true if equal
|
||||
*/
|
||||
bool IsEqual(const GenericList& rhs) const;
|
||||
|
||||
private:
|
||||
std::function<const IListItemAccessor*()> m_accessor;
|
||||
};
|
||||
|
||||
bool operator==(const GenericList& lhs, const GenericList& rhs);
|
||||
bool operator!=(const GenericList& lhs, const GenericList& rhs);
|
||||
|
||||
template<typename T, typename ...Args>
|
||||
inline ListEnumeratorPtr ListItemAccessor::MakeEnumerator(Args&& ...args)
|
||||
inline ListEnumeratorPtr IListItemAccessor::MakeEnumerator(Args&& ...args)
|
||||
{
|
||||
return ListEnumeratorPtr(new T(std::forward<Args>(args)...), [](ListEnumerator* e) { delete e; });
|
||||
return ListEnumeratorPtr(types::MakeValuePtr<T>(std::forward<Args>(args)...));
|
||||
}
|
||||
} // namespace jinja2
|
||||
|
||||
|
||||
#endif // JINJA2CPP_GENERIC_LIST_H
|
||||
#endif // JINJA2CPP_GENERIC_LIST_H
|
||||
|
|
|
@ -11,15 +11,15 @@ namespace jinja2
|
|||
namespace lists_impl
|
||||
{
|
||||
template<typename It1, typename It2>
|
||||
struct InputIteratorListAccessor : ListItemAccessor
|
||||
struct InputIteratorListAccessor : IListItemAccessor
|
||||
{
|
||||
mutable It1 m_begin;
|
||||
mutable It2 m_end;
|
||||
|
||||
struct Enumerator : public ListEnumerator
|
||||
struct Enumerator : public IListEnumerator
|
||||
{
|
||||
It1* m_cur;
|
||||
It2* m_end;
|
||||
It1* m_cur = nullptr;
|
||||
It2* m_end = nullptr;
|
||||
bool m_justInited = true;
|
||||
|
||||
Enumerator(It1* begin, It2* end)
|
||||
|
@ -49,7 +49,7 @@ struct InputIteratorListAccessor : ListItemAccessor
|
|||
ListEnumeratorPtr Clone() const override
|
||||
{
|
||||
auto result = MakeEnumerator<Enumerator>(m_cur, m_end);
|
||||
auto ptr = static_cast<Enumerator*>(result.get());
|
||||
auto ptr = static_cast<Enumerator*>(&(*result));
|
||||
ptr->m_cur = m_cur;
|
||||
ptr->m_justInited = m_justInited;
|
||||
return result;
|
||||
|
@ -59,6 +59,19 @@ struct InputIteratorListAccessor : ListItemAccessor
|
|||
{
|
||||
return MakeEnumerator<Enumerator>(std::move(*this));
|
||||
}
|
||||
bool IsEqual(const IComparable &other) const override
|
||||
{
|
||||
auto* val = dynamic_cast<const Enumerator*>(&other);
|
||||
if (!val)
|
||||
return false;
|
||||
if (m_cur != val->m_cur)
|
||||
return false;
|
||||
if (m_end != val->m_end)
|
||||
return false;
|
||||
if (m_justInited != val->m_justInited)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
explicit InputIteratorListAccessor(It1&& b, It2&& e) noexcept
|
||||
|
@ -72,7 +85,7 @@ struct InputIteratorListAccessor : ListItemAccessor
|
|||
return nonstd::optional<size_t>();
|
||||
}
|
||||
|
||||
const IndexBasedAccessor* GetIndexer() const override
|
||||
const IIndexBasedAccessor* GetIndexer() const override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -82,15 +95,23 @@ struct InputIteratorListAccessor : ListItemAccessor
|
|||
return MakeEnumerator<Enumerator>(&m_begin, &m_end );
|
||||
}
|
||||
|
||||
bool IsEqual(const IComparable& other) const override
|
||||
{
|
||||
auto* val = dynamic_cast<const InputIteratorListAccessor*>(&other);
|
||||
if (!val)
|
||||
return false;
|
||||
return m_begin == val->m_begin && m_end == val->m_end;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename It1, typename It2>
|
||||
struct ForwardIteratorListAccessor : ListItemAccessor
|
||||
struct ForwardIteratorListAccessor : IListItemAccessor
|
||||
{
|
||||
It1 m_begin;
|
||||
It2 m_end;
|
||||
|
||||
struct Enumerator : public ListEnumerator
|
||||
struct Enumerator : public IListEnumerator
|
||||
{
|
||||
It1 m_begin;
|
||||
It1 m_cur;
|
||||
|
@ -116,7 +137,9 @@ struct ForwardIteratorListAccessor : ListItemAccessor
|
|||
m_justInited = false;
|
||||
}
|
||||
else
|
||||
++ m_cur;
|
||||
{
|
||||
++m_cur;
|
||||
}
|
||||
|
||||
return m_cur != m_end;
|
||||
}
|
||||
|
@ -129,7 +152,7 @@ struct ForwardIteratorListAccessor : ListItemAccessor
|
|||
ListEnumeratorPtr Clone() const override
|
||||
{
|
||||
auto result = MakeEnumerator<Enumerator>(m_cur, m_end);
|
||||
auto ptr = static_cast<Enumerator*>(result.get());
|
||||
auto ptr = static_cast<Enumerator*>(&(*result));
|
||||
ptr->m_begin = m_cur;
|
||||
ptr->m_cur = m_cur;
|
||||
ptr->m_justInited = m_justInited;
|
||||
|
@ -140,6 +163,21 @@ struct ForwardIteratorListAccessor : ListItemAccessor
|
|||
{
|
||||
return MakeEnumerator<Enumerator>(std::move(*this));
|
||||
}
|
||||
bool IsEqual(const IComparable &other) const override
|
||||
{
|
||||
auto* val = dynamic_cast<const Enumerator*>(&other);
|
||||
if (!val)
|
||||
return false;
|
||||
if (m_begin != val->m_begin)
|
||||
return false;
|
||||
if (m_cur != val->m_cur)
|
||||
return false;
|
||||
if (m_end != val->m_end)
|
||||
return false;
|
||||
if (m_justInited != val->m_justInited)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
explicit ForwardIteratorListAccessor(It1&& b, It2&& e) noexcept
|
||||
|
@ -153,7 +191,7 @@ struct ForwardIteratorListAccessor : ListItemAccessor
|
|||
return nonstd::optional<size_t>();
|
||||
}
|
||||
|
||||
const IndexBasedAccessor* GetIndexer() const override
|
||||
const IIndexBasedAccessor* GetIndexer() const override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -162,16 +200,22 @@ struct ForwardIteratorListAccessor : ListItemAccessor
|
|||
{
|
||||
return MakeEnumerator<Enumerator>(m_begin, m_end);
|
||||
}
|
||||
|
||||
bool IsEqual(const IComparable& other) const override
|
||||
{
|
||||
auto* val = dynamic_cast<const ForwardIteratorListAccessor*>(&other);
|
||||
if (!val)
|
||||
return false;
|
||||
return m_begin == val->m_begin && m_end == val->m_end;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename It1, typename It2>
|
||||
struct RandomIteratorListAccessor : ListItemAccessor, IndexBasedAccessor
|
||||
struct RandomIteratorListAccessor : IListItemAccessor, IIndexBasedAccessor
|
||||
{
|
||||
It1 m_begin;
|
||||
It2 m_end;
|
||||
|
||||
struct Enumerator : public ListEnumerator
|
||||
struct Enumerator : public IListEnumerator
|
||||
{
|
||||
It1 m_begin;
|
||||
It1 m_cur;
|
||||
|
@ -197,7 +241,9 @@ struct RandomIteratorListAccessor : ListItemAccessor, IndexBasedAccessor
|
|||
m_justInited = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
++ m_cur;
|
||||
}
|
||||
|
||||
return m_cur != m_end;
|
||||
}
|
||||
|
@ -210,7 +256,7 @@ struct RandomIteratorListAccessor : ListItemAccessor, IndexBasedAccessor
|
|||
ListEnumeratorPtr Clone() const override
|
||||
{
|
||||
auto result = MakeEnumerator<Enumerator>(m_cur, m_end);
|
||||
auto ptr = static_cast<Enumerator*>(result.get());
|
||||
auto ptr = static_cast<Enumerator*>(&(*result));
|
||||
ptr->m_begin = m_cur;
|
||||
ptr->m_cur = m_cur;
|
||||
ptr->m_justInited = m_justInited;
|
||||
|
@ -221,6 +267,21 @@ struct RandomIteratorListAccessor : ListItemAccessor, IndexBasedAccessor
|
|||
{
|
||||
return MakeEnumerator<Enumerator>(std::move(*this));
|
||||
}
|
||||
bool IsEqual(const IComparable &other) const override
|
||||
{
|
||||
auto* val = dynamic_cast<const Enumerator*>(&other);
|
||||
if (!val)
|
||||
return false;
|
||||
if (m_begin != val->m_begin)
|
||||
return false;
|
||||
if (m_cur != val->m_cur)
|
||||
return false;
|
||||
if (m_end != val->m_end)
|
||||
return false;
|
||||
if (m_justInited != val->m_justInited)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
explicit RandomIteratorListAccessor(It1 b, It2 e) noexcept
|
||||
|
@ -234,7 +295,7 @@ struct RandomIteratorListAccessor : ListItemAccessor, IndexBasedAccessor
|
|||
return std::distance(m_begin, m_end);
|
||||
}
|
||||
|
||||
const IndexBasedAccessor* GetIndexer() const override
|
||||
const IIndexBasedAccessor* GetIndexer() const override
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
@ -252,14 +313,22 @@ struct RandomIteratorListAccessor : ListItemAccessor, IndexBasedAccessor
|
|||
return Reflect(*p);
|
||||
}
|
||||
|
||||
bool IsEqual(const IComparable& other) const override
|
||||
{
|
||||
auto* val = dynamic_cast<const RandomIteratorListAccessor*>(&other);
|
||||
if (!val)
|
||||
return false;
|
||||
return m_begin == val->m_begin && m_end == val->m_end;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
using ListGenerator = std::function<nonstd::optional<Value>()>;
|
||||
|
||||
class GeneratedListAccessor : public ListItemAccessor
|
||||
class GeneratedListAccessor : public IListItemAccessor
|
||||
{
|
||||
public:
|
||||
class Enumerator : public ListEnumerator
|
||||
class Enumerator : public IListEnumerator
|
||||
{
|
||||
public:
|
||||
Enumerator(const ListGenerator* fn)
|
||||
|
@ -296,10 +365,19 @@ public:
|
|||
return MakeEnumerator<Enumerator>(std::move(*this));
|
||||
}
|
||||
|
||||
bool IsEqual(const IComparable &other) const override
|
||||
{
|
||||
auto* val = dynamic_cast<const Enumerator*>(&other);
|
||||
if (!val)
|
||||
return false;
|
||||
return m_fn == val->m_fn && m_current == val->m_current && m_isFinished == val->m_isFinished;
|
||||
}
|
||||
protected:
|
||||
const ListGenerator* m_fn;
|
||||
Value m_current;
|
||||
bool m_isFinished = false;
|
||||
|
||||
|
||||
};
|
||||
|
||||
explicit GeneratedListAccessor(ListGenerator&& fn) : m_fn(std::move(fn)) {}
|
||||
|
@ -308,7 +386,7 @@ public:
|
|||
{
|
||||
return nonstd::optional<size_t>();
|
||||
}
|
||||
const IndexBasedAccessor* GetIndexer() const override
|
||||
const IIndexBasedAccessor* GetIndexer() const override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -317,6 +395,15 @@ public:
|
|||
{
|
||||
return MakeEnumerator<Enumerator>(&m_fn);
|
||||
}
|
||||
|
||||
bool IsEqual(const IComparable& other) const override
|
||||
{
|
||||
auto* val = dynamic_cast<const GeneratedListAccessor*>(&other);
|
||||
if (!val)
|
||||
return false;
|
||||
return m_fn() == val->m_fn();
|
||||
}
|
||||
|
||||
private:
|
||||
ListGenerator m_fn;
|
||||
};
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
|
||||
#include "generic_list.h"
|
||||
#include "value.h"
|
||||
#include "value_ptr.hpp"
|
||||
#include "value_ptr.h"
|
||||
|
||||
namespace jinja2
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
class GenericListIterator
|
||||
class JINJA2CPP_EXPORT GenericListIterator
|
||||
{
|
||||
public:
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
@ -17,41 +17,33 @@ public:
|
|||
using difference_type = std::ptrdiff_t;
|
||||
using reference = const Value&;
|
||||
using pointer = const Value*;
|
||||
using EnumeratorPtr = types::ValuePtr<IListEnumerator>;
|
||||
|
||||
struct Cloner
|
||||
{
|
||||
ListEnumerator* operator()(const ListEnumerator &x) const
|
||||
{
|
||||
return x.Clone().release();
|
||||
}
|
||||
GenericListIterator() = default;
|
||||
|
||||
ListEnumerator* operator()(ListEnumerator &&x) const
|
||||
{
|
||||
return x.Move().release();
|
||||
}
|
||||
};
|
||||
|
||||
using EnumeratorPtr = nonstd::value_ptr<ListEnumerator, Cloner>;
|
||||
|
||||
GenericListIterator(ListEnumerator* e = nullptr)
|
||||
: m_enumerator(e)
|
||||
GenericListIterator(ListEnumeratorPtr enumerator)
|
||||
: m_enumerator(types::ValuePtr<IListEnumerator>(enumerator))
|
||||
{
|
||||
if (m_enumerator)
|
||||
m_hasValue = m_enumerator->MoveNext();
|
||||
|
||||
if (m_hasValue)
|
||||
m_current = std::move(m_enumerator->GetCurrent());
|
||||
m_current = m_enumerator->GetCurrent();
|
||||
}
|
||||
|
||||
bool operator == (const GenericListIterator& other) const
|
||||
{
|
||||
if (!this->m_enumerator)
|
||||
return !other.m_enumerator ? true : other == *this;
|
||||
|
||||
if (!other.m_enumerator)
|
||||
return !m_hasValue;
|
||||
|
||||
return this->m_enumerator.get() == other.m_enumerator.get();
|
||||
if (m_hasValue != other.m_hasValue)
|
||||
return false;
|
||||
if (!m_enumerator && !other.m_enumerator)
|
||||
return true;
|
||||
if (this->m_enumerator && other.m_enumerator && !m_enumerator->IsEqual(*other.m_enumerator))
|
||||
return false;
|
||||
if ((m_enumerator && !other.m_enumerator) || (!m_enumerator && other.m_enumerator))
|
||||
return false;
|
||||
if (m_current != other.m_current)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator != (const GenericListIterator& other) const
|
||||
|
@ -66,9 +58,21 @@ public:
|
|||
|
||||
GenericListIterator& operator ++()
|
||||
{
|
||||
if (!m_enumerator)
|
||||
return *this;
|
||||
m_hasValue = m_enumerator->MoveNext();
|
||||
if (m_hasValue)
|
||||
m_current = std::move(m_enumerator->GetCurrent());
|
||||
{
|
||||
m_current = m_enumerator->GetCurrent();
|
||||
}
|
||||
else
|
||||
{
|
||||
EnumeratorPtr temp;
|
||||
Value tempVal;
|
||||
using std::swap;
|
||||
swap(m_enumerator, temp);
|
||||
swap(m_current, tempVal);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
@ -87,27 +91,14 @@ private:
|
|||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
const EnumeratorPtr m_enumerator;
|
||||
EnumeratorPtr m_enumerator;
|
||||
bool m_hasValue = false;
|
||||
Value m_current;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
inline detail::GenericListIterator GenericList::begin() const
|
||||
{
|
||||
return m_accessor && m_accessor() ? detail::GenericListIterator(m_accessor()->CreateEnumerator().release()) : detail::GenericListIterator();
|
||||
}
|
||||
|
||||
inline detail::GenericListIterator GenericList::end() const
|
||||
{
|
||||
return detail::GenericListIterator();
|
||||
}
|
||||
|
||||
inline auto GenericList::cbegin() const {return begin();}
|
||||
inline auto GenericList::cend() const {return end();}
|
||||
} // namespace jinja2
|
||||
|
||||
#endif // JINJA2CPP_GENERIC_LIST_ITERATOR_H
|
||||
#endif // JINJA2CPP_GENERIC_LIST_ITERATOR_H
|
||||
|
|
|
@ -0,0 +1,447 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2016 Jonathan B. Coe
|
||||
|
||||
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 ISOCPP_P0201_POLYMORPHIC_VALUE_H_INCLUDED
|
||||
#define ISOCPP_P0201_POLYMORPHIC_VALUE_H_INCLUDED
|
||||
|
||||
#include <cassert>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
|
||||
|
||||
//
|
||||
// in_place: code duplicated in any-lite, expected-lite, optional-lite, value-ptr-lite, variant-lite:
|
||||
//
|
||||
|
||||
#ifndef nonstd_lite_HAVE_IN_PLACE_TYPES
|
||||
#define nonstd_lite_HAVE_IN_PLACE_TYPES 1
|
||||
|
||||
// C++17 std::in_place in <utility>:
|
||||
|
||||
#if variant_CPP17_OR_GREATER
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace nonstd {
|
||||
|
||||
using std::in_place;
|
||||
using std::in_place_type;
|
||||
using std::in_place_index;
|
||||
using std::in_place_t;
|
||||
using std::in_place_type_t;
|
||||
using std::in_place_index_t;
|
||||
|
||||
#define nonstd_lite_in_place_t( T) std::in_place_t
|
||||
#define nonstd_lite_in_place_type_t( T) std::in_place_type_t<T>
|
||||
#define nonstd_lite_in_place_index_t(K) std::in_place_index_t<K>
|
||||
|
||||
#define nonstd_lite_in_place( T) std::in_place_t{}
|
||||
#define nonstd_lite_in_place_type( T) std::in_place_type_t<T>{}
|
||||
#define nonstd_lite_in_place_index(K) std::in_place_index_t<K>{}
|
||||
|
||||
} // namespace nonstd
|
||||
|
||||
#else // variant_CPP17_OR_GREATER
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace nonstd {
|
||||
namespace detail {
|
||||
|
||||
template< class T >
|
||||
struct in_place_type_tag {};
|
||||
|
||||
template< std::size_t K >
|
||||
struct in_place_index_tag {};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
struct in_place_t {};
|
||||
|
||||
template< class T >
|
||||
inline in_place_t in_place( detail::in_place_type_tag<T> = detail::in_place_type_tag<T>() )
|
||||
{
|
||||
return in_place_t();
|
||||
}
|
||||
|
||||
template< std::size_t K >
|
||||
inline in_place_t in_place( detail::in_place_index_tag<K> = detail::in_place_index_tag<K>() )
|
||||
{
|
||||
return in_place_t();
|
||||
}
|
||||
|
||||
template< class T >
|
||||
inline in_place_t in_place_type( detail::in_place_type_tag<T> = detail::in_place_type_tag<T>() )
|
||||
{
|
||||
return in_place_t();
|
||||
}
|
||||
|
||||
template< std::size_t K >
|
||||
inline in_place_t in_place_index( detail::in_place_index_tag<K> = detail::in_place_index_tag<K>() )
|
||||
{
|
||||
return in_place_t();
|
||||
}
|
||||
|
||||
// mimic templated typedef:
|
||||
|
||||
#define nonstd_lite_in_place_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag<T> )
|
||||
#define nonstd_lite_in_place_type_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag<T> )
|
||||
#define nonstd_lite_in_place_index_t(K) nonstd::in_place_t(&)( nonstd::detail::in_place_index_tag<K> )
|
||||
|
||||
#define nonstd_lite_in_place( T) nonstd::in_place_type<T>
|
||||
#define nonstd_lite_in_place_type( T) nonstd::in_place_type<T>
|
||||
#define nonstd_lite_in_place_index(K) nonstd::in_place_index<K>
|
||||
|
||||
} // namespace nonstd
|
||||
|
||||
#endif // variant_CPP17_OR_GREATER
|
||||
#endif // nonstd_lite_HAVE_IN_PLACE_TYPES
|
||||
|
||||
namespace isocpp_p0201 {
|
||||
|
||||
namespace detail {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation detail classes
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class T>
|
||||
struct default_copy {
|
||||
T* operator()(const T& t) const { return new T(t); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct default_delete {
|
||||
void operator()(const T* t) const { delete t; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct control_block {
|
||||
virtual ~control_block() = default;
|
||||
|
||||
virtual std::unique_ptr<control_block> clone() const = 0;
|
||||
|
||||
virtual T* ptr() = 0;
|
||||
};
|
||||
|
||||
template <class T, class U = T>
|
||||
class direct_control_block : public control_block<T> {
|
||||
static_assert(!std::is_reference<U>::value, "");
|
||||
U u_;
|
||||
|
||||
public:
|
||||
template <class... Ts>
|
||||
explicit direct_control_block(Ts&&... ts) : u_(U(std::forward<Ts>(ts)...)) {}
|
||||
|
||||
std::unique_ptr<control_block<T>> clone() const override {
|
||||
return std::make_unique<direct_control_block>(*this);
|
||||
}
|
||||
|
||||
T* ptr() override { return std::addressof(u_); }
|
||||
};
|
||||
|
||||
template <class T, class U, class C = default_copy<U>,
|
||||
class D = default_delete<U>>
|
||||
class pointer_control_block : public control_block<T>, public C {
|
||||
std::unique_ptr<U, D> p_;
|
||||
|
||||
public:
|
||||
explicit pointer_control_block(U* u, C c = C{}, D d = D{})
|
||||
: C(std::move(c)), p_(u, std::move(d)) {}
|
||||
|
||||
explicit pointer_control_block(std::unique_ptr<U, D> p, C c = C{})
|
||||
: C(std::move(c)), p_(std::move(p)) {}
|
||||
|
||||
std::unique_ptr<control_block<T>> clone() const override {
|
||||
assert(p_);
|
||||
return std::make_unique<pointer_control_block>(
|
||||
C::operator()(*p_), static_cast<const C&>(*this), p_.get_deleter());
|
||||
}
|
||||
|
||||
T* ptr() override { return p_.get(); }
|
||||
};
|
||||
|
||||
template <class T, class U>
|
||||
class delegating_control_block : public control_block<T> {
|
||||
std::unique_ptr<control_block<U>> delegate_;
|
||||
|
||||
public:
|
||||
explicit delegating_control_block(std::unique_ptr<control_block<U>> b)
|
||||
: delegate_(std::move(b)) {}
|
||||
|
||||
std::unique_ptr<control_block<T>> clone() const override {
|
||||
return std::make_unique<delegating_control_block>(delegate_->clone());
|
||||
}
|
||||
|
||||
T* ptr() override { return delegate_->ptr(); }
|
||||
};
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
class bad_polymorphic_value_construction : public std::exception {
|
||||
public:
|
||||
bad_polymorphic_value_construction() noexcept = default;
|
||||
|
||||
const char* what() const noexcept override {
|
||||
return "Dynamic and static type mismatch in polymorphic_value "
|
||||
"construction";
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class polymorphic_value;
|
||||
|
||||
template <class T>
|
||||
struct is_polymorphic_value : std::false_type {};
|
||||
|
||||
template <class T>
|
||||
struct is_polymorphic_value<polymorphic_value<T>> : std::true_type {};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// `polymorphic_value` class definition
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class T>
|
||||
class polymorphic_value {
|
||||
static_assert(!std::is_union<T>::value, "");
|
||||
static_assert(std::is_class<T>::value, "");
|
||||
|
||||
template <class U>
|
||||
friend class polymorphic_value;
|
||||
|
||||
template <class T_, class U, class... Ts>
|
||||
friend polymorphic_value<T_> make_polymorphic_value(Ts&&... ts);
|
||||
template <class T_, class... Ts>
|
||||
friend polymorphic_value<T_> make_polymorphic_value(Ts&&... ts);
|
||||
|
||||
T* ptr_ = nullptr;
|
||||
std::unique_ptr<detail::control_block<T>> cb_;
|
||||
|
||||
public:
|
||||
//
|
||||
// Destructor
|
||||
//
|
||||
|
||||
~polymorphic_value() = default;
|
||||
|
||||
//
|
||||
// Constructors
|
||||
//
|
||||
|
||||
polymorphic_value() {}
|
||||
|
||||
template <class U, class C = detail::default_copy<U>,
|
||||
class D = detail::default_delete<U>,
|
||||
class V = std::enable_if_t<std::is_convertible<U*, T*>::value>>
|
||||
explicit polymorphic_value(U* u, C copier = C{}, D deleter = D{}) {
|
||||
if (!u) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef ISOCPP_P0201_POLYMORPHIC_VALUE_NO_RTTI
|
||||
if (std::is_same<D, detail::default_delete<U>>::value &&
|
||||
std::is_same<C, detail::default_copy<U>>::value &&
|
||||
typeid(*u) != typeid(U))
|
||||
throw bad_polymorphic_value_construction();
|
||||
#endif
|
||||
std::unique_ptr<U, D> p(u, std::move(deleter));
|
||||
|
||||
cb_ = std::make_unique<detail::pointer_control_block<T, U, C, D>>(
|
||||
std::move(p), std::move(copier));
|
||||
ptr_ = u;
|
||||
}
|
||||
|
||||
//
|
||||
// Copy-constructors
|
||||
//
|
||||
|
||||
polymorphic_value(const polymorphic_value& p) {
|
||||
if (!p) {
|
||||
return;
|
||||
}
|
||||
auto tmp_cb = p.cb_->clone();
|
||||
ptr_ = tmp_cb->ptr();
|
||||
cb_ = std::move(tmp_cb);
|
||||
}
|
||||
|
||||
//
|
||||
// Move-constructors
|
||||
//
|
||||
|
||||
polymorphic_value(polymorphic_value&& p) noexcept {
|
||||
ptr_ = p.ptr_;
|
||||
cb_ = std::move(p.cb_);
|
||||
p.ptr_ = nullptr;
|
||||
}
|
||||
|
||||
//
|
||||
// Converting constructors
|
||||
//
|
||||
|
||||
template <class U,
|
||||
class V = std::enable_if_t<!std::is_same<T, U>::value &&
|
||||
std::is_convertible<U*, T*>::value>>
|
||||
explicit polymorphic_value(const polymorphic_value<U>& p) {
|
||||
polymorphic_value<U> tmp(p);
|
||||
ptr_ = tmp.ptr_;
|
||||
cb_ = std::make_unique<detail::delegating_control_block<T, U>>(
|
||||
std::move(tmp.cb_));
|
||||
}
|
||||
|
||||
template <class U,
|
||||
class V = std::enable_if_t<!std::is_same<T, U>::value &&
|
||||
std::is_convertible<U*, T*>::value>>
|
||||
explicit polymorphic_value(polymorphic_value<U>&& p) {
|
||||
ptr_ = p.ptr_;
|
||||
cb_ = std::make_unique<detail::delegating_control_block<T, U>>(
|
||||
std::move(p.cb_));
|
||||
p.ptr_ = nullptr;
|
||||
}
|
||||
|
||||
#if __cplusplus < 201703L
|
||||
|
||||
#endif
|
||||
//
|
||||
// In-place constructor
|
||||
//
|
||||
|
||||
template <class U,
|
||||
class V = std::enable_if_t<
|
||||
std::is_convertible<std::decay_t<U>*, T*>::value &&
|
||||
!is_polymorphic_value<std::decay_t<U>>::value>,
|
||||
class... Ts>
|
||||
explicit polymorphic_value(nonstd_lite_in_place_type_t(U), Ts&&... ts)
|
||||
// explicit polymorphic_value(std::in_place_type_t<U>, Ts&&... ts)
|
||||
: cb_(std::make_unique<detail::direct_control_block<T, U>>(
|
||||
std::forward<Ts>(ts)...)) {
|
||||
ptr_ = cb_->ptr();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Assignment
|
||||
//
|
||||
|
||||
polymorphic_value& operator=(const polymorphic_value& p) {
|
||||
if (std::addressof(p) == this) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
if (!p) {
|
||||
cb_.reset();
|
||||
ptr_ = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto tmp_cb = p.cb_->clone();
|
||||
ptr_ = tmp_cb->ptr();
|
||||
cb_ = std::move(tmp_cb);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//
|
||||
// Move-assignment
|
||||
//
|
||||
|
||||
polymorphic_value& operator=(polymorphic_value&& p) noexcept {
|
||||
if (std::addressof(p) == this) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
cb_ = std::move(p.cb_);
|
||||
ptr_ = p.ptr_;
|
||||
p.ptr_ = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//
|
||||
// Modifiers
|
||||
//
|
||||
|
||||
void swap(polymorphic_value& p) noexcept {
|
||||
using std::swap;
|
||||
swap(ptr_, p.ptr_);
|
||||
swap(cb_, p.cb_);
|
||||
}
|
||||
|
||||
//
|
||||
// Observers
|
||||
//
|
||||
|
||||
explicit operator bool() const { return bool(cb_); }
|
||||
|
||||
const T* operator->() const {
|
||||
assert(ptr_);
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
const T& operator*() const {
|
||||
assert(*this);
|
||||
return *ptr_;
|
||||
}
|
||||
|
||||
T* operator->() {
|
||||
assert(*this);
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
T& operator*() {
|
||||
assert(*this);
|
||||
return *ptr_;
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// polymorphic_value creation
|
||||
//
|
||||
template <class T, class... Ts>
|
||||
polymorphic_value<T> make_polymorphic_value(Ts&&... ts) {
|
||||
polymorphic_value<T> p;
|
||||
p.cb_ = std::make_unique<detail::direct_control_block<T, T>>(
|
||||
std::forward<Ts>(ts)...);
|
||||
p.ptr_ = p.cb_->ptr();
|
||||
return p;
|
||||
}
|
||||
template <class T, class U, class... Ts>
|
||||
polymorphic_value<T> make_polymorphic_value(Ts&&... ts) {
|
||||
polymorphic_value<T> p;
|
||||
p.cb_ = std::make_unique<detail::direct_control_block<T, U>>(
|
||||
std::forward<Ts>(ts)...);
|
||||
p.ptr_ = p.cb_->ptr();
|
||||
return p;
|
||||
}
|
||||
|
||||
//
|
||||
// non-member swap
|
||||
//
|
||||
template <class T>
|
||||
void swap(polymorphic_value<T>& t, polymorphic_value<T>& u) noexcept {
|
||||
t.swap(u);
|
||||
}
|
||||
|
||||
} // namespace isocpp_p0201
|
||||
|
||||
#endif // ISOCPP_P0201_POLYMORPHIC_VALUE_H_INCLUDED
|
|
@ -85,7 +85,7 @@ struct TypeReflection : TypeReflectedImpl<T, false>
|
|||
|
||||
#ifndef JINJA2CPP_NO_DOXYGEN
|
||||
template<typename Derived>
|
||||
class ReflectedMapImplBase : public MapItemAccessor
|
||||
class ReflectedMapImplBase : public IMapItemAccessor
|
||||
{
|
||||
public:
|
||||
bool HasValue(const std::string& name) const override
|
||||
|
@ -158,6 +158,7 @@ class ReflectedMapImpl : public ReflectedMapImplBase<ReflectedMapImpl<T>>, publi
|
|||
{
|
||||
public:
|
||||
using ReflectedDataHolder<T>::ReflectedDataHolder;
|
||||
using ThisType = ReflectedMapImpl<T>;
|
||||
|
||||
static auto GetAccessors() {return TypeReflection<T>::GetAccessors();}
|
||||
template<typename Fn>
|
||||
|
@ -168,6 +169,15 @@ public:
|
|||
return Value();
|
||||
return accessor(*v);
|
||||
}
|
||||
|
||||
bool IsEqual(const IComparable& other) const override
|
||||
{
|
||||
auto* val = dynamic_cast<const ThisType*>(&other);
|
||||
if (!val)
|
||||
return false;
|
||||
|
||||
return this->GetValue() == val->GetValue();
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail
|
||||
|
@ -179,8 +189,9 @@ template<typename T>
|
|||
using IsReflectedType = std::enable_if_t<TypeReflection<T>::value>;
|
||||
|
||||
template<typename It>
|
||||
struct Enumerator : public ListEnumerator
|
||||
struct Enumerator : public IListEnumerator
|
||||
{
|
||||
using ThisType = Enumerator<It>;
|
||||
It m_begin;
|
||||
It m_cur;
|
||||
It m_end;
|
||||
|
@ -205,7 +216,9 @@ struct Enumerator : public ListEnumerator
|
|||
m_justInited = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
++ m_cur;
|
||||
}
|
||||
|
||||
return m_cur != m_end;
|
||||
}
|
||||
|
@ -220,7 +233,7 @@ struct Enumerator : public ListEnumerator
|
|||
auto result = std::make_unique<Enumerator<It>>(m_begin, m_end);
|
||||
result->m_cur = m_cur;
|
||||
result->m_justInited = m_justInited;
|
||||
return jinja2::ListEnumeratorPtr(result.release(), Deleter);
|
||||
return jinja2::ListEnumeratorPtr(result.release()); //, Deleter);
|
||||
}
|
||||
|
||||
ListEnumeratorPtr Move() override
|
||||
|
@ -229,20 +242,46 @@ struct Enumerator : public ListEnumerator
|
|||
result->m_cur = std::move(m_cur);
|
||||
result->m_justInited = m_justInited;
|
||||
this->m_justInited = true;
|
||||
return jinja2::ListEnumeratorPtr(result.release(), Deleter);
|
||||
return jinja2::ListEnumeratorPtr(result.release()); //, Deleter);
|
||||
}
|
||||
|
||||
static void Deleter(ListEnumerator* e)
|
||||
bool IsEqual(const IComparable& other) const override
|
||||
{
|
||||
auto* val = dynamic_cast<const ThisType*>(&other);
|
||||
if (!val)
|
||||
return false;
|
||||