| /******************************************
  Mosel NI Examples
  =================
    
  File complex.c
  ``````````````
  Example module defining a new type
    complex
  with the corresponding arithmetic operators.
  (c) 2022 Fair Isaac Corporation
      author: Y. Colombani, 2002
*******************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#define XPRM_NICOMPAT 6000000   /* Compatibility level: Mosel 6.0.0 */
#include "xprm_ni.h"
#ifdef _WIN32
#define snprintf _snprintf
#endif
/**** Function prototypes ****/
static int xritrinit(XPRMcontext ctx,void *libctx);
static int xritrnext(XPRMcontext ctx,void *libctx);
static int cx_new0(XPRMcontext ctx,void *libctx);
static int cx_new1r(XPRMcontext ctx,void *libctx);
static int cx_new1i(XPRMcontext ctx,void *libctx);
static int cx_new2(XPRMcontext ctx,void *libctx);
static int cx_zero(XPRMcontext ctx,void *libctx);
static int cx_one(XPRMcontext ctx,void *libctx);
static int cx_imin(XPRMcontext ctx,void *libctx);
static int cx_imax(XPRMcontext ctx,void *libctx);
static int cx_asgn(XPRMcontext ctx,void *libctx);
static int cx_asgn_r(XPRMcontext ctx,void *libctx);
static int cx_pls(XPRMcontext ctx,void *libctx);
static int cx_pls_r(XPRMcontext ctx,void *libctx);
static int cx_neg(XPRMcontext ctx,void *libctx);
static int cx_mul(XPRMcontext ctx,void *libctx);
static int cx_mul_r(XPRMcontext ctx,void *libctx);
static int cx_div(XPRMcontext ctx,void *libctx);
static int cx_div_r1(XPRMcontext ctx,void *libctx);
static int cx_div_r2(XPRMcontext ctx,void *libctx);
static int cx_eql_r(XPRMcontext ctx,void *libctx);
static int cx_getim(XPRMcontext ctx,void *libctx);
static int cx_getre(XPRMcontext ctx,void *libctx);
static int cx_setim(XPRMcontext ctx,void *libctx);
static int cx_setre(XPRMcontext ctx,void *libctx);
static int cx_tostr(XPRMcontext ctx,void *,void *,char *,int,int);
static int cx_fromstr(XPRMcontext ctx,void *libctx,void *toinit,const char *str,int,const char **endptr);
static int cx_copy(XPRMcontext ctx,void *libctx,void *toinit,void *src,int typnum);
static int cx_compare(XPRMcontext ctx,void *libctx,void *c1,void *c2,int typnum);
static void *cx_create(XPRMcontext ctx,void *,void *,int);
static void cx_delete(XPRMcontext ctx,void *,void *,int);
static void *cx_reset(XPRMcontext ctx,void *libctx,int version);
static size_t cx_memuse(XPRMcontext ctx,void *libctx,void *ref,int code);
static int cx_getarrind(XPRMcontext ctx,void*libctx,void *itr,int cde,XPRMarray arr,int *indices,int op);
static void *reo_create(XPRMcontext ctx,void *,void *,int);
static void reo_delete(XPRMcontext ctx,void *,void *,int);
static int reo_reset(XPRMcontext ctx,void *libctx,void *toreset,void *src,int ust);
/**** Structures for passing info to Mosel ****/
/* Subroutines */
static XPRMdsofct tabfct[]=
        {
         {"@&",1000,XPRM_TYP_EXTN,1,"complex:|complex|",cx_new0},
         {"@&I",1001,XPRM_TYP_EXTN,1,"complex:r",cx_new1r},
         {"@&I",1002,XPRM_TYP_EXTN,1,"complex:i",cx_new1i},
         {"@&",1003,XPRM_TYP_EXTN,2,"complex:rr",cx_new2},
         {"@0",1004,XPRM_TYP_EXTN,0,"complex:",cx_zero},
         {"@1",1005,XPRM_TYP_EXTN,0,"complex:",cx_one},
         {"@2",1006,XPRM_TYP_EXTN,0,"complex:",cx_imin},
         {"@3",1007,XPRM_TYP_EXTN,0,"complex:",cx_imax},
         {"@:",1008,XPRM_TYP_NOT,2,"|complex||complex|",cx_asgn},
         {"@:",1009,XPRM_TYP_NOT,2,"|complex|r",cx_asgn_r},
         {"@+",1010,XPRM_TYP_EXTN,2,"complex:|complex||complex|",cx_pls},
         {"@+",1011,XPRM_TYP_EXTN,2,"complex:|complex|r",cx_pls_r},
         {"@*",1012,XPRM_TYP_EXTN,2,"complex:|complex||complex|",cx_mul},
         {"@*",1013,XPRM_TYP_EXTN,2,"complex:|complex|r",cx_mul_r},
         {"@-",1014,XPRM_TYP_EXTN,1,"complex:|complex|",cx_neg},
         {"@/",1015,XPRM_TYP_EXTN,2,"complex:|complex||complex|",cx_div},
         {"@/",1016,XPRM_TYP_EXTN,2,"complex:|complex|r",cx_div_r1},
         {"@/",1017,XPRM_TYP_EXTN,2,"complex:r|complex|",cx_div_r2},
         {"@=",1018,XPRM_TYP_BOOL,2,"|complex|r",cx_eql_r},
         {"getim",1050,XPRM_TYP_REAL,1,"|complex|",cx_getim},
         {"getre",1051,XPRM_TYP_REAL,1,"|complex|",cx_getre},
         {"setim",1052,XPRM_TYP_NOT,2,"|complex|r",cx_setim},
         {"setre",1053,XPRM_TYP_NOT,2,"|complex|r",cx_setre},
         {"initenum",1100,XPRM_TYP_NOT,2,"|realonly|a",xritrinit},
         {"nextreal",1103,XPRM_TYP_BOOL,1,"|realonly|",xritrnext}
        };
/* Types */
static XPRMdsotyp tabtyp[]=
        {
         {"complex",1,XPRM_DTYP_PNCTX|XPRM_DTYP_RFCNT|XPRM_DTYP_APPND|XPRM_DTYP_SHARE|XPRM_DTYP_TFBIN|XPRM_DTYP_ORD|XPRM_DTYP_CONST,cx_create,cx_delete,cx_tostr,cx_fromstr,cx_copy,cx_compare},
         {"realonly",2,XPRM_DTYP_RFCNT|XPRM_DTYP_ANDX|XPRM_DTYP_ORSET,reo_create,reo_delete,NULL,NULL,reo_reset}
        };
/* Services */
static XPRMdsoserv tabserv[]=
        {
         {XPRM_SRV_RESET,(void *)cx_reset},
         {XPRM_SRV_MEMUSE,(void *)cx_memuse},
         {XPRM_SRV_ARRIND,(void*)cx_getarrind}
        };
/* Interface structure */
static XPRMdsointer dsointer= 
        { 
         0,NULL,
         sizeof(tabfct)/sizeof(XPRMdsofct),tabfct,
         sizeof(tabtyp)/sizeof(XPRMdsotyp),tabtyp,
         sizeof(tabserv)/sizeof(XPRMdsoserv),tabserv
        };
/**** Structures used by this module ****/
static XPRMnifct mm;             /* For storing Mosel NI function table */
#define CX_SHARED (1<<29)       /* Marker for a shared complex number */
#define CX_CONST  (1<<30)       /* Marker for a constant complex number */
typedef struct                  /* Where we store a complex number */
        {
         unsigned int refcnt;   /* For reference count and shared flag */
         double re,im;
        } s_complex;
#define MAXITNDX 5              /* Maximum number of indices for an iterator */
#define ITR_READY  1            /* Stopped on a valid cell */
#define ITR_END    2            /* Enumeration finished */
typedef struct
        {
         unsigned int refcnt;
         unsigned short nbdim;
         unsigned short status;
         XPRMarray reftab;
         int indices[MAXITNDX];
        } s_realonly;
/************************************************/
/* Initialize the library just after loading it */
/************************************************/
DSO_INIT complex_init(XPRMnifct nifct, int *interver,int *libver, XPRMdsointer **interf)
{
 mm=nifct;                      /* Save the table of Mosel NI functions */
 *interver=XPRM_NIVERS;         /* The interface version we are using */
 *libver=XPRM_MKVER(0,0,1);     /* The version of the module: 0.0.1 */
 *interf=&dsointer;             /* Our interface */
 return 0;
}
/******** Functions implementing the operators ********/
/*****************************/
/* Initialise an enumeration */
/*****************************/
static int xritrinit(XPRMcontext ctx,void *libctx)
{
 XPRMarray tab;
 s_realonly *itr;
 int nbdim;
 itr=XPRM_POP_REF(ctx);
 tab=XPRM_POP_REF(ctx);
 if(itr==NULL)
 {
  mm->dispmsg(ctx,"Complex: Trying to access an uninitialized realonly.\n");
  return XPRM_RT_ERROR;
 }
 else
 if(tab==NULL)
 {
  mm->dispmsg(ctx,"Complex: Trying to access an uninitialized array.\n");
  return XPRM_RT_ERROR;
 }
 else
 if((nbdim=mm->getarrdim(tab))>MAXITNDX)
 {
  mm->dispmsg(ctx,"Complex: Too many array dimensions for a realonly.\n");
  return XPRM_RT_ERROR;
 }
 else
 {
  if(itr->reftab!=tab)
  {
   reo_reset(ctx,libctx,itr,NULL,0);
   itr->reftab=mm->newref(ctx,XPRM_STR_ARR,tab);
   itr->nbdim=nbdim;
  }
  itr->status=0;
  return RT_OK;
 }
}
/****************************************************/
/* Advance to the next cell containing a real value */
/****************************************************/
static int xritrnext(XPRMcontext ctx,void *libctx)
{
 s_realonly *itr;
 s_complex *cx;
 int cont;
 itr=XPRM_TOP_ST(ctx)->ref;
 if(itr==NULL)
 {
  mm->dispmsg(ctx,"Complex: Trying to access an uninitialized realonly.\n");
  return XPRM_RT_ERROR;
 }
 else
 if(itr->reftab==NULL)
 {
  mm->dispmsg(ctx,"Complex: Realonly not associated to any array.\n");
  return XPRM_RT_ERROR;
 }
 else
 {
  if(itr->status==ITR_END)
   XPRM_TOP_ST(ctx)->integer=0;
  else
  {
   if(itr->status==0)
   {
    itr->status=ITR_READY;
    cont=!mm->getfirstarrtruentry(itr->reftab,itr->indices);
   }
   else
    cont=!mm->getnextarrtruentry(itr->reftab,itr->indices);
   while(cont)
   {
    mm->getarrval(itr->reftab,itr->indices,&cx);
    if(cx->im==0)
     break;
    else
     cont=!mm->getnextarrtruentry(itr->reftab,itr->indices);
   }
   if(!cont)
   {
    itr->status=ITR_END;
    XPRM_TOP_ST(ctx)->integer=0;
   }
   else
    XPRM_TOP_ST(ctx)->integer=1;
  }
  return XPRM_RT_OK;
 }
}
/*******************/
/* Clone a complex */
/*******************/
static int cx_new0(XPRMcontext ctx,void *libctx)
{
 s_complex *complex,*new_complex;
 complex=XPRM_POP_REF(ctx);
 if(complex!=NULL)
 {
  new_complex=cx_create(ctx,libctx,NULL,0);
  new_complex->im=complex->im;
  new_complex->re=complex->re;
  XPRM_PUSH_REF(ctx,new_complex);
 }
 else
  XPRM_PUSH_REF(ctx,NULL);
 return XPRM_RT_OK;
}
/********************************/
/* Create a complex from a real */
/********************************/
static int cx_new1r(XPRMcontext ctx,void *libctx)
{
 s_complex *complex;
 complex=cx_create(ctx,libctx,NULL,0);
 complex->re=XPRM_POP_REAL(ctx);
 XPRM_PUSH_REF(ctx,complex);
 return XPRM_RT_OK;
}
/************************************/
/* Create a complex from an integer */
/************************************/
static int cx_new1i(XPRMcontext ctx,void *libctx)
{
 s_complex *complex;
 complex=cx_create(ctx,libctx,NULL,0);
 complex->re=XPRM_POP_INT(ctx);
 XPRM_PUSH_REF(ctx,complex);
 return XPRM_RT_OK;
}
/***********************************/
/* Create a complex from two reals */
/***********************************/
static int cx_new2(XPRMcontext ctx,void *libctx)
{
 s_complex *complex;
 complex=cx_create(ctx,libctx,NULL,0);
 complex->re=XPRM_POP_REAL(ctx);
 complex->im=XPRM_POP_REAL(ctx);
 XPRM_PUSH_REF(ctx,complex);
 return XPRM_RT_OK;
}
/**********************************************/
/* Zero in complex (used to initialise `sum') */
/**********************************************/
static int cx_zero(XPRMcontext ctx,void *libctx)
{
 XPRM_PUSH_REF(ctx,cx_create(ctx,libctx,NULL,0));
 return XPRM_RT_OK;
}
/**********************************************/
/* One in complex (used to initialise `prod') */
/**********************************************/
static int cx_one(XPRMcontext ctx,void *libctx)
{
 s_complex *complex;
 complex=cx_create(ctx,libctx,NULL,0);
 complex->re=1;
 XPRM_PUSH_REF(ctx,complex);
 return XPRM_RT_OK;
}
/******************************************/
/* Initial value for the 'min' aggregator */
/******************************************/
static int cx_imin(XPRMcontext ctx,void *libctx)
{
 s_complex *complex;
 complex=cx_create(ctx,libctx,NULL,0);
 complex->re=complex->im=INFINITY;
 XPRM_PUSH_REF(ctx,complex);
 return XPRM_RT_OK;
}
/******************************************/
/* Initial value for the 'max' aggregator */
/******************************************/
static int cx_imax(XPRMcontext ctx,void *libctx)
{
 s_complex *complex;
 complex=cx_create(ctx,libctx,NULL,0);
 complex->re=complex->im=-INFINITY;
 XPRM_PUSH_REF(ctx,complex);
 return XPRM_RT_OK;
}
/*******************************/
/* Assignment complex:=complex */
/*******************************/
static int cx_asgn(XPRMcontext ctx,void *libctx)
{
 s_complex *c1,*c2;
 c1=XPRM_POP_REF(ctx);
 c2=XPRM_POP_REF(ctx);
 if(c1==NULL)
 {
  mm->dispmsg(ctx,"Complex: Trying to access an uninitialized complex.\n");
  return RT_ERROR;
 }
 else
 if(c1->refcnt&CX_CONST)
 {
  mm->dispmsg(ctx,"Complex: Trying to modify a constant.\n");
  return RT_ERROR;
 }
 else
 if(c2==NULL)
 {
  c1->im=c1->re=0;
  return RT_OK;
 }
 else
 {
  c1->im=c2->im;
  c1->re=c2->re;
  cx_delete(ctx,libctx,c2,0);
  return XPRM_RT_OK;
 }
}
/****************************/
/* Assignment complex:=real */
/****************************/
static int cx_asgn_r(XPRMcontext ctx,void *libctx)
{
 s_complex *c1;
 c1=XPRM_POP_REF(ctx);
 if(c1==NULL)
 {
  mm->dispmsg(ctx,"Complex: Trying to access an uninitialized complex.\n");
  return RT_ERROR;
 }
 else
 if(c1->refcnt&CX_CONST)
 {
  mm->dispmsg(ctx,"Complex: Trying to modify a constant.\n");
  return RT_ERROR;
 }
 else
 {
  c1->re=XPRM_POP_REAL(ctx);
  c1->im=0;
  return XPRM_RT_OK;
 }
}
/***************************************/
/* Addition complex+complex -> complex */
/***************************************/
static int cx_pls(XPRMcontext ctx,void *libctx)
{
 s_complex *c1,*c2;
 c1=XPRM_POP_REF(ctx);
 c2=XPRM_POP_REF(ctx);
 if(c1!=NULL)
 {
  if(c2!=NULL)
  {
   c1->re+=c2->re;
   c1->im+=c2->im;
   cx_delete(ctx,libctx,c2,0);
  }
  XPRM_PUSH_REF(ctx,c1);
 }
 else
  XPRM_PUSH_REF(ctx,c2);
 return XPRM_RT_OK;
}
/************************************/
/* Addition complex+real -> complex */
/************************************/
static int cx_pls_r(XPRMcontext ctx,void *libctx)
{
 s_complex *c1;
 c1=XPRM_POP_REF(ctx);
 if(c1!=NULL)
 {
  c1->re+=XPRM_POP_REAL(ctx);
  XPRM_PUSH_REF(ctx,c1);
  return XPRM_RT_OK;
 }
 else
  return cx_new1r(ctx,libctx);
}
/**************************************/
/* Change of sign complex -> -complex */
/**************************************/
static int cx_neg(XPRMcontext ctx,void *libctx)
{
 s_complex *c1;
 c1=XPRM_POP_REF(ctx);
 if(c1!=NULL)
 {
  c1->re=-c1->re;
  c1->im=-c1->im;
 }
 XPRM_PUSH_REF(ctx,c1);
 return XPRM_RT_OK;
}
/**************************************/
/* Product complex*complex -> complex */
/**************************************/
static int cx_mul(XPRMcontext ctx,void *libctx)
{
 s_complex *c1,*c2;
 double re,im;
 c1=XPRM_POP_REF(ctx);
 c2=XPRM_POP_REF(ctx);
 if(c1!=NULL)
 {
  if(c2!=NULL)
  {
   re=c1->re*c2->re-c1->im*c2->im;
   im=c1->re*c2->im+c1->im*c2->re;
   c1->re=re;
   c1->im=im;
  }
  else
   c1->re=c2->im=0;
 }
 cx_delete(ctx,libctx,c2,0);
 XPRM_PUSH_REF(ctx,c1);
 return XPRM_RT_OK;
}
/***********************************/
/* Product complex*real -> complex */
/***********************************/
static int cx_mul_r(XPRMcontext ctx,void *libctx)
{
 s_complex *c1;
 double r;
 c1=XPRM_POP_REF(ctx);
 r=XPRM_POP_REAL(ctx);
 if(c1!=NULL)
 {
  c1->re*=r;
  c1->im*=r;
 }
 XPRM_PUSH_REF(ctx,c1);
 return XPRM_RT_OK;
}
/***************************************/
/* Division complex/complex -> complex */
/***************************************/
static int cx_div(XPRMcontext ctx,void *libctx)
{
 s_complex *c1,*c2;
 double re,im;
 c1=XPRM_POP_REF(ctx);
 c2=XPRM_POP_REF(ctx);
 if((c2==NULL)||((c2->re==0)&&(c2->im==0)))
 {
  mm->dispmsg(ctx,"Complex: Division by 0.");
  return XPRM_RT_ERROR;
 }
 else
 {
  if(c1!=NULL)
  {                             /* Compute 1/c2 then c1* 1/c2 */
   re=c2->re/(c2->re*c2->re+c2->im*c2->im);
   im=-c2->im/(c2->re*c2->re+c2->im*c2->im);
   c2->re=re;
   c2->im=im;
   XPRM_PUSH_REF(ctx,c2);
   XPRM_PUSH_REF(ctx,c1);
   return cx_mul(ctx,libctx);
  }
  else
  {
   cx_delete(ctx,libctx,c2,0);
   XPRM_PUSH_REF(ctx,c1);
   return XPRM_RT_OK;
  }
 }
}
/************************************/
/* Division complex/real -> complex */
/************************************/
static int cx_div_r1(XPRMcontext ctx,void *libctx)
{
 s_complex *c1;
 double r;
 c1=XPRM_POP_REF(ctx);
 r=XPRM_POP_REAL(ctx);
 if(r==0)
 {
  mm->dispmsg(ctx,"Complex: Division by 0.");
  return XPRM_RT_ERROR;
 }
 else
 {
  if(c1!=NULL)
  {
   c1->re/=r;
   c1->im/=r;
  }
  XPRM_PUSH_REF(ctx,c1);
  return XPRM_RT_OK;
 }
}
/************************************/
/* Division real/complex -> complex */
/************************************/
static int cx_div_r2(XPRMcontext ctx,void *libctx)
{
 s_complex *c1;
 double r,re,im;
 r=XPRM_POP_REAL(ctx);
 c1=XPRM_POP_REF(ctx);
 if((c1==NULL)||((c1->re==0)&&(c1->im==0)))
 {
  mm->dispmsg(ctx,"Complex: Division by 0.");
  return XPRM_RT_ERROR;
 }
 else
 {
  re=(c1->re*r)/(c1->re*c1->re+c1->im*c1->im);
  im=-(c1->im*r)/(c1->re*c1->re+c1->im*c1->im);
  c1->re=re;
  c1->im=im;
  XPRM_PUSH_REF(ctx,c1);
  return XPRM_RT_OK;
 }
}
/***************************/
/* Comparison complex=real */
/***************************/
static int cx_eql_r(XPRMcontext ctx,void *libctx)
{
 s_complex *c1;
 double r;
 int b;
 c1=XPRM_POP_REF(ctx);
 r=XPRM_POP_REAL(ctx);
 if(c1!=NULL)
  b=(c1->im==0)&&(c1->re==r);
 else
  b=(r==0);
 XPRM_PUSH_INT(ctx,b);
 return XPRM_RT_OK;
}
/***********************************/
/* Get imaginary part of a complex */
/***********************************/
static int cx_getim(XPRMcontext ctx,void *libctx)
{
 s_complex *c1;
 c1=XPRM_POP_REF(ctx);
 if(c1!=NULL)
  XPRM_PUSH_REAL(ctx,c1->im);
 else
  XPRM_PUSH_REAL(ctx,0);
 return RT_OK;
}
/******************************/
/* Get real part of a complex */
/******************************/
static int cx_getre(XPRMcontext ctx,void *libctx)
{
 s_complex *c1;
 c1=XPRM_POP_REF(ctx);
 if(c1!=NULL)
  XPRM_PUSH_REAL(ctx,c1->re);
 else
  XPRM_PUSH_REAL(ctx,0);
 return RT_OK;
}
/***********************************/
/* Set imaginary part of a complex */
/***********************************/
static int cx_setim(XPRMcontext ctx,void *libctx)
{
 s_complex *c1;
 double im;
 c1=XPRM_POP_REF(ctx);
 im=XPRM_POP_REAL(ctx);
 if(c1==NULL)
 {
  mm->dispmsg(ctx,"Complex: Trying to access an uninitialized complex.\n");
  return RT_ERROR;
 }
 else
 {
  c1->im=im;
  return RT_OK;
 }
}
/******************************/
/* Set real part of a complex */
/******************************/
static int cx_setre(XPRMcontext ctx,void *libctx)
{
 s_complex *c1;
 double re;
 c1=XPRM_POP_REF(ctx);
 re=XPRM_POP_REAL(ctx);
 if(c1==NULL)
 {
  mm->dispmsg(ctx,"Complex: Trying to access an uninitialized complex.\n");
  return RT_ERROR;
 }
 else
 {
  c1->re=re;
  return RT_OK;
 }
}
/**************** Type-related functions ****************/
/*****************************/
/* Allocate a complex number */
/*****************************/
static void *cx_create(XPRMcontext ctx,void *libctx,void *todup,int typnum)
{
 s_complex *complex;
 if((todup!=NULL)&&(XPRM_CREATE(typnum)==XPRM_CREATE_NEW))
 {
  /* Do not update the reference count if the object is shared */
  /* the global entity will be cleared when the model is reset */
  /* Note that this example is not complete: the implementation should */
  /* guarantee that concurrent access to a given shared object does not */
  /* corrupt the datastructure using e.g. critical sections */
  if((((s_complex *)todup)->refcnt&CX_SHARED)==0)
   ((s_complex *)todup)->refcnt++;
  return todup;
 }
 else
 {
  complex=mm->memalloc(ctx,sizeof(s_complex),0);
  if(XPRM_CREATE(typnum)==XPRM_CREATE_CST)
  {
   complex->re=((s_complex *)todup)->re;
   complex->im=((s_complex *)todup)->im;
   complex->refcnt=1|CX_CONST;
  }
  else
  {
   complex->re=complex->im=0;
   complex->refcnt=1;
   /* Tag a shared complex number to disable reference counting */
   if(XPRM_CREATE(typnum)==XPRM_CREATE_SHR)
    complex->refcnt|=CX_SHARED;
  }
  return complex;
 }
}
/*******************************/
/* Deallocate a complex number */
/*******************************/
static void cx_delete(XPRMcontext ctx,void *libctx,void *todel,int typnum)
{
 if((todel!=NULL)&&((((s_complex *)todel)->refcnt&CX_SHARED)==0)&&
    (((--((s_complex *)todel)->refcnt)&~CX_CONST)<1))
 {
  mm->memfree(ctx,todel,sizeof(s_complex));
 }
}
/*********************/
/* Complex -> String */
/*********************/
static int cx_tostr(XPRMcontext ctx,void *libctx,void *toprt,char *str,int len,int typnum)
{
 s_complex *c;
 if(typnum&XPRM_TFSTR_BIN)
 {
  if(len>=2*sizeof(double))
  {
   c=toprt;
   if(toprt==NULL)
    memset(str,0,2*sizeof(double));
   else
   {
    /* We assume that all supported platforms are little endian */
    memcpy(str,&(c->re),sizeof(double));
    memcpy(str+sizeof(double),&(c->im),sizeof(double));
   }
  }
  return 2*sizeof(double);
 }
 else
 if(toprt==NULL)
 {
  strncpy(str,"0+0i",len);
  return 4;
 }
 else
 {
  c=toprt;
  return snprintf(str,len,"%g%+gi",c->re,c->im);
 }
}
/*********************/
/* String -> Complex */
/*********************/
static int cx_fromstr(XPRMcontext ctx,void *libctx,void *toinit,const char *str,int typnum,const char **endptr)
{
 double re,im;
 s_complex *c;
 int len;
 struct Info
 {
  char dummy[4];
  s_complex *c;
 } *ref;
 c=toinit;
 if(c->refcnt&CX_CONST)
 {
  mm->dispmsg(ctx,"Complex: Trying to modify a constant.\n");
  return XPRM_RT_ERROR;
 }
 else
 if(typnum&XPRM_TFSTR_BIN)
 {
  if(*endptr-str!=2*sizeof(double))
   return XPRM_RT_ERROR;
  else
  {
   /* We assume that all supported platforms are little endian */
   memcpy(&(c->re),str,sizeof(double));
   memcpy(&(c->im),str+sizeof(double),sizeof(double));
   return RT_OK;
  }
 }
 else
 if((str[0]=='r') && (str[1]=='a') && (str[2]=='w') && (str[3]=='\0'))
 {
  if(endptr!=NULL) *endptr=NULL;
  ref=(struct Info *)str;
  if(ref->c==NULL)
   c->re=c->im=0;
  else
  {
   c->re=ref->c->re;
   c->im=ref->c->im;
  }
  return XPRM_RT_OK;
 }
 else
  if(sscanf(str,"%lf%lf%ni%n",&re,&im,&len,&len)<2)
  {
   if(endptr!=NULL) *endptr=str;
   return XPRM_RT_ERROR;
  }
  else
  {
   if(endptr!=NULL) *endptr=str+len;
   c->re=re;
   c->im=im;
   return XPRM_RT_OK;
  }
}
/******************/
/* Copy a complex */
/******************/
static int cx_copy(XPRMcontext ctx,void *libctx,void *toinit,void *src,int typnum)
{
 s_complex *c_dst;
 c_dst=(s_complex *)toinit;
 switch(XPRM_CPY(typnum))
 {
  case XPRM_CPY_COPY:
  case XPRM_CPY_RESET:
      if(c_dst->refcnt&CX_CONST)
       return 1;
      else
      if(src!=NULL)
      {
       c_dst->re=((s_complex *)src)->re;
       c_dst->im=((s_complex *)src)->im;
       return 0;
      }
      else
      {
       c_dst->re=0;
       c_dst->im=0;
       return 0;
      }
  case XPRM_CPY_APPEND:
      if(src!=NULL)
      {
       c_dst->re+=((s_complex *)src)->re;
       c_dst->im+=((s_complex *)src)->im;
      }
      return 0;
  case XPRM_CPY_HASH:
      {
       unsigned int hv;
       if(src==NULL)
       {
        double z=0;
        hv=mm->hashmix(ctx,0,&z,sizeof(double));
        *(unsigned int *)toinit=mm->hashmix(ctx,hv,&z,sizeof(double));
       }
       else
       {
        hv=mm->hashmix(ctx,0,&(((s_complex*)src)->re),sizeof(double));
        *(unsigned int *)toinit=mm->hashmix(ctx,hv,&(((s_complex*)src)->im),sizeof(double));
       }
       return 0;
      }
  default:
      return 1;
 }
}
/****************************/
/* Compare 2 complex values */
/****************************/
static int cx_compare(XPRMcontext ctx,void *libctx,void *r1,void *r2,int typnum)
{
 static const s_complex cstzero;
 const s_complex *c1,*c2;
 c1=(r1==NULL)?&cstzero:r1;
 c2=(r2==NULL)?&cstzero:r2;
 
 switch(XPRM_COMPARE(typnum))
 {
  case XPRM_COMPARE_EQ:
    return (c1->re==c2->re)&&(c1->im==c2->im);
  case XPRM_COMPARE_NEQ:
    return (c1->re!=c2->re)||(c1->im!=c2->im);
  case XPRM_COMPARE_LTH:
    return (c1->re<c2->re)||((c1->re==c2->re)&&(c1->im<c2->im));
  case XPRM_COMPARE_LEQ:
    return (c1->re<c2->re)||((c1->re==c2->re)&&(c1->im<=c2->im));
  case XPRM_COMPARE_GEQ:
    return (c1->re>c2->re)||((c1->re==c2->re)&&(c1->im>=c2->im));
  case XPRM_COMPARE_GTH:
    return (c1->re>c2->re)||((c1->re==c2->re)&&(c1->im>c2->im));
  case XPRM_COMPARE_CMP:
    if(c1->re==c2->re)
    {
     if(c1->im==c2->im)
      return 0;
     else
      return (c1->im<c2->im)?-1:1;
    }
    else
     return (c1->re<c2->re)?-1:1;
  default:
    return XPRM_COMPARE_ERROR;
 }
}
/**************** Iterator 'realonly' ***************/
/***********************/
/* Allocate a realonly */
/***********************/
static void *reo_create(XPRMcontext ctx,void *libctx,void *todup,int typnum)
{
 if(todup!=NULL)
 {
  ((s_realonly *)todup)->refcnt++;
  return todup;
 }
 else
 {
  s_realonly *itr;
  itr=mm->memalloc(ctx,sizeof(s_realonly),1);
  itr->refcnt=1;
  return itr;
 }
}
/**********************/
/* Release a realonly */
/**********************/
static void reo_delete(XPRMcontext ctx,void *libctx,void *todel,int typnum)
{
 if((todel!=NULL)&&((--((s_realonly *)todel)->refcnt)<1))
 {
  reo_reset(ctx,libctx,todel,NULL,0);
  mm->memfree(ctx,todel,sizeof(s_realonly));
 }
}
/********************/
/* Reset a realonly */
/********************/
static int reo_reset(XPRMcontext ctx,void *libctx,void *toreset,void *src,int ust)
{
 s_realonly *itr=toreset;
 if(itr!=NULL)
 {
  if(itr->reftab!=NULL)
  {
   mm->delref(ctx,XPRM_STR_ARR,itr->reftab);
   itr->reftab=NULL;
  }
  memset(itr->indices,0,sizeof(int)*MAXITNDX);
  itr->nbdim=0;
  itr->status=0;
 }
 return 0;
}
/******************** Services ********************/
/**************************************/
/* Reset the Complex module for a run */
/**************************************/
/* Dummy context to enable 'memoryuse' */
static void *cx_reset(XPRMcontext ctx,void *libctx,int version)
{
 if(libctx==NULL)               /* libctx==NULL => initialisation */
  return (void*)1l;
 else
  return NULL;
}
/*****************************/
/* Memory used by the module */
/*****************************/
static size_t cx_memuse(XPRMcontext ctx,void *libctx,void *ref,int code)
{
 switch(code)
 {
  case 0:
    return 0;
  case 1:
    return sizeof(s_complex);
  default:
    return -1;
 }
}
/*******************************************/
/* Extract the index tuple from a realonly */
/*******************************************/
static int cx_getarrind(XPRMcontext ctx,void*libctx,void *x,int cde,XPRMarray arr,int *indices,int op)
{
 s_realonly *itr;
 itr=x;
 if(itr==NULL)
 {
  mm->dispmsg(ctx,"Complex: Trying to access an uninitialized realonly.\n");
  return -1;
 }
 else
 if(itr->reftab==NULL)
 {
  mm->dispmsg(ctx,"Complex: Realonly not associated to any array.\n");
  return -1;
 }
 else
 if(arr!=itr->reftab)
 {
  mm->dispmsg(ctx,"Complex: Invalid array reference for a realonly.\n");
  return -1;
 }
 else
 if(itr->status!=ITR_READY)
 {
  if(op<=XPRM_OPNDX_DEL)
   return 1;
  else
  {
   mm->dispmsg(ctx,"Complex: Realonly in an invalid state.\n");
   return -1;
  }
 }
 else
 {
  memcpy(indices,itr->indices,itr->nbdim*sizeof(int));
  return 0;
 }
}
 |