Program Listing for File py2cpp.hpp

Return to documentation for file (py2cpp/py2cpp.hpp)

#pragma once

#include <algorithm> // std::max
#include <initializer_list>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>

template <typename T> using Value_type = typename T::value_type;

namespace py {

template <typename T, typename TIter = decltype(std::begin(std::declval<T>())),
          typename = decltype(std::end(std::declval<T>()))>
constexpr auto enumerate(T &&iterable) {
    struct iterator {
        size_t i;
        TIter iter;
        auto operator!=(const iterator &other) const -> bool {
            return iter != other.iter;
        }
        void operator++() {
            ++i;
            ++iter;
        }
        auto operator*() const { return std::tie(i, *iter); }
        auto operator*() { return std::tie(i, *iter); }
    };
    struct iterable_wrapper {
        T iterable;
        auto begin() { return iterator{0, std::begin(iterable)}; }
        auto end() { return iterator{0, std::end(iterable)}; }
    };
    return iterable_wrapper{std::forward<T>(iterable)};
}

// template <typename T>
// constexpr auto range(T stop) {
//     struct iterator {
//         T i;
//         constexpr bool operator!=(const iterator &other) const { return i !=
//         other.i; } constexpr bool operator==(const iterator &other) const {
//         return i == other.i; } constexpr T operator*() const { return i; }
//         constexpr iterator &operator++() {
//             ++i;
//             return *this;
//         }
//     };

//     struct iterable_wrapper {
//         using value_type = T; // luk
//         T stop;
//         constexpr auto begin() const { return iterator{0}; }
//         constexpr auto end() const { return iterator{stop}; }
//         constexpr auto empty() const -> bool { return stop == 0; }
//         constexpr auto size() const -> size_t { return stop; }
//         constexpr auto operator[](size_t n) const -> T { return n; } // no
//         bounds checking constexpr auto contains(T n) const -> bool { return n
//         < stop; }
//     };

//     if (stop < 0) stop = 0;
//     return iterable_wrapper{stop};
// }

template <typename T> inline constexpr auto range(T start, T stop) {
    struct _iterator {
        T i;
        constexpr auto operator!=(const _iterator &other) const -> bool {
            return this->i != other.i;
        }
        constexpr auto operator==(const _iterator &other) const -> bool {
            return this->i == other.i;
        }
        constexpr auto operator*() const -> T { return this->i; }
        constexpr auto operator++() -> _iterator & {
            ++this->i;
            return *this;
        }
    };

    struct iterable_wrapper {
      public:
        using value_type [[maybe_unused]] = T; // luk:
        using key_type [[maybe_unused]] = T;   // luk:
        using iterator = _iterator;            // luk
        T start;
        T stop;
        [[nodiscard]] constexpr auto begin() const {
            return iterator{this->start};
        }
        [[nodiscard]] constexpr auto end() const {
            return iterator{this->stop};
        }
        [[nodiscard]] constexpr auto empty() const -> bool {
            return this->stop == this->start;
        }
        [[nodiscard]] constexpr auto size() const -> size_t {
            return this->stop - this->start;
        }
        constexpr auto operator[](size_t n) const -> T {
            return T(this->start + n);
        } // no bounds checking
        [[nodiscard]] constexpr auto contains(T n) const -> bool {
            return !(n < this->start) && n < this->stop;
        }
    };

    stop = std::max(stop, start);
    // if (stop < start) {
    //     stop = start;
    // }
    return iterable_wrapper{start, stop};
}

template <typename T> inline constexpr auto range(T stop) {
    return range(T(0), stop);
}

template <typename Key> class set : public std::unordered_set<Key> {
    using Self = set<Key>;

  public:
    set() : std::unordered_set<Key>{} {}

    template <typename FwdIter>
    set(const FwdIter &start, const FwdIter &stop)
        : std::unordered_set<Key>(start, stop) {}

    set(std::initializer_list<Key> init) : std::unordered_set<Key>{init} {}

    auto contains(const Key &key) const -> bool {
        return this->find(key) != this->end();
    }

    auto copy() const -> set { return *this; }

    auto operator=(const set &) -> set & = delete;

    auto operator=(set &&) noexcept -> set & = default;

    set(set<Key> &&) noexcept = default;

    // private:
    set(const set<Key> &) = default;
};

template <typename Key>
inline auto operator<(const Key &key, const set<Key> &m) -> bool {
    return m.contains(key);
}

template <typename Key> inline auto len(const set<Key> &m) -> size_t {
    return m.size();
}

// template <typename Key>
// set(std::initializer_list<Key>) -> set<Key>;

// template <typename Key>
// set(std::initializer_list<const char*> ) -> set<std::string>;

template <typename Iter> struct key_iterator : Iter {
    explicit key_iterator(Iter it) : Iter(it) {}
    auto operator*() const { return Iter::operator*().first; }
    auto operator++() -> key_iterator & {
        Iter::operator++();
        return *this;
    }
};

template <typename Key, typename T>
class dict : public std::unordered_map<Key, T> {
    using Self = dict<Key, T>;
    using Base = std::unordered_map<Key, T>;

  public:
    using value_type = std::pair<const Key, T>;

    dict() : std::unordered_map<Key, T>{} {}

    dict(std::initializer_list<value_type> init)
        : std::unordered_map<Key, T>{init} {}

    // template <class Sequence>
    // explicit dict(const Sequence &S) {
    //     this->reserve(S.size());
    //     for (auto&& [i_v, v] : py::enumerate(S)) {
    //         (*this)[v] = i_v;
    //     }
    // }

    auto contains(const Key &key) const -> bool {
        return this->find(key) != this->end();
    }

    auto get(const Key &key, const T &default_value) -> T {
        if (!contains(key)) {
            return default_value;
        }
        return (*this)[key];
    }

    auto begin() const {
        using Iter = decltype(std::unordered_map<Key, T>::begin());
        return key_iterator<Iter>{std::unordered_map<Key, T>::begin()};
    }

    auto end() const {
        using Iter = decltype(std::unordered_map<Key, T>::end());
        return key_iterator<Iter>{std::unordered_map<Key, T>::end()};
    }

    auto items() -> std::unordered_map<Key, T> & { return *this; }

    auto items() const -> const std::unordered_map<Key, T> & { return *this; }

    auto copy() const -> Self { return *this; }

    auto operator[](const Key &k) const -> const T & {
        return this->at(k); // luk: a bug in std::unordered_map?
    }

    auto operator[](const Key &k) -> T & { return Base::operator[](k); }

    auto operator=(const Self &) -> Self & = delete;

    auto operator=(Self &&) noexcept -> dict & = default;

    dict(dict<Key, T> &&) noexcept = default;

    ~dict() = default;

    // private:
    dict(const dict<Key, T> &) = default;
};

template <typename Key, typename T>
inline auto operator<(const Key &key, const dict<Key, T> &m) -> bool {
    return m.contains(key);
}

template <typename Key, typename T>
inline auto len(const dict<Key, T> &m) -> size_t {
    return m.size();
}

// template <typename Key, typename T>
// dict(std::initializer_list<std::pair<const Key, T>>) -> dict<Key, T>;

// template <class Sequence>
// dict(const Sequence& S)
//     -> dict<std::remove_cv_t<decltype(*std::begin(S))>, size_t>;

} // namespace py