Skip to content

File interface_id.hpp

File List > backends > cxx > include > zmbt > core > interface_id.hpp

Go to the documentation of this file

#ifndef ZMBT_CORE_INTERFACE_ID_HPP_
#define ZMBT_CORE_INTERFACE_ID_HPP_

#include <iostream>


#include <array>
#include <cstdint>
#include <cstring>
#include <typeinfo>
#include <utility>

#include <boost/mp11/tuple.hpp>

#include "aliases.hpp"

#include "entity_id.hpp"
#include "interface_traits.hpp"
#include "type_info.hpp"

namespace zmbt {


class interface_id : public entity_id {


    template <class Interface>
    boost::json::string ifc_addr(Interface const& ifc)
    {
        struct {
            ifc_pointer_t<Interface const&> ptr;
        } wrapper {get_ifc_pointer(ifc)};

        std::array<unsigned char, sizeof(wrapper)> repr {};
        std::memcpy(repr.data(), &wrapper, repr.size());

        constexpr char digits[] = "0123456789ABCDEF";

        boost::json::string encoded;
        encoded.reserve(repr.size() * 2 + 4);

        std::size_t pending_zero_bytes = 0U;
        std::size_t emitted_bytes = 0U;

        boost::mp11::tuple_for_each(repr, [&](unsigned char byte){
            if (byte == 0U)
            {
                ++pending_zero_bytes;
                return;
            }

            while (pending_zero_bytes > 0U)
            {
                encoded.push_back('0');
                encoded.push_back('0');
                --pending_zero_bytes;
                ++emitted_bytes;
            }
            encoded.push_back(digits[(byte >> 4U) & 0x0FU]);
            encoded.push_back(digits[byte & 0x0FU]);
            ++emitted_bytes;
        });

        if (emitted_bytes == 0U)
        {
            encoded.push_back('0');
            emitted_bytes = 1U;
            pending_zero_bytes = 0U;
        }

        if (pending_zero_bytes > 0U)
        {
            // Put num of trailing zero bytes after underscore in decimal
            encoded.push_back('_');
            std::array<char, 20U> buffer {};
            std::size_t idx = buffer.size();
            std::size_t value = pending_zero_bytes * 2U;
            do
            {
                buffer[--idx] = static_cast<char>('0' + (value % 10U));
                value /= 10U;
            }
            while (value != 0U);

            encoded.append(buffer.data() + idx, buffer.data() + buffer.size());
        }

        return encoded;
    }


  public:

    using entity_id::entity_id;
    using entity_id::operator boost::json::value;
    using entity_id::operator==;
    using entity_id::operator!=;

    template <class Interface, class = mp_if<is_ifc_handle<Interface const&>, void>>
    interface_id(Interface const& ifc)
        : entity_id(
            ifc_addr(ifc),
            typeid(remove_pointer_t<remove_cvref_t<ifc_handle_t<Interface const&>>>)
        )
    {
    }
};


} // namespace zmbt

template <>
struct std::hash<zmbt::interface_id>
{
    std::size_t operator()(const zmbt::interface_id& k) const
    {
        return hash_value(k);
    }
};


#endif // ZMBT_CORE_INTERFACE_ID_HPP_