/*! * \file * \brief Base class for class factories and memory allocation functions * \author Johan Bergman and Adam Piatyszek * * ------------------------------------------------------------------------- * * IT++ - C++ library of mathematical, signal processing, speech processing, * and communications classes and functions * * Copyright (C) 1995-2007 (see AUTHORS file for a list of contributors) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * ------------------------------------------------------------------------- */ #ifndef FACTORY_H #define FACTORY_H #include #include namespace itpp { // Forward declarations template class Array; template class Mat; template class Vec; /*! \brief Base class for class factories A class factory (or virtual constructor) is a class that can create instances of another class. Factory is a base class for such factories. When declaring an Array, Vec or Mat, a factory can be passed as an (optional) constructor argument: \code // Declare a Vec with size=10 and factory=DEFAULT_FACTORY Vec a(10); // Declare a Vec with size=10 and factory=f Factory f; Vec b(10, f); \endcode By default, the factory (\c DEFAULT_FACTORY and \c f in the above examples) is not used at all! However, by overloading a help function called \e create_elements we can force Array/Vec/Mat to use the factory for element creation (instead of using the default constructor for the element type). \note It is the \e numeric elements that will be created by the factory, i.e. for an Array >, the factory will be used for creating the Mat elements rather than the Array elements. Here is an example that (partly) defines a user-defined numeric type My_Type, a corresponding factory My_Factory and a corresponding help function create_elements that will be used by Array, Vec and Mat for element creation. \code class My_Type { public: // Default constructor My_Type() : data(0) {} // Constructor My_Type(int d) : data(d) {} . . . protected: int data; }; class My_Factory : public Factory { public: // Constructor explicit My_Factory(int d) : init_data(d) {} // Destructor virtual ~My_Factory() {} // Create an n-length array of My_Type virtual void create(My_Type* &ptr, int n) const {ptr = new My_Type[n](init_data);} protected: int init_data; }; // Create an n-length array of My_Type using My_Factory f template<> void create_elements(My_Type* &ptr, int n, const Factory &f) { if (const My_Factory *my_factory_ptr = dynamic_cast(&f)) { // Yes, f seems to be a My_Factory. Now call the My_Factory::create method my_factory_ptr->create(ptr, n); } else { // No, f does not seem to be a My_Factory. As a fallback solution, // assume that f is DEFAULT_FACTORY and use the default constructor ptr = new My_Type[n]; } } \endcode Now, \code // Declare a My_Factory for init_data = 123 My_Factory my123_factory(123); // Declare a Vec with size 10 that uses My_Type() for element creation Vec v1(10); // Declare a Vec with size 10 that uses My_Type(123) for element creation Vec v1(10, my123_factory); \endcode For a more interesting example, see Fix_Factory. */ class Factory { public: //! Default constructor Factory() {} //! Destructor virtual ~Factory() {} }; //! Default (dummy) factory const Factory DEFAULT_FACTORY; //! Create an n-length array of T to be used as Array, Vec or Mat elements template void create_elements(T* &ptr, int n, const Factory &) { void *p = operator new(sizeof(T) * n); ptr = reinterpret_cast(p); for (int i = 0; i < n; i++) { new (ptr + i) T(); } } //! Specialization for unsigned char data arrays (used in GF2Mat) template<> void create_elements(unsigned char* &ptr, int n, const Factory &); //! Specialization for binary data arrays template<> void create_elements(bin* &ptr, int n, const Factory &); //! Specialization for short integer data arrays template<> void create_elements(short int* &ptr, int n, const Factory &); //! Specialization for integer data arrays template<> void create_elements(int* &ptr, int n, const Factory &); //! Specialization for 16-byte aligned double data arrays template<> void create_elements(double* &ptr, int n, const Factory &); //! Specialization for 16-byte aligned complex double data arrays template<> void create_elements >(std::complex* &ptr, int n, const Factory &); //! Destroy an array of Array, Vec or Mat elements template void destroy_elements(T* &ptr, int n) { if (ptr) { for (int i = 0; i < n; ++i) { ptr[i].~T(); } void *p = reinterpret_cast(ptr); operator delete(p); ptr = 0; } } //! Specialization for unsigned char data arrays (used in GF2Mat) template<> void destroy_elements(unsigned char* &ptr, int n); //! Specialization for binary data arrays template<> void destroy_elements(bin* &ptr, int n); //! Specialization for short integer data arrays template<> void destroy_elements(short int* &ptr, int n); //! Specialization for integer data arrays template<> void destroy_elements(int* &ptr, int n); //! Specialisation for 16-byte aligned double data arrays template<> void destroy_elements(double* &ptr, int n); //! Specialisation for 16-byte aligned complex double data arrays template<> void destroy_elements >(std::complex* &ptr, int n); //! Create an n-length array of Array to be used as Array elements template void create_elements(Array* &ptr, int n, const Factory &f) { void *p = operator new(sizeof(Array) * n); ptr = reinterpret_cast*>(p); for (int i = 0; i < n; ++i) { new (ptr + i) Array(f); } } //! Create an n-length array of Mat to be used as Array elements template void create_elements(Mat* &ptr, int n, const Factory &f) { void *p = operator new(sizeof(Mat) * n); ptr = reinterpret_cast*>(p); for (int i = 0; i < n; ++i) { new (ptr + i) Mat(f); } } //! Create an n-length array of Vec to be used as Array elements template void create_elements(Vec* &ptr, int n, const Factory &f) { void *p = operator new(sizeof(Vec) * n); ptr = reinterpret_cast*>(p); for (int i = 0; i < n; ++i) { new (ptr + i) Vec(f); } } } // namespace itpp #endif // #ifndef FACTORY_H