summaryrefslogtreecommitdiffhomepage
path: root/include
diff options
context:
space:
mode:
authorTyge Lovset <[email protected]>2023-06-29 09:32:39 +0200
committerTyge Lovset <[email protected]>2023-06-29 10:48:03 +0200
commit764d6b5a831c4ff58fb717a1360fe80f691a424d (patch)
tree55b0353d1952f749dc34d4286b25970de4039545 /include
parent5096c3c951f6b99e9d6ee04a21531e226153cca9 (diff)
downloadSTC-modified-764d6b5a831c4ff58fb717a1360fe80f691a424d.tar.gz
STC-modified-764d6b5a831c4ff58fb717a1360fe80f691a424d.zip
Usage change: comparison is no longer enabled when specifying i_val for cvec, cdeq and clist (like cstack and cqueue). Comparison functions are still required when specifying i_valclass. For fundamental/native types like integers, floats etc., define i_native_cmp along with i_val instead of i_less/i_cmp/i_eq.
Diffstat (limited to 'include')
-rw-r--r--include/stc/carc.h75
-rw-r--r--include/stc/cbox.h71
-rw-r--r--include/stc/ccommon.h4
-rw-r--r--include/stc/cdeq.h4
-rw-r--r--include/stc/clist.h13
-rw-r--r--include/stc/cqueue.h6
-rw-r--r--include/stc/cstr.h2
-rw-r--r--include/stc/csview.h2
-rw-r--r--include/stc/cvec.h18
-rw-r--r--include/stc/priv/template.h53
-rw-r--r--include/stc/priv/template2.h5
11 files changed, 145 insertions, 108 deletions
diff --git a/include/stc/carc.h b/include/stc/carc.h
index 2096b968..db0cdcec 100644
--- a/include/stc/carc.h
+++ b/include/stc/carc.h
@@ -30,6 +30,11 @@ typedef struct { cstr name, last; } Person;
Person Person_make(const char* name, const char* last) {
return (Person){.name = cstr_from(name), .last = cstr_from(last)};
}
+Person Person_clone(Person p) {
+ p.name = cstr_clone(p.name);
+ p.last = cstr_clone(p.last);
+ return p;
+}
void Person_drop(Person* p) {
printf("drop: %s %s\n", cstr_str(&p->name), cstr_str(&p->last));
cstr_drop(&p->name);
@@ -37,8 +42,8 @@ void Person_drop(Person* p) {
}
#define i_type ArcPers
-#define i_key Person
-#define i_keydrop Person_drop
+#define i_valclass Person // clone, drop, cmp, hash
+#define i_opt c_no_cmp|c_no_hash // exclude cmp, hash
#include <stc/carc.h>
int main() {
@@ -77,14 +82,7 @@ int main() {
#endif // CARC_H_INCLUDED
#define _i_prefix carc_
-#if !defined i_cmp && !defined i_less && \
- !defined i_valclass && !defined i_valboxed && \
- !defined i_val_str && !defined i_val_ssv
- #if !defined i_eq
- #define i_eq(x, y) x == y
- #endif
- #define i_less(x, y) x < y
-#endif
+#define _i_carc
#include "priv/template.h"
typedef i_keyraw _cx_raw;
@@ -178,32 +176,53 @@ STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self ptr) {
*self = ptr;
}
-#ifndef i_no_cmp
-STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry)
- { return i_cmp(rx, ry); }
+#if defined _i_has_cmp
+ STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry)
+ { return i_cmp(rx, ry); }
-STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) {
- _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get);
- return i_cmp((&rx), (&ry));
-}
+ STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) {
+ _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get);
+ return i_cmp((&rx), (&ry));
+ }
+#else
+ STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry)
+ { return c_default_cmp(&rx, &ry); }
-STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry)
- { return i_eq(rx, ry); }
+ STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) {
+ return c_default_cmp(&self->get, &other->get);
+ }
+#endif
+#if defined _i_has_eq || defined _i_has_cmp
+ STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry)
+ { return i_eq(rx, ry); }
-STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
- _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get);
- return i_eq((&rx), (&ry));
-}
+ STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
+ _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get);
+ return i_eq((&rx), (&ry));
+ }
+#else
+ STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry)
+ { return rx == ry; }
+
+ STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
+ return self->get == other->get;
+ }
#endif
+#if defined i_hash
+ STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx)
+ { return i_hash(rx); }
-#ifndef i_no_hash
-STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx)
- { return i_hash(rx); }
+ STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self)
+ { return i_hash(self->get); }
+#else
+ STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx)
+ { return c_default_hash(&rx); }
-STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self)
- { _cx_raw rx = i_keyto(self->get); return i_hash((&rx)); }
+ STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self)
+ { return c_default_hash(&self->get); }
#endif
#undef _i_atomic_inc
#undef _i_atomic_dec_and_test
#include "priv/template2.h"
+#undef _i_carc \ No newline at end of file
diff --git a/include/stc/cbox.h b/include/stc/cbox.h
index 24de71d4..c8d919b2 100644
--- a/include/stc/cbox.h
+++ b/include/stc/cbox.h
@@ -25,6 +25,7 @@
/* cbox: heap allocated boxed type
#define i_implement
#include <stc/cstr.h>
+#include <stc/algo/raii.h> // c_auto
typedef struct { cstr name, email; } Person;
@@ -41,8 +42,9 @@ void Person_drop(Person* p) {
c_drop(cstr, &p->name, &p->email);
}
-#define i_keyclass Person // bind Person clone+drop fn's
#define i_type PBox
+#define i_valclass Person // bind Person clone+drop fn's
+#define i_no_cmp // no cmp/hash is defined
#include <stc/cbox.h>
int main() {
@@ -70,14 +72,7 @@ int main() {
#endif // CBOX_H_INCLUDED
#define _i_prefix cbox_
-#if !defined i_cmp && !defined i_less && \
- !defined i_valclass && !defined i_valboxed && \
- !defined i_val_str && !defined i_val_ssv
- #if !defined i_eq
- #define i_eq(x, y) x == y
- #endif
- #define i_less(x, y) x < y
-#endif
+#define _i_cbox
#include "priv/template.h"
typedef i_keyraw _cx_raw;
@@ -164,30 +159,50 @@ STC_INLINE void _cx_MEMB(_assign)(_cx_Self* self, _cx_Self* moved) {
moved->get = NULL;
}
-#ifndef i_no_cmp
-STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry)
- { return i_cmp(rx, ry); }
-
-STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) {
- _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get);
- return i_cmp((&rx), (&ry));
-}
+#if defined _i_has_cmp
+ STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry)
+ { return i_cmp(rx, ry); }
-STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry)
- { return i_eq(rx, ry); }
+ STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) {
+ _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get);
+ return i_cmp((&rx), (&ry));
+ }
+#else
+ STC_INLINE int _cx_MEMB(_raw_cmp)(const _cx_raw* rx, const _cx_raw* ry)
+ { return c_default_cmp(&rx, &ry); }
-STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
- _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get);
- return i_eq((&rx), (&ry));
-}
+ STC_INLINE int _cx_MEMB(_cmp)(const _cx_Self* self, const _cx_Self* other) {
+ return c_default_cmp(&self->get, &other->get);
+ }
#endif
+#if defined _i_has_eq || defined _i_has_cmp
+ STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry)
+ { return i_eq(rx, ry); }
-#ifndef i_no_hash
-STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx)
- { return i_hash(rx); }
+ STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
+ _cx_raw rx = i_keyto(self->get), ry = i_keyto(other->get);
+ return i_eq((&rx), (&ry));
+ }
+#else
+ STC_INLINE bool _cx_MEMB(_raw_eq)(const _cx_raw* rx, const _cx_raw* ry)
+ { return rx == ry; }
-STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self)
- { _cx_raw rx = i_keyto(self->get); return i_hash((&rx)); }
+ STC_INLINE bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
+ return self->get == other->get;
+ }
#endif
+#if defined i_hash
+ STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx)
+ { return i_hash(rx); }
+ STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self)
+ { return i_hash(self->get); }
+#else
+ STC_INLINE uint64_t _cx_MEMB(_raw_hash)(const _cx_raw* rx)
+ { return c_default_hash(&rx); }
+
+ STC_INLINE uint64_t _cx_MEMB(_hash)(const _cx_Self* self)
+ { return c_default_hash(&self->get); }
+#endif
#include "priv/template2.h"
+#undef _i_cbox \ No newline at end of file
diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h
index 5f280218..bbf1579b 100644
--- a/include/stc/ccommon.h
+++ b/include/stc/ccommon.h
@@ -113,8 +113,8 @@
#define c_no_clone (1<<2)
#define c_no_emplace (1<<3)
#define c_no_cmp (1<<4)
-#define c_no_hash (1<<5)
-
+#define c_native_cmp (1<<5)
+#define c_no_hash (1<<6)
/* Function macros and others */
#define c_litstrlen(literal) (c_sizeof("" literal) - 1)
diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h
index 06dfdb82..2db040f1 100644
--- a/include/stc/cdeq.h
+++ b/include/stc/cdeq.h
@@ -101,7 +101,7 @@ _cx_MEMB(_emplace_at)(_cx_Self* self, _cx_iter it, const _cx_raw raw)
{ return _cx_MEMB(_insert_at)(self, it, i_keyfrom(raw)); }
#endif
-#if defined _i_has_cmp || defined _i_has_eq
+#if defined _i_has_eq || defined _i_has_cmp
STC_API _cx_iter _cx_MEMB(_find_in)(_cx_iter p1, _cx_iter p2, _cx_raw raw);
STC_INLINE _cx_iter
@@ -179,7 +179,7 @@ _cx_MEMB(_emplace_n)(_cx_Self* self, const intptr_t idx, const _cx_raw* raw, con
}
#endif
-#if defined _i_has_cmp || defined _i_has_eq
+#if defined _i_has_eq || defined _i_has_cmp
STC_DEF _cx_iter
_cx_MEMB(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) {
for (; i1.pos != i2.pos; _cx_MEMB(_next)(&i1)) {
diff --git a/include/stc/clist.h b/include/stc/clist.h
index 0785a6af..38358d73 100644
--- a/include/stc/clist.h
+++ b/include/stc/clist.h
@@ -93,11 +93,11 @@ STC_API _cx_value* _cx_MEMB(_push_front)(_cx_Self* self, i_key value);
STC_API _cx_iter _cx_MEMB(_insert_at)(_cx_Self* self, _cx_iter it, i_key value);
STC_API _cx_iter _cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it);
STC_API _cx_iter _cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter it1, _cx_iter it2);
-#if !defined i_no_cmp || defined _i_has_eq
+#if defined _i_has_eq || defined _i_has_cmp
STC_API _cx_iter _cx_MEMB(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val);
STC_API intptr_t _cx_MEMB(_remove)(_cx_Self* self, _cx_raw val);
#endif
-#ifndef i_no_cmp
+#if defined _i_has_cmp
STC_API bool _cx_MEMB(_sort_with)(_cx_Self* self, int(*cmp)(const _cx_value*, const _cx_value*));
STC_API int _cx_MEMB(_sort_cmp_)(const _cx_value*, const _cx_value*);
STC_INLINE bool _cx_MEMB(_sort)(_cx_Self* self)
@@ -188,7 +188,7 @@ _cx_MEMB(_splice_range)(_cx_Self* self, _cx_iter it,
return _cx_MEMB(_splice)(self, it, &tmp);
}
-#if !defined i_no_cmp || defined _i_has_eq
+#if defined _i_has_eq || defined _i_has_cmp
STC_INLINE _cx_iter
_cx_MEMB(_find)(const _cx_Self* self, _cx_raw val) {
return _cx_MEMB(_find_in)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), val);
@@ -350,8 +350,7 @@ _cx_MEMB(_split_off)(_cx_Self* self, _cx_iter it1, _cx_iter it2) {
return lst;
}
-#if !defined i_no_cmp || defined _i_has_eq
-
+#if defined _i_has_eq || defined _i_has_cmp
STC_DEF _cx_iter
_cx_MEMB(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw val) {
c_foreach (it, _cx_Self, it1, it2) {
@@ -379,7 +378,7 @@ _cx_MEMB(_remove)(_cx_Self* self, _cx_raw val) {
}
#endif
-#ifndef i_no_cmp
+#if defined _i_has_cmp
STC_DEF int _cx_MEMB(_sort_cmp_)(const _cx_value* x, const _cx_value* y) {
const _cx_raw a = i_keyto(x), b = i_keyto(y);
return i_cmp((&a), (&b));
@@ -401,7 +400,7 @@ STC_DEF bool _cx_MEMB(_sort_with)(_cx_Self* self, int(*cmp)(const _cx_value*, co
*i.ref = *p;
i_free(a); return true;
}
-#endif // !c_no_cmp
+#endif // _i_has_cmp
#endif // i_implement
#define CLIST_H_INCLUDED
#include "priv/template2.h"
diff --git a/include/stc/cqueue.h b/include/stc/cqueue.h
index 6eee712b..e9f1b877 100644
--- a/include/stc/cqueue.h
+++ b/include/stc/cqueue.h
@@ -63,8 +63,8 @@ STC_INLINE _cx_value* _cx_MEMB(_emplace)(_cx_Self* self, _cx_raw raw)
{ return _cx_MEMB(_push)(self, i_keyfrom(raw)); }
#endif
-#if defined _i_has_cmp || defined _i_has_eq
-STC_API bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other);
+#if defined _i_has_eq || defined _i_has_cmp
+STC_API bool _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other);
#endif
#if !defined i_no_clone
@@ -224,7 +224,7 @@ _cx_MEMB(_clone)(_cx_Self cx) {
}
#endif // i_no_clone
-#if defined _i_has_cmp || defined _i_has_eq
+#if defined _i_has_eq || defined _i_has_cmp
STC_DEF bool
_cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
if (_cx_MEMB(_size)(self) != _cx_MEMB(_size)(other)) return false;
diff --git a/include/stc/cstr.h b/include/stc/cstr.h
index ce42cf8d..0f217f53 100644
--- a/include/stc/cstr.h
+++ b/include/stc/cstr.h
@@ -433,7 +433,7 @@ cstr cstr_tocase(csview sv, int k) {
#endif // i_import
/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined i_import || defined i_implement
+#if defined i_implement
#ifndef CSTR_C_INCLUDED
#define CSTR_C_INCLUDED
diff --git a/include/stc/csview.h b/include/stc/csview.h
index 07ab4059..f960968c 100644
--- a/include/stc/csview.h
+++ b/include/stc/csview.h
@@ -150,7 +150,7 @@ STC_INLINE csview cstr_u8_substr(const cstr* self , intptr_t bytepos, intptr_t u
#endif
/* -------------------------- IMPLEMENTATION ------------------------- */
-#if defined i_import || defined i_implement
+#if defined i_implement
#ifndef CSVIEW_C_INCLUDED
#define CSVIEW_C_INCLUDED
diff --git a/include/stc/cvec.h b/include/stc/cvec.h
index 3213dd1c..6806e2bc 100644
--- a/include/stc/cvec.h
+++ b/include/stc/cvec.h
@@ -40,7 +40,7 @@ struct MyStruct {
#include <stc/cvec.h>
#define i_key int
-#define i_is_forward // forward declared
+#define i_is_forward
#define i_tag i32
#include <stc/cvec.h>
@@ -85,10 +85,10 @@ STC_API bool _cx_MEMB(_resize)(_cx_Self* self, intptr_t size, i_key n
STC_API _cx_value* _cx_MEMB(_push)(_cx_Self* self, i_key value);
STC_API _cx_iter _cx_MEMB(_erase_n)(_cx_Self* self, intptr_t idx, intptr_t n);
STC_API _cx_iter _cx_MEMB(_insert_uninit)(_cx_Self* self, intptr_t idx, intptr_t n);
-#if !defined i_no_cmp || defined _i_has_eq
+#if defined _i_has_eq || defined _i_has_cmp
STC_API _cx_iter _cx_MEMB(_find_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw);
#endif
-#ifndef i_no_cmp
+#if defined _i_has_cmp
STC_API int _cx_MEMB(_value_cmp)(const _cx_value* x, const _cx_value* y);
STC_API _cx_iter _cx_MEMB(_binary_search_in)(_cx_iter it1, _cx_iter it2, _cx_raw raw, _cx_iter* lower_bound);
#endif
@@ -214,7 +214,7 @@ STC_INLINE intptr_t _cx_MEMB(_index)(const _cx_Self* self, _cx_iter it)
STC_INLINE void _cx_MEMB(_adjust_end_)(_cx_Self* self, intptr_t n)
{ self->_len += n; }
-#if !defined i_no_cmp || defined _i_has_eq
+#if defined _i_has_eq || defined _i_has_cmp
STC_INLINE _cx_iter
_cx_MEMB(_find)(const _cx_Self* self, _cx_raw raw) {
@@ -240,7 +240,7 @@ _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
return true;
}
#endif
-#ifndef i_no_cmp
+#if defined _i_has_cmp
STC_INLINE _cx_iter
_cx_MEMB(_binary_search)(const _cx_Self* self, _cx_raw raw) {
@@ -265,7 +265,7 @@ STC_INLINE void
_cx_MEMB(_sort)(_cx_Self* self) {
_cx_MEMB(_sort_range)(_cx_MEMB(_begin)(self), _cx_MEMB(_end)(self), _cx_MEMB(_value_cmp));
}
-#endif // !c_no_cmp
+#endif // _i_has_cmp
/* -------------------------- IMPLEMENTATION ------------------------- */
#if defined(i_implement) || defined(i_static)
@@ -378,7 +378,7 @@ _cx_MEMB(_emplace_n)(_cx_Self* self, const intptr_t idx, const _cx_raw raw[], in
return it;
}
#endif // !i_no_emplace
-#if !defined i_no_cmp || defined _i_has_eq
+#if defined _i_has_eq || defined _i_has_cmp
STC_DEF _cx_iter
_cx_MEMB(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) {
@@ -392,7 +392,7 @@ _cx_MEMB(_find_in)(_cx_iter i1, _cx_iter i2, _cx_raw raw) {
return i2;
}
#endif
-#ifndef i_no_cmp
+#if defined _i_has_cmp
STC_DEF _cx_iter
_cx_MEMB(_binary_search_in)(_cx_iter i1, _cx_iter i2, const _cx_raw raw,
@@ -417,7 +417,7 @@ STC_DEF int _cx_MEMB(_value_cmp)(const _cx_value* x, const _cx_value* y) {
const _cx_raw ry = i_keyto(y);
return i_cmp((&rx), (&ry));
}
-#endif // !c_no_cmp
+#endif // _i_has_cmp
#endif // i_implement
#define CVEC_H_INCLUDED
#include "priv/template2.h"
diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h
index c1b7c1e7..03c27bdb 100644
--- a/include/stc/priv/template.h
+++ b/include/stc/priv/template.h
@@ -102,12 +102,6 @@
#if c_option(c_no_emplace)
#define i_no_emplace
#endif
-#ifdef i_eq
- #define _i_has_eq
-#endif
-#if defined i_cmp || defined i_less
- #define _i_has_cmp
-#endif
#if defined i_key_str
#define i_keyclass cstr
@@ -155,10 +149,10 @@
#endif
#ifdef i_rawclass
- #if !defined i_cmp && !defined i_no_cmp
+ #if !(defined i_cmp || defined i_no_cmp)
#define i_cmp c_PASTE(i_keyraw, _cmp)
#endif
- #if !defined i_hash && !defined i_no_hash
+ #if !(defined i_hash || defined i_no_hash || defined i_no_cmp)
#define i_hash c_PASTE(i_keyraw, _hash)
#endif
#endif
@@ -176,7 +170,7 @@
#ifndef i_tag
#define i_tag i_key
#endif
-#if c_option(c_no_clone)
+#if c_option(c_no_clone) || defined _i_carc
#define i_no_clone
#elif !(defined i_keyclone || defined i_no_clone) && (defined i_keydrop || defined i_keyraw)
#error i_keyclone/valclone should be defined when i_keydrop/valdrop or i_keyraw/valraw is defined
@@ -199,24 +193,33 @@
#define i_keydrop c_default_drop
#endif
-// i_eq, i_less, i_cmp
-#if !defined i_eq && (defined i_cmp || defined i_less)
- #define i_eq(x, y) !(i_cmp(x, y))
-#elif !defined i_eq
- #define i_eq c_default_eq
-#endif
-#if defined i_less && defined i_cmp
- #error "Only one of i_less and i_cmp may be defined"
-#elif !defined i_less && !defined i_cmp
- #define i_less c_default_less
-#elif !defined i_less
- #define i_less(x, y) (i_cmp(x, y)) < 0
-#endif
-#ifndef i_cmp
- #define i_cmp(x, y) (i_less(y, x)) - (i_less(x, y))
+#ifndef i_no_cmp
+ #if c_option(c_native_cmp) || defined i_native_cmp || defined i_cmp || defined i_less
+ #define _i_has_cmp
+ #endif
+ #if defined i_eq
+ #define _i_has_eq
+ #endif
+
+ // i_eq, i_less, i_cmp
+ #if !defined i_eq && (defined i_cmp || defined i_less)
+ #define i_eq(x, y) !(i_cmp(x, y))
+ #elif !defined i_eq
+ #define i_eq(x, y) *x == *y
+ #endif
+ #if defined i_cmp && defined i_less
+ #error "Only one of i_cmp and i_less may be defined"
+ #elif defined i_cmp
+ #define i_less(x, y) (i_cmp(x, y)) < 0
+ #elif !defined i_less
+ #define i_less(x, y) *x < *y
+ #endif
+ #ifndef i_cmp
+ #define i_cmp(x, y) (i_less(y, x)) - (i_less(x, y))
+ #endif
#endif
-#ifndef i_hash
+#if !(defined i_hash || defined _i_cbox || defined _i_carc)
#define i_hash c_default_hash
#endif
diff --git a/include/stc/priv/template2.h b/include/stc/priv/template2.h
index 47b82937..bd8bc5fc 100644
--- a/include/stc/priv/template2.h
+++ b/include/stc/priv/template2.h
@@ -67,6 +67,7 @@
#undef i_realloc
#undef i_free
+#undef i_native_cmp
#undef i_no_cmp
#undef i_no_hash
#undef i_no_clone
@@ -74,9 +75,9 @@
#undef i_is_forward
#undef i_has_emplace
+#undef _i_has_cmp
+#undef _i_has_eq
#undef _i_prefix
#undef _i_expandby
-#undef _i_has_eq
-#undef _i_has_cmp
#undef _i_template
#endif