Sign in to follow this  
MaulingMonkey

libindustry [ overengineered factory template class! ]

Recommended Posts

libindustry My generic components library, released under the Boost license. The main focal point of the library is currently the most overengineered factory classes for C++, ever, that I am aware of, with plans for much more! News 5/31/06 - libindustry-0.2 has now been released! This version comes after a few days of refactoring, and now supports boost::any, boost::variant*, boost::shared_ptr, std::auto_ptr, and raw pointers. create(id,...) now correctly throws an exception if a type hasn't been registered with type<T>(), and the new syntax for factory instantiation (no need for the methods<> wrapper there, although it is still supported). Compile times are growing, compile optimization will end up on the TODO list soon. Still reasonable if you ask me. * Note: You must still register the individual types with type<T> when using boost::variant. This should be done automatically in a future release, hopefully. 5/27/06 - libindustry-0.1.1 has now been released! Got access to my windows computer again, now compiles on VS2k5, added the missing return keyword in industry::type's comparison operators. Added -Wall to my internal build system's flags so an error like that won't make it to release again (so shameful!) 5/21/06 - libindustry-0.1 is has now been released! The Download Latest version: http://homepage.mac.com/pandamojo/industry/industry-0.2.zip The library is header-only, just copy and go! Source files included within the zip are tests/examples. Requirements The Boost Library (Preprocessor and Any, currently) Compatibility Visual Studio 2005 Express (tested OK 0.2) GCC 4.0.0 (tested OK 0.2) Example: test.factory.cpp (0.2)
// Copyright (c) 2006 Michael B. Edwin Rickert
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt )
//
// May 31, 2006 - Some refactoring, templatized test function and tested for all 5 currently supported types
// May 31, 2006 - Re-enabled invalid type test (throws instead of asserts now)
// May 27, 2006 - Disabled intentional assert, added void(void) to the test
// May 21, 2006 - Created

#include "industry.factory.hpp"
#include <boost/array.hpp>
#include <iostream>
#include <cassert>

struct base { virtual ~base() {} };

struct foo : base {
	foo( void )          { std::cout << "foo( void )" << std::endl; }
	foo( int n )         { std::cout << "foo( int " << n << " )" << std::endl; }
	foo( char c )        { std::cout << "foo( char " << c << " )" << std::endl; }
	foo( int a , int b ) { std::cout << "foo( int a " << a << " , int b " << b << " )" << std::endl; }
	foo( const foo & )   { std::cout << "foo( const foo & )" << std::endl; }
};
struct bar : base {
	bar( void )          { std::cout << "bar( void )" << std::endl; }
	bar( int n )         { std::cout << "bar( int " << n << " )" << std::endl; }
	bar( char c )        { std::cout << "bar( char " << c << " )" << std::endl; }
	bar( int a , int b ) { std::cout << "bar( int a " << a << " , int b " << b << " )" << std::endl; }
	bar( const foo & )   { std::cout << "bar( const bar & )" << std::endl; }
};

template < typename T > void verify( const boost::any & any ) {
	std::cout << "Verifying boost::any == T ..." << std::flush;
	boost::any_cast< T >( any ); //should throw on failure
	std::cout << "OK!" << std::endl;
}

template < typename T , typename B > void verify( const boost::shared_ptr<B> & ptr ) {
	std::cout << "Verifying boost::shared_ptr<B> == T ..." << std::flush;
	assert( dynamic_cast< T* >( ptr.get() ) );
	std::cout << "OK!" << std::endl;
}

template < typename T , typename B > void verify( const std::auto_ptr<B> & ptr ) {
	std::cout << "Verifying std::auto_ptr<B> == T ..." << std::flush;
	assert( dynamic_cast< T* >( ptr.get() ) );
	std::cout << "OK!" << std::endl;
}

template < typename T , BOOST_PP_ENUM_PARAMS( BOOST_VARIANT_LIMIT_TYPES , typename V ) >
void verify( const boost::variant< BOOST_PP_ENUM_PARAMS( BOOST_VARIANT_LIMIT_TYPES , V ) > & variant ) {
	std::cout << "Verifying boost::variant< ... > == T ..." << std::flush;
	boost::get< T >( variant ); //should throw on failure
	std::cout << "OK!" << std::endl;
}

template < typename T , typename B > void verify( B * ptr ) {
	std::cout << "Verifying B * == T ..." << std::flush;
	assert( dynamic_cast< T* >( ptr ) );
	std::cout << "OK!" << std::endl;
}

template < typename InterfaceT >
void test_factory_interface( void ) {
	industry::factory< InterfaceT , industry::methods< void ( void ) , void ( int ) , void( char ) , void ( int , int ) > > factory_via_methods;
	industry::factory< InterfaceT , void ( void ) , void ( int ) , void( char ) , void ( int , int ) > factory;
	factory.template type< foo >();
	factory.template type< bar >();
	
	boost::array< industry::type , 2 > types = { typeid(foo) , typeid(bar) };
	boost::array< InterfaceT , 2 > example;
	for ( unsigned i = 0 ; i < 2 ; ++i ) {
		example[i] = factory.create( types[i] , 42 );
	}
	
	verify< foo >( example[0] );
	verify< bar >( example[1] );
	
	InterfaceT v  = factory.create( typeid(foo) );
	InterfaceT u  = factory.create( typeid(foo) , 42 );
	InterfaceT c  = factory.create( typeid(foo) , 'c' );
	InterfaceT uu = factory.create( typeid(foo) , 42 , 42 );
	
	bool threw = false;
	try { //will throw bad_factory_type, hasn't been added with type<>()
		InterfaceT baz = factory.create( typeid(int) , 42 );
	} catch( industry::bad_factory_type ) {
		threw = true;
	}
	assert( threw );
	std::cout << "====================================" << std::endl;
}

void test_shared_ptr_factory( void ) {
	industry::factory< boost::shared_ptr< base > , void ( void ) , void ( int ) , void ( char ) , void ( int , int ) > factory;
	
	factory.type< foo >();
	factory.type< bar >();
	
	boost::array< industry::type , 2 > types = { typeid(foo) , typeid(bar) };
	boost::array< boost::shared_ptr< base > , 2 > example;
	for ( unsigned i = 0 ; i < 2 ; ++i ) {
		example[i] = factory.create( types[i] , 42 );
	}
}

void test_factory( void ) {
	test_factory_interface< boost::any >();
	test_factory_interface< std::auto_ptr< base > >();
	test_factory_interface< boost::shared_ptr< base > >();
	test_factory_interface< boost::variant< foo , bar > >();
	test_factory_interface< base * >(); //WARNING: Will leak, I'm a lazy bum.
}

Results (as expected):
Beginning test...
foo( int 42 )
foo( const foo & )
foo( const foo & )
foo( const foo & )
bar( int 42 )
Verifying boost::any == T ...foo( const foo & )
OK!
Verifying boost::any == T ...OK!
foo( void )
foo( const foo & )
foo( const foo & )
foo( int 42 )
foo( const foo & )
foo( const foo & )
foo( char c )
foo( const foo & )
foo( const foo & )
foo( int a 42 , int b 42 )
foo( const foo & )
foo( const foo & )
====================================
foo( int 42 )
bar( int 42 )
Verifying std::auto_ptr == T ...OK!
Verifying std::auto_ptr == T ...OK!
foo( void )
foo( int 42 )
foo( char c )
foo( int a 42 , int b 42 )
====================================
foo( int 42 )
bar( int 42 )
Verifying boost::shared_ptr == T ...OK!
Verifying boost::shared_ptr == T ...OK!
foo( void )
foo( int 42 )
foo( char c )
foo( int a 42 , int b 42 )
====================================
foo( void )
foo( void )
foo( int 42 )
foo( const foo & )
foo( const foo & )
bar( int 42 )
Verifying boost::variant< ... > == T ...OK!
Verifying boost::variant< ... > == T ...OK!
foo( void )
foo( const foo & )
foo( const foo & )
foo( int 42 )
foo( const foo & )
foo( const foo & )
foo( char c )
foo( const foo & )
foo( const foo & )
foo( int a 42 , int b 42 )
foo( const foo & )
foo( const foo & )
====================================
foo( int 42 )
bar( int 42 )
Verifying B * == T ...OK!
Verifying B * == T ...OK!
foo( void )
foo( int 42 )
foo( char c )
foo( int a 42 , int b 42 )
====================================
All succeeded!
Press any key to continue . . .
[Edited by - MaulingMonkey on May 31, 2006 8:32:04 PM]

Share this post


Link to post
Share on other sites
A great way of adding more over-engineering to that interface would be to make industry::methods<> actually be a typelist (so you could have any number of those). I'm just sayin'... :-)

Share this post


Link to post
Share on other sites
Quote:
Original post by hplus0603
A great way of adding more over-engineering to that interface would be to make industry::methods<> actually be a typelist (so you could have any number of those). I'm just sayin'... :-)


I was originally using boost::mpl containers, but the messyness of having to use "typename container<...>::type" in many places, besides only working with one mpl container, made me decide to use a simpler typedef.

In the next phases of refactoring, the current factory class will probably become factory_base. The new factory template will be N-ary template argumented, so the methods<> list will be un-necessary. I'll add partial specializations to allow the current factory< T , methods< ... > > syntax, and probably factory< T , boost::mpl::container< ... >::type > as well. I'll extend methods< ... > if it makes refactoring easier, but with these changes, boost::mpl should be a better alternative (pre-existing usage, more advanced, etc)

Internal refactoring is also on the list, namely, pulling the boost::any related specifics out and into their own "plugin" template, which should ease the creation of boost::factory< boost::shared_ptr<T> | boost::scoped_ptr<T> | std::auto_ptr<T> | T * | users_custom_smart_ptr_class< T > >.

I'm also considering relaxing the restrictions on the return type of methods, currently they're required to be void (whereas boost::any might be more "appropriate", and in the end, any return type would be okay since it's replaced anyways). *shrug*

Share this post


Link to post
Share on other sites
Sign in to follow this