

SWIGRUNTIME bool SWIG_check_num_args(const char *func_name, int num_args, int max_args, int min_args, int varargs) {
  if (num_args > max_args && !varargs)
    error("function %s takes at most %i arguments", func_name, max_args);
  else if (num_args < min_args)
    error("function %s requires at least %i arguments", func_name, min_args);
  else
    return true;
  return false;
}

SWIGRUNTIME octave_value_list *SWIG_Octave_AppendOutput(octave_value_list *ovl, const octave_value &ov) {
  ovl->append(ov);
  return ovl;
}

SWIGRUNTIME octave_value SWIG_ErrorType(int code) {
  switch (code) {
  case SWIG_MemoryError:
    return "SWIG_MemoryError";
  case SWIG_IOError:
    return "SWIG_IOError";
  case SWIG_RuntimeError:
    return "SWIG_RuntimeError";
  case SWIG_IndexError:
    return "SWIG_IndexError";
  case SWIG_TypeError:
    return "SWIG_TypeError";
  case SWIG_DivisionByZero:
    return "SWIG_DivisionByZero";
  case SWIG_OverflowError:
    return "SWIG_OverflowError";
  case SWIG_SyntaxError:
    return "SWIG_SyntaxError";
  case SWIG_ValueError:
    return "SWIG_ValueError";
  case SWIG_SystemError:
    return "SWIG_SystemError";
  case SWIG_AttributeError:
    return "SWIG_AttributeError";
  }
  return "SWIG unknown error";
}

SWIGRUNTIME octave_value SWIG_Error(int code, const char *msg) {
  octave_value type(SWIG_ErrorType(code));
  std::string r = msg;
  r += " (" + type.string_value() + ")";
  error(r.c_str());
  return octave_value(r);
}

#define SWIG_fail                                       goto fail

#define SWIG_Octave_ConvertPtr(obj, pptr, type, flags)  SWIG_Octave_ConvertPtrAndOwn(obj, pptr, type, flags, 0)
#define SWIG_ConvertPtr(obj, pptr, type, flags)         SWIG_Octave_ConvertPtr(obj, pptr, type, flags)
#define SWIG_ConvertPtrAndOwn(obj,pptr,type,flags,own)  SWIG_Octave_ConvertPtrAndOwn(obj, pptr, type, flags, own)
#define SWIG_ConvertPtr(obj, pptr, type, flags)         SWIG_Octave_ConvertPtr(obj, pptr, type, flags)
#define SWIG_NewPointerObj(ptr, type, flags)            SWIG_Octave_NewPointerObj(ptr, type, flags)
#define swig_owntype                                    int

#define SWIG_ConvertPacked(obj, ptr, sz, ty)            SWIG_Octave_ConvertPacked(obj, ptr, sz, ty)
#define SWIG_NewPackedObj(ptr, sz, type)                SWIG_Octave_NewPackedObj(ptr, sz, type)

#define SWIG_ConvertFunctionPtr(obj, pptr, type)        SWIG_ConvertPtr(obj, pptr, type, 0)
#define SWIG_NewFunctionPtrObj(ptr, type)               SWIG_NewPointerObj(ptr, type, 0)

#define SWIG_ConvertMember(obj, ptr, sz, ty)            SWIG_Octave_ConvertPacked(obj, ptr, sz, ty)
#define SWIG_NewMemberObj(ptr, sz, type)                SWIG_Octave_NewPackedObj(ptr, sz, type)

#define SWIG_GetModule(clientdata) SWIG_Octave_GetModule(clientdata)
#define SWIG_SetModule(clientdata, pointer) SWIG_Octave_SetModule(clientdata,pointer);
#define SWIG_MODULE_CLIENTDATA_TYPE void*

#define Octave_Error_Occurred() 0
#define SWIG_Octave_AddErrorMsg(msg) {;}

SWIGRUNTIME swig_module_info *SWIG_Octave_GetModule(void *clientdata);
SWIGRUNTIME void SWIG_Octave_SetModule(void *clientdata, swig_module_info *pointer);

// For backward compatibility only
#define SWIG_POINTER_EXCEPTION  0
#define SWIG_arg_fail(arg)      0

// Runtime API implementation

#include <map>
#include <vector>
#include <string>

typedef octave_value_list(*octave_func) (const octave_value_list &, int);
class octave_swig_type;

namespace Swig {
  class Director;

  SWIGRUNTIME void swig_register_director(octave_swig_type *self, void *ptr, Director *d);
  SWIGRUNTIME void swig_director_destroyed(octave_swig_type *self, Director *d);
  SWIGRUNTIME void swig_director_set_self(Director *d, octave_swig_type *self);

  SWIGRUNTIME octave_base_value *swig_value_ref(octave_swig_type *ost);
  SWIGRUNTIME octave_swig_type *swig_value_deref(octave_value ov);
  SWIGRUNTIME octave_swig_type *swig_value_deref(const octave_base_value &ov);

  typedef std::map < void *, Director * > rtdir_map;

  SWIGINTERN rtdir_map &get_rtdir_map() {
    static swig_module_info *module = 0;
    if (!module)
      module = SWIG_GetModule(0);
    assert(module);
    if (!module->clientdata)
      module->clientdata = new rtdir_map;
    return *(rtdir_map *) module->clientdata;
  }

  SWIGINTERNINLINE void set_rtdir(void *vptr, Director *d) {
    get_rtdir_map()[vptr] = d;
  }

  SWIGINTERNINLINE void erase_rtdir(void *vptr) {
    get_rtdir_map().erase(vptr);
  }

  SWIGINTERNINLINE Director *get_rtdir(void *vptr) {
    rtdir_map::const_iterator pos = get_rtdir_map().find(vptr);
    Director *rtdir = (pos != get_rtdir_map().end())? pos->second : 0;
    return rtdir;
  }
}

  struct swig_octave_member {
    const char *name;
    octave_func method;
    octave_func get_method;
    octave_func set_method;
    int flags;			// 1 static, 2 global
    const char *doc;
    bool is_static() const {
      return flags &1;
    } bool is_global() const {
      return flags &2;
    }
  };

  struct swig_octave_class {
    const char *name;
    swig_type_info **type;
    int director;
    octave_func constructor;
    const char *constructor_doc;
    octave_func destructor;
    const swig_octave_member *members;
    const char **base_names;
    const swig_type_info **base;
  };

  // octave_swig_type plays the role of both the shadow class and the class 
  // representation within Octave, since there is no support for classes.
  //
  // These should really be decoupled, with the class support added to Octave
  // and the shadow class given by an m-file script. That would dramatically 
  // reduce the runtime complexity, and be more in line w/ other modules.

  class octave_swig_type:public octave_base_value {
    struct cpp_ptr {
      void *ptr;
      bool destroyed;
      cpp_ptr(void *_ptr):ptr(_ptr), destroyed(false) {
      }};
    typedef std::pair < const swig_type_info *, cpp_ptr > type_ptr_pair;

    mutable swig_module_info *module;

    const swig_type_info *construct_type;	// type of special type object
    std::vector < type_ptr_pair > types;	// our c++ base classes
    int own;			// whether we call c++ destructors when we die

    typedef std::pair < const swig_octave_member *, octave_value > member_value_pair;
    typedef std::map < std::string, member_value_pair > member_map;
    member_map members;
    bool always_static;

    const swig_octave_member *find_member(const swig_type_info *type, const std::string &name) {
      if (!type->clientdata)
	return 0;
      swig_octave_class *c = (swig_octave_class *) type->clientdata;
      const swig_octave_member *m;
      for (m = c->members; m->name; ++m)
	if (m->name == name)
	  return m;
      for (int j = 0; c->base_names[j]; ++j) {
	if (!c->base[j]) {
	  if (!module)
	    module = SWIG_GetModule(0);
	  assert(module);
	  c->base[j] = SWIG_MangledTypeQueryModule(module, module, c->base_names[j]);
	}
	if (!c->base[j])
	  return 0;
	if ((m = find_member(c->base[j], name)))
	  return m;
      }
      return 0;
    }

    member_value_pair *find_member(const std::string &name, bool insert_if_not_found) {
      member_map::iterator it = members.find(name);
      if (it != members.end())
	return &it->second;
      const swig_octave_member *m;
      for (unsigned int j = 0; j < types.size(); ++j)
	if ((m = find_member(types[j].first, name)))
	  return &members.insert(std::make_pair(name, std::make_pair(m, octave_value()))).first->second;
      if (!insert_if_not_found)
	return 0;
      return &members[name];
    }

    const swig_type_info *find_base(const std::string &name, const swig_type_info *base) {
      if (!base) {
	for (unsigned int j = 0; j < types.size(); ++j) {
	  assert(types[j].first->clientdata);
	  swig_octave_class *cj = (swig_octave_class *) types[j].first->clientdata;
	  if (cj->name == name)
	    return types[j].first;
	}
	return 0;
      }
      assert(base->clientdata);
      swig_octave_class *c = (swig_octave_class *) base->clientdata;
      for (int j = 0; c->base_names[j]; ++j) {
	if (!c->base[j]) {
	  if (!module)
	    module = SWIG_GetModule(0);
	  assert(module);
	  c->base[j] = SWIG_MangledTypeQueryModule(module, module, c->base_names[j]);
	}
	if (!c->base[j])
	  return 0;
	assert(c->base[j]->clientdata);
	swig_octave_class *cj = (swig_octave_class *) c->base[j]->clientdata;
	if (cj->name == name)
	  return c->base[j];
      }
      return 0;
    }

    void load_members(const swig_octave_class* c,member_map& out) const {
      for (const swig_octave_member *m = c->members; m->name; ++m) {
	if (out.find(m->name) == out.end())
	  out.insert(std::make_pair(m->name, std::make_pair(m, octave_value())));
      }
      for (int j = 0; c->base_names[j]; ++j) {
	if (!c->base[j]) {
	  if (!module)
	    module = SWIG_GetModule(0);
	  assert(module);
	  c->base[j] = SWIG_MangledTypeQueryModule(module, module, c->base_names[j]);
	}
	if (!c->base[j])
	  continue;
	assert(c->base[j]->clientdata);
	const swig_octave_class *cj =
	  (const swig_octave_class *) c->base[j]->clientdata;
	load_members(cj,out);
      }
    }

    void load_members(member_map& out) const {
      out=members;
      for (unsigned int j = 0; j < types.size(); ++j)
	if (types[j].first->clientdata)
	  load_members((const swig_octave_class *) types[j].first->clientdata, out);
    }

    octave_value_list member_invoke(member_value_pair *m, const octave_value_list &args, int nargout) {
      if (m->second.is_defined())
	return m->second.subsref("(", std::list < octave_value_list > (1, args), nargout);
      else if (m->first && m->first->method)
	return m->first->method(args, nargout);
      error("member not defined or not invocable");
      return octave_value_list();
    }

    bool dispatch_unary_op(const std::string &symbol, octave_value &ret) {
      member_value_pair *m = find_member(symbol, false);
      if (!m || m->first->is_static() || m->first->is_global())
	return false;
      octave_value_list args;
      args.append(as_value());
      octave_value_list argout(member_invoke(m, args, 1));
      if (argout.length() < 1)
	return false;
      ret = argout(0);
      return true;
    }

    bool dispatch_binary_op(const std::string &symbol, const octave_base_value &rhs, octave_value &ret) {
      member_value_pair *m = find_member(symbol, false);
      if (!m || m->first->is_static() || m->first->is_global())
	return false;
      octave_value_list args;
      args.append(as_value());
      args.append(make_value_hack(rhs));
      octave_value_list argout(member_invoke(m, args, 1));
      if (argout.length() < 1)
	return false;
      ret = argout(0);
      return true;
    }

    bool dispatch_index_op(const std::string &symbol, const octave_value_list &rhs, octave_value_list &ret) {
      member_value_pair *m = find_member(symbol, false);
      if (!m || m->first->is_static() || m->first->is_global())
	return false;
      octave_value_list args;
      args.append(as_value());
      args.append(rhs);
      octave_value_list argout(member_invoke(m, args, 1));
      if (argout.length() >= 1)
	ret = argout(0);
      return true;
    }

    octave_value_list member_deref(member_value_pair *m, const octave_value_list &args) {
      if (m->second.is_defined())
	return m->second;
      else if (m->first) {
	if (m->first->get_method)
	  return m->first->get_method(args, 1);
	else if (m->first->method)
	  return octave_value(new octave_builtin(m->first->method));
      }
      error("undefined member");
      return octave_value_list();
    }

    static octave_value make_value_hack(const octave_base_value &x) {
      ((octave_swig_type &) x).count++;
      return octave_value((octave_base_value *) &x);
    }

    octave_swig_type(const octave_swig_type &x);
    octave_swig_type &operator=(const octave_swig_type &rhs);
  public:

    octave_swig_type(void *_ptr = 0, const swig_type_info *_type = 0, int _own = 0,
		     bool _always_static = false)
      :	module(0), construct_type(_ptr ? 0 : _type), own(_own), 
      always_static(_always_static) {
      if (_type || _ptr)
	types.push_back(std::make_pair(_type, _ptr));
      if (_ptr) {
	Swig::Director *d = Swig::get_rtdir(_ptr);
	if (d)
	  Swig::swig_director_set_self(d, this);
      }
    }

    ~octave_swig_type() {
      if (own) {
	++count;
	for (unsigned int j = 0; j < types.size(); ++j) {
	  if (!types[j].first || !types[j].first->clientdata)
	    continue;
	  swig_octave_class *c = (swig_octave_class *) types[j].first->clientdata;
	  if (c->destructor && !types[j].second.destroyed && types[j].second.ptr) {
	    c->destructor(as_value(), 0);
	  }
	}
      }
      for (unsigned int j = 0; j < types.size(); ++j)
	Swig::erase_rtdir(types[j].second.ptr);
    }

    octave_value as_value() {
      ++count;
      return Swig::swig_value_ref(this);
    }

    void incref() {
      ++count;
    }

    void decref() {
      if (!--count)
	delete this;
    }

    long swig_this() const {
      if (!types.size())
	return (long) this;
      return (long) types[0].second.ptr;
    }
    const char* help_text() const {
      if (!types.size())
	return 0;
      if (!types[0].first->clientdata)
	return 0;
      swig_octave_class *c = (swig_octave_class *) types[0].first->clientdata;
      return c->constructor_doc;
    }

    std::string swig_type_name() const {
      // * need some way to manually name subclasses.
      // * eg optional first arg to subclass(), or named_subclass()
      std::string ret;
      for (unsigned int j = 0; j < types.size(); ++j) {
	if (j)
	  ret += "_";
	if (types[j].first->clientdata) {
	  swig_octave_class *c = (swig_octave_class *) types[j].first->clientdata;
	  ret += c->name;
	} else
	  ret += types[j].first->name;
      }
      return ret;
    }

    void merge(octave_swig_type &rhs) {
      rhs.own = 0;
      for (unsigned int j = 0; j < rhs.types.size(); ++j) {
	assert(!rhs.types[j].second.destroyed);
	Swig::Director *d = Swig::get_rtdir(rhs.types[j].second.ptr);
	if (d)
	  Swig::swig_director_set_self(d, this);
      }
      types.insert(types.end(), rhs.types.begin(), rhs.types.end());
      members.insert(rhs.members.begin(), rhs.members.end());
      rhs.types.clear();
      rhs.members.clear();
    }

    void install_global() {
      for (member_map::const_iterator it = members.begin(); it != members.end(); ++it) {
	if (it->second.first && it->second.first->method)
	  install_builtin_function(it->second.first->method, it->first,
				   it->second.first->doc?it->second.first->doc:std::string());
	else if (it->second.second.is_defined()) {
	  link_to_global_variable(curr_sym_tab->lookup(it->first, true));
	  set_global_value(it->first, it->second.second);
	  
	  octave_swig_type *ost = Swig::swig_value_deref(it->second.second);
	  if (ost) {
	    const char* h = ost->help_text();
	    if (h) {
	      symbol_record *sr = global_sym_tab->lookup (it->first, true);
	      sr->document(h);
	    }
	  }
	}
      }
    }

    void *cast(swig_type_info *type, int *_own, int flags) {
      if (_own)
	*_own = own;
      if (flags &SWIG_POINTER_DISOWN)
	own = 0;
      if (!type && types.size())
	return types[0].second.ptr;
      for (unsigned int j = 0; j < types.size(); ++j)
	if (type == types[j].first)
	  return types[j].second.ptr;
      for (unsigned int j = 0; j < types.size(); ++j) {
	swig_cast_info *tc = SWIG_TypeCheck(types[j].first->name, type);
	if (!tc)
	  continue;
	int newmemory = 0;
	void *vptr = SWIG_TypeCast(tc, types[j].second.ptr, &newmemory);
	assert(!newmemory);	// newmemory handling not yet implemented
	return vptr;
      }
      return 0;
    }

    bool is_owned() const {
      return own;
    }

    void director_destroyed(Swig::Director *d) {
      bool found = false;
      for (unsigned int j = 0; j < types.size(); ++j) {
	Swig::Director *dj = Swig::get_rtdir(types[j].second.ptr);
	if (dj == d) {
	  types[j].second.destroyed = true;
	  found = true;
	}
      }
      assert(found);
    }

    void assign(const std::string &name, const octave_value &ov) {
      members[name] = std::make_pair((const swig_octave_member *) 0, ov);
    }

    void assign(const std::string &name, const swig_octave_member *m) {
      members[name] = std::make_pair(m, octave_value());
    }

    octave_base_value *clone() const {
      // pass-by-value is probably not desired, and is harder;
      // requires calling copy constructors of contained types etc.
      assert(0);
      *(int *) 0 = 0;
      return 0;
    }

    octave_base_value *empty_clone() const {
      return new octave_swig_type();
    }

    bool is_defined() const {
      return true;
    }

    virtual bool is_map() const {
      return true;
    }

    virtual octave_value subsref(const std::string &ops, const std::list < octave_value_list > &idx) {
      octave_value_list ovl = subsref(ops, idx, 1);
      return ovl.length()? ovl(0) : octave_value();
    }

    virtual octave_value_list subsref(const std::string &ops, const std::list < octave_value_list > &idx, int nargout) {
      assert(ops.size() > 0);
      assert(ops.size() == idx.size());

      std::list < octave_value_list >::const_iterator idx_it = idx.begin();
      int skip = 0;
      octave_value_list sub_ovl;

      // constructor invocation
      if (ops[skip] == '(' && construct_type) {
	assert(construct_type->clientdata);
	swig_octave_class *c = (swig_octave_class *) construct_type->clientdata;
	if (!c->constructor) {
	  error("cannot create instance");
	  return octave_value_list();
	}
	octave_value_list args;
	if (c->director)
	  args.append(Swig::swig_value_ref(new octave_swig_type(this, 0, 0)));
	args.append(*idx_it++);
	++skip;
	sub_ovl = c->constructor(args, nargout);
      }
      // member dereference or invocation
      else if (ops[skip] == '.') {
	std::string subname;
	const swig_type_info *base = 0;	// eg, a.base.base_cpp_mem
	for (;;) {
	  octave_value_list subname_ovl(*idx_it++);
	  ++skip;
	  assert(subname_ovl.length() == 1 && subname_ovl(0).is_string());
	  subname = subname_ovl(0).string_value();

	  const swig_type_info *next_base = find_base(subname, base);
	  if (!next_base || skip >= (int) ops.size() || ops[skip] != '.')
	    break;
	  base = next_base;
	}

	member_value_pair tmp, *m = &tmp;
	if (!base || !(m->first = find_member(base, subname)))
	  m = find_member(subname, false);
	if (!m) {
	  error("member not found");
	  return octave_value_list();
	}

	octave_value_list args;
	if (!always_static &&
	    (!m->first || (!m->first->is_static() && !m->first->is_global())))
	  args.append(as_value());
	if (skip < (int) ops.size() && ops[skip] == '(' && 
	    ((m->first && m->first->method) || m->second.is_function() || 
	     m->second.is_function_handle())) {
	  args.append(*idx_it++);
	  ++skip;
	  sub_ovl = member_invoke(m, args, nargout);
	} else {
	  sub_ovl = member_deref(m, args);
	}
      }
      // index operator
      else {
	if (ops[skip] == '(' || ops[skip] == '{') {
	  const char *op_name = ops[skip] == '(' ? "__paren" : "__brace";
	  octave_value_list args;
	  args.append(*idx_it++);
	  ++skip;
	  if (!dispatch_index_op(op_name, args, sub_ovl)) {
	    error("error evaluating index operator");
	    return octave_value_list();
	  }
	} else {
	  error("unsupported subsref");
	  return octave_value_list();
	}
      }

      if (skip >= (int) ops.size())
	return sub_ovl;
      if (sub_ovl.length() < 1) {
	error("bad subs ref");
	return octave_value_list();
      }
      return sub_ovl(0).next_subsref(nargout, ops, idx, skip);
    }

    octave_value subsasgn(const std::string &ops, const std::list < octave_value_list > &idx, const octave_value &rhs) {
      assert(ops.size() > 0);
      assert(ops.size() == idx.size());

      std::list < octave_value_list >::const_iterator idx_it = idx.begin();
      int skip = 0;

      if (ops.size() > 1) {
	std::list < octave_value_list >::const_iterator last = idx.end();
	--last;
	std::list < octave_value_list > next_idx(idx.begin(), last);
	octave_value next_ov = subsref(ops.substr(0, ops.size() - 1), next_idx);
	next_ov.subsasgn(ops.substr(ops.size() - 1), std::list < octave_value_list > (1, *last), rhs);
      }

      else if (ops[skip] == '(' || ops[skip] == '{') {
	const char *op_name = ops[skip] == '(' ? "__paren_asgn" : "__brace_asgn";
	member_value_pair *m = find_member(op_name, false);
	if (m) {
	  octave_value_list args;
	  args.append(as_value());
	  args.append(*idx_it);
	  args.append(rhs);
	  member_invoke(m, args, 1);
	} else
	  error("%s member not found", op_name);
      }

      else if (ops[skip] == '.') {
	octave_value_list subname_ovl(*idx_it++);
	++skip;
	assert(subname_ovl.length() == 1 &&subname_ovl(0).is_string());
	std::string subname = subname_ovl(0).string_value();

	member_value_pair *m = find_member(subname, true);
	if (!m->first || !m->first->set_method) {
	  m->first = 0;
	  m->second = rhs;
	} else if (m->first->set_method) {
	  octave_value_list args;
	  if (!m->first->is_static() && !m->first->is_global())
	    args.append(as_value());
	  args.append(rhs);
	  m->first->set_method(args, 1);
	} else
	  error("member not assignable");
      } else
	error("unsupported subsasgn");

      return as_value();
    }

    virtual bool is_string() const {
      octave_swig_type *nc_this = const_cast < octave_swig_type *>(this);
      return !!nc_this->find_member("__str", false);
    }

    virtual std::string string_value(bool force = false) const {
      octave_swig_type *nc_this = const_cast < octave_swig_type *>(this);
      member_value_pair *m = nc_this->find_member("__str", false);
      if (!m) {
	error("__str method not defined");
	return std::string();
      }
      octave_value_list outarg = nc_this->member_invoke(m, octave_value_list(nc_this->as_value()), 1);
      if (outarg.length() < 1 || !outarg(0).is_string()) {
	error("__str method did not return a string");
	return std::string();
      }
      return outarg(0).string_value();
    }

    /*
    virtual Octave_map map_value() const {
      octave_swig_type *nc_this = const_cast < octave_swig_type *>(this);
      member_value_pair *m = nc_this->find_member("__str", false);
      if (!m) {
	error("__map method not defined");
	return std::string();
      }
      octave_value_list outarg = nc_this->member_invoke(m, octave_value_list(nc_this->as_value()), 1);
      if (outarg.length() < 1 || !outarg(0).is_map()) {
	error("__map method did not return a string");
	return std::string();
      }
      return outarg(0).map_value();
    }
    */

    virtual string_vector map_keys() const {
      member_map tmp;
      load_members(tmp);

      string_vector keys(tmp.size());
      int k = 0;
      for (member_map::iterator it = tmp.begin(); it != tmp.end(); ++it)
	keys(k++) = it->first;

      return keys;
    }

    virtual octave_value convert_to_str(bool pad = false, bool force = false, char type = '"') const {
      return string_value();
    }

    virtual octave_value convert_to_str_internal(bool pad, bool force, char type) const {
      return string_value();
    }

    static bool dispatch_global_op(const std::string &symbol, const octave_value_list &args, octave_value &ret) {
      // we assume that "op_"-prefixed functions are installed in global namespace
      // (rather than any module namespace).

      octave_value fcn = get_global_value(symbol, true);
      if (!fcn.is_function() && !fcn.is_function_handle())
	return false;
      ret = fcn.subsref("(", std::list < octave_value_list > (1, args));
      return true;
    }

    static octave_value dispatch_unary_op(const octave_base_value &x, const char *op_name) {
      octave_swig_type *ost = Swig::swig_value_deref(x);
      assert(ost);

      octave_value ret;
      if (ost->dispatch_unary_op(std::string("__") + op_name, ret))
	return ret;
      std::string symbol = "op_" + ost->swig_type_name() + "_" + op_name;
      octave_value_list args;
      args.append(make_value_hack(x));
      if (dispatch_global_op(symbol, args, ret))
	return ret;

      error("could not dispatch unary operator");
      return octave_value();
    }

    static octave_value dispatch_binary_op(const octave_base_value &lhs, const octave_base_value &rhs, const char *op_name) {
      octave_swig_type *lhs_ost = Swig::swig_value_deref(lhs);
      octave_swig_type *rhs_ost = Swig::swig_value_deref(rhs);

      octave_value ret;
      if (lhs_ost && lhs_ost->dispatch_binary_op(std::string("__") + op_name, rhs, ret))
	return ret;

      std::string symbol;
      octave_value_list args;
      args.append(make_value_hack(lhs));
      args.append(make_value_hack(rhs));

      symbol = "op_";
      symbol += lhs_ost ? lhs_ost->swig_type_name() : lhs.type_name();
      symbol += "_";
      symbol += op_name;
      symbol += "_";
      symbol += rhs_ost ? rhs_ost->swig_type_name() : rhs.type_name();
      if (dispatch_global_op(symbol, args, ret))
	return ret;

      symbol = "op_";
      symbol += lhs_ost ? lhs_ost->swig_type_name() : lhs.type_name();
      symbol += "_";
      symbol += op_name;
      symbol += "_";
      symbol += "any";
      if (dispatch_global_op(symbol, args, ret))
	return ret;

      symbol = "op_";
      symbol += "any";
      symbol += "_";
      symbol += op_name;
      symbol += "_";
      symbol += rhs_ost ? rhs_ost->swig_type_name() : rhs.type_name();
      if (dispatch_global_op(symbol, args, ret))
	return ret;

      error("could not dispatch binary operator");
      return octave_value();
    }

    void print(std::ostream &os, bool pr_as_read_syntax = false) const {
      if (is_string()) {
	os << string_value();
	return;
      }

      member_map tmp;
      load_members(tmp);

      os << "{" << std::endl;
      for (unsigned int j = 0; j < types.size(); ++j) {
	if (types[j].first->clientdata) {
	  const swig_octave_class *c = (const swig_octave_class *) types[j].first->clientdata;
	  os << "  " << c->name << ", ptr = " << types[j].second.ptr << std::endl;
	} else {
	  os << "  " << types[j].first->name << ", ptr = " << types[j].second.ptr << std::endl;
	}
      }
      for (member_map::const_iterator it = tmp.begin(); it != tmp.end(); ++it) {
	if (it->second.first) {
	  const char *objtype = it->second.first->method ? "method" : "variable";
	  const char *modifier = (it->second.first->flags &1) ? "static " : (it->second.first->flags &2) ? "global " : "";
	  os << "  " << it->second.first->name << " (" << modifier << objtype << ")" << std::endl;
	  assert(it->second.first->name == it->first);
	} else {
	  os << "  " << it->first << std::endl;
	}
      }
      os << "}" << std::endl;
    }
  };

  // Octave tries hard to preserve pass-by-value semantics. Eg, assignments
  // will call clone() via make_unique() if there is more than one outstanding 
  // reference to the lhs, and forces the clone's reference count to 1 
  // (so you can't just increment your own count and return this).
  //
  // One way to fix this (without modifying Octave) is to add a level of
  // indirection such that clone copies ref-counted pointer and we keep 
  // pass-by-ref semantics (which are more natural/expected for C++ bindings).
  //
  // Supporting both pass-by-{ref,value} and toggling via %feature/option 
  // might be nice.

  class octave_swig_ref:public octave_base_value {
    octave_swig_type *ptr;
  public:
    octave_swig_ref(octave_swig_type *_ptr = 0)
      :ptr(_ptr) { }

    ~octave_swig_ref()
      { if (ptr) ptr->decref(); }

    octave_swig_type *get_ptr() const
      { return ptr; }

    octave_base_value *clone() const
      { if (ptr) ptr->incref(); return new octave_swig_ref(ptr); }

    octave_base_value *empty_clone() const
      { return new octave_swig_ref(0); }

    bool is_defined() const
      { return ptr->is_defined(); }

    virtual bool is_map() const 
      { return ptr->is_map(); }

    virtual octave_value subsref(const std::string &ops, const std::list < octave_value_list > &idx) 
      { return ptr->subsref(ops, idx); }

    virtual octave_value_list subsref(const std::string &ops, const std::list < octave_value_list > &idx, int nargout)
      { return ptr->subsref(ops, idx, nargout); }

    octave_value subsasgn(const std::string &ops, const std::list < octave_value_list > &idx, const octave_value &rhs)
      { return ptr->subsasgn(ops, idx, rhs); }

    virtual bool is_string() const 
      { return ptr->is_string(); }

    virtual std::string string_value(bool force = false) const 
      { return ptr->string_value(force); }

    virtual string_vector map_keys() const
      { return ptr->map_keys(); }

    virtual octave_value convert_to_str(bool pad = false, bool force = false, char type = '"') const
      { return ptr->convert_to_str(pad, force, type); }

    virtual octave_value convert_to_str_internal(bool pad, bool force, char type) const
      { return ptr->convert_to_str_internal(pad, force, type); }

    void print(std::ostream &os, bool pr_as_read_syntax = false) const
      { return ptr->print(os, pr_as_read_syntax); }

  private:
    DECLARE_OCTAVE_ALLOCATOR;
    DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA;
  };
  DEFINE_OCTAVE_ALLOCATOR(octave_swig_ref);
  DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(octave_swig_ref, "swig_ref", "swig_ref");

  class octave_swig_packed:public octave_base_value {
    swig_type_info *type;
    std::vector < char > buf;
  public:

    octave_swig_packed(swig_type_info *_type = 0, const void *_buf = 0, size_t _buf_len = 0)
      :	type(_type), buf((const char*)_buf, (const char*)_buf + _buf_len) {
    }

    bool copy(swig_type_info *outtype, void *ptr, size_t sz) const {
      if (outtype && outtype != type)
	return false;
      assert(sz <= buf.size());
      std::copy(buf.begin(), buf.begin()+sz, (char*)ptr);
      return true;
    }

    octave_base_value *clone() const {
      return new octave_swig_packed(*this);
    }

    octave_base_value *empty_clone() const {
      return new octave_swig_packed();
    }

    bool is_defined() const {
      return true;
    }

    void print(std::ostream &os, bool pr_as_read_syntax = false) const {
      os << "swig packed type: name = " << (type ? type->name : std::string()) << ", len = " << buf.size() << std::endl;
    }
  private:
    DECLARE_OCTAVE_ALLOCATOR;
    DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA;
  };
  DEFINE_OCTAVE_ALLOCATOR(octave_swig_packed);
  DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(octave_swig_packed, "swig_packed", "swig_packed");

  static octave_value_list octave_set_immutable(const octave_value_list &args, int nargout) {
    error("attempt to set immutable member variable");
    return octave_value_list();
  }

  struct octave_value_ref {
    const octave_value_list &ovl;
    int j;

    octave_value_ref(const octave_value_list &_ovl, int _j)
      :ovl(_ovl), j(_j) { }

    operator  octave_value() const {
      return ovl(j);
    }

    octave_value operator*() const {
      return ovl(j);
    }
  };

  octave_value_list swig_subclass(const octave_value_list &args, int nargout) {
    octave_swig_type *top = new octave_swig_type;
    for (int j = 0; j < args.length(); ++j) {
      if (args(j).type_id() == octave_swig_ref::static_type_id()) {
	octave_swig_ref *osr = static_cast < octave_swig_ref *>(args(j).internal_rep());
	octave_swig_type *ost = osr->get_ptr();
	if (!ost->is_owned()) {
	  error("cannot subclass object not constructed on octave side");
	  return octave_value_list();
	}
	top->merge(*ost);
      } else if (args(j).is_function_handle()) {
	top->assign(args(j).fcn_handle_value()->fcn_name(), args(j));
      } else if (args(j).is_string()) {
	if (j + 1 >= args.length()) {
	  error("member assignments must be of string,value form");
	  return octave_value_list();
	}
	top->assign(args(j).string_value(), args(j + 1));
	++j;
      } else {
	error("invalid arguments to subclass");
	return octave_value_list();
      }
    }
    return octave_value(Swig::swig_value_ref(top));
  }

  octave_value_list swig_type(const octave_value_list &args, int nargout) {
    if (args.length() != 1) {
      error("swig_typeinfo must be called with only a single object");
      return octave_value_list();
    }
    octave_swig_type *ost = Swig::swig_value_deref(args(0));
    if (!ost) {
      error("object is not a swig_ref");
      return octave_value_list();
    }
    return octave_value(ost->swig_type_name());
  }

  octave_value_list swig_typequery(const octave_value_list &args, int nargout) {
    if (args.length() != 1 || !args(0).is_string()) {
      error("swig_typeinfo must be called with single string argument");
      return octave_value_list();
    }
    swig_module_info *module = SWIG_GetModule(0);
    swig_type_info *type = SWIG_TypeQueryModule(module, module, args(0).string_value().c_str());
    if (!type)
      return octave_value("<unknown>");
    return octave_value(type->name);
  }

  octave_value_list swig_this(const octave_value_list &args, int nargout) {
    if (args.length() != 1) {
      error("swig_typeinfo must be called with only a single object");
      return octave_value_list();
    }
    if (args(0).is_matrix_type() && args(0).rows() == 0 && args(0).columns() == 0)
      return octave_value(octave_uint64(0));
    octave_swig_type *ost = Swig::swig_value_deref(args(0));
    if (!ost) {
      error("object is not a swig_ref");
      return octave_value_list();
    }
    return octave_value(octave_uint64((unsigned long long) ost->swig_this()));
  }

#define SWIG_DIRECTORS

namespace Swig {
  class Director {
    octave_swig_type *self;
    bool disowned;

    Director(const Director &x);
    Director &operator=(const Director &rhs);
  public:

    Director(void *vptr):self(0), disowned(false) {
      set_rtdir(vptr, this);
    }

    ~Director() {
      swig_director_destroyed(self, this);
      if (disowned)
	self->decref();
    }

    void swig_set_self(octave_swig_type *new_self) {
      assert(!disowned);
      self = new_self;
    }

    octave_swig_type *swig_get_self() const {
      return self;
    }

    void swig_disown() {
      if (disowned)
	return;
      disowned = true;
      self->incref();
    }
  };

  struct DirectorTypeMismatchException {
    static void raise(const char *msg) {
      // ... todo
      throw(DirectorTypeMismatchException());
    }

    static void raise(const octave_value &ov, const char *msg) {
      // ... todo
      raise(msg);
    }
  };
  struct DirectorPureVirtualException {
    static void raise(const char *msg) {
      // ... todo
      throw(DirectorPureVirtualException());
    }

    static void raise(const octave_value &ov, const char *msg) {
      // ... todo
      raise(msg);
    }
  };

}

  SWIGRUNTIME void swig_acquire_ownership(void *vptr) {
    //  assert(0);
    // ... todo
  }

  SWIGRUNTIME void swig_acquire_ownership_array(void *vptr) {
    //  assert(0);
    // ... todo
  }

  SWIGRUNTIME void swig_acquire_ownership_obj(void *vptr, int own) {
    //  assert(0);
    // ... todo
  }

  namespace Swig {
    SWIGRUNTIME void swig_director_destroyed(octave_swig_type *self, Director *d) {
      self->director_destroyed(d);
    }

    SWIGRUNTIME void swig_director_set_self(Director *d, octave_swig_type *self) {
      d->swig_set_self(self);
    }

    SWIGRUNTIME octave_base_value *swig_value_ref(octave_swig_type *ost) {
      return new octave_swig_ref(ost);
    }

    SWIGRUNTIME octave_swig_type *swig_value_deref(octave_value ov) {
      if (ov.is_cell() && ov.rows() == 1 && ov.columns() == 1)
	ov = ov.cell_value()(0);
      return swig_value_deref(*ov.internal_rep());
    }

    SWIGRUNTIME octave_swig_type *swig_value_deref(const octave_base_value &ov) {
      if (ov.type_id() != octave_swig_ref::static_type_id())
	return 0;
      const octave_swig_ref *osr = static_cast < const octave_swig_ref *>(&ov);
      return osr->get_ptr();
    }

  }

#define swig_unary_op(name) \
SWIGRUNTIME octave_value swig_unary_op_##name(const octave_base_value &x) { \
  return octave_swig_type::dispatch_unary_op(x,#name); \
}
#define swig_binary_op(name) \
SWIGRUNTIME octave_value swig_binary_op_##name(const octave_base_value&lhs,const octave_base_value &rhs) { \
  return octave_swig_type::dispatch_binary_op(lhs,rhs,#name); \
}
#define swigreg_unary_op(name) \
if (!octave_value_typeinfo::lookup_unary_op(octave_value::op_##name,tid)) \
octave_value_typeinfo::register_unary_op(octave_value::op_##name,tid,swig_unary_op_##name);
#define swigreg_binary_op(name) \
if (!octave_value_typeinfo::lookup_binary_op(octave_value::op_##name,tid1,tid2)) \
octave_value_typeinfo::register_binary_op(octave_value::op_##name,tid1,tid2,swig_binary_op_##name);

  swig_unary_op(not);
  swig_unary_op(uplus);
  swig_unary_op(uminus);
  swig_unary_op(transpose);
  swig_unary_op(hermitian);
  swig_unary_op(incr);
  swig_unary_op(decr);

  swig_binary_op(add);
  swig_binary_op(sub);
  swig_binary_op(mul);
  swig_binary_op(div);
  swig_binary_op(pow);
  swig_binary_op(ldiv);
  swig_binary_op(lshift);
  swig_binary_op(rshift);
  swig_binary_op(lt);
  swig_binary_op(le);
  swig_binary_op(eq);
  swig_binary_op(ge);
  swig_binary_op(gt);
  swig_binary_op(ne);
  swig_binary_op(el_mul);
  swig_binary_op(el_div);
  swig_binary_op(el_pow);
  swig_binary_op(el_ldiv);
  swig_binary_op(el_and);
  swig_binary_op(el_or);

  SWIGRUNTIME void SWIG_InstallUnaryOps(int tid) {
    swigreg_unary_op(not);
    swigreg_unary_op(uplus);
    swigreg_unary_op(uminus);
    swigreg_unary_op(transpose);
    swigreg_unary_op(hermitian);
    swigreg_unary_op(incr);
    swigreg_unary_op(decr);
  }
  SWIGRUNTIME void SWIG_InstallBinaryOps(int tid1, int tid2) {
    swigreg_binary_op(add);
    swigreg_binary_op(sub);
    swigreg_binary_op(mul);
    swigreg_binary_op(div);
    swigreg_binary_op(pow);
    swigreg_binary_op(ldiv);
    swigreg_binary_op(lshift);
    swigreg_binary_op(rshift);
    swigreg_binary_op(lt);
    swigreg_binary_op(le);
    swigreg_binary_op(eq);
    swigreg_binary_op(ge);
    swigreg_binary_op(gt);
    swigreg_binary_op(ne);
    swigreg_binary_op(el_mul);
    swigreg_binary_op(el_div);
    swigreg_binary_op(el_pow);
    swigreg_binary_op(el_ldiv);
    swigreg_binary_op(el_and);
    swigreg_binary_op(el_or);
  }
  SWIGRUNTIME void SWIG_InstallOps(int tid) {
    // here we assume that tid are conseq integers increasing from zero, and 
    // that our tid is the last one. might be better to have explicit string 
    // list of types we should bind to, and use lookup_type to resolve their tid.

    SWIG_InstallUnaryOps(tid);
    SWIG_InstallBinaryOps(tid, tid);
    for (int j = 0; j < tid; ++j) {
      SWIG_InstallBinaryOps(j, tid);
      SWIG_InstallBinaryOps(tid, j);
    }
  }

SWIGRUNTIME octave_value SWIG_Octave_NewPointerObj(void *ptr, swig_type_info *type, int flags) {
  int own = (flags &SWIG_POINTER_OWN) ? SWIG_POINTER_OWN : 0;

  Swig::Director *d = Swig::get_rtdir(ptr);
  if (d && d->swig_get_self())
    return d->swig_get_self()->as_value();
  return Swig::swig_value_ref(new octave_swig_type(ptr, type, own));
}

SWIGRUNTIME int SWIG_Octave_ConvertPtrAndOwn(octave_value ov, void **ptr, swig_type_info *type, int flags, int *own) {
  if (ov.is_cell() && ov.rows() == 1 && ov.columns() == 1)
    ov = ov.cell_value()(0);
  if (!ov.is_defined() ||
      (ov.is_matrix_type() && ov.rows() == 0 && ov.columns() == 0) ) {
    if (ptr)
      *ptr = 0;
    return SWIG_OK;
  }
  if (ov.type_id() != octave_swig_ref::static_type_id())
    return SWIG_ERROR;
  octave_swig_ref *osr = static_cast < octave_swig_ref *>(ov.internal_rep());
  octave_swig_type *ost = osr->get_ptr();
  void *vptr = ost->cast(type, own, flags);
  if (!vptr)
    return SWIG_ERROR;
  if (ptr)
    *ptr = vptr;
  return SWIG_OK;
}

SWIGRUNTIME octave_value SWIG_Octave_NewPackedObj(void *ptr, size_t sz, swig_type_info *type) {
  return new octave_swig_packed(type, (char *) ptr, sz);
}

SWIGRUNTIME int SWIG_Octave_ConvertPacked(const octave_value &ov, void *ptr, size_t sz, swig_type_info *type) {
  if (!ov.is_defined())
    return SWIG_ERROR;
  if (ov.type_id() != octave_swig_packed::static_type_id())
    return SWIG_ERROR;
  octave_swig_packed *ost = static_cast < octave_swig_packed *>(ov.internal_rep());
  return ost->copy(type, (char *) ptr, sz) ? SWIG_OK : SWIG_ERROR;
}

void SWIG_Octave_SetConstant(octave_swig_type *module_ns, const std::string &name, const octave_value &ov) {
  module_ns->assign(name, ov);
}

SWIGRUNTIME swig_module_info *SWIG_Octave_GetModule(void *clientdata) {
  octave_value ov = get_global_value("__SWIG_MODULE__" SWIG_TYPE_TABLE_NAME SWIG_RUNTIME_VERSION, true);
  if (!ov.is_defined() ||
      ov.type_id() != octave_swig_packed::static_type_id())
    return 0;
  const octave_swig_packed* osp = 
    static_cast < const octave_swig_packed *> (ov.internal_rep());
  swig_module_info *pointer = 0;
  osp->copy(0, &pointer, sizeof(swig_module_info *));
  return pointer;
}

SWIGRUNTIME void SWIG_Octave_SetModule(void *clientdata, swig_module_info *pointer) {
  octave_value ov = new octave_swig_packed(0, &pointer, sizeof(swig_module_info *));
  const char *module_var = "__SWIG_MODULE__" SWIG_TYPE_TABLE_NAME SWIG_RUNTIME_VERSION;
  link_to_global_variable(curr_sym_tab->lookup(module_var, true));
  set_global_value(module_var, ov);
}
