From 6de8a6907f21f0a2c5477e0c88b602d5d0e147be Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Fri, 29 Nov 2013 23:37:42 -0800 Subject: [PATCH] Add AbstractObject --- .../Builds/VisualStudio2012/beast.vcxproj | 11 + .../VisualStudio2012/beast.vcxproj.filters | 18 ++ src/beast/beast/SmartPtr.h | 1 + src/beast/beast/smart_ptr/AbstractObject.h | 253 ++++++++++++++++++ src/beast/beast/smart_ptr/SmartPtr.cpp | 6 + .../beast/smart_ptr/impl/AbstractObject.cpp | 150 +++++++++++ 6 files changed, 439 insertions(+) create mode 100644 src/beast/beast/smart_ptr/AbstractObject.h create mode 100644 src/beast/beast/smart_ptr/impl/AbstractObject.cpp diff --git a/src/beast/Builds/VisualStudio2012/beast.vcxproj b/src/beast/Builds/VisualStudio2012/beast.vcxproj index 9319d642ac..29ce253cfd 100644 --- a/src/beast/Builds/VisualStudio2012/beast.vcxproj +++ b/src/beast/Builds/VisualStudio2012/beast.vcxproj @@ -143,6 +143,7 @@ + @@ -511,6 +512,12 @@ true + + true + true + true + true + true @@ -1482,6 +1489,8 @@ Disabled WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) $(ProjectDir);%(AdditionalIncludeDirectories) + false + true Windows @@ -1510,6 +1519,8 @@ true WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) $(ProjectDir);%(AdditionalIncludeDirectories) + false + true Windows diff --git a/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters b/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters index dffaf6ebb9..be1df3c138 100644 --- a/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters +++ b/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters @@ -303,6 +303,18 @@ {30b0fdfb-02b6-47dd-bdd9-ffc1f57e1f2c} + + {9c1ef4c4-5623-4500-859f-12d6ce5ae362} + + + {fc3d3f14-9ba1-43e4-b086-cbbd2f63b944} + + + {44489531-f44a-439a-a6ea-d32c252b1e8b} + + + {df4f2935-13a1-4afe-90cc-d86472ec2466} + @@ -1263,6 +1275,9 @@ beast\crypto + + beast\smart_ptr + @@ -1817,6 +1832,9 @@ beast\crypto\impl + + beast\smart_ptr\impl + diff --git a/src/beast/beast/SmartPtr.h b/src/beast/beast/SmartPtr.h index 13aab726a8..c73470b262 100644 --- a/src/beast/beast/SmartPtr.h +++ b/src/beast/beast/SmartPtr.h @@ -22,6 +22,7 @@ #include "Config.h" +#include "smart_ptr/AbstractObject.h" #include "smart_ptr/ContainerDeletePolicy.h" #include "smart_ptr/SharedObject.h" #include "smart_ptr/SharedPtr.h" diff --git a/src/beast/beast/smart_ptr/AbstractObject.h b/src/beast/beast/smart_ptr/AbstractObject.h new file mode 100644 index 0000000000..36c617847b --- /dev/null +++ b/src/beast/beast/smart_ptr/AbstractObject.h @@ -0,0 +1,253 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Portions of this file are from JUCE. + Copyright (c) 2013 - Raw Material Software Ltd. + Please visit http://www.juce.com + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_SMARTPTR_ABSTRACTOBJECT_H_INCLUDED +#define BEAST_SMARTPTR_ABSTRACTOBJECT_H_INCLUDED + +#include +#include +#include +#include "../Atomic.h" +#include "../Config.h" +#include "../Uncopyable.h" +#include "../intrusive/LockFreeStack.h" +#include "../smart_ptr/ScopedPointer.h" + +namespace beast { +namespace abstract { + +/** Base for all abstract interfaces. */ +class BasicInterface +{ +public: + virtual ~BasicInterface() { } + + /** Returns the unique ID of this interface type. + The ID must be the same for all instances of the + derived interface. + */ + virtual std::size_t id () const = 0; + + /** Returns the unique ID associated with the Derived type. */ + template + static std::size_t type_id () + { + static std::size_t const value (next_id ()); + return value; + } + +private: + // Returns a new unique id + static std::size_t next_id () + { + static Atomic value; + return ++value; + } +}; + +//------------------------------------------------------------------------------ + +/** Base for a derived interface. */ +template +class Interface : public BasicInterface +{ +public: + // Returns the unique ID for all instances of Derived + std::size_t id () const + { + return BasicInterface::type_id (); + } +}; + +//------------------------------------------------------------------------------ + +/** Factory for producing interfaces on a specific object. */ +template +class Factory +{ +public: + class Callback; + +private: + struct Item; + + typedef LockFreeStack Items; + + struct Item : Items::Node + { + Item (Callback& owner_) + : owner (owner_) + { } + Callback& owner; + }; + + Items m_items; + +public: + /** Base for hooking object creation. */ + class Callback + { + public: + /** Create the callback and insert it into the factory. */ + explicit Callback (Factory& factory) + : m_item (*this) + { + factory.m_items.push_front (&m_item); + } + + /** Called when Object is created. + Object must be fully constructed. The order of calls to callbacks + is not defined. + */ + virtual void create_interfaces (Object& object) = 0; + + private: + Item m_item; + }; + + /** Invokes the callbacks for an instance of Object. + This must be called after the object is fully constructed, for example + as the last statement in the constructor. + */ + void create_interfaces (Object& object) + { + for (typename Items::iterator iter (m_items.begin()); + iter != m_items.end(); ++iter) + iter->owner.create_interfaces (object); + } +}; + +//------------------------------------------------------------------------------ + +/** A container of polymorphic interfaces. + The Object type associated with the container is used to gain access + to the corresponding factory. +*/ +template +class Interfaces : public Uncopyable +{ +public: + Interfaces () + { + } + + /** Returns a reference to the specified interface. + The interface must exist in the container or an exception is thrown. + Requirements: + Derived must be a subclass of Interface + */ + /** @{ */ + template + Derived& get_interface() + { + Derived* derived (find_interface ()); + if (derived == nullptr) + throw std::bad_cast (); + return *derived; + } + + template + Derived const& get_interface() const + { + Derived const* derived (find_interface ()); + if (derived == nullptr) + throw std::bad_cast (); + return *derived; + } + /** @} */ + + /** Returns a pointer to the specified interface. + If the interface does not exist, `nullptr` is returned. + Requirements: + Derived must be a subclass of Interface + */ + /** @{ */ + template + Derived* find_interface() + { + std::size_t const id = BasicInterface::type_id (); + + for (typename Set::iterator iter (m_set.begin()); + iter != m_set.end(); ++iter) + { + if ((*iter)->id() == id) + { + Derived* const derived ( + dynamic_cast (iter->get())); + check_postcondition (derived != nullptr); + return derived; + } + } + return nullptr; + } + + template + Derived const* find_interface() const + { + std::size_t const id = BasicInterface::type_id (); + + for (typename Set::const_iterator iter (m_set.begin()); + iter != m_set.end(); ++iter) + { + if ((*iter)->id() == id) + { + Derived const* const derived ( + dynamic_cast (iter->get())); + check_postcondition (derived != nullptr); + return derived; + } + } + return nullptr; + } + + template + bool has_interface() const + { + return find_interface () != nullptr; + } + /** @} */ + + /** Adds the specified interface to the container. + Ownership of the object, which must be allocated via operator new, + is transferred to the container. If the interface already exists, + an exception is thrown. + Requirements: + Derived must be a subclass of Interface + */ + template + void add_interface (ScopedPointer && derived) + { + if (has_interface ()) + throw std::invalid_argument ("non-unique"); + m_set.emplace_back (derived); + } + +private: + typedef std::list > Set; + Set m_set; +}; + +} +} + +#endif diff --git a/src/beast/beast/smart_ptr/SmartPtr.cpp b/src/beast/beast/smart_ptr/SmartPtr.cpp index 02700c5642..59a677e492 100644 --- a/src/beast/beast/smart_ptr/SmartPtr.cpp +++ b/src/beast/beast/smart_ptr/SmartPtr.cpp @@ -19,7 +19,13 @@ #include "BeastConfig.h" +#include "../Config.h" + #include "ContainerDeletePolicy.h" #include "ScopedPointer.h" #include "SharedObject.h" #include "SharedPtr.h" + +#include "../../modules/beast_core/beast_core.h" // for UnitTest + +#include "impl/AbstractObject.cpp" diff --git a/src/beast/beast/smart_ptr/impl/AbstractObject.cpp b/src/beast/beast/smart_ptr/impl/AbstractObject.cpp new file mode 100644 index 0000000000..f60e48b27d --- /dev/null +++ b/src/beast/beast/smart_ptr/impl/AbstractObject.cpp @@ -0,0 +1,150 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Portions of this file are from JUCE. + Copyright (c) 2013 - Raw Material Software Ltd. + Please visit http://www.juce.com + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "../AbstractObject.h" + +namespace beast { +namespace abstract { + +class AbstractObjectTests : public UnitTest +{ +public: + class Object : public Interfaces + { + public: + explicit Object (UnitTest& test) + : m_test (test) + { + } + + UnitTest& test () + { + return m_test; + } + + private: + UnitTest& m_test; + }; + + //-------------------------------------------------------------------------- + + class Interface1 : public Interface + { + public: + Interface1 () + { + } + }; + + class Callback1 : public Factory ::Callback + { + public: + explicit Callback1 (Factory & factory) + : Factory ::Callback (factory) + { + } + + void create_interfaces (Object& object) + { + object.add_interface (ScopedPointer ( + new Interface1)); + } + }; + + //-------------------------------------------------------------------------- + + class Interface2 : public Interface + { + public: + Interface2 () + { + } + }; + + class Callback2 : public Factory ::Callback + { + public: + explicit Callback2 (Factory & factory) + : Factory ::Callback (factory) + { + } + + void create_interfaces (Object& object) + { + object.add_interface (ScopedPointer ( + new Interface2)); + } + }; + + //-------------------------------------------------------------------------- + + void runTest () + { + beginTestCase ("create"); + + Factory factory; + Callback1 callback1 (factory); + Callback2 callback2 (factory); + + Object object (*this); + factory.create_interfaces (object); + + // find existing interfaces + expect (object.find_interface () != nullptr); + expect (object.find_interface () != nullptr); + + // add duplicate interface + try + { + object.add_interface (ScopedPointer ( + new Interface1)); + fail ("uncaught exeption"); + } + catch (std::invalid_argument const&) + { + pass (); + } + + // request missing interface + try + { + struct MissingInterface { }; + object.get_interface (); + fail ("uncaught exeption"); + } + catch (std::bad_cast const&) + { + pass (); + } + } + + AbstractObjectTests () : UnitTest ( + "AbstractObject", "beast") + { + } +}; + +static AbstractObjectTests abstractObjectTests; + +} +}