Skip to content

Commit 95c8fd7

Browse files
committed
Total ordering
1 parent 5255788 commit 95c8fd7

File tree

8 files changed

+56
-17
lines changed

8 files changed

+56
-17
lines changed

core-misc.cc

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,12 @@ namespace MNL_AUX_UUID { using namespace aux;
107107
return !MNL_LIKELY(argv[0].rep.tag() == 0x7FF8u) || argv[0].rep.dat<void *>() != rep.dat<void *>();
108108
case 3: // Order
109109
if (MNL_UNLIKELY(argc != 1)) MNL_ERR(MNL_SYM("InvalidInvocation"));
110-
if (MNL_UNLIKELY(argv[0].rep.tag() != 0x7FF8u) || MNL_UNLIKELY(argv[0].rep.dat<void *>() != rep.dat<void *>())) MNL_ERR(MNL_SYM("TypeMismatch"));
111-
return 0;
110+
{ auto mask = MNL_AUX_RAND(uintptr_t);
111+
int res = default_order(argv[0]);
112+
return MNL_UNLIKELY(res) ? res :
113+
((reinterpret_cast<uintptr_t>(rep.dat<void *>()) ^ mask) < (reinterpret_cast<uintptr_t>(argv[0].rep.dat<void *>()) ^ mask)) -
114+
((reinterpret_cast<uintptr_t>(argv[0].rep.dat<void *>()) ^ mask) < (reinterpret_cast<uintptr_t>(rep.dat<void *>()) ^ mask));
115+
}
112116
case 4: // Clone
113117
if (MNL_UNLIKELY(argc != 0)) MNL_ERR(MNL_SYM("InvalidInvocation"));
114118
return move(*this);
@@ -162,6 +166,12 @@ namespace MNL_AUX_UUID { using namespace aux;
162166
record_descr::record_descr(initializer_list<const char *> il): record_descr([=]()->set<sym>{
163167
set<sym> res; for (auto el: il) res.insert(el); return res;
164168
}()) {}
169+
int pub::order(const record_descr &lhs, const record_descr &rhs) noexcept {
170+
auto mask = MNL_AUX_RAND(uintptr_t);
171+
return
172+
((reinterpret_cast<uintptr_t>(&*lhs.rep) ^ mask) < (reinterpret_cast<uintptr_t>(&*rhs.rep) ^ mask)) -
173+
((reinterpret_cast<uintptr_t>(&*rhs.rep) ^ mask) < (reinterpret_cast<uintptr_t>(&*lhs.rep) ^ mask));
174+
}
165175

166176
decltype(record_descr::store) record_descr::store;
167177
MNL_IF_WITH_MT(decltype(record_descr::mutex) record_descr::mutex;)

core-ops.cc

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ namespace aux {
436436
return !test<>(argv[1]);
437437
case sym::op_order:
438438
if (MNL_UNLIKELY(argc != 2)) MNL_ERR(MNL_SYM("InvalidInvocation"));
439-
if (MNL_UNLIKELY(!test<>(argv[1]))) MNL_ERR(MNL_SYM("TypeMismatch"));
439+
if (MNL_UNLIKELY(!test<>(argv[1]))) return argv[0].default_order(argv[1]);
440440
return 0;
441441
case sym::op_clone: case sym::op_deep_clone:
442442
if (MNL_UNLIKELY(argc != 1)) MNL_ERR(MNL_SYM("InvalidInvocation"));
@@ -512,7 +512,7 @@ namespace aux {
512512
return cast<long long>(argv[0]) >= cast<long long>(argv[1]);
513513
case sym::op_order:
514514
if (MNL_UNLIKELY(argc != 2)) MNL_ERR(MNL_SYM("InvalidInvocation"));
515-
if (MNL_UNLIKELY(!test<long long>(argv[1]))) MNL_ERR(MNL_SYM("TypeMismatch"));
515+
if (MNL_UNLIKELY(!test<long long>(argv[1]))) return argv[0].default_order(argv[1]);
516516
return (cast<long long>(argv[0]) > cast<long long>(argv[1])) - (cast<long long>(argv[0]) < cast<long long>(argv[1]));
517517
case sym::op_abs:
518518
if (MNL_UNLIKELY(argc != 1)) MNL_ERR(MNL_SYM("InvalidInvocation"));
@@ -580,7 +580,7 @@ namespace aux {
580580
return cast<DAT>(argv[0]) >= cast<DAT>(argv[1]); \
581581
case sym::op_order: \
582582
if (MNL_UNLIKELY(argc != 2)) MNL_ERR(MNL_SYM("InvalidInvocation")); \
583-
if (MNL_UNLIKELY(!test<DAT>(argv[1]))) MNL_ERR(MNL_SYM("TypeMismatch")); \
583+
if (MNL_UNLIKELY(!test<DAT>(argv[1]))) return argv[0].default_order(argv[1]); \
584584
return signbit(cast<DAT>(argv[0])) ^ signbit(cast<DAT>(argv[1])) ? signbit(cast<DAT>(argv[1])) - signbit(cast<DAT>(argv[0])) : \
585585
cast<DAT>(argv[0]) < cast<DAT>(argv[1]) ? -1 : cast<DAT>(argv[0]) != cast<DAT>(argv[1]); \
586586
case sym::op_abs: \
@@ -724,7 +724,7 @@ namespace aux {
724724
return !MNL_LIKELY(test<sym>(argv[1])) || cast<const sym &>(argv[0]) != cast<const sym &>(argv[1]);
725725
case sym::op_order:
726726
if (MNL_UNLIKELY(argc != 2)) MNL_ERR(MNL_SYM("InvalidInvocation"));
727-
if (MNL_UNLIKELY(!test<sym>(argv[1]))) MNL_ERR(MNL_SYM("TypeMismatch"));
727+
if (MNL_UNLIKELY(!test<sym>(argv[1]))) return argv[0].default_order(argv[1]);
728728
return (cast<sym>(argv[0]) > cast<sym>(argv[1])) - (cast<sym>(argv[0]) < cast<sym>(argv[1]));
729729
case sym::op_apply:
730730
return cast<const sym &>(argv[0])(argc - 1, argv + 1, argv_out + !!argv_out);
@@ -746,7 +746,7 @@ namespace aux {
746746
return argv[1].rep.tag() != 0x7FFEu;
747747
case sym::op_order:
748748
if (MNL_UNLIKELY(argc != 2)) MNL_ERR(MNL_SYM("InvalidInvocation"));
749-
if (MNL_UNLIKELY(!test<bool>(argv[1]))) MNL_ERR(MNL_SYM("TypeMismatch"));
749+
if (MNL_UNLIKELY(!test<bool>(argv[1]))) return argv[0].default_order(argv[1]);
750750
return +-cast<bool>(argv[1]);
751751
case sym::op_or:
752752
case sym::op_xor:
@@ -778,7 +778,7 @@ namespace aux {
778778
return argv[1].rep.tag() != 0x7FFFu;
779779
case sym::op_order:
780780
if (MNL_UNLIKELY(argc != 2)) MNL_ERR(MNL_SYM("InvalidInvocation"));
781-
if (MNL_UNLIKELY(!test<bool>(argv[1]))) MNL_ERR(MNL_SYM("TypeMismatch"));
781+
if (MNL_UNLIKELY(!test<bool>(argv[1]))) return argv[0].default_order(argv[1]);
782782
return +!cast<bool>(argv[1]);
783783
case sym::op_and:
784784
if (MNL_UNLIKELY(argc != 2)) MNL_ERR(MNL_SYM("InvalidInvocation"));
@@ -854,7 +854,7 @@ namespace aux {
854854
return cast<unsigned>(argv[0]) >= cast<unsigned>(argv[1]);
855855
case sym::op_order:
856856
if (MNL_UNLIKELY(argc != 2)) MNL_ERR(MNL_SYM("InvalidInvocation"));
857-
if (MNL_UNLIKELY(!test<unsigned>(argv[1]))) MNL_ERR(MNL_SYM("TypeMismatch"));
857+
if (MNL_UNLIKELY(!test<unsigned>(argv[1]))) return argv[0].default_order(argv[1]);
858858
return (cast<unsigned>(argv[0]) > cast<unsigned>(argv[1])) - (cast<unsigned>(argv[0]) < cast<unsigned>(argv[1]));
859859
case sym::op_abs:
860860
if (MNL_UNLIKELY(argc != 1)) MNL_ERR(MNL_SYM("InvalidInvocation"));
@@ -1225,7 +1225,7 @@ namespace aux {
12251225
return !MNL_LIKELY(test<string>(argv[0])) || (MNL_IF_WITH_IDENT_OPT(&dat != &cast<const string &>(argv[0]) &&) dat != cast<const string &>(argv[0]));
12261226
case sym::op_order:
12271227
if (MNL_UNLIKELY(argc != 1)) MNL_ERR(MNL_SYM("InvalidInvocation"));
1228-
if (MNL_UNLIKELY(!test<string>(argv[0]))) MNL_ERR(MNL_SYM("TypeMismatch"));
1228+
if (MNL_UNLIKELY(!test<string>(argv[0]))) return self.default_order(argv[0]);
12291229
MNL_IF_WITH_IDENT_OPT(if (&dat == &cast<const string &>(argv[0])) return 0;)
12301230
for (auto lhs = dat.cbegin(), rhs = cast<const string &>(argv[0]).begin();; ++lhs, ++rhs) {
12311231
if (MNL_UNLIKELY(lhs == dat.cend())) return -(rhs != cast<const string &>(argv[0]).end());
@@ -1416,7 +1416,7 @@ namespace aux {
14161416
}
14171417
case sym::op_order:
14181418
if (MNL_UNLIKELY(argc != 1)) MNL_ERR(MNL_SYM("InvalidInvocation"));
1419-
if (MNL_UNLIKELY(!test<vector<val>>(argv[0]))) MNL_ERR(MNL_SYM("TypeMismatch"));
1419+
if (MNL_UNLIKELY(!test<vector<val>>(argv[0]))) return self.default_order(argv[0]);
14201420
MNL_IF_WITH_IDENT_OPT(if (&dat == &cast<const vector<val> &>(argv[0])) return 0;)
14211421
for (auto lhs = dat.cbegin(), rhs = cast<const vector<val> &>(argv[0]).begin();; ++lhs, ++rhs) {
14221422
if (MNL_UNLIKELY(lhs == dat.cend())) return -(rhs != cast<const vector<val> &>(argv[0]).end());
@@ -1554,8 +1554,9 @@ namespace aux {
15541554
return false;
15551555
case sym::op_order:
15561556
if (MNL_UNLIKELY(argc != 1)) MNL_ERR(MNL_SYM("InvalidInvocation"));
1557-
if (MNL_UNLIKELY(!test<_record>(argv[0])) || MNL_UNLIKELY(descr != cast<const _record &>(argv[0]).descr)) MNL_ERR(MNL_SYM("TypeMismatch"));
1557+
if (MNL_UNLIKELY(!test<_record>(argv[0]))) return self.default_order(argv[0]);
15581558
MNL_IF_WITH_IDENT_OPT(if (this == &cast<const _record &>(argv[0])) return 0;)
1559+
{ int res = order(descr, cast<const _record &>(argv[0]).descr); if (MNL_UNLIKELY(res)) return res; }
15591560
for (auto lhs = begin(const_cast<const _record *>(this)->items), rhs = begin(cast<const _record &>(argv[0]).items); lhs != end(items); ++lhs, ++rhs)
15601561
{ auto res = safe_cast<long long>(op(args<2>{*lhs, *rhs})); if (MNL_UNLIKELY(res)) return res; }
15611562
return 0;

lib-0.5-all.mnl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,4 +452,5 @@
452452
Out; Err; In; OpenFile; OpenPipe; OpenTemp; IsStream -- 7
453453
StartThread; MakeMutex; MakeCond; IsMutex; IsCond -- 5
454454
Random; Clock; Delay -- 3
455+
OrderEx
455456
}

lib-base-main2.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1879,6 +1879,12 @@ namespace aux { extern "C" code mnl_aux_base() { // main ///////////////////////
18791879
if (MNL_UNLIKELY(argc != 1)) MNL_ERR(MNL_SYM("InvalidInvocation"));
18801880
return argv[0].is_list();
18811881
}};
1882+
struct proc_OrderEx { MNL_INLINE static val invoke(val &&self, const sym &op, int argc, val argv[], val *) {
1883+
if (MNL_UNLIKELY(op != MNL_SYM("Apply"))) return self.default_invoke(op, argc, argv);
1884+
if (MNL_UNLIKELY(argc != 2)) MNL_ERR(MNL_SYM("InvalidInvocation"));
1885+
int res = argv[0].default_order(argv[1]);
1886+
return MNL_LIKELY(res) ? res : MNL_SYM("Order")(2, argv);
1887+
}};
18821888
return expr_export{
18831889
{"=", comp_set{}},
18841890
{"!", comp_move{}},
@@ -1941,6 +1947,7 @@ namespace aux { extern "C" code mnl_aux_base() { // main ///////////////////////
19411947
{"Bind", make_lit(proc_Bind{})},
19421948
{"Min", make_lit(proc_Min{})},
19431949
{"Max", make_lit(proc_Max{})},
1950+
{"OrderEx", make_lit(proc_OrderEx{})},
19441951
};
19451952
}}
19461953

lib-base-ops-composite.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ namespace aux { namespace {
195195
}
196196
case 10: // Order
197197
if (MNL_UNLIKELY(argc != 1)) MNL_ERR(MNL_SYM("InvalidInvocation"));
198-
if (MNL_UNLIKELY(!test<dict<val, val>>(argv[0]))) MNL_ERR(MNL_SYM("TypeMismatch"));
198+
if (MNL_UNLIKELY(!test<dict<val, val>>(argv[0]))) return self.default_order(argv[0]);
199199
MNL_IF_WITH_IDENT_OPT(if (&dat == &cast<const dict<val, val> &>(argv[0])) return 0;)
200200
for (auto lhs = dat.cbegin(), rhs = cast<const dict<val, val> &>(argv[0]).begin();; ++lhs, ++rhs) {
201201
if (MNL_UNLIKELY(lhs == dat.cend())) return -(rhs != cast<const dict<val, val> &>(argv[0]).end());
@@ -359,7 +359,7 @@ namespace aux { namespace {
359359
}
360360
case 15: // Order
361361
if (MNL_UNLIKELY(argc != 1)) MNL_ERR(MNL_SYM("InvalidInvocation"));
362-
if (MNL_UNLIKELY(!test<dict<val>>(argv[0]))) MNL_ERR(MNL_SYM("TypeMismatch"));
362+
if (MNL_UNLIKELY(!test<dict<val>>(argv[0]))) return self.default_order(argv[0]);
363363
MNL_IF_WITH_IDENT_OPT(if (&dat == &cast<const dict<val> &>(argv[0])) return 0;)
364364
for (auto lhs = dat.cbegin(), rhs = cast<const dict<val> &>(argv[0]).begin();; ++lhs, ++rhs) {
365365
if (MNL_UNLIKELY(lhs == dat.cend())) return -(rhs != cast<const dict<val> &>(argv[0]).end());
@@ -566,7 +566,7 @@ namespace aux { namespace {
566566
}
567567
case 10: // Order
568568
if (MNL_UNLIKELY(argc != 1)) MNL_ERR(MNL_SYM("InvalidInvocation"));
569-
if (MNL_UNLIKELY(!test<list<val>>(argv[0]))) MNL_ERR(MNL_SYM("TypeMismatch"));
569+
if (MNL_UNLIKELY(!test<list<val>>(argv[0]))) return self.default_order(argv[0]);
570570
MNL_IF_WITH_IDENT_OPT(if (&dat == &cast<const list<val> &>(argv[0])) return 0;)
571571
for (auto lhs = dat.cbegin(), rhs = cast<const list<val> &>(argv[0]).begin();; ++lhs, ++rhs) {
572572
if (MNL_UNLIKELY(lhs == dat.cend())) return -(rhs != cast<const list<val> &>(argv[0]).end());

lib-base-ops-misc.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ namespace MNL_AUX_UUID { using namespace aux;
203203
return move(self);
204204
case 4: // Order
205205
if (MNL_UNLIKELY(argc != 1)) MNL_ERR(MNL_SYM("InvalidInvocation"));
206-
if (MNL_UNLIKELY(!test<w_pointer>(argv[0]))) MNL_ERR(MNL_SYM("TypeMismatch"));
206+
if (MNL_UNLIKELY(!test<w_pointer>(argv[0]))) return self.default_order(argv[0]);
207207
{ auto mask = MNL_AUX_RAND(uintptr_t);
208208
return
209209
((reinterpret_cast<uintptr_t>(this) ^ mask) > (reinterpret_cast<uintptr_t>(&cast<const w_pointer &>(argv[0])) ^ mask)) -
@@ -237,7 +237,7 @@ namespace MNL_AUX_UUID { using namespace aux;
237237
return weak;
238238
case 5: // Order
239239
if (MNL_UNLIKELY(argc != 1)) MNL_ERR(MNL_SYM("InvalidInvocation"));
240-
if (MNL_UNLIKELY(!test<s_pointer>(argv[0]))) MNL_ERR(MNL_SYM("TypeMismatch"));
240+
if (MNL_UNLIKELY(!test<s_pointer>(argv[0]))) return self.default_order(argv[0]);
241241
{ auto mask = MNL_AUX_RAND(uintptr_t);
242242
return
243243
((reinterpret_cast<uintptr_t>(this) ^ mask) > (reinterpret_cast<uintptr_t>(&cast<const s_pointer &>(argv[0])) ^ mask)) -

manool.cc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,23 @@ namespace MNL_AUX_UUID { using namespace aux;
391391
return res;
392392
}
393393

394+
int val::default_order(const val &rhs) const noexcept {
395+
auto mask1 = MNL_AUX_RAND(unsigned);
396+
auto mask2 = MNL_AUX_RAND(size_t);
397+
bool mask3 = MNL_AUX_RAND(unsigned) & 1;
398+
return
399+
MNL_LIKELY(rep.tag() != 0x7FF8u) || MNL_LIKELY(rhs.rep.tag() != 0x7FF8u) ?
400+
(((~rep.tag() & 0x7FF0u ? 0 : rep.tag()) ^ mask1) < ((~rhs.rep.tag() & 0x7FF0u ? 0 : rhs.rep.tag()) ^ mask1)) -
401+
(((~rhs.rep.tag() & 0x7FF0u ? 0 : rhs.rep.tag()) ^ mask1) < ((~rep.tag() & 0x7FF0u ? 0 : rep.tag()) ^ mask1)) :
402+
MNL_LIKELY(!test<object>()) || MNL_LIKELY(!rhs.test<object>()) ?
403+
(typeid(*static_cast<root *>(rep.dat<void *>())).hash_code() ^ mask2) < (typeid(*static_cast<root *>(rhs.rep.dat<void *>())).hash_code() ^ mask2) ? -1 :
404+
(typeid(*static_cast<root *>(rhs.rep.dat<void *>())).hash_code() ^ mask2) < (typeid(*static_cast<root *>(rep.dat<void *>())).hash_code() ^ mask2) ? +1 :
405+
typeid(*static_cast<root *>(rep.dat<void *>())).before(typeid(*static_cast<root *>(rhs.rep.dat<void *>()))) ? mask3 ? -1 : +1 :
406+
typeid(*static_cast<root *>(rhs.rep.dat<void *>())).before(typeid(*static_cast<root *>(rep.dat<void *>()))) ? mask3 ? +1 : -1 : 0 :
407+
// else
408+
order(cast<const object &>().descr, rhs.cast<const object &>().descr);
409+
}
410+
394411
code expr_export::compile(code &&, const pub::form &form, const loc &_loc) const {
395412
if (form.size() < 3 || form[1] != MNL_SYM("in")) err_compile("invalid form", _loc);
396413
if (form.size() == 3 && test<sym>(form[2])) for (auto &&el: bind) if (MNL_UNLIKELY(el.first == cast<const sym &>(form[2]))) return el.second; // shortcut

mnl-aux-core.tcc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ namespace aux { namespace pub {
217217
val operator()(int argc, val argv[], val *argv_out = {}) &&; // functional application - !argc => !argv && !argv_out
218218
val default_invoke(const sym &op, int argc, val argv[]);
219219
long rc /*reference counter*/() const noexcept;
220+
int default_order(const val &) const noexcept; // actually from MANOOL API
220221
private: // Concrete representation
221222
static_assert(sizeof(double) == 8, "sizeof(double) == 8");
222223
class MNL_ALIGN(8) rep { // bit-layout management - IEEE 754 FP representation and uniform FP endianness are assumed (and NOT checked)
@@ -835,6 +836,7 @@ namespace aux { namespace pub {
835836
MNL_INLINE int operator[](const sym &id) const noexcept { return tab()[id]; }
836837
MNL_INLINE bool has(const sym &id) const noexcept { return (*this)[id] != (unsigned char)-1; }
837838
MNL_INLINE friend bool operator==(const record_descr &lhs, const record_descr &rhs) noexcept { return lhs.rep == rhs.rep; }
839+
friend int order(const record_descr &, const record_descr &) noexcept;
838840
private: // Concrete representation and implementation helpers
839841
static map<set<sym>, pair<const sym::tab<unsigned char>, /*atomic*/ long>> store;
840842
decltype(store)::iterator rep;
@@ -843,6 +845,7 @@ namespace aux { namespace pub {
843845
};
844846
MNL_INLINE inline void swap(record_descr &lhs, record_descr &rhs) noexcept { lhs.swap(rhs); }
845847
bool operator==(const record_descr &, const record_descr &) noexcept;
848+
int order (const record_descr &, const record_descr &) noexcept;
846849
MNL_INLINE inline bool operator!=(const record_descr &lhs, const record_descr &rhs) noexcept { return std::rel_ops::operator!=(lhs, rhs); }
847850
}} // namespace aux::pub
848851
# define MNL_RECORD_DESCR(...) MNL_AUX_INIT(::mnl::record_descr({__VA_ARGS__}))

0 commit comments

Comments
 (0)