Skip to content

Commit effcb7c

Browse files
committed
more tests + bug fixes
1 parent 4dec3f8 commit effcb7c

26 files changed

+369
-79
lines changed

include/flags/flags.hpp

Lines changed: 30 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,17 @@ template <class E> struct flags {
9797

9898
constexpr bool operator!() const noexcept { return !val_; }
9999

100-
flags operator~() const noexcept { return flags(~val_); }
100+
friend constexpr bool operator==(flags fl1, flags fl2) {
101+
return fl1.val_ == fl2.val_;
102+
}
103+
104+
friend constexpr bool operator!=(flags fl1, flags fl2) {
105+
return fl1.val_ != fl2.val_;
106+
}
101107

102108

109+
constexpr flags operator~() const noexcept { return flags(~val_); }
110+
103111
flags &operator|=(const flags &fl) noexcept {
104112
val_ |= fl.val_;
105113
return *this;
@@ -131,6 +139,18 @@ template <class E> struct flags {
131139
return *this;
132140
}
133141

142+
friend constexpr flags operator|(flags f1, flags f2) noexcept {
143+
return flags{f1.val_ | f2.val_};
144+
}
145+
146+
friend constexpr flags operator&(flags f1, flags f2) noexcept {
147+
return flags{f1.val_ & f2.val_};
148+
}
149+
150+
friend constexpr flags operator^(flags f1, flags f2) noexcept {
151+
return flags{f1.val_ ^ f2.val_};
152+
}
153+
134154

135155
void swap(flags &fl) noexcept { std::swap(val_, fl.val_); }
136156

@@ -153,7 +173,7 @@ template <class E> struct flags {
153173
}
154174

155175

156-
bool empty() const noexcept { return !val_; }
176+
constexpr bool empty() const noexcept { return !val_; }
157177

158178
size_type size() const noexcept {
159179
return std::distance(this->begin(), this->end());
@@ -165,13 +185,13 @@ template <class E> struct flags {
165185
iterator begin() const noexcept { return cbegin(); }
166186
iterator cbegin() const noexcept { return iterator{val_}; }
167187

168-
iterator end() const noexcept { return cend(); }
169-
iterator cend() const noexcept { return {}; }
188+
constexpr iterator end() const noexcept { return cend(); }
189+
constexpr iterator cend() const noexcept { return {}; }
170190

171191

172-
iterator find(enum_type e) const noexcept { return {val_, e}; }
192+
constexpr iterator find(enum_type e) const noexcept { return {val_, e}; }
173193

174-
size_type count(enum_type e) const noexcept {
194+
constexpr size_type count(enum_type e) const noexcept {
175195
return find(e) != end() ? 1 : 0;
176196
}
177197

@@ -256,67 +276,7 @@ template <class E> struct flags {
256276

257277

258278
template <class E>
259-
constexpr flags<E> operator|(flags<E> f1, flags<E> f2) noexcept {
260-
return f1 |= f2;
261-
}
262-
263-
template <class E>
264-
constexpr flags<E> operator|(flags<E> f, E e) noexcept {
265-
return f |= e;
266-
}
267-
268-
template <class E>
269-
constexpr flags<E> operator|(E e, flags<E> f) noexcept {
270-
return f |= e;
271-
}
272-
273-
274-
template <class E>
275-
constexpr flags<E> operator&(flags<E> f1, flags<E> f2) noexcept {
276-
return f1 &= f2;
277-
}
278-
279-
template <class E>
280-
constexpr flags<E> operator&(flags<E> f, E e) noexcept {
281-
return f &= e;
282-
}
283-
284-
template <class E>
285-
constexpr flags<E> operator&(E e, flags<E> f) noexcept {;
286-
return f &= e;
287-
}
288-
289-
290-
template <class E>
291-
constexpr flags<E> operator^(flags<E> f1, flags<E> f2) noexcept {
292-
return f1 ^= f2;
293-
}
294-
295-
template <class E>
296-
constexpr flags<E> operator^(flags<E> f, E e) noexcept {
297-
return f ^= e;
298-
}
299-
300-
template <class E>
301-
constexpr flags<E> operator^(E e, flags<E> f) noexcept {
302-
return f ^= e;
303-
}
304-
305-
306-
template <class E>
307-
constexpr bool operator==(const flags<E> &fl1, const flags<E> &fl2) noexcept {
308-
return fl1.underlying_value() == fl2.underlying_value();
309-
}
310-
311-
312-
template <class E>
313-
constexpr bool operator!=(const flags<E> &fl1, const flags<E> &fl2) noexcept {
314-
return fl1.underlying_value() != fl2.underlying_value();
315-
}
316-
317-
318-
template <class E>
319-
constexpr void swap(flags<E> &fl1, flags<E> &fl2) noexcept { fl1.swap(fl2); }
279+
void swap(flags<E> &fl1, flags<E> &fl2) noexcept { fl1.swap(fl2); }
320280

321281

322282
} // namespace flags
@@ -326,23 +286,23 @@ template <class E>
326286
constexpr auto operator|(E e1, E e2) noexcept
327287
-> typename std::enable_if<flags::is_flags<E>::value,
328288
flags::flags<E>>::type {
329-
return flags::flags<E>{e1} |= e2;
289+
return flags::flags<E>(e1) | e2;
330290
}
331291

332292

333293
template <class E>
334294
constexpr auto operator&(E e1, E e2) noexcept
335295
-> typename std::enable_if<flags::is_flags<E>::value,
336296
flags::flags<E>>::type {
337-
return flags::flags<E>{e1} &= e2;
297+
return flags::flags<E>(e1) & e2;
338298
}
339299

340300

341301
template <class E>
342302
constexpr auto operator^(E e1, E e2) noexcept
343303
-> typename std::enable_if<flags::is_flags<E>::value,
344304
flags::flags<E>>::type {
345-
return flags::flags<E>{e1} ^= e2;
305+
return flags::flags<E>(e1) ^ e2;
346306
}
347307

348308

include/flags/iterator.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class FlagsIterator {
6060
using impl_type = typename flags_type::impl_type;
6161

6262

63-
explicit FlagsIterator(impl_type uv) noexcept : mask_(1), uvalue_(uv) {
63+
explicit FlagsIterator(impl_type uv) noexcept : uvalue_(uv), mask_(1) {
6464
if (!(mask_ & uvalue_)) { nextMask(); }
6565
}
6666

test/Jamroot

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import testing ;
22

3+
34
project flags_tests
45
: requirements <warnings>all
56
<cxxflags>-std=c++11
@@ -18,4 +19,12 @@ unit-test main-test
1819
: main-test.cpp boost_utf
1920
: <define>BOOST_TEST_DYN_LINK
2021
<define>BOOST_TEST_MODULE=enum_flags
21-
;
22+
;
23+
24+
25+
compile should-compile.cpp ;
26+
27+
28+
for src in [ glob shouldnt-compile/*.cpp ] {
29+
compile-fail $(src) ;
30+
}

test/common.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#ifndef ENUM_CLASS_TEST_COMMON_HPP
2+
#define ENUM_CLASS_TEST_COMMON_HPP
3+
4+
5+
#include <flags/flags.hpp>
6+
7+
8+
enum class Enum : int {One = 1, Two = 2, Four = 4, Eight = 8};
9+
ALLOW_FLAGS_FOR_ENUM(Enum)
10+
11+
using Enums = flags::flags<Enum>;
12+
13+
14+
#endif // ENUM_CLASS_TEST_COMMON_HPP

test/main-test.cpp

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
1-
#include <flags/flags.hpp>
1+
#include "common.hpp"
22

33
#include <vector>
44

55
#include <boost/test/unit_test.hpp>
66

77

8-
enum class Enum : int {One = 1, Two = 2, Four = 4, Eight = 8};
9-
ALLOW_FLAGS_FOR_ENUM(Enum)
10-
11-
using Enums = flags::flags<Enum>;
12-
13-
148
BOOST_AUTO_TEST_CASE(set_underlying_value) {
159
Enums result;
1610
constexpr int random_number = 87;

test/should-compile.cpp

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
#include "common.hpp"
2+
3+
4+
// type traits
5+
static_assert(std::is_pod<Enums>::value,
6+
"Enums is not POD!");
7+
static_assert(std::is_literal_type<Enums>::value,
8+
"Enums is not a literal type!");
9+
10+
11+
// associated types
12+
13+
// general
14+
static_assert(std::is_same<Enums::enum_type, Enum>::value,
15+
"Enums::enum_type is not Enum!");
16+
static_assert(std::is_same<std::underlying_type<Enum>::type,
17+
Enums::underlying_type>::value,
18+
"Enums::underlying_type is different from "
19+
"underlying type of Enum!");
20+
static_assert(std::is_same<std::make_unsigned<Enums::underlying_type>::type,
21+
Enums::impl_type>::value,
22+
"Enums::impl_type is not unsigned version of "
23+
"Enums::underlying_type!");
24+
25+
// iterator
26+
using Iterator = Enums::iterator;
27+
28+
static_assert(std::is_literal_type<Iterator>::value,
29+
"Enums::iterator is not a literal type!");
30+
static_assert(std::is_same<Enums::const_iterator, Iterator>::value,
31+
"Enums::const_iterator and Enums::iterator are different types!");
32+
static_assert(std::is_same<Iterator::flags_type, Enums>::value,
33+
"Enums::iterator::flags_type is not Enums!");
34+
static_assert(std::is_same<Iterator::iterator_category,
35+
std::forward_iterator_tag>::value,
36+
"Enums::iterator category is not forward iterator!");
37+
static_assert(std::is_same<Iterator::value_type, Enum>::value,
38+
"Enums::iterator::value_type is not Enum!");
39+
static_assert(std::is_same<Iterator::reference, const Enum>::value,
40+
"Enums::iterator::reference is not const Enum!");
41+
// (const) forward iterator requirements
42+
static_assert(std::is_copy_constructible<Iterator>::value
43+
&& std::is_copy_assignable<Iterator>::value
44+
&& std::is_destructible<Iterator>::value
45+
// && std::is_same<decltype(*std::declval<Iterator &>()),
46+
// Iterator::reference>::value
47+
&& std::is_same<decltype(++std::declval<Iterator &>()),
48+
Iterator &>::value,
49+
"Enums::iterator does not model Iterator!");
50+
static_assert(std::is_convertible<
51+
decltype(std::declval<Iterator>() == std::declval<Iterator>()),
52+
bool>::value,
53+
"Enums::iterator does not model EqualityComparable!");
54+
static_assert(std::is_convertible<
55+
decltype(std::declval<Iterator>() != std::declval<Iterator>()),
56+
bool>::value
57+
&& std::is_convertible<decltype(*std::declval<Iterator &>()),
58+
Iterator::value_type>::value
59+
&& std::is_convertible<decltype(*std::declval<Iterator &>()++),
60+
Iterator::value_type>::value,
61+
"Enums::iterator does not model InputIterator!");
62+
static_assert(std::is_default_constructible<Iterator>::value
63+
&& std::is_convertible<decltype(++std::declval<Iterator &>()),
64+
Iterator>::value
65+
&& std::is_convertible<decltype(std::declval<Iterator &>()++),
66+
Iterator>::value,
67+
"Enums::iterator does not model ForwardIterator!");
68+
69+
// container
70+
static_assert(std::is_same<Enums::iterator::value_type,
71+
Enums::value_type>::value,
72+
"Enums::value_type is not Enums::iterator::value_type!");
73+
74+
static_assert(std::is_same<Enums::iterator::reference, Enums::reference>::value,
75+
"Enums::reference is not Enums::iterator::reference!");
76+
static_assert(std::is_same<Enums::const_reference, Enums::reference>::value,
77+
"Enums::const_reference is not Enums::reference!");
78+
79+
static_assert(std::is_same<Enums::iterator::pointer, Enums::pointer>::value,
80+
"Enums::pointer is not Enums::iterator::pointer!");
81+
static_assert(std::is_same<Enums::enum_type *, Enums::pointer>::value,
82+
"Enums::pointer is not Enum *!");
83+
static_assert(std::is_same<const Enums::enum_type *,
84+
Enums::const_pointer>::value,
85+
"Enums::const_pointer is not const Enum *!");
86+
87+
static_assert(std::is_arithmetic<Enums::size_type>::value,
88+
"Enums::size_type is not arithmetic!");
89+
90+
static_assert(std::is_same<Enums::iterator::difference_type,
91+
Enums::difference_type>::value,
92+
"Enums::difference_type is not Enums::iterator::difference_type!"
93+
);
94+
static_assert(std::is_signed<Enums::difference_type>::value,
95+
"Enums::difference_type is not signed!");
96+
97+
98+
// constexpr construction
99+
constexpr Enums ec1(flags::empty);
100+
constexpr Enums ec2{flags::empty};
101+
constexpr Enums vc1(Enum::One);
102+
constexpr auto vc2 = Enums(Enum::One);
103+
104+
105+
// constexpr logical operators
106+
constexpr bool l1 = static_cast<bool>(ec1);
107+
constexpr bool l2 = !ec1;
108+
constexpr bool l3 = ec1 == ec2;
109+
constexpr bool l4 = ec1 != ec2;
110+
111+
112+
// constexpr bitwise operators
113+
constexpr auto b1 = ~ec1;
114+
115+
constexpr auto b2 = ec1 | ec2;
116+
constexpr auto b3 = ec1 | Enum::One;
117+
constexpr auto b4 = Enum::One | ec1;
118+
constexpr auto b5 = Enum::One | Enum::Two;
119+
120+
constexpr auto b6 = ec1 & ec2;
121+
constexpr auto b7 = ec1 & Enum::One;
122+
constexpr auto b8 = Enum::One & ec1;
123+
constexpr auto b9 = Enum::One & Enum::Two;
124+
125+
constexpr auto b10 = ec1 ^ ec2;
126+
constexpr auto b11 = ec1 & Enum::One;
127+
constexpr auto b12 = Enum::One ^ ec1;
128+
constexpr auto b13 = Enum::One ^ Enum::Two;
129+
130+
131+
// constexpr conversions
132+
constexpr auto cv1 = ec1.underlying_value();
133+
static_assert(std::is_same<decltype(ec1.underlying_value()),
134+
Enums::underlying_type>::value,
135+
"Enums::underlying_value() did not return an object of type "
136+
"Enums::underlying_type!");
137+
constexpr auto cv2 = ec1.to_bitset();
138+
constexpr auto cv3 = static_cast<std::bitset<Enums::bit_size()>>(ec1);
139+
static_assert(std::is_same<decltype(cv2), decltype(cv3)>::value,
140+
"Bitset conversion functions return different types!");
141+
142+
143+
// constexpr container functions
144+
constexpr bool cf1 = ec1.empty();
145+
constexpr Enums::size_type cf2 = ec1.max_size();
146+
constexpr Enums::iterator cf3 = ec1.find(Enum::One);
147+
constexpr Enums::size_type cf4 = ec1.count(Enum::One);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include "common.hpp"
2+
3+
4+
enum class AnotherEnum { One = 1, Two = 2 };
5+
6+
7+
void check() {
8+
auto aes = AnotherEnum::One | AnotherEnum::Two;
9+
}

0 commit comments

Comments
 (0)