Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/iris/bits/is_function_object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

// SPDX-License-Identifier: MIT

#include <iris/config.hpp> // IWYU pragma: keep

#include <type_traits>

namespace iris {
Expand Down
2 changes: 2 additions & 0 deletions include/iris/bits/specialization_of.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

// SPDX-License-Identifier: MIT

#include <iris/config.hpp> // IWYU pragma: keep

#include <type_traits>

namespace iris {
Expand Down
4 changes: 3 additions & 1 deletion include/iris/requirements.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@

// SPDX-License-Identifier: MIT

#include <iris/config.hpp> // IWYU pragma: keep

#include <iris/hash_fwd.hpp>
#include <iris/bits/is_function_object.hpp>
#include <iris/bits/specialization_of.hpp>

#include <concepts>
#include <concepts> // IWYU pragma: export
#include <type_traits>
#include <utility>

Expand Down
130 changes: 130 additions & 0 deletions include/iris/stdint.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#ifndef IRIS_ZZ_STDINT_HPP
#define IRIS_ZZ_STDINT_HPP

// SPDX-License-Identifier: MIT

#include <iris/config.hpp> // IWYU pragma: keep

#include <iris/type_traits.hpp>

#include <concepts>
#include <type_traits>

#include <cstdint> // IWYU pragma: export
#include <cstddef> // IWYU pragma: keep

namespace iris {

// `std::make_signed<T>` family requires T to be nonbool integer or enum

namespace detail {

template<bool IsSigned, std::size_t Bytes>
struct integer_of_size_impl;

template<>
struct integer_of_size_impl<true, 1>
{
using type = std::int8_t;
};

template<>
struct integer_of_size_impl<true, 2>
{
using type = std::int16_t;
};

template<>
struct integer_of_size_impl<true, 4>
{
using type = std::int32_t;
};

template<>
struct integer_of_size_impl<true, 8>
{
using type = std::int64_t;
};

// ----------------------------------------------

template<>
struct integer_of_size_impl<false, 1>
{
using type = std::uint8_t;
};

template<>
struct integer_of_size_impl<false, 2>
{
using type = std::uint16_t;
};

template<>
struct integer_of_size_impl<false, 4>
{
using type = std::uint32_t;
};

template<>
struct integer_of_size_impl<false, 8>
{
using type = std::uint64_t;
};

template<class T>
struct signedness_of_integral;

template<std::integral T>
struct signedness_of_integral<T> : std::bool_constant<std::is_signed_v<T>>
{};

template<class T>
requires std::is_enum_v<T>
struct signedness_of_integral<T> : std::bool_constant<std::is_signed_v<std::underlying_type_t<T>>>
{};

template<class T>
using make_signed_of_size_impl_t = integer_of_size_impl<true, sizeof(T)>::type;

template<class T>
using make_unsigned_of_size_impl_t = integer_of_size_impl<false, sizeof(T)>::type;

template<class T>
using make_integer_of_size_impl_t = integer_of_size_impl<signedness_of_integral<T>::value, sizeof(T)>::type;

} // detail

template<class T>
struct make_signed_of_size
{
static_assert(std::integral<T> && !std::same_as<std::remove_cv_t<T>, bool> || std::is_enum_v<T>);
using type = remove_cv<T>::template apply<detail::make_signed_of_size_impl_t>;
};

template<class T>
using make_signed_of_size_t = make_signed_of_size<T>::type;

template<class T>
struct make_unsigned_of_size
{
static_assert(std::integral<T> && !std::same_as<std::remove_cv_t<T>, bool> || std::is_enum_v<T>);
using type = remove_cv<T>::template apply<detail::make_unsigned_of_size_impl_t>;
};

template<class T>
using make_unsigned_of_size_t = make_unsigned_of_size<T>::type;

template<class T>
struct make_integer_of_size
{
static_assert(std::integral<T> && !std::same_as<std::remove_cv_t<T>, bool> || std::is_enum_v<T>);
using type = remove_cv<T>::template apply<detail::make_integer_of_size_impl_t>;
};

template<class T>
using make_integer_of_size_t = make_integer_of_size<T>::type;

} // iris

#endif
41 changes: 39 additions & 2 deletions include/iris/type_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,58 @@

// SPDX-License-Identifier: MIT

#include <iris/config.hpp>
#include <iris/config.hpp> // IWYU pragma: keep

#include <iris/bits/is_function_object.hpp> // IWYU pragma: export
#include <iris/bits/specialization_of.hpp> // IWYU pragma: export

#include <iris/requirements.hpp>

#include <concepts>
#include <type_traits>
#include <type_traits> // IWYU pragma: export
#include <utility>

#include <cstddef>

namespace iris {

template<class T>
struct remove_cv
{
using type = T;

template<template <class> class F>
using apply = F<T>;
};

template<class T>
struct remove_cv<T const>
{
using type = T;

template<template <class> class F>
using apply = F<T> const;
};

template<class T>
struct remove_cv<T volatile>
{
using type = T;

template<template <class> class F>
using apply = F<T> volatile;
};

template<class T>
struct remove_cv<T const volatile>
{
using type = T;

template<template <class> class F>
using apply = F<T> const volatile;
};


template<class... Ts>
struct type_list
{
Expand Down
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ if(PROJECT_IS_TOP_LEVEL)
IRIS_TEST_IRIS_TESTS
core
type_traits
stdint
enum
indirect
colorize_format
Expand Down
118 changes: 118 additions & 0 deletions test/stdint.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#include "iris_test.hpp"

#include <iris/stdint.hpp>

#include <concepts>

#include <cstdint>
#include <cstddef> // std::byte

enum non_scoped_int16_t : std::int16_t {};
enum struct scoped_int16_t : std::int16_t {};

TEST_CASE("stdint")
{
static_assert(sizeof(char) == 1);

{
STATIC_CHECK(std::same_as<iris::make_signed_of_size_t<std::int8_t>, std::int8_t>);
STATIC_CHECK(std::same_as<iris::make_signed_of_size_t<std::int16_t>, std::int16_t>);
STATIC_CHECK(std::same_as<iris::make_signed_of_size_t<std::int32_t>, std::int32_t>);
STATIC_CHECK(std::same_as<iris::make_signed_of_size_t<std::int64_t>, std::int64_t>);

// If cv variants works here, everything else works; skip other test cases.
STATIC_CHECK(std::same_as<iris::make_signed_of_size_t<std::int8_t const>, std::int8_t const>);
STATIC_CHECK(std::same_as<iris::make_signed_of_size_t<std::int16_t const>, std::int16_t const>);
STATIC_CHECK(std::same_as<iris::make_signed_of_size_t<std::int32_t const>, std::int32_t const>);
STATIC_CHECK(std::same_as<iris::make_signed_of_size_t<std::int64_t const>, std::int64_t const>);
STATIC_CHECK(std::same_as<iris::make_signed_of_size_t<std::int8_t const volatile>, std::int8_t const volatile>);
STATIC_CHECK(std::same_as<iris::make_signed_of_size_t<std::int16_t const volatile>, std::int16_t const volatile>);
STATIC_CHECK(std::same_as<iris::make_signed_of_size_t<std::int32_t const volatile>, std::int32_t const volatile>);
STATIC_CHECK(std::same_as<iris::make_signed_of_size_t<std::int64_t const volatile>, std::int64_t const volatile>);

STATIC_CHECK(std::same_as<iris::make_signed_of_size_t<std::uint8_t>, std::int8_t>);
STATIC_CHECK(std::same_as<iris::make_signed_of_size_t<std::uint16_t>, std::int16_t>);
STATIC_CHECK(std::same_as<iris::make_signed_of_size_t<std::uint32_t>, std::int32_t>);
STATIC_CHECK(std::same_as<iris::make_signed_of_size_t<std::uint64_t>, std::int64_t>);

STATIC_CHECK(std::same_as<iris::make_signed_of_size_t<char>, std::int8_t>);
STATIC_CHECK(std::same_as<iris::make_signed_of_size_t<signed char>, std::int8_t>);
STATIC_CHECK(std::same_as<iris::make_signed_of_size_t<unsigned char>, std::int8_t>);
STATIC_CHECK(std::same_as<iris::make_signed_of_size_t<char8_t>, std::int8_t>);
STATIC_CHECK(std::same_as<iris::make_signed_of_size_t<char16_t>, std::int16_t>);
STATIC_CHECK(std::same_as<iris::make_signed_of_size_t<char32_t>, std::int32_t>);

STATIC_CHECK(std::same_as<iris::make_signed_of_size_t<std::byte>, std::int8_t>);
STATIC_CHECK(std::same_as<iris::make_signed_of_size_t<non_scoped_int16_t>, std::int16_t>);
STATIC_CHECK(std::same_as<iris::make_signed_of_size_t<scoped_int16_t>, std::int16_t>);
}
{
STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<std::int8_t>, std::uint8_t>);
STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<std::int16_t>, std::uint16_t>);
STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<std::int32_t>, std::uint32_t>);
STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<std::int64_t>, std::uint64_t>);

// If cv variants works here, everything else works; skip other test cases.
STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<std::int8_t const>, std::uint8_t const>);
STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<std::int16_t const>, std::uint16_t const>);
STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<std::int32_t const>, std::uint32_t const>);
STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<std::int64_t const>, std::uint64_t const>);
STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<std::int8_t const volatile>, std::uint8_t const volatile>);
STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<std::int16_t const volatile>, std::uint16_t const volatile>);
STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<std::int32_t const volatile>, std::uint32_t const volatile>);
STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<std::int64_t const volatile>, std::uint64_t const volatile>);

STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<std::uint8_t>, std::uint8_t>);
STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<std::uint16_t>, std::uint16_t>);
STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<std::uint32_t>, std::uint32_t>);
STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<std::uint64_t>, std::uint64_t>);

STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<char>, std::uint8_t>);
STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<signed char>, std::uint8_t>);
STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<unsigned char>, std::uint8_t>);
STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<char8_t>, std::uint8_t>);
STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<char16_t>, std::uint16_t>);
STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<char32_t>, std::uint32_t>);

STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<std::byte>, std::uint8_t>);
STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<std::byte const>, std::uint8_t const>);
STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<non_scoped_int16_t>, std::uint16_t>);
STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<non_scoped_int16_t const>, std::uint16_t const>);
STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<scoped_int16_t>, std::uint16_t>);
STATIC_CHECK(std::same_as<iris::make_unsigned_of_size_t<scoped_int16_t const>, std::uint16_t const>);
}
{
STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<std::int8_t>, std::int8_t>);
STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<std::int16_t>, std::int16_t>);
STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<std::int32_t>, std::int32_t>);
STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<std::int64_t>, std::int64_t>);

// If cv variants works here, everything else works; skip other test cases.
STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<std::int8_t const>, std::int8_t const>);
STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<std::int16_t const>, std::int16_t const>);
STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<std::int32_t const>, std::int32_t const>);
STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<std::int64_t const>, std::int64_t const>);
STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<std::int8_t const volatile>, std::int8_t const volatile>);
STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<std::int16_t const volatile>, std::int16_t const volatile>);
STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<std::int32_t const volatile>, std::int32_t const volatile>);
STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<std::int64_t const volatile>, std::int64_t const volatile>);

STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<std::uint8_t>, std::uint8_t>);
STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<std::uint16_t>, std::uint16_t>);
STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<std::uint32_t>, std::uint32_t>);
STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<std::uint64_t>, std::uint64_t>);

STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<signed char>, std::int8_t>);
STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<unsigned char>, std::uint8_t>);
STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<char8_t>, std::uint8_t>);
STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<char16_t>, std::uint16_t>);
STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<char32_t>, std::uint32_t>);

STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<std::byte>, std::uint8_t>);
STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<std::byte const>, std::uint8_t const>);
STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<non_scoped_int16_t>, std::int16_t>);
STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<non_scoped_int16_t const>, std::int16_t const>);
STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<scoped_int16_t>, std::int16_t>);
STATIC_CHECK(std::same_as<iris::make_integer_of_size_t<scoped_int16_t const>, std::int16_t const>);
}
}
Loading