Program Listing for File primitives.hpp

Return to documentation for file (include/beluga/primitives.hpp)

// Copyright 2023-2024 Ekumen, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef BELUGA_PRIMITIVES_HPP
#define BELUGA_PRIMITIVES_HPP

#include <tuple>
#include <type_traits>

#include <beluga/type_traits/strongly_typed_numeric.hpp>
#include <beluga/type_traits/tuple_traits.hpp>
#include <beluga/utility/forward_like.hpp>

namespace beluga {

using Weight = Numeric<double, struct WeightTag>;

using Cluster = Numeric<std::size_t, struct ClusterTag>;

namespace state_detail {


template <class T, class = void>
struct has_member_variable_state : std::false_type {};

template <class T>
struct has_member_variable_state<T, std::void_t<decltype(std::declval<T>().state)>> : std::true_type {};

template <class T>
inline constexpr bool has_member_variable_state_v = has_member_variable_state<T>::value;

template <class T, class = void>
struct has_member_state : std::false_type {};

template <class T>
struct has_member_state<T, std::void_t<decltype(std::declval<T>().state())>> : std::true_type {};

template <class T>
inline constexpr bool has_member_state_v = has_member_state<T>::value;

template <class T, class = void>
struct has_non_member_state : std::false_type {};

template <class T>
struct has_non_member_state<T, std::void_t<decltype(state(std::declval<T>()))>> : std::true_type {};

template <class T>
inline constexpr bool has_non_member_state_v = has_non_member_state<T>::value;



struct state_fn {
  template <
      class T,
      std::enable_if_t<
          std::conjunction_v<
              has_member_variable_state<T>,        //
              std::negation<has_member_state<T>>,  //
              std::negation<has_non_member_state<T>>>,
          int> = 0>
  constexpr decltype(auto) operator()(T&& t) const noexcept {
    return beluga::forward_like<T>(t.state);
  }

  template <
      class T,
      std::enable_if_t<
          std::conjunction_v<
              std::negation<has_member_variable_state<T>>,  //
              has_member_state<T>,                          //
              std::negation<has_non_member_state<T>>>,
          int> = 0>
  constexpr decltype(auto) operator()(T&& t) const noexcept(noexcept(std::forward<T>(t).state())) {
    return std::forward<T>(t).state();
  }


  template <
      class T,
      std::enable_if_t<
          std::conjunction_v<
              std::negation<has_member_variable_state<T>>,  //
              std::negation<has_member_state<T>>,           //
              has_non_member_state<T>>,
          int> = 0>
  constexpr decltype(auto) operator()(T&& t) const noexcept(noexcept(state(std::forward<T>(t)))) {
    return state(std::forward<T>(t));
  }


  template <
      class T,
      std::enable_if_t<
          std::conjunction_v<
              std::negation<has_member_variable_state<T>>,  //
              std::negation<has_member_state<T>>,           //
              std::negation<has_non_member_state<T>>,       //
              is_tuple_like<T>>,
          int> = 0,
      std::enable_if_t<(std::tuple_size_v<std::decay_t<T>> > 1), int> = 0>
  constexpr decltype(auto) operator()(T&& t) const noexcept(noexcept(std::get<0>(std::forward<T>(t)))) {
    return std::get<0>(std::forward<T>(t));
  }
};

}  // namespace state_detail

inline constexpr state_detail::state_fn state;

namespace weight_detail {


template <class T, class = void>
struct has_member_variable_weight : std::false_type {};

template <class T>
struct has_member_variable_weight<T, std::void_t<decltype(std::declval<T>().weight)>> : std::true_type {};

template <class T>
inline constexpr bool has_member_variable_weight_v = has_member_variable_weight<T>::value;

template <class T, class = void>
struct has_member_weight : std::false_type {};

template <class T>
struct has_member_weight<T, std::void_t<decltype(std::declval<T>().weight())>> : std::true_type {};

template <class T>
inline constexpr bool has_member_weight_v = has_member_weight<T>::value;

template <class T, class = void>
struct has_non_member_weight : std::false_type {};

template <class T>
struct has_non_member_weight<T, std::void_t<decltype(weight(std::declval<T>()))>> : std::true_type {};

template <class T>
inline constexpr bool has_non_member_weight_v = has_non_member_weight<T>::value;



struct weight_fn {
  template <
      class T,
      std::enable_if_t<
          std::conjunction_v<
              has_member_variable_weight<T>,        //
              std::negation<has_member_weight<T>>,  //
              std::negation<has_non_member_weight<T>>>,
          int> = 0>
  constexpr decltype(auto) operator()(T&& t) const noexcept {
    return beluga::forward_like<T>(t.weight);
  }

  template <
      class T,
      std::enable_if_t<
          std::conjunction_v<
              std::negation<has_member_variable_weight<T>>,  //
              has_member_weight<T>,                          //
              std::negation<has_non_member_weight<T>>>,
          int> = 0>
  constexpr decltype(auto) operator()(T&& t) const noexcept(noexcept(std::forward<T>(t).weight())) {
    return std::forward<T>(t).weight();
  }


  template <
      class T,
      std::enable_if_t<
          std::conjunction_v<
              std::negation<has_member_variable_weight<T>>,  //
              std::negation<has_member_weight<T>>,           //
              has_non_member_weight<T>>,
          int> = 0>
  constexpr decltype(auto) operator()(T&& t) const noexcept(noexcept(weight(std::forward<T>(t)))) {
    return weight(std::forward<T>(t));
  }

  template <
      class T,
      std::enable_if_t<
          std::conjunction_v<
              std::negation<has_member_variable_weight<T>>,  //
              std::negation<has_member_weight<T>>,           //
              std::negation<has_non_member_weight<T>>,       //
              is_tuple_like<T>,                              //
              has_single_element<beluga::Weight, std::decay_t<T>>>,
          int> = 0>
  constexpr decltype(auto) operator()(T&& t) const noexcept(noexcept(element<beluga::Weight>(std::forward<T>(t)))) {
    return element<beluga::Weight>(std::forward<T>(t));
  }
};

}  // namespace weight_detail

inline constexpr weight_detail::weight_fn weight;

}  // namespace beluga

#endif