ecl/src/c/predicate.d
Marius Gerbershagen 8a38c9a3c2 remove register storage class specifier
This option is not needed anymore, ignored by modern compilers and has
been removed in the C++17 standard.

Fixes #647.
2021-07-17 12:13:05 +02:00

602 lines
15 KiB
C

/* -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/* vim: set filetype=c tabstop=2 shiftwidth=2 expandtab: */
/*
* predicate.d - predicates
*
* Copyright (c) 1984 Taiichi Yuasa and Masami Hagiya
* Copyright (c) 1990 Giuseppe Attardi
* Copyright (c) 2001 Juan Jose Garcia Ripoll
*
* See file 'LICENSE' for the copyright details.
*
*/
#include <string.h>
#define ECL_INCLUDE_MATH_H
#include <ecl/ecl.h>
#define ECL_DEFINE_AET_SIZE
#include <ecl/internal.h>
cl_object
cl_identity(cl_object x)
{
@(return x);
}
cl_object
cl_null(cl_object x)
{
@(return (Null(x) ? ECL_T : ECL_NIL));
}
cl_object
cl_symbolp(cl_object x)
{
@(return (ECL_SYMBOLP(x) ? ECL_T : ECL_NIL));
}
cl_object
cl_atom(cl_object x)
{
@(return (ECL_ATOM(x) ? ECL_T : ECL_NIL));
}
cl_object
cl_consp(cl_object x)
{
@(return (CONSP(x) ? ECL_T : ECL_NIL));
}
cl_object
cl_listp(cl_object x)
{
@(return ((Null(x) || CONSP(x)) ? ECL_T : ECL_NIL));
}
cl_object
cl_numberp(cl_object x)
{
cl_type t = ecl_t_of(x);
@(return (ECL_NUMBER_TYPE_P(t) ? ECL_T : ECL_NIL));
}
/* Used in compiled code */
bool ecl_numberp(cl_object x)
{
cl_type t = ecl_t_of(x);
return ECL_NUMBER_TYPE_P(t);
}
cl_object
cl_integerp(cl_object x)
{
cl_type t = ecl_t_of(x);
@(return ((t == t_fixnum || t == t_bignum) ? ECL_T : ECL_NIL));
}
cl_object
cl_rationalp(cl_object x)
{
cl_type t = ecl_t_of(x);
@(return ((t == t_fixnum || t == t_bignum || t == t_ratio) ? ECL_T : ECL_NIL));
}
cl_object
cl_floatp(cl_object x)
{
@(return (floatp(x)? ECL_T : ECL_NIL));
}
bool
floatp(cl_object x)
{
cl_type t = ecl_t_of(x);
return (t == t_singlefloat) || (t == t_doublefloat) || (t == t_longfloat);
}
cl_object
cl_realp(cl_object x)
{
cl_type t = ecl_t_of(x);
@(return (ECL_REAL_TYPE_P(t) ? ECL_T : ECL_NIL));
}
bool
ecl_realp(cl_object x)
{
cl_type t = ecl_t_of(x);
return ECL_REAL_TYPE_P(t);
}
cl_object
cl_complexp(cl_object x)
{
@(return (ECL_COMPLEXP(x) ? ECL_T : ECL_NIL));
}
cl_object
cl_characterp(cl_object x)
{
@(return (ECL_CHARACTERP(x) ? ECL_T : ECL_NIL));
}
#ifdef ECL_UNICODE
cl_object
si_base_char_p(cl_object c)
{
@(return ((ECL_CHARACTERP(c) && ECL_BASE_CHAR_P(c))? ECL_T : ECL_NIL));
}
#endif
bool
ecl_stringp(cl_object x)
{
cl_type t = ecl_t_of(x);
#ifdef ECL_UNICODE
return t == t_base_string || t == t_string;
#else
return t == t_base_string;
#endif
}
cl_object
cl_stringp(cl_object x)
{
@(return (ECL_STRINGP(x)? ECL_T : ECL_NIL));
}
cl_object
cl_bit_vector_p(cl_object x)
{
@(return (ECL_BIT_VECTOR_P(x) ? ECL_T : ECL_NIL));
}
cl_object
cl_vectorp(cl_object x)
{
@(return (ECL_VECTORP(x) ? ECL_T : ECL_NIL));
}
cl_object
cl_simple_string_p(cl_object x)
{
@(return ((ECL_STRINGP(x) &&
!ECL_ADJUSTABLE_ARRAY_P(x) &&
!ECL_ARRAY_HAS_FILL_POINTER_P(x) &&
Null(CAR(x->base_string.displaced))) ? ECL_T : ECL_NIL));
}
#ifdef ECL_UNICODE
cl_object
si_base_string_p(cl_object x)
{
@(return (ECL_BASE_STRING_P(x) ? ECL_T : ECL_NIL));
}
#endif
cl_object
cl_simple_bit_vector_p(cl_object x)
{
@(return ((ECL_BIT_VECTOR_P(x) &&
!ECL_ADJUSTABLE_ARRAY_P(x) &&
!ECL_ARRAY_HAS_FILL_POINTER_P(x) &&
Null(CAR(x->vector.displaced))) ? ECL_T : ECL_NIL));
}
cl_object
cl_simple_vector_p(cl_object x)
{
cl_type t = ecl_t_of(x);
@(return ((t == t_vector &&
!ECL_ADJUSTABLE_ARRAY_P(x) &&
!ECL_ARRAY_HAS_FILL_POINTER_P(x) &&
Null(CAR(x->vector.displaced)) &&
(cl_elttype)x->vector.elttype == ecl_aet_object) ? ECL_T : ECL_NIL));
}
cl_object
cl_arrayp(cl_object x)
{
@(return (ECL_ARRAYP(x) ? ECL_T : ECL_NIL));
}
cl_object
cl_packagep(cl_object x)
{
@(return (ECL_PACKAGEP(x) ? ECL_T : ECL_NIL));
}
cl_object
cl_functionp(cl_object x)
{
cl_type t;
cl_object output;
t = ecl_t_of(x);
if (t == t_bytecodes || t == t_bclosure || t == t_cfun
|| t == t_cfunfixed || t == t_cclosure
|| (t == t_instance && x->instance.isgf))
output = ECL_T;
else
output = ECL_NIL;
@(return output);
}
cl_object
cl_compiled_function_p(cl_object x)
{
cl_type t = ecl_t_of(x);
@(return ((t == t_bytecodes || t == t_bclosure || t == t_cfun
|| t == t_cfunfixed || t == t_cclosure) ? ECL_T : ECL_NIL))
}
cl_object
cl_eq(cl_object x, cl_object y)
{
@(return ((x == y) ? ECL_T : ECL_NIL));
}
/*
* EQL-comparison of floats. If we are using signed zeros and NaNs,
* numeric comparison of floating points is not equivalent to bit-wise
* equality. In particular every two NaNs always give false
* (= #1=(/ 0.0 0.0) #1#) => NIL
* and signed zeros always compare equal
* (= 0 -0.0) => T
* which is not the same as what EQL should return
* (EQL #1=(/ 0.0 0.0) #1#) => T
* (EQL 0 -0.0) => NIL
*
* Furthermore, we can not use bit comparisons because in some platforms
* long double has unused bits that makes two long floats be = but not eql.
*/
#if !defined(ECL_SIGNED_ZERO) && !defined(ECL_IEEE_FP)
#define FLOAT_EQL(name, type) \
static bool name(type a, type b) { return a == b; }
#else
#define FLOAT_EQL(name, type) \
static bool name(type a, type b) { \
if (a == b) return signbit(a) == signbit(b); \
if (isnan(a) || isnan(b)) return isnan(a) && isnan(b); \
return 0; \
}
#endif
FLOAT_EQL(float_eql, float);
FLOAT_EQL(double_eql, double);
FLOAT_EQL(long_double_eql, long double);
#undef FLOAT_EQL
bool
ecl_eql(cl_object x, cl_object y)
{
if (x == y)
return TRUE;
if (ECL_IMMEDIATE(x) || ECL_IMMEDIATE(y))
return FALSE;
if (x->d.t != y->d.t)
return FALSE;
switch (x->d.t) {
case t_bignum:
return (_ecl_big_compare(x, y) == 0);
case t_ratio:
return (ecl_eql(x->ratio.num, y->ratio.num) &&
ecl_eql(x->ratio.den, y->ratio.den));
case t_singlefloat:
return float_eql(ecl_single_float(x), ecl_single_float(y));
case t_longfloat:
return long_double_eql(ecl_long_float(x), ecl_long_float(y));
case t_doublefloat:
return double_eql(ecl_double_float(x), ecl_double_float(y));
case t_complex:
return (ecl_eql(x->gencomplex.real, y->gencomplex.real) &&
ecl_eql(x->gencomplex.imag, y->gencomplex.imag));
#ifdef ECL_COMPLEX_FLOAT
case t_csfloat:
return (float_eql(crealf(ecl_csfloat(x)), crealf(ecl_csfloat(y))) &&
float_eql(cimagf(ecl_csfloat(x)), cimagf(ecl_csfloat(y))));
case t_cdfloat:
return (double_eql(creal(ecl_cdfloat(x)), creal(ecl_cdfloat(y))) &&
double_eql(cimag(ecl_cdfloat(x)), cimag(ecl_cdfloat(y))));
case t_clfloat:
return (long_double_eql(creall(ecl_clfloat(x)), creall(ecl_clfloat(y))) &&
long_double_eql(cimagl(ecl_clfloat(x)), cimagl(ecl_clfloat(y))));
#endif
#ifdef ECL_SSE2
case t_sse_pack:
return !memcmp(x->sse.data.b8, y->sse.data.b8, 16);
#endif
default:
return FALSE;
}
}
cl_object
cl_eql(cl_object x, cl_object y)
{
@(return (ecl_eql(x, y) ? ECL_T : ECL_NIL));
}
bool
ecl_equal(cl_object x, cl_object y)
{
cl_type tx, ty;
BEGIN:
if (x==y)
return(TRUE);
tx = ecl_t_of(x);
ty = ecl_t_of(y);
switch (tx) {
case t_list:
if (Null(x) || Null(y)) {
/* If X is NIL, then X and Y must be EQ */
return FALSE;
}
if (tx != ty || !ecl_equal(CAR(x), CAR(y)))
return FALSE;
x = CDR(x);
y = CDR(y);
goto BEGIN;
case t_symbol:
case t_vector:
case t_array:
case t_fixnum:
return FALSE;
case t_bignum:
return (tx == ty) && (_ecl_big_compare(x,y) == 0);
case t_ratio:
return (tx == ty) && ecl_eql(x->ratio.num, y->ratio.num) &&
ecl_eql(x->ratio.den, y->ratio.den);
case t_singlefloat: {
if (tx != ty) return 0;
return float_eql(ecl_single_float(x), ecl_single_float(y));
}
case t_doublefloat: {
if (tx != ty) return 0;
return double_eql(ecl_double_float(x), ecl_double_float(y));
}
case t_longfloat: {
if (tx != ty) return 0;
return long_double_eql(ecl_long_float(x), ecl_long_float(y));
}
case t_complex:
return (tx == ty) && ecl_eql(x->gencomplex.real, y->gencomplex.real) &&
ecl_eql(x->gencomplex.imag, y->gencomplex.imag);
#ifdef ECL_COMPLEX_FLOAT
case t_csfloat:
if (tx != ty) return 0;
return (float_eql(crealf(ecl_csfloat(x)), crealf(ecl_csfloat(y))) &&
float_eql(cimagf(ecl_csfloat(x)), cimagf(ecl_csfloat(y))));
case t_cdfloat:
if (tx != ty) return 0;
return (double_eql(creal(ecl_cdfloat(x)), creal(ecl_cdfloat(y))) &&
double_eql(cimag(ecl_cdfloat(x)), cimag(ecl_cdfloat(y))));
case t_clfloat:
if (tx != ty) return 0;
return (long_double_eql(creall(ecl_clfloat(x)), creall(ecl_clfloat(y))) &&
long_double_eql(cimagl(ecl_clfloat(x)), cimagl(ecl_clfloat(y))));
#endif
case t_character:
return (tx == ty) && (ECL_CHAR_CODE(x) == ECL_CHAR_CODE(y));
case t_base_string:
#ifdef ECL_UNICODE
case t_string:
if (ty != t_base_string && ty != t_string)
return FALSE;
#else
if (ty != t_base_string)
return FALSE;
#endif
return ecl_string_eq(x, y);
case t_bitvector: {
cl_index i, ox, oy;
if (ty != tx)
return FALSE;
if (x->vector.fillp != y->vector.fillp)
return(FALSE);
ox = x->vector.offset;
oy = y->vector.offset;
for (i = 0; i < x->vector.fillp; i++)
if(((x->vector.self.bit[(i+ox)/8] << (i+ox)%8) & 0200)
!= ((y->vector.self.bit[(i+oy)/8] << (i+oy)%8) & 0200))
return(FALSE);
return(TRUE);
}
case t_pathname:
return ty == tx &&
ecl_equal(x->pathname.host, y->pathname.host) &&
ecl_equal(x->pathname.device, y->pathname.device) &&
ecl_equal(x->pathname.directory, y->pathname.directory) &&
ecl_equal(x->pathname.name, y->pathname.name) &&
ecl_equal(x->pathname.type, y->pathname.type) &&
ecl_equal(x->pathname.version, y->pathname.version);
case t_foreign:
return (tx == ty) && (x->foreign.data == y->foreign.data);
default:
return FALSE;
}
}
cl_object
cl_equal(cl_object x, cl_object y)
{
@(return (ecl_equal(x, y) ? ECL_T : ECL_NIL));
}
bool
ecl_equalp(cl_object x, cl_object y)
{
cl_type tx, ty;
cl_index j;
BEGIN:
if (x == y)
return TRUE;
tx = ecl_t_of(x);
ty = ecl_t_of(y);
switch (tx) {
case t_fixnum:
case t_bignum:
case t_ratio:
case t_singlefloat:
case t_doublefloat:
case t_longfloat:
case t_complex:
#ifdef ECL_COMPLEX_FLOAT
case t_csfloat:
case t_cdfloat:
case t_clfloat:
#endif
return ECL_NUMBER_TYPE_P(ty) && ecl_number_equalp(x, y);
case t_vector:
case t_base_string:
case t_bitvector:
#ifdef ECL_UNICODE
case t_string:
if (ty != t_vector && ty != t_base_string && ty != t_bitvector
&& ty != t_string)
return FALSE;
#else
if (ty != t_vector && ty != t_base_string && ty != t_bitvector)
return FALSE;
#endif
j = x->vector.fillp;
if (j != y->vector.fillp)
return FALSE;
goto ARRAY;
case t_array:
if (ty != t_array || x->array.rank != y->array.rank)
return FALSE;
if (x->array.rank > 1) {
cl_index i = 0;
for (i = 0; i < x->array.rank; i++)
if (x->array.dims[i] != y->array.dims[i])
return(FALSE);
}
if (x->array.dim != y->array.dim)
return(FALSE);
j=x->array.dim;
ARRAY: {
cl_index i;
cl_elttype etx = x->array.elttype;
cl_elttype ety = y->array.elttype;
if (etx == ety
&& (etx == ecl_aet_b8 || etx == ecl_aet_i8
|| etx == ecl_aet_b16 || etx == ecl_aet_i16
|| etx == ecl_aet_b32 || etx == ecl_aet_i32
|| etx == ecl_aet_b64 || etx == ecl_aet_i64
|| etx == ecl_aet_fix || etx == ecl_aet_index)) {
return memcmp(x->array.self.t, y->array.self.t, j * ecl_aet_size[etx]) == 0;
}
#define AET_FLOAT_EQUALP(t1, t2) \
case ecl_aet_##t2: \
for (i = 0; i < j; i++) \
if (x->array.self.t1[i] != y->array.self.t2[i]) \
return(FALSE); \
return(TRUE);
#ifdef ECL_COMPLEX_FLOAT
#define AET_FLOAT_EQUALP_CF(t1, cf) AET_FLOAT_EQUALP(t1, cf)
#else
#define AET_FLOAT_EQUALP_CF(t1, cf)
#endif
#define AET_FLOAT_SWITCH(t1) \
case ecl_aet_##t1: \
switch(ety) { \
AET_FLOAT_EQUALP(t1, sf); \
AET_FLOAT_EQUALP(t1, df); \
AET_FLOAT_EQUALP(t1, lf); \
AET_FLOAT_EQUALP_CF(t1, csf); \
AET_FLOAT_EQUALP_CF(t1, cdf); \
AET_FLOAT_EQUALP_CF(t1, clf); \
default: \
break; \
}
switch (etx) {
AET_FLOAT_SWITCH(sf);
AET_FLOAT_SWITCH(df);
AET_FLOAT_SWITCH(lf);
#ifdef ECL_COMPLEX_FLOAT
AET_FLOAT_SWITCH(csf);
AET_FLOAT_SWITCH(cdf);
AET_FLOAT_SWITCH(clf);
#endif
default:
break;
}
#undef AET_FLOAT_EQUALP
#undef AET_FLOAT_SWITCH
#undef AET_FLOAT_EQUALP_CF
for (i = 0; i < j; i++)
if (!ecl_equalp(ecl_aref_unsafe(x, i), ecl_aref_unsafe(y, i)))
return(FALSE);
return(TRUE);
}
case t_character:
return (ty == tx) && ecl_char_equal(x, y);
case t_list:
if ((tx != ty) || Null(x) || Null(y)) {
/* X is NIL but it is not EQ to Y */
return FALSE;
}
if (!ecl_equalp(CAR(x), CAR(y)))
return(FALSE);
x = CDR(x);
y = CDR(y);
goto BEGIN;
case t_instance: {
cl_index i;
if ((ty != tx) || (ECL_CLASS_OF(x) != ECL_CLASS_OF(y)) || si_structurep(x) == ECL_NIL)
return(FALSE);
for (i = 0; i < x->instance.length; i++)
if (!ecl_equalp(x->instance.slots[i], y->instance.slots[i]))
return(FALSE);
return(TRUE);
}
case t_pathname:
return (tx == ty) && ecl_equal(x, y);
case t_hashtable: {
if (tx != ty ||
x->hash.entries != y->hash.entries ||
x->hash.test != y->hash.test)
return(FALSE);
{
cl_env_ptr env = ecl_process_env();
cl_object iterator = si_hash_table_iterator(x);
do {
cl_object ndx = _ecl_funcall1(iterator);
if (Null(ndx)) {
return TRUE;
} else {
cl_object key = env->values[1];
cl_object x_value = env->values[2];
cl_object y_value = ecl_gethash_safe(key, y, OBJNULL);
if (y_value == OBJNULL || !ecl_equalp(x_value, y_value))
return FALSE;
}
} while (1);
}
}
case t_random:
return (tx == ty) && ecl_equalp(x->random.value, y->random.value);
default:
return ecl_eql(x,y);
}
}
cl_object
cl_equalp(cl_object x, cl_object y)
{
@(return (ecl_equalp(x, y) ? ECL_T : ECL_NIL));
}
cl_object
si_fixnump(cl_object x)
{
@(return (ECL_FIXNUMP(x) ? ECL_T : ECL_NIL));
}