@sdeverywhere/cli 0.7.28 → 0.7.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/c/main.c +1 -1
- package/src/c/makefile +1 -1
- package/src/c/vensim.c +76 -22
- package/src/c/vensim.h +32 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sdeverywhere/cli",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.29",
|
|
4
4
|
"description": "Contains the `sde` command line interface for the SDEverywhere tool suite.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@sdeverywhere/build": "^0.3.7",
|
|
15
|
-
"@sdeverywhere/compile": "^0.7.
|
|
15
|
+
"@sdeverywhere/compile": "^0.7.22",
|
|
16
16
|
"bufx": "^1.0.5",
|
|
17
17
|
"byline": "^5.0.0",
|
|
18
18
|
"ramda": "^0.27.0",
|
package/src/c/main.c
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
int main(int argc, char** argv) {
|
|
4
4
|
// TODO make the input buffer size dynamic
|
|
5
|
-
char inputs[
|
|
5
|
+
char inputs[500000];
|
|
6
6
|
// When true, output data without newlines or a header, suitable for embedding reference data.
|
|
7
7
|
bool raw_output = false;
|
|
8
8
|
// When true, suppress data output when using PR* macros.
|
package/src/c/makefile
CHANGED
package/src/c/vensim.c
CHANGED
|
@@ -56,25 +56,79 @@ double _ZIDZ(double a, double b) {
|
|
|
56
56
|
Lookup* __new_lookup(size_t size, bool copy, double* data) {
|
|
57
57
|
// Make a new Lookup with "size" number of pairs given in x, y order in a flattened list.
|
|
58
58
|
Lookup* lookup = malloc(sizeof(Lookup));
|
|
59
|
-
lookup->
|
|
60
|
-
lookup->
|
|
61
|
-
lookup->data_is_owned = copy;
|
|
59
|
+
lookup->original_size = size;
|
|
60
|
+
lookup->original_data_is_owned = copy;
|
|
62
61
|
if (copy) {
|
|
63
|
-
// Copy
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
// Copy the given lookup data into an internally managed buffer.
|
|
63
|
+
size_t data_length_in_bytes = size * 2 * sizeof(double);
|
|
64
|
+
lookup->original_data = malloc(data_length_in_bytes);
|
|
65
|
+
memcpy(lookup->original_data, data, data_length_in_bytes);
|
|
66
66
|
} else {
|
|
67
67
|
// Store a pointer to the lookup data (assumed to be static or owned elsewhere).
|
|
68
|
-
lookup->
|
|
68
|
+
lookup->original_data = data;
|
|
69
69
|
}
|
|
70
|
+
// Set the original data as "active".
|
|
71
|
+
lookup->active_data = lookup->original_data;
|
|
72
|
+
lookup->active_size = lookup->original_size;
|
|
73
|
+
// Set `dynamic_data` to NULL initially; it will be allocated on demand if lookup
|
|
74
|
+
// data is overridden at runtime using `__set_lookup`.
|
|
75
|
+
lookup->dynamic_data = NULL;
|
|
76
|
+
lookup->dynamic_data_length = 0;
|
|
77
|
+
lookup->dynamic_size = 0;
|
|
78
|
+
// Set `inverted_data` to NULL initially; it will be allocated on demand in case
|
|
79
|
+
// of `LOOKUP INVERT` calls.
|
|
80
|
+
lookup->inverted_data = NULL;
|
|
81
|
+
// Set the cached "last" values to the initial values.
|
|
70
82
|
lookup->last_input = DBL_MAX;
|
|
71
83
|
lookup->last_hit_index = 0;
|
|
72
84
|
return lookup;
|
|
73
85
|
}
|
|
86
|
+
void __set_lookup(Lookup* lookup, size_t size, double* data) {
|
|
87
|
+
// Set new data for the given `Lookup`. If `data` is NULL, the original data that was
|
|
88
|
+
// supplied to the `__new_lookup` call will be restored as the "active" data. Otherwise,
|
|
89
|
+
// `data` will be copied to an internal data buffer, which will be the "active" data.
|
|
90
|
+
// If `size` is greater than the size passed to previous calls, the internal data buffer
|
|
91
|
+
// will be grown as needed.
|
|
92
|
+
if (lookup == NULL) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (data != NULL) {
|
|
96
|
+
// Allocate or grow the internal buffer as needed.
|
|
97
|
+
size_t data_length_in_elems = size * 2;
|
|
98
|
+
size_t data_length_in_bytes = data_length_in_elems * sizeof(double);
|
|
99
|
+
if (data_length_in_elems > lookup->dynamic_data_length) {
|
|
100
|
+
lookup->dynamic_data = malloc(data_length_in_bytes);
|
|
101
|
+
lookup->dynamic_data_length = data_length_in_elems;
|
|
102
|
+
}
|
|
103
|
+
// Copy the given lookup data into the internally managed buffer.
|
|
104
|
+
lookup->dynamic_size = size;
|
|
105
|
+
if (data_length_in_bytes > 0) {
|
|
106
|
+
memcpy(lookup->dynamic_data, data, data_length_in_bytes);
|
|
107
|
+
}
|
|
108
|
+
// Set the dynamic data as the "active" data.
|
|
109
|
+
lookup->active_data = lookup->dynamic_data;
|
|
110
|
+
lookup->active_size = lookup->dynamic_size;
|
|
111
|
+
} else {
|
|
112
|
+
// Restore the original data as the "active" data.
|
|
113
|
+
lookup->active_data = lookup->original_data;
|
|
114
|
+
lookup->active_size = lookup->original_size;
|
|
115
|
+
}
|
|
116
|
+
// Clear the cached inverted data, if needed.
|
|
117
|
+
if (lookup->inverted_data) {
|
|
118
|
+
free(lookup->inverted_data);
|
|
119
|
+
lookup->inverted_data = NULL;
|
|
120
|
+
}
|
|
121
|
+
// Reset the cached "last" values to the initial values.
|
|
122
|
+
lookup->last_input = DBL_MAX;
|
|
123
|
+
lookup->last_hit_index = 0;
|
|
124
|
+
}
|
|
74
125
|
void __delete_lookup(Lookup* lookup) {
|
|
75
126
|
if (lookup) {
|
|
76
|
-
if (lookup->
|
|
77
|
-
free(lookup->
|
|
127
|
+
if (lookup->original_data && lookup->original_data_is_owned) {
|
|
128
|
+
free(lookup->original_data);
|
|
129
|
+
}
|
|
130
|
+
if (lookup->dynamic_data) {
|
|
131
|
+
free(lookup->dynamic_data);
|
|
78
132
|
}
|
|
79
133
|
if (lookup->inverted_data) {
|
|
80
134
|
free(lookup->inverted_data);
|
|
@@ -84,8 +138,8 @@ void __delete_lookup(Lookup* lookup) {
|
|
|
84
138
|
}
|
|
85
139
|
void __print_lookup(Lookup* lookup) {
|
|
86
140
|
if (lookup) {
|
|
87
|
-
for (size_t i = 0; i < lookup->
|
|
88
|
-
printf("(%g, %g)\n", *(lookup->
|
|
141
|
+
for (size_t i = 0; i < lookup->active_size; i++) {
|
|
142
|
+
printf("(%g, %g)\n", *(lookup->active_data + 2 * i), *(lookup->active_data + 2 * i + 1));
|
|
89
143
|
}
|
|
90
144
|
}
|
|
91
145
|
}
|
|
@@ -94,12 +148,12 @@ double __lookup(Lookup* lookup, double input, bool use_inverted_data, LookupMode
|
|
|
94
148
|
// Interpolate the y value from an array of (x,y) pairs.
|
|
95
149
|
// NOTE: The x values are assumed to be monotonically increasing.
|
|
96
150
|
|
|
97
|
-
if (lookup == NULL || lookup->
|
|
151
|
+
if (lookup == NULL || lookup->active_size == 0) {
|
|
98
152
|
return _NA_;
|
|
99
153
|
}
|
|
100
154
|
|
|
101
|
-
const double* data = use_inverted_data ? lookup->inverted_data : lookup->
|
|
102
|
-
const size_t max = (lookup->
|
|
155
|
+
const double* data = use_inverted_data ? lookup->inverted_data : lookup->active_data;
|
|
156
|
+
const size_t max = (lookup->active_size) * 2;
|
|
103
157
|
|
|
104
158
|
// Use the cached values for improved lookup performance, except in the case
|
|
105
159
|
// of `LOOKUP INVERT` (since it may not be accurate if calls flip back and forth
|
|
@@ -166,12 +220,12 @@ double __get_data_between_times(Lookup* lookup, double input, LookupMode mode) {
|
|
|
166
220
|
// Interpolate the y value from an array of (x,y) pairs.
|
|
167
221
|
// NOTE: The x values are assumed to be monotonically increasing.
|
|
168
222
|
|
|
169
|
-
if (lookup == NULL || lookup->
|
|
223
|
+
if (lookup == NULL || lookup->active_size == 0) {
|
|
170
224
|
return _NA_;
|
|
171
225
|
}
|
|
172
226
|
|
|
173
|
-
const double* data = lookup->
|
|
174
|
-
const size_t n = lookup->
|
|
227
|
+
const double* data = lookup->active_data;
|
|
228
|
+
const size_t n = lookup->active_size;
|
|
175
229
|
const size_t max = n * 2;
|
|
176
230
|
|
|
177
231
|
switch (mode) {
|
|
@@ -248,10 +302,10 @@ double __get_data_between_times(Lookup* lookup, double input, LookupMode mode) {
|
|
|
248
302
|
double _LOOKUP_INVERT(Lookup* lookup, double y) {
|
|
249
303
|
if (lookup->inverted_data == NULL) {
|
|
250
304
|
// Invert the matrix and cache it.
|
|
251
|
-
lookup->inverted_data = malloc(sizeof(double) * 2 * lookup->
|
|
252
|
-
double* pLookup = lookup->
|
|
305
|
+
lookup->inverted_data = malloc(sizeof(double) * 2 * lookup->active_size);
|
|
306
|
+
double* pLookup = lookup->active_data;
|
|
253
307
|
double* pInvert = lookup->inverted_data;
|
|
254
|
-
for (size_t i = 0; i < lookup->
|
|
308
|
+
for (size_t i = 0; i < lookup->active_size; i++) {
|
|
255
309
|
*pInvert++ = *(pLookup + 1);
|
|
256
310
|
*pInvert++ = *pLookup;
|
|
257
311
|
pLookup += 2;
|
|
@@ -261,12 +315,12 @@ double _LOOKUP_INVERT(Lookup* lookup, double y) {
|
|
|
261
315
|
}
|
|
262
316
|
|
|
263
317
|
double _GAME(Lookup* lookup, double default_value) {
|
|
264
|
-
if (lookup == NULL || lookup->
|
|
318
|
+
if (lookup == NULL || lookup->active_size == 0) {
|
|
265
319
|
// The lookup is NULL or empty, so return the default value
|
|
266
320
|
return default_value;
|
|
267
321
|
}
|
|
268
322
|
|
|
269
|
-
double x0 = lookup->
|
|
323
|
+
double x0 = lookup->active_data[0];
|
|
270
324
|
if (_time < x0) {
|
|
271
325
|
// The current time is earlier than the first data point, so return the
|
|
272
326
|
// default value
|
package/src/c/vensim.h
CHANGED
|
@@ -54,15 +54,44 @@ typedef enum {
|
|
|
54
54
|
} LookupMode;
|
|
55
55
|
|
|
56
56
|
typedef struct {
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
// The pointer to the active data buffer. This will be the same as either
|
|
58
|
+
// `original_data` or `dynamic_data`, depending on whether the lookup data
|
|
59
|
+
// is overridden at runtime using `__set_lookup`.
|
|
60
|
+
double* active_data;
|
|
61
|
+
// The size (i.e., number of pairs) of the active data.
|
|
62
|
+
size_t active_size;
|
|
63
|
+
|
|
64
|
+
// The pointer to the original data buffer.
|
|
65
|
+
double* original_data;
|
|
66
|
+
// The size (i.e., number of pairs) of the original data.
|
|
67
|
+
size_t original_size;
|
|
68
|
+
// Whether the `original_data` is owned by this `Lookup` instance. If `true`,
|
|
69
|
+
// the `original_data` buffer will be freed by `__delete_lookup`.
|
|
70
|
+
bool original_data_is_owned;
|
|
71
|
+
|
|
72
|
+
// The pointer to the dynamic data buffer. This will be NULL initially,
|
|
73
|
+
// and the buffer will be allocated (or grown) by `__set_lookup`.
|
|
74
|
+
double* dynamic_data;
|
|
75
|
+
// The size (i.e., number of pairs) of the dynamic data.
|
|
76
|
+
size_t dynamic_size;
|
|
77
|
+
// The number of elements in the dynamic data buffer. The buffer will grow
|
|
78
|
+
// as needed, so this can be greater than `2 * dynamic_size`.
|
|
79
|
+
size_t dynamic_data_length;
|
|
80
|
+
|
|
81
|
+
// The inverted version of the active data buffer. This is allocated on demand
|
|
82
|
+
// only in the case of `LOOKUP INVERT` function calls.
|
|
59
83
|
double* inverted_data;
|
|
60
|
-
|
|
84
|
+
|
|
85
|
+
// The input value for the last hit. This is cached for performance so that we
|
|
86
|
+
// can reduce the amount of linear searching in the common case where `LOOKUP`
|
|
87
|
+
// input values are monotonically increasing.
|
|
61
88
|
double last_input;
|
|
89
|
+
// The index for the last hit (see `last_input`).
|
|
62
90
|
size_t last_hit_index;
|
|
63
91
|
} Lookup;
|
|
64
92
|
|
|
65
93
|
Lookup* __new_lookup(size_t size, bool copy, double* data);
|
|
94
|
+
void __set_lookup(Lookup* lookup, size_t size, double* data);
|
|
66
95
|
void __delete_lookup(Lookup* lookup);
|
|
67
96
|
void __print_lookup(Lookup* lookup);
|
|
68
97
|
|