/* Copyright (c) 1997-2010
   Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Darmstadt, Germany)
   http://www.polymake.de

   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2, or (at your option) any
   later version: http://www.gnu.org/licenses/gpl.txt.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
--------------------------------------------------------------------------------
   $Project: polymake $$Id: glue.h 9718 2010-07-08 13:32:42Z gawrilow $
*/

#ifndef _POLYMAKE_PERL_GLUE_H
#define _POLYMAKE_PERL_GLUE_H

#ifdef __cplusplus
class SV { void *sv_any; unsigned int sv_refcnt, flags; protected: SV(); ~SV(); };

typedef SV HV;

#include <typeinfo>

namespace pm { namespace perl {
   typedef std::type_info typeinfo;
#else
   typedef struct typeinfo typeinfo;
   typedef enum value_flags value_flags;
   typedef enum number_flags number_flags;
   typedef enum class_kind class_kind;
#endif

   enum number_flags { not_a_number, number_is_int, number_is_float, number_is_object };

   enum class_kind {
      class_is_scalar, class_is_container, class_is_composite, class_is_opaque, class_is_kind_mask=0xf,
      class_is_assoc_container=0x100, class_is_sparse_container=0x200, class_is_set=0x400,
      class_is_serializable=0x800, class_is_declared=0x1000
   };
   enum value_flags {
      value_read_only=1, value_expect_lval=2, value_alloc_magic=4,
      value_allow_undef=8, value_allow_non_persistent=16, value_ignore_magic=32,
      value_trusted=0, value_not_trusted=64
   };

   typedef SV* (*wrapper_type)(SV**, char*);
   typedef SV* (*indirect_wrapper_type)(void*, SV**, char*);
   typedef void (*destructor_type)(char*);
   typedef SV* (*copy_constructor_type)(void*, const char*);
   typedef SV* (*assignment_type)(char*, SV*, value_flags);
   typedef SV* (*conv_to_SV_type)(const char*, const char*);
   typedef int (*conv_to_int_type)(const char*);
   typedef double (*conv_to_double_type)(const char*);
   typedef SV* (*container_resize_type)(char*, int);
   typedef SV* (*container_begin_type)(void*, char*);
   typedef SV* (*container_access_type)(char*, char*, int, SV*, const char*);
   typedef SV* (*container_store_type)(char*, char*, int, SV*);
   typedef SV* (*composite_access_type)(char*, SV*, const char*);
   typedef SV* (*iterator_deref_type)(const char*, const char*);
   typedef SV* (*iterator_incr_type)(char*);
   typedef SV* (*provide_type)();

   struct cached_cv {
      const char *name;
      SV *addr;
   };

#ifdef __cplusplus
extern "C" {
#else
typedef struct cached_cv cached_cv;
#endif

   SV *pm_perl_errsv();
   SV* pm_perl_newSV();
   SV* pm_perl_newSVstr_shared(const char *s, int l);
   SV* pm_perl_newSVstri_shared(const char *s, int l, int i);
   SV* pm_perl_new_ref(SV *sv, int noincr);
   SV* pm_perl_incr_SV(SV *sv);
   void pm_perl_decr_SV(SV *sv);
   SV* pm_perl_2mortal(SV *sv);
   number_flags pm_perl_number_flags(SV *sv);
   int pm_perl_int_value(SV *sv);
   double pm_perl_float_value(SV *sv);
   int pm_perl_object_int_value(SV *sv);
   double pm_perl_object_float_value(SV *sv);
   int pm_perl_is_true(SV *sv);
   int pm_perl_is_defined(SV *sv);
   SV* pm_perl_undef();
   SV* pm_perl_TRUE();
   SV* pm_perl_FALSE();
   int pm_perl_is_plain_text(SV *sv);
   const char* pm_perl_string_value(SV *sv);
   char* pm_perl_get_string_value(SV *sv, size_t *lp);
   char* pm_perl_get_string_value_nolen(SV *sv);
   void pm_perl_set_int_value(SV *dst, int x);
   void pm_perl_set_bool_value(SV *dst, int x);
   void pm_perl_set_float_value(SV *dst, double x);
   void pm_perl_set_undef(SV *dst);
   void pm_perl_set_copy(SV *dst, SV *src);
   void pm_perl_set_string_value(SV *dst, const char *p, size_t l);
   void pm_perl_set_string_value_nolen(SV *dst, const char *p);
   void pm_perl_append_string_value(SV *dst, const char *p, size_t l);
   void pm_perl_set_utf8_flag(SV *dst);
   void pm_perl_store_int_lvalue(SV *dst, SV *descr_ref, int x, const char *xp, int flags);
   void pm_perl_store_float_lvalue(SV *dst, SV *descr_ref, double x, const char *xp, int flags);
   void pm_perl_store_string_lvalue(SV *dst, SV *descr_ref, const char *p, size_t l, const char *xp, int flags);
   SV* pm_perl_init_ref(SV* src);
   void pm_perl_copy_ref(SV* src, SV **dstp);
   char* pm_perl_grow_string(SV *sv, size_t l);
   size_t pm_perl_get_cur_length(SV *sv);
   size_t pm_perl_get_cur_alloc(SV *sv);
   void pm_perl_set_cur_length(SV *sv, size_t l);
   int pm_perl_is_object_reference(SV *sv);
   int pm_perl_equal_refs(SV *r1, SV *r2);
   SV* pm_perl_deref(SV *sv);
   SV* pm_perl_yield_ref(SV *sv);
   SV* pm_perl_copy(SV *sv);
   SV* pm_perl_newAV(int prealloc);
   void pm_perl_makeAV(SV *sv, int prealloc);
   int pm_perl_is_AV_reference(SV *avref);
   int pm_perl_AV_size(SV *avref);
   void pm_perl_AV_resize(SV *avref, int n);
   SV** pm_perl_AV_fetch(SV *avref, int i);
   SV* pm_perl_AV_shift(SV *avref);
   SV* pm_perl_AV_pop(SV *avref);
   void pm_perl_AV_unshift(SV *avref, SV *sv);
   void pm_perl_AV_push(SV *avref, SV *sv);
   int pm_perl_get_sparse_dim(SV *avref, int *has_sparse_representation);
   SV* pm_perl_newHV();
   int pm_perl_is_HV_reference(SV *avref);
   SV* pm_perl_app_pkg_fetch(const char *key, size_t klen);
   SV* pm_perl_HV_fetch(SV *hvref, const char *key, size_t klen, int create);
   int pm_perl_HV_exists(SV *hvref, const char *key, size_t klen);
   HV* pm_perl_lookup_class_in_app(const char *name, size_t l);
   SV* pm_perl_lookup_sub_in_class(HV *stash, const char *name, size_t l);
   SV** pm_perl_start_funcall();
   SV** pm_perl_start_funcall_intermediate(SV **sp);
   SV** pm_perl_push_arg(SV **sp, SV *sv);
   SV** pm_perl_push_string_arg(SV **sp, const char *p, size_t l);
   SV** pm_perl_push_ref2arg(SV **sp, SV *sv);
   SV** pm_perl_push_cur_app_pkg(SV **sp);
   SV** pm_perl_get_stack();
   void pm_perl_sync_stack(SV **sp);
   SV** pm_perl_extend_stack(SV **sp, int amount);
   void pm_perl_cancel_funcall();
   SV* pm_perl_call_func_scalar(SV **sp, cached_cv *cv);
   SV** pm_perl_call_func_scalar_intermediate(SV **sp, cached_cv *cv);
   int pm_perl_call_func_bool(SV **sp, cached_cv *cv, int boolean_check);
   int pm_perl_call_func_list(SV **sp, cached_cv *cv);
   int pm_perl_call_func_void(SV **sp, cached_cv *cv);
   SV* pm_perl_call_method_scalar(SV **sp, const char *method);
   SV** pm_perl_call_method_scalar_intermediate(SV **sp, const char *method);
   int pm_perl_call_method_list(SV **sp, const char *method);
   SV* pm_perl_pop_result(int last);

   SV*
   pm_perl_create_builtin_vtbl(const typeinfo *type,
			       size_t obj_size,
			       int primitive_lvalue,
			       copy_constructor_type copy_constructor,
 			       assignment_type assignment,
			       destructor_type destructor);
   SV*
   pm_perl_create_opaque_vtbl(const typeinfo *type,
			      size_t obj_size,
			      assignment_type assignment,
			      destructor_type destructor,
			      conv_to_SV_type to_string,
			      conv_to_SV_type to_serialized,
			      provide_type provide_serialized_type);
   SV*
   pm_perl_create_scalar_vtbl(const typeinfo *type,
			      size_t obj_size,
			      copy_constructor_type copy_constructor,
			      assignment_type assignment,
			      destructor_type destructor,
			      conv_to_SV_type to_string,
			      conv_to_SV_type to_serialized,
			      conv_to_int_type to_int,
			      conv_to_double_type to_double);
   SV*
   pm_perl_create_container_vtbl(const typeinfo *type,
				 size_t obj_size, int total_dimension, int own_dimension,
				 copy_constructor_type copy_constructor,
				 assignment_type assignment,
				 destructor_type destructor,
				 conv_to_SV_type to_string,
				 conv_to_int_type size,
				 container_resize_type resize,
				 container_store_type store_at_ref,
				 provide_type provide_key_type,
				 provide_type provide_value_type);
   void
   pm_perl_it_access_vtbl(SV *vtbl, int i,
			  size_t it_size, size_t cit_size,
			  destructor_type it_destructor,
			  destructor_type cit_destructor,
			  container_begin_type begin,
			  container_begin_type cbegin,
			  container_access_type deref,
			  container_access_type cderef);
   void
   pm_perl_random_access_vtbl(SV *vtbl,
			      container_access_type random,
			      container_access_type crandom);
   SV*
   pm_perl_create_iterator_vtbl(const typeinfo *type,
				size_t obj_size,
				copy_constructor_type copy_constructor,
				destructor_type destructor,
				iterator_deref_type deref,
				iterator_incr_type incr,
				conv_to_int_type at_end);
   SV*
   pm_perl_create_composite_vtbl(const typeinfo *type,
				 size_t obj_size, int obj_dimension,
				 copy_constructor_type copy_constructor,
				 assignment_type assignment,
				 destructor_type destructor,
				 conv_to_SV_type to_string,
				 provide_type provide_elem_types,
				 int n_elems,
				 void (*fill_gets)(void**));

   int pm_perl_register_func(wrapper_type wrapper, const char *sig, size_t siglen, const char *file, size_t filelen, int line,
			     SV *arg_types, void *func_ptr, const char *func_ptr_type);
   void pm_perl_register_disabled_func(const char *sig, size_t siglen, const char *file, size_t filelen, int line, SV *arg_types);
   void pm_perl_register_embedded_property_type(const char *name, size_t namelen,
						wrapper_type wrapper, const char *file, size_t filelen);
   SV* pm_perl_register_class(const char *name, size_t namelen, const char *file, size_t filelen, int line, SV *someref,
			      const char *typeid_name, const char *const_typeid_name, int is_mutable,
			      class_kind kind, SV *vtbl_sv);
   SV* pm_perl_register_builtin(const char *name, size_t namelen, const char *file, size_t filelen, int line,
				const char *typeid_name, SV *vtbl);
   void pm_perl_register_class_template(const char *name, size_t namelen);
   void pm_perl_add_rules(const char *file, int line, const char *text, size_t l);
   void pm_perl_add_rules_v(const char *file, int line, const char *text, ...);

   const typeinfo* pm_perl_get_cpp_typeinfo(SV *sv);
   const char* pm_perl_get_forbidden_type(SV *sv);
   char* pm_perl_get_cpp_value(SV *sv);
   int pm_perl_get_cpp_dim(SV *sv, int tell_size_if_dense);

   wrapper_type pm_perl_get_assignment_operator(SV *src, SV *dst_descr);
   wrapper_type pm_perl_get_conversion_operator(SV *src, SV *dst_descr);
   wrapper_type pm_perl_get_conversion_constructor(SV *src, SV *dst_descr);
   SV* pm_perl_lookup_cpp_type(const char* typeid_name);
   void pm_perl_increase_nesting_level();
   SV* pm_perl_TypeDescr2Proto(SV *descr);
   SV* pm_perl_Proto2TypeDescr(SV *proto);

   int pm_perl_allow_magic_storage(SV *proto);
   void pm_perl_bless_to_proto(SV *val, SV *proto);
   void* pm_perl_new_cpp_value(SV *sv, SV *descr_ref, int flags);
   void pm_perl_share_cpp_value(SV *sv, SV *descr_ref, void *obj, SV *anchor, int flags);

   void pm_perl_throw(const char *msg);

   SV* pm_perl_name_of_ret_var();

   extern int pm_perl_Object_name_index, pm_perl_Object_description_index,
              pm_perl_Object_parent_index, pm_perl_Object_transaction_index, pm_perl_Object_attachments_index;

#ifdef __cplusplus
} } }
#endif

#endif // _POLYMAKE_PERL_GLUE_H
