#pragma once

#include <algorithm>
#include <cstddef>
#include <cstdio>
#include <cstdlib>

namespace std {
    // TODO: where does this go?
    inline void __msl_error(const char* param_0) {
        fprintf(stderr, param_0);
        abort();
    }

    template < size_t N >
    class __bitset_base {
    public:
        __bitset_base();

        const __bitset_base& set(size_t pos, bool val);
        const __bitset_base& reset(size_t pos);
        bool test(size_t pos) const;
        bool any() const;

    private:
        size_t data[N];
    };

    template <>
    class __bitset_base< 1 > {
    public:
        __bitset_base() {
            data = 0;
        }

        bool test(size_t pos) const {
            size_t r31 = 1UL << pos;
            return data & r31;
        }
        bool any() const {
            return data != 0;
        }
        const __bitset_base& set(size_t pos, bool val) {
            size_t r31 = 1UL << pos;
            if (val) {
                data |= r31;
            } else {
                data &= ~r31;
            }
            return *this;
        }
        const __bitset_base& reset(size_t pos) {
            data &= ~(1UL << pos);
            return *this;
        }

    private:
        size_t data;
    };

    template < size_t N >
    __bitset_base< N >::__bitset_base() {
        std::fill_n(data, N, 0);
    }

    template < size_t N >
    bool __bitset_base< N >::test(size_t pos) const {
        size_t i = pos / (sizeof(size_t) * 8);
        size_t mask = 1 << (pos % (sizeof(size_t) * 8));
        return data[i] & mask;
    }

    template < size_t N >
    const __bitset_base< N >& __bitset_base< N >::set(size_t pos, bool val) {
        size_t i = pos / (sizeof(size_t) * 8);
        size_t mask = 1 << (pos % (sizeof(size_t) * 8));
        if (val) {
            data[i] |= mask;
        } else {
            data[i] &= ~mask;
        }
        return *this;
    }

    template < size_t N >
    const __bitset_base< N >& __bitset_base< N >::reset(size_t pos) {
        size_t i = pos / (sizeof(size_t) * 8);
        size_t mask = 1 << (pos % (sizeof(size_t) * 8));
        data[i] &= ~mask;
        return *this;
    }

    template < size_t N >
    bool __bitset_base< N >::any() const {
        for (int i = 0; i < N; i++) {
            if (data[i] != 0) {
                return true;
            }
        }
        return false;
    }

    template < size_t N >
    class bitset : private __bitset_base< (N - 1) / (sizeof(size_t) * 8) + 1 > {
    public:
        typedef __bitset_base< (N - 1) / (sizeof(size_t) * 8) + 1 > base;

        bitset(){};

        const base& set(size_t pos, bool val) {
            if (pos >= N) {
                __msl_error("index out of range of bitset::set");
            }
            return base::set(pos, val);
        }
        const base& reset(size_t pos) {
            if (pos >= N) {
                __msl_error("index out of range of bitset::reset");
            }
            return base::reset(pos);
        }
        bool test(size_t pos) const {
            if (pos >= N) {
                __msl_error("index out of range of bitset::test");
            }
            return base::test(pos);
        }
        bool any() const {
            return base::any();
        }
    };
}  // namespace std
