Newer
Older
/** Copyright (C) 2010-2024 Belledonne Communications SARL
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
/** Safely cast wrapped types to const.
*
* Using a wrapper type like std::shared_ptr<T> as if it was a std::shared_ptr<const T> is always safe, since we are
* restricting the set of operations that can be made on it, not broadening it.
* However C++'s type system does not allow for such casts.
*
* You could use reinterpret_cast directly, but that would be dangerous if the underlying type is later changed. (e.g.
* std::map<std::shared_ptr<T>> -> std::unordered_map<std::shared_ptr<T>>).
* The functions in this file provide a (non-exhaustive) list of safe casts, while ensuring your code still type-checks
* in a sane way.
*/
#pragma once
#include <array>
#include <map>
#include <memory>
#include <type_traits>
#include <unordered_map>
namespace flexisip {
template <typename, typename = void>
constexpr bool is_interior_const = true;
template <typename T>
constexpr bool
is_interior_const<T, std::void_t<decltype(*std::declval<T>() = std::declval<decltype(*std::declval<T>())>())>> =
false;
template <typename T>
struct add_interior_const {
static_assert(is_interior_const<T>);
using type = T;
};
template <typename T>
using add_interior_const_t = typename add_interior_const<T>::type;
template <template <typename...> class Tmpl, typename... Args>
struct add_interior_const<Tmpl<Args...>> {
static_assert(is_interior_const<Tmpl<Args...>>);
using type = Tmpl<add_interior_const_t<Args>...>;
};
template <typename T>
struct add_interior_const<std::unique_ptr<T>> {
using type = std::unique_ptr<std::add_const_t<add_interior_const_t<T>>>;
};
template <typename T>
struct add_interior_const<std::weak_ptr<T>> {
using type = std::weak_ptr<std::add_const_t<add_interior_const_t<T>>>;
};
template <typename T>
struct add_interior_const<std::shared_ptr<T>> {
using type = std::shared_ptr<std::add_const_t<add_interior_const_t<T>>>;
};
template <typename T, std::size_t S>
struct add_interior_const<std::array<T, S>> {
using type = std::array<add_interior_const_t<T>, S>;
};
template <typename T>
const add_interior_const_t<T>& castToConst(const T& t) {
return reinterpret_cast<const add_interior_const_t<T>&>(t);
}
} // namespace flexisip