/*************************************************************************
 *
 *  $RCSfile: compat.hxx,v $
 *
 *  $Revision: 1.1.1.1 $
 *
 *  last change: $Author: hr $ $Date: 2000/09/18 16:58:50 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifdef C_START
#undef C_START1
#undef C_START
#undef C_END
#undef C_INIT
#undef C_DONE
#undef C
#undef C1
#undef C2
#undef V_INIT
#undef V_PTR
#undef V_DECL_PTR
#undef V_IMPL_PTR
#undef V_DECL0
#undef V_BASE_DECL0
#undef V_IMPL0
#undef V_IMPL0V
#undef V_BASE_IMPL0
#undef V_BASE_IMPL0V
#undef V_DECL1
#undef V_BASE_DECL1
#undef V_IMPL1
#undef V_IMPL1V
#undef V_BASE_IMPL1
#undef V_BASE_IMPL1V
#undef V_DECL2
#undef V_BASE_DECL2
#undef V_IMPL2
#undef V_IMPL2V
#undef V_BASE_IMPL2
#undef V_BASE_IMPL2V
#endif

#ifndef _COMPAT_HXX_SPE
#define _COMPAT_HXX_SPE

#ifndef _SOLAR_H
#include <tools/solar.h>
#endif

#ifndef _SOLAR_HRC
#include <svtools/solar.hrc>
#endif

#define SFX_POINTER_SIZE  4096
#define SFX_MOD_SIZE      4096

/*  [Beschreibung]

	Die Klassen SfxPointerEntry und SfxPointerServer dienen im
	Zusammenspiel mit Macros der kompatiblen
	Erweiterung von Klassen.

	Der SfxPointerServer gibt durch CreatePointer einen Pointer auf
	einen frei benutzbaren Pointer A zurueck. Der der Methode uebergebene
	const void * dient als Schluessel zu diesem Pointer. Weitere Aufrufe
	von GetPointer geben den Pointer A zurueck. Nach Gebrauch wird der
	Pointer A duch ReleasePointer wieder freigegeben.

	[Beispiel]

	Die C_* Makros dienen der kompatiblen Erzeugung von Membern in
	Klassen. Vor der Klassendeclaration ist das Define C_VERSION auf
	die SOLAR_VERSION zu setzen, bis zu der einschliesslich die
	Erweiterung kompatibel bleiben muss. Die neuen Menber werden in
	C_START1(aMember) und C_END geklammert. aMember ist ein alter Member.
	Gibt es keinen, so kann C_START verwendet werden. Im Konstruktor
	ist C_INIT; aufzurufen, im Destruktor C_DONE; Auf neue Member wird
	ueber C(aMember) zugegriffen.

	usw. usf.

	#define C_VERSION 2560
	#include <svtools/compat.hxx>

	class SollCompatibleBleiben

	C_START1(a)
	int nKompatibelHinzufuegen;
	C_END

	int a;
	int b;

	SollCompatibleBleiben(int aa, int bb, int nnKomp) a(aa), b(bb)
	{
	C_INIT;
	C(nKompatibelHinzufuegen)=nnKomp;
	}

	~SollCompatibleBleiben()
	{
	C_DONE;
	}
	};

	[Vorsicht]

	Vorsicht ist geboten:

	Verfuegt die Klasse ueber keinen Destruktor, aber einen Konstruktor
	so sind 2 Faelle zu unterscheinden:

	1. Klasse hat Basisklasse mit virtuellem Destruktor.

	In diesem Fall darf die Klasse nur von Methoden instanziiert werden,
	die nach der Aenderung neu kompiliert werden. Sonst zeigt
	die virtuelle Tabelle auf den DefaultDestruktor, den es nun nicht
	mehr gibt.

	2. Nicht 1.

	In diesem Fall werden die angelegten Pointer nach Zerstoerung des
	Objektes nicht mehr freigegeben. Dieser Fall ist unproblematisch,
	solange nicht zu viele Objekte angelegt werden und das automatisch
	resultierende Speicherleck nicht stoert.

	Verfuegt die Klasse ueber keinen Konstruktor und werden Instanzen
	von Modulen angelegt, die nach der Aenderung nicht neukompiliert
	werden, so  ist vor include
	compat.hxx das define C_SAFEUSE zu setzen. Dadurch wird bei jedem
	Zugriff auf ein Member getestet, ob der Pointer schon angelegt
	wurde und er anderenfalls angelegt.

	VERFUEGT DIE KLASSE UEBER KEINEN KONSTRUKTOR UND KEINEN DESTRUKTOR,
	SO SIND NACH DER AENDERUNG ALLE MODULE, DIE INSTANZEN DER KLASSE
	ANLEGEN ZU REKOMPILIEREN. (ODER ABER, MAN NIMMT IN KAUF, DASS
	MAN MANCHMAL DIE COMPATIBLE_IMPL STRUKTUR DES VORGAENGERS BEKOMMT)

	Die V_ Makros dienen dem kompatiblen Hinzufuegen virtueller
	Funktionen. Zunaechst ist dazu ein Member VirtualPtr an der BasisKlasse
	zur Verfuegung zu stellen (ueber compat oder an einer Impl Struktur).
	Folgende Makros fuegen dann die Methode hinzu:

	V_PTR(aMethod, aVirtualPtr);
	V_DECL_PTR(aMethod);
	V_IMPL_PTR(aClass, aMethod, aVirtualPtr);

	dienen der Zurverfuegungstellung des VirtualPtr. Steckt der Ptr an
	einer inline erreichbaren Stelle, so kann V_PTR verwendet werden (etwa
	bei compat), sonst nimmt man die anderen beiden Makros.

	V_DECL1, V_BASE_DECL1, V_IMPL1, V_IMPL1V, V_BASE_IMPL1, V_BASE_IMPL1V
	V_DECL2 usw.

	Deklarieren bzw. implementieren die virtuelle Methode. Die auf V endenden
	DECL Makros implementieren void Methoden, die anderen beliebige
	nicht-voids.

	V_INIT(aMethod); ist in der Basisklasse und in jeder ueberladenden
	abgeleiteten im Konstruktor zu rufen.

	Beispiel:

	struct A
	{
		int a;
		A(){a=0;}
		~A(){}
	}

	struct B : public A
	{
		B(){}
	}

	hier soll nun die virtuelle Methode void test(int) eingebaut werden.
	Der VirtualPtr wird ueber compat eingebaut.

	#define C_VERSION 3030
	#include <svtools/compat.hxx>

	struct A
	{
		C_START1(a)
		VirtualPtr aPtr;
		C_END

		int a;
		A(){a=0; C_INIT; V_INIT(test);}
	   ~A(){C_DONE;}

		V_PTR(test, C(aPtr));
		V_BASE_DECL1(void, test, int);
	}

	V_BASE_IMPL1V(A, test, int, aInt)
	{
		printf("A::test\n");
	}

	struct B : public A
	{
		B(){V_INIT;}
		V_DECL1(void, test,  int);
	}

	V_IMPL1V(B, test, int, aInt)
	{
		printf("B::test\n");
	}

*/

struct VirtualPtr
{
	void (*pMethod)();
	void *pThis;
};

struct SfxPointerEntry
{
	const void *pObject;
	void *pPointer;
	SfxPointerEntry(){pObject=0;}
};

class SfxPointerServer
{

  public:

	SfxPointerServer();
	~SfxPointerServer();

	BOOL HasPointer( const void *);
	void * GetPointer(const void *);
	void ReleasePointer(const void *);
	void **CreatePointer(const void *);

	static	SfxPointerServer* GetServer();
	static	void ReleaseServer();

  private:

	SfxPointerEntry aPointers[SFX_POINTER_SIZE];

	const SfxPointerEntry *pLast;
	const void *pCache;
	void *pCachePtr;

	long MakeHash(const void * pObj);
	USHORT nObjectCount;
};

inline long SfxPointerServer::MakeHash(const void *pObj)
{
	return ((((unsigned long)pObj) >> 16) + ((unsigned long) pObj) )
		% SFX_MOD_SIZE;
}

#endif

#if SUPD >= 311
#if C_VERSION > 1000
#error S_VERSION oder SOLAR_VERSION implizit durch compat verwendet
#endif
#endif

#if (((SOLAR_VERSION > C_VERSION && C_VERSION < 4000 && C_VERSION > 1000) ||	\
     (S_VERSION >= C_VERSION && C_VERSION > 4000) ||							\
     (SUPD >= C_VERSION && C_VERSION < 1000 )) || defined(ICC))

#define V_INIT(aClass, aMethod)

#define V_PTR(aMethod, aPtr)

#define V_DECL_PTR(aMethod) void Dummy##aMethod()

#define V_IMPL_PTR(aClass, aMethod, aPtr)

#define V_DECL0(aRetType, aMethod) \
	 virtual aRetType aMethod()

#define V_BASE_DECL0(aRetType, aMethod) \
	 virtual aRetType aMethod()

#define V_IMPL0V(aClass, aMethod) \
     void __EXPORT aClass::aMethod()

#define V_IMPL0(aRetType, aClass, aMethod) \
     aRetType __EXPORT aClass::aMethod()

#define V_BASE_IMPL0V(aClass, aMethod) \
     void __EXPORT aClass::aMethod()

#define V_BASE_IMPL0(aRetType, aClass, aMethod) \
     aRetType __EXPORT aClass::aMethod()

#define V_DECL1(aRetType, aMethod, aArgType1) \
	 virtual aRetType aMethod(aArgType1)

#define V_BASE_DECL1(aRetType, aMethod, aArgType1) \
	 virtual aRetType aMethod(aArgType1)

#define V_IMPL1V(aClass, aMethod, aArgType1, aArgName1) \
     void __EXPORT aClass::aMethod(aArgType1 aArgName1)

#define V_IMPL1(aRetType, aClass, aMethod, aArgType1, aArgName1) \
     aRetType __EXPORT aClass::aMethod(aArgType1 aArgName1)

#define V_BASE_IMPL1V(aClass, aMethod, aArgType1, aArgName1) \
     void __EXPORT aClass::aMethod(aArgType1 aArgName1)

#define V_BASE_IMPL1(aRetType, aClass, aMethod, aArgType1, aArgName1) \
     aRetType __EXPORT aClass::aMethod(aArgType1 aArgName1)

#define V_DECL2(aRetType, aMethod, aArgType1, aArgType2) \
	 virtual aRetType aMethod(aArgType1, aArgType2)

#define V_BASE_DECL2(aRetType, aMethod, aArgType1, aArgType2) \
	 virtual aRetType aMethod(aArgType1, aArgType2)

#define V_IMPL2V(aClass, aMethod, aArgType1, aArgName1, aArgType2, aArgName2) \
     void __EXPORT aClass::aMethod(aArgType1 aArgName1, aArgType2 aArgName2)

#define V_IMPL2(aRetType, aClass, aMethod, aArgType1, aArgName1, aArgType2, aArgName2) \
     aRetType __EXPORT aClass::aMethod(aArgType1 aArgName1, aArgType2 aArgName2)

#define V_BASE_IMPL2V(aClass, aMethod, aArgType1, aArgName1, aArgType2, aArgName2) \
     void __EXPORT aClass::aMethod(aArgType1 aArgName1, aArgType2 aArgName2)

#define V_BASE_IMPL2(aRetType, aClass, aMethod, aArgType1, aArgName1, aArgType2, aArgName2) \
     aRetType __EXPORT aClass::aMethod(aArgType1 aArgName1, aArgType2 aArgName2)

#define C_START

#define C_START1(x)

#define C_END

#define C_INIT

#define C_DONE

#define C(Member) (Member)

#define C1(Class, Member) (Class::Member)

#define C2(Object, Class, Member) ((Object)->Member)

#else

#define V_INIT(aClass, aMethod) \
     VirtualGetThisPtr##aMethod()->pMethod= \
	     (void (*)())&aClass::VirtualStub##aMethod; \
	 VirtualGetThisPtr##aMethod()->pThis=this

#define V_PTR(aMethod, aPtr) \
	 VirtualPtr *VirtualGetThisPtr##aMethod() \
     { return &aPtr; }

#define V_DECL_PTR(aMethod) \
	 VirtualPtr *VirtualGetThisPtr##aMethod()

#define V_IMPL_PTR(aClass, aMethod, aPtr) \
     VirtualPtr* aClass::VirtualGetThisPtr##aMethod() \
     { return &aPtr; }

#define V_DECL0(aRetType, aMethod) \
     static aRetType VirtualStub##aMethod(void *pThis); \
	 aRetType VirtualMethod##aMethod()

#define V_BASE_DECL0(aRetType, aMethod) \
	 aRetType aMethod(); \
     V_DECL1(aRetType, aMethod)

#define V_IMPL0V(aClass, aMethod) \
     void __EXPORT aClass::VirtualStub##aMethod( \
         void *pThis) \
     { ((aClass*)pThis) \
		   ->VirtualMethod##aMethod(); } \
     void aClass::VirtualMethod##aMethod()

#define V_IMPL0(aRetType, aClass, aMethod) \
     aRetType __EXPORT aClass::VirtualStub##aMethod( \
         void *pThis) \
     { return ((aClass*)pThis) \
		   ->VirtualMethod##aMethod(); } \
     aRetType aClass::VirtualMethod##aMethod()

#define V_BASE_IMPL0V(aClass, aMethod) \
     void aClass::aMethod() \
     { (* ( void (*)(void*) ) \
		VirtualGetThisPtr##aMethod()->pMethod ) \
		   ( VirtualGetThisPtr##aMethod()->pThis ); } \
	 V_IMPL0V(aClass, aMethod)

#define V_BASE_IMPL0(aRetType, aClass, aMethod) \
     aRetType aClass::aMethod() \
     { return (* ( aRetType (*)(void*) ) \
		VirtualGetThisPtr##aMethod()->pMethod ) \
		   ( VirtualGetThisPtr##aMethod()->pThis ); } \
	 V_IMPL0(aRetType, aClass, aMethod)

#define V_DECL1(aRetType, aMethod, aArgType1) \
     static aRetType VirtualStub##aMethod(void *pThis, aArgType1); \
	 aRetType VirtualMethod##aMethod(aArgType1)

#define V_BASE_DECL1(aRetType, aMethod, aArgType1) \
	 aRetType aMethod(aArgType1); \
     V_DECL1(aRetType, aMethod, aArgType1)

#define V_IMPL1V(aClass, aMethod, aArgType1, aArgName1) \
     void __EXPORT aClass::VirtualStub##aMethod( \
         void *pThis, aArgType1 aArgName1) \
     { ((aClass*)pThis) \
		   ->VirtualMethod##aMethod(aArgName1); } \
     void aClass::VirtualMethod##aMethod(aArgType1 aArgName1)

#define V_IMPL1(aRetType, aClass, aMethod, aArgType1, aArgName1) \
     aRetType __EXPORT aClass::VirtualStub##aMethod( \
         void *pThis, aArgType1 aArgName1) \
     { return ((aClass*)pThis) \
		   ->VirtualMethod##aMethod(aArgName1); } \
     aRetType aClass::VirtualMethod##aMethod(aArgType1 aArgName1)

#define V_BASE_IMPL1V(aClass, aMethod, aArgType1, aArgName1) \
     void aClass::aMethod(aArgType1 aArgName1) \
     { (* ( void (*)(void*, aArgType1) ) \
		VirtualGetThisPtr##aMethod()->pMethod ) \
		   ( VirtualGetThisPtr##aMethod()->pThis, aArgName1 ); } \
	 V_IMPL1V(aClass, aMethod, aArgType1, aArgName1)

#define V_BASE_IMPL1(aRetType, aClass, aMethod, aArgType1, aArgName1) \
     aRetType aClass::aMethod(aArgType1 aArgName1) \
     { return (* ( aRetType(*)(void*, aArgType1) ) \
		VirtualGetThisPtr##aMethod()->pMethod ) \
		   ( VirtualGetThisPtr##aMethod()->pThis, aArgName1 ); } \
	 V_IMPL1(aRetType, aClass, aMethod, aArgType1, aArgName1)

#define V_DECL2(aRetType, aMethod, aArgType1, aArgType2) \
     static aRetType VirtualStub##aMethod(void *pThis, aArgType1, aArgType2); \
	 aRetType VirtualMethod##aMethod(aArgType1, aArgType2)

#define V_BASE_DECL2(aRetType, aMethod, aArgType1, aArgType2) \
	 aRetType aMethod(aArgType1, aArgType2); \
     V_DECL2(aRetType, aMethod, aArgType1, aArgType2)

#define V_IMPL2V(aClass, aMethod, aArgType1, aArgName1, aArgType2, aArgName2) \
     void __EXPORT aClass::VirtualStub##aMethod( \
         void *pThis, aArgType1 aArgName1, aArgType2 aArgName2) \
     { ((aClass*)pThis) \
		   ->VirtualMethod##aMethod(aArgName1, aArgName2); } \
     void aClass::VirtualMethod##aMethod(aArgType1 aArgName1, aArgType2 aArgName2)

#define V_IMPL2(aRetType, aClass, aMethod, aArgType1, aArgName1, aArgType2, aArgName2) \
     aRetType __EXPORT aClass::VirtualStub##aMethod( \
         void *pThis, aArgType1 aArgName1, aArgType2 aArgName2) \
     { return ((aClass*)pThis) \
		   ->VirtualMethod##aMethod(aArgName1, aArgName2); } \
     aRetType aClass::VirtualMethod##aMethod(aArgType1 aArgName1, aArgType2 aArgName2)

#define V_BASE_IMPL2V(aClass, aMethod, aArgType1, aArgName1, aArgType2, aArgName2) \
     void aClass::aMethod(aArgType1 aArgName1, aArgType2 aArgName2) \
     { (* ( void (*)(void*, aArgType1, aArgType2) ) \
		VirtualGetThisPtr##aMethod()->pMethod ) \
		   ( VirtualGetThisPtr##aMethod()->pThis, aArgName1, aArgName2 ); } \
	 V_IMPL1V(aClass, aMethod, aArgType1, aArgName1, aArgType2, aArgName2)

#define V_BASE_IMPL2(aRetType, aClass, aMethod, aArgType1, aArgName1, aArgType2, aArgName2) \
     aRetType aClass::aMethod(aArgType1 aArgName1, aArgType2, aArgName2) \
     { return (* ( aRetType (*)(void*, aArgType1, aArgType2) ) \
		VirtualGetThisPtr##aMethod()->pMethod ) \
		   ( VirtualGetThisPtr##aMethod()->pThis, aArgName1, aArgName2 ); } \
	 V_IMPL1(aRetType, aClass, aMethod, aArgType1, aArgName1, aArgType2, aArgName2)

#define C_START \
     const void * CompatibleGetThis() const {return this;} \
     struct CompatibleImpl {

#define C_START1(x) \
     const void * CompatibleGetThis() const {return &x;} \
	 struct CompatibleImpl {

#define C_END };

#define C_INIT \
  (*(CompatibleImpl **)SfxPointerServer::GetServer()->CreatePointer(CompatibleGetThis()))= \
      new CompatibleImpl

#define C_DONE \
  delete ((CompatibleImpl *)SfxPointerServer::GetServer()->GetPointer(CompatibleGetThis())); \
  SfxPointerServer::GetServer()->ReleasePointer(CompatibleGetThis())

#ifdef C_SAFEUSE

#define C(Member) \
( \
  (SfxPointerServer::GetServer()->HasPointer(CompatibleGetThis()) ? NULL : (C_INIT)),\
  ((CompatibleImpl *)SfxPointerServer::GetServer()->GetPointer(CompatibleGetThis()))->Member \
)

#define C1(Class, Member) \
( \
  (SfxPointerServer::GetServer()->HasPointer(Class::CompatibleGetThis()) ? NULL : (C_INIT)),\
  ((Class::CompatibleImpl *) \
   SfxPointerServer::GetServer()->GetPointer(Class::CompatibleGetThis()))->Member \
)

#define C2(Object, Class, Member) \
( \
  (SfxPointerServer::GetServer()->HasPointer(((Class*)Object)->CompatibleGetThis()) \
      ? NULL : (C_INIT)),\
  ((Class::CompatibleImpl *) \
   SfxPointerServer::GetServer()->GetPointer(((Class*)Object)->CompatibleGetThis()))->Member \
)

#else

#define C(Member) \
  (((CompatibleImpl *)SfxPointerServer::GetServer()->GetPointer(CompatibleGetThis()))->Member)

#define C1(Class, Member) \
  (((Class::CompatibleImpl *) \
   SfxPointerServer::GetServer()->GetPointer(Class::CompatibleGetThis()))->Member)

#define C2(Object, Class, Member) \
  (((Class::CompatibleImpl *) \
   SfxPointerServer::GetServer()->GetPointer(((Class*)Object)->CompatibleGetThis()))->Member)

#endif

#endif

#undef C_VERSION
#ifdef C_SAFEUSE
#undef C_SAVEUSE

#endif

