#include <gtest/gtest.h>
#include <pgs/sum_type.hpp>
#include <string>
#include <utility>
#include <numeric>
#include <iterator>
#include <iostream>
namespace {
namespace tree_detail {
struct empty_t {};
template <class T, class V> struct node_t;
template <class K, class V>
template <class K, class V>
struct node_t {
using tree_type = tree<K, V>;
template <class D, class L, class R>
node_t (D&& data, L&& left_child, R&& right_child)
: data {std::forward<D>(data)}
, left_child {std::forward<L> (left_child)}
, right_child {std::forward<R> (right_child)}
{}
value_type data;
tree_type left_child;
tree_type right_child;
};
template <class K, class V>
bool empty (tree<K, V> const& t) {
return t.template is<empty_t> ();
}
template <class K, class V, class AccT, class F>
AccT fold (tree<K, V> const& t, AccT const& z, F f) {
return t.template match<AccT>(
[&z](empty_t const&) -> AccT { return z; },
[=, &z](node_t<K, V> const& n) -> AccT {
auto const& b = n.data;
auto const& l = n.left_child;
auto const& r = n.right_child;
return fold(r, f (fold (l, z, f), b), f);
}
);
}
template <class K, class V, class P>
tree<K, V> insert (tree<K, V> const& t, P&& p) {
return t.template match<tree<K, V>> (
[&p](empty_t) {
return tree<K, V>{
, std::forward<P>(p)
};
},
[&p](node_t<K, V> const& m) {
K const& k = p.first;
V const& v = p.second;
K const& a = m.data.first;
tree<K, V> const& l = m.left_child;
tree<K, V> const& r = m.right_child;
if (k == a)
return tree<K, V>{
, std::forward<P> (p), l, r};
if (k < a) {
return tree<K, V>{
, m.data, insert (l, p), r};
}
return tree<K, V>{
, m.data, l, insert (r, p)};
}
);
}
template <class K, class V>
bool contains (tree<K, V> const& t, K const& k) {
return t.template match<bool>(
[](empty_t) { return false; },
[&k](node_t<K, V> const& n) {
auto const& a = n.data.first;
auto const& l = n.left_child;
auto const& r = n.right_child;
if (k == a) return true;
if (k < a) return contains (l, k);
return contains (r, k);
}
);
}
template <class K, class V>
V const& lookup (tree<K, V> const& t, K const& k) {
return t.template match<V const&>(
[](empty_t const&) -> V const& {
},
[&k](node_t<K, V> const& n) -> V const& {
auto const& a = n.data.first;
auto const& l = n.left_child;
auto const& r = n.right_child;
if (k == a) return n.data.second;
if (k < a) return lookup (l, k);
return lookup (r, k);
}
);
}
template <class K, class V, class P>
auto f = [&p](
auto const& l = acc.first;
auto const& r = acc.second;
if (p (b))
};
}
template <class K, class V>
return t.template match<std::pair<K, V> const&>(
},
auto const& l = n.left_child;
if (empty (l)) return n.data;
return min_binding (l);
}
);
}
template <class K, class V>
return t.template match<std::pair<K, V> const&>(
},
auto const& r = n.right_child;
if (empty (r)) return n.data;
return max_binding (r);
}
);
}
using empty_type = empty_t;
template<class K, class V>
using node_type =node_t<K, V>;
template<class K, class V>
using value_type = typename node_type<K, V>::value_type;
template <class K, class V>
using tree_type = typename node_type<K, V>::tree_type;
}
template <class K, class V>
class binary_search_tree {
private:
using empty_type = tree_detail::empty_t;
using node_type = tree_detail::node_type<K, V>;
using value_type = typename node_type::value_type;
using tree_type = typename node_type::tree_type;
using self_type = binary_search_tree<K, V>;
private:
tree_type impl_;
private:
template <
class T,
class = pgs::enable_if_t<
>
binary_search_tree (T&& n) : impl_{std::forward<T> (n)}
{}
public:
{}
bool empty () {
return tree_detail::empty (impl_);
}
template <class AccT, class F>
AccT fold (AccT const& z, F f) const {
return tree_detail::fold (impl_, z, f);
}
template <class P>
self_type insert (P&& p) const {
return self_type { tree_detail::insert (impl_, std::forward<P>(p))};
}
self_type remove (K const& k) const {
return this->fold (self_type {},
[&k](self_type const& acc, value_type const& p) -> self_type {
return k == p.first ? acc : acc.insert (p);
});
}
, [](
std::size_t acc, value_type
const&) {
return ++acc; });
}
bool contains (K const& k) const {
return tree_detail::contains (impl_, k);
}
V const& lookup (K const& k) const {
return tree_detail::lookup (impl_, k);
}
template <class ItT>
ItT bindings (ItT dst) const {
return this->fold (dst, [](ItT dst, value_type const& n) {
return *dst++ = n; });
}
template <class P>
bool for_all (P const& p) const {
return this->fold (true, [&p](bool acc, value_type const& n) {
return acc && p (n); });
}
template <class P>
bool exists (P const& p) const {
return fold (false, [&p](bool acc, value_type const& n) {
return acc || p (n); });
}
template <class P>
self_type filter (P const& p) const {
auto f = [&p](self_type const& acc, value_type const& b) {
if (p (b))
return acc.insert (b);
return acc;
};
return this->fold (self_type{}, f);
}
template <class P>
}
template <class F>
auto map (F f) ->
binary_search_tree<K, decltype (f (std::declval<V>()))> {
auto l = [=](self_type const& acc, value_type const& b) {
};
return this->fold (self_type{}, l);
}
value_type min_binding () const {
return tree_detail::min_binding (impl_);
}
value_type max_binding () const {
return tree_detail::max_binding (impl_);
}
};
template <class ItT>
struct tree_type_from_it {
using key_t = typename node_t::first_type;
using val_t = typename node_t::second_type;
using tree_t = binary_search_tree<key_t, val_t>;
using type = tree_t;
};
template <class ItT>
using tree_type_from_it_t =typename tree_type_from_it<ItT>::type;
template <class ItT>
tree_type_from_it_t<ItT> mk_tree (ItT
begin, ItT
end) {
using tree_t = tree_type_from_it_t<ItT>;
tree_t l;
for (; begin != end; l = l.insert(*begin++));
return l;
}
}
TEST (
pgs, tree2_basic) {
using tree_t = binary_search_tree<int, std::string>;
tree_t t;
ASSERT_TRUE(t.empty ());
tree_t tt = t.insert (
ASSERT_EQ(tt.size (), 2);
tree_t ttt = tt.remove (2);
ASSERT_EQ(ttt.size (), 1);
}
template <class K, class V>
std::ostream& operator << (std::ostream& os, std::pair<K, V>
const& p) {
return os << "(" << p.first << ", " << p.second << ")";
}
}
using tree_t = binary_search_tree<std::string, int>;
node_t data[] = {
};
tree_t ages = mk_tree (data, data + 5);
EXPECT_EQ (ages.size (), 5);
EXPECT_TRUE (ages.contains (
std::string {
"sebastien"}));
EXPECT_FALSE (ages.for_all (everyone_of_age));
auto no_senior_citizen = [](node_t const& b) { return b.second < 70; };
EXPECT_TRUE (ages.for_all (no_senior_citizen));
auto sebastien = [](node_t const& b) { return b.first == "sebastien"; };
EXPECT_TRUE (ages.exists (sebastien));
auto gru = [](node_t const& b) { return b.first == "gru"; };
EXPECT_FALSE (ages.exists (gru));
auto logans_run = ages.filter ([](node_t const& b) { return b.second >= 35; });
EXPECT_EQ (logans_run.size (), 2);
auto pp = ages.partition ([](node_t const& b) { return b.second < 30; });
ages = ages.map ([](int age) { return ++age; });
}