#pragma once #include #include #include #include #include class bad_cast : public std::exception { std::string why; public: bad_cast( const std::type_index& f, const std::type_index& t ) : std::exception() { why = std::string{"bad cast of "} + f.name() + " to " + t.name(); } ~bad_cast() override = default; const char* what() const noexcept override { return why.c_str(); } }; template std::type_index class_of() { return { typeid(T) }; } class object { public: std::type_index get_class() const { return { typeid(*this) }; } template T& as() { std::type_index from = get_class(), to = class_of(); if ( from != to ) throw bad_cast{ from, to }; return reinterpret_cast(*this); } template const T& as() const { std::type_index from = get_class(), to = class_of(); if ( from != to ) throw bad_cast{ from, to }; return reinterpret_cast(*this); } virtual std::unique_ptr new_inst() const = 0; virtual std::unique_ptr new_copy() const = 0; virtual object& operator= (const object&) = 0; virtual ~object() = default; }; template T* as_subclass_of( object* o ) { T* r = dynamic_cast( o ); if ( r == nullptr ) throw bad_cast{ o->get_class(), class_of() }; return r; } template const T* as_subclass_of( const object* o ) { const T* r = dynamic_cast( o ); if ( r == nullptr ) throw bad_cast{ o->get_class(), class_of() }; return r; } class ordered : public object { public: virtual int cmp(const ordered&) const = 0; bool operator< (const ordered& that) const { return cmp(that) < 0; } bool operator<= ( const ordered& that ) const { return cmp(that) <= 0; } bool operator== ( const ordered& that ) const { return cmp(that) == 0; } bool operator!= ( const ordered& that ) const { return cmp(that) != 0; } bool operator> ( const ordered& that ) const { return cmp(that) > 0; } bool operator>= ( const ordered& that ) const { return cmp(that) >= 0; } }; class boolean : public ordered { private: bool x; public: boolean() = default; boolean(bool x) : x(x) {} std::unique_ptr new_inst() const override { return std::make_unique(); } std::unique_ptr new_copy() const override { return std::make_unique(*this); } boolean& operator= (const boolean& that) { x = that.x; return *this; } object& operator= (const object& that) override { std::type_index from = that.get_class(), to = get_class(); if ( from != to ) throw bad_cast{ from, to }; return *this = static_cast(that); } ~boolean() override = default; int cmp(const boolean& that) const { return x == that.x ? 0 : x == false ? -1 : 1; } // bool operator< (const boolean& that) const { return x < that.x; } // bool operator== (const boolean& that) const { return x == that.x; } int cmp(const ordered& that) const override { std::type_index from = that.get_class(), to = get_class(); if ( from != to ) throw bad_cast{ from, to }; return cmp( static_cast(that) ); } }; class character : public ordered { private: char x; public: character() = default; character(char x) : x(x) {} std::unique_ptr new_inst() const override { return std::make_unique(); } std::unique_ptr new_copy() const override { return std::make_unique(*this); } character& operator= (const character& that) { x = that.x; return *this; } object& operator= (const object& that) override { std::type_index from = that.get_class(), to = get_class(); if ( from != to ) throw bad_cast{ from, to }; return *this = static_cast(that); } ~character() override = default; int cmp(const character& that) const { return x == that.x ? 0 : x < that.x ? -1 : 1; } // bool operator< (const character& that) const { return x < that.x; } // bool operator== (const character& that) const { return x == that.x; } int cmp(const ordered& that) const override { std::type_index from = that.get_class(), to = get_class(); if ( from != to ) throw bad_cast{ from, to }; return cmp( static_cast(that) ); } }; class integer : public ordered { private: int x; public: integer() = default; integer(int x) : x(x) {} std::unique_ptr new_inst() const override { return std::make_unique(); } std::unique_ptr new_copy() const override { return std::make_unique(*this); } integer& operator= (const integer& that) { x = that.x; return *this; } object& operator= (const object& that) override { std::type_index from = that.get_class(), to = get_class(); if ( from != to ) throw bad_cast{ from, to }; return *this = static_cast(that); } ~integer() override = default; int cmp(const integer& that) const { return x == that.x ? 0 : x < that.x ? -1 : 1; } // bool operator< (const integer& that) const { return x < that.x; } // bool operator== (const integer& that) const { return x == that.x; } int cmp(const ordered& that) const override { std::type_index from = that.get_class(), to = get_class(); if ( from != to ) throw bad_cast{ from, to }; return cmp( static_cast(that) ); } }; class pair : public ordered { private: std::unique_ptr x; std::unique_ptr y; public: pair() = default; pair(std::unique_ptr&& x, std::unique_ptr&& y) : x(std::move(x)), y(std::move(y)) {} std::unique_ptr new_inst() const override { return std::make_unique(); } std::unique_ptr new_copy() const override { return std::make_unique(x->new_copy(), y->new_copy()); } pair& operator= (const pair& that) { x = that.x->new_copy(); y = that.y->new_copy(); return *this; } object& operator= (const object& that) override { std::type_index from = that.get_class(), to = get_class(); if ( from != to ) throw bad_cast{ from, to }; return *this = static_cast(that); } ~pair() override = default; int cmp(const pair& that) const { const ordered* a = as_subclass_of( x.get() ); const ordered* b = as_subclass_of( that.x.get() ); int c = a->cmp( *b ); if ( c != 0 ) return c; a = as_subclass_of( y.get() ); b = as_subclass_of( that.y.get() ); return a->cmp( *b ); } // bool operator< (const pair& that) const { return cmp(that) < 0; } // bool operator== ( const pair& that) const { return cmp(that) == 0; } int cmp(const ordered& that) const override { std::type_index from = that.get_class(), to = get_class(); if ( from != to ) throw bad_cast{ from, to }; return cmp( static_cast(that) ); } };