text: // @HEADER
  // ***********************************************************************
  //
  //                    Teuchos: Common Tools Package
  //                 Copyright (2004) Sandia Corporation
  //
  // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
  // license for use of this work by or on behalf of the U.S. Government.
  //
  // Redistribution and use in source and binary forms, with or without
  // modification, are permitted provided that the following conditions are
  // met:
  //
  // 1. Redistributions of source code must retain the above copyright
  // notice, this list of conditions and the following disclaimer.
  //
  // 2. Redistributions in binary form must reproduce the above copyright
  // notice, this list of conditions and the following disclaimer in the
  // documentation and/or other materials provided with the distribution.
  //
  // 3. Neither the name of the Corporation nor the names of the
  // contributors may be used to endorse or promote products derived from
  // this software without specific prior written permission.
  //
  // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
  // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
  // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  //
  // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
  //
  // ***********************************************************************
  // @HEADER
  
  #ifndef TEUCHOS_ABSTRACT_FACTORY_STD_HPP
  #define TEUCHOS_ABSTRACT_FACTORY_STD_HPP
  
  #include "Teuchos_AbstractFactory.hpp"
  
  namespace Teuchos {
  
  /** \brief Default post-modification policy class for
   * <tt>AbstractFactorStd</tt> which does nothing!
   */
  template<class T_impl>
  class PostModNothing {
  public:
  	/** \brief . */
  	void initialize(T_impl* p) const {} // required!
  };
  
  /** \brief Default allocation policy class for
   * <tt>AbstractFactoryStd</tt> which returns <tt>new T_impl()</tt>.
   */
  template<class T_impl>
  class AllocatorNew {
  public:
    /** \brief . */
    typedef Teuchos::RCP<T_impl>  ptr_t;                         // required!
    /** \brief . */
    const ptr_t allocate() const { return Teuchos::rcp(new T_impl()); }  // required!
  };
  
  /** \brief Simple, templated concrete subclass of universal "Abstract
   * Factory" interface for the creation of objects.
   *
   * This concrete subclass represents a general
   * <tt>AbstractFactory</tt> subclass that can be modified through
   * policy template parameters.  This class is templated on the
   * interface type <tt>T_itfc</tt> that is exposed by the
   * <tt>AbstractFactory<T_itfc></tt> base interface and by a (concrete)
   * implementation type <tt>T_impl</tt>.  The most typical use of this
   * subclass is to use a concrete, default-constructable subclass for
   * <tt>T_impl</tt> and then to simply instantiate a concrete abstract
   * factory for that class using:
   
   \verbatim
  
   Teuchos::AbstractFactoryStd<T_itfc,T_impl>  abstractFactory;
   \endverbatim
   *
   * For this default usage, The only requirements for the derived classes type
   * <tt>T_impl</tt> is that it allow the default constructor
   * <tt>T_impl::T_impl()</tt> (i.e. dont make <tt>T_impl::T_impl()</tt>
   * private) and that it allow <tt>T_impl::new()</tt> and
   * <tt>T_impl::delete</tt> (i.e.  don't make them private functions, see
   * Meyers, More Effective C++, Item 27).
   
   * However, this subclass is also templated on two other policy types that
   * allow a modification on how objects are created and destroyed.  The first
   * templated policy type, <tt>T_PostMod</tt>, defines how an object is
   * modified after it is initially created.  The second templated policy type,
   * <tt>T_Allocator</tt>, defines exactly how an object is created (and
   * therefore also how it is destroyed).  These type two policy classes are
   * described in more detail below.
   *
   * The type <tt>T_PostMod</tt> is responsible for performing any post
   * modifications on a dynamically allocated object before returning it from
   * <tt>create()</tt>.  The requirements for the type <tt>T_PostMod</tt> are
   * that it has a default constructor, a copy constructor and a method
   * <tt>T_PostMod::initialize(T_itfc2*) const</tt> that will perform any
   * required post modifications (initializations).  The type <tt>T_itfc2</tt>
   * argument for this function must be a base class of <tt>T_impl</tt> of
   * course.  The default type for <tt>T_PostMod</tt> is
   * <tt>PostModNothing</tt><tt><T_impl></tt> which does nothing.
   *
   * The type <tt>T_Allocator</tt> allows for specialized memory allocation and
   * cleanup.  This type must allow the default constructor and copy constructor
   * and have a method <tt>Teuchos::RCP<T_impl> T_Allocator::allocate()
   * const</tt> which creates a smart reference-counted pointer to the allocated
   * object.  Also, in returning a <tt>RCP<></tt> object, the client can
   * set a deallocatioin policy object that can specialize the deallocation of
   * the object (see <tt>RCP</tt>).  In defining a specialized
   * <tt>T_Allocator</tt> class, the client can all initialize the object using
   * more than just the default constructor.  Therefore, if the client provides
   * a specialized <tt>T_Allocator</tt> class, there are no restrictions on the
   * class <tt>T_impl</tt> (i.e. does not have to have a default constructor or
   * allow <tt>new</tt> or <tt>delete</tt>).  The default class for
   * <tt>T_Allocator</tt> is <tt>AllocatorNew</tt><tt><T_impl></tt> who's
   * <tt>allocate()</tt> function just returns <tt>rcp(new T_impl())</tt>.
   * 
   * Since the <tt>T_Allocator</tt> class can specialize both the memory
   * management and can initialize the object using more that the default
   * constructor, the class <tt>T_PostMod</tt> may seem unecessary.  However, it
   * is more likely that the client will want to define an initialization for a
   * set of classes through an abstract interface and can not for a particular
   * concrete subclass.  Also the initialization for an object can be orthogonal
   * to how it is created and destroyed, thus the two classes <tt>T_PostMod</tt>
   * and <tt>T_Allocator</tt> are both needed for a more general implementation.
   */
  template<class T_itfc, class T_impl
  				 ,class T_PostMod = PostModNothing<T_impl>
  				 ,class T_Allocator = AllocatorNew<T_impl>
          >
  class AbstractFactoryStd : public AbstractFactory<T_itfc> {
  public:
  
  	typedef typename Teuchos::AbstractFactory<T_itfc>::obj_ptr_t   obj_ptr_t;  // RAB: 20030916: G++ 3.2 complains without this
  
    /** \brief . */
    AbstractFactoryStd( const T_PostMod& post_mod = T_PostMod(), const T_Allocator& alloc = T_Allocator() );
  
    /** @name Overriden from AbstractFactory */
    //@{
    /** \brief . */
    obj_ptr_t create() const;
    //@}
  
  private:
    T_PostMod    post_mod_;
    T_Allocator  alloc_;
  
  };
  
  
  /** \brief Nonmember constructor for an standar abstract factory object.
   *
   * \relates AbstractFactoryStd
   */
  template<class T_itfc, class T_impl>
  RCP<const AbstractFactory<T_itfc> >
  abstractFactoryStd()
  {
  	return rcp(
  		new AbstractFactoryStd<T_itfc,T_impl,PostModNothing<T_impl>,AllocatorNew<T_impl> >()
  		);
  }
  
  
  /** \brief Nonmember constructor for an standar abstract factory object.
   *
   * \relates AbstractFactoryStd
   */
  template<class T_itfc, class T_impl, class T_Allocator>
  RCP<const AbstractFactory<T_itfc> >
  abstractFactoryStd( const T_Allocator& alloc = T_Allocator() )
  {
  	return rcp(
  		new AbstractFactoryStd<T_itfc,T_impl,PostModNothing<T_impl>,T_Allocator>(
        PostModNothing<T_impl>(), alloc
        )
  		);
  }
  
  
  // ///////////////////////////////////////////////////////
  // Template member definitions
  
  template<class T_itfc, class T_impl, class T_PostMod, class T_Allocator>
  inline
  AbstractFactoryStd<T_itfc,T_impl,T_PostMod,T_Allocator>::AbstractFactoryStd(
  	const T_PostMod& post_mod, const T_Allocator& alloc
  	)
  	:post_mod_(post_mod)
  	,alloc_(alloc)
  {}
  
  template<class T_itfc, class T_impl, class T_PostMod, class T_Allocator>
  inline
  typename AbstractFactoryStd<T_itfc,T_impl,T_PostMod,T_Allocator>::obj_ptr_t
  AbstractFactoryStd<T_itfc,T_impl,T_PostMod,T_Allocator>::create() const
  {
  	typename T_Allocator::ptr_t
  		ptr = alloc_.allocate();
  	post_mod_.initialize(ptr.get());
  	return ptr;
  }
  
  } // end Teuchos
  
  #endif // TEUCHOS_ABSTRACT_FACTORY_STD_HPP
  