1995-08-09 08:06:35 -07:00
|
|
|
/***********************************************************************/
|
|
|
|
/* */
|
1996-04-30 07:53:58 -07:00
|
|
|
/* Objective Caml */
|
1995-08-09 08:06:35 -07:00
|
|
|
/* */
|
|
|
|
/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
|
|
|
|
/* */
|
1996-04-30 07:53:58 -07:00
|
|
|
/* Copyright 1996 Institut National de Recherche en Informatique et */
|
1999-11-17 10:59:06 -08:00
|
|
|
/* en Automatique. All rights reserved. This file is distributed */
|
2001-12-07 05:41:02 -08:00
|
|
|
/* under the terms of the GNU Library General Public License, with */
|
|
|
|
/* the special exception on linking described in file ../LICENSE. */
|
1995-08-09 08:06:35 -07:00
|
|
|
/* */
|
|
|
|
/***********************************************************************/
|
|
|
|
|
|
|
|
/* $Id$ */
|
|
|
|
|
1995-05-04 03:15:53 -07:00
|
|
|
#include <stdio.h>
|
1996-05-28 05:41:37 -07:00
|
|
|
#include <string.h>
|
1995-05-04 03:15:53 -07:00
|
|
|
#include "alloc.h"
|
2000-02-11 04:03:31 -08:00
|
|
|
#include "custom.h"
|
1995-05-04 03:15:53 -07:00
|
|
|
#include "fail.h"
|
2000-02-11 04:03:31 -08:00
|
|
|
#include "intext.h"
|
1995-05-04 03:15:53 -07:00
|
|
|
#include "memory.h"
|
1995-07-13 02:02:41 -07:00
|
|
|
#include "misc.h"
|
1995-05-04 03:15:53 -07:00
|
|
|
#include "mlvalues.h"
|
|
|
|
|
2000-02-11 04:03:31 -08:00
|
|
|
static char * parse_sign_and_base(char * p,
|
|
|
|
/*out*/ int * base,
|
|
|
|
/*out*/ int * sign)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
2000-02-11 04:03:31 -08:00
|
|
|
*sign = 1;
|
1995-05-04 03:15:53 -07:00
|
|
|
if (*p == '-') {
|
2000-02-11 04:03:31 -08:00
|
|
|
*sign = -1;
|
1995-05-04 03:15:53 -07:00
|
|
|
p++;
|
|
|
|
}
|
2000-02-11 04:03:31 -08:00
|
|
|
*base = 10;
|
1995-05-04 03:15:53 -07:00
|
|
|
if (*p == '0') {
|
|
|
|
switch (p[1]) {
|
|
|
|
case 'x': case 'X':
|
2000-02-11 04:03:31 -08:00
|
|
|
*base = 16; p += 2; break;
|
1995-05-04 03:15:53 -07:00
|
|
|
case 'o': case 'O':
|
2000-02-11 04:03:31 -08:00
|
|
|
*base = 8; p += 2; break;
|
2002-10-11 13:18:00 -07:00
|
|
|
case 'b': case 'B':
|
2000-02-11 04:03:31 -08:00
|
|
|
*base = 2; p += 2; break;
|
1995-05-04 03:15:53 -07:00
|
|
|
}
|
|
|
|
}
|
2000-02-11 04:03:31 -08:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2002-02-04 08:44:55 -08:00
|
|
|
static int parse_digit(char c)
|
2000-02-11 04:03:31 -08:00
|
|
|
{
|
|
|
|
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);
|
2002-02-04 08:44:55 -08:00
|
|
|
d = parse_digit(*p);
|
2000-11-20 04:27:56 -08:00
|
|
|
if (d < 0 || d >= base) failwith("int_of_string");
|
2000-03-07 01:08:17 -08:00
|
|
|
for (p++, res = d; /*nothing*/; p++) {
|
2002-02-04 08:44:55 -08:00
|
|
|
char c = *p;
|
|
|
|
if (c == '_') continue;
|
|
|
|
d = parse_digit(c);
|
2000-08-08 05:26:50 -07:00
|
|
|
if (d < 0 || d >= base) break;
|
1995-05-04 03:15:53 -07:00
|
|
|
res = base * res + d;
|
|
|
|
}
|
2000-02-11 04:03:31 -08:00
|
|
|
if (*p != 0) failwith("int_of_string");
|
|
|
|
return sign < 0 ? -((long) res) : (long) res;
|
1995-05-04 03:15:53 -07:00
|
|
|
}
|
|
|
|
|
2002-05-25 01:32:53 -07:00
|
|
|
#ifdef NONSTANDARD_DIV_MOD
|
|
|
|
long caml_safe_div(long p, long q)
|
|
|
|
{
|
|
|
|
unsigned long ap = p >= 0 ? p : -p;
|
|
|
|
unsigned long aq = q >= 0 ? q : -q;
|
|
|
|
unsigned long ar = ap / aq;
|
|
|
|
return (p ^ q) >= 0 ? ar : -ar;
|
|
|
|
}
|
|
|
|
|
|
|
|
long caml_safe_mod(long p, long q)
|
|
|
|
{
|
|
|
|
unsigned long ap = p >= 0 ? p : -p;
|
|
|
|
unsigned long aq = q >= 0 ? q : -q;
|
|
|
|
unsigned long ar = ap % aq;
|
|
|
|
return p >= 0 ? ar : -ar;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Tagged integers */
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int_of_string(value s)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
2000-02-11 04:03:31 -08:00
|
|
|
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;
|
1995-05-04 03:15:53 -07:00
|
|
|
char * p;
|
2000-02-11 04:03:31 -08:00
|
|
|
mlsize_t len, len_suffix;
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2000-02-11 04:03:31 -08:00
|
|
|
/* 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");
|
2000-10-12 11:05:42 -07:00
|
|
|
memmove(format_string, String_val(fmt), len);
|
2000-02-11 04:03:31 -08:00
|
|
|
p = format_string + len - 1;
|
|
|
|
lastletter = *p;
|
2001-10-28 06:19:13 -08:00
|
|
|
/* Compress two-letter formats, ignoring the [lnL] annotation */
|
|
|
|
if (p[-1] == 'l' || p[-1] == 'n' || p[-1] == 'L') p--;
|
2000-10-12 11:05:42 -07:00
|
|
|
memmove(p, suffix, len_suffix); p += len_suffix;
|
2000-02-11 04:03:31 -08:00
|
|
|
*p++ = lastletter;
|
|
|
|
*p = 0;
|
|
|
|
/* Determine space needed for result and allocate it dynamically if needed */
|
2001-10-28 06:19:13 -08:00
|
|
|
prec = 22 + 5; /* 22 digits for 64-bit number in octal + 5 extra */
|
1995-05-04 03:15:53 -07:00
|
|
|
for (p = String_val(fmt); *p != 0; p++) {
|
|
|
|
if (*p >= '0' && *p <= '9') {
|
|
|
|
prec = atoi(p) + 5;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2000-02-11 04:03:31 -08:00
|
|
|
if (prec < FORMAT_BUFFER_SIZE)
|
|
|
|
return default_format_buffer;
|
|
|
|
else
|
|
|
|
return stat_alloc(prec + 1);
|
|
|
|
}
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value format_int(value fmt, value arg)
|
2000-02-11 04:03:31 -08:00
|
|
|
{
|
2001-02-05 00:51:56 -08:00
|
|
|
char format_string[FORMAT_BUFFER_SIZE];
|
|
|
|
char default_format_buffer[FORMAT_BUFFER_SIZE];
|
2000-02-11 04:03:31 -08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLexport struct custom_operations int32_ops = {
|
2000-02-11 04:03:31 -08:00
|
|
|
"_i",
|
|
|
|
custom_finalize_default,
|
|
|
|
int32_compare,
|
|
|
|
int32_hash,
|
|
|
|
int32_serialize,
|
|
|
|
int32_deserialize
|
|
|
|
};
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLexport value copy_int32(int32 i)
|
2000-02-11 04:03:31 -08:00
|
|
|
{
|
|
|
|
value res = alloc_custom(&int32_ops, 4, 0, 1);
|
|
|
|
Int32_val(res) = i;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int32_neg(value v)
|
2000-02-11 04:03:31 -08:00
|
|
|
{ return copy_int32(- Int32_val(v)); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int32_add(value v1, value v2)
|
2000-02-11 04:03:31 -08:00
|
|
|
{ return copy_int32(Int32_val(v1) + Int32_val(v2)); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int32_sub(value v1, value v2)
|
2000-02-11 04:03:31 -08:00
|
|
|
{ return copy_int32(Int32_val(v1) - Int32_val(v2)); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int32_mul(value v1, value v2)
|
2000-02-11 04:03:31 -08:00
|
|
|
{ return copy_int32(Int32_val(v1) * Int32_val(v2)); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int32_div(value v1, value v2)
|
2000-02-11 04:03:31 -08:00
|
|
|
{
|
|
|
|
int32 divisor = Int32_val(v2);
|
|
|
|
if (divisor == 0) raise_zero_divide();
|
2002-05-25 01:32:53 -07:00
|
|
|
#ifdef NONSTANDARD_DIV_MOD
|
|
|
|
return copy_int32(caml_safe_div(Int32_val(v1), divisor));
|
|
|
|
#else
|
2000-02-11 04:03:31 -08:00
|
|
|
return copy_int32(Int32_val(v1) / divisor);
|
2002-05-25 01:32:53 -07:00
|
|
|
#endif
|
2000-02-11 04:03:31 -08:00
|
|
|
}
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int32_mod(value v1, value v2)
|
2000-02-11 04:03:31 -08:00
|
|
|
{
|
|
|
|
int32 divisor = Int32_val(v2);
|
|
|
|
if (divisor == 0) raise_zero_divide();
|
2002-05-25 01:32:53 -07:00
|
|
|
#ifdef NONSTANDARD_DIV_MOD
|
|
|
|
return copy_int32(caml_safe_mod(Int32_val(v1), divisor));
|
|
|
|
#else
|
2000-02-11 04:03:31 -08:00
|
|
|
return copy_int32(Int32_val(v1) % divisor);
|
2002-05-25 01:32:53 -07:00
|
|
|
#endif
|
2000-02-11 04:03:31 -08:00
|
|
|
}
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int32_and(value v1, value v2)
|
2000-02-11 04:03:31 -08:00
|
|
|
{ return copy_int32(Int32_val(v1) & Int32_val(v2)); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int32_or(value v1, value v2)
|
2000-02-11 04:03:31 -08:00
|
|
|
{ return copy_int32(Int32_val(v1) | Int32_val(v2)); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int32_xor(value v1, value v2)
|
2000-02-11 04:03:31 -08:00
|
|
|
{ return copy_int32(Int32_val(v1) ^ Int32_val(v2)); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int32_shift_left(value v1, value v2)
|
2000-02-11 04:03:31 -08:00
|
|
|
{ return copy_int32(Int32_val(v1) << Int_val(v2)); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int32_shift_right(value v1, value v2)
|
2000-02-11 04:03:31 -08:00
|
|
|
{ return copy_int32(Int32_val(v1) >> Int_val(v2)); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int32_shift_right_unsigned(value v1, value v2)
|
2000-02-11 04:03:31 -08:00
|
|
|
{ return copy_int32((uint32)Int32_val(v1) >> Int_val(v2)); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int32_of_int(value v)
|
2000-02-11 04:03:31 -08:00
|
|
|
{ return copy_int32(Long_val(v)); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int32_to_int(value v)
|
2000-02-11 04:03:31 -08:00
|
|
|
{ return Val_long(Int32_val(v)); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int32_of_float(value v)
|
2000-04-18 07:41:13 -07:00
|
|
|
{ return copy_int32((int32)(Double_val(v))); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int32_to_float(value v)
|
2000-04-18 07:41:13 -07:00
|
|
|
{ return copy_double((double)(Int32_val(v))); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int32_format(value fmt, value arg)
|
2000-02-11 04:03:31 -08:00
|
|
|
{
|
2001-02-05 00:51:56 -08:00
|
|
|
char format_string[FORMAT_BUFFER_SIZE];
|
|
|
|
char default_format_buffer[FORMAT_BUFFER_SIZE];
|
2000-02-11 04:03:31 -08:00
|
|
|
char * buffer;
|
|
|
|
value res;
|
|
|
|
|
2000-02-21 11:38:32 -08:00
|
|
|
buffer = parse_format(fmt, "", format_string, default_format_buffer);
|
2000-02-11 04:03:31 -08:00
|
|
|
sprintf(buffer, format_string, (long) Int32_val(arg));
|
|
|
|
res = copy_string(buffer);
|
|
|
|
if (buffer != default_format_buffer) stat_free(buffer);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int32_of_string(value s)
|
2000-02-11 04:03:31 -08:00
|
|
|
{
|
|
|
|
return copy_int32(parse_long(String_val(s)));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 64-bit integers */
|
|
|
|
|
2000-02-11 07:47:09 -08:00
|
|
|
#ifdef ARCH_INT64_TYPE
|
2002-05-25 01:32:53 -07:00
|
|
|
#include "int64_native.h"
|
|
|
|
#else
|
|
|
|
#include "int64_emul.h"
|
|
|
|
#endif
|
2000-02-11 04:03:31 -08:00
|
|
|
|
2000-03-10 09:36:31 -08:00
|
|
|
#ifdef ARCH_ALIGN_INT64
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLexport int64 Int64_val(value v)
|
2000-03-10 09:36:31 -08:00
|
|
|
{
|
|
|
|
union { int32 i[2]; int64 j; } buffer;
|
|
|
|
buffer.i[0] = ((int32 *) Data_custom_val(v))[0];
|
|
|
|
buffer.i[1] = ((int32 *) Data_custom_val(v))[1];
|
|
|
|
return buffer.j;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2000-02-11 04:03:31 -08:00
|
|
|
static int int64_compare(value v1, value v2)
|
|
|
|
{
|
|
|
|
int64 i1 = Int64_val(v1);
|
|
|
|
int64 i2 = Int64_val(v2);
|
2002-05-25 01:32:53 -07:00
|
|
|
return I64_compare(i1, i2);
|
2000-02-11 04:03:31 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static long int64_hash(value v)
|
|
|
|
{
|
2002-05-25 01:32:53 -07:00
|
|
|
return I64_to_long(Int64_val(v));
|
2000-02-11 04:03:31 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void int64_serialize(value v, unsigned long * wsize_32,
|
|
|
|
unsigned long * wsize_64)
|
|
|
|
{
|
|
|
|
serialize_int_8(Int64_val(v));
|
2000-11-30 09:13:41 -08:00
|
|
|
*wsize_32 = *wsize_64 = 8;
|
2000-02-11 04:03:31 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned long int64_deserialize(void * dst)
|
|
|
|
{
|
2001-09-24 05:39:26 -07:00
|
|
|
#ifndef ARCH_ALIGN_INT64
|
2000-02-11 04:03:31 -08:00
|
|
|
*((int64 *) dst) = deserialize_sint_8();
|
2001-09-24 05:39:26 -07:00
|
|
|
#else
|
|
|
|
union { int32 i[2]; int64 j; } buffer;
|
|
|
|
buffer.j = deserialize_sint_8();
|
|
|
|
((int32 *) dst)[0] = buffer.i[0];
|
|
|
|
((int32 *) dst)[1] = buffer.i[1];
|
|
|
|
#endif
|
2000-02-11 04:03:31 -08:00
|
|
|
return 8;
|
|
|
|
}
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLexport struct custom_operations int64_ops = {
|
2000-02-11 07:09:27 -08:00
|
|
|
"_j",
|
2000-02-11 04:03:31 -08:00
|
|
|
custom_finalize_default,
|
|
|
|
int64_compare,
|
|
|
|
int64_hash,
|
|
|
|
int64_serialize,
|
|
|
|
int64_deserialize
|
|
|
|
};
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLexport value copy_int64(int64 i)
|
2000-02-11 04:03:31 -08:00
|
|
|
{
|
2000-02-16 19:22:43 -08:00
|
|
|
value res = alloc_custom(&int64_ops, 8, 0, 1);
|
2000-03-10 09:54:18 -08:00
|
|
|
#ifndef ARCH_ALIGN_INT64
|
2000-02-11 04:03:31 -08:00
|
|
|
Int64_val(res) = i;
|
2000-03-10 09:54:18 -08:00
|
|
|
#else
|
|
|
|
union { int32 i[2]; int64 j; } buffer;
|
|
|
|
buffer.j = i;
|
|
|
|
((int32 *) Data_custom_val(res))[0] = buffer.i[0];
|
|
|
|
((int32 *) Data_custom_val(res))[1] = buffer.i[1];
|
|
|
|
#endif
|
2000-02-11 04:03:31 -08:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int64_neg(value v)
|
2002-05-25 01:32:53 -07:00
|
|
|
{ return copy_int64(I64_neg(Int64_val(v))); }
|
2000-02-11 04:03:31 -08:00
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int64_add(value v1, value v2)
|
2002-05-25 01:32:53 -07:00
|
|
|
{ return copy_int64(I64_add(Int64_val(v1), Int64_val(v2))); }
|
2000-02-11 04:03:31 -08:00
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int64_sub(value v1, value v2)
|
2002-05-25 01:32:53 -07:00
|
|
|
{ return copy_int64(I64_sub(Int64_val(v1), Int64_val(v2))); }
|
2000-02-11 04:03:31 -08:00
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int64_mul(value v1, value v2)
|
2002-05-25 01:32:53 -07:00
|
|
|
{ return copy_int64(I64_mul(Int64_val(v1), Int64_val(v2))); }
|
2000-02-11 04:03:31 -08:00
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int64_div(value v1, value v2)
|
2000-02-11 04:03:31 -08:00
|
|
|
{
|
|
|
|
int64 divisor = Int64_val(v2);
|
2002-05-25 01:32:53 -07:00
|
|
|
if (I64_is_zero(divisor)) raise_zero_divide();
|
|
|
|
return copy_int64(I64_div(Int64_val(v1), divisor));
|
2000-02-11 04:03:31 -08:00
|
|
|
}
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int64_mod(value v1, value v2)
|
2000-02-11 04:03:31 -08:00
|
|
|
{
|
|
|
|
int64 divisor = Int64_val(v2);
|
2002-05-25 01:32:53 -07:00
|
|
|
if (I64_is_zero(divisor)) raise_zero_divide();
|
|
|
|
return copy_int64(I64_mod(Int64_val(v1), divisor));
|
2000-02-11 04:03:31 -08:00
|
|
|
}
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int64_and(value v1, value v2)
|
2002-05-25 01:32:53 -07:00
|
|
|
{ return copy_int64(I64_and(Int64_val(v1), Int64_val(v2))); }
|
2000-02-11 04:03:31 -08:00
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int64_or(value v1, value v2)
|
2002-05-25 01:32:53 -07:00
|
|
|
{ return copy_int64(I64_or(Int64_val(v1), Int64_val(v2))); }
|
2000-02-11 04:03:31 -08:00
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int64_xor(value v1, value v2)
|
2002-05-25 01:32:53 -07:00
|
|
|
{ return copy_int64(I64_xor(Int64_val(v1), Int64_val(v2))); }
|
2000-02-11 04:03:31 -08:00
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int64_shift_left(value v1, value v2)
|
2002-05-25 01:32:53 -07:00
|
|
|
{ return copy_int64(I64_lsl(Int64_val(v1), Int_val(v2))); }
|
2000-02-11 04:03:31 -08:00
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int64_shift_right(value v1, value v2)
|
2002-05-25 01:32:53 -07:00
|
|
|
{ return copy_int64(I64_asr(Int64_val(v1), Int_val(v2))); }
|
2000-02-11 04:03:31 -08:00
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int64_shift_right_unsigned(value v1, value v2)
|
2002-05-25 01:32:53 -07:00
|
|
|
{ return copy_int64(I64_lsr(Int64_val(v1), Int_val(v2))); }
|
2000-02-11 04:03:31 -08:00
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int64_of_int(value v)
|
2002-05-25 01:32:53 -07:00
|
|
|
{ return copy_int64(I64_of_long(Long_val(v))); }
|
2000-02-11 04:03:31 -08:00
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int64_to_int(value v)
|
2002-05-25 01:32:53 -07:00
|
|
|
{ return Val_long(I64_to_long(Int64_val(v))); }
|
2000-02-11 04:03:31 -08:00
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int64_of_float(value v)
|
2002-05-25 01:32:53 -07:00
|
|
|
{ return copy_int64(I64_of_double(Double_val(v))); }
|
2000-04-18 07:41:13 -07:00
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int64_to_float(value v)
|
2002-05-25 01:32:53 -07:00
|
|
|
{ return copy_double(I64_to_double(Int64_val(v))); }
|
2000-04-18 07:41:13 -07:00
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int64_of_int32(value v)
|
2002-05-25 01:32:53 -07:00
|
|
|
{ return copy_int64(I64_of_int32(Int32_val(v))); }
|
2000-02-11 04:03:31 -08:00
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int64_to_int32(value v)
|
2002-05-25 01:32:53 -07:00
|
|
|
{ return copy_int32(I64_to_int32(Int64_val(v))); }
|
2000-02-11 04:03:31 -08:00
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int64_of_nativeint(value v)
|
2002-05-25 01:32:53 -07:00
|
|
|
{ return copy_int64(I64_of_long(Nativeint_val(v))); }
|
2000-03-05 11:17:54 -08:00
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int64_to_nativeint(value v)
|
2002-05-25 01:32:53 -07:00
|
|
|
{ return copy_nativeint(I64_to_long(Int64_val(v))); }
|
2000-03-05 11:17:54 -08:00
|
|
|
|
2000-04-05 11:30:22 -07:00
|
|
|
#ifdef ARCH_INT64_PRINTF_FORMAT
|
2002-05-25 01:32:53 -07:00
|
|
|
#define I64_format(buf,fmt,x) sprintf(buf,fmt,x)
|
|
|
|
#else
|
|
|
|
#include "int64_format.h"
|
|
|
|
#define ARCH_INT64_PRINTF_FORMAT ""
|
|
|
|
#endif
|
|
|
|
|
|
|
|
CAMLprim value int64_format(value fmt, value arg)
|
2000-02-11 04:03:31 -08:00
|
|
|
{
|
2001-02-05 00:51:56 -08:00
|
|
|
char format_string[FORMAT_BUFFER_SIZE];
|
|
|
|
char default_format_buffer[FORMAT_BUFFER_SIZE];
|
2000-02-11 04:03:31 -08:00
|
|
|
char * buffer;
|
|
|
|
value res;
|
|
|
|
|
2000-02-11 07:47:09 -08:00
|
|
|
buffer = parse_format(fmt, ARCH_INT64_PRINTF_FORMAT,
|
2000-02-11 04:03:31 -08:00
|
|
|
format_string, default_format_buffer);
|
2002-05-25 01:32:53 -07:00
|
|
|
I64_format(buffer, format_string, Int64_val(arg));
|
2000-02-11 04:03:31 -08:00
|
|
|
res = copy_string(buffer);
|
|
|
|
if (buffer != default_format_buffer) stat_free(buffer);
|
1995-05-04 03:15:53 -07:00
|
|
|
return res;
|
|
|
|
}
|
2000-02-11 04:03:31 -08:00
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int64_of_string(value s)
|
2000-02-11 04:03:31 -08:00
|
|
|
{
|
|
|
|
char * p;
|
2002-05-25 01:32:53 -07:00
|
|
|
int64 res;
|
2000-02-11 04:03:31 -08:00
|
|
|
int sign, base, d;
|
|
|
|
|
|
|
|
p = parse_sign_and_base(String_val(s), &base, &sign);
|
2002-02-04 08:44:55 -08:00
|
|
|
d = parse_digit(*p);
|
2001-02-05 00:51:56 -08:00
|
|
|
if (d < 0 || d >= base) failwith("int_of_string");
|
2002-05-25 01:32:53 -07:00
|
|
|
res = I64_of_int32(d);
|
|
|
|
for (p++; /*nothing*/; p++) {
|
2002-02-04 08:44:55 -08:00
|
|
|
char c = *p;
|
|
|
|
if (c == '_') continue;
|
|
|
|
d = parse_digit(c);
|
2000-08-08 05:26:50 -07:00
|
|
|
if (d < 0 || d >= base) break;
|
2002-05-25 01:32:53 -07:00
|
|
|
res = I64_add(I64_mul(I64_of_int32(base), res), I64_of_int32(d));
|
2000-02-11 04:03:31 -08:00
|
|
|
}
|
2000-02-11 07:09:27 -08:00
|
|
|
if (*p != 0) failwith("int_of_string");
|
2002-05-25 01:32:53 -07:00
|
|
|
if (sign < 0) res = I64_neg(res);
|
|
|
|
return copy_int64(res);
|
2000-02-11 04:03:31 -08:00
|
|
|
}
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int64_bits_of_float(value vd)
|
2001-02-05 00:51:56 -08:00
|
|
|
{
|
|
|
|
union { double d; int64 i; } u;
|
|
|
|
u.d = Double_val(vd);
|
|
|
|
return copy_int64(u.i);
|
|
|
|
}
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value int64_float_of_bits(value vi)
|
2001-02-05 00:51:56 -08:00
|
|
|
{
|
|
|
|
union { double d; int64 i; } u;
|
|
|
|
u.i = Int64_val(vi);
|
|
|
|
return copy_double(u.d);
|
|
|
|
}
|
|
|
|
|
2000-02-11 07:09:27 -08:00
|
|
|
/* Native integers */
|
|
|
|
|
|
|
|
static int nativeint_compare(value v1, value v2)
|
|
|
|
{
|
2000-02-21 11:38:32 -08:00
|
|
|
long i1 = Nativeint_val(v1);
|
|
|
|
long i2 = Nativeint_val(v2);
|
2000-02-11 07:09:27 -08:00
|
|
|
return i1 == i2 ? 0 : i1 < i2 ? -1 : 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static long nativeint_hash(value v)
|
|
|
|
{
|
|
|
|
return Nativeint_val(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void nativeint_serialize(value v, unsigned long * wsize_32,
|
|
|
|
unsigned long * wsize_64)
|
|
|
|
{
|
|
|
|
long l = Nativeint_val(v);
|
|
|
|
#ifdef ARCH_SIXTYFOUR
|
|
|
|
if (l <= 0x7FFFFFFFL && l >= -0x80000000L) {
|
|
|
|
serialize_int_1(1);
|
|
|
|
serialize_int_4((int32) l);
|
|
|
|
} else {
|
|
|
|
serialize_int_1(2);
|
|
|
|
serialize_int_8(l);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
serialize_int_1(1);
|
|
|
|
serialize_int_4(l);
|
|
|
|
#endif
|
|
|
|
*wsize_32 = 4;
|
|
|
|
*wsize_64 = 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned long nativeint_deserialize(void * dst)
|
|
|
|
{
|
|
|
|
switch (deserialize_uint_1()) {
|
|
|
|
case 1:
|
|
|
|
*((long *) dst) = deserialize_sint_4();
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
#ifdef ARCH_SIXTYFOUR
|
|
|
|
*((long *) dst) = deserialize_sint_8();
|
|
|
|
#else
|
|
|
|
deserialize_error("input_value: native integer value too large");
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
deserialize_error("input_value: ill-formed native integer");
|
|
|
|
}
|
|
|
|
return sizeof(long);
|
|
|
|
}
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLexport struct custom_operations nativeint_ops = {
|
2000-02-11 07:09:27 -08:00
|
|
|
"_n",
|
|
|
|
custom_finalize_default,
|
|
|
|
nativeint_compare,
|
|
|
|
nativeint_hash,
|
|
|
|
nativeint_serialize,
|
|
|
|
nativeint_deserialize
|
|
|
|
};
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLexport value copy_nativeint(long i)
|
2000-02-11 07:09:27 -08:00
|
|
|
{
|
|
|
|
value res = alloc_custom(&nativeint_ops, sizeof(long), 0, 1);
|
|
|
|
Nativeint_val(res) = i;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value nativeint_neg(value v)
|
2000-02-11 07:09:27 -08:00
|
|
|
{ return copy_nativeint(- Nativeint_val(v)); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value nativeint_add(value v1, value v2)
|
2000-02-11 07:09:27 -08:00
|
|
|
{ return copy_nativeint(Nativeint_val(v1) + Nativeint_val(v2)); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value nativeint_sub(value v1, value v2)
|
2000-02-11 07:09:27 -08:00
|
|
|
{ return copy_nativeint(Nativeint_val(v1) - Nativeint_val(v2)); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value nativeint_mul(value v1, value v2)
|
2000-02-11 07:09:27 -08:00
|
|
|
{ return copy_nativeint(Nativeint_val(v1) * Nativeint_val(v2)); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value nativeint_div(value v1, value v2)
|
2000-02-11 07:09:27 -08:00
|
|
|
{
|
|
|
|
long divisor = Nativeint_val(v2);
|
|
|
|
if (divisor == 0) raise_zero_divide();
|
2002-05-25 01:32:53 -07:00
|
|
|
#ifdef NONSTANDARD_DIV_MOD
|
|
|
|
return copy_nativeint(caml_safe_div(Nativeint_val(v1), divisor));
|
|
|
|
#else
|
2000-02-11 07:09:27 -08:00
|
|
|
return copy_nativeint(Nativeint_val(v1) / divisor);
|
2002-05-25 01:32:53 -07:00
|
|
|
#endif
|
2000-02-11 07:09:27 -08:00
|
|
|
}
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value nativeint_mod(value v1, value v2)
|
2000-02-11 07:09:27 -08:00
|
|
|
{
|
|
|
|
long divisor = Nativeint_val(v2);
|
|
|
|
if (divisor == 0) raise_zero_divide();
|
2002-05-25 01:32:53 -07:00
|
|
|
#ifdef NONSTANDARD_DIV_MOD
|
|
|
|
return copy_nativeint(caml_safe_mod(Nativeint_val(v1), divisor));
|
|
|
|
#else
|
2000-02-11 07:09:27 -08:00
|
|
|
return copy_nativeint(Nativeint_val(v1) % divisor);
|
2002-05-25 01:32:53 -07:00
|
|
|
#endif
|
2000-02-11 07:09:27 -08:00
|
|
|
}
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value nativeint_and(value v1, value v2)
|
2000-02-11 07:09:27 -08:00
|
|
|
{ return copy_nativeint(Nativeint_val(v1) & Nativeint_val(v2)); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value nativeint_or(value v1, value v2)
|
2000-02-11 07:09:27 -08:00
|
|
|
{ return copy_nativeint(Nativeint_val(v1) | Nativeint_val(v2)); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value nativeint_xor(value v1, value v2)
|
2000-02-11 07:09:27 -08:00
|
|
|
{ return copy_nativeint(Nativeint_val(v1) ^ Nativeint_val(v2)); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value nativeint_shift_left(value v1, value v2)
|
2000-02-11 07:09:27 -08:00
|
|
|
{ return copy_nativeint(Nativeint_val(v1) << Int_val(v2)); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value nativeint_shift_right(value v1, value v2)
|
2000-02-11 07:09:27 -08:00
|
|
|
{ return copy_nativeint(Nativeint_val(v1) >> Int_val(v2)); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value nativeint_shift_right_unsigned(value v1, value v2)
|
2000-02-21 11:38:32 -08:00
|
|
|
{ return copy_nativeint((unsigned long)Nativeint_val(v1) >> Int_val(v2)); }
|
2000-02-11 07:09:27 -08:00
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value nativeint_of_int(value v)
|
2000-02-11 07:09:27 -08:00
|
|
|
{ return copy_nativeint(Long_val(v)); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value nativeint_to_int(value v)
|
2000-02-11 07:09:27 -08:00
|
|
|
{ return Val_long(Nativeint_val(v)); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value nativeint_of_float(value v)
|
2000-04-18 07:41:13 -07:00
|
|
|
{ return copy_nativeint((long)(Double_val(v))); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value nativeint_to_float(value v)
|
2000-04-18 07:41:13 -07:00
|
|
|
{ return copy_double((double)(Nativeint_val(v))); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value nativeint_of_int32(value v)
|
2000-03-05 11:17:54 -08:00
|
|
|
{ return copy_nativeint(Int32_val(v)); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value nativeint_to_int32(value v)
|
2000-03-05 11:17:54 -08:00
|
|
|
{ return copy_int32(Nativeint_val(v)); }
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value nativeint_format(value fmt, value arg)
|
2000-02-11 07:09:27 -08:00
|
|
|
{
|
2001-02-05 00:51:56 -08:00
|
|
|
char format_string[FORMAT_BUFFER_SIZE];
|
|
|
|
char default_format_buffer[FORMAT_BUFFER_SIZE];
|
2000-02-11 07:09:27 -08:00
|
|
|
char * buffer;
|
|
|
|
value res;
|
|
|
|
|
|
|
|
buffer = parse_format(fmt, "l", format_string, default_format_buffer);
|
|
|
|
sprintf(buffer, format_string, (long) Nativeint_val(arg));
|
|
|
|
res = copy_string(buffer);
|
|
|
|
if (buffer != default_format_buffer) stat_free(buffer);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
CAMLprim value nativeint_of_string(value s)
|
2000-02-11 07:09:27 -08:00
|
|
|
{
|
|
|
|
return copy_nativeint(parse_long(String_val(s)));
|
|
|
|
}
|
|
|
|
|
|
|
|
|