Skip to content

Commit 6bed0a0

Browse files
authored
Merge pull request #32 from finger563/master
Support for std::bitset
2 parents 93f4b77 + e0bbff7 commit 6bed0a0

File tree

5 files changed

+176
-1
lines changed

5 files changed

+176
-1
lines changed

include/alpaca/alpaca.h

+16
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <alpaca/detail/to_bytes.h>
1111
#include <alpaca/detail/type_info.h>
1212
#include <alpaca/detail/types/array.h>
13+
#include <alpaca/detail/types/bitset.h>
1314
#include <alpaca/detail/types/deque.h>
1415
#include <alpaca/detail/types/duration.h>
1516
#include <alpaca/detail/types/filesystem_path.h>
@@ -142,6 +143,21 @@ void serialize_helper(const T &s, Container &bytes, std::size_t &byte_index) {
142143
}
143144
}
144145

146+
#ifndef ALPACA_EXCLUDE_SUPPORT_STD_BITSET
147+
// version for bitset
148+
template <options O, typename T, typename U>
149+
typename std::enable_if<is_bitset<U>::value, void>::type
150+
to_bytes(T &bytes, std::size_t &byte_index, const U &input) {
151+
detail::to_bytes_router(input, bytes, byte_index);
152+
}
153+
154+
template <options O, std::size_t N, typename Container>
155+
void to_bytes_router(const std::bitset<N> &input, Container &bytes,
156+
std::size_t &byte_index) {
157+
to_bytes<O>(bytes, byte_index, input);
158+
}
159+
#endif
160+
145161
} // namespace detail
146162

147163
template <typename T,

include/alpaca/detail/field_type.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ enum class field_type : uint8_t {
3535
chrono_duration,
3636
list,
3737
deque,
38-
filesystem_path
38+
filesystem_path,
39+
bitset
3940
};
4041

4142
template <field_type value> constexpr uint8_t to_byte() {

include/alpaca/detail/is_bitset.h

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#pragma once
2+
#ifndef ALPACA_EXCLUDE_SUPPORT_STD_BITSET
3+
#include <bitset>
4+
#include <type_traits>
5+
6+
namespace alpaca {
7+
8+
namespace detail {
9+
10+
// check if T is instantiation of Bitset
11+
template <typename T>
12+
struct is_bitset : std::false_type {};
13+
14+
template <std::size_t N>
15+
struct is_bitset<std::bitset<N>> : std::true_type {};
16+
17+
} // namespace detail
18+
19+
} // namespace alpaca
20+
21+
#endif // ALPACA_EXCLUDE_SUPPORT_STD_BITSET

include/alpaca/detail/type_info.h

+14
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
#pragma once
22
#include <alpaca/detail/field_type.h>
3+
#include <alpaca/detail/is_bitset.h>
34
#include <alpaca/detail/is_specialization.h>
45

56
#ifndef ALPACA_EXCLUDE_SUPPORT_STD_ARRAY
67
#include <array>
78
#endif
89

10+
#ifndef ALPACA_EXCLUDE_SUPPORT_STD_BITSET
11+
#include <bitset>
12+
#endif
13+
914
#ifndef ALPACA_EXCLUDE_SUPPORT_STD_FILESYSTEM_PATH
1015
#include <filesystem>
1116
#endif
@@ -173,6 +178,15 @@ typename std::enable_if<is_array_type<T>::value, void>::type type_info(
173178
std::unordered_map<std::string_view, std::size_t> &struct_visitor_map);
174179
#endif
175180

181+
#ifndef ALPACA_EXCLUDE_SUPPORT_STD_BITSET
182+
// std::bitset type
183+
template <typename T>
184+
typename std::enable_if<is_bitset<T>::value, void>::type
185+
type_info(
186+
std::vector<uint8_t> &typeids,
187+
std::unordered_map<std::string_view, std::size_t> &struct_visitor_map);
188+
#endif
189+
176190
#ifndef ALPACA_EXCLUDE_SUPPORT_STD_FILESYSTEM_PATH
177191
// filesystem::path
178192
template <typename T>

include/alpaca/detail/types/bitset.h

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
#pragma once
2+
#ifndef ALPACA_EXCLUDE_SUPPORT_STD_BITSET
3+
#include <alpaca/detail/to_bytes.h>
4+
#include <alpaca/detail/type_info.h>
5+
#include <system_error>
6+
#include <vector>
7+
8+
namespace alpaca {
9+
10+
namespace detail {
11+
12+
template <typename T>
13+
typename std::enable_if<is_bitset<T>::value, void>::type
14+
type_info(
15+
std::vector<uint8_t> &typeids,
16+
std::unordered_map<std::string_view, std::size_t> &struct_visitor_map) {
17+
typeids.push_back(to_byte<field_type::bitset>());
18+
using value_type = typename T::value_type;
19+
type_info<value_type>(typeids, struct_visitor_map);
20+
}
21+
22+
template <options O, std::size_t N, typename Container>
23+
void to_bytes_router(const std::bitset<N> &input, Container &bytes, std::size_t &byte_index);
24+
25+
template <options O, std::size_t N, typename Container>
26+
void to_bytes_from_bitset_type(const std::bitset<N> &input, Container &bytes,
27+
std::size_t &byte_index) {
28+
// save bitset size
29+
to_bytes_router<O, std::size_t>(input.size(), bytes, byte_index);
30+
31+
// serialize the bitset itself into (bits/8 + 1) bytes
32+
int num_bytes = input.size() / 8 + 1;
33+
for (int i=0; i < num_bytes; ++i) {
34+
uint8_t byte = 0;
35+
for (int bit = 0; bit < 8; ++bit) {
36+
int bit_index = i * 8 + bit;
37+
if (bit_index > input.size()) break;
38+
if (input[bit_index]) byte |= (1 << bit);
39+
}
40+
to_bytes<O>(bytes, byte_index, byte);
41+
}
42+
}
43+
44+
template <options O, typename Container, std::size_t N>
45+
void to_bytes(Container &bytes, std::size_t &byte_index,
46+
const std::bitset<N> &input) {
47+
to_bytes_from_bitset_type<O>(input, bytes, byte_index);
48+
}
49+
50+
template <options O, typename T, typename Container>
51+
void from_bytes_router(T &output, Container &bytes, std::size_t &byte_index,
52+
std::size_t &end_index, std::error_code &error_code);
53+
54+
template <options O, std::size_t N, typename Container>
55+
bool from_bytes_to_bitset(std::bitset<N> &value, Container &bytes,
56+
std::size_t &current_index, std::size_t &end_index,
57+
std::error_code &error_code) {
58+
59+
if (current_index >= end_index) {
60+
// end of input
61+
// return true for forward compatibility
62+
return true;
63+
}
64+
65+
// current byte is the size of the vector
66+
std::size_t size = 0;
67+
detail::from_bytes<O, std::size_t>(size, bytes, current_index, end_index,
68+
error_code);
69+
70+
if (size != N) {
71+
// the bitset we received is not the same size as the bitset we were given
72+
error_code = std::make_error_code(std::errc::invalid_argument);
73+
74+
// stop here
75+
return false;
76+
}
77+
78+
// we encode the number of bits as the size, but when we actually serialize
79+
// them we pack them, so we need to only deserialize (size/8 + 1) bytes.
80+
std::size_t num_serialized_bytes = size / 8 + 1;
81+
82+
if (num_serialized_bytes > end_index - current_index) {
83+
// size is greater than the number of bytes remaining
84+
error_code = std::make_error_code(std::errc::value_too_large);
85+
86+
// stop here
87+
return false;
88+
}
89+
90+
// reset the value to 0
91+
value.reset();
92+
93+
for (std::size_t i = 0; i < num_serialized_bytes; ++i) {
94+
uint8_t byte{};
95+
from_bytes_router<O>(byte, bytes, current_index, end_index, error_code);
96+
if (error_code) {
97+
// something went wrong
98+
return false;
99+
}
100+
// loop over the bits
101+
for (int j=0; j<8; ++j) {
102+
int bit_index = i * 8 + j;
103+
if (bit_index > size) break;
104+
bool bit = static_cast<bool>(byte & (1 << j));
105+
value[bit_index] = bit;
106+
}
107+
}
108+
109+
return true;
110+
}
111+
112+
template <options O, std::size_t N, typename Container>
113+
bool from_bytes(std::bitset<N> &output, Container &bytes,
114+
std::size_t &byte_index, std::size_t &end_index,
115+
std::error_code &error_code) {
116+
return from_bytes_to_bitset<O>(output, bytes, byte_index, end_index,
117+
error_code);
118+
}
119+
120+
} // namespace detail
121+
122+
} // namespace alpaca
123+
#endif

0 commit comments

Comments
 (0)