<commit_before>#pragma once

#if defined(USE_ARCHIE_TUPLE)
#include <utility>
#include <array>
#include <archie/utils/meta/eval.h>
#include <archie/utils/meta/index_of.h>
#include <archie/utils/meta/requires.h>
#include <archie/utils/meta/at.h>
#include <archie/utils/meta/indexable.h>
#include <archie/utils/meta/logic.h>
#include <archie/utils/meta/variable_template.h>
#include <archie/utils/traits.h>
#include <archie/utils/fused/nth.h>
#include <archie/utils/fused/mover.h>
#include <archie/utils/traits/model_of.h>
#include <archie/utils/fused/ignore.h>
#include <archie/utils/models.h>

namespace archie {
namespace utils {
  namespace fused {
    template <typename... Ts>
    struct tuple {
    private:
      template <typename... Us>
      static decltype(auto) make_storage(Us... args) {
        return [args...](auto&& func) mutable -> decltype(auto) {
          return std::forward<decltype(func)>(func)(args...);
        };
      }
      using storage_type = decltype(make_storage(std::declval<move_t<Ts>>()...));

      storage_type storage;

      struct explicit_ctor_tag {};
      struct implicit_ctor_tag {};
      struct move_t_ctor_tag {};

      template <typename... Us>
      constexpr explicit tuple(implicit_ctor_tag, Us&&... args)
          : tuple(move_t_ctor_tag{}, move_t<Ts>(std::forward<Us>(args))...) {}

      constexpr explicit tuple(move_t_ctor_tag, move_t<Ts>... mvs)
          : storage(make_storage(mvs...)) {}

      template <typename... Us>
      constexpr explicit tuple(explicit_ctor_tag, Us&&... args)
          : tuple(Ts { std::forward<Us>(args) }...) {}

    public:
      template <typename... Us>
      constexpr explicit tuple(Us&&... args)
          : tuple(meta::if_t<meta::all<traits::is_convertible<Us, Ts>...>,
                             implicit_ctor_tag,
                             explicit_ctor_tag>{},
                  std::forward<Us>(args)...) {}

      constexpr tuple() : tuple(Ts {}...) {}
      tuple(tuple& other) : tuple(const_cast<tuple const&>(other)) {}

      tuple(tuple&&) = default;
      tuple(tuple const&) = default;
      tuple& operator=(tuple const&);
      tuple& operator=(tuple&&);

      template <typename... Us>
      tuple& operator=(tuple<Us...> const&);

      template <typename... Us>
      bool operator==(tuple<Us...> const&) const;
      bool operator<(tuple const&) const;

      bool operator!=(tuple const& rhs) const { return !(*this == rhs); }
      bool operator>(tuple const& rhs) const { return rhs < *this; }
      bool operator>=(tuple const& rhs) const { return !(*this < rhs); }
      bool operator<=(tuple const& rhs) const { return !(*this > rhs); }

      constexpr std::size_t size() noexcept { return sizeof...(Ts); }

      template <typename F>
      decltype(auto) apply(F&& f,
                           meta::requires<traits::model_of<models::Callable(F, Ts const&...)>> =
                               fused::ignore) const & {
        auto exec = [&f](move_t<Ts>&... xs) -> decltype(auto) {
          return std::forward<decltype(f)>(f)(static_cast<Ts const&>(xs)...);
        };
        // TODO explain why const_cast is used here
        return const_cast<storage_type&>(storage)(exec);
      }

      template <typename F>
          decltype(auto) apply(F&& f) &
          ;
      template <typename F>
          decltype(auto) apply(F&& f) &&
          ;
    };

    template <typename... Ts>
    template <typename F>
    decltype(auto) tuple<Ts...>::apply(F&& f) & {
      auto exec = [&f](move_t<Ts>&... xs) -> decltype(auto) {
        return std::forward<decltype(f)>(f)(static_cast<std::add_lvalue_reference_t<Ts>>(xs)...);
      };
      return storage(exec);
    }

    template <typename... Ts>
    template <typename F>
    decltype(auto) tuple<Ts...>::apply(F&& f) && {
      auto exec = [&f](move_t<Ts>&... xs) -> decltype(auto) {
        return std::forward<decltype(f)>(f)(static_cast<Ts&&>(xs)...);
      };
      return storage(exec);
    }

    namespace detail {
      struct make_tuple_ {
        template <typename... Ts>
        constexpr decltype(auto) operator()(Ts&&... args) const {
          return fused::tuple<std::remove_reference_t<Ts>...>(std::forward<Ts>(args)...);
        }
      };

      struct tie_ {
        template <typename... Ts>
        constexpr decltype(auto) operator()(Ts&... args) const {
          return fused::tuple<Ts&...>(args...);
        }
      };
    }

    template <std::size_t N, typename Tp>
    decltype(auto) get(Tp&& tp) {
#if defined(HAS_VARIABLE_TEMPLATES)
      constexpr auto& nth_n = nth<N>;
#else
      constexpr auto& nth_n = nth_v<N>::value;
#endif
      return tp.apply(nth_n);
    }

    template <typename Tp, typename... Us>
    decltype(auto) get(tuple<Us...>& u) {
      constexpr auto idx = meta::index_of<Tp>(meta::type_list<Us...>{});
      return get<idx>(u);<commit_msg>add more constraints to fused::tuple::apply<commit_after>#pragma once

#if defined(USE_ARCHIE_TUPLE)
#include <utility>
#include <array>
#include <archie/utils/meta/eval.h>
#include <archie/utils/meta/index_of.h>
#include <archie/utils/meta/requires.h>
#include <archie/utils/meta/at.h>
#include <archie/utils/meta/indexable.h>
#include <archie/utils/meta/logic.h>
#include <archie/utils/meta/variable_template.h>
#include <archie/utils/traits.h>
#include <archie/utils/fused/nth.h>
#include <archie/utils/fused/mover.h>
#include <archie/utils/traits/model_of.h>
#include <archie/utils/fused/ignore.h>
#include <archie/utils/models.h>

namespace archie {
namespace utils {
  namespace fused {
    template <typename... Ts>
    struct tuple {
    private:
      template <typename... Us>
      static decltype(auto) make_storage(Us... args) {
        return [args...](auto&& func) mutable -> decltype(auto) {
          return std::forward<decltype(func)>(func)(args...);
        };
      }
      using storage_type = decltype(make_storage(std::declval<move_t<Ts>>()...));

      storage_type storage;

      struct explicit_ctor_tag {};
      struct implicit_ctor_tag {};
      struct move_t_ctor_tag {};

      template <typename... Us>
      constexpr explicit tuple(implicit_ctor_tag, Us&&... args)
          : tuple(move_t_ctor_tag{}, move_t<Ts>(std::forward<Us>(args))...) {}

      constexpr explicit tuple(move_t_ctor_tag, move_t<Ts>... mvs)
          : storage(make_storage(mvs...)) {}

      template <typename... Us>
      constexpr explicit tuple(explicit_ctor_tag, Us&&... args)
          : tuple(Ts { std::forward<Us>(args) }...) {}

      template <typename F, typename... Us>
      using is_callable = meta::requires<traits::model_of<models::Callable(F, Us...)>>;

    public:
      template <typename... Us>
      constexpr explicit tuple(Us&&... args)
          : tuple(meta::if_t<meta::all<traits::is_convertible<Us, Ts>...>,
                             implicit_ctor_tag,
                             explicit_ctor_tag>{},
                  std::forward<Us>(args)...) {}

      constexpr tuple() : tuple(Ts {}...) {}
      tuple(tuple& other) : tuple(const_cast<tuple const&>(other)) {}

      tuple(tuple&&) = default;
      tuple(tuple const&) = default;
      tuple& operator=(tuple const&);
      tuple& operator=(tuple&&);

      template <typename... Us>
      tuple& operator=(tuple<Us...> const&);

      template <typename... Us>
      bool operator==(tuple<Us...> const&) const;
      bool operator<(tuple const&) const;

      bool operator!=(tuple const& rhs) const { return !(*this == rhs); }
      bool operator>(tuple const& rhs) const { return rhs < *this; }
      bool operator>=(tuple const& rhs) const { return !(*this < rhs); }
      bool operator<=(tuple const& rhs) const { return !(*this > rhs); }

      constexpr std::size_t size() noexcept { return sizeof...(Ts); }

      template <typename F>
      decltype(auto) apply(F&& f, is_callable<F, Ts const&...> = fused::ignore) const & {
        auto exec = [&f](move_t<Ts>&... xs) -> decltype(auto) {
          return std::forward<decltype(f)>(f)(static_cast<Ts const&>(xs)...);
        };
        // TODO explain why const_cast is used here
        return const_cast<storage_type&>(storage)(exec);
      }

      template <typename F>
      decltype(auto) apply(F&& f, is_callable<F, Ts&...> = fused::ignore) & {
        auto exec = [&f](move_t<Ts>&... xs) -> decltype(auto) {
          return std::forward<decltype(f)>(f)(static_cast<std::add_lvalue_reference_t<Ts>>(xs)...);
        };
        return storage(exec);
      }

      template <typename F>
      decltype(auto) apply(F&& f, is_callable<F, Ts&&...> = fused::ignore) && {
        auto exec = [&f](move_t<Ts>&... xs) -> decltype(auto) {
          return std::forward<decltype(f)>(f)(static_cast<Ts&&>(xs)...);
        };
        return storage(exec);
      }
    };

    namespace detail {
      struct make_tuple_ {
        template <typename... Ts>
        constexpr decltype(auto) operator()(Ts&&... args) const {
          return fused::tuple<std::remove_reference_t<Ts>...>(std::forward<Ts>(args)...);
        }
      };

      struct tie_ {
        template <typename... Ts>
        constexpr decltype(auto) operator()(Ts&... args) const {
          return fused::tuple<Ts&...>(args...);
        }
      };
    }

    template <std::size_t N, typename Tp>
    decltype(auto) get(Tp&& tp) {
#if defined(HAS_VARIABLE_TEMPLATES)
      constexpr auto& nth_n = nth<N>;
#else
      constexpr auto& nth_n = nth_v<N>::value;
#endif
      return tp.apply(nth_n);
    }

    template <typename Tp, typename... Us>
    decltype(auto) get(tuple<Us...>& u) {
      constexpr auto idx = meta::index_of<Tp>(meta::type_list<Us...>{});
      return get<idx>(u);
{'fraction_non_alphanumeric': 0.1746670795912047, 'fraction_numerical': 0.0, 'mean_word_length': 2.616274729376633, 'pattern_counts': {'":': 0, '<': 153, '<?xml version=': 0, '>': 159, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '2222072', 'n_tokens_mistral': 3237, 'n_tokens_neox': 3119, 'n_words': 640}