Skip to content

Commit 6e705b1

Browse files
authored
Merge pull request #77 from saxbophone/josh/76-inc-bug
Fix increment bug
2 parents 43209bf + 8dc429c commit 6e705b1

File tree

3 files changed

+69
-22
lines changed

3 files changed

+69
-22
lines changed

arby/include/arby/Nat.hpp

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -260,23 +260,18 @@ namespace com::saxbophone::arby {
260260
* @returns new value of Nat object after incrementing
261261
*/
262262
constexpr Nat& operator++() {
263-
// empty digits vector (means value is zero) is a special case
264-
if (_digits.size() == 0) {
265-
_digits.push_back(1);
266-
} else {
267-
// increment least significant digit
268-
auto it = _digits.rbegin();
269-
(*it)++;
270-
// increment remaining digits (rollover) as needed
271-
while (it != _digits.rend() and *it == 0) { // last digit overflowed to zero
272-
++it; // increment index
273-
(*it)++; // increment digit
274-
}
275-
// if last digit is zero, we need another one
276-
if (_digits.front() == 0) {
277-
_digits.push_front(1);
263+
// increment least significant digit then rollover remaining digits as needed
264+
for (auto it = _digits.rbegin(); it != _digits.rend(); ++it) {
265+
// only contine to next digit if incrementing this one rolls over
266+
if (++(*it) != 0) {
267+
break;
278268
}
279269
}
270+
// if last digit is zero, we need another one
271+
if (_digits.empty() or _digits.front() == 0) {
272+
_digits.push_front(1);
273+
}
274+
_trap_leading_zero();
280275
return *this; // return new value by reference
281276
}
282277
/**
@@ -298,13 +293,12 @@ namespace com::saxbophone::arby {
298293
if (_digits.size() == 0) {
299294
throw std::underflow_error("arithmetic underflow: can't decrement unsigned zero");
300295
} else {
301-
// decrement least significant digit
302-
auto it = _digits.rbegin();
303-
(*it)--;
304-
// decrement remaining digits (borrow) as needed
305-
while (it != _digits.rend() and *it == std::numeric_limits<StorageType>::max()) { // last digit overflowed to zero
306-
++it; // increment index
307-
(*it)--; // decrement digit
296+
// decrement least significant digit then borrow from remaining digits as needed
297+
for (auto it = _digits.rbegin(); it != _digits.rend(); ++it) {
298+
// only continue to next digit if decrementing this one rolls over
299+
if (--(*it) != std::numeric_limits<StorageType>::max()) {
300+
break;
301+
}
308302
}
309303
// if last digit is zero, remove it
310304
if (_digits.front() == 0) {

arby/include/arby/codlili.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ namespace com::saxbophone::arby::PRIVATE::codlili {
111111
return *this;
112112
}
113113
/* element access */
114+
// TODO: make these trap when accessed on an empty List
114115
// get reference to first element
115116
constexpr reference front() { return this->_front->value; }
116117
// get read-only reference to first element

tests/basic_arithmetic.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,22 @@ TEST_CASE("constexpr arby::Nat", "[constexpr]") {
7979
WARN("No constexpr tests written yet");
8080
}
8181

82+
TEST_CASE("arby::Nat prefix increment 0", "[basic-arithmetic]") {
83+
arby::Nat original;
84+
arby::Nat changed = ++original;
85+
86+
CHECK((uintmax_t)original == 1);
87+
CHECK((uintmax_t)changed == 1);
88+
}
89+
90+
TEST_CASE("arby::Nat postfix increment 0", "[basic-arithmetic]") {
91+
arby::Nat original;
92+
arby::Nat previous = original++;
93+
94+
CHECK((uintmax_t)original == 1);
95+
CHECK((uintmax_t)previous == 0);
96+
}
97+
8298
TEST_CASE("arby::Nat prefix increment", "[basic-arithmetic]") {
8399
uintmax_t input = GENERATE(take(1000, random((uintmax_t)0, std::numeric_limits<uintmax_t>::max() - 1)));
84100

@@ -99,6 +115,24 @@ TEST_CASE("arby::Nat postfix increment", "[basic-arithmetic]") {
99115
CHECK((uintmax_t)previous == input);
100116
}
101117

118+
TEST_CASE("arby::Nat prefix increment requiring additional digits", "[basic-arithmetic]") {
119+
// setting input value to BASE-1 means an increment will add another digit
120+
arby::Nat original = arby::Nat::BASE - 1;
121+
arby::Nat changed = ++original;
122+
123+
CHECK((uintmax_t)original == arby::Nat::BASE);
124+
CHECK((uintmax_t)changed == arby::Nat::BASE);
125+
}
126+
127+
TEST_CASE("arby::Nat postfix increment requiring additional digits", "[basic-arithmetic]") {
128+
// setting input value to BASE-1 means an increment will add another digit
129+
arby::Nat original = arby::Nat::BASE - 1;
130+
arby::Nat previous = original++;
131+
132+
CHECK((uintmax_t)original == arby::Nat::BASE);
133+
CHECK((uintmax_t)previous == arby::Nat::BASE - 1);
134+
}
135+
102136
TEST_CASE("arby::Nat prefix decrement", "[basic-arithmetic]") {
103137
uintmax_t input = GENERATE(take(1000, random((uintmax_t)1, std::numeric_limits<uintmax_t>::max())));
104138

@@ -119,6 +153,24 @@ TEST_CASE("arby::Nat postfix decrement", "[basic-arithmetic]") {
119153
CHECK((uintmax_t)previous == input);
120154
}
121155

156+
TEST_CASE("arby::Nat prefix decrement requiring digit removal", "[basic-arithmetic]") {
157+
// setting input value to BASE means a decrement will remove a digit
158+
arby::Nat original = arby::Nat::BASE;
159+
arby::Nat changed = --original;
160+
161+
CHECK((uintmax_t)original == arby::Nat::BASE - 1);
162+
CHECK((uintmax_t)changed == arby::Nat::BASE - 1);
163+
}
164+
165+
TEST_CASE("arby::Nat postfix decrement requiring digit removal", "[basic-arithmetic]") {
166+
// setting input value to BASE means a decrement will remove a digit
167+
arby::Nat original = arby::Nat::BASE;
168+
arby::Nat previous = original--;
169+
170+
CHECK((uintmax_t)original == arby::Nat::BASE - 1);
171+
CHECK((uintmax_t)previous == arby::Nat::BASE);
172+
}
173+
122174
// NOTE: no need for increment overflow tests as Nat doesn't overflow --it expands as necessary
123175
// TODO: consider writing a test case that applies very large size-increasing operations (maybe exponents)
124176
// on Nat to force a failure condition when memory runs out an an exception is thrown.

0 commit comments

Comments
 (0)