//==================================================================================================
// S t a n d a r d                                                                        Interface
// C l a s s
//                                                                                By Bruno Bachelet
//==================================================================================================
// Copyright (c) 1999-2016
// Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net
//
// This file is part of the B++ Library. This library is free software; you can redistribute it
// and/or modify it under the terms of the GNU Library General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This library 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 Library General Public License for more details (http://www.gnu.org).

/*DESCRIPTION*/
/* This module provides facilities to manage classes. */

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "standard/class.hpp"

// Guardian //--------------------------------------------------------------------------------------
#ifndef guStandardClass
#define guStandardClass

// Headers //---------------------------------------------------------------------------------------
#include <cstring> /*INCLUDE*/
#include <string> /*INCLUDE*/
#include <utility> /*INCLUDE*/
#include <bpp/standard/environment.hpp> /*INCLUDE*/
#include <bpp/standard/type.hpp> /*INCLUDE*/

#ifdef USE_SYMBOL_DEMANGLING
 #include <contribution/demangle.hpp>
#endif

namespace bpp {

// Importation/Exportation //-----------------------------------------------------------------------
#ifdef STANDARD_DLL
 #define dll_export DLL_EXPORT
#else
 #define dll_export DLL_IMPORT
#endif

// Namespaces //------------------------------------------------------------------------------------
#define public_area  standardClass
#define private_area standardClass_private

namespace public_area  { /*NAMESPACE*/ using namespace standardType; }
namespace private_area { using namespace public_area; }

extern_module_name;

// Initialization //--------------------------------------------------------------------------------

// Macrocommands //---------------------------------------------------------------------------------
/*MACROCOMMAND*/
/* Provides a <I>slot</I> for a given method. A slot is a nested class (without any code) with a
   name similar to the name of the original method (<CODE>_slot</CODE> is appended to the original
   name). Thus it allows to associate a static identifier with a method. This is useful when the
   method pointer needs to be given as a template parameter: instead of giving the method pointer
   (that is not a global reference), the associated static identifier (i.e. the method slot) is
   provided. */
#define add_method_slot(prMethod) public_property class prMethod##_slot {}

/*MACROCOMMAND*/ /* Provides the slot of a given method. */
#define method_slot(prClass,prMethod) prClass::prMethod##_slot

/*MACROCOMMAND*/ /* Provides the unique number (from a given reference) assigned to a method. */
#define method_no(prReference,prClass,prMethod)                                              \
 (clMethodInformation< prReference,prClass,method_slot(prClass,prMethod) >::index().value()) \

/*MACROCOMMAND*/
/* Provides the unique number (from a given reference) assigned to a class. */
#define class_no(prReference,prClass) (clClassInformation< prReference,prClass >::index().value())

/*MACROCOMMAND*/ /* Declares a class indexer inside a reference class. */
#define class_indexer(prReference)                                                     \
 friend class clClassIndexer<prReference>;                                             \
                                                                                       \
 private_property static tcString   clClassIndexer_atClassNameS[CLASS_NUMBERING_SIZE]; \
 private_property static tyCardinal clClassIndexer_atNbClass;                          \
 private_property static tyCardinal clClassIndexer_atNbMethodS[CLASS_NUMBERING_SIZE];  \
                                                                                       \
 read_write_static_attribute(clClassIndexer<prReference>,atClassIndexer,classIndexer)  \

/*MACROCOMMAND*/ /* Creates the class indexer of a reference class. */
#define static_class_indexer(prReference)                                                    \
 tcString                    prReference::clClassIndexer_atClassNameS[CLASS_NUMBERING_SIZE]; \
 tyCardinal                  prReference::clClassIndexer_atNbClass = 0;                      \
 tyCardinal                  prReference::clClassIndexer_atNbMethodS[CLASS_NUMBERING_SIZE];  \
 clClassIndexer<prReference> prReference::atClassIndexer                                     \

/*MACROCOMMAND*/
/* Wraps a type into a class. See the <code>TypeWrapper</code> class for details. */
#define type_wrapper(prType) bpp::standardClass::clTypeWrapper< prType >::clType

// Types & Classes //-------------------------------------------------------------------------------
namespace public_area {
 //------------------------------------------------------------------------------------------Classes
 class clBaseObject;

 template <class prReference,class prClass>                class clClassIndex;
 template <class prReference>                              class clClassIndexer;
 template <class prReference,class prClass>                class clClassInformation;
 template <class prReference,class prClass>                class clMethodIndex;
 template <class prReference,class prClass,class prMethod> class clMethodInformation;
 template <class prType>                                   class clTypeWrapper;
 template <int prVersion>                                  class clVersion;
 //-----------------------------------------------------------------------------------Constant Types
 typedef const clBaseObject ctBaseObject;
}

namespace private_area {}

// Functions Interface //---------------------------------------------------------------------------
namespace public_area {
 std::string demangleSymbol(tcString);
 std::string demangleType(tcString);

 #ifdef NEED_COMPLEMENTARY_COMPARATORS
  template <class prObject1,class prObject2>
  tyBoolean operator != (const prObject1 &,const prObject2 &);

  template <class prObject1,class prObject2>
  tyBoolean operator > (const prObject1 &,const prObject2 &);

  template <class prObject1,class prObject2>
  tyBoolean operator <= (const prObject1 &,const prObject2 &);

  template <class prObject1,class prObject2>
  tyBoolean operator >= (const prObject1 &,const prObject2 &);
 #endif

 template <class prKey,class prElement>
 inline std::pair<prKey,prElement> make_pair(const prKey &,const prElement &);
}

namespace private_area { testing_mode ( function void test(void); ) }

// Errors //----------------------------------------------------------------------------------------
namespace public_area {}

// Constants & Variables //-------------------------------------------------------------------------
extern_dynamic_constant(private,clMutex,goDemangleMutex,?);

// B a s e O b j e c t  Interface //----------------------------------------------------------------
namespace public_area {
 /*CLASS clBaseObject */ /* Defines the base class of all the other classes. */
 class clBaseObject {
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clBaseObject(ctBaseObject &);
  private_property clBaseObject & operator = (ctBaseObject &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor        clBaseObject(void);
  public_property virtual destructor clBaseObject(void);
 };
}

// C l a s s I n d e x e r  Interface //------------------------------------------------------------
namespace public_area {
 /*CLASS clClassIndexer */
 /* Represents the indexer of a set of classes. It is used to assign unique numbers to classes and
    their methods. The numbering is a continuous sequence of indexes, starting from 0, so it is
    possible to store and access quickly data for the classes and their methods (through vectors
    for instance). An indexer must be located inside a class, called the <I>reference</I> for all
    the information that the class indexer and its associated classes
    (<CODE>clClassInformation</CODE> and <CODE>clMethodInformation</CODE>) can provide. */
 template <class prReference> class clClassIndexer : public clBaseObject {
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clClassIndexer(const clClassIndexer &);
  private_property clClassIndexer & operator = (const clClassIndexer &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clClassIndexer(void);
  public_property destructor  clClassIndexer(void);

  public_property tcString   className(tyCardinal) const;
  public_property tyCardinal nbClass(void) const;
  public_property tyCardinal nbMethod(tyCardinal) const;

  public_property tyCardinal getClassNo(ctTypeInformation &);
  public_property tyCardinal getMethodNo(ctTypeInformation &);
 };
}

// C l a s s I n d e x  Interface //----------------------------------------------------------------
namespace public_area {
 /*CLASS clClassIndex */ /* Represents the index of a class according to a given reference. */
 template <class prReference,class prClass> class clClassIndex : public clBaseObject {
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clClassIndex(const clClassIndex &);
  private_property clClassIndex & operator = (const clClassIndex &);
  //------------------------------------------------------------------------------------------Public
  /*ATTRIBUTE clClassIndex */ /* Value of the index. */
  read_only_attribute(tyCardinal,atValue,value);

  public_property constructor clClassIndex(void);
  public_property destructor  clClassIndex(void);
 };
}

// M e t h o d I n d e x  Interface //--------------------------------------------------------------
namespace public_area {
 /*CLASS clMethodIndex */ /* Represents the index of a class according to a given reference. */
 template <class prReference,class prClass> class clMethodIndex : public clBaseObject {
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clMethodIndex(const clMethodIndex &);
  private_property clMethodIndex & operator = (const clMethodIndex &);
  //------------------------------------------------------------------------------------------Public
  /*ATTRIBUTE clMethodIndex */ /* Value of the index. */
  read_only_attribute(tyCardinal,atValue,value);

  public_property constructor clMethodIndex(void);
  public_property destructor  clMethodIndex(void);
 };
}

// C l a s s I n f o r m a t i o n  Interface //----------------------------------------------------
namespace public_area {
 /*CLASS clClassInformation */
 /* Represents information (from a given reference) about a class. This class can not be
    instantiated. */
 template <class prReference,class prClass> class clClassInformation : public clBaseObject {
  //-------------------------------------------------------------------------------------------Types
  /*TYPE clClassInformation */ /* Type of the index of the class. */
  public_property typedef clClassIndex<prReference,prClass> cpIndex;
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clClassInformation(void);
  private_property constructor clClassInformation(const clClassInformation &);
  private_property clClassInformation & operator = (const clClassInformation &);
  //------------------------------------------------------------------------------------------Public
  /*ATTRIBUTE clClassInformation */ /* Index of the class. */
  read_only_static_attribute(cpIndex,atIndex,index);
 };
}

// M e t h o d I n f o r m a t i o n  Interface //--------------------------------------------------
namespace public_area {
 /*CLASS clMethodInformation */
 /* Represents information (from a given reference) about a method. The last parameter
    <CODE>prMethod</CODE> is not a pointer on the method, but a <I>slot</I> (it is a static
    identifier the user must associate with the method, see the <CODE>add_method_slot</CODE>
    macrocommand for details). This class can not be instantiated. */
 template <class prReference,class prClass,class prMethod>
 class clMethodInformation : public clBaseObject {
  //-------------------------------------------------------------------------------------------Types
  /*TYPE clMethodInformation */ /* Type of the index of the method. */
  public_property typedef clMethodIndex<prReference,prClass> cpIndex;
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clMethodInformation(void);
  private_property constructor clMethodInformation(const clMethodInformation &);
  private_property clMethodInformation & operator = (const clMethodInformation &);
  //------------------------------------------------------------------------------------------Public
  /*ATTRIBUTE clMethodInformation */ /* Index of the method. */
  read_only_static_attribute(cpIndex,atIndex,index);
 };
}

// T y p e W r a p p e r  Interface //--------------------------------------------------------------
namespace public_area {
 /*CLASS clTypeWrapper */
 /* Wraps a type into a class. It is useful to manipulate a complex type expression (like a
    function pointer) as a single expression. Abstract class. */
 template <class prType> class clTypeWrapper {
  //-------------------------------------------------------------------------------------------Types
  /*TYPE clTypeWrapper */ /* Type of the parameter of the template. */
  public_property typedef prType clType;
  //------------------------------------------------------------------------------------------Public
  public_property virtual ~clTypeWrapper(void) = 0;
 };
}

// V e r s i o n  Interface //----------------------------------------------------------------------
namespace public_area {
 /*CLASS clVersion */
 /* Represents a version of an algorithm. Necessary to manipulate an algorithm that has several
    implementations. */
 template <int prVersion> class clVersion : public clBaseObject {
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clVersion(const clVersion &);
  private_property clVersion & operator = (const clVersion &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor        clVersion(void);
  public_property virtual destructor clVersion(void);
 };
}

// Functions Inline //------------------------------------------------------------------------------
namespace public_area {
 #ifdef NEED_COMPLEMENTARY_COMPARATORS
  //-------------------------------------------------------------------------------------Operator !=
  template <class prObject1,class prObject2>
  inline tyBoolean operator != (const prObject1 & agObject1,const prObject2 & agObject2)
  { return (not (agObject1==agObject2)); }
  //--------------------------------------------------------------------------------------Operator >
  template <class prObject1,class prObject2>
  inline tyBoolean operator > (const prObject1 & agObject1,const prObject2 & agObject2)
  { return (agObject2<agObject1); }
  //-------------------------------------------------------------------------------------Operator <=
  template <class prObject1,class prObject2>
  inline tyBoolean operator <= (const prObject1 & agObject1,const prObject2 & agObject2)
  { return (not (agObject2<agObject1)); }
  //-------------------------------------------------------------------------------------Operator >=
  template <class prObject1,class prObject2>
  inline tyBoolean operator >= (const prObject1 & agObject1,const prObject2 & agObject2)
  { return (not (agObject1<agObject2)); }
 #endif

 //----------------------------------------------------------------------------------------Make_pair
 /*FUNCTION*/
 /* For efficiency reasons, the <CODE>make_pair</CODE> of the STL is rewritten. This version is
    for general purpose (do not use it with STL maps, or for any structure that uses pairs
    where the first element's type is constant). */
 template <class prKey,class prElement>
 inline std::pair<prKey,prElement> make_pair(const prKey & agKey,const prElement & agElement)
 { return (std::pair<prKey,prElement>(agKey,agElement)); }
}

namespace private_area {}

// B a s e O b j e c t  Inline //-------------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clBaseObject */ /* Default constructor. */
 inline clBaseObject::clBaseObject(void) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clBaseObject */ /* Destructor. */
 inline clBaseObject::~clBaseObject(void) {}
}

// C l a s s I n d e x e r  Inline //---------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clClassIndexer */ /* Builds a class indexer. */
 template <class prReference>
 inline clClassIndexer<prReference>::clClassIndexer(void) : clBaseObject() {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clClassIndexer */ /* Destructs the class indexer. */
 template <class prReference> inline clClassIndexer<prReference>::~clClassIndexer(void) {}
 //----------------------------------------------------------------------------------------ClassName
 /*METHOD clClassIndexer */ /* Returns the name of a class indexed by the object. */
 template <class prReference>
 inline tcString clClassIndexer<prReference>::className(tyCardinal agClassNo) const
 { return (prReference::clClassIndexer_atClassNameS[agClassNo]); }
 //------------------------------------------------------------------------------------------NbClass
 /*METHOD clClassIndexer */ /* Returns the number of classes indexed by the object. */
 template <class prReference> inline tyCardinal clClassIndexer<prReference>::nbClass(void) const
 { return (prReference::clClassIndexer_atNbClass); }
 //-----------------------------------------------------------------------------------------NbMethod
 /*METHOD clClassIndexer */
 /* Returns the number of methods of a given class indexed by the object. */
 template <class prReference>
 inline tyCardinal clClassIndexer<prReference>::nbMethod(tyCardinal agClassNo) const
 { return (prReference::clClassIndexer_atNbMethodS[agClassNo]); }
 //--------------------------------------------------------------------------------------GetMethodNo
 /*METHOD clClassIndexer */
 /* Gets a new method number in the continuous sequence of indexes of a given class. <B>Do not call
    directly this method.</B> Use instead the <CODE>clMethodInformation</CODE> class to get the
    number of a method. */
 template <class prReference> inline
 tyCardinal clClassIndexer<prReference>::getMethodNo(ctTypeInformation & agClassInformation)
 { return ((prReference::clClassIndexer_atNbMethodS[getClassNo(agClassInformation)])++); }
}

// V e r s i o n  Inline //-------------------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clVersion */ /* Default constructor. */
 template <int prVersion> inline clVersion<prVersion>::clVersion(void) : clBaseObject() {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clVersion */ /* Destructor. */
 template <int prVersion> inline clVersion<prVersion>::~clVersion(void) {}
}

// C l a s s I n d e x e r  Implementation //-------------------------------------------------------
namespace public_area {
 //---------------------------------------------------------------------------------------GetClassNo
 /*METHOD clClassIndexer */
 /* Gets a new class number in the continuous sequence of indexes. <B>Do not call directly
    this method.</B> Use instead the <CODE>clClassInformation</CODE> class to get the number
    of a class. */
 template <class prReference>
 tyCardinal clClassIndexer<prReference>::getClassNo(ctTypeInformation & agClassInformation) {
  typedef tcString tyClassNameS[CLASS_NUMBERING_SIZE];

  tyClassNameS & lcClassNameS = prReference::clClassIndexer_atClassNameS;
  tyCardinal     lcCounter    = 0;
  tcString       lcName       = agClassInformation.name();
  tyCardinal &   lcNbClass    = prReference::clClassIndexer_atNbClass;

  while (lcCounter<lcNbClass and strcmp(lcClassNameS[lcCounter],lcName)!=0) ++lcCounter;

  if (lcCounter==lcNbClass) {
   ++lcNbClass;
   prReference::clClassIndexer_atNbMethodS[lcCounter]=0;
   lcClassNameS[lcCounter]=lcName;
  }

  return (lcCounter);
 }
}

// C l a s s I n d e x  Implementation //-----------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clClassIndex */ /* Builds a class index (i.e. gets a number to identify a class). */
 template <class prReference,class prClass> clClassIndex<prReference,prClass>::clClassIndex(void)
 : clBaseObject(),atValue(prReference::classIndexer().getClassNo(typeid(prClass))) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clClassIndex */ /* Destructs the index. */
 template <class prReference,class prClass>
 clClassIndex<prReference,prClass>::~clClassIndex(void) {}
}

// M e t h o d I n d e x  Implementation //---------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clMethodIndex */ /* Builds a method index (i.e. gets a number to identify a method). */
 template <class prReference,class prClass> clMethodIndex<prReference,prClass>::clMethodIndex(void)
 : clBaseObject(),atValue(prReference::classIndexer().getMethodNo(typeid(prClass))) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clMethodIndex */ /* Destructs the index. */
 template <class prReference,class prClass>
 clMethodIndex<prReference,prClass>::~clMethodIndex(void) {}
}

// C l a s s I n f o r m a t i o n  Implementation //-----------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------Static Attributes
 template <class prReference,class prClass>
 clClassIndex<prReference,prClass> clClassInformation<prReference,prClass>::atIndex;
}

// M e t h o d I n f o r m a t i o n  Implementation //---------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------Static Attributes
 template <class prReference,class prClass,class prMethod>
 clMethodIndex<prReference,prClass> clMethodInformation<prReference,prClass,prMethod>::atIndex;
}

// End //-------------------------------------------------------------------------------------------
}
#undef dll_export
#undef public_area
#undef private_area
#endif
 
//==================================================================================================
// S t a n d a r d                                                                   Implementation
// C l a s s
//                                                                                By Bruno Bachelet
//==================================================================================================
// Copyright (c) 1999-2016
// Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net
//
// This file is part of the B++ Library. This library is free software; you can redistribute it
// and/or modify it under the terms of the GNU Library General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This library 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 Library General Public License for more details (http://www.gnu.org).

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "standard/class.cpp"

// DLL Belonging //---------------------------------------------------------------------------------
#define STANDARD_DLL

// Headers //---------------------------------------------------------------------------------------
#include <bpp/standard/class.hpp> /*INTERFACE*/

namespace bpp {

// Namespaces //------------------------------------------------------------------------------------
#define public_area  standardClass
#define private_area standardClass_private
#define dll_export   DLL_EXPORT

namespace public_area  {}
namespace private_area {}

static_module_name("Standard/Class");

// Initialization //--------------------------------------------------------------------------------

// Errors //----------------------------------------------------------------------------------------
namespace public_area  {}

// Constants & Variables //-------------------------------------------------------------------------
dynamic_constant(clMutex,goDemangleMutex);

// Static Members //--------------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// Functions Implementation //----------------------------------------------------------------------
namespace public_area {
 //-----------------------------------------------------------------------------------DemangleSymbol
 /*FUNCTION*/ /* Demangles the string representing the name of a symbol. */
 function std::string demangleSymbol(tcString agString) {
  std::string lcString;

  #ifdef USE_SYMBOL_DEMANGLING
   clMutex * lcMutex = private_area::goDemangleMutex;

   if (lcMutex!=nil) lcMutex->lock();
   libcw::debug::demangle_symbol(agString,lcString);
   if (lcMutex!=nil) lcMutex->release();
  #else
   lcString=agString;
  #endif

  return (lcString);
 }
 //-------------------------------------------------------------------------------------DemangleType
 /*FUNCTION*/ /* Demangles the string representing the name of a type. */
 function std::string demangleType(tcString agString) {
  std::string lcString;

  #ifdef USE_SYMBOL_DEMANGLING
   clMutex * lcMutex = private_area::goDemangleMutex;

   if (lcMutex!=nil) lcMutex->lock();
   libcw::debug::demangle_type(agString,lcString);
   if (lcMutex!=nil) lcMutex->release();
  #else
   lcString=agString;
  #endif

  return (lcString);
 }
}

namespace private_area {}

// X X X  Implementation //-------------------------------------------------------------------------
namespace {}

// End //-------------------------------------------------------------------------------------------
}