/********************************************** License: BSD Project Webpage: http://cajun-jsonapi.sourceforge.net/ Author: Terry Caton ***********************************************/ #include "libaegisub/cajun/elements.h" #include "libaegisub/cajun/visitor.h" #include namespace { using namespace json; class CastVisitorBase : public Visitor { void Visit(Array&) override { } void Visit(Object&) override { } void Visit(Integer&) override { } void Visit(Double&) override { } void Visit(String&) override { } void Visit(Boolean&) override { } void Visit(Null&) override { is_null = true; } public: bool is_null = false; }; template struct CastVisitor final : public CastVisitorBase { T *element = nullptr; void Visit(T& ele) override { element = &ele; } }; } namespace json { class UnknownElement::Imp { public: virtual ~Imp() {} virtual void Accept(ConstVisitor& visitor) const = 0; virtual void Accept(Visitor& visitor) = 0; }; } namespace { template class Imp_T final : public UnknownElement::Imp { ElementTypeT m_Element; public: Imp_T(ElementTypeT element) : m_Element(std::move(element)) { } void Accept(ConstVisitor& visitor) const { visitor.Visit(m_Element); } void Accept(Visitor& visitor) { visitor.Visit(m_Element); } }; } namespace json { UnknownElement::UnknownElement() : m_pImp(new Imp_T(Null())) {} UnknownElement::UnknownElement(UnknownElement&& unknown) : m_pImp(std::move(unknown.m_pImp)) {} UnknownElement::UnknownElement(int number) : m_pImp(new Imp_T(number)) {} UnknownElement::UnknownElement(const char *string) : m_pImp(new Imp_T(string)) {} UnknownElement::~UnknownElement() { } #define DEFINE_UE_TYPE(Type) \ UnknownElement::UnknownElement(Type val) : m_pImp(new Imp_T(std::move(val))) { } \ UnknownElement::operator Type const&() const { return CastTo(); } \ UnknownElement::operator Type&() { return CastTo(); } DEFINE_UE_TYPE(Object) DEFINE_UE_TYPE(Array) DEFINE_UE_TYPE(Integer) DEFINE_UE_TYPE(Double) DEFINE_UE_TYPE(Boolean) DEFINE_UE_TYPE(String) DEFINE_UE_TYPE(Null) UnknownElement& UnknownElement::operator=(UnknownElement&& unknown) { m_pImp = std::move(unknown.m_pImp); return *this; } template ElementTypeT const& UnknownElement::CastTo() const { CastVisitor castVisitor; const_cast(this)->Accept(castVisitor); if (!castVisitor.element) throw Exception("Bad cast"); return *castVisitor.element; } template ElementTypeT& UnknownElement::CastTo() { CastVisitor castVisitor; Accept(castVisitor); // If this element is uninitialized, implicitly convert it to the desired type if (castVisitor.is_null) { *this = ElementTypeT(); return *this; } // Otherwise throw an exception if (!castVisitor.element) throw Exception("Bad cast"); return *castVisitor.element; } void UnknownElement::Accept(ConstVisitor& visitor) const { m_pImp->Accept(visitor); } void UnknownElement::Accept(Visitor& visitor) { m_pImp->Accept(visitor); } }