more convenient and flexible implementation of dptr;
[web/konrad/chester.git] / dptr.h
diff --git a/dptr.h b/dptr.h
index b6c79b9..7812a0b 100644 (file)
--- a/dptr.h
+++ b/dptr.h
 //d-ptr header
 //
-// (c) Konrad Rosenbaum, 2010
-// protected under the GNU LGPL v3 or at your option any newer
+// (c) Konrad Rosenbaum, 2010-2011
+// Copying and distribution of this file, with or without modification,
+// are permitted in any medium without royalty provided the copyright
+// notice and this notice are preserved.  This file is offered as-is,
+// without any warranty.
 
-#ifndef DPTR_H
-#define DPTR_H
+#include "dptr_base.h"
 
-/** \page dptr Automatic d-Pointers
-to be written
 
-\see dptr.h
-*/
+#ifndef DPTR_CLASS_H
+#define DPTR_CLASS_H
+
+/** \mainpage Chester - d-pointers
+
+Chester is an implementation of the Cheshire Cat idiom - also known as
+d-pointer, PImpl (Pointer IMPLementation), or opaqua data pointer.
+It hides the data of a class behind a "d" pointer.
+
+This implementation takes away much of the bookkeeping work, like allocating
+and de-allocating the pointer.
+
+All the files of Chester are copyrighted under a permissive license:
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved.  This file is offered as-is,
+ without any warranty.
+
+So, you are free to use this implementation in any project under any kind of
+license as long as you do not remove my copyright notice.
+
+Although I do not require it, I would appreciate feedback on problems, bugs,
+and the occasional code improvement - if you feel like it...
+
+Different versions of Chester can be mixed for different classes, but the same version must be used both in the header file and in the implementation of the same class.
+
+\section kinds Kinds of D-Pointers
+
+Cheshire cats or d-pointers allow you to hide the data members (and if you want some of the implementation) of a class and also allow (within some constraints) to maintain ABI compatibility (ABI=Application Binary Interface) while adding or removing hidden data members.
+
+Chester defines three different kinds of d-pointers: non-copy, non-shared, and shared. Those three define different access patterns to the d-pointer.
+
+Non-copy d-pointers cannot be copied directly, if you want to make your main class copyable you have to explicitly create a copy constructor and/or an assignment operator. Those should be used with main classes and data objects that cannot be copied (like Qt's QObject and its subclasses).
 
-/** \file "dptr.h"
-Automatic d-Pointers Header File
+Non-shared d-pointers can be copied - if you copy an instance of the main class, the content of the d-pointer gets copied automatically (at least if you use the automatic copy constructor or call the copy constructor of the d-pointer). Each copy acts independently. This version produces the same behavior as if the data was defined directly in the main class instead of inside the d-pointer.
+
+Shared d-pointers can also be copied, but copying shares the data between instances of the main class. This can be used to create interface classes in which all copied instances share their data.
+
+All three kinds share the usage pattern. The header file and class interface declaration is declared like this (this example uses non-shared d-pointers):
+\code
+//file: myclass.h
+
+#include <DPtrBase>
+
+class MyClass
+{
+  DECLARE_DPTR(d)
+  public:
+    void myFunction();
+};
+\endcode
+
+The actual implementation file then declares and defines the d-pointer class:
+\code
+//file: myclass.cpp
+
+#include "myclass.h"
+#include <DPtr>
+
+class DPTR_CLASS_NAME(MyClass):public DPtr
+{
+  public:
+    int myint;
+};
+DEFINE_DPTR(MyClass)
 
-Please see \ref dptr "Automatic d-Pointers"
-for a tutorial.
+void MyClass::myFunction()
+{
+  d->myint = 99;
+}
+
+main()
+{
+  MyClass myinst;
+  myinst.myFunction();
+  MyClass otherinst(myinst);
+}
+\endcode
+
+Which actual kind of d-pointer behavior is declared is decided by using different macros and base classes for the d-pointer class. The argument to the DECLARE_* macro defines the name of the d-pointer variable, usually this will be "d", but you can chose any other name (except "Private" and "DPrivate", which are used as wrapper class names).
+
+The DPTR_CLASS_NAME macro returns the class name of the d-pointer class relative to the main class, which is given as argument. The DEFINE_* macro defines the logic that automatically instantiates, deletes and copies the d-pointer when the main class is instantiated, deleted, and copied. The d-pointer class must be derived from one of the DPtr classes, since these implement some functionality complementing the DEFINE_* macro.
+
+The header file should only include \<DPtrBase> - this file contains the DECLARE_* macros, which is the only thing needed for the header. If you include any other file, this makes mixing versions of Chester impossible in some situations. The implementation file must include one of the d-pointer implementation variants.
+
+\section table Comparison Table
+
+The macros, classes, \#include statements above need to be replaced with different ones if you want one of the other kinds of d-pointers:
+
+<table>
+<tr>
+ <td><b>Type</b><td><b>Pointer Declaration (1)</b><td><b>Declaration Include (1)</b>
+ <td><b>Base Class(2, 3)</b><td><b>Definition (2)</b><td><b>Implementation Include (2)</b></tr>
+<tr>
+ <td>Non-Shared, Copyable<td>DECLARE_DPTR(Class)<td>\#include \<\link dptr_base.h DPtrBase \endlink >
+ <td>DPtr<td>DEFINE_DPTR(Class)
+ <td>\#include \<\link dptr.h DPtr \endlink >
+ </tr>
+<tr>
+ <td>Shared<td>DECLARE_SHARED_DPTR(Class)<td>\#include \<\link dptr_base.h DPtrBase \endlink >
+ <td>SharedDPtr<td>DEFINE_SHARED_DPTR(Class)
+ <td>\#include \<\link dptr_shared.h SharedDPtr \endlink >
+ </tr>
+<tr>
+ <td>Non-Copyable<td>DECLARE_NONCOPY_DPTR(Class)<td>\#include \<\link dptr_base.h DPtrBase \endlink >
+ <td>NonCopyDPtr<td>DEFINE_NONCOPY_DPTR(Class)
+ <td>\#include \<\link dptr_noncopy.h NonCopyDPtr \endlink >
+ </tr>
+</table>
+
+(1) The DECLARE_* macro and declartion include directive are supposed to be used in the header file of the main class.
+
+(2) The implementation include directive should only be used in the main class'es implementation file - use the DEFINE_* macro to create the glue code that connects the d-pointer class with the main class.
+
+(3) The base class must be used to derive the d-pointer class in the implementation file. It contains some functionality that the DEFINE_* macro relies on.
 */
 
-/** \brief Expands to the fully qualified name of the d-pointer class.
-\param Class the fully qualified name of the class the d-pointer was declared in.*/
-#define DPTR_CLASS_NAME(Class) Class::Private
-///Expands to the local name of d-pointer classes (Private).
-#define DPTR_NAME Private
-///Expands to the local name of the d-pointer wrapper class (DPrivate).
-#define DPTR_WRAPPER_NAME DPrivate
-
-/** \brief Declares a smart shared or non-shared d-pointer, to be used inside class declaration.
-
-It also declares the internal nested classes DPrivate and Private - Private is the actual d-pointer class, while DPrivate is a wrapper that automatically allocates, copies and deallocates the d-pointer.
-
-The wrapper DPointer class contains these methods:
-   - constructor, copy constructor for creating instances of Private
-    - used by automatic and explicit constructors of the containing class
-   - destructor for deallocation of Private
-    - used by the destructor of the containing class
-   - assignment operator to copy the content of Private
-    - used by the assignment operator of the containing class
-   - pointer operator to actually access the Private data
-
-You can use DEFINE_DPTR to define the necessary methods for a non-shared d-pointer or DEFINE_SHARED_DPTR if you want to share d-pointer data between instances of the containing class. It is recommended that non-shared d-pointer classes (Private) are derived from DPtr and the shared variants be derived from SharedDPtr.
-
-The d-pointer class Private is only forward declared, you have to fully declare and implement it in the code where you are using it, i.e. where you are implementing the containing class.
-
-\param dp name of the d-pointer*/
-#define DECLARE_DPTR(dp) \
- private:\
- class Private; \
- class DPrivate{\
-  public:DPrivate();DPrivate(const DPrivate&);~DPrivate();\
-  DPrivate&operator=(const DPrivate&);\
-  const Private*operator->()const{return d;}\
-  Private*operator->(){return d;}\
-  DPrivate clone()const;\
-  private:Private*d;\
- }; \
- DPrivate dp;
-
- /** \brief Alias for DECLARE_DPTR for convenience.
-
-\param dp name of the d-pointer*/
-#define DECLARE_SHARED_DPTR(dp) DECLARE_DPTR(dp)
+//hide the namespace
+/// \cond never
+namespace Chester_0_1{
+/// \endcond
 
 /** \brief Base class of non-shared d-pointers.
 
@@ -75,9 +143,20 @@ class DPtr
                virtual ~DPtr(){}
 };
 
+//hide the namespace
+/// \cond never
+};
+using namespace Chester_0_1;
+/// \endcond
+#endif
+
+#ifdef DEFINE_DPTR
+#undef DEFINE_DPTR
+#endif
+
 /** \brief Creates definitions for methods of the non-shared d-pointer wrapper. 
 
-This variant is not shared between instances of the containing class.
+This variant is not shared between instances of the containing class, but it is able to copy its content (using the contents copy constructor and assignment operator). You cannot use this variant if any of the content classes have inaccessable copy constructors or assignment operators (like Qt's QObject and its subclasses).
 
 To be used in implementation where the actual d-pointer class is implemented.
 
@@ -90,37 +169,3 @@ To be used in implementation where the actual d-pointer class is implemented.
  Class::DPrivate& Class::DPrivate::operator=(const Class::DPrivate&dp)\
  {*d=*(dp.d);return *this;}
 
-/** \brief Base class of shared d-pointers.
-
-Use in conjunction with DECLARE_SHARED_DPTR and DEFINE_SHARED_DPTR */
-class SharedDPtr
-{
-       private:
-               int cnt;
-       public:
-               ///instantiates a shared d-pointer
-               SharedDPtr(){cnt=1;}
-               ///deletes a shared d-pointer
-               virtual ~SharedDPtr(){}
-               ///called by the wrapper to attach to a new instance
-               virtual void attach(){cnt++;}
-               ///called by the wrapper to detach from an instance
-               virtual void detach(){cnt--;if(cnt==0)delete this;}
-};
-
-/** \brief Defines the methods of the shared d-pointer wrapper.
-
-This implements the shared version of the d-pointer wrapper.
-To be used in implementation where the actual d-pointer class is implemented.
-
-\param Class the base class within which the d-pointer was declared*/
-#define DEFINE_SHARED_DPTR(Class) \
- Class::DPrivate::DPrivate(){d=new Class::Private;}\
- Class::DPrivate::DPrivate(const DPrivate&dp){d=dp.d;d->attach();}\
- Class::DPrivate::~DPrivate(){d->detach();}\
- Class::DPrivate Class::DPrivate::clone()const{DPrivate r;*(r.d)=*d;return r;}\
- Class::DPrivate& Class::DPrivate::operator=(const DPrivate&dp)\
- {d->detach();d=dp.d;d->attach();return *this;}
-
-
-#endif