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 aliases
master
rmorozov 2021-12-12 23:20:15 +03:00 committed by GitHub
parent 4b86a7cecb
commit 6092f44df1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 3513 additions and 2122 deletions

View File

@ -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

1
.gitignore vendored
View File

@ -33,3 +33,4 @@
build/
dist/
compile_commands.json

View File

@ -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 ()

View File

@ -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<>

View File

@ -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>

View File

@ -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;
};

View File

@ -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

View File

@ -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;
};

View File

@ -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

View File

@ -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

View File

@ -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;