blob: c13265021816d89091c25b160bcc2e2774b472e9 [file] [log] [blame]
/**
* @file GeneralUtils.h
*
* 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.
*/
#ifndef LIBMINIFI_INCLUDE_UTILS_GENERALUTILS_H_
#define LIBMINIFI_INCLUDE_UTILS_GENERALUTILS_H_
#include <memory>
#include <type_traits>
#include <utility>
#include <functional>
#include "gsl.h"
namespace org {
namespace apache {
namespace nifi {
namespace minifi {
namespace utils {
#if __cplusplus < 201402L
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
return std::unique_ptr<T>{ new T(std::forward<Args>(args)...) };
}
#else
using std::make_unique;
#endif /* < C++14 */
template<typename T, typename = typename std::enable_if<std::is_integral<T>::value>::type>
constexpr T intdiv_ceil(T numerator, T denominator) {
// note: division and remainder is 1 instruction on x86
return gsl_Expects(denominator != 0), ((numerator >= 0) != (denominator > 0)
? numerator / denominator // negative result rounds towards zero, i.e. up
: numerator / denominator + (numerator % denominator != 0));
}
using gsl::owner;
#if __cplusplus < 201402L
// from https://en.cppreference.com/w/cpp/utility/exchange
template<typename T, typename U = T>
T exchange(T& obj, U&& new_value) {
T old_value = std::move(obj);
obj = std::forward<U>(new_value);
return old_value;
}
#else
using std::exchange;
#endif /* < C++14 */
#if __cplusplus < 201703L
template<typename...>
using void_t = void;
#else
using std::void_t;
#endif /* < C++17 */
namespace internal {
/*
* We need this base class to enable safe multiple inheritance
* from std::enable_shared_from_this, it also needs to be polymorphic
* to allow dynamic_cast to the derived class.
*/
struct EnableSharedFromThisBase : std::enable_shared_from_this<EnableSharedFromThisBase> {
virtual ~EnableSharedFromThisBase() = default;
};
} // namespace internal
/*
* The virtual inheritance ensures that there is only a single
* std::weak_ptr instance in each instance.
*/
template<typename T>
struct EnableSharedFromThis : virtual internal::EnableSharedFromThisBase {
std::shared_ptr<T> sharedFromThis() {
return std::dynamic_pointer_cast<T>(internal::EnableSharedFromThisBase::shared_from_this());
}
};
// utilities to define single expression functions with proper noexcept and a decltype-ed return type (like decltype(auto) since C++14)
#define MINIFICPP_UTIL_DEDUCED(...) noexcept(noexcept(__VA_ARGS__)) -> decltype(__VA_ARGS__) { return __VA_ARGS__; }
#define MINIFICPP_UTIL_DEDUCED_CONDITIONAL(condition, ...) noexcept(noexcept(__VA_ARGS__)) -> typename std::enable_if<(condition), decltype(__VA_ARGS__)>::type { return __VA_ARGS__; }
#if __cplusplus < 201703L
namespace detail {
template<typename>
struct is_reference_wrapper : std::false_type {};
template<typename T>
struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
// invoke on pointer to member function
template<typename T, typename Clazz, typename Obj, typename... Args>
auto invoke_member_function_impl(T Clazz::*f, Obj&& obj, Args&&... args) MINIFICPP_UTIL_DEDUCED_CONDITIONAL(
/* cond: */ (std::is_base_of<Clazz, typename std::decay<decltype(obj)>::type>::value),
/* expr: */ (std::forward<Obj>(obj).*f)(std::forward<Args>(args)...))
template<typename T, typename Clazz, typename Obj, typename... Args>
auto invoke_member_function_impl(T Clazz::*f, Obj&& obj, Args&&... args) MINIFICPP_UTIL_DEDUCED_CONDITIONAL(
/* cond: */ (!std::is_base_of<Clazz, typename std::decay<decltype(obj)>::type>::value && is_reference_wrapper<typename std::decay<decltype(obj)>::type>::value),
/* expr: */ (std::forward<Obj>(obj).get().*f)(std::forward<Args>(args)...))
template<typename T, typename Clazz, typename Obj, typename... Args>
auto invoke_member_function_impl(T Clazz::*f, Obj&& obj, Args&&... args) MINIFICPP_UTIL_DEDUCED_CONDITIONAL(
/* cond: */ (!std::is_base_of<Clazz, typename std::decay<decltype(obj)>::type>::value && !is_reference_wrapper<typename std::decay<decltype(obj)>::type>::value),
/* expr: */ ((*std::forward<Obj>(obj)).*f)(std::forward<Args>(args)...))
// invoke on pointer to data member
template<typename T, typename Clazz, typename Obj>
auto invoke_member_object_impl(T Clazz::*f, Obj&& obj) MINIFICPP_UTIL_DEDUCED_CONDITIONAL(
/* cond: */ (std::is_base_of<Clazz, typename std::decay<decltype(obj)>::type>::value),
/* expr: */ std::forward<Obj>(obj).*f)
template<typename T, typename Clazz, typename Obj>
auto invoke_member_object_impl(T Clazz::*f, Obj&& obj) MINIFICPP_UTIL_DEDUCED_CONDITIONAL(
/* cond: */ (!std::is_base_of<Clazz, typename std::decay<decltype(obj)>::type>::value && is_reference_wrapper<typename std::decay<decltype(obj)>::type>::value),
/* expr: */ std::forward<Obj>(obj).get().*f)
template<typename T, typename Clazz, typename Obj>
auto invoke_member_object_impl(T Clazz::*f, Obj&& obj) MINIFICPP_UTIL_DEDUCED_CONDITIONAL(
/* cond: */ (!std::is_base_of<Clazz, typename std::decay<decltype(obj)>::type>::value && !is_reference_wrapper<typename std::decay<decltype(obj)>::type>::value),
/* expr: */ (*std::forward<Obj>(obj)).*f)
// invoke_impl
template<typename T, typename Clazz, typename Obj, typename... Args>
auto invoke_impl(T Clazz::*f, Obj&& obj, Args&&... args) MINIFICPP_UTIL_DEDUCED_CONDITIONAL(
/* cond: */ std::is_member_function_pointer<decltype(f)>::value,
/* expr: */ invoke_member_function_impl(f, std::forward<Obj>(obj), std::forward<Args>(args)...))
template<typename T, typename Clazz, typename Obj>
auto invoke_impl(T Clazz::*f, Obj&& obj) MINIFICPP_UTIL_DEDUCED_CONDITIONAL(
/* cond: */ std::is_member_object_pointer<decltype(f)>::value,
/* expr: */ invoke_member_object_impl(f, std::forward<Obj>(obj)))
template<typename F, typename... Args>
auto invoke_impl(F&& f, Args&&... args) MINIFICPP_UTIL_DEDUCED_CONDITIONAL(
/* cond: */ !std::is_member_function_pointer<F>::value && !std::is_member_object_pointer<F>::value,
/* expr: */ std::forward<F>(f)(std::forward<Args>(args)...))
} // namespace detail
template<typename F, typename... Args>
auto invoke(F&& f, Args&&... args) MINIFICPP_UTIL_DEDUCED(detail::invoke_impl(std::forward<F>(f), std::forward<Args>(args)...))
#else
using std::invoke
#endif /* < C++17 */
} // namespace utils
} // namespace minifi
} // namespace nifi
} // namespace apache
} // namespace org
#endif // LIBMINIFI_INCLUDE_UTILS_GENERALUTILS_H_