libindustry [ overengineered factory template class! ]

Started by
2 comments, last by MaulingMonkey 17 years, 10 months ago
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 = factory.create( types , 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 = factory.create( types , 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]
Advertisement
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'... :-)
enum Bool { True, False, FileNotFound };
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*
libindustry-0.2 has been released!!!

This topic is closed to new replies.

Advertisement