Skip to content

iceoryx_utils/internal/cxx/variant.inl🔗

Namespaces🔗

Name
iox
building block to easily create free function for logging in a library context
iox::cxx

Defines🔗

Name
IOX_UTILS_CXX_VARIANT_INL

Macro Documentation🔗

define IOX_UTILS_CXX_VARIANT_INL🔗

#define IOX_UTILS_CXX_VARIANT_INL

Source code🔗

// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
// Copyright (c) 2021 by Apex.AI Inc. All rights reserved.
//
// 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.
//
// SPDX-License-Identifier: Apache-2.0
#ifndef IOX_UTILS_CXX_VARIANT_INL
#define IOX_UTILS_CXX_VARIANT_INL

#include "iceoryx_utils/cxx/variant.hpp"

namespace iox
{
namespace cxx
{
template <typename... Types>
inline variant<Types...>::variant(const variant& f_rhs) noexcept
    : m_type_index(f_rhs.m_type_index)
{
    if (m_type_index != INVALID_VARIANT_INDEX)
    {
        internal::call_at_index<0, Types...>::copyConstructor(
            m_type_index, const_cast<internal::byte_t*>(f_rhs.m_storage), m_storage);
    }
}

template <typename... Types>
template <uint64_t N, typename... CTorArguments>
inline variant<Types...>::variant(const in_place_index<N>&, CTorArguments&&... f_args) noexcept
{
    emplace_at_index<N>(std::forward<CTorArguments>(f_args)...);
}

template <typename... Types>
template <typename T, typename... CTorArguments>
inline variant<Types...>::variant(const in_place_type<T>&, CTorArguments&&... f_args) noexcept
{
    emplace<T>(std::forward<CTorArguments>(f_args)...);
}

template <typename... Types>
variant<Types...>& variant<Types...>::operator=(const variant& f_rhs) noexcept
{
    if (this != &f_rhs)
    {
        if (m_type_index != f_rhs.m_type_index)
        {
            call_element_destructor();
            m_type_index = f_rhs.m_type_index;

            if (m_type_index != INVALID_VARIANT_INDEX)
            {
                internal::call_at_index<0, Types...>::copyConstructor(
                    m_type_index, const_cast<internal::byte_t*>(f_rhs.m_storage), m_storage);
            }
        }
        else
        {
            if (m_type_index != INVALID_VARIANT_INDEX)
            {
                internal::call_at_index<0, Types...>::copy(
                    m_type_index, const_cast<internal::byte_t*>(f_rhs.m_storage), m_storage);
            }
        }
    }
    return *this;
}

template <typename... Types>
variant<Types...>::variant(variant&& f_rhs) noexcept
    : m_type_index{std::move(f_rhs.m_type_index)}
{
    if (m_type_index != INVALID_VARIANT_INDEX)
    {
        internal::call_at_index<0, Types...>::moveConstructor(m_type_index, f_rhs.m_storage, m_storage);
    }
}

template <typename... Types>
variant<Types...>& variant<Types...>::operator=(variant&& f_rhs) noexcept
{
    if (this != &f_rhs)
    {
        if (m_type_index != f_rhs.m_type_index)
        {
            call_element_destructor();
            m_type_index = std::move(f_rhs.m_type_index);
            if (m_type_index != INVALID_VARIANT_INDEX)
            {
                internal::call_at_index<0, Types...>::moveConstructor(m_type_index, f_rhs.m_storage, m_storage);
            }
        }
        else
        {
            if (m_type_index != INVALID_VARIANT_INDEX)
            {
                internal::call_at_index<0, Types...>::move(m_type_index, f_rhs.m_storage, m_storage);
            }
        }
    }
    return *this;
}

template <typename... Types>
inline variant<Types...>::~variant() noexcept
{
    call_element_destructor();
}

template <typename... Types>
void variant<Types...>::call_element_destructor() noexcept
{
    if (m_type_index != INVALID_VARIANT_INDEX)
    {
        internal::call_at_index<0, Types...>::destructor(m_type_index, m_storage);
    }
}

template <typename... Types>
template <typename T>
inline typename std::enable_if<!std::is_same<T, variant<Types...>&>::value, variant<Types...>>::type&
variant<Types...>::operator=(T&& f_rhs) noexcept
{
    if (m_type_index == INVALID_VARIANT_INDEX)
    {
        m_type_index = internal::get_index_of_type<0, T, Types...>::index;
    }

    if (!has_bad_variant_element_access<T>())
    {
        auto storage = static_cast<T*>(static_cast<void*>(m_storage));
        *storage = (std::forward<T>(f_rhs));
    }
    else
    {
        error_message(__PRETTY_FUNCTION__,
                      "wrong variant type assignment, another type is already "
                      "set in variant");
    }

    return *this;
}

template <typename... Types>
template <uint64_t TypeIndex, typename... CTorArguments>
inline bool variant<Types...>::emplace_at_index(CTorArguments&&... f_args) noexcept
{
    static_assert(TypeIndex <= sizeof...(Types), "TypeIndex is out of bounds");

    using T = typename internal::get_type_at_index<0, TypeIndex, Types...>::type;

    call_element_destructor();
    new (m_storage) T(std::forward<CTorArguments>(f_args)...);
    m_type_index = TypeIndex;

    return true;
}

template <typename... Types>
template <typename T, typename... CTorArguments>
inline bool variant<Types...>::emplace(CTorArguments&&... f_args) noexcept
{
    if (m_type_index != INVALID_VARIANT_INDEX && has_bad_variant_element_access<T>())
    {
        error_message(__PRETTY_FUNCTION__,
                      "wrong variant type emplacement, another type is already "
                      "set in variant");
        return false;
    }

    if (m_type_index != INVALID_VARIANT_INDEX)
    {
        call_element_destructor();
    }

    new (m_storage) T(std::forward<CTorArguments>(f_args)...);
    m_type_index = internal::get_index_of_type<0, T, Types...>::index;

    return true;
}

template <typename... Types>
template <uint64_t TypeIndex>
inline typename internal::get_type_at_index<0, TypeIndex, Types...>::type* variant<Types...>::get_at_index() noexcept
{
    if (TypeIndex != m_type_index)
    {
        return nullptr;
    }

    using T = typename internal::get_type_at_index<0, TypeIndex, Types...>::type;

    return static_cast<T*>(static_cast<void*>(m_storage));
}

template <typename... Types>
template <uint64_t TypeIndex>
inline const typename internal::get_type_at_index<0, TypeIndex, Types...>::type*
variant<Types...>::get_at_index() const noexcept
{
    using T = typename internal::get_type_at_index<0, TypeIndex, Types...>::type;
    return const_cast<const T*>(const_cast<variant*>(this)->get_at_index<TypeIndex>());
}

template <typename... Types>
template <typename T>
inline const T* variant<Types...>::get() const noexcept
{
    if (has_bad_variant_element_access<T>())
    {
        return nullptr;
    }
    else
    {
        return static_cast<const T*>(static_cast<const void*>(m_storage));
    }
}

template <typename... Types>
template <typename T>
inline T* variant<Types...>::get() noexcept
{
    return const_cast<T*>(const_cast<const variant*>(this)->get<T>());
}

template <typename... Types>
template <typename T>
inline T* variant<Types...>::get_if(T* f_default_value) noexcept
{
    return const_cast<T*>(const_cast<const variant*>(this)->get_if<T>(const_cast<const T*>(f_default_value)));
}

template <typename... Types>
template <typename T>
inline const T* variant<Types...>::get_if(const T* f_default_value) const noexcept
{
    if (has_bad_variant_element_access<T>())
    {
        return f_default_value;
    }

    return this->get<T>();
}

template <typename... Types>
constexpr size_t variant<Types...>::index() const noexcept
{
    return m_type_index;
}

template <typename... Types>
template <typename T>
inline bool variant<Types...>::has_bad_variant_element_access() const noexcept
{
    static_assert(internal::does_contain_type<T, Types...>::value, "variant does not contain given type");
    return (m_type_index != internal::get_index_of_type<0, T, Types...>::index);
}

template <typename... Types>
inline void variant<Types...>::error_message(const char* f_source, const char* f_msg) noexcept
{
    std::cerr << f_source << " ::: " << f_msg << std::endl;
}

template <typename T, typename... Types>
inline constexpr bool holds_alternative(const variant<Types...>& f_variant) noexcept
{
    return f_variant.template get<T>() != nullptr;
}
} // namespace cxx
} // namespace iox

#endif // IOX_UTILS_CXX_VARIANT_INL

Updated on 31 May 2022 at 15:29:15 CEST