#include <pgs/pgs.hpp>
#include <gtest/gtest.h>
#include <memory>
#include <vector>
#include <iterator>
#include <algorithm>
#include <iostream>
#include <sstream>
namespace {
namespace detail {
template <class T> struct array_data;
template <class T>
struct array_t {
array_t (int n, T const& val)
: data (n, val)
{}
{}
};
template <class T>
struct diff_t {
T v;
persistent_array<T> t;
diff_t (
std::size_t i, T
const& v, persistent_array<T>
const& t)
: i{i}, v{v}, t{t}
{}
};
template <class T>
struct array_data :
sum_type<array_t<T>, diff_t<T>> {
template <class U, class... Args>
: base_type{t, std::forward<Args>(args)...}
{}
};
template <class T>
persistent_array<T> make (int n, T const& val) {
return persistent_array<T>{
}
template <class T>
T
const&
get (persistent_array<T>
const& t,
std::size_t i) {
return t->template match<T const&>(
[=](array_t<T> const& a) -> T const& {
return a.data[i];
}
, [=](diff_t<T> const& d) -> T const& {
return (i == d.i) ? d.v : get (d.t, i); });
}
template <class T>
persistent_array<T> set (
persistent_array<T> const& t
return t->template match<persistent_array<T>>(
[&t, &v, i](array_t<T>& a) -> persistent_array<T> {
T old = a.data[i];
a.data[i] = v;
persistent_array<T> res{
return res;
}
, [t, v, i](diff_t<T>& d) -> persistent_array<T> {
return persistent_array<T>{
});
}
template <class T>
return t->template match<std::ostream&>(
os << "[| ";
os << "|]";
return os;
}
os << "Diff (";
os << d.i << ", " << d.v << ", " << d.t;
os << ")";
return os;
});
}
template <class T>
std::string string_of_persistent_array (persistent_array<T>
const& t) {
os << t;
}
}
template <class T>
class persistent_array {
private:
detail::persistent_array<T> impl_;
private:
persistent_array (detail::persistent_array<T> a)
: impl_{a}
{}
public:
persistent_array (int n, T const& val)
: impl_{ detail::make (n, val)}
{}
return detail::get (impl_, i);
}
persistent_array<T> set (
std::size_t i, T
const& val)
const {
return persistent_array<T>{detail::set (impl_, i, val)};
}
return detail::string_of_persistent_array (impl_);
}
};
}
persistent_array<int> a0{7, 0};
persistent_array<int> a1 = a0.set (1, 7);
persistent_array<int> a2 = a1.set (2, 8);
persistent_array<int> a3 = a1.set (2, 9);
ASSERT_EQ (
a0.as_string ()
,
std::string (
"Diff (1, 0, Diff (2, 0, [| 0; 7; 8; 0; 0; 0; 0; |]))"));
ASSERT_EQ (
a1.as_string ()
,
std::string (
"Diff (2, 0, [| 0; 7; 8; 0; 0; 0; 0; |])"));
ASSERT_EQ (
a2.as_string ()
ASSERT_EQ (
a3.as_string ()
,
std::string (
"Diff (2, 9, Diff (2, 0, [| 0; 7; 8; 0; 0; 0; 0; |]))"));
}