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%define %_factory_dispatch(Type)
73if (!dcast) {
74  Type *dobj = dynamic_cast<Type *>($1);
75  if (dobj) {
76    dcast = 1;
77    %set_output(SWIG_NewPointerObj(%as_voidptr(dobj),$descriptor(Type *), $owner | %newpointer_flags));
78  }
79}%enddef
80
81%define %factory(Method,Types...)
82%typemap(out) Method {
83  int dcast = 0;
84  %formacro(%_factory_dispatch, Types)
85  if (!dcast) {
86    %set_output(SWIG_NewPointerObj(%as_voidptr($1),$descriptor, $owner | %newpointer_flags));
87  }
88}%enddef
89