Home | History | Annotate | Download | only in ruby
      1 /* -----------------------------------------------------------------------------
      2  * director.swg
      3  *
      4  * This file contains support for director classes that proxy
      5  * method calls from C++ to Ruby extensions.
      6  * ----------------------------------------------------------------------------- */
      7 
      8 /*
      9   Use -DSWIG_DIRECTOR_NOUEH if you prefer to avoid the use of the
     10   Undefined Exception Handler provided by swig.
     11 */
     12 #ifndef SWIG_DIRECTOR_NOUEH
     13 #ifndef SWIG_DIRECTOR_UEH
     14 #define SWIG_DIRECTOR_UEH
     15 #endif
     16 #endif
     17 
     18 #ifdef __cplusplus
     19 
     20 #include <string>
     21 #include <iostream>
     22 #include <map>
     23 
     24 # define SWIG_DIRECTOR_CAST(ARG) dynamic_cast<Swig::Director *>(ARG)
     25 
     26 namespace Swig {
     27   /* memory handler */
     28   struct GCItem
     29   {
     30     virtual ~GCItem()
     31     {
     32     }
     33 
     34     virtual ruby_owntype get_own() const
     35     {
     36       return 0;
     37     }
     38   };
     39 
     40   struct GCItem_var
     41   {
     42     GCItem_var(GCItem *item = 0) : _item(item)
     43     {
     44     }
     45 
     46     GCItem_var& operator=(GCItem *item)
     47     {
     48       GCItem *tmp = _item;
     49       _item = item;
     50       delete tmp;
     51       return *this;
     52     }
     53 
     54     ~GCItem_var()
     55     {
     56       delete _item;
     57     }
     58 
     59     GCItem * operator->() const
     60     {
     61       return _item;
     62     }
     63 
     64   private:
     65     GCItem *_item;
     66   };
     67 
     68 
     69   template <typename Type>
     70   struct GCItem_T : GCItem
     71   {
     72     GCItem_T(Type *ptr) : _ptr(ptr)
     73     {
     74     }
     75 
     76     virtual ~GCItem_T()
     77     {
     78       delete _ptr;
     79     }
     80 
     81   private:
     82     Type *_ptr;
     83   };
     84 
     85   struct GCItem_Object : GCItem
     86   {
     87     GCItem_Object(ruby_owntype own) : _own(own)
     88     {
     89     }
     90 
     91     virtual ~GCItem_Object()
     92     {
     93     }
     94 
     95     ruby_owntype get_own() const
     96     {
     97       return _own;
     98     }
     99 
    100   private:
    101     ruby_owntype _own;
    102   };
    103 
    104 
    105   template <typename Type>
    106   struct GCArray_T : GCItem
    107   {
    108     GCArray_T(Type *ptr) : _ptr(ptr)
    109     {
    110     }
    111 
    112     virtual ~GCArray_T()
    113     {
    114       delete[] _ptr;
    115     }
    116 
    117   private:
    118     Type *_ptr;
    119   };
    120 
    121 
    122   /* body args */
    123   struct body_args {
    124     VALUE recv;
    125     ID id;
    126     int argc;
    127     VALUE *argv;
    128   };
    129 
    130   /* Base class for director exceptions */
    131   class DirectorException {
    132   protected:
    133     VALUE swig_error;
    134     std::string swig_msg;
    135   protected:
    136     DirectorException(VALUE error)
    137       : swig_error(error)
    138     {
    139     }
    140 
    141     DirectorException(VALUE error, const char* hdr, const char* msg ="")
    142       : swig_error(error), swig_msg(hdr) {
    143       if (strlen(msg)) {
    144 	swig_msg += " ";
    145 	swig_msg += msg;
    146       }
    147       if (swig_msg.size()) {
    148 	VALUE str = rb_str_new(swig_msg.data(), swig_msg.size());
    149 	swig_error = rb_exc_new3(error, str);
    150       } else {
    151 	swig_error = error;
    152       }
    153     }
    154   public:
    155     VALUE getType() const  {
    156       return CLASS_OF(swig_error);
    157     }
    158     VALUE getError() const {
    159       return swig_error;
    160     }
    161     const std::string& getMessage() const
    162     {
    163       return swig_msg;
    164     }
    165 
    166     virtual ~DirectorException() {}
    167   };
    168 
    169   /* unknown exception handler  */
    170 
    171   class UnknownExceptionHandler
    172   {
    173 #ifdef SWIG_DIRECTOR_UEH
    174     static void handler() {
    175       try {
    176 	throw;
    177       } catch (DirectorException& e) {
    178 	std::cerr << "SWIG Director exception caught:" << std::endl
    179 		  << e.getMessage() << std::endl;
    180       } catch (std::exception& e) {
    181 	std::cerr << "std::exception caught: "<< e.what() << std::endl;
    182       } catch (...) {
    183 	std::cerr << "Unknown exception caught." << std::endl;
    184       }
    185       std::cerr << std::endl
    186 		<< "Ruby interpreter traceback:" << std::endl;
    187       std::cerr << std::endl;
    188       std::cerr << "This exception was caught by the SWIG unexpected exception handler." << std::endl
    189 		<< "Try using %feature(\"director:except\") to avoid reaching this point." << std::endl
    190 		<< std::endl
    191 		<< "Exception is being re-thrown, program will like abort/terminate." << std::endl;
    192       throw;
    193     }
    194 
    195   public:
    196     std::unexpected_handler old;
    197     UnknownExceptionHandler(std::unexpected_handler nh = handler)
    198     {
    199       old = std::set_unexpected(nh);
    200     }
    201 
    202     ~UnknownExceptionHandler()
    203     {
    204       std::set_unexpected(old);
    205     }
    206 #endif
    207   };
    208 
    209 
    210   /* Type mismatch in the return value from a Ruby method call */
    211   class DirectorTypeMismatchException : public Swig::DirectorException {
    212   public:
    213     DirectorTypeMismatchException(VALUE error, const char *msg="")
    214       : Swig::DirectorException(error, "SWIG director type mismatch", msg)
    215     {
    216     }
    217 
    218     DirectorTypeMismatchException(const char *msg="")
    219       : Swig::DirectorException(rb_eTypeError, "SWIG director type mismatch", msg)
    220     {
    221     }
    222 
    223     static void raise(VALUE error, const char *msg) {
    224       throw DirectorTypeMismatchException(error, msg);
    225     }
    226 
    227     static void raise(const char *msg) {
    228       throw DirectorTypeMismatchException(msg);
    229     }
    230   };
    231 
    232   /* Any Ruby exception that occurs during a director method call */
    233   class DirectorMethodException : public Swig::DirectorException {
    234   public:
    235     DirectorMethodException(VALUE error)
    236       : Swig::DirectorException(error) {
    237     }
    238 
    239     DirectorMethodException(const char* msg = "")
    240       : Swig::DirectorException(rb_eRuntimeError, "SWIG director method error.", msg) {
    241     }
    242 
    243     static void raise(VALUE error)
    244     {
    245       throw DirectorMethodException(error);
    246     }
    247   };
    248 
    249   /* Attempted to call a pure virtual method via a director method */
    250   class DirectorPureVirtualException : public Swig::DirectorException
    251   {
    252   public:
    253     DirectorPureVirtualException(const char* msg = "")
    254       : DirectorException(rb_eRuntimeError, "SWIG director pure virtual method called", msg)
    255     {
    256     }
    257 
    258     static void raise(const char *msg)
    259     {
    260       throw DirectorPureVirtualException(msg);
    261     }
    262   };
    263 
    264   /* Simple thread abstraction for pthreads on win32 */
    265 #ifdef __THREAD__
    266 # define __PTHREAD__
    267 # if defined(_WIN32) || defined(__WIN32__)
    268 #  define pthread_mutex_lock EnterCriticalSection
    269 #  define pthread_mutex_unlock LeaveCriticalSection
    270 #  define pthread_mutex_t CRITICAL_SECTION
    271 #  define SWIG_MUTEX_INIT(var) var
    272 # else
    273 #  include <pthread.h>
    274 #  define SWIG_MUTEX_INIT(var) var = PTHREAD_MUTEX_INITIALIZER
    275 # endif
    276 #endif
    277 
    278 #ifdef  __PTHREAD__
    279   struct Guard
    280   {
    281     pthread_mutex_t *_mutex;
    282 
    283     Guard(pthread_mutex_t &mutex) : _mutex(&mutex)
    284     {
    285       pthread_mutex_lock(_mutex);
    286     }
    287 
    288     ~Guard()
    289     {
    290       pthread_mutex_unlock(_mutex);
    291     }
    292   };
    293 # define SWIG_GUARD(mutex) Guard _guard(mutex)
    294 #else
    295 # define SWIG_GUARD(mutex)
    296 #endif
    297 
    298   /* director base class */
    299   class Director {
    300   private:
    301     /* pointer to the wrapped Ruby object */
    302     VALUE swig_self;
    303     /* flag indicating whether the object is owned by Ruby or c++ */
    304     mutable bool swig_disown_flag;
    305 
    306   public:
    307     /* wrap a Ruby object, optionally taking ownership */
    308     Director(VALUE self) : swig_self(self), swig_disown_flag(false) {
    309     }
    310 
    311     /* discard our reference at destruction */
    312     virtual ~Director() {
    313     }
    314 
    315     /* return a pointer to the wrapped Ruby object */
    316     VALUE swig_get_self() const {
    317       return swig_self;
    318     }
    319 
    320     /* acquire ownership of the wrapped Ruby object (the sense of "disown"
    321      * is from Ruby) */
    322     void swig_disown() const {
    323       if (!swig_disown_flag) {
    324         swig_disown_flag = true;
    325       }
    326     }
    327 
    328   /* ownership management */
    329   private:
    330     typedef std::map<void*, GCItem_var> swig_ownership_map;
    331     mutable swig_ownership_map swig_owner;
    332 #ifdef __PTHREAD__
    333     static pthread_mutex_t swig_mutex_own;
    334 #endif
    335 
    336   public:
    337     template <typename Type>
    338     void swig_acquire_ownership_array(Type *vptr)  const
    339     {
    340       if (vptr) {
    341 	SWIG_GUARD(swig_mutex_own);
    342 	swig_owner[vptr] = new GCArray_T<Type>(vptr);
    343       }
    344     }
    345 
    346     template <typename Type>
    347     void swig_acquire_ownership(Type *vptr)  const
    348     {
    349       if (vptr) {
    350 	SWIG_GUARD(swig_mutex_own);
    351 	swig_owner[vptr] = new GCItem_T<Type>(vptr);
    352       }
    353     }
    354 
    355     void swig_acquire_ownership_obj(void *vptr, ruby_owntype own) const
    356     {
    357       if (vptr && own) {
    358 	SWIG_GUARD(swig_mutex_own);
    359 	swig_owner[vptr] = new GCItem_Object(own);
    360       }
    361     }
    362 
    363     ruby_owntype swig_release_ownership(void *vptr) const
    364     {
    365       ruby_owntype own = 0;
    366       if (vptr) {
    367 	SWIG_GUARD(swig_mutex_own);
    368 	swig_ownership_map::iterator iter = swig_owner.find(vptr);
    369 	if (iter != swig_owner.end()) {
    370 	  own = iter->second->get_own();
    371 	  swig_owner.erase(iter);
    372 	}
    373       }
    374       return own;
    375     }
    376   };
    377 }
    378 
    379 #endif /* __cplusplus */
    380 
    381 
    382