Program Listing for File policy.hpp

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

// Copyright 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_POLICIES_POLICY_HPP
#define BELUGA_POLICIES_POLICY_HPP

#include <type_traits>

namespace beluga {

template <class PolicyFn>
struct policy;

namespace detail {


struct make_policy_fn {
  template <class Fn>
  constexpr policy<Fn> operator()(Fn&& fn) const {
    return policy<Fn>{std::forward<Fn>(fn)};
  }
};


}  // namespace detail

inline constexpr detail::make_policy_fn make_policy;

struct policy_base {
  template <class Left, class Right>
  friend constexpr auto operator&&(policy<Left> left, policy<Right> right) {
    return make_policy([=](const auto&... args) mutable -> bool { return left(args...) && right(args...); });
  }

  template <class Left, class Right>
  friend constexpr auto operator&(policy<Left> left, policy<Right> right) {
    return make_policy([=](const auto&... args) mutable -> bool {
      const bool first = left(args...);
      const bool second = right(args...);
      return first && second;
    });
  }

  template <class Left, class Right>
  friend constexpr auto operator||(policy<Left> left, policy<Right> right) {
    return make_policy([=](const auto&... args) mutable -> bool { return left(args...) || right(args...); });
  }

  template <class Left, class Right>
  friend constexpr auto operator|(policy<Left> left, policy<Right> right) {
    return make_policy([=](const auto&... args) mutable -> bool {
      const bool first = left(args...);
      const bool second = right(args...);
      return first || second;
    });
  }

  template <class Fn>
  friend constexpr auto operator!(policy<Fn> fn) {
    return make_policy([=](const auto&... args) mutable -> bool { return !fn(args...); });
  }
};


template <class PolicyFn>
struct policy : public policy_base, public PolicyFn {
  policy() = default;

  constexpr explicit policy(PolicyFn fn) : PolicyFn(std::move(fn)) {}

  using PolicyFn::PolicyFn;
  using PolicyFn::operator=;
  using PolicyFn::operator();


  template <class... Args>
  constexpr auto operator()(Args...) ->  //
      std::enable_if_t<                  //
          std::is_invocable_r_v<bool, PolicyFn> && !std::is_invocable_r_v<bool, PolicyFn, Args...>,
          bool> {
    return (*this)();
  }
};

template <class... Args>
using any_policy = policy<std::function<bool(Args...)>>;

}  // namespace beluga

#endif