// // 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 #include #include #include #include namespace { template struct rotator { using value_type = typename std::iterator_traits::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 struct range_rotator : rotator { using base_t = rotator; Range range; range_rotator(Range r) : range{std::move(r)} { base_t::init(range.begin(), range.end()); } }; template auto make_rotator(Range r) -> range_rotator { return { r }; } inline auto magic_rotator() { return make_rotator(std::array{{ 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 struct dadaist_heap : Heap { template static auto allocate(std::size_t s, Tags... tags) { dada(); return Heap::allocate(s, tags...); } }; template struct dadaist_memory_policy : MP { struct heap { using type = dadaist_heap; template struct optimized { using base = typename MP::heap::template optimized::type; using type = dadaist_heap; }; }; }; 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 struct dadaist : tristan_tzara { T value; dadaist() : value{} {} dadaist(T v) : value{std::move(v)} {} operator T() const { return value; } }; template struct dadaist_wrapper; using rbits_t = immer::detail::rbts::bits_t; using hbits_t = immer::detail::rbts::bits_t; template