Lichen

templates/native/float.c

881:31053f0bb63b
2019-01-27 Paul Boddie Experiment with a statically-allocated table of preallocated instances, also marking the instances as "atomic". float-preallocation
     1 /* Native functions for floating point operations.     2      3 Copyright (C) 2016, 2017, 2018, 2019 Paul Boddie <paul@boddie.org.uk>     4      5 This program is free software; you can redistribute it and/or modify it under     6 the terms of the GNU General Public License as published by the Free Software     7 Foundation; either version 3 of the License, or (at your option) any later     8 version.     9     10 This program is distributed in the hope that it will be useful, but WITHOUT    11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS    12 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more    13 details.    14     15 You should have received a copy of the GNU General Public License along with    16 this program.  If not, see <http://www.gnu.org/licenses/>.    17 */    18     19 #include <math.h>   /* pow */    20 #include <stdio.h>  /* snprintf */    21 #include <errno.h>  /* errno */    22 #include "native/common.h"    23 #include "types.h"    24 #include "exceptions.h"    25 #include "ops.h"    26 #include "progconsts.h"    27 #include "progops.h"    28 #include "progtypes.h"    29 #include "main.h"    30     31 /* A table of preallocated float instances. */    32     33 #define NUM_PREALLOCATED 1000    34     35 __ref preallocated_floats[NUM_PREALLOCATED];    36     37 static int floats_left = 0;    38     39 /* Preallocate some float instances. */    40     41 static void preallocate_floats()    42 {    43     int i;    44     45     for (i = 0; i < NUM_PREALLOCATED; i++)    46     {    47         /* Allocate a float for each table entry. */    48     49         preallocated_floats[i] = \    50             __ALLOCATEIM(1, __INSTANCESIZE(__builtins___float_float));    51     }    52     53     floats_left = NUM_PREALLOCATED;    54 }    55     56 static __attr new_float(double n)    57 {    58     __ref obj;    59     __attr attr;    60     61     if (!floats_left)    62         preallocate_floats();    63     64     floats_left--;    65     obj = preallocated_floats[floats_left];    66     67     /* Initialise the instance. */    68     69     __init(obj, &__INSTANCETABLE(__builtins___float_float),    70                 &__builtins___float_float);    71     72     /* Populate the float with the value. */    73     74     attr = __ATTRVALUE(obj);    75     __set_trailing_data(attr, __builtins___float_float, n);    76     77     return attr;    78 }    79     80 /* Conversion of trailing data to a double-precision floating point number. */    81     82 static double __TOFLOAT(__attr attr)    83 {    84     return __get_trailing_data(attr, __builtins___float_float);    85 }    86     87 /* Numeric formatting using snprintf.    88    NOTE: This might be moved elsewhere and used by other types. */    89     90 static __attr format_number(double n, int size)    91 {    92     char *s = (char *) __ALLOCATE(size, sizeof(char));    93     int digits;    94     95     /* Allocation should raise a memory error if it fails, so this loop should    96        terminate via the return statement or an allocation failure. */    97     98     while (1)    99     {   100         digits = snprintf(s, size, "%f", n);   101    102         if (digits < size)   103         {   104             s = (char *) __REALLOCATE(s, (digits + 1) * sizeof(char));   105             return __new_str(s, digits);   106         }   107    108         size = digits + 1;   109         s = (char *) __REALLOCATE(s, size * sizeof(char));   110     }   111    112     return __NULL;   113 }   114    115 /* Floating point operations. Exceptions are raised in the signal handler. */   116    117 __attr __fn_native_float_float_add(__attr __self, __attr self, __attr other)   118 {   119     /* self and other interpreted as float */   120     double i = __TOFLOAT(self);   121     double j = __TOFLOAT(other);   122     return new_float(i + j);   123 }   124    125 __attr __fn_native_float_float_sub(__attr __self, __attr self, __attr other)   126 {   127     /* self and other interpreted as float */   128     double i = __TOFLOAT(self);   129     double j = __TOFLOAT(other);   130     return new_float(i - j);   131 }   132    133 __attr __fn_native_float_float_mul(__attr __self, __attr self, __attr other)   134 {   135     /* self and other interpreted as float */   136     double i = __TOFLOAT(self);   137     double j = __TOFLOAT(other);   138     return new_float(i * j);   139 }   140    141 __attr __fn_native_float_float_div(__attr __self, __attr self, __attr other)   142 {   143     /* self and other interpreted as float */   144     double i = __TOFLOAT(self);   145     double j = __TOFLOAT(other);   146     return new_float(i / j);   147 }   148    149 __attr __fn_native_float_float_mod(__attr __self, __attr self, __attr other)   150 {   151     /* self and other interpreted as float */   152     double i = __TOFLOAT(self);   153     double j = __TOFLOAT(other);   154     return new_float(fmod(i, j));   155 }   156    157 __attr __fn_native_float_float_neg(__attr __self, __attr self)   158 {   159     /* self interpreted as float */   160     double i = __TOFLOAT(self);   161     return new_float(-i);   162 }   163    164 __attr __fn_native_float_float_pow(__attr __self, __attr self, __attr other)   165 {   166     /* self and other interpreted as float */   167     double i = __TOFLOAT(self);   168     double j = __TOFLOAT(other);   169     double result;   170    171     errno = 0;   172     result = pow(i, j);   173    174     /* Test for overflow. */   175    176     if (errno == ERANGE)   177         __raise_overflow_error();   178    179     /* Return the result. */   180     return new_float(result);   181 }   182    183 __attr __fn_native_float_float_le(__attr __self, __attr self, __attr other)   184 {   185     /* self and other interpreted as float */   186     double i = __TOFLOAT(self);   187     double j = __TOFLOAT(other);   188    189     /* Return a boolean result. */   190     return i <= j ? __builtins___boolean_True : __builtins___boolean_False;   191 }   192    193 __attr __fn_native_float_float_lt(__attr __self, __attr self, __attr other)   194 {   195     /* self and other interpreted as float */   196     double i = __TOFLOAT(self);   197     double j = __TOFLOAT(other);   198    199     /* Return a boolean result. */   200     return i < j ? __builtins___boolean_True : __builtins___boolean_False;   201 }   202    203 __attr __fn_native_float_float_ge(__attr __self, __attr self, __attr other)   204 {   205     /* self and other interpreted as float */   206     double i = __TOFLOAT(self);   207     double j = __TOFLOAT(other);   208    209     /* Return a boolean result. */   210     return i >= j ? __builtins___boolean_True : __builtins___boolean_False;   211 }   212    213 __attr __fn_native_float_float_gt(__attr __self, __attr self, __attr other)   214 {   215     /* self and other interpreted as float */   216     double i = __TOFLOAT(self);   217     double j = __TOFLOAT(other);   218    219     /* Return a boolean result. */   220     return i > j ? __builtins___boolean_True : __builtins___boolean_False;   221 }   222    223 __attr __fn_native_float_float_eq(__attr __self, __attr self, __attr other)   224 {   225     /* self and other interpreted as float */   226     double i = __TOFLOAT(self);   227     double j = __TOFLOAT(other);   228    229     /* Return a boolean result. */   230     return i == j ? __builtins___boolean_True : __builtins___boolean_False;   231 }   232    233 __attr __fn_native_float_float_ne(__attr __self, __attr self, __attr other)   234 {   235     /* self and other interpreted as float */   236     double i = __TOFLOAT(self);   237     double j = __TOFLOAT(other);   238    239     /* Return a boolean result. */   240     return i != j ? __builtins___boolean_True : __builtins___boolean_False;   241 }   242    243 __attr __fn_native_float_float_str(__attr __self, __attr self)   244 {   245     /* self interpreted as float */   246     double i = __TOFLOAT(self);   247    248     /* Return a new string. */   249     return format_number(i, 64);   250 }   251    252 __attr __fn_native_float_float_int(__attr __self, __attr self)   253 {   254     /* self interpreted as float */   255     double i = __TOFLOAT(self);   256    257     /* NOTE: Test for conversion failure. */   258     return __new_int((int) i);   259 }   260    261 /* Module initialisation. */   262    263 void __main_native_float()   264 {   265 }