summaryrefslogtreecommitdiffstats
path: root/byterun/ints.c
diff options
context:
space:
mode:
Diffstat (limited to 'byterun/ints.c')
-rw-r--r--byterun/ints.c445
1 files changed, 391 insertions, 54 deletions
diff --git a/byterun/ints.c b/byterun/ints.c
index 6019fd01e..d6afe0976 100644
--- a/byterun/ints.c
+++ b/byterun/ints.c
@@ -15,66 +15,93 @@
#include <stdio.h>
#include <string.h>
#include "alloc.h"
+#include "custom.h"
#include "fail.h"
+#include "intext.h"
#include "memory.h"
#include "misc.h"
#include "mlvalues.h"
-value int_of_string(value s) /* ML */
+static char * parse_sign_and_base(char * p,
+ /*out*/ int * base,
+ /*out*/ int * sign)
{
- long res;
- int sign;
- int base;
- char * p;
- int c, d;
-
- p = String_val(s);
- if (*p == 0) failwith("int_of_string");
- sign = 1;
+ *sign = 1;
if (*p == '-') {
- sign = -1;
+ *sign = -1;
p++;
}
- base = 10;
+ *base = 10;
if (*p == '0') {
switch (p[1]) {
case 'x': case 'X':
- base = 16; p += 2; break;
+ *base = 16; p += 2; break;
case 'o': case 'O':
- base = 8; p += 2; break;
+ *base = 8; p += 2; break;
case 'b': case 'B':
- base = 2; p += 2; break;
+ *base = 2; p += 2; break;
}
}
- res = 0;
- while (1) {
- c = *p;
- if (c >= '0' && c <= '9')
- d = c - '0';
- else if (c >= 'A' && c <= 'F')
- d = c - 'A' + 10;
- else if (c >= 'a' && c <= 'f')
- d = c - 'a' + 10;
- else
- break;
- if (d >= base) break;
+ return p;
+}
+
+static int parse_digit(char * p)
+{
+ int c = *p;
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ else if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ else if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ else
+ return -1;
+}
+
+static long parse_long(char * p)
+{
+ unsigned long res;
+ int sign, base, d;
+
+ p = parse_sign_and_base(p, &base, &sign);
+ for (res = 0; /*nothing*/; p++) {
+ d = parse_digit(p);
+ if (d < 0) break;
res = base * res + d;
- p++;
}
- if (*p != 0)
- failwith("int_of_string");
- return Val_long(sign < 0 ? -res : res);
+ if (*p != 0) failwith("int_of_string");
+ return sign < 0 ? -((long) res) : (long) res;
}
-value format_int(value fmt, value arg) /* ML */
+value int_of_string(value s) /* ML */
{
- char format_string[32], format_buffer[32];
- int prec;
+ return Val_long(parse_long(String_val(s)));
+}
+
+#define FORMAT_BUFFER_SIZE 32
+
+static char * parse_format(value fmt,
+ char * suffix,
+ char format_string[],
+ char default_format_buffer[])
+{
+ int prec, lastletter;
char * p;
- char * dest;
- mlsize_t len;
- value res;
+ mlsize_t len, len_suffix;
+ /* Copy Caml format fmt to format_string,
+ adding the suffix before the last letter of the format */
+ len = string_length(fmt);
+ len_suffix = strlen(suffix);
+ if (len + len_suffix + 1 >= FORMAT_BUFFER_SIZE)
+ invalid_argument("format_int: format too long");
+ bcopy(String_val(fmt), format_string, len);
+ p = format_string + len - 1;
+ lastletter = *p;
+ bcopy(suffix, p, len_suffix); p += len_suffix;
+ *p++ = lastletter;
+ *p = 0;
+ /* Determine space needed for result and allocate it dynamically if needed */
prec = 32;
for (p = String_val(fmt); *p != 0; p++) {
if (*p >= '0' && *p <= '9') {
@@ -82,22 +109,332 @@ value format_int(value fmt, value arg) /* ML */
break;
}
}
- if (prec <= sizeof(format_buffer)) {
- dest = format_buffer;
- } else {
- dest = stat_alloc(prec);
- }
- len = string_length(fmt);
- if (len >= sizeof(format_string) - 1)
- invalid_argument("format_int: format too long");
- bcopy(String_val(fmt), format_string, len);
- format_string[len + 1] = 0;
- format_string[len] = format_string[len - 1];
- format_string[len - 1] = 'l';
- sprintf(dest, format_string, Long_val(arg));
- res = copy_string(dest);
- if (dest != format_buffer) {
- stat_free(dest);
- }
+ if (prec < FORMAT_BUFFER_SIZE)
+ return default_format_buffer;
+ else
+ return stat_alloc(prec + 1);
+}
+
+value format_int(value fmt, value arg) /* ML */
+{
+ char format_string[32], default_format_buffer[32];
+ char * buffer;
+ value res;
+
+ buffer = parse_format(fmt, "l", format_string, default_format_buffer);
+ sprintf(buffer, format_string, Long_val(arg));
+ res = copy_string(buffer);
+ if (buffer != default_format_buffer) stat_free(buffer);
+ return res;
+}
+
+/* 32-bit integers */
+
+static int int32_compare(value v1, value v2)
+{
+ int32 i1 = Int32_val(v1);
+ int32 i2 = Int32_val(v2);
+ return i1 == i2 ? 0 : i1 < i2 ? -1 : 1;
+}
+
+static long int32_hash(value v)
+{
+ return Int32_val(v);
+}
+
+static void int32_serialize(value v, unsigned long * wsize_32,
+ unsigned long * wsize_64)
+{
+ serialize_int_4(Int32_val(v));
+ *wsize_32 = *wsize_64 = 4;
+}
+
+static unsigned long int32_deserialize(void * dst)
+{
+ *((int32 *) dst) = deserialize_sint_4();
+ return 4;
+}
+
+static struct custom_operations int32_ops = {
+ "_i",
+ custom_finalize_default,
+ int32_compare,
+ int32_hash,
+ int32_serialize,
+ int32_deserialize
+};
+
+value copy_int32(int32 i)
+{
+ value res = alloc_custom(&int32_ops, 4, 0, 1);
+ Int32_val(res) = i;
+ return res;
+}
+
+value int32_neg(value v) /* ML */
+{ return copy_int32(- Int32_val(v)); }
+
+value int32_add(value v1, value v2) /* ML */
+{ return copy_int32(Int32_val(v1) + Int32_val(v2)); }
+
+value int32_sub(value v1, value v2) /* ML */
+{ return copy_int32(Int32_val(v1) - Int32_val(v2)); }
+
+value int32_mul(value v1, value v2) /* ML */
+{ return copy_int32(Int32_val(v1) * Int32_val(v2)); }
+
+value int32_div(value v1, value v2) /* ML */
+{
+ int32 divisor = Int32_val(v2);
+ if (divisor == 0) raise_zero_divide();
+ return copy_int32(Int32_val(v1) / divisor);
+}
+
+value int32_mod(value v1, value v2) /* ML */
+{
+ int32 divisor = Int32_val(v2);
+ if (divisor == 0) raise_zero_divide();
+ return copy_int32(Int32_val(v1) % divisor);
+}
+
+value int32_and(value v1, value v2) /* ML */
+{ return copy_int32(Int32_val(v1) & Int32_val(v2)); }
+
+value int32_or(value v1, value v2) /* ML */
+{ return copy_int32(Int32_val(v1) | Int32_val(v2)); }
+
+value int32_xor(value v1, value v2) /* ML */
+{ return copy_int32(Int32_val(v1) ^ Int32_val(v2)); }
+
+value int32_shift_left(value v1, value v2) /* ML */
+{ return copy_int32(Int32_val(v1) << Int_val(v2)); }
+
+value int32_shift_right(value v1, value v2) /* ML */
+{ return copy_int32(Int32_val(v1) >> Int_val(v2)); }
+
+value int32_shift_right_unsigned(value v1, value v2) /* ML */
+{ return copy_int32((uint32)Int32_val(v1) >> Int_val(v2)); }
+
+value int32_of_int(value v) /* ML */
+{ return copy_int32(Long_val(v)); }
+
+value int32_to_int(value v) /* ML */
+{ return Val_long(Int32_val(v)); }
+
+value format_int32(value fmt, value arg) /* ML */
+{
+ char format_string[32], default_format_buffer[32];
+ char * buffer;
+ value res;
+
+ buffer = parse_format(fmt, "l", format_string, default_format_buffer);
+ sprintf(buffer, format_string, (long) Int32_val(arg));
+ res = copy_string(buffer);
+ if (buffer != default_format_buffer) stat_free(buffer);
+ return res;
+}
+
+value int32_of_string(value s) /* ML */
+{
+ return copy_int32(parse_long(String_val(s)));
+}
+
+/* 64-bit integers */
+
+#if SIZEOF_LONG == 8 || SIZEOF_LONG_LONG == 8
+
+static int int64_compare(value v1, value v2)
+{
+ int64 i1 = Int64_val(v1);
+ int64 i2 = Int64_val(v2);
+ return i1 == i2 ? 0 : i1 < i2 ? -1 : 1;
+}
+
+static long int64_hash(value v)
+{
+ return (long) Int64_val(v);
+}
+
+static void int64_serialize(value v, unsigned long * wsize_32,
+ unsigned long * wsize_64)
+{
+ serialize_int_8(Int64_val(v));
+ *wsize_64 = *wsize_64 = 8;
+}
+
+static unsigned long int64_deserialize(void * dst)
+{
+ *((int64 *) dst) = deserialize_sint_8();
+ return 8;
+}
+
+static struct custom_operations int64_ops = {
+ "_i",
+ custom_finalize_default,
+ int64_compare,
+ int64_hash,
+ int64_serialize,
+ int64_deserialize
+};
+
+value copy_int64(int64 i)
+{
+ value res = alloc_custom(&int64_ops, 4, 0, 1);
+ Int64_val(res) = i;
+ return res;
+}
+
+value int64_neg(value v) /* ML */
+{ return copy_int64(- Int64_val(v)); }
+
+value int64_add(value v1, value v2) /* ML */
+{ return copy_int64(Int64_val(v1) + Int64_val(v2)); }
+
+value int64_sub(value v1, value v2) /* ML */
+{ return copy_int64(Int64_val(v1) - Int64_val(v2)); }
+
+value int64_mul(value v1, value v2) /* ML */
+{ return copy_int64(Int64_val(v1) * Int64_val(v2)); }
+
+value int64_div(value v1, value v2) /* ML */
+{
+ int64 divisor = Int64_val(v2);
+ if (divisor == 0) raise_zero_divide();
+ return copy_int64(Int64_val(v1) / divisor);
+}
+
+value int64_mod(value v1, value v2) /* ML */
+{
+ int64 divisor = Int64_val(v2);
+ if (divisor == 0) raise_zero_divide();
+ return copy_int64(Int64_val(v1) % divisor);
+}
+
+value int64_and(value v1, value v2) /* ML */
+{ return copy_int64(Int64_val(v1) & Int64_val(v2)); }
+
+value int64_or(value v1, value v2) /* ML */
+{ return copy_int64(Int64_val(v1) | Int64_val(v2)); }
+
+value int64_xor(value v1, value v2) /* ML */
+{ return copy_int64(Int64_val(v1) ^ Int64_val(v2)); }
+
+value int64_shift_left(value v1, value v2) /* ML */
+{ return copy_int64(Int64_val(v1) << Int_val(v2)); }
+
+value int64_shift_right(value v1, value v2) /* ML */
+{ return copy_int64(Int64_val(v1) >> Int_val(v2)); }
+
+value int64_shift_right_unsigned(value v1, value v2) /* ML */
+{ return copy_int64((uint64)Int64_val(v1) >> Int_val(v2)); }
+
+value int64_of_int(value v) /* ML */
+{ return copy_int64(Long_val(v)); }
+
+value int64_to_int(value v) /* ML */
+{ return Val_long((long) Int64_val(v)); }
+
+value int64_of_int32(value v) /* ML */
+{ return copy_int64(Int32_val(v)); }
+
+value int64_to_int32(value v) /* ML */
+{ return copy_int32((int32) Int64_val(v)); }
+
+value format_int64(value fmt, value arg) /* ML */
+{
+ char format_string[64], default_format_buffer[64];
+ char * buffer;
+ value res;
+
+ buffer = parse_format(fmt,
+#if SIZEOF_LONG == 8
+ "l",
+#else
+ "ll",
+#endif
+ format_string, default_format_buffer);
+ sprintf(buffer, format_string, Int64_val(arg));
+ res = copy_string(buffer);
+ if (buffer != default_format_buffer) stat_free(buffer);
return res;
}
+
+value int64_of_string(value s) /* ML */
+{
+ char * p;
+ uint64 res;
+ int sign, base, d;
+
+ p = parse_sign_and_base(String_val(s), &base, &sign);
+ for (res = 0; /*nothing*/; p++) {
+ d = parse_digit(p);
+ if (d < 0) break;
+ res = base * res + d;
+ }
+ if (*p != 0) failwith("Int64.of_string");
+ return copy_int64(sign < 0 ? -((int64) res) : (int64) res);
+}
+
+#else
+
+static char int64_error[] =
+ "The type Int64.t is not supported on this platform";
+
+value copy_int64(int64 i)
+{ invalid_arg(int64_error); }
+
+value int64_neg(value v)
+{ invalid_arg(int64_error); }
+
+value int64_add(value v1, value v2)
+{ invalid_arg(int64_error); }
+
+value int64_sub(value v1, value v2)
+{ invalid_arg(int64_error); }
+
+value int64_mul(value v1, value v2)
+{ invalid_arg(int64_error); }
+
+value int64_div(value v1, value v2)
+{ invalid_arg(int64_error); }
+
+value int64_mod(value v1, value v2)
+{ invalid_arg(int64_error); }
+
+value int64_and(value v1, value v2)
+{ invalid_arg(int64_error); }
+
+value int64_or(value v1, value v2)
+{ invalid_arg(int64_error); }
+
+value int64_xor(value v1, value v2)
+{ invalid_arg(int64_error); }
+
+value int64_shift_left(value v1, value v2)
+{ invalid_arg(int64_error); }
+
+value int64_shift_right(value v1, value v2)
+{ invalid_arg(int64_error); }
+
+value int64_shift_right_unsigned(value v1, value v2)
+{ invalid_arg(int64_error); }
+
+value int64_of_int(value v)
+{ invalid_arg(int64_error); }
+
+value int64_to_int(value v)
+{ invalid_arg(int64_error); }
+
+value int64_of_int32(value v)
+{ invalid_arg(int64_error); }
+
+value int64_to_int32(value v)
+{ invalid_arg(int64_error); }
+
+value format_int64(value fmt, value arg)
+{ invalid_arg(int64_error); }
+
+value int64_of_string(value s)
+{ invalid_arg(int64_error); }
+
+#endif