1/*
2  Implement a more natural wrap for factory methods, for example, if
3  you have:
4
5  ----  geometry.h --------
6       struct Geometry {
7         enum GeomType{
8           POINT,
9           CIRCLE
10         };
11
12         virtual ~Geometry() {}
13         virtual int draw() = 0;
14
15	 //
16	 // Factory method for all the Geometry objects
17	 //
18         static Geometry *create(GeomType i);
19       };
20
21       struct Point : Geometry  {
22         int draw() { return 1; }
23         double width() { return 1.0; }
24       };
25
26       struct Circle : Geometry  {
27         int draw() { return 2; }
28         double radius() { return 1.5; }
29       };
30
31       //
32       // Factory method for all the Geometry objects
33       //
34       Geometry *Geometry::create(GeomType type) {
35         switch (type) {
36         case POINT: return new Point();
37         case CIRCLE: return new Circle();
38         default: return 0;
39         }
40       }
41  ----  geometry.h --------
42
43
44  You can use the %factory with the Geometry::create method as follows:
45
46    %newobject Geometry::create;
47    %factory(Geometry *Geometry::create, Point, Circle);
48    %include "geometry.h"
49
50  and Geometry::create will return a 'Point' or 'Circle' instance
51  instead of the plain 'Geometry' type. For example, in python:
52
53    circle = Geometry.create(Geometry.CIRCLE)
54    r = circle.radius()
55
56  where circle is a Circle proxy instance.
57
58  NOTES: remember to fully qualify all the type names and don't
59  use %factory inside a namespace declaration, ie, instead of
60
61     namespace Foo {
62       %factory(Geometry *Geometry::create, Point, Circle);
63     }
64
65  use
66
67     %factory(Foo::Geometry *Foo::Geometry::create, Foo::Point,  Foo::Circle);
68
69
70*/
71
72/* for loop for macro with one argument */
73%define %_formacro_1(macro, arg1,...)macro(arg1)
74#if #__VA_ARGS__ != "__fordone__"
75%_formacro_1(macro, __VA_ARGS__)
76#endif
77%enddef
78
79/* for loop for macro with one argument */
80%define %formacro_1(macro,...)%_formacro_1(macro,__VA_ARGS__,__fordone__)%enddef
81%define %formacro(macro,...)%_formacro_1(macro,__VA_ARGS__,__fordone__)%enddef
82
83/* for loop for macro with two arguments */
84%define %_formacro_2(macro, arg1, arg2, ...)macro(arg1, arg2)
85#if #__VA_ARGS__ != "__fordone__"
86%_formacro_2(macro, __VA_ARGS__)
87#endif
88%enddef
89
90/* for loop for macro with two arguments */
91%define %formacro_2(macro,...)%_formacro_2(macro, __VA_ARGS__, __fordone__)%enddef
92
93%define %_factory_dispatch(Type)
94if (!dcast) {
95  Type *dobj = dynamic_cast<Type *>($1);
96  if (dobj) {
97    dcast = 1;
98    SWIG_SetPointerZval(return_value, SWIG_as_voidptr(dobj),$descriptor(Type *), $owner);
99  }
100}%enddef
101
102%define %factory(Method,Types...)
103%typemap(out) Method {
104  int dcast = 0;
105  %formacro(%_factory_dispatch, Types)
106  if (!dcast) {
107    SWIG_SetPointerZval(return_value, SWIG_as_voidptr($1),$descriptor, $owner);
108  }
109}%enddef
110