Skip to content

Commit 97e7def

Browse files
committed
[Add] Flags support
1 parent 83c4c86 commit 97e7def

2 files changed

Lines changed: 175 additions & 0 deletions

File tree

Include/SA/Support/Flags.hpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// Copyright (c) 2024 Sapphire's Suite. All Rights Reserved.
2+
3+
#pragma once
4+
5+
#ifndef SAPPHIRE_SUPPORT_FLAGS_GUARD
6+
#define SAPPHIRE_SUPPORT_FLAGS_GUARD
7+
8+
#include <cstdint>
9+
10+
/**
11+
* \file Flags.hpp
12+
*
13+
* \brief \b Flags support file.
14+
*
15+
* Define preprocessor for enum class to flag support.
16+
*
17+
* \ingroup Support
18+
* \{
19+
*/
20+
21+
22+
namespace SA
23+
{
24+
/// \cond Internal
25+
26+
namespace Intl
27+
{
28+
template <uint32_t size>
29+
struct IntSizeT;
30+
31+
template <>
32+
struct IntSizeT<sizeof(int8_t)>
33+
{
34+
using intT = int8_t;
35+
using uintT = uint8_t;
36+
};
37+
38+
template <>
39+
struct IntSizeT<sizeof(int16_t)>
40+
{
41+
using intT = int16_t;
42+
using uintT = uint16_t;
43+
};
44+
45+
template <>
46+
struct IntSizeT<sizeof(int32_t)>
47+
{
48+
using intT = int32_t;
49+
using uintT = uint32_t;
50+
};
51+
52+
template <>
53+
struct IntSizeT<sizeof(int64_t)>
54+
{
55+
using intT = int64_t;
56+
using uintT = uint64_t;
57+
};
58+
59+
#define __SA_EINT(EnumType) SA::Intl::IntSizeT<sizeof(EnumType)>::intT
60+
#define __SA_EUINT(EnumType) SA::Intl::IntSizeT<sizeof(EnumType)>::uintT
61+
}
62+
63+
#define __SA_DEFINE_ENUM_CLASS_FLAGS_OP(EnumType, op)\
64+
inline constexpr __SA_EUINT(EnumType) operator op(EnumType _e1, EnumType _e2) {\
65+
return static_cast<__SA_EUINT(EnumType)>(_e1) op static_cast<__SA_EUINT(EnumType)>(_e2);\
66+
}\
67+
inline constexpr __SA_EUINT(EnumType) operator op(__SA_EUINT(EnumType) _flags, EnumType _e) {\
68+
return _flags op static_cast<__SA_EUINT(EnumType)>(_e);\
69+
}\
70+
inline constexpr __SA_EUINT(EnumType) operator op(EnumType _e, __SA_EUINT(EnumType) _flags) {\
71+
return static_cast<__SA_EUINT(EnumType)>(_e) op _flags;\
72+
}\
73+
inline __SA_EUINT(EnumType)& operator op##=(__SA_EUINT(EnumType)& _flags, EnumType _e) {\
74+
return _flags op##= static_cast<__SA_EUINT(EnumType)>(_e);\
75+
}
76+
77+
78+
/// \endcond
79+
80+
#define SA_DEFINE_ENUM_CLASS_FLAGS(EnumType)\
81+
__SA_DEFINE_ENUM_CLASS_FLAGS_OP(EnumType, &)\
82+
__SA_DEFINE_ENUM_CLASS_FLAGS_OP(EnumType, |)\
83+
__SA_DEFINE_ENUM_CLASS_FLAGS_OP(EnumType, ^)\
84+
inline constexpr __SA_EUINT(EnumType) operator ~(EnumType _e){\
85+
return ~static_cast<__SA_EUINT(EnumType)>(_e);\
86+
}\
87+
inline constexpr __SA_EUINT(EnumType) operator +(EnumType _e){\
88+
return static_cast<__SA_EUINT(EnumType)>(_e);\
89+
}
90+
}
91+
92+
93+
/** \} */
94+
95+
#endif // SAPPHIRE_SUPPORT_FLAGS_GUARD

Tests/UnitTests/Flags.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright (c) 2024 Sapphire development team. All Rights Reserved.
2+
3+
#include <gtest/gtest.h>
4+
5+
#include <SA/Support/Flags.hpp>
6+
7+
namespace SA::UT::Flags
8+
{
9+
enum class MyEnumFlag : uint8_t
10+
{
11+
MyFlag1 = (1 << 0),
12+
MyFlag2 = (1 << 1),
13+
MyFlag3 = (1 << 2),
14+
MyFlag4 = (1 << 3),
15+
MyFlag5 = (1 << 4),
16+
};
17+
18+
SA_DEFINE_ENUM_CLASS_FLAGS(MyEnumFlag);
19+
20+
21+
TEST(Flags, FlagsAND)
22+
{
23+
constexpr uint8_t flags1 = MyEnumFlag::MyFlag1 & MyEnumFlag::MyFlag2;
24+
EXPECT_EQ((flags1), 0u);
25+
26+
constexpr uint8_t flags2 = MyEnumFlag::MyFlag3 & 4u;
27+
EXPECT_EQ(flags2, 4u);
28+
29+
constexpr uint8_t flags3 = 4u & MyEnumFlag::MyFlag3;
30+
EXPECT_EQ(flags3, 4u);
31+
32+
uint8_t flags4 = 7u;
33+
flags4 &= MyEnumFlag::MyFlag1;
34+
EXPECT_EQ(flags4, 1u);
35+
}
36+
37+
TEST(Flags, FlagsOR)
38+
{
39+
constexpr uint8_t flags1 = MyEnumFlag::MyFlag1 | MyEnumFlag::MyFlag2;
40+
EXPECT_EQ((flags1), 3u);
41+
42+
constexpr uint8_t flags2 = MyEnumFlag::MyFlag3 | 3u;
43+
EXPECT_EQ(flags2, 7u);
44+
45+
constexpr uint8_t flags3 = 3u | MyEnumFlag::MyFlag3;
46+
EXPECT_EQ(flags3, 7u);
47+
48+
uint8_t flags4 = 6u;
49+
flags4 |= MyEnumFlag::MyFlag1;
50+
EXPECT_EQ(flags4, 7u);
51+
}
52+
53+
TEST(Flags, FlagsXOR)
54+
{
55+
constexpr uint8_t flags1 = MyEnumFlag::MyFlag1 ^ MyEnumFlag::MyFlag2;
56+
EXPECT_EQ((flags1), 3u);
57+
58+
constexpr uint8_t flags2 = MyEnumFlag::MyFlag3 ^ 4u;
59+
EXPECT_EQ(flags2, 0u);
60+
61+
constexpr uint8_t flags3 = 4u ^ MyEnumFlag::MyFlag3;
62+
EXPECT_EQ(flags3, 0u);
63+
64+
uint8_t flags4 = 6u;
65+
flags4 ^= MyEnumFlag::MyFlag2;
66+
EXPECT_EQ(flags4, 4u);
67+
}
68+
69+
TEST(Flags, FlagsInv)
70+
{
71+
constexpr uint8_t flags1 = ~MyEnumFlag::MyFlag2;
72+
EXPECT_EQ((flags1), 0xFD);
73+
}
74+
75+
TEST(Flags, FlagsCast)
76+
{
77+
constexpr uint8_t flags1 = +MyEnumFlag::MyFlag2;
78+
EXPECT_EQ((flags1), 2);
79+
}
80+
}

0 commit comments

Comments
 (0)