Skip to content

Commit ba96203

Browse files
authored
Merge pull request #642 from OpenVicProject/add/error-set
Add ErrorSet for returning all reported errors
2 parents f7377b3 + 980fac8 commit ba96203

File tree

2 files changed

+261
-0
lines changed

2 files changed

+261
-0
lines changed
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
#pragma once
2+
3+
#include <bitset>
4+
#include <cstddef>
5+
6+
#include "openvic-simulation/utility/Containers.hpp"
7+
#include "openvic-simulation/utility/Error.hpp"
8+
9+
namespace OpenVic {
10+
// Set of all reported errors, if empty operates as if set to Error::OK
11+
struct ErrorSet : private std::bitset<static_cast<std::size_t>(Error::MAX) - 1> {
12+
ErrorSet() = default;
13+
ErrorSet(ErrorSet const&) = default;
14+
ErrorSet(ErrorSet&&) = default;
15+
ErrorSet& operator=(ErrorSet const&) = default;
16+
ErrorSet& operator=(ErrorSet&&) = default;
17+
18+
ErrorSet(Error error) {
19+
if (error != Error::OK) {
20+
set(static_cast<std::size_t>(error) - 1, true);
21+
}
22+
}
23+
24+
ErrorSet& operator=(Error error) {
25+
reset();
26+
if (error != Error::OK) {
27+
set(static_cast<std::size_t>(error) - 1, true);
28+
}
29+
return *this;
30+
}
31+
32+
using bitset::all;
33+
using bitset::any;
34+
using bitset::count;
35+
using bitset::none;
36+
using bitset::size;
37+
38+
bool operator[](Error error) const {
39+
if (error == Error::OK) {
40+
return none();
41+
}
42+
43+
return bitset::operator[](static_cast<std::size_t>(error) - 1);
44+
}
45+
46+
bool operator[](ErrorSet const& errors) const {
47+
if (errors.none()) {
48+
return none();
49+
}
50+
51+
return (*this & errors) == errors;
52+
}
53+
54+
bool operator==(ErrorSet const& rhs) const {
55+
return bitset::operator==(rhs);
56+
}
57+
58+
bool operator==(Error rhs) const {
59+
return operator[](rhs);
60+
}
61+
62+
bool test(Error error) const {
63+
return operator[](error);
64+
}
65+
66+
bool test(ErrorSet const& errors) const {
67+
return operator[](errors);
68+
}
69+
70+
ErrorSet& operator|=(ErrorSet const& rhs) {
71+
bitset::operator|=(rhs);
72+
return *this;
73+
}
74+
75+
ErrorSet operator|=(Error rhs) {
76+
if (rhs != Error::OK) {
77+
set(static_cast<std::size_t>(rhs) - 1, true);
78+
}
79+
return *this;
80+
}
81+
82+
friend inline ErrorSet operator|(ErrorSet const& lhs, ErrorSet const& rhs) {
83+
ErrorSet result { lhs };
84+
result |= rhs;
85+
return result;
86+
}
87+
88+
friend inline ErrorSet operator|(ErrorSet const& lhs, Error rhs) {
89+
ErrorSet result { lhs };
90+
result |= rhs;
91+
return result;
92+
}
93+
94+
friend inline ErrorSet operator|(Error lhs, ErrorSet const& rhs) {
95+
ErrorSet result { rhs };
96+
result |= lhs;
97+
return result;
98+
}
99+
100+
memory::string to_bitset_string(memory::string::value_type zero = '0', memory::string::value_type one = '1') const {
101+
return bitset::to_string<memory::string::value_type, memory::string::traits_type, memory::string::allocator_type>(
102+
zero, one
103+
);
104+
}
105+
106+
memory::string to_string() const {
107+
memory::string result;
108+
if (none()) {
109+
result.append(as_string(Error::OK));
110+
return result;
111+
}
112+
113+
{
114+
std::size_t str_size = 0;
115+
for (std::size_t i = 1; i <= size(); i++) {
116+
if (!(*this).bitset::operator[](i - 1)) {
117+
continue;
118+
}
119+
120+
if (str_size > 0) {
121+
str_size += 2; // for ", "
122+
}
123+
124+
str_size += as_string(static_cast<Error>(i)).size();
125+
}
126+
127+
result.reserve(str_size);
128+
}
129+
130+
for (std::size_t i = 1; i <= size(); i++) {
131+
if (!(*this).bitset::operator[](i - 1)) {
132+
continue;
133+
}
134+
135+
if (result.size() > 0) {
136+
result.append(", ");
137+
}
138+
139+
result.append(as_string(static_cast<Error>(i)));
140+
}
141+
return result;
142+
}
143+
144+
private:
145+
using bitset::bitset;
146+
};
147+
}

tests/src/utility/ErrorSet.cpp

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
#include "openvic-simulation/utility/ErrorSet.hpp"
2+
3+
#include <string_view>
4+
5+
#include "openvic-simulation/utility/Error.hpp"
6+
7+
#include <snitch/snitch_macros_check.hpp>
8+
#include <snitch/snitch_macros_test_case.hpp>
9+
10+
using namespace OpenVic;
11+
12+
TEST_CASE("ErrorSet Constructor methods", "[ErrorSet][ErrorSet-constructor]") {
13+
CHECK(ErrorSet {}.none());
14+
CHECK(ErrorSet { Error::OK }.none());
15+
CHECK(ErrorSet { Error::FAILED }.any());
16+
17+
ErrorSet set_1;
18+
ErrorSet set_2 = Error::OK;
19+
ErrorSet set_3 = Error::BUG;
20+
21+
CHECK(set_1.none());
22+
CHECK(set_2.none());
23+
CHECK(set_3.any());
24+
CHECK(set_3[Error::BUG]);
25+
CHECK_FALSE(set_3[Error::FAILED]);
26+
27+
ErrorSet set_4 = set_3;
28+
29+
CHECK(set_4.any());
30+
CHECK(set_4[Error::BUG]);
31+
CHECK_FALSE(set_4[Error::FAILED]);
32+
33+
ErrorSet set_5 = std::move(set_4);
34+
35+
CHECK(set_5.any());
36+
CHECK(set_5[Error::BUG]);
37+
CHECK_FALSE(set_5[Error::FAILED]);
38+
}
39+
40+
TEST_CASE("ErrorSet Operators", "[ErrorSet][ErrorSet-operators]") {
41+
ErrorSet set_ok = Error::OK;
42+
ErrorSet set_bug = Error::BUG;
43+
ErrorSet set_multiple = Error::BUG;
44+
set_multiple |= Error::FAILED;
45+
46+
CHECK(set_ok[Error::OK]);
47+
CHECK_FALSE(set_ok[Error::BUG]);
48+
CHECK_FALSE(set_ok[Error::FAILED]);
49+
CHECK_FALSE(set_ok[Error::ALREADY_EXISTS]);
50+
CHECK(set_ok == Error::OK);
51+
CHECK_FALSE(set_ok == Error::BUG);
52+
CHECK_FALSE(set_ok == Error::FAILED);
53+
CHECK_FALSE(set_ok == Error::ALREADY_EXISTS);
54+
CHECK_FALSE(set_ok == set_bug);
55+
CHECK_FALSE(set_ok == set_multiple);
56+
CHECK_FALSE(set_ok[set_bug]);
57+
CHECK_FALSE(set_ok[set_multiple]);
58+
59+
CHECK_FALSE(set_bug[Error::OK]);
60+
CHECK(set_bug[Error::BUG]);
61+
CHECK_FALSE(set_bug[Error::FAILED]);
62+
CHECK_FALSE(set_bug[Error::ALREADY_EXISTS]);
63+
CHECK_FALSE(set_bug == Error::OK);
64+
CHECK(set_bug == Error::BUG);
65+
CHECK_FALSE(set_bug == Error::FAILED);
66+
CHECK_FALSE(set_bug == Error::ALREADY_EXISTS);
67+
CHECK_FALSE(set_bug == set_ok);
68+
CHECK_FALSE(set_bug == set_multiple);
69+
CHECK_FALSE(set_bug[set_ok]);
70+
CHECK_FALSE(set_bug[set_multiple]);
71+
72+
CHECK_FALSE(set_multiple[Error::OK]);
73+
CHECK(set_multiple[Error::BUG]);
74+
CHECK(set_multiple[Error::FAILED]);
75+
CHECK_FALSE(set_multiple[Error::ALREADY_EXISTS]);
76+
CHECK_FALSE(set_multiple == Error::OK);
77+
CHECK(set_multiple == Error::BUG);
78+
CHECK(set_multiple == Error::FAILED);
79+
CHECK_FALSE(set_multiple == Error::ALREADY_EXISTS);
80+
CHECK_FALSE(set_multiple == set_bug);
81+
CHECK_FALSE(set_multiple == set_ok);
82+
CHECK(set_multiple[set_bug]);
83+
CHECK_FALSE(set_multiple[set_ok]);
84+
85+
CHECK((set_multiple | Error::ALREADY_EXISTS)[Error::ALREADY_EXISTS]);
86+
CHECK_FALSE((set_multiple | Error::ALREADY_EXISTS)[Error::CONNECTION_ERROR]);
87+
88+
set_multiple |= Error::CONNECTION_ERROR;
89+
CHECK(set_multiple[Error::BUG]);
90+
CHECK(set_multiple[Error::FAILED]);
91+
CHECK(set_multiple[Error::CONNECTION_ERROR]);
92+
93+
set_multiple |= Error::OK;
94+
CHECK(set_multiple[Error::BUG]);
95+
CHECK(set_multiple[Error::FAILED]);
96+
CHECK(set_multiple[Error::CONNECTION_ERROR]);
97+
}
98+
99+
TEST_CASE("ErrorSet to_string", "[ErrorSet][ErrorSet-to_string]") {
100+
using namespace std::string_view_literals;
101+
102+
ErrorSet set_ok = Error::OK;
103+
ErrorSet set_bug = Error::BUG;
104+
ErrorSet set_multiple = Error::BUG;
105+
set_multiple |= Error::FAILED;
106+
107+
CHECK(set_ok.to_string() == "OK"sv);
108+
CHECK(set_bug.to_string() == "Bug"sv);
109+
CHECK(set_multiple.to_string() == "Failed, Bug"sv);
110+
111+
CHECK(set_ok.to_bitset_string() == "00000000000000000000000"sv);
112+
CHECK(set_bug.to_bitset_string() == "10000000000000000000000"sv);
113+
CHECK(set_multiple.to_bitset_string() == "10000000000000000000001"sv);
114+
}

0 commit comments

Comments
 (0)