stardis

Perform coupled heat transfer calculations
git clone git://git.meso-star.fr/stardis.git
Log | Files | Refs | README | LICENSE

commit 07105c9726f8146f972f6435bc67e1d1ac27cd0f
parent c58e6d34fb67f63bb4ed510e3bcd10688a4a6273
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Thu, 13 Feb 2020 15:16:05 +0100

Get rid of expressions in initial/boundary conditions

Diffstat:
Mcmake/CMakeLists.txt | 29+++--------------------------
Msrc/stardis-app.c | 4----
Msrc/stardis-app.h | 465++++++++++++++++++++++---------------------------------------------------------
Msrc/stardis-compute.c | 97+++++++++++++------------------------------------------------------------------
Msrc/stardis-compute.h | 16----------------
Msrc/stardis-fluid.c | 54+++++++++++-------------------------------------------
Msrc/stardis-fluid.h | 12+++++-------
Msrc/stardis-intface.c | 40++++++++++++----------------------------
Msrc/stardis-intface.h | 7+++----
Msrc/stardis-output.c | 15++++++++-------
Msrc/stardis-parsing.c | 80++++++++++++++++++++++++++++++++++++++-----------------------------------------
Msrc/stardis-solid.c | 78+++++++++++++++---------------------------------------------------------------
Msrc/stardis-solid.h | 17+++++++----------
Dtinyexpr/tinyexpr.c | 891-------------------------------------------------------------------------------
Dtinyexpr/tinyexpr.h | 197-------------------------------------------------------------------------------
15 files changed, 246 insertions(+), 1756 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -28,16 +28,12 @@ find_package(StarEnc3D 0.3.1 REQUIRED) find_package(Stardis 0.7.1 REQUIRED) find_package(StarSTL 0.3 REQUIRED) -set(TINYEXPR_SOURCE_DIR "${PROJECT_SOURCE_DIR}/../tinyexpr" - CACHE PATH "Directory for TinyExpr source files") - include_directories( ${RSys_INCLUDE_DIR} ${StarGeom3D_INCLUDE_DIR} ${StarEnc3D_INCLUDE_DIR} ${Stardis_INCLUDE_DIR} - ${StarSTL_INCLUDE_DIR} - ${TINYEXPR_SOURCE_DIR}) + ${StarSTL_INCLUDE_DIR}) if(MSVC) find_package(MuslGetopt REQUIRED) include_directories(${MuslGetopt_INCLUDE_DIR}) @@ -83,25 +79,6 @@ rcmake_prepend_path(SDIS_FILES_SRC ${SDIS_SOURCE_DIR}) rcmake_prepend_path(SDIS_FILES_INC ${SDIS_SOURCE_DIR}) rcmake_prepend_path(SDIS_FILES_DOC ${PROJECT_SOURCE_DIR}/../) -# Default is right to left pow and log is natural log -# Build tinyExpr without closure support and with function_1 to function_3 -# support only (these ones cannot be disabled as predefined functions require -# them). -set(TE_DEFAULTS - "-DTE_POW_FROM_RIGHT -DTE_NAT_LOG -DTE_WITHOUT_CLOSURES \ - -DTE_WITHOUT_FUNCTION_0 -DTE_MAX_FUNCTION_ARITY=3") - -ADD_LIBRARY(tinyexpr STATIC - ${TINYEXPR_SOURCE_DIR}/tinyexpr.c ${TINYEXPR_SOURCE_DIR}/tinyexpr.h) - -if(CMAKE_COMPILER_IS_GNUCC) - set_target_properties(tinyexpr PROPERTIES - COMPILE_FLAGS "-std=c99 ${TE_DEFAULTS}") -elseif(MSVC) - set_target_properties(tinyexpr PROPERTIES - COMPILE_FLAGS ${TE_DEFAULTS}) -endif() - add_executable(sdis-app ${SDIS_FILES_SRC} ${SDIS_FILES_INC}) @@ -111,13 +88,13 @@ if(CMAKE_COMPILER_IS_GNUCC) COMPILE_FLAGS "-std=c99 ${TE_DEFAULTS}" VERSION ${VERSION}) target_link_libraries(sdis-app - Stardis StarGeom3D StarEnc3D StarSTL RSys tinyexpr m) + Stardis StarGeom3D StarEnc3D StarSTL RSys m) elseif(MSVC) set_target_properties(sdis-app PROPERTIES COMPILE_FLAGS "${TE_DEFAULTS}" VERSION ${VERSION}) target_link_libraries(sdis-app - Stardis StarGeom3D StarEnc3D StarSTL RSys tinyexpr MuslGetopt) + Stardis StarGeom3D StarEnc3D StarSTL RSys MuslGetopt) endif() rcmake_copy_runtime_libraries(sdis-app) diff --git a/src/stardis-app.c b/src/stardis-app.c @@ -11,8 +11,6 @@ #define HTABLE_KEY_FUNCTOR_HASH hash_description #define HTABLE_KEY_FUNCTOR_INIT init_description #define HTABLE_KEY_FUNCTOR_COPY cp_description -#define HTABLE_KEY_FUNCTOR_RELEASE release_description -#define HTABLE_KEY_FUNCTOR_COPY_AND_RELEASE cp_release_description #include <rsys/hash_table.h> #include <string.h> @@ -498,8 +496,6 @@ stardis_release(struct stardis* stardis) } sa_release(stardis->geometry.interf_bytrg); stardis->geometry.interf_bytrg = NULL; - for (i=0; i<sa_size(stardis->descriptions); ++i) - release_description(stardis->descriptions + i); sa_release(stardis->descriptions); release_geometry(&stardis->geometry); sa_release(stardis->boundary.primitives); diff --git a/src/stardis-app.h b/src/stardis-app.h @@ -11,7 +11,6 @@ #include <rsys/stretchy_array.h> #include <rsys/hash_table.h> #include <sdis.h> -#include <tinyexpr.h> #include <limits.h> @@ -116,10 +115,10 @@ struct mat_fluid { unsigned fluid_id; double rho; double cp; - char* Tinit; - char* Temp; + double tinit; + double imposed_temperature; }; -#define NULL_FLUID__ { "", UINT_MAX, 0, 0, NULL, NULL } +#define NULL_FLUID__ { "", UINT_MAX, 0, 0, -1, -1 } static const struct mat_fluid NULL_FLUID = NULL_FLUID__; static void @@ -128,20 +127,19 @@ print_fluid(FILE* stream, const struct mat_fluid* f) ASSERT(stream && f); fprintf(stream, "Fluid '%s': cp=%g rho=%g", f->name, f->cp, f->rho); - if (f->Tinit) fprintf(stream, " Tinit='%s'", f->Tinit); - if (f->Temp) fprintf(stream, " Temp='%s'", f->Temp); + if (f->tinit >= 0) fprintf(stream, " Tinit=%f", f->tinit); + if (f->imposed_temperature >= 0) fprintf(stream, " Temp=%f", f->imposed_temperature); fprintf(stream, "\n"); -} +}static char -static char eq_fluid(const struct mat_fluid* a, const struct mat_fluid* b) { if (strcmp(a->name, b->name) || a->fluid_id != b->fluid_id || a->rho != b->rho || a->cp != b->cp - || strcmp(a->Tinit, b->Tinit) - || strcmp(a->Temp, b->Temp)) + || a->tinit != b->tinit + || a->imposed_temperature != b->imposed_temperature) return 0; return 1; } @@ -153,38 +151,8 @@ cp_fluid(struct mat_fluid* dst, const struct mat_fluid* src) dst->fluid_id = src->fluid_id; dst->rho = src->rho; dst->cp = src->cp; - if (!src->Tinit) dst->Tinit = NULL; - else { - dst->Tinit = malloc(sizeof(src->Tinit) + 1); - if (!dst->Tinit) return RES_MEM_ERR; - strcpy(dst->Tinit, src->Tinit); - } - if (!src->Temp) dst->Temp = NULL; - else { - dst->Temp = malloc(sizeof(src->Temp) + 1); - if (!dst->Temp) return RES_MEM_ERR; - strcpy(dst->Temp, src->Temp); - } - return RES_OK; -} - -static FINLINE res_T -cp_release_fluid(struct mat_fluid* dst, struct mat_fluid* src) -{ - strcpy(dst->name, src->name); - dst->fluid_id = src->fluid_id; - dst->rho = src->rho; - dst->cp = src->cp; - dst->Tinit = src->Tinit; src->Tinit = NULL; - dst->Temp = src->Temp; src->Temp = NULL; - return RES_OK; -} - -static FINLINE res_T -release_fluid(struct mat_fluid* a) -{ - free(a->Tinit); - free(a->Temp); + dst->tinit = src->tinit; + dst->imposed_temperature = src->imposed_temperature; return RES_OK; } @@ -193,8 +161,8 @@ hash_fluid(const struct mat_fluid* key) { /* 64-bits Fowler/Noll/Vo hash function */ const uint64_t FNV64_PRIME = - (uint64_t) (((uint64_t) 1 << 40) + ((uint64_t) 1 << 8) + 0xB3); - const uint64_t OFFSET64_BASIS = (uint64_t) 14695981039346656037u; + (uint64_t)(((uint64_t)1 << 40) + ((uint64_t)1 << 8) + 0xB3); + const uint64_t OFFSET64_BASIS = (uint64_t)14695981039346656037u; uint64_t hash = OFFSET64_BASIS; size_t i; ASSERT(key); @@ -207,23 +175,23 @@ hash_fluid(const struct mat_fluid* key) hash = hash * FNV64_PRIME; } FOR_EACH(i, 0, sizeof(key->rho)) { - hash = hash ^ (uint64_t) ((unsigned char)((const char*)&key->rho)[i]); + hash = hash ^ (uint64_t)((unsigned char)((const char*)&key->rho)[i]); hash = hash * FNV64_PRIME; } FOR_EACH(i, 0, sizeof(key->cp)) { hash = hash ^ (uint64_t)((unsigned char)((const char*)&key->cp)[i]); hash = hash * FNV64_PRIME; } - hash = hash ^ (uint64_t)((unsigned char)(key->Tinit == 0)); + hash = hash ^ (uint64_t)((unsigned char)(key->tinit == 0)); hash = hash * FNV64_PRIME; - FOR_EACH(i, 0, key->Tinit ? strlen(key->Tinit)*sizeof(*key->Tinit) : 0) { - hash = hash ^ (uint64_t)((unsigned char) ((const char*)key->Tinit)[i]); + FOR_EACH(i, 0, sizeof(key->tinit)) { + hash = hash ^ (uint64_t)((unsigned char)((const char*)&key->tinit)[i]); hash = hash * FNV64_PRIME; } - hash = hash ^ (uint64_t)((unsigned char)(key->Temp == 0)); + hash = hash ^ (uint64_t)((unsigned char)(key->imposed_temperature == 0)); hash = hash * FNV64_PRIME; - FOR_EACH(i, 0, key->Temp ? strlen(key->Temp) * sizeof(*key->Temp) : 0) { - hash = hash ^ (uint64_t)((unsigned char)((const char*)key->Temp)[i]); + FOR_EACH(i, 0, sizeof(key->imposed_temperature)) { + hash = hash ^ (uint64_t)((unsigned char)((const char*)&key->imposed_temperature)[i]); hash = hash * FNV64_PRIME; } return hash; @@ -236,12 +204,11 @@ struct mat_solid { double rho; double cp; double delta; - char* Tinit; - char* Temp; - char* power; - int has_power; + double tinit; + double imposed_temperature; + double vpower; }; -#define NULL_SOLID__ { "", UINT_MAX, 0, 0, 0, 0, NULL, NULL, NULL, 0} +#define NULL_SOLID__ { "", UINT_MAX, 0, 0, 0, 0, -1, -1, 0 } static const struct mat_solid NULL_SOLID = NULL_SOLID__; static void @@ -249,11 +216,11 @@ print_solid(FILE* stream, const struct mat_solid* s) { ASSERT(stream && s); fprintf(stream, - "Solid '%s': lambda=%g cp=%g rho=%g delta=%g Power='%s'", - s->name, s->lambda, s->cp, s->rho, s->delta, - (s->has_power ? s->power : "0")); - if (s->Tinit) fprintf(stream, " Tinit='%s'", s->Tinit); - if (s->Temp) fprintf(stream, " Temp='%s'", s->Temp); + "Solid '%s': lambda=%g cp=%g rho=%g delta=%g Power=%f", + s->name, s->lambda, s->cp, s->rho, s->delta, s->vpower); + if (s->tinit >= 0) fprintf(stream, " Tinit=%f", s->tinit); + if (s->imposed_temperature >= 0) + fprintf(stream, " Temp=%f", s->imposed_temperature); fprintf(stream, "\n"); } @@ -266,11 +233,9 @@ eq_solid(const struct mat_solid* a, const struct mat_solid* b) || a->rho != b->rho || a->cp != b->cp || a->delta != b->delta - || strcmp(a->Tinit, b->Tinit) - || strcmp(a->Temp, b->Temp) - || a->has_power != b->has_power) + || a->tinit != b->tinit + || a->imposed_temperature != b->imposed_temperature) return 0; - if (a->has_power && a->power != b->power) return 0; return 1; } @@ -283,50 +248,8 @@ cp_solid(struct mat_solid* dst, const struct mat_solid* src) dst->rho = src->rho; dst->cp = src->cp; dst->delta = src->delta; - if (!src->Tinit) dst->Tinit = NULL; - else { - dst->Tinit = malloc(sizeof(src->Tinit) + 1); - if (!dst->Tinit) return RES_MEM_ERR; - strcpy(dst->Tinit, src->Tinit); - } - if (!src->Temp) dst->Temp = NULL; - else { - dst->Temp = malloc(sizeof(src->Temp) + 1); - if (!dst->Temp) return RES_MEM_ERR; - strcpy(dst->Temp, src->Temp); - } - dst->has_power = src->has_power; - if (!src->power) dst->power = NULL; - else { - dst->power = malloc(sizeof(src->power) + 1); - if (!dst->power) return RES_MEM_ERR; - strcpy(dst->power, src->power); - } - return RES_OK; -} - -static FINLINE res_T -cp_release_solid(struct mat_solid* dst, struct mat_solid* src) -{ - strcpy(dst->name, src->name); - dst->solid_id = src->solid_id; - dst->lambda = src->lambda; - dst->rho = src->rho; - dst->cp = src->cp; - dst->delta = src->delta; - dst->Tinit = src->Tinit; src->Tinit = NULL; - dst->Temp = src->Temp; src->Temp = NULL; - dst->has_power = src->has_power; - dst->power = src->power; src->power = NULL; - return RES_OK; -} - -static FINLINE res_T -release_solid(struct mat_solid* a) -{ - free(a->power); - free(a->Tinit); - free(a->Temp); + dst->tinit = src->tinit; + dst->imposed_temperature = src->imposed_temperature; return RES_OK; } @@ -335,8 +258,8 @@ hash_solid(const struct mat_solid* key) { /* 64-bits Fowler/Noll/Vo hash function */ const uint64_t FNV64_PRIME = - (uint64_t) (((uint64_t) 1 << 40) + ((uint64_t) 1 << 8) + 0xB3); - const uint64_t OFFSET64_BASIS = (uint64_t) 14695981039346656037u; + (uint64_t)(((uint64_t)1 << 40) + ((uint64_t)1 << 8) + 0xB3); + const uint64_t OFFSET64_BASIS = (uint64_t)14695981039346656037u; uint64_t hash = OFFSET64_BASIS; size_t i; ASSERT(key); @@ -364,25 +287,21 @@ hash_solid(const struct mat_solid* key) hash = hash ^ (uint64_t)((unsigned char)((const char*)&key->delta)[i]); hash = hash * FNV64_PRIME; } - hash = hash ^ (uint64_t)((unsigned char)(key->Tinit == 0)); + hash = hash ^ (uint64_t)((unsigned char)(key->tinit == 0)); hash = hash * FNV64_PRIME; - FOR_EACH(i, 0, key->Tinit ? strlen(key->Tinit) * sizeof(*key->Tinit) : 0) { - hash = hash ^ (uint64_t)((unsigned char)((const char*)key->Tinit)[i]); + FOR_EACH(i, 0,sizeof(key->tinit)) { + hash = hash ^ (uint64_t)((unsigned char)((const char*)&key->tinit)[i]); hash = hash * FNV64_PRIME; } - hash = hash ^ (uint64_t)((unsigned char)(key->Temp == 0)); + hash = hash ^ (uint64_t)((unsigned char)(key->imposed_temperature == 0)); hash = hash * FNV64_PRIME; - FOR_EACH(i, 0, key->Temp ? strlen(key->Temp) * sizeof(*key->Temp) : 0) { - hash = hash ^ (uint64_t)((unsigned char)((const char*)key->Temp)[i]); - hash = hash * FNV64_PRIME; - } - FOR_EACH(i, 0, sizeof(key->has_power)) { - hash = hash ^ (uint64_t) ((unsigned char) ((const char*) &key->has_power)[i]); + FOR_EACH(i, 0, sizeof(key->imposed_temperature)) { + hash = hash ^ (uint64_t)((unsigned char) + ((const char*)&key->imposed_temperature)[i]); hash = hash * FNV64_PRIME; } - if (!key->has_power) return hash; - FOR_EACH(i, 0, strlen(key->power) * sizeof(*key->power)) { - hash = hash ^ (uint64_t)((unsigned char)((const char*)key->power)[i]); + FOR_EACH(i, 0, sizeof(key->vpower)) { + hash = hash ^ (uint64_t)((unsigned char)((const char*)&key->vpower)[i]); hash = hash * FNV64_PRIME; } return hash; @@ -395,10 +314,10 @@ struct h_boundary { double specular_fraction; double hc; double hc_max; - char* T; + double imposed_temperature; int has_emissivity, has_hc; }; -#define NULL_HBOUND__ { "", UINT_MAX, 0, 0, 0, 0, NULL, 0, 0} +#define NULL_HBOUND__ { "", UINT_MAX, 0, 0, 0, -1, 0, 0 } static const struct h_boundary NULL_HBOUND = NULL_HBOUND__; static void @@ -410,25 +329,23 @@ print_h_boundary ASSERT(stream && b && (type == DESC_BOUND_H_FOR_SOLID || type == DESC_BOUND_H_FOR_FLUID)); fprintf(stream, - "H boundary %s for %s: emissivity=%g specular_fraction=%g hc=%g hc_max=%g T='%s'\n", + "H boundary %s for %s: emissivity=%g specular_fraction=%g hc=%g hc_max=%g T=%f\n", b->name, (type == DESC_BOUND_H_FOR_SOLID ? "solid" : "fluid"), (b->has_emissivity ? b->emissivity : 0), (b->has_emissivity ? b->specular_fraction : 0), (b->has_hc ? b->hc : 0), (b->has_hc ? b->hc_max : 0), - (b->T ? b->T : "0")); + b->imposed_temperature); } static char -eq_h_boundary - (const struct h_boundary* a, - const struct h_boundary* b) +eq_h_boundary(const struct h_boundary* a, const struct h_boundary* b) { if (a->mat_id != b->mat_id || strcmp(a->name, b->name) || a->specular_fraction != b->specular_fraction - || strcmp(a->T, b->T) + || a->imposed_temperature != b->imposed_temperature || a->has_emissivity != b->has_emissivity || a->has_hc != b->has_hc) return 0; @@ -443,12 +360,7 @@ cp_h_boundary(struct h_boundary* dst, const struct h_boundary* src) strcpy(dst->name, src->name); dst->mat_id = src->mat_id; dst->specular_fraction = src->specular_fraction; - if (!src->T) dst->T = NULL; - else { - dst->T = malloc(sizeof(src->T) + 1); - if (!dst->T) return RES_MEM_ERR; - strcpy(dst->T, src->T); - } + dst->imposed_temperature = src->imposed_temperature; dst->has_emissivity = src->has_emissivity; dst->has_hc = src->has_hc; dst->emissivity = src->emissivity; @@ -457,35 +369,13 @@ cp_h_boundary(struct h_boundary* dst, const struct h_boundary* src) return RES_OK; } -static FINLINE res_T -cp_release_h_boundary(struct h_boundary* dst, struct h_boundary* src) -{ - strcpy(dst->name, src->name); - dst->mat_id = src->mat_id; - dst->specular_fraction = src->specular_fraction; - dst->T = src->T; src->T = NULL; - dst->has_emissivity = src->has_emissivity; - dst->has_hc = src->has_hc; - dst->emissivity = src->emissivity; - dst->hc_max = src->hc_max; - dst->hc = src->hc; - return RES_OK; -} - -static FINLINE res_T -release_h_boundary(struct h_boundary* a) -{ - free(a->T); - return RES_OK; -} - static size_t hash_h_boundary(const struct h_boundary* key) { /* 64-bits Fowler/Noll/Vo hash function */ const uint64_t FNV64_PRIME = - (uint64_t) (((uint64_t) 1 << 40) + ((uint64_t) 1 << 8) + 0xB3); - const uint64_t OFFSET64_BASIS = (uint64_t) 14695981039346656037u; + (uint64_t)(((uint64_t)1 << 40) + ((uint64_t)1 << 8) + 0xB3); + const uint64_t OFFSET64_BASIS = (uint64_t)14695981039346656037u; uint64_t hash = OFFSET64_BASIS; size_t i; ASSERT(key); @@ -502,11 +392,13 @@ hash_h_boundary(const struct h_boundary* key) hash = hash * FNV64_PRIME; } FOR_EACH(i, 0, sizeof(key->specular_fraction)) { - hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->specular_fraction)[i]); + hash = hash ^ (uint32_t)((unsigned char) + ((const char*)&key->specular_fraction)[i]); hash = hash * FNV64_PRIME; } - FOR_EACH(i, 0, strlen(key->T) * sizeof(*key->T)) { - hash = hash ^ (uint32_t)((unsigned char)((const char*)key->T)[i]); + FOR_EACH(i, 0, sizeof(key->imposed_temperature)) { + hash = hash ^ (uint32_t)((unsigned char) + ((const char*)&key->imposed_temperature)[i]); hash = hash * FNV64_PRIME; } FOR_EACH(i, 0, sizeof(key->has_emissivity)) { @@ -514,16 +406,16 @@ hash_h_boundary(const struct h_boundary* key) hash = hash * FNV64_PRIME; } FOR_EACH(i, 0, sizeof(key->has_hc)) { - hash = hash ^ (uint32_t) ((unsigned char) ((const char*) &key->has_hc)[i]); + hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->has_hc)[i]); hash = hash * FNV64_PRIME; } if (!key->has_hc) return hash; FOR_EACH(i, 0, sizeof(key->hc)) { - hash = hash ^ (uint32_t) ((unsigned char) ((const char*) &key->hc)[i]); + hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->hc)[i]); hash = hash * FNV64_PRIME; } FOR_EACH(i, 0, sizeof(key->hc_max)) { - hash = hash ^ (uint32_t) ((unsigned char) ((const char*) &key->hc_max)[i]); + hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->hc_max)[i]); hash = hash * FNV64_PRIME; } return hash; @@ -532,13 +424,12 @@ hash_h_boundary(const struct h_boundary* key) struct t_boundary { char name[32]; unsigned mat_id; - char* T; - struct te_expr* te_temperature; + double imposed_temperature; double hc; double hc_max; int has_hc; }; -#define NULL_TBOUND__ { "", UINT_MAX, NULL, NULL, 0, 0, 0} +#define NULL_TBOUND__ { "", UINT_MAX, -1, 0, 0, 0 } static const struct t_boundary NULL_TBOUND = NULL_TBOUND__; static void @@ -550,12 +441,12 @@ print_t_boundary ASSERT(stream && b && (type == DESC_BOUND_T_FOR_SOLID || type == DESC_BOUND_T_FOR_FLUID)); fprintf(stream, - "T boundary %s for %s: hc=%g hc_max=%g T='%s'\n", + "T boundary %s for %s: hc=%g hc_max=%g T=%f\n", b->name, (type == DESC_BOUND_T_FOR_SOLID ? "solid" : "fluid"), (b->has_hc ? b->hc : 0), (b->has_hc ? b->hc_max : 0), - (b->T ? b->T : "0")); + b->imposed_temperature); } static char @@ -568,7 +459,7 @@ eq_t_boundary /* These fields are meaningful by both types */ if (strcmp(a->name, b->name)) return 0; - if (a->mat_id != b->mat_id || strcmp(a->T, b->T)) + if (a->mat_id != b->mat_id || a->imposed_temperature != b->imposed_temperature) return 0; if (type != DESC_BOUND_T_FOR_FLUID) return 1; @@ -585,55 +476,24 @@ cp_t_boundary(struct t_boundary* dst, const struct t_boundary* src) { strcpy(dst->name, src->name); dst->mat_id = src->mat_id; - if (!src->T) dst->T = NULL; - else { - dst->T = malloc(sizeof(src->T) + 1); - if (!dst->T) return RES_MEM_ERR; - strcpy(dst->T, src->T); - } - dst->has_hc = src->has_hc; - dst->hc_max = src->hc_max; - dst->hc = src->hc; - if (!src->te_temperature) dst->te_temperature = NULL; - else { - dst->te_temperature = te_duplicate(src->te_temperature); - if (!dst->te_temperature) return RES_MEM_ERR; - } - return RES_OK; -} - -static FINLINE res_T -cp_release_t_boundary(struct t_boundary* dst, struct t_boundary* src) -{ - strcpy(dst->name, src->name); - dst->mat_id = src->mat_id; - dst->T = src->T; src->T = NULL; + dst->imposed_temperature = src->imposed_temperature; dst->has_hc = src->has_hc; dst->hc_max = src->hc_max; dst->hc = src->hc; - dst->te_temperature = src->te_temperature; src->te_temperature = NULL; - return RES_OK; -} - -static FINLINE res_T -release_t_boundary(struct t_boundary* a) -{ - free(a->T); - te_free(a->te_temperature); return RES_OK; } static size_t hash_t_boundary - (const struct t_boundary* key, - const enum description_type type) +(const struct t_boundary* key, + const enum description_type type) { (void)type; ASSERT(type == DESC_BOUND_T_FOR_SOLID || type == DESC_BOUND_T_FOR_FLUID); /* 64-bits Fowler/Noll/Vo hash function */ const uint64_t FNV64_PRIME = - (uint64_t) (((uint64_t) 1 << 40) + ((uint64_t) 1 << 8) + 0xB3); - const uint64_t OFFSET64_BASIS = (uint64_t) 14695981039346656037u; + (uint64_t)(((uint64_t)1 << 40) + ((uint64_t)1 << 8) + 0xB3); + const uint64_t OFFSET64_BASIS = (uint64_t)14695981039346656037u; uint64_t hash = OFFSET64_BASIS; size_t i; ASSERT(key); @@ -646,11 +506,12 @@ hash_t_boundary hash = hash * FNV64_PRIME; } FOR_EACH(i, 0, sizeof(key->has_hc)) { - hash = hash ^ (uint32_t) ((unsigned char) ((const char*) &key->has_hc)[i]); + hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->has_hc)[i]); hash = hash * FNV64_PRIME; } - FOR_EACH(i, 0, strlen(key->T) * sizeof(*key->T)) { - hash = hash ^ (uint32_t) ((unsigned char) ((const char*) key->T)[i]); + FOR_EACH(i, 0, sizeof(key->imposed_temperature)) { + hash = hash ^ (uint32_t)((unsigned char) + ((const char*)&key->imposed_temperature)[i]); hash = hash * FNV64_PRIME; } if (!key->has_hc) return hash; @@ -668,23 +529,21 @@ hash_t_boundary struct f_boundary { char name[32]; unsigned mat_id; - char* flux; - struct te_expr* te_flux; + double imposed_flux; }; -#define NULL_FBOUND__ { "", UINT_MAX, NULL, NULL} +#define NULL_FBOUND__ { "", UINT_MAX, SDIS_FLUX_NONE } static const struct f_boundary NULL_FBOUND = NULL_FBOUND__; static void print_f_boundary (FILE* stream, - const struct f_boundary* b, - const enum description_type type) + const struct f_boundary* b) { - ASSERT(stream && b && type == DESC_BOUND_F_FOR_SOLID); (void)type; + ASSERT(stream && b); fprintf(stream, - "F boundary %s for SOLID: flux='%s'\n", + "F boundary %s for SOLID: flux=%f\n", b->name, - (b->flux ? b->flux : "0")); + b->imposed_flux); } static char @@ -692,7 +551,7 @@ eq_f_boundary(const struct f_boundary* a, const struct f_boundary* b) { return (a->mat_id == b->mat_id && 0 == strcmp(a->name, b->name) - && 0 == strcmp(a->flux, b->flux)); + && a->imposed_flux == b->imposed_flux); } static FINLINE res_T @@ -700,36 +559,7 @@ cp_f_boundary(struct f_boundary* dst, const struct f_boundary* src) { strcpy(dst->name, src->name); dst->mat_id = src->mat_id; - if (!src->flux) dst->flux = NULL; - else { - dst->flux = malloc(sizeof(src->flux) + 1); - if (!dst->flux) return RES_MEM_ERR; - strcpy(dst->flux, src->flux); - } - if (!src->te_flux) dst->te_flux = NULL; - else { - dst->te_flux = te_duplicate(src->te_flux); - if (!dst->te_flux) return RES_MEM_ERR; - } - return RES_OK; -} - -static FINLINE res_T -cp_release_f_boundary(struct f_boundary* dst, struct f_boundary* src) -{ - strcpy(dst->name, src->name); - dst->mat_id = src->mat_id; - dst->flux = malloc(sizeof(src->flux) + 1); - dst->flux = src->flux; src->flux = NULL; - dst->te_flux = src->te_flux; src->te_flux = NULL; - return RES_OK; -} - -static FINLINE res_T -release_f_boundary(struct f_boundary* a) -{ - free(a->flux); - te_free(a->te_flux); + dst->imposed_flux = src->imposed_flux; return RES_OK; } @@ -738,8 +568,8 @@ hash_f_boundary(const struct f_boundary* key) { /* 64-bits Fowler/Noll/Vo hash function */ const uint64_t FNV64_PRIME = - (uint64_t) (((uint64_t) 1 << 40) + ((uint64_t) 1 << 8) + 0xB3); - const uint64_t OFFSET64_BASIS = (uint64_t) 14695981039346656037u; + (uint64_t)(((uint64_t)1 << 40) + ((uint64_t)1 << 8) + 0xB3); + const uint64_t OFFSET64_BASIS = (uint64_t)14695981039346656037u; uint64_t hash = OFFSET64_BASIS; size_t i; ASSERT(key); @@ -751,8 +581,8 @@ hash_f_boundary(const struct f_boundary* key) hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->mat_id)[i]); hash = hash * FNV64_PRIME; } - FOR_EACH(i, 0, strlen(key->flux) * sizeof(*key->flux)) { - hash = hash ^ (uint32_t)((unsigned char)((const char*)key->flux)[i]); + FOR_EACH(i, 0, sizeof(key->imposed_flux)) { + hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->imposed_flux)[i]); hash = hash * FNV64_PRIME; } return hash; @@ -769,6 +599,20 @@ struct solid_fluid_connect { #define NULL_SFCONNECT__ { "", 0, 0, 0, 0, 0, 0} static const struct solid_fluid_connect NULL_SFCONNECT = NULL_SFCONNECT__; +static void +print_sf_connect + (FILE* stream, + const struct solid_fluid_connect* c) +{ + ASSERT(stream && c); + fprintf(stream, "Solid-Fluid connection %s:", c->name); + if(c->has_emissivity) + fprintf(stream, " emissivity=%f, specular_fraction=%f", + c->emissivity, c->specular_fraction); + if (c->has_hc) fprintf(stream, " hc=%f", c->hc); + fprintf(stream, "\n"); +} + static char eq_sf_connect(const struct solid_fluid_connect* a, const struct solid_fluid_connect* b) { @@ -812,8 +656,8 @@ hash_sf_connect(const struct solid_fluid_connect* key) { /* 64-bits Fowler/Noll/Vo hash function */ const uint64_t FNV64_PRIME = - (uint64_t) (((uint64_t) 1 << 40) + ((uint64_t) 1 << 8) + 0xB3); - const uint64_t OFFSET64_BASIS = (uint64_t) 14695981039346656037u; + (uint64_t)(((uint64_t)1 << 40) + ((uint64_t)1 << 8) + 0xB3); + const uint64_t OFFSET64_BASIS = (uint64_t)14695981039346656037u; uint64_t hash = OFFSET64_BASIS; size_t i; ASSERT(key); @@ -847,7 +691,6 @@ hash_sf_connect(const struct solid_fluid_connect* key) } return hash; } - struct description { enum description_type type; union d { @@ -882,7 +725,10 @@ print_description print_h_boundary(stream, &desc->d.h_boundary, desc->type); break; case DESC_BOUND_F_FOR_SOLID: - print_f_boundary(stream, &desc->d.f_boundary, desc->type); + print_f_boundary(stream, &desc->d.f_boundary); + break; + case DESC_SOLID_FLUID_CONNECT: + print_sf_connect(stream, &desc->d.sf_connect); break; default: FATAL("error:" STR(__FILE__) ":" STR(__LINE__)": Invalid type.\n"); @@ -913,110 +759,57 @@ eq_description(const struct description* a, const struct description* b) } } -static FINLINE res_T -init_description(struct mem_allocator* alloc, struct description* key) -{ - (void)alloc; - key->type = DESCRIPTION_TYPE_COUNT__; - return RES_OK; -} - -static FINLINE res_T -cp_description(struct description* dst, const struct description* src) +static INLINE size_t +hash_description(const struct description* key) { - ASSERT(src && dst); - dst->type = src->type; - switch (dst->type) { + switch (key->type) { case DESC_MAT_SOLID: - return cp_solid(&dst->d.solid, &src->d.solid); + return hash_solid(&key->d.solid); case DESC_MAT_FLUID: - return cp_fluid(&dst->d.fluid, &src->d.fluid); + return hash_fluid(&key->d.fluid); case DESC_BOUND_H_FOR_SOLID: case DESC_BOUND_H_FOR_FLUID: - return cp_h_boundary(&dst->d.h_boundary, &src->d.h_boundary); + return hash_h_boundary(&key->d.h_boundary); case DESC_BOUND_T_FOR_SOLID: case DESC_BOUND_T_FOR_FLUID: - return cp_t_boundary(&dst->d.t_boundary, &src->d.t_boundary); + return hash_t_boundary(&key->d.t_boundary, key->type); case DESC_BOUND_F_FOR_SOLID: - return cp_f_boundary(&dst->d.f_boundary, &src->d.f_boundary); + return hash_f_boundary(&key->d.f_boundary); case DESC_SOLID_FLUID_CONNECT: - return cp_sf_connect(&dst->d.sf_connect, &src->d.sf_connect); + return hash_sf_connect(&key->d.sf_connect); default: FATAL("error:" STR(__FILE__) ":" STR(__LINE__)": Invalid type.\n"); } } static FINLINE res_T -cp_release_description(struct description* dst, struct description* src) +init_description(struct mem_allocator* alloc, struct description* key) { - ASSERT(src && dst); - dst->type = src->type; - switch (dst->type) { - case DESC_MAT_SOLID: - return cp_release_solid(&dst->d.solid, &src->d.solid); - case DESC_MAT_FLUID: - return cp_release_fluid(&dst->d.fluid, &src->d.fluid); - case DESC_BOUND_H_FOR_SOLID: - case DESC_BOUND_H_FOR_FLUID: - return cp_release_h_boundary(&dst->d.h_boundary, &src->d.h_boundary); - case DESC_BOUND_T_FOR_SOLID: - case DESC_BOUND_T_FOR_FLUID: - return cp_release_t_boundary(&dst->d.t_boundary, &src->d.t_boundary); - case DESC_BOUND_F_FOR_SOLID: - return cp_release_f_boundary(&dst->d.f_boundary, &src->d.f_boundary); - case DESC_SOLID_FLUID_CONNECT: - return cp_release_sf_connect(&dst->d.sf_connect, &src->d.sf_connect); - case DESCRIPTION_TYPE_COUNT__: - return RES_OK; - default: - FATAL("error:" STR(__FILE__) ":" STR(__LINE__)": Invalid type.\n"); - } + (void)alloc; + key->type = DESCRIPTION_TYPE_COUNT__; + return RES_OK; } static FINLINE res_T -release_description(struct description* a) -{ - ASSERT(a); - switch (a->type) { - case DESC_MAT_SOLID: - return release_solid(&a->d.solid); - case DESC_MAT_FLUID: - return release_fluid(&a->d.fluid); - case DESC_BOUND_H_FOR_SOLID: - case DESC_BOUND_H_FOR_FLUID: - return release_h_boundary(&a->d.h_boundary); - case DESC_BOUND_T_FOR_SOLID: - case DESC_BOUND_T_FOR_FLUID: - return release_t_boundary(&a->d.t_boundary); - case DESC_BOUND_F_FOR_SOLID: - return release_f_boundary(&a->d.f_boundary); - case DESC_SOLID_FLUID_CONNECT: - return release_sf_connect(&a->d.sf_connect); - case DESCRIPTION_TYPE_COUNT__: - return RES_OK; - default: - FATAL("error:" STR(__FILE__) ":" STR(__LINE__)": Invalid type.\n"); - } -} - -static INLINE size_t -hash_description(const struct description* key) +cp_description(struct description* dst, const struct description* src) { - switch (key->type) { + ASSERT(src && dst); + dst->type = src->type; + switch (dst->type) { case DESC_MAT_SOLID: - return hash_solid(&key->d.solid); + return cp_solid(&dst->d.solid, &src->d.solid); case DESC_MAT_FLUID: - return hash_fluid(&key->d.fluid); + return cp_fluid(&dst->d.fluid, &src->d.fluid); case DESC_BOUND_H_FOR_SOLID: case DESC_BOUND_H_FOR_FLUID: - return hash_h_boundary(&key->d.h_boundary); + return cp_h_boundary(&dst->d.h_boundary, &src->d.h_boundary); case DESC_BOUND_T_FOR_SOLID: case DESC_BOUND_T_FOR_FLUID: - return hash_t_boundary(&key->d.t_boundary, key->type); + return cp_t_boundary(&dst->d.t_boundary, &src->d.t_boundary); case DESC_BOUND_F_FOR_SOLID: - return hash_f_boundary(&key->d.f_boundary); + return cp_f_boundary(&dst->d.f_boundary, &src->d.f_boundary); case DESC_SOLID_FLUID_CONNECT: - return hash_sf_connect(&key->d.sf_connect); + return cp_sf_connect(&dst->d.sf_connect, &src->d.sf_connect); default: FATAL("error:" STR(__FILE__) ":" STR(__LINE__)": Invalid type.\n"); } diff --git a/src/stardis-compute.c b/src/stardis-compute.c @@ -194,42 +194,33 @@ create_holder const int is_green) { res_T res = RES_OK; - /* Could be less restrictive if green output included positions/dates */ - int prohibited = is_green ? NO_VAR_ALLOWED : ALL_VARS_ALLOWED; switch (description->type) { case DESC_BOUND_H_FOR_SOLID: counts->hbound_count++; /* Create an external fluid with bound temp as fluid temp */ - res = create_fluid(dev, NULL, 1, 1, is_green, 1, NULL, - description->d.h_boundary.T, media, &description->d.h_boundary.mat_id); + res = create_fluid(dev, NULL, 1, 1, is_green, 1, -1, + description->d.h_boundary.imposed_temperature, media, + &description->d.h_boundary.mat_id); if (res != RES_OK) goto error; break; case DESC_BOUND_H_FOR_FLUID: /* Create an external solid with bound temp as solid temp */ counts->hbound_count++; - res = create_solid(dev, NULL, INF, 1, 1, 1, is_green, 1, NULL, - description->d.h_boundary.T, NULL, media, NULL, + res = create_solid(dev, NULL, INF, 1, 1, 1, is_green, 1, -1, + description->d.h_boundary.imposed_temperature, 0, media, &description->d.h_boundary.mat_id); if (res != RES_OK) goto error; break; case DESC_BOUND_T_FOR_SOLID: counts->tbound_count++; - ASSERT(description->d.t_boundary.T != NULL); - res = compile_expr_to_fn(&description->d.t_boundary.te_temperature, - description->d.t_boundary.T, prohibited, NULL); - if (res != RES_OK) { - fprintf(stderr, "Invalid boundary temperature expression: %s\n", - description->d.t_boundary.T); - goto error; - } if (dummies->dummy_fluid) { /* Reuse external dummy fluid */ description->d.t_boundary.mat_id = dummies->dummy_fluid_id; } else { /* Create dummy fluid */ - res = create_fluid(dev, NULL, 1, 1, is_green, 1, NULL, - NULL, media, &description->d.t_boundary.mat_id); + res = create_fluid(dev, NULL, 1, 1, is_green, 1, -1, + -1, media, &description->d.t_boundary.mat_id); if (res != RES_OK) goto error; dummies->dummy_fluid = sa_last(*media); dummies->dummy_fluid_id = description->d.t_boundary.mat_id; @@ -237,21 +228,13 @@ create_holder break; case DESC_BOUND_T_FOR_FLUID: counts->tbound_count++; - ASSERT(description->d.t_boundary.T != NULL); - res = compile_expr_to_fn(&description->d.t_boundary.te_temperature, - description->d.t_boundary.T, prohibited, NULL); - if (res != RES_OK) { - fprintf(stderr, "Invalid boundary temperature expression: %s\n", - description->d.t_boundary.T); - goto error; - } if (dummies->dummy_solid) { /* Reuse external dummy solid */ description->d.t_boundary.mat_id = dummies->dummy_solid_id; } else { /* Create dummy solid */ - res = create_solid(dev, NULL, 1, 1, 1, 1, is_green, 1, NULL, - NULL, NULL, media, NULL, &description->d.t_boundary.mat_id); + res = create_solid(dev, NULL, 1, 1, 1, 1, is_green, 1, -1, + -1, 0, media, &description->d.t_boundary.mat_id); if (res != RES_OK) goto error; dummies->dummy_solid = sa_last(*media); dummies->dummy_solid_id = description->d.t_boundary.mat_id; @@ -259,20 +242,12 @@ create_holder break; case DESC_BOUND_F_FOR_SOLID: counts->fbound_count++; - ASSERT(description->d.f_boundary.flux != NULL); - res = compile_expr_to_fn(&description->d.f_boundary.te_flux, - description->d.f_boundary.flux, 1, NULL); - if (res != RES_OK) { - fprintf(stderr, "Invalid boundary flux expression: %s\n", - description->d.f_boundary.flux); - goto error; - } if (dummies->dummy_fluid) { /* Reuse external dummy fluid */ description->d.f_boundary.mat_id = dummies->dummy_fluid_id; } else { /* Create dummy fluid */ - res = create_fluid(dev, NULL, 1, 1, is_green, 1, NULL, NULL, + res = create_fluid(dev, NULL, 1, 1, is_green, 1, -1, -1, media, &description->d.f_boundary.mat_id); if (res != RES_OK) goto error; dummies->dummy_fluid = sa_last(*media); @@ -296,11 +271,10 @@ create_holder description->d.solid.delta, is_green, 0, - description->d.solid.Tinit, - description->d.solid.Temp, - description->d.solid.power, + description->d.solid.tinit, + description->d.solid.imposed_temperature, + description->d.solid.vpower, media, - &description->d.solid.has_power, &description->d.solid.solid_id); if (res != RES_OK) goto error; break; @@ -312,8 +286,8 @@ create_holder description->d.fluid.cp, is_green, 0, - description->d.fluid.Tinit, - description->d.fluid.Temp, + description->d.fluid.tinit, + description->d.fluid.imposed_temperature, media, &description->d.fluid.fluid_id); if (res != RES_OK) goto error; @@ -744,47 +718,6 @@ error: ******************************************************************************/ res_T -compile_expr_to_fn - (struct te_expr** f, - const char* math_expr, - const int prohibited, - int* is_zero) -{ - te_variable vars[4] = { - TE_DEF_OFFSET("x", offsetof(struct sdis_rwalk_vertex, P[0])), - TE_DEF_OFFSET("y", offsetof(struct sdis_rwalk_vertex, P[1])), - TE_DEF_OFFSET("z", offsetof(struct sdis_rwalk_vertex, P[2])), - TE_DEF_OFFSET("t", offsetof(struct sdis_rwalk_vertex, time)) - }; - int fst = 0, lst = 4; - - ASSERT(f && math_expr); - ASSERT(prohibited == (prohibited & NO_VAR_ALLOWED)); /* Use only defined flags */ - - if (prohibited & XYZ_PROHIBITED) fst = 3; - if (prohibited & T_PROHIBITED) lst = 3; - *f = te_compile(math_expr, vars + fst, lst - fst, NULL); - if (!*f) { - if (!te_compile(math_expr, vars, 4, NULL)) - return RES_BAD_ARG; /* Expr is not valid */ - /* Expr is valid */ - if (prohibited != ALL_VARS_ALLOWED) - fprintf(stderr, "Expression \"%s\" use a probibited variable ", math_expr); - if (prohibited == NO_VAR_ALLOWED) - fprintf(stderr, "(no variable allowed)\n"); - else if (prohibited == XYZ_PROHIBITED) - fprintf(stderr, "(xyz prohibited)\n"); - else { - ASSERT(prohibited == T_PROHIBITED); - fprintf(stderr, "(t prohibited)\n"); - } - return RES_BAD_OP; /* Expr is valid, but use a forbidden var */ - } - if (is_zero) *is_zero = !((*f)->type == TE_CONSTANT && (*f)->v.value == 0); - return RES_OK; -} - -res_T stardis_compute (struct stardis* stardis, const int mode) diff --git a/src/stardis-compute.h b/src/stardis-compute.h @@ -11,7 +11,6 @@ #define HTABLE_KEY unsigned #include <rsys/hash_table.h> -struct te_expr; struct stardis; struct counts { @@ -23,21 +22,6 @@ struct counts { } static const struct counts COUNTS_NULL = COUNTS_NULL__; -/* A type to limit variable use in tinyexpr expressions */ -enum var_prohibited_t { - ALL_VARS_ALLOWED = 0, - T_PROHIBITED = BIT(4), - XYZ_PROHIBITED = BIT(5), - NO_VAR_ALLOWED = T_PROHIBITED | XYZ_PROHIBITED -}; - -extern res_T -compile_expr_to_fn - (struct te_expr** f, - const char* math_expr, - const int prohibited, - int* is_zero); - extern res_T stardis_compute (struct stardis* stardis, diff --git a/src/stardis-fluid.c b/src/stardis-fluid.c @@ -2,7 +2,6 @@ #include "stardis-compute.h" #include <sdis.h> -#include <tinyexpr.h> #include<rsys/stretchy_array.h> #include <limits.h> @@ -37,17 +36,15 @@ fluid_get_temperature struct sdis_data* data) { const struct fluid* fluid_props = sdis_data_cget(data); - ASSERT(fluid_props->t_init || fluid_props->temp); if (fluid_props->is_green || vtx->time > fluid_props->t0) { /* Always use temp for Green mode, regardless of time */ - if (fluid_props->temp) - return te_eval(fluid_props->temp, vtx); + if (fluid_props->imposed_temperature >= 0) + return fluid_props->imposed_temperature; else return -1; } - /* Time is t0: use t_init */ - if (fluid_props->t_init) - return te_eval(fluid_props->t_init, vtx); - /* Must have had t_init defined: error! */ + /* Time is <= 0: use tinit */ + if (fluid_props->tinit >= 0) return fluid_props->tinit; + /* Must have had tinit defined: error! */ if (fluid_props->name[0]) { fprintf(stderr, "fluid_get_temperature: getting undefined Tinit (fluid '%s')\n", @@ -58,15 +55,6 @@ fluid_get_temperature FATAL("fluid_get_temperature: getting undefined Tinit\n"); } -static void -release_fluid_data - (void* f) -{ - struct fluid* fluid = (struct fluid*)f; - te_free(fluid->t_init); - te_free(fluid->temp); -} - /******************************************************************************* * Public Functions ******************************************************************************/ @@ -79,8 +67,8 @@ create_fluid const double cp, const int is_green, const int is_outside, - const char* tinit_expr, - const char* t_expr, + const double tinit, + const double imposed_temperature, struct sdis_medium*** media_ptr, unsigned* out_id) { @@ -89,15 +77,14 @@ create_fluid struct sdis_data* data = NULL; struct fluid* fluid_props; size_t sz; - /* Could be less restrictive if green output included positions/dates */ - int prohibited = is_green ? NO_VAR_ALLOWED : ALL_VARS_ALLOWED; ASSERT(dev && rho >= 0 && cp >= 0 && media_ptr && out_id); + ASSERT(tinit >= 0 || imposed_temperature >= 0); fluid_shader.calorific_capacity = fluid_get_calorific_capacity; fluid_shader.volumic_mass = fluid_get_volumic_mass; fluid_shader.temperature = fluid_get_temperature; res = sdis_data_create(dev, sizeof(struct fluid), ALIGNOF(struct fluid), - release_fluid_data, &data); + NULL, &data); if (res != RES_OK) goto error; sz = sa_size(*media_ptr); @@ -107,31 +94,12 @@ create_fluid else fluid_props->name[0] = '\0'; fluid_props->cp = cp; fluid_props->rho = rho; - fluid_props->t_init = NULL; - fluid_props->temp = NULL; + fluid_props->tinit = tinit; + fluid_props->imposed_temperature = imposed_temperature; fluid_props->is_green = is_green; fluid_props->is_outside = is_outside; - fluid_props->t0 = 0; fluid_props->id = (unsigned)sz; - if (tinit_expr) { - res = compile_expr_to_fn(&fluid_props->t_init, tinit_expr, - prohibited | T_PROHIBITED, NULL); - if (res != RES_OK) { - if (res == RES_BAD_ARG) - fprintf(stderr, "Invalid initial temperature expression: %s\n", - tinit_expr); - goto error; - } - } - if (t_expr) { - res = compile_expr_to_fn(&fluid_props->temp, t_expr, prohibited, NULL); - if (res != RES_OK) { - fprintf(stderr, "Invalid temperature expression: %s\n", - t_expr); - goto error; - } - } res = sdis_fluid_create(dev, &fluid_shader, data, sa_add(*media_ptr, 1)); if (res != RES_OK) goto error; *out_id = fluid_props->id; diff --git a/src/stardis-fluid.h b/src/stardis-fluid.h @@ -6,7 +6,6 @@ #include <sdis.h> #include <rsys/rsys.h> -struct te_expr; struct sdis_device; struct sdis_medium; @@ -19,10 +18,9 @@ struct fluid { double rho; /* Volumic mass */ /* Compute mode */ int is_green, is_outside; - double t0; - /* TinyExpr stuff to compute temperature */ - struct te_expr *temp; - struct te_expr *t_init; + double t0; /* End time of tinit */ + double tinit; + double imposed_temperature; /* ID */ unsigned id; }; @@ -35,8 +33,8 @@ create_fluid const double cp, const int is_green, const int is_outside, - const char* tinit_expr, - const char* t_expr, + const double tinit, + const double imposed_temperature, struct sdis_medium*** media_ptr, unsigned* out_id); diff --git a/src/stardis-intface.c b/src/stardis-intface.c @@ -2,7 +2,6 @@ #include "stardis-app.h" #include "stardis-output.h" -#include <tinyexpr.h> #include <sdis.h> #include <rsys/stretchy_array.h> @@ -26,11 +25,8 @@ interface_get_temperature struct sdis_data* data) { const struct intface* interface_props = sdis_data_cget(data); - - if (interface_props->temperature == NULL) - return -1; - - return te_eval(interface_props->temperature, frag); + (void)frag; + return interface_props->imposed_temperature; } static double @@ -39,11 +35,8 @@ interface_get_flux struct sdis_data* data) { const struct intface* interface_props = sdis_data_cget(data); - - if (interface_props->flux == NULL) - return SDIS_FLUX_NONE; - - return te_eval(interface_props->flux, frag); + (void)frag; + return interface_props->imposed_flux; } static double @@ -66,15 +59,6 @@ interface_get_alpha return interface_props->alpha; } -static void -release_interface_data - (void* s) -{ - struct intface* intface = (struct intface*)s; - te_free(intface->temperature); - te_free(intface->flux); -} - /******************************************************************************* * Public Functions ******************************************************************************/ @@ -127,10 +111,10 @@ create_intface int connect_defined = (cd != UINT_MAX); SDIS(data_create(dev, sizeof(struct intface), ALIGNOF(struct intface), - release_interface_data, &data)); + NULL, &data)); interface_props = sdis_data_get(data); - interface_props->temperature = NULL; - interface_props->flux = NULL; + interface_props->imposed_temperature = -1; + interface_props->imposed_flux = SDIS_FLUX_NONE; interface_props->front_boundary_id = UINT_MAX; interface_props->back_boundary_id = UINT_MAX; @@ -266,9 +250,9 @@ create_intface * TODO: should be outside to allow contact resistances */ interface_shader.back.temperature = interface_get_temperature; } - ASSERT(connect->d.t_boundary.te_temperature); - interface_props->temperature - = te_duplicate(connect->d.t_boundary.te_temperature); + ASSERT(connect->d.t_boundary.imposed_temperature >= 0); + interface_props->imposed_temperature + = connect->d.t_boundary.imposed_temperature; if (connect->d.t_boundary.has_hc) { ASSERT(connect->type == DESC_BOUND_T_FOR_FLUID); interface_shader.convection_coef = interface_get_convection_coef; @@ -292,8 +276,8 @@ create_intface front_med = media[connect->d.f_boundary.mat_id]; interface_shader.back.flux = interface_get_flux; } - ASSERT(connect->d.f_boundary.te_flux); - interface_props->flux = te_duplicate(connect->d.f_boundary.te_flux); + ASSERT(connect->d.f_boundary.imposed_flux != SDIS_FLUX_NONE); + interface_props->imposed_flux = connect->d.f_boundary.imposed_flux; break; case DESC_SOLID_FLUID_CONNECT: /* Both front and back should be defined; diff --git a/src/stardis-intface.h b/src/stardis-intface.h @@ -7,7 +7,6 @@ #include <limits.h> -struct te_expr; struct sdis_data; struct sdis_device; struct geometry; @@ -21,9 +20,9 @@ struct intface { double hc; /* Convection coefficient */ double emissivity; double alpha; - /* TinyExpr stuff to compute temperature & flux */ - struct te_expr *temperature; - struct te_expr *flux; + /* Imposed compute temperature & flux */ + double imposed_temperature; + double imposed_flux; /* IDs */ unsigned front_boundary_id, back_boundary_id; }; diff --git a/src/stardis-output.c b/src/stardis-output.c @@ -440,8 +440,8 @@ dump_green const struct mat_solid* sl; if (desc->type != DESC_MAT_SOLID) continue; sl = &desc->d.solid; - printf("%u\t%s\t%g\t%g\t%g\t%s\n", - i, sl->name, sl->lambda, sl->rho, sl->cp, (sl->has_power ? sl->power : "0")); + printf("%u\t%s\t%g\t%g\t%g\t%g\n", + i, sl->name, sl->lambda, sl->rho, sl->cp, sl->vpower); } } if (counts->fmed_count) { @@ -465,7 +465,7 @@ dump_green if (desc->type != DESC_BOUND_T_FOR_SOLID && desc->type != DESC_BOUND_T_FOR_FLUID) continue; bd = &desc->d.t_boundary; - printf("%u\t%s\t%s\n", i, bd->name, bd->T); + printf("%u\t%s\t%g\n", i, bd->name, bd->imposed_temperature); } } if (counts->hbound_count) { @@ -477,10 +477,11 @@ dump_green if (desc->type != DESC_BOUND_H_FOR_SOLID && desc->type != DESC_BOUND_H_FOR_FLUID) continue; bd = &desc->d.h_boundary; - printf("%u\t%s\t%g\t%g\t%g\t%g\t%s\n", + printf("%u\t%s\t%g\t%g\t%g\t%g\t%g\n", i, bd->name, (bd->has_emissivity ? bd->emissivity : 0), (bd->has_emissivity ? bd->specular_fraction : 0), - (bd->has_hc ? bd->hc : 0), (bd->has_hc ? bd->hc_max : 0), bd->T); + (bd->has_hc ? bd->hc : 0), (bd->has_hc ? bd->hc_max : 0), + bd->imposed_temperature); } } if (counts->fbound_count) { @@ -491,8 +492,8 @@ dump_green const struct f_boundary* bd; if (desc->type != DESC_BOUND_F_FOR_SOLID) continue; bd = &desc->d.f_boundary; - printf("%u\t%s\t%s\n", - i, bd->name, bd->flux); + printf("%u\t%s\t%g\n", + i, bd->name, bd->imposed_flux); } } diff --git a/src/stardis-parsing.c b/src/stardis-parsing.c @@ -625,29 +625,25 @@ parse_medium_line res = RES_BAD_ARG; goto exit; } - /* Depending of the number of spaces before '"' strtok should - * be called once or twice */ - CHK_TOK(strtok(NULL, "\""), "Tinit"); - if (*(tk + strspn(tk, " \t")) == '\0') { - CHK_TOK(strtok(NULL, "\""), "Tinit"); + CHK_TOK(strtok(NULL, " "), "Tinit"); + res = cstr_to_double(tk, &desc->d.solid.tinit); + if (res != RES_OK || desc->d.solid.tinit < 0) { + fprintf(stderr, "Invalid Tinit: %s\n", tk); + res = RES_BAD_ARG; + goto exit; } - desc->d.solid.Tinit = malloc(strlen(tk) + 1); - strcpy(desc->d.solid.Tinit, tk); - /* Closing " fot Tinit; can return NULL if line ends just after "Tinit" */ - tk = strtok(NULL, "\""); /* Volumic Power is optional */ - if (tk && *(tk + strspn(tk, " \t")) == '\0') { - /* Depending of the number of spaces before '"' strtok should - * be called once or twice */ - tk = strtok(NULL, "\""); - } + tk = strtok(NULL, " "); if (tk) { - desc->d.solid.power = malloc(strlen(tk) + 1); - strcpy(desc->d.solid.power, tk); - /* Can be changed aftwerwards if compiled to constant 0 */ - desc->d.solid.has_power = 1; + res = cstr_to_double(tk, &desc->d.solid.vpower); + if (res != RES_OK) { + fprintf(stderr, "Invalid volumic power: %s\n", tk); + res = RES_BAD_ARG; + goto exit; + } } + else desc->d.solid.vpower = SDIS_VOLUMIC_POWER_NONE; } else if (strcmp(tk, "FLUID") == 0) { desc->type = DESC_MAT_FLUID; @@ -681,12 +677,13 @@ parse_medium_line } /* Depending of the number of spaces before '"' strtok should * be called once or twice */ - CHK_TOK(strtok(NULL, "\""), "Tinit"); - if (*(tk + strspn(tk, " \t")) == '\0') { - CHK_TOK(strtok(NULL, "\""), "Tinit"); + CHK_TOK(strtok(NULL, " "), "Tinit"); + res = cstr_to_double(tk, &desc->d.fluid.tinit); + if (res != RES_OK || desc->d.fluid.tinit < 0) { + fprintf(stderr, "Invalid Tinit: %s\n", tk); + res = RES_BAD_ARG; + goto exit; } - desc->d.fluid.Tinit = malloc(strlen(tk) + 1); - strcpy(desc->d.fluid.Tinit, tk); } else { res = RES_BAD_ARG; fprintf(stderr, "Invalid medium type: %s\n", tk); @@ -796,14 +793,13 @@ parse_boundary_line res = RES_BAD_ARG; goto exit; } - /* Depending of the number of spaces before '"' strtok should - * be called once or twice */ - CHK_TOK(strtok(NULL, "\""), "temperature"); - if (*(tk + strspn(tk, " \t")) == '\0') { - CHK_TOK(strtok(NULL, "\""), "temperature"); + CHK_TOK(strtok(NULL, " "), "temperature"); + res = cstr_to_double(tk, &desc->d.h_boundary.imposed_temperature); + if (res != RES_OK || desc->d.h_boundary.imposed_temperature < 0) { + fprintf(stderr, "Invalid temperature value: %s\n", tk); + res = RES_BAD_ARG; + goto exit; } - desc->d.h_boundary.T = malloc(strlen(tk) + 1); - strcpy(desc->d.h_boundary.T, tk); } else if (t_solid || t_fluid) { desc->type = t_solid ? DESC_BOUND_T_FOR_SOLID : DESC_BOUND_T_FOR_FLUID; @@ -822,14 +818,13 @@ parse_boundary_line *stl_filename = malloc(strlen(tk) + 1); strcpy(*stl_filename, tk); - /* Depending of the number of spaces before '"' strtok should - * be called once or twice */ - CHK_TOK(strtok(NULL, "\""), "temperature"); - if (*(tk + strspn(tk, " \t")) == '\0') { - CHK_TOK(strtok(NULL, "\""), "temperature"); + CHK_TOK(strtok(NULL, " "), "temperature"); + res = cstr_to_double(tk, &desc->d.t_boundary.imposed_temperature); + if (res != RES_OK || desc->d.t_boundary.imposed_temperature < 0) { + fprintf(stderr, "Invalid temperature value: %s\n", tk); + res = RES_BAD_ARG; + goto exit; } - desc->d.t_boundary.T = malloc(strlen(tk) + 1); - strcpy(desc->d.t_boundary.T, tk); /* Parse hc + hc_max only if fluid */ if (t_fluid) { @@ -871,12 +866,13 @@ parse_boundary_line /* Depending of the number of spaces before '"' strtok should * be called once or twice */ - CHK_TOK(strtok(NULL, "\""), "flux"); - if (*(tk + strspn(tk, " \t")) == '\0') { - CHK_TOK(strtok(NULL, "\""), "flux"); + CHK_TOK(strtok(NULL, " "), "flux"); + res = cstr_to_double(tk, &desc->d.f_boundary.imposed_flux); + if (res != RES_OK) { + fprintf(stderr, "Invalid flux value: %s\n", tk); + res = RES_BAD_ARG; + goto exit; } - desc->d.f_boundary.flux = malloc(strlen(tk) + 1); - strcpy(desc->d.f_boundary.flux, tk); } else if (sf_connect) { desc->type = DESC_SOLID_FLUID_CONNECT; diff --git a/src/stardis-solid.c b/src/stardis-solid.c @@ -2,7 +2,6 @@ #include "stardis-compute.h" #include <sdis.h> -#include <tinyexpr.h> #include<rsys/stretchy_array.h> #include <limits.h> @@ -58,10 +57,7 @@ solid_get_delta_boundary struct sdis_data* data) { const struct solid* solid_props = sdis_data_cget(data); - return solid_props->delta - /* Emperical scale factor that ensures that delta_boundary > delta withouht - * being an exact multiple of delta. */ - /** 2.1 */; + return solid_props->delta; } #endif @@ -71,17 +67,14 @@ solid_get_temperature struct sdis_data* data) { const struct solid* solid_props = sdis_data_cget(data); - char msg[128]; - ASSERT(solid_props->t_init || solid_props->temp); if (solid_props->is_green || vtx->time > solid_props->t0) { /* Always use temp for Green mode, regardless of time */ - if (solid_props->temp) - return te_eval(solid_props->temp, vtx); + if (solid_props->imposed_temperature >= 0) + return solid_props->imposed_temperature; else return -1; } - /* Time is t0: use t_init */ - if (solid_props->t_init) - return te_eval(solid_props->t_init, vtx); + /* Time is <= 0: use tinit */ + if (solid_props->tinit >= 0) return solid_props->tinit; /* Must have had t_init defined: error! */ if (solid_props->name[0]) { fprintf(stderr, @@ -99,16 +92,8 @@ solid_get_power struct sdis_data* data) { const struct solid* solid_props = sdis_data_cget(data); - return te_eval(solid_props->power, vtx); -} - -static void -release_solid_data - (void* s) -{ - struct solid* solid = (struct solid*)s; - te_free(solid->t_init); - te_free(solid->power); + (void)vtx; + return solid_props->vpower; } /******************************************************************************* @@ -125,11 +110,10 @@ create_solid const double delta, const int is_green, const int is_outside, - const char* tinit_expr, /* Can be NULL if not used by getter */ - const char* t_expr, /* Can be NULL if not used by getter */ - const char* power_expr, /* Can be NULL */ + const double tinit, + const double imposed_temperature, + const double vpower, struct sdis_medium*** media_ptr, - int* out_has_power, /* Can be NULL */ unsigned* out_id) { res_T res = RES_OK; @@ -138,7 +122,6 @@ create_solid struct solid* solid_props; size_t sz; /* Could be less restrictive if green output included positions/dates */ - int prohibited = is_green ? NO_VAR_ALLOWED : ALL_VARS_ALLOWED; ASSERT(dev && lambda >= 0 && rho >= 0 && cp >= 0 && delta > 0 && media_ptr && out_id); @@ -151,7 +134,7 @@ create_solid #endif solid_shader.temperature = solid_get_temperature; res = sdis_data_create(dev, sizeof(struct solid), ALIGNOF(struct solid), - release_solid_data, &data); + NULL, &data); if (res != RES_OK) goto error; sz = sa_size(*media_ptr); @@ -163,44 +146,13 @@ create_solid solid_props->rho = rho; solid_props->cp = cp; solid_props->delta = delta; - solid_props->t_init = NULL; - solid_props->temp = NULL; - solid_props->power = NULL; + solid_props->tinit = tinit; + solid_props->imposed_temperature = imposed_temperature; + solid_props->vpower = vpower; solid_props->is_green = is_green; solid_props->is_outside = is_outside; - solid_props->t0 = 0; solid_props->id = (unsigned)sz; - if (tinit_expr) { - res = compile_expr_to_fn(&solid_props->t_init, tinit_expr, - prohibited | T_PROHIBITED, NULL); - if (res != RES_OK) { - if (res == RES_BAD_ARG) - fprintf(stderr, "Invalid initial temperature expression: %s\n", - tinit_expr); - goto error; - } - } - if (t_expr) { - res = compile_expr_to_fn(&solid_props->temp, t_expr, prohibited, NULL); - if (res != RES_OK) { - fprintf(stderr, "Invalid temperature expression: %s\n", - t_expr); - goto error; - } - } - if (power_expr) { - int has_power; - res = compile_expr_to_fn(&solid_props->power, power_expr, prohibited, &has_power); - if (res != RES_OK) { - fprintf(stderr, "Invalid volumic power expression: %s\n", - power_expr); - goto error; - } - if (out_has_power) *out_has_power = has_power; - if (has_power) solid_shader.volumic_power = solid_get_power; - } else { - if (out_has_power) *out_has_power = 0; - } + if (vpower != 0) solid_shader.volumic_power = solid_get_power; res = sdis_solid_create(dev, &solid_shader, data, sa_add(*media_ptr, 1)); if (res != RES_OK) goto error; *out_id = solid_props->id; diff --git a/src/stardis-solid.h b/src/stardis-solid.h @@ -5,7 +5,6 @@ #include <rsys/rsys.h> -struct te_expr; struct sdis_device; struct sdis_medium; @@ -18,13 +17,12 @@ struct solid { double lambda; /* Conductivity */ double rho; /* Volumic mass */ double delta; /* Numerical parameter */ + double tinit; /* Initial temperature */ + double imposed_temperature; /* allow to impose a T; -1 if unset */ + double vpower; /* Compute mode */ int is_green, is_outside; - double t0; - /* TinyExpr stuff to compute temperature & power */ - struct te_expr *temp; - struct te_expr *t_init; - struct te_expr *power; + double t0; /* End time of tinit */ /* ID */ unsigned id; }; @@ -39,11 +37,10 @@ create_solid const double delta, const int is_green, const int is_outside, - const char* tinit_expr, /* Can be NULL if not used by getter */ - const char* t_expr, /* Can be NULL if not used by getter */ - const char* power_expr, /* Can be NULL */ + const double tinit, + const double imposed_temperature, + const double vpower, struct sdis_medium*** media_ptr, - int* out_has_power, /* Can be NULL */ unsigned* out_id); #endif diff --git a/tinyexpr/tinyexpr.c b/tinyexpr/tinyexpr.c @@ -1,891 +0,0 @@ -/* - * TINYEXPR - Tiny recursive descent parser and evaluation engine in C - * - * Copyright (c) 2015-2018 Lewis Van Winkle - * - * http://CodePlea.com - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgement in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - */ - -/* COMPILE TIME OPTIONS */ - -/* Exponentiation associativity: -For a^b^c = (a^b)^c and -a^b = (-a)^b do nothing. -For a^b^c = a^(b^c) and -a^b = -(a^b) uncomment the next line.*/ -/* #define TE_POW_FROM_RIGHT */ - -/* Logarithms -For log = base 10 log do nothing -For log = natural log uncomment the next line. */ -/* #define TE_NAT_LOG */ - -#include "tinyexpr.h" -#include <stdlib.h> -#include <math.h> -#include <string.h> -#include <stdio.h> -#include <limits.h> -#include <assert.h> - -#ifndef M_E -#define M_E 2.71828182845904523536 // e -#endif - -#ifndef M_PI -#define M_PI 3.14159265358979323846 // pi -#endif - -#ifndef NAN -#define NAN (0.0/0.0) -#endif - -#ifndef INFINITY -#define INFINITY (1.0/0.0) -#endif - - -typedef double (*te_fun2)(double, double); - -enum { - -#ifdef TE_WITHOUT_FUNCTION_0 - TE_FUNCTION0 = 8, -#endif -#ifdef TE_WITHOUT_CLOSURES - TE_CLOSURE7 = 23, -#endif - - TOK_NULL = TE_CLOSURE7+1, TOK_ERROR, TOK_END, TOK_SEP, - TOK_OPEN, TOK_CLOSE, TOK_NUMBER, TOK_VARIABLE, TOK_OFFSET, TOK_INFIX, - - TE_CONDITION = 256 -}; - -typedef struct state { - const char *start; - const char *next; - int type; - union value v; - void *context; - - const te_variable *lookup; - int lookup_len; -} state; - - -#define TYPE_MASK(TYPE) ((TYPE)&0x0000003F) - -#define IS_PURE(TYPE) (((TYPE) & TE_FLAG_PURE) != 0) -#define IS_FUNCTION(TYPE) (((TYPE) & TE_FUNCTION0) != 0) -#ifdef TE_WITHOUT_CLOSURES -#define ARITY(TYPE) ( ((TYPE) & TE_FUNCTION0) ? ((TYPE) & 0x00000007) : 0 ) -#else -#define IS_CLOSURE(TYPE) (((TYPE) & TE_CLOSURE0) != 0) -#define ARITY(TYPE) ( ((TYPE) & (TE_FUNCTION0 | TE_CLOSURE0)) ? ((TYPE) & 0x00000007) : 0 ) -#endif -#define IS_CONDITION(TYPE) (((TYPE) & TE_CONDITION) != 0) -#define NEW_EXPR(type, ...) new_expr((type), (const te_expr*[]){__VA_ARGS__}) - -static te_expr *new_expr(const int type, const te_expr *parameters[]) { - const size_t arity = ARITY(type); - const size_t psize = sizeof(void*) * arity; - const size_t size = (sizeof(te_expr) - sizeof(void*)) + psize -#ifndef TE_WITHOUT_CLOSURES - + (IS_CLOSURE(type) ? sizeof(void*) : 0) -#endif - ; - te_expr *ret = malloc(size); - memset(ret, 0, size); - if (arity && parameters) { - memcpy(ret->parameters, parameters, psize); - } - ret->type = type; - ret->v.bound = 0; - return ret; -} - -static te_expr *new_expr1(const int type, te_expr *p1) { - const size_t size = sizeof(te_expr) -#ifndef TE_WITHOUT_CLOSURES - + (IS_CLOSURE(type) ? sizeof(void*) : 0) -#endif - ; - assert(p1 && ARITY(type) == 1); - te_expr *ret = malloc(size); - ret->type = type; - ret->v.bound = 0; - ret->parameters[0] = p1; - return ret; -} - -te_expr* te_duplicate(te_expr* n) { - const size_t size = sizeof(te_expr) -#ifndef TE_WITHOUT_CLOSURES - + (IS_CLOSURE(n->type) ? sizeof(void*) : 0); -#endif - ; - te_expr* nn; - assert(n); - nn = malloc(size); - if (!nn) return NULL; - memcpy(nn, n, size); - return nn; -} - -static te_expr *new_expr2(const int type, te_expr *p1, te_expr *p2) { - const size_t size = sizeof(te_expr) + sizeof(void*) -#ifndef TE_WITHOUT_CLOSURES - + (IS_CLOSURE(type) ? sizeof(void*) : 0) -#endif - ; - assert(p1 && p2 && ARITY(type) == 2); - te_expr *ret = malloc(size); - ret->type = type; - ret->v.bound = 0; - ret->parameters[0] = p1; - ret->parameters[1] = p2; - return ret; -} - -static void te_free_parameters(te_expr *n) { - int i; - if (!n) return; - for (i = 0; i < ARITY(n->type); i++)te_free(n->parameters[i]); -} - - -void te_free(te_expr *n) { - if (!n) return; - te_free_parameters(n); - free(n); -} - -static double fac(double a) {/* simplest version of fac */ - if (a < 0.0) - return NAN; - if (a > UINT_MAX) - return INFINITY; - unsigned int ua = (unsigned int)(a); - unsigned long int result = 1, i; - for (i = 1; i <= ua; i++) { - if (i > ULONG_MAX / result) - return INFINITY; - result *= i; - } - return (double)result; -} -static double ncr(double n, double r) { - if (n < 0.0 || r < 0.0 || n < r) return NAN; - if (n > UINT_MAX || r > UINT_MAX) return INFINITY; - unsigned long int un = (unsigned int)(n), ur = (unsigned int)(r), i; - unsigned long int result = 1; - if (ur > un / 2) ur = un - ur; - for (i = 1; i <= ur; i++) { - if (result > ULONG_MAX / (un - ur + i)) - return INFINITY; - result *= un - ur + i; - result /= i; - } - return (double)result; -} -static double npr(double n, double r) {return ncr(n, r) * fac(r);} - -/* Workaround for a VC 2017 problem */ -static double ceil_(double x) { return ceil(x); } -static double floor_(double x) { return floor(x); } - -static const te_variable functions[] = { - /* must be in alphabetical order */ - {"abs", {.f1=fabs}, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"acos", {.f1=acos}, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"asin", {.f1=asin}, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"atan", {.f1=atan}, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"atan2", {.f2=atan2}, TE_FUNCTION2 | TE_FLAG_PURE, 0}, - {"ceil", {.f1=ceil_}, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"cos", {.f1=cos}, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"cosh", {.f1=cosh}, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"e", {.value = M_E}, TE_CONSTANT, 0}, - {"exp", {.f1=exp}, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"fac", {.f1=fac}, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"floor", {.f1=floor_}, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"if", {.f3 = NULL}, /* Specific treatment, no associated C function */ - TE_FUNCTION3 | TE_CONDITION | TE_FLAG_PURE, 0}, - {"ln", {.f1=log}, TE_FUNCTION1 | TE_FLAG_PURE, 0}, -#ifdef TE_NAT_LOG - {"log", {.f1=log}, TE_FUNCTION1 | TE_FLAG_PURE, 0}, -#else - {"log", {.f1=log10}, TE_FUNCTION1 | TE_FLAG_PURE, 0}, -#endif - {"log10", {.f1=log10}, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"ncr", {.f2=ncr}, TE_FUNCTION2 | TE_FLAG_PURE, 0}, - {"npr", {.f2=npr}, TE_FUNCTION2 | TE_FLAG_PURE, 0}, - {"pi", {.value=M_PI}, TE_CONSTANT, 0}, - {"pow", {.f2=pow}, TE_FUNCTION2 | TE_FLAG_PURE, 0}, - {"sin", {.f1=sin}, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"sinh", {.f1=sinh}, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"sqrt", {.f1=sqrt}, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"tan", {.f1=tan}, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"tanh", {.f1=tanh}, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {0, {0}, 0, 0} -}; - -static const te_variable *find_builtin(const char *name, size_t len) { - int imin = 0; - int imax = sizeof(functions) / sizeof(te_variable) - 2; - - /*Binary search.*/ - while (imax >= imin) { - const int i = (imin + ((imax-imin)/2)); - int c = strncmp(name, functions[i].name, len); - if (!c) c = '\0' - functions[i].name[len]; - if (c == 0) { - return functions + i; - } else if (c > 0) { - imin = i + 1; - } else { - imax = i - 1; - } - } - - return 0; -} - -static const te_variable *find_lookup(const state *s, const char *name, size_t len) { - int iters; - const te_variable *var; - if (!s->lookup) return 0; - - for (var = s->lookup, iters = s->lookup_len; iters; ++var, --iters) { - if (strncmp(name, var->name, len) == 0 && var->name[len] == '\0') { - return var; - } - } - return 0; -} - - - -static double add(double a, double b) {return a + b;} -static double sub(double a, double b) {return a - b;} -static double mul(double a, double b) {return a * b;} -static double divide(double a, double b) {return a / b;} -static double negate(double a) {return -a;} -static double comma(double a, double b) {(void)a; return b;} -static double is_gt(double a, double b) { return a > b ? 1 : 0; } -static double is_ge(double a, double b) { return a >= b ? 1 : 0; } -static double is_lt(double a, double b) { return a < b ? 1 : 0; } -static double is_le(double a, double b) { return a <= b ? 1 : 0; } -static double is_eq(double a, double b) { return a == b ? 1 : 0; } -static double is_neq(double a, double b) { return a != b ? 1 : 0; } - -static int next_if(state *s, const char c) { - int r = *s->next && s->next[0] == c; - if (r) s->next++; - return r; -} - -static void next_token(state *s) { - s->type = TOK_NULL; - - do { - - if (!*s->next){ - s->type = TOK_END; - return; - } - - /* Try reading a number. */ - if ((s->next[0] >= '0' && s->next[0] <= '9') || s->next[0] == '.') { - s->v.value = strtod(s->next, (char**)&s->next); - s->type = TOK_NUMBER; - } else { - /* Look for a variable or builtin function call. */ - if (s->next[0] >= 'a' && s->next[0] <= 'z') { - const char *start; - start = s->next; - while ((s->next[0] >= 'a' && s->next[0] <= 'z') || (s->next[0] >= '0' && s->next[0] <= '9') || (s->next[0] == '_')) s->next++; - - const te_variable *var = find_lookup(s, start, (size_t)(s->next - start)); - if (!var) var = find_builtin(start, (size_t)(s->next - start)); - - if (!var) { - s->type = TOK_ERROR; - } else { - switch(TYPE_MASK(var->type)) - { - case TE_VARIABLE: - s->type = TOK_VARIABLE; - s->v.bound = var->v.bound; - break; - - case TE_OFFSET: - s->type = TOK_OFFSET; - s->v.offset = var->v.offset; - break; - - case TE_CONSTANT: - s->type = TE_CONSTANT; - s->v.value = var->v.value; - break; - -#ifndef TE_WITHOUT_CLOSURES - case TE_CLOSURE0: case TE_CLOSURE1: case TE_CLOSURE2: case TE_CLOSURE3: - case TE_CLOSURE4: case TE_CLOSURE5: case TE_CLOSURE6: case TE_CLOSURE7: - s->context = var->context; -#endif -#ifndef TE_WITHOUT_FUNCTION_0 - /* fall through */ - case TE_FUNCTION0: -#endif - /* fall through */ - case TE_FUNCTION1: case TE_FUNCTION2: case TE_FUNCTION3: -#if TE_MAX_FUNCTION_ARITY >= 4 - /* fall through */ - case TE_FUNCTION4: -#endif -#if TE_MAX_FUNCTION_ARITY >= 5 - /* fall through */ - case TE_FUNCTION5: -#endif -#if TE_MAX_FUNCTION_ARITY >= 6 - /* fall through */ - case TE_FUNCTION6: -#endif -#if TE_MAX_FUNCTION_ARITY == 7 - /* fall through */ - case TE_FUNCTION7: -#endif - s->type = var->type; - s->v.any = var->v.any; - break; - } - } - - } else { - /* Look for an operator or special character. */ - switch (s->next++[0]) { - case '+': s->type = TOK_INFIX; s->v.f2 = add; break; - case '-': s->type = TOK_INFIX; s->v.f2 = sub; break; - case '*': s->type = TOK_INFIX; s->v.f2 = mul; break; - case '/': s->type = TOK_INFIX; s->v.f2 = divide; break; - case '^': s->type = TOK_INFIX; s->v.f2 = pow; break; - case '%': s->type = TOK_INFIX; s->v.f2 = fmod; break; - case '>': s->type = TOK_INFIX; - s->v.f2 = next_if(s, '=') ? is_ge : is_gt; break; - case '<': s->type = TOK_INFIX; - s->v.f2 = next_if(s, '=') ? is_le : is_lt; break; - case '=': s->type = TOK_INFIX; - /* The only valid char after = is = */ - if (next_if(s, '=')) s->v.f2 = is_eq; else s->type = TOK_ERROR; - break; - case '!': s->type = TOK_INFIX; - /* The only valid char after ! is = */ - if (next_if(s, '=')) s->v.f2 = is_neq; else s->type = TOK_ERROR; - break; - case '(': s->type = TOK_OPEN; break; - case ')': s->type = TOK_CLOSE; break; - case ',': s->type = TOK_SEP; break; - case ' ': case '\t': case '\n': case '\r': break; - default: s->type = TOK_ERROR; break; - } - } - } - } while (s->type == TOK_NULL); -} - - -static te_expr *list(state *s); -static te_expr *eql(state *s); -static te_expr *power(state *s); - -static te_expr *base(state *s) { - /* <base> = <constant> | <variable> | <function-0> {"(" ")"} | <function-1> <power> | <function-X> "(" <expr> {"," <expr>} ")" | "(" <list> ")" */ - te_expr *ret; - int arity; - - switch (TYPE_MASK(s->type)) { - case TOK_NUMBER: - ret = new_expr(TE_CONSTANT, 0); - ret->v.value = s->v.value; - next_token(s); - break; - - case TOK_VARIABLE: - ret = new_expr(TE_VARIABLE, 0); - ret->v.bound = s->v.bound; - next_token(s); - break; - - case TOK_OFFSET: - ret = new_expr(TE_OFFSET, 0); - ret->v.offset = s->v.offset; - next_token(s); - break; - - case TE_CONSTANT: - ret = new_expr(TE_CONSTANT, 0); - ret->v.value = s->v.value; - next_token(s); - break; - -#if ! defined(TE_WITHOUT_FUNCTION_0) || ! defined(TE_WITHOUT_CLOSURES) -#ifndef TE_WITHOUT_FUNCTION_0 - case TE_FUNCTION0: -#endif -#ifndef TE_WITHOUT_CLOSURES - case TE_CLOSURE0: -#endif - ret = new_expr(s->type, 0); - ret->v.any = s->v.any; -#ifndef TE_WITHOUT_CLOSURES - if (IS_CLOSURE(s->type)) ret->parameters[0] = s->context; -#endif - next_token(s); - if (s->type == TOK_OPEN) { - next_token(s); - if (s->type != TOK_CLOSE) { - s->type = TOK_ERROR; - } else { - next_token(s); - } - } - break; -#endif - - case TE_FUNCTION1: -#ifndef TE_WITHOUT_CLOSURES - case TE_CLOSURE1: -#endif - ret = new_expr(s->type, 0); - ret->v.any = s->v.any; -#ifndef TE_WITHOUT_CLOSURES - if (IS_CLOSURE(s->type)) ret->parameters[1] = s->context; -#endif - next_token(s); - ret->parameters[0] = power(s); - break; - - case TE_FUNCTION2: case TE_FUNCTION3: -#if TE_MAX_FUNCTION_ARITY >= 4 - case TE_FUNCTION4: -#endif -#if TE_MAX_FUNCTION_ARITY >= 5 - case TE_FUNCTION5: -#endif -#if TE_MAX_FUNCTION_ARITY >= 6 - case TE_FUNCTION6: -#endif -#if TE_MAX_FUNCTION_ARITY == 7 - case TE_FUNCTION7: -#endif -#ifndef TE_WITHOUT_CLOSURES - case TE_CLOSURE2: case TE_CLOSURE3: case TE_CLOSURE4: - case TE_CLOSURE5: case TE_CLOSURE6: case TE_CLOSURE7: -#endif - arity = ARITY(s->type); - - ret = new_expr(s->type, 0); - ret->v.any = s->v.any; -#ifndef TE_WITHOUT_CLOSURES - if (IS_CLOSURE(s->type)) ret->parameters[arity] = s->context; -#endif - next_token(s); - - if (s->type != TOK_OPEN) { - s->type = TOK_ERROR; - } else { - int i; - for(i = 0; i < arity; i++) { - next_token(s); - ret->parameters[i] = eql(s); - if(s->type != TOK_SEP) { - break; - } - } - if(s->type != TOK_CLOSE || i != arity - 1) { - s->type = TOK_ERROR; - } else { - next_token(s); - } - } - - break; - - case TOK_OPEN: - next_token(s); - ret = list(s); - if (s->type != TOK_CLOSE) { - s->type = TOK_ERROR; - } else { - next_token(s); - } - break; - - default: - ret = new_expr(0, 0); - s->type = TOK_ERROR; - ret->v.value = NAN; - break; - } - - return ret; -} - - -static te_expr *power(state *s) { - /* <power> = {("-" | "+")} <base> */ - int sign = 1; - while (s->type == TOK_INFIX && (s->v.f2 == add || s->v.f2 == sub)) { - if (s->v.f2 == sub) sign = -sign; - next_token(s); - } - - te_expr *ret; - - if (sign == 1) { - ret = base(s); - } else { - ret = new_expr1(TE_FUNCTION1 | TE_FLAG_PURE, base(s)); - ret->v.f1 = negate; - } - - return ret; -} - -#ifdef TE_POW_FROM_RIGHT -static te_expr *factor(state *s) { - /* <factor> = <power> {"^" <power>} */ - te_expr *ret = power(s); - - int neg = 0; - te_expr *insertion = 0; - - if (ret->type == (TE_FUNCTION1 | TE_FLAG_PURE) && ret->v.f1 == negate) { - te_expr *se = ret->parameters[0]; - free(ret); - ret = se; - neg = 1; - } - - while (s->type == TOK_INFIX && (s->v.f2 == pow)) { - te_fun2 t = s->v.f2; - next_token(s); - - if (insertion) { - /* Make exponentiation go right-to-left. */ - te_expr *insert = new_expr2(TE_FUNCTION2 | TE_FLAG_PURE, insertion->parameters[1], power(s)); - insert->v.f2 = t; - insertion->parameters[1] = insert; - insertion = insert; - } else { - ret = new_expr2(TE_FUNCTION2 | TE_FLAG_PURE, ret, power(s)); - ret->v.f2 = t; - insertion = ret; - } - } - - if (neg) { - ret = new_expr1(TE_FUNCTION1 | TE_FLAG_PURE, ret); - ret->v.f1 = negate; - } - - return ret; -} -#else -static te_expr *factor(state *s) { - /* <factor> = <power> {"^" <power>} */ - te_expr *ret = power(s); - - while (s->type == TOK_INFIX && (s->v.f2 == pow)) { - te_fun2 t = s->v.f2; - next_token(s); - ret = new_expr2(TE_FUNCTION2 | TE_FLAG_PURE, ret, power(s)); - ret->v.f2 = t; - } - - return ret; -} -#endif - - - -static te_expr *term(state *s) { - /* <term> = <factor> {("*" | "/" | "%") <factor>} */ - te_expr *ret = factor(s); - - while (s->type == TOK_INFIX && (s->v.f2 == mul || s->v.f2 == divide || s->v.f2 == fmod)) { - te_fun2 t = s->v.f2; - next_token(s); - ret = new_expr2(TE_FUNCTION2 | TE_FLAG_PURE, ret, factor(s)); - ret->v.f2 = t; - } - - return ret; -} - - -static te_expr *expr(state *s) { - /* <expr> = <term> {("+" | "-") <term>} */ - te_expr *ret = term(s); - - while (s->type == TOK_INFIX && (s->v.f2 == add || s->v.f2 == sub)) { - te_fun2 t = s->v.f2; - next_token(s); - ret = new_expr2(TE_FUNCTION2 | TE_FLAG_PURE, ret, term(s)); - ret->v.f2 = t; - } - - return ret; -} - - -static te_expr *cmp(state *s) { - /* <cmp> = <expr> {(">" | "<" | ">=" | "<=") <expr>} */ - te_expr *ret = expr(s); - - while (s->type == TOK_INFIX - && (s->v.f2 == is_lt || s->v.f2 == is_le || s->v.f2 == is_gt || s->v.f2 == is_ge)) { - te_fun2 t = s->v.f2; - next_token(s); - ret = new_expr2(TE_FUNCTION2 | TE_FLAG_PURE, ret, expr(s)); - ret->v.f2 = t; - } - - return ret; -} - - -static te_expr *eql(state *s) { - /* <eql> = <cmp> {("==" | "!=") <cmp>} */ - te_expr *ret = cmp(s); - - while (s->type == TOK_INFIX && (s->v.f2 == is_eq || s->v.f2 == is_neq)) { - te_fun2 t = s->v.f2; - next_token(s); - ret = new_expr2(TE_FUNCTION2 | TE_FLAG_PURE, ret, cmp(s)); - ret->v.f2 = t; - } - - return ret; -} - - -static te_expr *list(state *s) { - /* <list> = <eql> {"," <eql>} */ - te_expr *ret = eql(s); - - while (s->type == TOK_SEP) { - next_token(s); - ret = new_expr2(TE_FUNCTION2 | TE_FLAG_PURE, ret, eql(s)); - ret->v.f2 = comma; - } - - return ret; -} - - -#define M(e) te_eval(n->parameters[e], base_addr) - - -double te_eval(const te_expr *n, const void* base_addr) { - if (!n) return NAN; - - switch(TYPE_MASK(n->type)) { - case TE_CONSTANT: return n->v.value; - case TE_VARIABLE: return *n->v.bound; - case TE_OFFSET: assert(base_addr); - return *(double*)(((char*)base_addr)+n->v.offset); - -#ifndef TE_WITHOUT_FUNCTION_0 - case TE_FUNCTION0: return n->v.f0(); -#endif - case TE_FUNCTION1: return n->v.f1(M(0)); - case TE_FUNCTION2: return n->v.f2(M(0), M(1)); - case TE_FUNCTION3: - if (IS_CONDITION(n->type)) return M(0) ? M(1) : M(2); - else return n->v.f3(M(0), M(1), M(2)); -#if TE_MAX_FUNCTION_ARITY >= 4 - case TE_FUNCTION4: return n->v.f4(M(0), M(1), M(2), M(3)); -#endif -#if TE_MAX_FUNCTION_ARITY >= 5 - case TE_FUNCTION5: return n->v.f5(M(0), M(1), M(2), M(3), M(4)); -#endif -#if TE_MAX_FUNCTION_ARITY >= 6 - case TE_FUNCTION6: return n->v.f6(M(0), M(1), M(2), M(3), M(4), M(5)); -#endif -#if TE_MAX_FUNCTION_ARITY == 7 - case TE_FUNCTION7: return n->v.f7(M(0), M(1), M(2), M(3), M(4), M(5), M(6)); -#endif - -#ifndef TE_WITHOUT_CLOSURES - case TE_CLOSURE0: return n->v.cl0(n->parameters[0]); - case TE_CLOSURE1: return n->v.cl1(n->parameters[1], M(0)); - case TE_CLOSURE2: return n->v.cl2(n->parameters[2], M(0), M(1)); - case TE_CLOSURE3: return n->v.cl3(n->parameters[3], M(0), M(1), M(2)); - case TE_CLOSURE4: return n->v.cl4(n->parameters[4], M(0), M(1), M(2), M(3)); - case TE_CLOSURE5: return n->v.cl5(n->parameters[5], M(0), M(1), M(2), M(3), M(4)); - case TE_CLOSURE6: return n->v.cl6(n->parameters[6], M(0), M(1), M(2), M(3), M(4), M(5)); - case TE_CLOSURE7: return n->v.cl7(n->parameters[7], M(0), M(1), M(2), M(3), M(4), M(5), M(6)); -#endif - - default: return NAN; - } - -} - -#undef M - -static int expr_equal(const te_expr* e1, const te_expr* e2) { - int i; - if (e1->type != e2->type) return 0; - if (e1->v.any != e2->v.any) return 0; - for (i = 0; i < ARITY(e1->type); i++) { - if(!expr_equal(e1->parameters[i], e2->parameters[i])) return 0; - } - return 1; -} - -static void optimize(te_expr *n) { - /* Only optimize out conditions and functions flagged as pure. */ - if (IS_CONDITION(n->type)) { - te_expr* cond = n->parameters[0]; - assert(IS_FUNCTION(n->type) && ARITY(n->type) == 3); - optimize(cond); - if (cond->type == TE_CONSTANT) { - te_expr* keep = (cond->v.value) ? n->parameters[1] : n->parameters[2]; - /* Can keep either param[1] or param[2] */ - optimize(keep); - n->type = keep->type; - n->v.any = keep->v.any; - te_free_parameters(n); - } - else { /* c ? x : x is x */ - te_expr* if_branch = n->parameters[1]; - te_expr* else_branch = n->parameters[2]; - optimize(if_branch); - optimize(else_branch); - if (expr_equal(if_branch, else_branch)) { - n->type = if_branch->type; - n->v.any = if_branch->v.any; - te_free_parameters(n); - } - } - } - else if (IS_PURE(n->type)) { - const int arity = ARITY(n->type); - int known = 1; - int i; - assert(IS_FUNCTION(n->type)); - for (i = 0; i < arity; ++i) { - optimize(n->parameters[i]); - if (((te_expr*)(n->parameters[i]))->type != TE_CONSTANT) { - known = 0; - } - } - if (known) { - const double value = te_eval(n, NULL); - te_free_parameters(n); - n->type = TE_CONSTANT; - n->v.value = value; - } - } -} - - -te_expr *te_compile(const char *expression, const te_variable *variables, int var_count, int *error) { - state s; - s.start = s.next = expression; - s.lookup = variables; - s.lookup_len = var_count; - - next_token(&s); - te_expr *root = list(&s); - - if (s.type != TOK_END) { - te_free(root); - if (error) { - *error = (int)(s.next - s.start); - if (*error == 0) *error = 1; - } - return 0; - } else { - optimize(root); - if (error) *error = 0; - return root; - } -} - - -double te_interp(const char *expression, int *error) { - te_expr *n = te_compile(expression, 0, 0, error); - double ret; - if (n) { - ret = te_eval(n, NULL); - te_free(n); - } else { - ret = NAN; - } - return ret; -} - -static void pn (const te_expr *n, int depth) { - int i, arity; - printf("%*s", depth, ""); - - switch(TYPE_MASK(n->type)) { - case TE_CONSTANT: printf("%f\n", n->v.value); break; - case TE_VARIABLE: printf("bound %p\n", (void*) n->v.bound); break; - case TE_OFFSET: printf("offset %zu\n", n->v.offset); break; - -#ifndef TE_WITHOUT_FUNCTION_0 - case TE_FUNCTION0: -#endif - case TE_FUNCTION1: case TE_FUNCTION2: case TE_FUNCTION3: -#if TE_MAX_FUNCTION_ARITY >= 4 - case TE_FUNCTION4: -#endif -#if TE_MAX_FUNCTION_ARITY >= 5 - case TE_FUNCTION5: -#endif -#if TE_MAX_FUNCTION_ARITY >= 6 - case TE_FUNCTION6: -#endif -#if TE_MAX_FUNCTION_ARITY == 7 - case TE_FUNCTION7: -#endif -#ifndef TE_WITHOUT_CLOSURES - case TE_CLOSURE0: case TE_CLOSURE1: case TE_CLOSURE2: case TE_CLOSURE3: - case TE_CLOSURE4: case TE_CLOSURE5: case TE_CLOSURE6: case TE_CLOSURE7: -#endif - arity = ARITY(n->type); - printf("f%d", arity); - for(i = 0; i < arity; i++) { - printf(" %p", n->parameters[i]); - } - printf("\n"); - for(i = 0; i < arity; i++) { - pn(n->parameters[i], depth + 1); - } - break; - } -} - - -void te_print(const te_expr *n) { - pn(n, 0); -} diff --git a/tinyexpr/tinyexpr.h b/tinyexpr/tinyexpr.h @@ -1,197 +0,0 @@ -/* - * TINYEXPR - Tiny recursive descent parser and evaluation engine in C - * - * Copyright (c) 2015-2018 Lewis Van Winkle - * - * http://CodePlea.com - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgement in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - */ - -#ifndef __TINYEXPR_H__ -#define __TINYEXPR_H__ - -#include <stddef.h> - -/* Helper macro to be used when defining a te_variable */ -#define TE_DEF_VARIABLE(Name, Var) {(Name), {.var=&(Var)}, TE_VARIABLE, NULL} -#define TE_DEF_OFFSET(Name, Offset) {(Name), {.offset=(Offset)}, TE_OFFSET, NULL} -#define TE_DEF_CONSTANT(Name, Value) {(Name), {.value=(Value)}, TE_CONSTANT, NULL} -#define TE_DEF_FUNCTION(Name, Fun, Arity) {(Name), {.f##Arity=(Fun)}, TE_FUNCTION##Arity, NULL} -#ifndef TE_WITHOUT_CLOSURES -#define TE_DEF_CLOSURE(Name, Closure, Arity, Ctx) {(Name), {.cl##Arity=(Closure)}, TE_CLOSURE##Arity, (Ctx)} -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef TE_MAX_FUNCTION_ARITY -#if !(TE_MAX_FUNCTION_ARITY >= 3 && TE_MAX_FUNCTION_ARITY <= 7) -#error Valid range for TE_MAX_FUNCTION_ARITY is [3 7] -#endif -#else -#define TE_MAX_FUNCTION_ARITY 7 -#endif - - -#ifndef TE_WITHOUT_FUNCTION_0 -#define FUN_TYPE_0 \ - double(*f0)(void); -#else -#define FUN_TYPE_0 -#endif -#define FUN_TYPES_1_3 \ - void *any;\ - double(*f1)(double);\ - double(*f2)(double, double);\ - double(*f3)(double, double, double); -#if TE_MAX_FUNCTION_ARITY >= 4 -#define FUN_TYPE_4 \ - double(*f4)(double, double, double, double); -#else -#define FUN_TYPE_4 -#endif -#if TE_MAX_FUNCTION_ARITY >= 5 -#define FUN_TYPE_5 \ - double(*f5)(double, double, double, double, double); -#else -#define FUN_TYPE_5 -#endif -#if TE_MAX_FUNCTION_ARITY >= 6 -#define FUN_TYPE_6 \ - double(*f6)(double, double, double, double, double, double); -#else -#define FUN_TYPE_6 -#endif -#if TE_MAX_FUNCTION_ARITY == 7 -#define FUN_TYPE_7 \ - double(*f7)(double, double, double, double, double, double, double); -#else -#define FUN_TYPE_7 -#endif - -#ifndef TE_WITHOUT_CLOSURES -#define CLOSURE_TYPES \ - double(*cl0)(void*);\ - double(*cl1)(void*, double);\ - double(*cl2)(void*, double, double);\ - double(*cl3)(void*, double, double, double);\ - double(*cl4)(void*, double, double, double, double);\ - double(*cl5)(void*, double, double, double, double, double);\ - double(*cl6)(void*, double, double, double, double, double, double);\ - double(*cl7)(void*, double, double, double, double, double, double, double); -#else -#define CLOSURE_TYPES -#endif - -union fun { - FUN_TYPE_0 - FUN_TYPES_1_3 - FUN_TYPE_4 - FUN_TYPE_5 - FUN_TYPE_6 - FUN_TYPE_7 - CLOSURE_TYPES -}; - -union value { - FUN_TYPE_0 - FUN_TYPES_1_3 - FUN_TYPE_4 - FUN_TYPE_5 - FUN_TYPE_6 - FUN_TYPE_7 - CLOSURE_TYPES - double value; - const double *var; - size_t offset; - const double *bound; -}; - -typedef struct te_expr { - int type; - union value v; - void *parameters[1]; -} te_expr; - - -enum { - TE_VARIABLE = 0, - TE_OFFSET = 1, - TE_CONSTANT = 2, - -#ifndef TE_WITHOUT_FUNCTION_0 - TE_FUNCTION0 = 8, -#endif - TE_FUNCTION1 = 9, TE_FUNCTION2, TE_FUNCTION3, -#if TE_MAX_FUNCTION_ARITY >= 4 - TE_FUNCTION4, -#endif -#if TE_MAX_FUNCTION_ARITY >= 5 - TE_FUNCTION5, -#endif -#if TE_MAX_FUNCTION_ARITY >= 6 - TE_FUNCTION6, -#endif -#if TE_MAX_FUNCTION_ARITY == 7 - TE_FUNCTION7, -#endif -#ifndef TE_WITHOUT_CLOSURES - TE_CLOSURE0 = 16, TE_CLOSURE1, TE_CLOSURE2, TE_CLOSURE3, - TE_CLOSURE4, TE_CLOSURE5, TE_CLOSURE6, TE_CLOSURE7, -#endif - TE_FLAG_PURE = 64 -}; - -typedef struct te_variable { - const char *name; - const union value v; - int type; - /* context could be member only if TE_WITHOUT_CLOSURES is undefined - * we don't take the opportunity as it would add too much complexity */ - void *context; -} te_variable; - - - -/* Parses the input expression, evaluates it, and frees it. */ -/* Returns NaN on error. */ -double te_interp(const char *expression, int *error); - -/* Parses the input expression and binds variables. */ -/* Returns NULL on error. */ -te_expr *te_compile(const char *expression, const te_variable *variables, int var_count, int *error); - -/* Evaluates the expression. */ -double te_eval(const te_expr *n, const void* base_addr); - -/* Prints debugging information on the syntax tree. */ -void te_print(const te_expr *n); - -/* Frees the expression. */ -/* This is safe to call on NULL pointers. */ -void te_free(te_expr *n); - -/* Duplicates a te_expr */ -te_expr* te_duplicate(te_expr* n); - -#ifdef __cplusplus -} -#endif - -#endif /*__TINYEXPR_H__*/