Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
59 changes: 57 additions & 2 deletions libc/src/__support/CPP/type_traits/is_signed.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,73 @@

#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)))> {
struct is_signed : bool_constant<((is_fixed_point_v<T> || is_arithmetic_v<T>) &&
Copy link
Contributor

Choose a reason for hiding this comment

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

probably you could change it to:

(is_fixed_point_v<T> && T(-0.5) < T(0)) || (is_arithmetic_v<T> && T(-1) < T(0))

and remove all the fixed point specializations.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it won't work. even if the value is just less than 0, it will try to wrap around in unsigned type(and its not possible in fixed-points). I have tried it out.

Copy link
Contributor

Choose a reason for hiding this comment

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

@PiJoules is there problem with constexpr for fixed point type in clang?

Copy link
Contributor

Choose a reason for hiding this comment

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

What's the failure mode? Is it a compilation error or failure in one of the tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What's the failure mode? Is it a compilation error or failure in one of the tests?

i have explained here #133680

Copy link
Contributor

Choose a reason for hiding this comment

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

Replied to the issue.

tl;dr overflow for non-saturating types isn't defined, so unsigned _Fract(-1) can't be constant evaluated. If you want to check if a type is signed, I think you can do FXRep<T>::MIN() < FXRep::ZERO(). I also need to update the diagnostic since it's misleading.

(T(-1) < T(0)))> {
LIBC_INLINE constexpr operator bool() const { return is_signed::value; }
LIBC_INLINE constexpr bool operator()() const { return is_signed::value; }
};

#ifdef LIBC_COMPILER_HAS_FIXED_POINT
// Specializations for unsigned fixed-point types
template <> struct is_signed<unsigned short _Fract> : bool_constant<false> {
LIBC_INLINE constexpr operator bool() const { return is_signed::value; }
LIBC_INLINE constexpr bool operator()() const { return is_signed::value; }
};
template <> struct is_signed<unsigned _Fract> : bool_constant<false> {
LIBC_INLINE constexpr operator bool() const { return is_signed::value; }
LIBC_INLINE constexpr bool operator()() const { return is_signed::value; }
};
template <> struct is_signed<unsigned long _Fract> : bool_constant<false> {
LIBC_INLINE constexpr operator bool() const { return is_signed::value; }
LIBC_INLINE constexpr bool operator()() const { return is_signed::value; }
};
template <> struct is_signed<unsigned short _Accum> : bool_constant<false> {
LIBC_INLINE constexpr operator bool() const { return is_signed::value; }
LIBC_INLINE constexpr bool operator()() const { return is_signed::value; }
};
template <> struct is_signed<unsigned _Accum> : bool_constant<false> {
LIBC_INLINE constexpr operator bool() const { return is_signed::value; }
LIBC_INLINE constexpr bool operator()() const { return is_signed::value; }
};
template <> struct is_signed<unsigned long _Accum> : bool_constant<false> {
LIBC_INLINE constexpr operator bool() const { return is_signed::value; }
LIBC_INLINE constexpr bool operator()() const { return is_signed::value; }
};
template <> struct is_signed<unsigned short sat _Fract> : bool_constant<false> {
LIBC_INLINE constexpr operator bool() const { return is_signed::value; }
LIBC_INLINE constexpr bool operator()() const { return is_signed::value; }
};
template <> struct is_signed<unsigned sat _Fract> : bool_constant<false> {
LIBC_INLINE constexpr operator bool() const { return is_signed::value; }
LIBC_INLINE constexpr bool operator()() const { return is_signed::value; }
};
template <> struct is_signed<unsigned long sat _Fract> : bool_constant<false> {
LIBC_INLINE constexpr operator bool() const { return is_signed::value; }
LIBC_INLINE constexpr bool operator()() const { return is_signed::value; }
};
template <> struct is_signed<unsigned short sat _Accum> : bool_constant<false> {
LIBC_INLINE constexpr operator bool() const { return is_signed::value; }
LIBC_INLINE constexpr bool operator()() const { return is_signed::value; }
};
template <> struct is_signed<unsigned sat _Accum> : bool_constant<false> {
LIBC_INLINE constexpr operator bool() const { return is_signed::value; }
LIBC_INLINE constexpr bool operator()() const { return is_signed::value; }
};
template <> struct is_signed<unsigned long sat _Accum> : bool_constant<false> {
LIBC_INLINE constexpr operator bool() const { return is_signed::value; }
LIBC_INLINE constexpr bool operator()() const { return is_signed::value; }
};
#endif // LIBC_COMPILER_HAS_FIXED_POINT

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

Expand Down
61 changes: 59 additions & 2 deletions libc/src/__support/CPP/type_traits/is_unsigned.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,75 @@

#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)))> {
struct is_unsigned
: bool_constant<((is_fixed_point_v<T> || 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 <> struct is_unsigned<unsigned short _Fract> : bool_constant<true> {
LIBC_INLINE constexpr operator bool() const { return is_unsigned::value; }
LIBC_INLINE constexpr bool operator()() const { return is_unsigned::value; }
};
template <> struct is_unsigned<unsigned _Fract> : bool_constant<true> {
LIBC_INLINE constexpr operator bool() const { return is_unsigned::value; }
LIBC_INLINE constexpr bool operator()() const { return is_unsigned::value; }
};
template <> struct is_unsigned<unsigned long _Fract> : bool_constant<true> {
LIBC_INLINE constexpr operator bool() const { return is_unsigned::value; }
LIBC_INLINE constexpr bool operator()() const { return is_unsigned::value; }
};
template <> struct is_unsigned<unsigned short accum> : bool_constant<true> {
LIBC_INLINE constexpr operator bool() const { return is_unsigned::value; }
LIBC_INLINE constexpr bool operator()() const { return is_unsigned::value; }
};
template <> struct is_unsigned<unsigned accum> : bool_constant<true> {
LIBC_INLINE constexpr operator bool() const { return is_unsigned::value; }
LIBC_INLINE constexpr bool operator()() const { return is_unsigned::value; }
};
template <> struct is_unsigned<unsigned long accum> : bool_constant<true> {
LIBC_INLINE constexpr operator bool() const { return is_unsigned::value; }
LIBC_INLINE constexpr bool operator()() const { return is_unsigned::value; }
};
template <>
struct is_unsigned<unsigned short sat _Fract> : bool_constant<true> {
LIBC_INLINE constexpr operator bool() const { return is_unsigned::value; }
LIBC_INLINE constexpr bool operator()() const { return is_unsigned::value; }
};
template <> struct is_unsigned<unsigned sat _Fract> : bool_constant<true> {
LIBC_INLINE constexpr operator bool() const { return is_unsigned::value; }
LIBC_INLINE constexpr bool operator()() const { return is_unsigned::value; }
};
template <> struct is_unsigned<unsigned long sat _Fract> : bool_constant<true> {
LIBC_INLINE constexpr operator bool() const { return is_unsigned::value; }
LIBC_INLINE constexpr bool operator()() const { return is_unsigned::value; }
};
template <> struct is_unsigned<unsigned short sat accum> : bool_constant<true> {
LIBC_INLINE constexpr operator bool() const { return is_unsigned::value; }
LIBC_INLINE constexpr bool operator()() const { return is_unsigned::value; }
};
template <> struct is_unsigned<unsigned sat accum> : bool_constant<true> {
LIBC_INLINE constexpr operator bool() const { return is_unsigned::value; }
LIBC_INLINE constexpr bool operator()() const { return is_unsigned::value; }
};
template <> struct is_unsigned<unsigned long sat accum> : bool_constant<true> {
LIBC_INLINE constexpr operator bool() const { return is_unsigned::value; }
LIBC_INLINE constexpr bool operator()() const { return is_unsigned::value; }
};
#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