Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
80 changes: 79 additions & 1 deletion libc/src/__support/CPP/type_traits/is_signed.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,98 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_SIGNED_H
#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_SIGNED_H

#include "include/llvm-libc-macros/stdfix-macros.h"
#include "src/__support/CPP/type_traits/bool_constant.h"
#include "src/__support/CPP/type_traits/is_arithmetic.h"
#include "src/__support/CPP/type_traits/is_fixed_point.h"
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"

namespace LIBC_NAMESPACE_DECL {
namespace cpp {

// is_signed
// Primary template: handles arithmetic and signed fixed-point types
template <typename T>
struct is_signed : bool_constant<(is_arithmetic_v<T> && (T(-1) < T(0)))> {
LIBC_INLINE constexpr operator bool() const { return is_signed::value; }
LIBC_INLINE constexpr bool operator()() const { return is_signed::value; }
};
Comment on lines 23 to 27
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I just tested locally, and the following seems to work without all the specializations:

struct is_signed : bool_constant<
    (is_fixed_point_v<T> && T(-0.5) < T(0)) ||
    (is_arithmetic_v<T> && (T(-1) < T(0)))> {
    ...
};

Copy link
Contributor Author

@kr-2003 kr-2003 Mar 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

really? i think i am missing out on something, because this is what i get when i try this on my machine:

/Users/llvm-project/libc/src/__support/CPP/type_traits/is_signed.h:23:34: error: non-type template argument is not a constant expression
   23 | struct is_signed : bool_constant<(is_fixed_point_v<T> && T(-0.5) < T(0)) ||
      |                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   24 |                                  (is_arithmetic_v<T> && (T(-1) < T(0)))> {
      |                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/llvm-project/libc/src/__support/CPP/type_traits/is_signed.h:105:46: note: in instantiation of template class '__llvm_libc_21_0_0_git::cpp::is_signed<unsigned _Fract>' requested here
  105 | LIBC_INLINE_VAR constexpr bool is_signed_v = is_signed<T>::value;
      |                                              ^
/Users/llvm-project/libc/test/src/__support/CPP/type_traits_test.cpp:427:17: note: in instantiation of variable template specialization '__llvm_libc_21_0_0_git::cpp::is_signed_v<unsigned _Fract>' requested here
  427 |   EXPECT_FALSE((is_signed_v<unsigned fract>));
/Users/llvm-project/libc/src/__support/CPP/type_traits/is_signed.h:23:60: note: value 0.0 is outside the range of representable values of type 'unsigned _Fract'
   23 | struct is_signed : bool_constant<(is_fixed_point_v<T> && T(-0.5) < T(0)) ||

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So it looks like static_assert with that works fine, but not with EXPECT_EQ in the tests that you added. Probably something is missing for fixed point support in constexpr context.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So it looks like static_assert with that works fine, but not with EXPECT_EQ in the tests that you added. Probably something is missing for fixed point support in constexpr context.

opened issue at #133680


#ifdef LIBC_COMPILER_HAS_FIXED_POINT
// Specializations for unsigned fixed-point types
template <typename T, bool IsSigned>
struct fixed_point_is_signed : bool_constant<IsSigned> {
LIBC_INLINE constexpr operator bool() const {
return fixed_point_is_signed::value;
}
LIBC_INLINE constexpr bool operator()() const {
return fixed_point_is_signed::value;
}
};
template <> struct is_signed<fract> : fixed_point_is_signed<fract, true> {};
template <>
struct is_signed<unsigned short fract>
: fixed_point_is_signed<unsigned short fract, false> {};
template <>
struct is_signed<unsigned fract>
: fixed_point_is_signed<unsigned fract, false> {};
template <>
struct is_signed<unsigned long fract>
: fixed_point_is_signed<unsigned long fract, false> {};
template <>
struct is_signed<short fract> : fixed_point_is_signed<short fract, true> {};
template <>
struct is_signed<long fract> : fixed_point_is_signed<long fract, true> {};
template <> struct is_signed<accum> : fixed_point_is_signed<accum, true> {};
template <>
struct is_signed<unsigned short accum>
: fixed_point_is_signed<unsigned short accum, false> {};
template <>
struct is_signed<unsigned accum>
: fixed_point_is_signed<unsigned accum, false> {};
template <>
struct is_signed<unsigned long accum>
: fixed_point_is_signed<unsigned long accum, false> {};
template <>
struct is_signed<short accum> : fixed_point_is_signed<short accum, true> {};
template <>
struct is_signed<long accum> : fixed_point_is_signed<long accum, true> {};
template <>
struct is_signed<sat fract> : fixed_point_is_signed<sat fract, true> {};
template <>
struct is_signed<unsigned short sat fract>
: fixed_point_is_signed<unsigned short sat fract, false> {};
template <>
struct is_signed<unsigned sat fract>
: fixed_point_is_signed<unsigned sat fract, false> {};
template <>
struct is_signed<unsigned long sat fract>
: fixed_point_is_signed<unsigned long sat fract, false> {};
template <>
struct is_signed<short sat fract>
: fixed_point_is_signed<short sat fract, true> {};
template <>
struct is_signed<long sat fract> : fixed_point_is_signed<long sat fract, true> {
};
template <>
struct is_signed<sat accum> : fixed_point_is_signed<sat accum, true> {};
template <>
struct is_signed<unsigned short sat accum>
: fixed_point_is_signed<unsigned short sat accum, false> {};
template <>
struct is_signed<unsigned sat accum>
: fixed_point_is_signed<unsigned sat accum, false> {};
template <>
struct is_signed<unsigned long sat accum>
: fixed_point_is_signed<unsigned long sat accum, false> {};
template <>
struct is_signed<short sat accum>
: fixed_point_is_signed<short sat accum, true> {};
template <>
struct is_signed<long sat accum> : fixed_point_is_signed<long sat accum, true> {
};
#endif // LIBC_COMPILER_HAS_FIXED_POINT

template <typename T>
LIBC_INLINE_VAR constexpr bool is_signed_v = is_signed<T>::value;

Expand Down
84 changes: 83 additions & 1 deletion libc/src/__support/CPP/type_traits/is_unsigned.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,102 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_UNSIGNED_H
#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_UNSIGNED_H

#include "include/llvm-libc-macros/stdfix-macros.h"
#include "src/__support/CPP/type_traits/bool_constant.h"
#include "src/__support/CPP/type_traits/is_arithmetic.h"
#include "src/__support/CPP/type_traits/is_fixed_point.h"
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"

namespace LIBC_NAMESPACE_DECL {
namespace cpp {

// is_unsigned
// Primary template: handles arithmetic and signed fixed-point types
template <typename T>
struct is_unsigned : bool_constant<(is_arithmetic_v<T> && (T(-1) > T(0)))> {
LIBC_INLINE constexpr operator bool() const { return is_unsigned::value; }
LIBC_INLINE constexpr bool operator()() const { return is_unsigned::value; }
};

#ifdef LIBC_COMPILER_HAS_FIXED_POINT
// Specializations for unsigned fixed-point types
template <typename T, bool IsUnsigned>
struct fixed_point_is_unsigned : bool_constant<IsUnsigned> {
LIBC_INLINE constexpr operator bool() const {
return fixed_point_is_unsigned::value;
}
LIBC_INLINE constexpr bool operator()() const {
return fixed_point_is_unsigned::value;
}
};
template <>
struct is_unsigned<fract> : fixed_point_is_unsigned<fract, false> {};
template <>
struct is_unsigned<unsigned short fract>
: fixed_point_is_unsigned<unsigned short fract, true> {};
template <>
struct is_unsigned<unsigned fract>
: fixed_point_is_unsigned<unsigned fract, true> {};
template <>
struct is_unsigned<unsigned long fract>
: fixed_point_is_unsigned<unsigned long fract, true> {};
template <>
struct is_unsigned<short fract> : fixed_point_is_unsigned<short fract, false> {
};
template <>
struct is_unsigned<long fract> : fixed_point_is_unsigned<long fract, false> {};
template <>
struct is_unsigned<accum> : fixed_point_is_unsigned<accum, false> {};
template <>
struct is_unsigned<unsigned short accum>
: fixed_point_is_unsigned<unsigned short accum, true> {};
template <>
struct is_unsigned<unsigned accum>
: fixed_point_is_unsigned<unsigned accum, true> {};
template <>
struct is_unsigned<unsigned long accum>
: fixed_point_is_unsigned<unsigned long accum, true> {};
template <>
struct is_unsigned<short accum> : fixed_point_is_unsigned<short accum, false> {
};
template <>
struct is_unsigned<long accum> : fixed_point_is_unsigned<long accum, false> {};
template <>
struct is_unsigned<sat fract> : fixed_point_is_unsigned<sat fract, false> {};
template <>
struct is_unsigned<unsigned short sat fract>
: fixed_point_is_unsigned<unsigned short sat fract, true> {};
template <>
struct is_unsigned<unsigned sat fract>
: fixed_point_is_unsigned<unsigned sat fract, true> {};
template <>
struct is_unsigned<unsigned long sat fract>
: fixed_point_is_unsigned<unsigned long sat fract, true> {};
template <>
struct is_unsigned<short sat fract>
: fixed_point_is_unsigned<short sat fract, false> {};
template <>
struct is_unsigned<long sat fract>
: fixed_point_is_unsigned<long sat fract, false> {};
template <>
struct is_unsigned<sat accum> : fixed_point_is_unsigned<sat accum, false> {};
template <>
struct is_unsigned<unsigned short sat accum>
: fixed_point_is_unsigned<unsigned short sat accum, true> {};
template <>
struct is_unsigned<unsigned sat accum>
: fixed_point_is_unsigned<unsigned sat accum, true> {};
template <>
struct is_unsigned<unsigned long sat accum>
: fixed_point_is_unsigned<unsigned long sat accum, true> {};
template <>
struct is_unsigned<short sat accum>
: fixed_point_is_unsigned<short sat accum, false> {};
template <>
struct is_unsigned<long sat accum>
: fixed_point_is_unsigned<long sat accum, false> {};
#endif // LIBC_COMPILER_HAS_FIXED_POINT

template <typename T>
LIBC_INLINE_VAR constexpr bool is_unsigned_v = is_unsigned<T>::value;

Expand Down
65 changes: 63 additions & 2 deletions libc/test/src/__support/CPP/type_traits_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//

#include "include/llvm-libc-macros/stdfix-macros.h"
#include "src/__support/CPP/type_traits.h"
#include "src/__support/macros/config.h"
#include "test/UnitTest/Test.h"
Expand Down Expand Up @@ -409,7 +410,37 @@ TEST(LlvmLibcTypeTraitsTest, is_object) {

// TODO is_scalar

// TODO is_signed
TEST(LlvmLibcTypeTraitsTest, is_signed) {
EXPECT_TRUE((is_signed_v<int>));
EXPECT_TRUE((is_signed_v<long>));
EXPECT_TRUE((is_signed_v<long long>));
EXPECT_FALSE((is_signed_v<unsigned int>));
EXPECT_FALSE((is_signed_v<unsigned long>));
EXPECT_FALSE((is_signed_v<unsigned long long>));
EXPECT_TRUE((is_signed_v<float>));
EXPECT_TRUE((is_signed_v<double>));
EXPECT_TRUE((is_signed_v<long double>));

#ifdef LIBC_COMPILER_HAS_FIXED_POINT
// for fixed point types
EXPECT_TRUE((is_signed_v<fract>));
EXPECT_FALSE((is_signed_v<unsigned fract>));
EXPECT_TRUE((is_signed_v<accum>));
EXPECT_FALSE((is_signed_v<unsigned accum>));
EXPECT_TRUE((is_signed_v<sat fract>));
EXPECT_FALSE((is_signed_v<unsigned sat fract>));
EXPECT_TRUE((is_signed_v<sat accum>));
EXPECT_FALSE((is_signed_v<unsigned sat accum>));
EXPECT_TRUE((is_signed_v<short fract>));
EXPECT_FALSE((is_signed_v<unsigned short fract>));
EXPECT_TRUE((is_signed_v<short accum>));
EXPECT_FALSE((is_signed_v<unsigned short accum>));
EXPECT_TRUE((is_signed_v<long fract>));
EXPECT_FALSE((is_signed_v<unsigned long fract>));
EXPECT_TRUE((is_signed_v<long accum>));
EXPECT_FALSE((is_signed_v<unsigned long accum>));
#endif
}

// TODO is_trivially_constructible

Expand All @@ -419,7 +450,37 @@ TEST(LlvmLibcTypeTraitsTest, is_object) {

// TODO is_union

// TODO is_unsigned
TEST(LlvmLibcTypeTraitsTest, is_unsigned) {
EXPECT_FALSE((is_unsigned_v<int>));
EXPECT_FALSE((is_unsigned_v<long>));
EXPECT_FALSE((is_unsigned_v<long long>));
EXPECT_TRUE((is_unsigned_v<unsigned int>));
EXPECT_TRUE((is_unsigned_v<unsigned long>));
EXPECT_TRUE((is_unsigned_v<unsigned long long>));
EXPECT_FALSE((is_unsigned_v<float>));
EXPECT_FALSE((is_unsigned_v<double>));
EXPECT_FALSE((is_unsigned_v<long double>));

#ifdef LIBC_COMPILER_HAS_FIXED_POINT
// for fixed point types
EXPECT_FALSE((is_unsigned_v<fract>));
EXPECT_TRUE((is_unsigned_v<unsigned fract>));
EXPECT_FALSE((is_unsigned_v<accum>));
EXPECT_TRUE((is_unsigned_v<unsigned accum>));
EXPECT_FALSE((is_unsigned_v<sat fract>));
EXPECT_TRUE((is_unsigned_v<unsigned sat fract>));
EXPECT_FALSE((is_unsigned_v<sat accum>));
EXPECT_TRUE((is_unsigned_v<unsigned sat accum>));
EXPECT_FALSE((is_unsigned_v<short fract>));
EXPECT_TRUE((is_unsigned_v<unsigned short fract>));
EXPECT_FALSE((is_unsigned_v<short accum>));
EXPECT_TRUE((is_unsigned_v<unsigned short accum>));
EXPECT_FALSE((is_unsigned_v<long fract>));
EXPECT_TRUE((is_unsigned_v<unsigned long fract>));
EXPECT_FALSE((is_unsigned_v<long accum>));
EXPECT_TRUE((is_unsigned_v<unsigned long accum>));
#endif
}

// TODO is_void

Expand Down
Loading