<commit_before>// {{{ GPL License

// This file is part of gringo - a grounder for logic programs.
// Copyright <NAME>

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// }}}

#ifndef CLINGO_HH
#define CLINGO_HH

#include <clingo.h>
#include <string>
#include <cstring>
#include <functional>
#include <ostream>
#include <algorithm>
#include <vector>
#include <cassert>
#include <type_traits>
#include <memory>

#include <iostream>

namespace Clingo {

// {{{1 basic types

// consider using upper case
using literal_t = clingo_literal_t;
using id_t = clingo_id_t;
using weight_t = clingo_weight_t;
using atom_t = clingo_atom_t;

enum class TruthValue {
    Free = clingo_truth_value_free,
    True = clingo_truth_value_true,
    False = clingo_truth_value_false
};

inline std::ostream &operator<<(std::ostream &out, TruthValue tv) {
    switch (tv) {
        case TruthValue::Free:  { out << "Free"; break; }
        case TruthValue::True:  { out << "True"; break; }
        case TruthValue::False: { out << "False"; break; }
    }
    return out;
}

// {{{1 variant

namespace Detail {

template <class T, class... U>
struct TypeInList : std::false_type { };

template <class T, class... U>
struct TypeInList<T, T, U...> : std::true_type { };

template <class T, class V, class... U>
struct TypeInList<T, V, U...> : TypeInList<T, U...> { };

template <unsigned, class... U>
struct VariantHolder;

template <unsigned n>
struct VariantHolder<n> {
    bool check_type() const { return type_ == 0; }
    void emplace() { }
    void copy(VariantHolder const &) { }
    void destroy() {
        type_ = 0;
        data_ = nullptr;
    }
    void swap(VariantHolder &other) {
        std::swap(type_, other.type_);
        std::swap(data_, other.data_);
    }
    template <class V>
    typename std::enable_if<std::is_copy_constructible<V>::value>::type copy_if_possible(void *src) {
        data_ = new V(*static_cast<V const*>(src));
    }
    template <class V>
    typename std::enable_if<!std::is_copy_constructible<V>::value>::type copy_if_possible(void *) {
        throw std::runtime_error("variant not copyable");
    }
    unsigned type_ = 0;
    void *data_ = nullptr;
};

template <unsigned n, class T, class... U>
struct VariantHolder<n, T, U...> : VariantHolder<n+1, U...>{
    using Helper = VariantHolder<n+1, U...>;
    using Helper::check_type;
    using Helper::emplace;
    using Helper::data_;
    using Helper::type_;
    bool check_type(T *) const { return type_ == n; }
    template <class... Args>
    void emplace(T *, Args&& ...x) {
        data_ = new T(std::forward<Args>(x)...);
        type_ = n;
    }
    void copy(VariantHolder const &src) {
        if (src.type_ == n) {
            Helper::template copy_if_possible<T>(src.data_);
            type_ = src.type_;
        }
        Helper::copy(src);
    }
    void destroy() {
        if (n == type_) { delete static_cast<T*>(data_); }
        Helper::destroy();
    }
};

} // Detail

template <bool allow_empty, class... T>
class Variant {
public:
    using CompatibleVariant = Variant<!allow_empty, T...>;
    Variant() { static_assert(allow_empty, "empty variant not permitted"); }
    Variant(Variant const &other)           : Variant(other.data_) { }
    Variant(CompatibleVariant const &other) : Variant(other.data_) { }
    Variant(Variant &&other)           { data_.swap(other.data_); }
    Variant(CompatibleVariant &&other) { data_.swap(other.data_); }
    template <class U>
    Variant(U &&u, typename std::enable_if<Detail::TypeInList<U, T...>::value>::type * = nullptr) { emplace<U>(std::forward<U>(u)); }
    template <class U, class... Args>
    static Variant make(Args&& ...args) {
        Variant<true, T...> x;
        x.data_.emplace(static_cast<U*>(nullptr), std::forward<Args>(args)...);
        return x;
    }
    ~Variant() { data_.destroy(); }
    Variant &operator=(Variant const &other) { *this = other.data_; }
    Variant &operator=(CompatibleVariant const &other) { *this = other.data_; }
    Variant &operator=(Variant &&other) { return *this = std::move(other.data_); }
    Variant &operator=(CompatibleVariant &&other) { return *this = std::move(other.data_); }
    void clear() {
        static_assert(allow_empty, "clearing variant not permitted");
        data_.destroy();
    }
    template <class U>
    typename std::enable_if<Detail::TypeInList<U, T...>::value, Variant>::type &operator=(U &&u) {
        Variant x(std::forward<U>(u));
        data_.swap(x.data_);
        return *this;
    }
    template <class U>
    U &get() {
        if (!data_.check_type(static_cast<U*>(nullptr))) { throw std::bad_cast(); }
        return *static_cast<U*>(data_.data_);
    }
    template <class U, class... Args>
    void emplace(Args&& ...args) {
        Variant<true, T...> x;
        x.data_.emplace(static_cast<U*>(nullptr), std::forward<Args>(args)...);
        data_.swap(x.data_);
    }
    template <class U>
    bool is() const { return data_.check_type(static_cast<U*>(nullptr)); }
    bool empty() const { return data_.check_type(); }
    void swap(Variant &other)           { swap(other.data_); }
    void swap(CompatibleVariant &other) { swap(other.data_); }
private:
    using Holder = Detail::VariantHolder<1, T...>;
    Variant(Holder const &data) {
        if (!allow_empty && data.check_type()) { throw std::runtime_error("copying empty variant"); }
        data_.copy(data);
    }
    Variant &operator=(Holder const &data) {
        Variant x(data);
        data_.swap(x.data_);
        return *this;
    }
    Variant &operator=(Holder &&data) {
        data_.swap(data);
        data.destroy();
        return *this;
    }
    void swap_(Holder &data) {
        if (!allow_empty && data.check_type()) { throw std::runtime_error("swapping empty variant"); }
        data_.swap(data_);
    }

private:
    Holder data_;
};
<commit_msg>tests for variant<commit_after>// {{{ GPL License

// This file is part of gringo - a grounder for logic programs.
// Copyright <NAME>

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// }}}

#ifndef CLINGO_HH
#define CLINGO_HH

#include <clingo.h>
#include <string>
#include <cstring>
#include <functional>
#include <ostream>
#include <algorithm>
#include <vector>
#include <cassert>
#include <type_traits>
#include <memory>

#include <iostream>

namespace Clingo {

// {{{1 basic types

// consider using upper case
using literal_t = clingo_literal_t;
using id_t = clingo_id_t;
using weight_t = clingo_weight_t;
using atom_t = clingo_atom_t;

enum class TruthValue {
    Free = clingo_truth_value_free,
    True = clingo_truth_value_true,
    False = clingo_truth_value_false
};

inline std::ostream &operator<<(std::ostream &out, TruthValue tv) {
    switch (tv) {
        case TruthValue::Free:  { out << "Free"; break; }
        case TruthValue::True:  { out << "True"; break; }
        case TruthValue::False: { out << "False"; break; }
    }
    return out;
}

// {{{1 variant

namespace Detail {

template <class T, class... U>
struct TypeInList : std::false_type { };

template <class T, class... U>
struct TypeInList<T, T, U...> : std::true_type { };

template <class T, class V, class... U>
struct TypeInList<T, V, U...> : TypeInList<T, U...> { };

template <unsigned, class... U>
struct VariantHolder;

template <unsigned n>
struct VariantHolder<n> {
    bool check_type() const { return type_ == 0; }
    void emplace() { }
    void copy(VariantHolder const &) { }
    void destroy() {
        type_ = 0;
        data_ = nullptr;
    }
    void swap(VariantHolder &other) {
        std::swap(type_, other.type_);
        std::swap(data_, other.data_);
    }
    template <class V>
    typename std::enable_if<std::is_copy_constructible<V>::value>::type copy_if_possible(void *src) {
        data_ = new V(*static_cast<V const*>(src));
    }
    template <class V>
    typename std::enable_if<!std::is_copy_constructible<V>::value>::type copy_if_possible(void *) {
        throw std::runtime_error("variant not copyable");
    }
    template <bool allow_empty, class V>
    void accept(V &&visitor, typename std::enable_if<allow_empty>::type * = nullptr) const {
        if (type_ == 0) { visitor.visit(); }
    }
    template <bool allow_empty, class V>
    void accept(V &&, typename std::enable_if<!allow_empty>::type * = nullptr) const {
    }
    unsigned type_ = 0;
    void *data_ = nullptr;
};

template <unsigned n, class T, class... U>
struct VariantHolder<n, T, U...> : VariantHolder<n+1, U...>{
    using Helper = VariantHolder<n+1, U...>;
    using Helper::check_type;
    using Helper::emplace;
    using Helper::data_;
    using Helper::type_;
    bool check_type(T *) const { return type_ == n; }
    template <class... Args>
    void emplace(T *, Args&& ...x) {
        data_ = new T(std::forward<Args>(x)...);
        type_ = n;
    }
    void copy(VariantHolder const &src) {
        if (src.type_ == n) {
            Helper::template copy_if_possible<T>(src.data_);
            type_ = src.type_;
        }
        Helper::copy(src);
    }
    template <bool allow_empty, class V>
    void accept(V &&visitor) {
        if (n == type_) { visitor.visit(*static_cast<T*>(data_)); }
        Helper::template accept<allow_empty, V>(std::forward<V>(visitor));
    }
    template <bool allow_empty, class V>
    void accept(V &&visitor) const {
        if (n == type_) { visitor.visit(*static_cast<T const*>(data_)); }
        Helper::template accept<allow_empty, V>(std::forward<V>(visitor));
    }
    void destroy() {
        if (n == type_) { delete static_cast<T*>(data_); }
        Helper::destroy();
    }
};

} // Detail

template <bool allow_empty, class... T>
class Variant {
public:
    using CompatibleVariant = Variant<!allow_empty, T...>;
    friend CompatibleVariant;
    Variant() { static_assert(allow_empty, "empty variant not permitted"); }
    Variant(Variant const &other)           : Variant(other.data_) { }
    Variant(CompatibleVariant const &other) : Variant(other.data_) { }
    Variant(Variant &&other)           { data_.swap(other.data_); }
    Variant(CompatibleVariant &&other) { data_.swap(other.data_); }
    template <class U>
    Variant(U &&u, typename std::enable_if<Detail::TypeInList<U, T...>::value>::type * = nullptr) { emplace<U>(std::forward<U>(u)); }
    template <class U>
    Variant(U &u, typename std::enable_if<Detail::TypeInList<U, T...>::value>::type * = nullptr) { emplace<U>(u); }
    template <class U>
    Variant(U const &u, typename std::enable_if<Detail::TypeInList<U, T...>::value>::type * = nullptr) { emplace<U>(u); }
    template <class U, class... Args>
    static Variant make(Args&& ...args) {
        Variant<true, T...> x;
        x.data_.emplace(static_cast<U*>(nullptr), std::forward<Args>(args)...);
        return std::move(x);
    }
    ~Variant() { data_.destroy(); }
    Variant &operator=(Variant const &other) { return *this = other.data_; }
    Variant &operator=(CompatibleVariant const &other) { return *this = other.data_; }
    Variant &operator=(Variant &&other) { return *this = std::move(other.data_); }
    Variant &operator=(CompatibleVariant &&other) { return *this = std::move(other.data_); }
    void clear() {
        static_assert(allow_empty, "clearing variant not permitted");
        data_.destroy();
    }
    template <class U>
    typename std::enable_if<Detail::TypeInList<U, T...>::value, Variant>::type &operator=(U &&u) {
        emplace<U>(std::forward<U>(u));
        return *this;
    }
    template <class U>
    typename std::enable_if<Detail::TypeInList<U, T...>::value, Variant>::type &operator=(U &u) {
        emplace<U>(u);
        return *this;
    }
    template <class U>
    typename std::enable_if<Detail::TypeInList<U, T...>::value, Variant>::type &operator=(U const &u) {
        emplace<U>(u);
        return *this;
    }
    template <class U>
    U &get() {
        if (!data_.check_type(static_cast<U*>(nullptr))) { throw std::bad_cast(); }
        return *static_cast<U*>(data_.data_);
    }
    template <class U>
    U const &get() const {
        if (!data_.check_type(static_cast<U*>(nullptr))) { throw std::bad_cast(); }
        return *static_cast<U*>(data_.data_);
    }
    template <class U, class... Args>
    void emplace(Args&& ...args) {
        Variant<true, T...> x;
        x.data_.emplace(static_cast<U*>(nullptr), std::forward<Args>(args)...);
        data_.swap(x.data_);
    }
    template <class U>
    bool is() const { return data_.check_type(static_cast<U*>(nullptr)); }
    bool empty() const { return data_.check_type(); }
    void swap(Variant &other)           { swap_(other.data_); }
    void swap(CompatibleVariant &other) {
        if (!allow_empty) { swap_(other.data_); }
        else              { other.swap_(data_); }
    }
    template <class V>
    void accept(V &&visitor) {
        data_.template accept<allow_empty, V>(std::forward<V>(visitor));
    }
private:
    using Holder = Detail::VariantHolder<1, T...>;
    Variant(Holder const &data) {
        if (!allow_empty && data.check_type()) { throw std::logic_error("copying empty variant"); }
        data_.copy(data);
    }
    Variant &operator=(Holder const &data) {
        if (!allow_empty && data.check_type()) { throw std::logic_error("assigning empty variant"); }
        Variant x(data);
        data_.swap(x.data_);
        return *this;
    }
    Variant &operator=(Holder &&data) {
        if (!allow_empty && data.check_type()) { throw std::logic_error("assigning empty variant"); }
        data_.swap(data);
        data.destroy();
        return *this;
    }
    void swap_(Holder &data) {
        if (!allow_empty && data.check_type()) { throw std::logic_error("swapping empty variant"); }
        data_.swap(data_);
    }

private:
    Holder data_;
};

{'fraction_non_alphanumeric': 0.15479131886477462, 'fraction_numerical': 0.0012687813021702839, 'mean_word_length': 3.0940404592673594, 'pattern_counts': {'":': 0, '<': 178, '<?xml version=': 0, '>': 162, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1832692', 'n_tokens_mistral': 4786, 'n_tokens_neox': 4698, 'n_words': 1259}