243 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			243 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
//
 | 
						|
// immer: immutable data structures for C++
 | 
						|
// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
 | 
						|
//
 | 
						|
// This software is distributed under the Boost Software License, Version 1.0.
 | 
						|
// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
 | 
						|
//
 | 
						|
 | 
						|
#pragma once
 | 
						|
 | 
						|
#include <array>
 | 
						|
#include <cstddef>
 | 
						|
#include <utility>
 | 
						|
 | 
						|
#include <immer/detail/hamts/bits.hpp>
 | 
						|
#include <immer/detail/rbts/bits.hpp>
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
template <typename Iterator>
 | 
						|
struct rotator
 | 
						|
{
 | 
						|
    using value_type = typename std::iterator_traits<Iterator>::value_type;
 | 
						|
 | 
						|
    Iterator first;
 | 
						|
    Iterator last;
 | 
						|
    Iterator curr;
 | 
						|
 | 
						|
    void init(Iterator f, Iterator l)
 | 
						|
    {
 | 
						|
        first = f;
 | 
						|
        last  = l;
 | 
						|
        curr  = f;
 | 
						|
    }
 | 
						|
 | 
						|
    value_type next()
 | 
						|
    {
 | 
						|
        if (curr == last)
 | 
						|
            curr = first;
 | 
						|
        return *curr++;
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
template <typename Range>
 | 
						|
struct range_rotator : rotator<typename Range::iterator>
 | 
						|
{
 | 
						|
    using base_t = rotator<typename Range::iterator>;
 | 
						|
 | 
						|
    Range range;
 | 
						|
 | 
						|
    range_rotator(Range r)
 | 
						|
        : range{std::move(r)}
 | 
						|
    {
 | 
						|
        base_t::init(range.begin(), range.end());
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
template <typename Range>
 | 
						|
auto make_rotator(Range r) -> range_rotator<Range>
 | 
						|
{
 | 
						|
    return {r};
 | 
						|
}
 | 
						|
 | 
						|
inline auto magic_rotator()
 | 
						|
{
 | 
						|
    return make_rotator(std::array<unsigned, 15>{
 | 
						|
        {7, 11, 2, 3, 5, 7, 11, 13, 17, 19, 23, 5, 29, 31, 37}});
 | 
						|
}
 | 
						|
 | 
						|
struct dada_error
 | 
						|
{};
 | 
						|
 | 
						|
struct dadaism;
 | 
						|
static dadaism* g_dadaism = nullptr;
 | 
						|
 | 
						|
struct dadaism
 | 
						|
{
 | 
						|
    using rotator_t = decltype(magic_rotator());
 | 
						|
 | 
						|
    rotator_t magic = magic_rotator();
 | 
						|
 | 
						|
    unsigned step       = magic.next();
 | 
						|
    unsigned count      = 0;
 | 
						|
    unsigned happenings = 0;
 | 
						|
    unsigned last       = 0;
 | 
						|
    bool toggle         = false;
 | 
						|
 | 
						|
    struct scope
 | 
						|
    {
 | 
						|
        bool moved     = false;
 | 
						|
        dadaism* save_ = g_dadaism;
 | 
						|
        scope(scope&& s)
 | 
						|
        {
 | 
						|
            save_   = s.save_;
 | 
						|
            s.moved = true;
 | 
						|
        }
 | 
						|
        scope(dadaism* self) { g_dadaism = self; }
 | 
						|
        ~scope()
 | 
						|
        {
 | 
						|
            if (!moved)
 | 
						|
                g_dadaism = save_;
 | 
						|
        }
 | 
						|
    };
 | 
						|
 | 
						|
    static scope disable() { return {nullptr}; }
 | 
						|
 | 
						|
    scope next()
 | 
						|
    {
 | 
						|
        toggle = last == happenings;
 | 
						|
        last   = happenings;
 | 
						|
        step   = toggle ? step : magic.next();
 | 
						|
        return {this};
 | 
						|
    }
 | 
						|
 | 
						|
    void dada()
 | 
						|
    {
 | 
						|
        if (toggle && ++count % step == 0) {
 | 
						|
            ++happenings;
 | 
						|
            throw dada_error{};
 | 
						|
        }
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
inline void dada()
 | 
						|
{
 | 
						|
    if (g_dadaism)
 | 
						|
        g_dadaism->dada();
 | 
						|
}
 | 
						|
 | 
						|
inline bool soft_dada()
 | 
						|
{
 | 
						|
    try {
 | 
						|
        dada();
 | 
						|
        return false;
 | 
						|
    } catch (dada_error) {
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
template <typename Heap>
 | 
						|
struct dadaist_heap : Heap
 | 
						|
{
 | 
						|
    template <typename... Tags>
 | 
						|
    static auto allocate(std::size_t s, Tags... tags)
 | 
						|
    {
 | 
						|
        dada();
 | 
						|
        return Heap::allocate(s, tags...);
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
template <typename MP>
 | 
						|
struct dadaist_memory_policy : MP
 | 
						|
{
 | 
						|
    struct heap
 | 
						|
    {
 | 
						|
        using type = dadaist_heap<typename MP::heap::type>;
 | 
						|
 | 
						|
        template <std::size_t Size>
 | 
						|
        struct optimized
 | 
						|
        {
 | 
						|
            using base = typename MP::heap::template optimized<Size>::type;
 | 
						|
            using type = dadaist_heap<base>;
 | 
						|
        };
 | 
						|
    };
 | 
						|
};
 | 
						|
 | 
						|
struct tristan_tzara
 | 
						|
{
 | 
						|
    tristan_tzara() { dada(); }
 | 
						|
    tristan_tzara(const tristan_tzara&) { dada(); }
 | 
						|
    tristan_tzara(tristan_tzara&&) { dada(); }
 | 
						|
    tristan_tzara& operator=(const tristan_tzara&)
 | 
						|
    {
 | 
						|
        dada();
 | 
						|
        return *this;
 | 
						|
    }
 | 
						|
    tristan_tzara& operator=(tristan_tzara&&)
 | 
						|
    {
 | 
						|
        dada();
 | 
						|
        return *this;
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
template <typename T>
 | 
						|
struct dadaist : tristan_tzara
 | 
						|
{
 | 
						|
    T value;
 | 
						|
 | 
						|
    dadaist()
 | 
						|
        : value{}
 | 
						|
    {}
 | 
						|
    dadaist(T v)
 | 
						|
        : value{std::move(v)}
 | 
						|
    {}
 | 
						|
    operator T() const { return value; }
 | 
						|
};
 | 
						|
 | 
						|
template <typename T>
 | 
						|
struct dadaist_wrapper;
 | 
						|
 | 
						|
using rbits_t = immer::detail::rbts::bits_t;
 | 
						|
using hbits_t = immer::detail::rbts::bits_t;
 | 
						|
 | 
						|
template <template <class, class, rbits_t, rbits_t> class V,
 | 
						|
          typename T,
 | 
						|
          typename MP,
 | 
						|
          rbits_t B,
 | 
						|
          rbits_t BL>
 | 
						|
struct dadaist_wrapper<V<T, MP, B, BL>>
 | 
						|
{
 | 
						|
    using type = V<dadaist<T>, dadaist_memory_policy<MP>, B, BL>;
 | 
						|
};
 | 
						|
 | 
						|
template <template <class, class> class V, typename T, typename MP>
 | 
						|
struct dadaist_wrapper<V<T, MP>>
 | 
						|
{
 | 
						|
    using type = V<dadaist<T>, dadaist_memory_policy<MP>>;
 | 
						|
};
 | 
						|
 | 
						|
template <template <class, class, class, class, hbits_t> class V,
 | 
						|
          typename T,
 | 
						|
          typename E,
 | 
						|
          typename H,
 | 
						|
          typename MP,
 | 
						|
          hbits_t B>
 | 
						|
struct dadaist_wrapper<V<T, H, E, MP, B>>
 | 
						|
{
 | 
						|
    using type = V<dadaist<T>, H, E, dadaist_memory_policy<MP>, B>;
 | 
						|
};
 | 
						|
 | 
						|
template <template <class, class, class, class, class, hbits_t> class V,
 | 
						|
          typename K,
 | 
						|
          typename T,
 | 
						|
          typename E,
 | 
						|
          typename H,
 | 
						|
          typename MP,
 | 
						|
          hbits_t B>
 | 
						|
struct dadaist_wrapper<V<K, T, H, E, MP, B>>
 | 
						|
{
 | 
						|
    using type = V<K, dadaist<T>, H, E, dadaist_memory_policy<MP>, B>;
 | 
						|
};
 | 
						|
 | 
						|
} // anonymous namespace
 |