mercredi 13 janvier 2021

get packing of a POD structure to calculate element offset

I am writing a function to calculate an offset of an element in a POD struct in my pod_reflection library. Complete header link.

To calculate an offset of a next element I need to know the packing value of a struct (which can be set via #pragma pack(N)). I assumed that alignof operator yields this value since, for example, for pack(1) it returned 1:

#pragma pack(push, 1)
struct packed
{
    char a;
    int b;
};
#pragma pack(pop)

static_assert(alignof(packed) == 1, "");

I found out that I was wrong. If a structure contains double (8 bytes), alignof yields 8. So the calculated offset will be invalid.

Here is the code I use to calculate an offset.

        template<typename POD, typename TupleFeed = basic_feed>
        constexpr size_t pod_packing()
        {
            return alignof(POD);
        }

        // TODO: check this function!
        template<size_t I, typename POD, typename TupleFeed>
        class pod_elem_offset
        {
            static_assert(!std::is_same<undeduced, pod_element_t<I, POD, TupleFeed>>::value,
                          "Can't get an offset for an undeduced POD element!");

            template<size_t Indx>
            constexpr static size_t pod_elem_size()
            {
                return sizeof(pod_element_t<Indx, POD, TupleFeed>);
            }

        public:
            constexpr static std::ptrdiff_t packing = pod_packing<POD, TupleFeed>();

            constexpr static std::ptrdiff_t value()
            {
                return get_value(tag_s<0>(), 0);
            }

        private:
            // stop case
            constexpr static std::ptrdiff_t get_value(tag_s<I>, size_t offset)
            {
                return offset;
            }

            // general recursion
            template<size_t N>
            constexpr static std::ptrdiff_t get_value(tag_s<N>, size_t offset)
            {
                static_assert(!std::is_same<undeduced, pod_element_t<N, POD, TupleFeed>>::value,
                              "Can't get an offset for a POD element: failed to deduce one of POD elements' type!");

                // TODO: implement with packing
                return get_value(tag_s<N + 1>(),
                                 !((offset + pod_elem_size<N>()) % packing) ||
                                 packing - (offset + pod_elem_size<N>()) % packing >= pod_elem_size<N + 1>() ?
                                 offset + pod_elem_size<N>() :
                                 offset + pod_elem_size<N>() +
                                 packing - (offset + pod_elem_size<N>()) % packing
                );
            }

        };

How can I deduce the packing value of a struct for padding calculation?


I figured out a workaround. Not sure it would suffice for every possible packing.

        template<typename POD>
        constexpr size_t pod_packing()
        {
            return sizeof(POD) % 4 ?
                   sizeof(POD) % 4 :
                   4;
        }




Aucun commentaire:

Enregistrer un commentaire