#ifndef JINJA2CPP_SRC_GENERIC_ADAPTERS_H #define JINJA2CPP_SRC_GENERIC_ADAPTERS_H #include <jinja2cpp/value.h> #include "internal_value.h" namespace jinja2 { template<typename ImplType, typename List, typename ValType, typename Base> class IndexedEnumeratorImpl : public Base { public: using ValueType = ValType; using ThisType = IndexedEnumeratorImpl<ImplType, List, ValType, Base>; IndexedEnumeratorImpl(const List* list) : m_list(list) , m_maxItems(list->GetSize().value()) { } void Reset() override { m_curItem = m_invalidIndex; } bool MoveNext() override { if (m_curItem == m_invalidIndex) m_curItem = 0; else ++ m_curItem; return m_curItem < m_maxItems; } bool IsEqual(const IComparable& other) const override { auto* val = dynamic_cast<const ThisType*>(&other); if (!val) return false; if (m_list && val->m_list && !m_list->IsEqual(*val->m_list)) return false; if ((m_list && !val->m_list) || (!m_list && val->m_list)) return false; if (m_curItem != val->m_curItem) return false; if (m_maxItems != val->m_maxItems) return false; return true; } protected: constexpr static auto m_invalidIndex = std::numeric_limits<size_t>::max(); const List* m_list{}; size_t m_curItem = m_invalidIndex; size_t m_maxItems{}; }; template<typename T> class IndexedListItemAccessorImpl : public IListItemAccessor, public IIndexBasedAccessor { public: using ThisType = IndexedListItemAccessorImpl<T>; class Enumerator : public IndexedEnumeratorImpl<Enumerator, ThisType, Value, IListEnumerator> { public: using BaseClass = IndexedEnumeratorImpl<Enumerator, ThisType, Value, IListEnumerator>; #if defined(_MSC_VER) using IndexedEnumeratorImpl::IndexedEnumeratorImpl; #else using BaseClass::BaseClass; #endif typename BaseClass::ValueType GetCurrent() const override { auto indexer = this->m_list->GetIndexer(); if (!indexer) return Value(); return indexer->GetItemByIndex(this->m_curItem); } ListEnumeratorPtr Clone() const override { auto result = MakeEnumerator<Enumerator>(this->m_list); auto base = static_cast<Enumerator*>(&(*result)); base->m_curItem = this->m_curItem; return result; } ListEnumeratorPtr Move() override { auto result = MakeEnumerator<Enumerator>(this->m_list); auto base = static_cast<Enumerator*>(&(*result)); base->m_curItem = this->m_curItem; this->m_list = nullptr; this->m_curItem = this->m_invalidIndex; this->m_maxItems = 0; return result; } }; Value GetItemByIndex(int64_t idx) const override { return IntValue2Value(std::move(static_cast<const T*>(this)->GetItem(idx).value())); } std::optional<size_t> GetSize() const override { return static_cast<const T*>(this)->GetItemsCountImpl(); } const IIndexBasedAccessor* GetIndexer() const override { return this; } ListEnumeratorPtr CreateEnumerator() const override; bool IsEqual(const IComparable& other) const override { auto* val = dynamic_cast<const ThisType*>(&other); if (!val) return false; auto enumerator = CreateEnumerator(); auto otherEnum = val->CreateEnumerator(); if (enumerator && otherEnum && !enumerator->IsEqual(*otherEnum)) return false; return true; } }; template<typename T> class IndexedListAccessorImpl : public IListAccessor, public IndexedListItemAccessorImpl<T> { public: using ThisType = IndexedListAccessorImpl<T>; class Enumerator : public IndexedEnumeratorImpl<Enumerator, ThisType, InternalValue, IListAccessorEnumerator> { public: using BaseClass = IndexedEnumeratorImpl<Enumerator, ThisType, InternalValue, IListAccessorEnumerator>; #if defined(_MSC_VER) using IndexedEnumeratorImpl::IndexedEnumeratorImpl; #else using BaseClass::BaseClass; #endif typename BaseClass::ValueType GetCurrent() const override { const auto& result = this->m_list->GetItem(this->m_curItem); if (!result) return InternalValue(); return result.value(); } IListAccessorEnumerator* Clone() const override { auto result = new Enumerator(this->m_list); auto base = result; base->m_curItem = this->m_curItem; return result; } IListAccessorEnumerator* Transfer() override { auto result = new Enumerator(std::move(*this)); auto base = result; base->m_curItem = this->m_curItem; this->m_list = nullptr; this->m_curItem = this->m_invalidIndex; this->m_maxItems = 0; return result; } }; std::optional<size_t> GetSize() const override { return static_cast<const T*>(this)->GetItemsCountImpl(); } ListAccessorEnumeratorPtr CreateListAccessorEnumerator() const override; }; template<typename T> class MapItemAccessorImpl : public IMapItemAccessor { public: Value GetValueByName(const std::string& name) const { return IntValue2Value(static_cast<const T*>(this)->GetItem(name)); } }; template<typename T> class MapAccessorImpl : public IMapAccessor, public MapItemAccessorImpl<T> { public: }; template<typename T> inline ListAccessorEnumeratorPtr IndexedListAccessorImpl<T>::CreateListAccessorEnumerator() const { return ListAccessorEnumeratorPtr(new Enumerator(this)); } template<typename T> inline ListEnumeratorPtr IndexedListItemAccessorImpl<T>::CreateEnumerator() const { return MakeEnumerator<Enumerator>(this); } } // namespace jinja2 #endif // JINJA2CPP_SRC_GENERIC_ADAPTERS_H