@@ -18,78 +18,129 @@ namespace bit {
1818template <typename Derived, typename T, typename W, typename It, typename CIt>
1919class bit_array_base ;
2020
21- template <std::integral size_type = uint32_t >
21+ template <std::signed_integral size_type = int >
2222class bounds {
2323 template <typename Derived, typename T, typename W, typename It, typename CIt>
2424 friend class bit_array_base ;
25- private:
26- size_type begin;
27- size_type end;
28- size_type step;
29-
30- public:
31- using None = std::tuple<>;
32- constexpr bounds () = delete;
33- constexpr bounds (const bounds& other) = default;
34- constexpr bounds (const bounds&& other)
35- : begin(other.begin), end(other.end), step(other.step) {
25+
26+ public:
27+ using None_t = std::tuple<>;
28+ static constexpr None_t None = None_t{};
29+
30+ private:
31+ using var_t = std::variant<None_t, size_type>;
32+ var_t begin;
33+ var_t end;
34+
35+ public:
36+ constexpr bounds () : begin(None), end(None) {
37+ }
38+ constexpr bounds (const bounds& other) = default;
39+ constexpr bounds (const bounds&& other)
40+ : begin(other.begin), end(other.end) {
41+ }
42+ constexpr bounds (const size_type pos)
43+ : begin(pos), end(None) {
44+ }
45+ constexpr bounds (const size_type begin, const size_type end)
46+ : begin(begin), end(end) {
47+ }
48+ constexpr bounds (std::initializer_list<var_t > components) {
49+ if (components.size () > 3 ) {
50+ throw std::invalid_argument (" Initializer list must have at most 2 elements" );
3651 }
37- constexpr bounds (const size_type& pos)
38- : begin(pos), end(pos + 1 ), step(1 ) {
52+ auto it = components.begin ();
53+ begin = None;
54+ end = None;
55+ if (components.size () >= 1 ) {
56+ begin = *it;
3957 }
40- constexpr bounds (const size_type& begin, const size_type& end, const size_type& step = 1 )
41- : begin(begin), end(end), step(step) {
58+ if (components.size () >= 2 ) {
59+ it++;
60+ end = *it;
4261 }
43- constexpr bounds (const None begin, const size_type& end, const size_type& step = 1 )
44- : begin(0 ), end(end), step(step) {
62+ if (std::holds_alternative<size_type>(begin)) {
63+ std::cout << " pos " << std::get<size_type>(begin) << " , " ;
64+ } else {
65+ std::cout << " None, " ;
4566 }
46- constexpr bounds (std::initializer_list<std::variant<None, size_type>> components) {
47- if (components.size () > 3 ) {
48- throw std::invalid_argument (" Initializer list must have at most 2 elements" );
49- }
50- auto it = components.begin ();
51- begin = 0 ;
52- end = 1 ;
53- step = 1 ;
54- if (components.size () >= 1 ) {
55- if (std::holds_alternative<size_type>(*it)) {
56- begin = std::get<size_type>(*it);
57- end = begin + 1 ;
58- } else {
59- std::cout << " None for [0]" << std::endl;
60- begin = 0 ;
61- end = 1 ;
62- }
63- }
64- if (components.size () >= 2 ) {
65- it++;
66- if (std::holds_alternative<size_type>(*it)) {
67- end = std::get<size_type>(*it);
68- }
69- }
70- if (components.size () >= 3 ) {
71- it++;
72- if (std::holds_alternative<size_type>(*it)) {
73- step = std::get<size_type>(*it);
74- } else {
75- step = 1 ;
76- }
77- }
67+ if (std::holds_alternative<size_type>(end)) {
68+ std::cout << " pos" << std::get<size_type>(end) << std::endl;
69+ } else {
70+ std::cout << " None" << std::endl;
7871 }
72+ }
7973
8074 constexpr bool operator ==(const bounds& other) const = default ;
8175 constexpr auto operator <=>(const bounds& other) const = default ;
8276
83- constexpr bounds& operator +=(const size_type& size) {
84- end = begin + size;
77+ constexpr bounds& operator +=(const size_t & _size) {
78+ const size_type size = static_cast <size_type>(_size);
79+ if (std::holds_alternative<size_type>(end)) {
80+ size_type end_pos = std::get<size_type>(end);
81+ if (end_pos >= 0 ) {
82+ end = end_pos + size;
83+ } else {
84+ end = ((size_type (-1 ) - size) < end_pos) ? size_type (-1 ) : (end_pos + size);
85+ }
86+ } else if (std::holds_alternative<size_type>(begin)) {
87+ end = std::get<size_type>(begin) + size;
88+ }
8589 return *this ;
8690 }
87- constexpr bounds& operator -=(const size_type& size) {
88- begin = end - size;
91+
92+ constexpr bounds& operator -=(const size_t & _size) {
93+ const size_type size = static_cast <size_type>(_size);
94+ if (std::holds_alternative<size_type>(begin)) {
95+ size_type begin_pos = std::get<size_type>(begin);
96+ if (!std::holds_alternative<size_type>(end)) {
97+ end = begin_pos + 1 ;
98+ begin = begin_pos + 1 - size;
99+ } else {
100+ if (begin_pos < 0 ) {
101+ begin = begin_pos - size;
102+ } else {
103+ begin = ((size_type (0 ) + size) > begin_pos) ? size_type (0 ) : (begin_pos - size);
104+ }
105+ }
106+ }
89107 return *this ;
90108 }
91- constexpr size_type size () const {
92- return end - begin;
109+
110+ constexpr std::pair<size_type, size_type> resolve (size_t _length) const {
111+ const size_type length = static_cast <size_type>(_length);
112+ // Helper: translate a possibly-negative int into a signed index
113+ auto translate_index = [&](size_type idx) -> size_type {
114+ size_type x = (idx);
115+ if (x < size_type (0 )) {
116+ x += length;
117+ }
118+ return x;
119+ };
120+
121+ // 1) Compute raw_start
122+ size_type raw_start;
123+ if (std::holds_alternative<None_t>(begin)) {
124+ raw_start = size_type (0 );
125+ } else {
126+ raw_start = translate_index (std::get<size_type>(begin));
127+ }
128+
129+ // 2) Compute raw_end
130+ size_type raw_end;
131+ if (std::holds_alternative<None_t>(end)) {
132+ raw_end = length;
133+ } else {
134+ raw_end = translate_index (std::get<size_type>(end));
135+ }
136+
137+ // 3) Clamp into [0..L]
138+ return {std::clamp (raw_start,
139+ size_type (0 ),
140+ length),
141+ std::clamp (raw_end,
142+ size_type (0 ),
143+ length)};
93144 }
94145};
95146
0 commit comments