Add AbstractObject

This commit is contained in:
Vinnie Falco
2013-11-29 23:37:42 -08:00
parent d346e6645a
commit 045e38314a
6 changed files with 439 additions and 0 deletions

View File

@@ -143,6 +143,7 @@
<ClInclude Include="..\..\beast\net\IPAddress.h" />
<ClInclude Include="..\..\beast\SafeBool.h" />
<ClInclude Include="..\..\beast\SmartPtr.h" />
<ClInclude Include="..\..\beast\smart_ptr\AbstractObject.h" />
<ClInclude Include="..\..\beast\smart_ptr\ContainerDeletePolicy.h" />
<ClInclude Include="..\..\beast\smart_ptr\ScopedPointer.h" />
<ClInclude Include="..\..\beast\smart_ptr\SharedObject.h" />
@@ -511,6 +512,12 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\beast\net\Net.cpp" />
<ClCompile Include="..\..\beast\smart_ptr\impl\AbstractObject.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\beast\smart_ptr\SmartPtr.cpp" />
<ClCompile Include="..\..\beast\strings\impl\CharacterFunctions.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
@@ -1482,6 +1489,8 @@
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableLanguageExtensions>false</DisableLanguageExtensions>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@@ -1510,6 +1519,8 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableLanguageExtensions>false</DisableLanguageExtensions>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>

View File

@@ -303,6 +303,18 @@
<Filter Include="beast\asio\impl">
<UniqueIdentifier>{30b0fdfb-02b6-47dd-bdd9-ffc1f57e1f2c}</UniqueIdentifier>
</Filter>
<Filter Include="beast\http\crypto">
<UniqueIdentifier>{9c1ef4c4-5623-4500-859f-12d6ce5ae362}</UniqueIdentifier>
</Filter>
<Filter Include="beast\http\crypto\impl">
<UniqueIdentifier>{fc3d3f14-9ba1-43e4-b086-cbbd2f63b944}</UniqueIdentifier>
</Filter>
<Filter Include="beast\http\crypto\impl\sha2">
<UniqueIdentifier>{44489531-f44a-439a-a6ea-d32c252b1e8b}</UniqueIdentifier>
</Filter>
<Filter Include="beast\smart_ptr\impl">
<UniqueIdentifier>{df4f2935-13a1-4afe-90cc-d86472ec2466}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\modules\beast_core\beast_core.h">
@@ -1263,6 +1275,9 @@
<ClInclude Include="..\..\beast\crypto\MurmurHash.h">
<Filter>beast\crypto</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\smart_ptr\AbstractObject.h">
<Filter>beast\smart_ptr</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\modules\beast_core\containers\AbstractFifo.cpp">
@@ -1817,6 +1832,9 @@
<ClCompile Include="..\..\beast\crypto\impl\MurmurHash.cpp">
<Filter>beast\crypto\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\smart_ptr\impl\AbstractObject.cpp">
<Filter>beast\smart_ptr\impl</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Text Include="..\..\TODO.txt">

View File

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

View File

@@ -0,0 +1,253 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 <list>
#include <stdexcept>
#include <typeinfo>
#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 <typename Derived>
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 <std::size_t> value;
return ++value;
}
};
//------------------------------------------------------------------------------
/** Base for a derived interface. */
template <typename Derived>
class Interface : public BasicInterface
{
public:
// Returns the unique ID for all instances of Derived
std::size_t id () const
{
return BasicInterface::type_id <Derived> ();
}
};
//------------------------------------------------------------------------------
/** Factory for producing interfaces on a specific object. */
template <typename Object>
class Factory
{
public:
class Callback;
private:
struct Item;
typedef LockFreeStack <Item> 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 <typename Object>
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 <typename Derived>
Derived& get_interface()
{
Derived* derived (find_interface <Derived> ());
if (derived == nullptr)
throw std::bad_cast ();
return *derived;
}
template <typename Derived>
Derived const& get_interface() const
{
Derived const* derived (find_interface <Derived> ());
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 <typename Derived>
Derived* find_interface()
{
std::size_t const id = BasicInterface::type_id <Derived> ();
for (typename Set::iterator iter (m_set.begin());
iter != m_set.end(); ++iter)
{
if ((*iter)->id() == id)
{
Derived* const derived (
dynamic_cast <Derived*> (iter->get()));
check_postcondition (derived != nullptr);
return derived;
}
}
return nullptr;
}
template <typename Derived>
Derived const* find_interface() const
{
std::size_t const id = BasicInterface::type_id <Derived> ();
for (typename Set::const_iterator iter (m_set.begin());
iter != m_set.end(); ++iter)
{
if ((*iter)->id() == id)
{
Derived const* const derived (
dynamic_cast <Derived const*> (iter->get()));
check_postcondition (derived != nullptr);
return derived;
}
}
return nullptr;
}
template <typename Derived>
bool has_interface() const
{
return find_interface <Derived> () != 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 <typename Derived>
void add_interface (ScopedPointer <Derived>&& derived)
{
if (has_interface <Derived> ())
throw std::invalid_argument ("non-unique");
m_set.emplace_back (derived);
}
private:
typedef std::list <ScopedPointer <BasicInterface>> Set;
Set m_set;
};
}
}
#endif

View File

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

View File

@@ -0,0 +1,150 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 <Object>
{
public:
explicit Object (UnitTest& test)
: m_test (test)
{
}
UnitTest& test ()
{
return m_test;
}
private:
UnitTest& m_test;
};
//--------------------------------------------------------------------------
class Interface1 : public Interface <Interface1>
{
public:
Interface1 ()
{
}
};
class Callback1 : public Factory <Object>::Callback
{
public:
explicit Callback1 (Factory <Object>& factory)
: Factory <Object>::Callback (factory)
{
}
void create_interfaces (Object& object)
{
object.add_interface (ScopedPointer <Interface1> (
new Interface1));
}
};
//--------------------------------------------------------------------------
class Interface2 : public Interface <Interface2>
{
public:
Interface2 ()
{
}
};
class Callback2 : public Factory <Object>::Callback
{
public:
explicit Callback2 (Factory <Object>& factory)
: Factory <Object>::Callback (factory)
{
}
void create_interfaces (Object& object)
{
object.add_interface (ScopedPointer <Interface2> (
new Interface2));
}
};
//--------------------------------------------------------------------------
void runTest ()
{
beginTestCase ("create");
Factory <Object> factory;
Callback1 callback1 (factory);
Callback2 callback2 (factory);
Object object (*this);
factory.create_interfaces (object);
// find existing interfaces
expect (object.find_interface <Interface1> () != nullptr);
expect (object.find_interface <Interface2> () != nullptr);
// add duplicate interface
try
{
object.add_interface (ScopedPointer <Interface1> (
new Interface1));
fail ("uncaught exeption");
}
catch (std::invalid_argument const&)
{
pass ();
}
// request missing interface
try
{
struct MissingInterface { };
object.get_interface <MissingInterface> ();
fail ("uncaught exeption");
}
catch (std::bad_cast const&)
{
pass ();
}
}
AbstractObjectTests () : UnitTest (
"AbstractObject", "beast")
{
}
};
static AbstractObjectTests abstractObjectTests;
}
}