blob: 7289b6457cd5e96a94e50d2190bc7dce077c7180 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#pragma once
#include <functional>
#include <optional>
#include <type_traits>
#include <utility>
#include <iostream>
#include "nonstd/expected.hpp"
#include "utils/GeneralUtils.h"
#include "minifi-cpp/utils/gsl.h"
#include "utils/detail/MonadicOperationWrappers.h"
#include "fmt/format.h"
namespace org::apache::nifi::minifi::utils {
template<typename T>
std::optional<gsl::not_null<utils::remove_cvref_t<T>>> optional_from_ptr(T&& obj) {
return obj == nullptr ? std::nullopt : std::optional<gsl::not_null<utils::remove_cvref_t<T>>>{ gsl::make_not_null(std::forward<T>(obj)) };
}
template<typename, typename = void>
struct is_optional : std::false_type {};
template<typename T>
struct is_optional<std::optional<T>, void> : std::true_type {};
namespace detail {
// transform implementation
template<typename SourceType, typename F>
auto operator|(std::optional<SourceType> o, transform_wrapper<F> f) noexcept(noexcept(std::invoke(std::forward<F>(f.function), *std::move(o)))) {
using cb_result = std::decay_t<std::invoke_result_t<F, SourceType>>;
if constexpr(std::is_same_v<cb_result, void>) {
if (o.has_value()) {
std::invoke(std::forward<F>(f.function), *std::move(o));
}
} else {
using return_type = std::optional<cb_result>;
if (o.has_value()) {
return return_type{std::make_optional(std::invoke(std::forward<F>(f.function), *std::move(o)))};
} else {
return return_type{std::nullopt};
}
}
}
// andThen implementation
template<typename SourceType, typename F>
auto operator|(const std::optional<SourceType>& o, and_then_wrapper<F> f) noexcept(noexcept(std::invoke(std::forward<F>(f.function), *o)))
-> std::optional<typename std::decay<decltype(*std::invoke(std::forward<F>(f.function), *o))>::type> {
static_assert(is_optional<decltype(std::invoke(std::forward<F>(f.function), *o))>::value, "flatMap expects a function returning optional");
if (o.has_value()) {
return std::invoke(std::forward<F>(f.function), *o);
} else {
return std::nullopt;
}
}
template<typename SourceType, typename F>
auto operator|(std::optional<SourceType>&& o, and_then_wrapper<F> f) noexcept(noexcept(std::invoke(std::forward<F>(f.function), std::move(*o))))
-> std::optional<typename std::decay<decltype(*std::invoke(std::forward<F>(f.function), std::move(*o)))>::type> {
static_assert(is_optional<decltype(std::invoke(std::forward<F>(f.function), std::move(*o)))>::value, "flatMap expects a function returning optional");
if (o.has_value()) {
return std::invoke(std::forward<F>(f.function), std::move(*o));
} else {
return std::nullopt;
}
}
// orElse implementation
template<typename SourceType, typename F>
auto operator|(std::optional<SourceType> o, or_else_wrapper<F> f) noexcept(noexcept(std::invoke(std::forward<F>(f.function))))
-> typename std::enable_if<std::is_same<decltype(std::invoke(std::forward<F>(f.function))), void>::value, std::optional<SourceType>>::type {
if (o.has_value()) {
return o;
} else {
std::invoke(std::forward<F>(f.function));
return std::nullopt;
}
}
template<typename SourceType, typename F>
auto operator|(std::optional<SourceType> o, or_else_wrapper<F> f) noexcept(noexcept(std::invoke(std::forward<F>(f.function))))
-> typename std::enable_if<std::is_same<typename std::decay<decltype(std::invoke(std::forward<F>(f.function)))>::type, std::optional<SourceType>>::value, std::optional<SourceType>>::type {
if (o.has_value()) {
return o;
} else {
return std::invoke(std::forward<F>(f.function));
}
}
// valueOrElse implementation
template<typename SourceType, typename F>
auto operator|(std::optional<SourceType> o, value_or_else_wrapper<F> f) noexcept(noexcept(std::invoke(std::forward<F>(f.function))))
-> std::common_type_t<SourceType, std::decay_t<decltype(std::invoke(std::forward<F>(f.function)))>> {
if (o) {
return *std::move(o);
} else {
return std::invoke(std::forward<F>(f.function));
}
}
// filter implementation
template<typename SourceType, typename F>
requires std::is_convertible_v<std::invoke_result_t<F, SourceType>, bool>
auto operator|(std::optional<SourceType> o, filter_wrapper<F> f) noexcept(noexcept(std::invoke(std::forward<F>(f.function), *o)))
-> std::optional<SourceType> {
if (o && std::invoke(std::forward<F>(f.function), *o)) {
return o;
} else {
return std::nullopt;
}
}
template<typename T, typename E>
nonstd::expected<T, E> operator|(std::optional<T> object, to_expected_wrapper<E> e) {
if (!object) {
return nonstd::make_unexpected(e.error);
}
return std::move(*object);
}
template<typename T>
T operator|(std::optional<T> object, const or_throw_wrapper e) {
if (object) {
return std::move(*object);
}
throw std::runtime_error(fmt::format("{}", e.reason));
}
template<typename T>
T&& operator|(std::optional<T> object, const or_terminate_wrapper e) {
if (object) {
return std::move(*object);
}
std::cerr << fmt::format("Aborting due to {}", e.reason) << std::endl;
std::terminate();
}
} // namespace detail
} // namespace org::apache::nifi::minifi::utils