Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ endif ()

add_library(libpl ${LIBRARY_TYPE}
source/pl/helpers/utils.cpp
source/pl/helpers/sort_checks.cpp

source/pl/pattern_language.cpp

Expand Down
4 changes: 3 additions & 1 deletion lib/include/pl/core/token.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,10 @@ namespace pl::core {
constexpr bool operator==(const Comment &) const = default;
};

using LiteralVariantType = std::variant<char, bool, u128, i128, double, std::string, std::shared_ptr<ptrn::Pattern>>;

struct Literal : std::variant<char, bool, u128, i128, double, std::string, std::shared_ptr<ptrn::Pattern>> {

struct Literal : LiteralVariantType {
using variant::variant;

[[nodiscard]] std::shared_ptr<ptrn::Pattern> toPattern() const;
Expand Down
139 changes: 139 additions & 0 deletions lib/include/pl/helpers/sort_checks.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#pragma once

//#define ENABLE_STD_SORT_CHECKS

#ifdef ENABLE_STD_SORT_CHECKS
#include <cstddef>
#endif

#include <algorithm>

namespace pl::hlp {

#ifdef ENABLE_STD_SORT_CHECKS

void sortPredicateError(const char *pMsg);
void transitivityError(const char *pMsg, std::size_t b_idx, std::size_t e_idx, std::size_t x_idx, std::size_t y_idx);

// Logical implication
inline bool imp(bool l, bool r) {
return !(l && !r);
}

template <typename Predicate>
auto checked_pedicate(const Predicate pred) {
return [=](const auto &l, const auto &r) {
// Irreflexivity: !(x<x)
if (pred(l,l))
sortPredicateError("Irreflexivity: pred(l,l) is false");
if (pred(r,r))
sortPredicateError("Irreflexivity: pred(r,r) is false");

// Asymmetry: if l<r not r<l
if (!imp(pred(l,r), !pred(r,l)))
sortPredicateError("Asymmetry: if pred(l,r) then !pred(r,l) is false");
if (!imp(pred(r,l), !pred(l,r)))
sortPredicateError("Asymmetry: if pred(r,l) then !pred(l,r) is false");

return pred(l, r);
};
}

namespace impl {

// Transitivity:
// For all x,y.z in [b, e)
// if pred(x,y) and pred(y,z) are true then pred(x,z) is true
//
// All elements in [b, e) should have already been sorted so
// b[n]<b[n+1]. We'll assume this even though with a dogy predicate
// it may not be the case.
template <typename Iter, typename Predicate>
void transitivity(const Iter cb, const Iter b, const Iter e, const Predicate pred)
{
for (Iter l=b; l<e-2; ++l) {
for (Iter r=l+2; r<e; ++r) {
if (!pred(*l, *r)) {
transitivityError("Transitivity", b-cb, e-cb-1, l-cb, r-cb);
// For all x (at index n) in [b, e-1):
// pred(b[n], b[n+1]) == true
// pred(*l, *r) returned false however. This is in violation
// of a strict weak ordering.
}
}
}
}

// For all x,y.z in [b, e)
// if !pred(x,y) && !pred(y,x) && !pred(y,z) && !pred(z,y)
// then
// !pred(x,z) && !pred(z,x)
//
// Incomparability is perhaps better undersood as equality.
template <typename Iter, typename Predicate>
void transitivity_of_incomparability(const Iter cb, const Iter b, const Iter e, const Predicate pred)
{
for (Iter l=b; l<e-2; ++l) {
for (Iter r=l+2; r<e; ++r) {
if (!(!pred(*l, *r) && !pred(*r, *l))) {
transitivityError("Transitivity of incomparability", b-cb, e-cb-1, l-cb, r-cb);
// For all x (at index n) in [b, e-1):
// pred(b[n], b[n+1]) == false && pred(b[n+1], b[n]) == false
// (!pred(*l, *r) && !pred(*r, *l)) returned false however. This is in violation
// of a strict weak ordering.
}
}
}
}

} // namespace impl

template <typename Iter, typename Predicate>
void post_sort_check(const Iter b, const Iter e, const Predicate pred) {
if (b==e)
return;

for (Iter l=b; l<e-1;) {
if (pred(*l, *(l+1))) {
Iter r = l+1;
for (; r<e-1 && pred(*r, *(r+1)); ++r) {}
impl::transitivity(b, l, r+1, pred);
l = r;
} else if (!pred(*(l+1), *l)) {
Iter r = l+1;
for (; r<e-1 && !pred(*(r+1), *r) && !pred(*r, *(r+1)); ++r) {}
impl::transitivity_of_incomparability(b, l, r+1, pred);
l = r;
}
else {
// !pred(*l, *(l+1)) && pred(*(l+1), *l)
// So l>=r && l>r
sortPredicateError("Not sorted"); // NOT sorted!
++l;
}
}
}

#endif // ENABLE_STD_SORT_CHECKS

template<typename RandomIt, typename Compare>
void checked_sort(RandomIt first, RandomIt last, Compare comp) {
#ifdef ENABLE_STD_SORT_CHECKS
std::sort(first, last, checked_pedicate(comp));
post_sort_check(first, last, comp);
#else
std::sort(first, last, comp);
#endif
}

template<typename RandomIt, typename Compare>
void checked_stable_sort(RandomIt first, RandomIt last, Compare comp) {
#ifdef ENABLE_STD_SORT_CHECKS
std::stable_sort(first, last, checked_pedicate(comp));
post_sort_check(first, last, comp);
#else
std::stable_sort(first, last, comp);
#endif
}

} // namespace pl::hlp
31 changes: 31 additions & 0 deletions lib/include/pl/helpers/variant_type_index.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#pragma once

#include <variant>
#include <type_traits>
#include <cstddef>

namespace pl::hlp {

template<typename T, typename Variant>
struct variant_type_index;

template<typename T, typename... Ts>
struct variant_type_index<T, std::variant<Ts...>> {
static constexpr auto value = [] -> std::size_t {
static_assert(
(std::is_same_v<std::remove_cvref_t<T>, Ts> || ...),
"T not in std::variant");
constexpr bool matches[] = { std::is_same_v<std::remove_cvref_t<T>, Ts>... };

for (std::size_t i=0; i<sizeof...(Ts); ++i) {
if (matches[i]) { return i; }
}

return -1;
}();
};

template<class T, class Variant>
inline constexpr std::size_t variant_type_index_v = variant_type_index<T, Variant>::value;

} // namespace pl::hlp
5 changes: 3 additions & 2 deletions lib/include/pl/patterns/pattern_bitfield.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <pl/patterns/pattern.hpp>
#include <pl/patterns/pattern_enum.hpp>
#include <pl/helpers/sort_checks.hpp>

namespace pl::ptrn {

Expand Down Expand Up @@ -497,7 +498,7 @@ namespace pl::ptrn {
for (auto &member : this->m_entries)
this->m_sortedEntries.push_back(member.get());

std::sort(this->m_sortedEntries.begin(), this->m_sortedEntries.end(), comparator);
pl::hlp::checked_sort(this->m_sortedEntries.begin(), this->m_sortedEntries.end(), comparator);
if (this->isReversed())
std::reverse(this->m_sortedEntries.begin(), this->m_sortedEntries.end());

Expand Down Expand Up @@ -774,7 +775,7 @@ namespace pl::ptrn {
for (auto &member : this->m_fields)
this->m_sortedFields.push_back(member.get());

std::sort(this->m_sortedFields.begin(), this->m_sortedFields.end(), comparator);
pl::hlp::checked_sort(this->m_sortedFields.begin(), this->m_sortedFields.end(), comparator);
if (this->isReversed())
std::reverse(this->m_sortedFields.begin(), this->m_sortedFields.end());

Expand Down
4 changes: 2 additions & 2 deletions lib/include/pl/patterns/pattern_struct.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <pl/patterns/pattern.hpp>
#include <pl/helpers/sort_checks.hpp>

namespace pl::ptrn {

Expand Down Expand Up @@ -160,8 +161,7 @@ namespace pl::ptrn {
for (auto &member : this->m_members)
this->m_sortedMembers.push_back(member.get());

std::sort(this->m_sortedMembers.begin(), this->m_sortedMembers.end(), comparator);

pl::hlp::checked_sort(this->m_sortedMembers.begin(), this->m_sortedMembers.end(), comparator);
for (auto &member : this->m_sortedMembers)
member->sort(comparator);
}
Expand Down
3 changes: 2 additions & 1 deletion lib/include/pl/patterns/pattern_union.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <pl/patterns/pattern.hpp>
#include <pl/helpers/sort_checks.hpp>

namespace pl::ptrn {

Expand Down Expand Up @@ -159,7 +160,7 @@ namespace pl::ptrn {
for (auto &member : this->m_members)
this->m_sortedMembers.push_back(member.get());

std::sort(this->m_sortedMembers.begin(), this->m_sortedMembers.end(), comparator);
pl::hlp::checked_sort(this->m_sortedMembers.begin(), this->m_sortedMembers.end(), comparator);

for (auto &member : this->m_members)
member->sort(comparator);
Expand Down
5 changes: 3 additions & 2 deletions lib/source/pl/core/token.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <pl/helpers/utils.hpp>
#include <pl/helpers/concepts.hpp>
#include <pl/helpers/variant_type_index.hpp>
#include <variant>

namespace pl::core {
Expand Down Expand Up @@ -160,8 +161,8 @@ namespace pl::core {
return std::strong_ordering::greater;
}
},
[](auto, auto) -> std::strong_ordering {
return std::strong_ordering::equal;
[]<typename TL, typename TR>(TL, TR) -> std::strong_ordering {
return hlp::variant_type_index_v<TL, LiteralVariantType> <=> hlp::variant_type_index_v<TR, LiteralVariantType>;
}
}, *this, other);
}
Expand Down
25 changes: 25 additions & 0 deletions lib/source/pl/helpers/sort_checks.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include <pl/helpers/sort_checks.hpp>

#ifdef ENABLE_STD_SORT_CHECKS
#include <cstddef>
#include <iostream>

using std::size_t;
using std::cout;
using std::endl;

namespace pl::hlp {

void sortPredicateError(const char *pMsg) {
cout << pMsg << endl;
}

void transitivityError(const char *pMsg, size_t b_idx, size_t e_idx, size_t x_idx, size_t y_idx) {
cout << pMsg << endl
<< " Run: " << "b_idx=" << b_idx << ", e_idx=" << e_idx << endl
<< " Error: " << "x_idx=" << x_idx << ", y_idx=" << y_idx << endl;
}

} // namespace pl::hlp

#endif // ENABLE_STD_SORT_CHECKS
Loading