1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-09 15:10:29 +02:00
guile/gc-options.c
2023-02-28 09:40:28 +01:00

181 lines
6 KiB
C

#include <limits.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#define GC_IMPL 1
#include "gc-options-internal.h"
#include "gc-platform.h"
// M(UPPER, lower, repr, parser, default, min, max)
#define FOR_EACH_INT_GC_OPTION(M) \
M(HEAP_SIZE_POLICY, heap_size_policy, "heap-size-policy", \
int, GC_HEAP_SIZE_FIXED, GC_HEAP_SIZE_FIXED, GC_HEAP_SIZE_ADAPTIVE) \
M(PARALLELISM, parallelism, "parallelism", \
int, default_parallelism(), 1, 64)
#define FOR_EACH_SIZE_GC_OPTION(M) \
M(HEAP_SIZE, heap_size, "heap-size", \
size, 6 * 1024 * 1024, 0, -1) \
M(MAXIMUM_HEAP_SIZE, maximum_heap_size, "maximum-heap-size", \
size, 0, 0, -1)
#define FOR_EACH_DOUBLE_GC_OPTION(M) \
M(HEAP_SIZE_MULTIPLIER, heap_size_multiplier, "heap-size-multiplier", \
double, 1.75, 1.0, 1e6) \
M(HEAP_FRUGALITY, heap_frugality, "heap-frugality", \
double, 1e-1, 1e-6, 1e6)
typedef int gc_option_int;
typedef size_t gc_option_size;
typedef double gc_option_double;
#define FOR_EACH_COMMON_GC_OPTION(M) \
FOR_EACH_INT_GC_OPTION(M) \
FOR_EACH_SIZE_GC_OPTION(M) \
FOR_EACH_DOUBLE_GC_OPTION(M)
static int clamp_int(int n, int lo, int hi) {
return n < lo ? lo : n > hi ? hi : n;
}
static size_t clamp_size(size_t n, size_t lo, size_t hi) {
return n < lo ? lo : n > hi ? hi : n;
}
static double clamp_double(double n, double lo, double hi) {
return n < lo ? lo : n > hi ? hi : n;
}
static int default_parallelism(void) {
return clamp_int(gc_platform_processor_count(), 1, 8);
}
void gc_init_common_options(struct gc_common_options *options) {
#define INIT(UPPER, lower, repr, parser, default, min, max) \
options->lower = default;
FOR_EACH_COMMON_GC_OPTION(INIT)
#undef INIT
}
int gc_common_option_from_string(const char *str) {
#define GET_OPTION(UPPER, lower, repr, parser, default, min, max) \
if (strcmp(str, repr) == 0) return GC_OPTION_##UPPER;
FOR_EACH_COMMON_GC_OPTION(GET_OPTION)
#undef GET_OPTION
return -1;
}
#define SET_OPTION(UPPER, lower, repr, parser, default, min, max) \
case GC_OPTION_##UPPER: \
if (value != clamp_##parser(value, min, max)) return 0; \
options->lower = value; \
return 1;
#define DEFINE_SETTER(STEM, stem, type) \
int gc_common_options_set_##stem(struct gc_common_options *options, \
int option, type value) { \
switch (option) { \
FOR_EACH_##STEM##_GC_OPTION(SET_OPTION) \
default: return 0; \
} \
}
DEFINE_SETTER(INT, int, int)
DEFINE_SETTER(SIZE, size, size_t)
DEFINE_SETTER(DOUBLE, double, double)
#undef SET_OPTION
#undef DEFINE_SETTER
static int parse_size(const char *arg, size_t *val) {
char *end;
long i = strtol(arg, &end, 0);
if (i < 0 || i == LONG_MAX) return 0;
if (end == arg) return 0;
char delim = *end;
if (delim == 'k' || delim == 'K')
++end, i *= 1024L;
else if (delim == 'm' || delim == 'M')
++end, i *= 1024L * 1024L;
else if (delim == 'g' || delim == 'G')
++end, i *= 1024L * 1024L * 1024L;
else if (delim == 't' || delim == 'T')
++end, i *= 1024L * 1024L * 1024L * 1024L;
if (*end != '\0') return 0;
*val = i;
return 1;
}
static int parse_int(const char *arg, int *val) {
char *end;
long i = strtol(arg, &end, 0);
if (i == LONG_MIN || i == LONG_MAX || end == arg || *end)
return 0;
*val = i;
return 1;
}
static int parse_double(const char *arg, double *val) {
char *end;
double d = strtod(arg, &end);
if (end == arg || *end)
return 0;
*val = d;
return 1;
}
int gc_common_options_parse_and_set(struct gc_common_options *options,
int option, const char *value) {
switch (option) {
#define SET_OPTION(UPPER, lower, repr, parser, default, min, max) \
case GC_OPTION_##UPPER: { \
gc_option_##parser v; \
if (!parse_##parser(value, &v)) return 0; \
return gc_common_options_set_##parser(options, option, v); \
}
FOR_EACH_COMMON_GC_OPTION(SET_OPTION)
default: return 0;
}
}
static int is_lower(char c) { return 'a' <= c && c <= 'z'; }
static int is_digit(char c) { return '0' <= c && c <= '9'; }
static int is_option(char c) { return is_lower(c) || c == '-'; }
static int is_option_end(char c) { return c == '='; }
static int is_value(char c) {
return is_lower(c) || is_digit(c) || c == '-' || c == '+' || c == '.';
}
static int is_value_end(char c) { return c == '\0' || c == ','; }
static char* read_token(char *p, int (*is_tok)(char c), int (*is_end)(char c),
char *delim) {
char c;
for (c = *p; is_tok(c); c = *++p);
if (!is_end(c)) return NULL;
*delim = c;
*p = '\0';
return p + 1;
}
int gc_options_parse_and_set_many(struct gc_options *options,
const char *str) {
if (!*str) return 1;
char *copy = strdup(str);
char *cur = copy;
int ret = 0;
while (1) {
char delim;
char *next = read_token(cur, is_option, is_option_end, &delim);
if (!next) break;
int option = gc_option_from_string(cur);
if (option < 0) break;
cur = next;
next = read_token(cur, is_value, is_value_end, &delim);
if (!next) break;
if (!gc_options_parse_and_set(options, option, cur)) break;
cur = next;
if (delim == '\0') {
ret = 1;
break;
}
}
free(copy);
return ret;
}