Program Listing for File integer.h

Return to documentation for file (liberate/serialization/integer.h)

/*
 * This file is part of liberate.
 *
 * Author(s): Jens Finkhaeuser <jens@finkhaeuser.de>
 *
 * Copyright (c) 2020-2021 Jens Finkhaeuser.
 * Copyright (c) 2022 Interpeer gUG (haftungsbeschränkt)
 *
 * SPDX-License-Identifier: GPL-3.0-only
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef LIBERATE_SERIALIZATION_INTEGER_H
#define LIBERATE_SERIALIZATION_INTEGER_H

#ifndef __cplusplus
#error You are trying to include a C++ only header file
#endif

#include <liberate.h>

#include <cstddef>
#include <type_traits>

#include <liberate/types/type_traits.h>

namespace liberate::serialization {

template <typename T>
struct enable_integer_serialization
{};


template <typename T>
struct enable_integer_serialization<T const>
  : enable_integer_serialization<T>
{};

template <typename T>
struct enable_integer_serialization<T volatile>
  : enable_integer_serialization<T>
{};

template <typename T>
struct enable_integer_serialization<T const volatile>
  : enable_integer_serialization<T>
{};


template <typename T>
using integer_serialization_enabled = typename enable_integer_serialization<T>::type;

template <> struct enable_integer_serialization<char> { using type = std::size_t;  };
template <> struct enable_integer_serialization<signed char> { using type = std::size_t;  };
template <> struct enable_integer_serialization<unsigned char> { using type = std::size_t;  };
#if defined(LIBERATE_HAVE_WHCAR_T)
template <> struct enable_integer_serialization<wchar_t> { using type = std::size_t;  };
#endif
#if defined(LIBERATE_HAVE_CHAR8_T)
template <> struct enable_integer_serialization<char8_t> { using type = std::size_t;  };
#endif
template <> struct enable_integer_serialization<char16_t> { using type = std::size_t;  };
template <> struct enable_integer_serialization<char32_t> { using type = std::size_t;  };
template <> struct enable_integer_serialization<short> { using type = std::size_t;  };
template <> struct enable_integer_serialization<unsigned short> { using type = std::size_t;  };
template <> struct enable_integer_serialization<int> { using type = std::size_t;  };
template <> struct enable_integer_serialization<unsigned int> { using type = std::size_t;  };
template <> struct enable_integer_serialization<long> { using type = std::size_t;  };
template <> struct enable_integer_serialization<unsigned long> { using type = std::size_t;  };
template <> struct enable_integer_serialization<long long> { using type = std::size_t;  };
template <> struct enable_integer_serialization<unsigned long long> { using type = std::size_t;  };

namespace detail {

template <
  typename outT,
  typename inT
>
constexpr integer_serialization_enabled<inT>
serialize_int_impl(outT * output, std::size_t const & output_length, inT const & value)
{
  if (!output || !output_length) {
    return 0;
  }

  constexpr std::size_t const input_size = sizeof(inT);
  constexpr std::size_t const out_unit_size = sizeof(outT);
  if (input_size > out_unit_size * output_length) {
    return 0;
  }

  std::size_t written = 0;
  for (std::size_t i = 0 ; i < input_size / out_unit_size ; ++i) {
    output[i] = static_cast<outT>(value >>
        ((input_size - ((i + 1) * out_unit_size)) * 8)
      );
    ++written;
  }

  return written;
}



template <
  typename outT,
  typename inT
>
constexpr integer_serialization_enabled<outT>
deserialize_int_impl(outT & output, inT const * input, std::size_t input_length)
{
  if (!input || !input_length) {
    return 0;
  }

  constexpr std::size_t const output_size = sizeof(outT);
  constexpr std::size_t const in_unit_size = sizeof(inT);
  if (output_size > in_unit_size * input_length) {
    return 0;
  }

  std::size_t read = 0;
  output = outT{0};

  using unsigned_inT = typename std::make_unsigned<inT>::type;
  constexpr unsigned_inT const IN_MASK = ~unsigned_inT{0};

  for (std::size_t i = output_size / in_unit_size ; i > 0 ; --i) {
    output += (static_cast<outT>(input[i - 1]) & IN_MASK) << (output_size - (i * in_unit_size)) * 8;
    ++read; // flawfinder: ignore
  }

  return read; // flawfinder: ignore
}


} // namespace detail

template <
  typename outT,
  typename inT,
  std::enable_if_t<liberate::types::is_8bit_type<outT>::value, int> = 0
>
constexpr integer_serialization_enabled<inT>
serialize_int(outT * output, std::size_t output_length, inT const & value)
{
  return detail::serialize_int_impl(output, output_length, value);
}


template <
  typename outT,
  typename inT,
  std::enable_if_t<liberate::types::is_8bit_type<inT>::value, int> = 0
>
constexpr integer_serialization_enabled<outT>
deserialize_int(outT & output, inT const * input, std::size_t const & input_length)
{
  return detail::deserialize_int_impl(output, input, input_length);
}

} // namespace liberate::serialization

#endif // guard