Skip to content

Commit

Permalink
Add an EntryModel option to disable automatic clamping (#680)
Browse files Browse the repository at this point in the history
* Make automatic clamping optional.

* Fix bug.

* Fix build.

* Add tests for disabling automatic clamping.

* Add a test where the minimum value is significantly greater than zero.
  • Loading branch information
bakerstu authored Nov 29, 2022
1 parent 970f905 commit e81d237
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 12 deletions.
75 changes: 75 additions & 0 deletions src/utils/EntryModel.cxxtest
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,81 @@ TEST(EntryModelBoundedTest, SetMinMax)
EXPECT_FALSE(em.empty());
}

TEST(EntryModelBoundedTest, SetMinMaxUnclamped)
{
EntryModelBounded<int16_t> em;

// intial value
em.init(4, 10, 9, -100, 100, 11, false);
EXPECT_EQ(4U, em.max_size());
EXPECT_EQ(4U, em.max_size());
EXPECT_EQ(9, em.get_value());
EXPECT_EQ("9", em.get_string());
EXPECT_EQ(" 9", em.get_string(true));
EXPECT_EQ(0U, em.size());
EXPECT_TRUE(em.is_at_initial_value());
EXPECT_FALSE(em.empty());

// set default
em.set_default();
EXPECT_EQ(11, em.get_value());
EXPECT_EQ("11", em.get_string());
EXPECT_EQ(" 11", em.get_string(true));
EXPECT_EQ(0U, em.size());
EXPECT_TRUE(em.is_at_initial_value());
EXPECT_FALSE(em.empty());

// boundary checks, automatic clamping disabled
em.push_back(1);
em.push_back(2);
em.push_back(3);
em.push_back(4);
EXPECT_EQ(1234, em.get_value());
EXPECT_EQ("1234", em.get_string());
EXPECT_EQ("1234", em.get_string(true));
EXPECT_EQ(4U, em.size());
EXPECT_EQ(100, em.get_value(true)); // now clamp
EXPECT_EQ("100", em.get_string());
EXPECT_EQ(" 100", em.get_string(true));
EXPECT_EQ(3U, em.size());
EXPECT_FALSE(em.is_at_initial_value());
EXPECT_FALSE(em.empty());

em.init(4, 10, 9, -100, 1003, 11, false);
EXPECT_EQ(4U, em.max_size());
em.push_back(1);
em.push_back(2);
em.push_back(3);
em.push_back(4);
EXPECT_EQ(1234, em.get_value());
EXPECT_EQ("1234", em.get_string());
EXPECT_EQ("1234", em.get_string(true));
EXPECT_EQ(4U, em.size());
EXPECT_EQ(1003, em.get_value(true)); // now clamp
EXPECT_EQ("1003", em.get_string());
EXPECT_EQ("1003", em.get_string(true));
EXPECT_EQ(4U, em.size());
EXPECT_FALSE(em.is_at_initial_value());
EXPECT_FALSE(em.empty());

em.init(4, 10, 2800, 1500, 2800, 11, false);
EXPECT_EQ(4U, em.max_size());
em.push_back(1);
em.push_back(2);
em.push_back(3);
em.push_back(4);
EXPECT_EQ(1234, em.get_value());
EXPECT_EQ("1234", em.get_string());
EXPECT_EQ("1234", em.get_string(true));
EXPECT_EQ(4U, em.size());
EXPECT_EQ(1500, em.get_value(true)); // now clamp
EXPECT_EQ("1500", em.get_string());
EXPECT_EQ("1500", em.get_string(true));
EXPECT_EQ(4U, em.size());
EXPECT_FALSE(em.is_at_initial_value());
EXPECT_FALSE(em.empty());
}

TEST(EntryModelBoundedTest, LeadingZerosNonZeroMin)
{
EntryModelBounded<uint16_t> uem;
Expand Down
49 changes: 37 additions & 12 deletions src/utils/EntryModel.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,11 @@ public:
, isAtInitialValue_(false)
, empty_(true)
, base_(10)
, autoClamp_(true)
{
}

///Clear the entry string.
/// Clear the entry string.
void clear()
{
value_ = 0;
Expand All @@ -79,6 +80,7 @@ public:
void init(unsigned max_size, int base)
{
maxSize_ = max_size;
autoClamp_ = true;
clear();
set_base(base); // this will call set_boundaries()
}
Expand All @@ -87,9 +89,14 @@ public:
/// @param max_size max number of digits in the base type
/// @param base base type, 10 or 16
/// @param value value to initialize with
void init(unsigned max_size, int base, T value)
/// @param automatic_clamp Unless otherwise specified by the API, enables
/// automatic clamping of the value each time it is
/// modified when true, else automatic clamping is
/// not applied.
void init(unsigned max_size, int base, T value, bool automatic_clamp = true)
{
init(max_size, base);
autoClamp_ = automatic_clamp;
value_ = value;
isAtInitialValue_ = true;
empty_ = false;
Expand Down Expand Up @@ -136,7 +143,7 @@ public:
}
empty_ = false;
++size_;
clamp();
auto_clamp();
}

/// Append a character to the "back".
Expand Down Expand Up @@ -188,7 +195,7 @@ public:
if (isAtInitialValue_)
{
isAtInitialValue_ = false;
clamp();
auto_clamp();
// need to compute the size now that the initial value is false
calculate_size();
}
Expand All @@ -197,7 +204,7 @@ public:
// no more characters left, so the entry is "empty"
empty_ = true;
}
clamp();
auto_clamp();
}

/// Set the radix base.
Expand Down Expand Up @@ -236,7 +243,7 @@ public:
/// @param value value to initialize with
void set_value(T value)
{
init(maxSize_, base_, value);
init(maxSize_, base_, value, autoClamp_);
}

/// Get the size (actual number of digits). Note, if the entry is still
Expand Down Expand Up @@ -297,7 +304,7 @@ public:
/// "empty". However, if force is set to true, we will
/// clamp anyways. This may be valuable when wanting an
/// "empty" entry to return a valid value and '0' is out
/// of bounds.
/// of bounds. The auto clamping setting is ignored.
/// @return value representation of the entry
T get_value(bool force_clamp = false)
{
Expand Down Expand Up @@ -381,7 +388,7 @@ public:
{
++size_;
}
clamp();
auto_clamp();
}

/// Clamp the value at the min or max. Clamping will not occur if the value
Expand Down Expand Up @@ -415,7 +422,8 @@ public:

/// Pre-increment value. While this method does prevent wrap around of
/// the native type limits, it is incumbent on the caller to limit the
/// resulting number of digits.
/// resulting number of digits. Always clamps, the auto clamping setting
/// is ignroed.
T operator ++()
{
isAtInitialValue_ = false;
Expand All @@ -429,7 +437,8 @@ public:

/// Pre-decrement value. While this method does prevent wrap around of
/// the native type limits, it is incumbent on the caller to limit the
/// resulting number of digits.
/// resulting number of digits. Always clamps, the auto clamping setting
/// is ignroed.
T operator --()
{
isAtInitialValue_ = false;
Expand All @@ -442,6 +451,19 @@ public:
}

protected:
/// Calls clamp() only if automatic clamping is enabled (autoClamp_ = true).
/// @param force Normally, clamping doesn't occur if the entry is "empty".
/// However, if force is set to true, we will clamp anyways.
/// force also applies if the value is zero yet there is space
/// for more leading zeros.
void auto_clamp(bool force = false)
{
if (autoClamp_)
{
clamp(force);
}
}

/// Set min and max boundaries supported based on maxSize_ (digit count).
virtual void set_boundaries()
{
Expand Down Expand Up @@ -478,6 +500,7 @@ protected:
unsigned isAtInitialValue_ : 1; ///< true if still has the initial value
unsigned empty_ : 1; ///< true if the value_ is "empty"
unsigned base_ : 6; ///< radix base
unsigned autoClamp_ : 1; ///< true to auto clamp the values

DISALLOW_COPY_AND_ASSIGN(EntryModel);
};
Expand All @@ -501,10 +524,12 @@ public:
/// @param min minumum value
/// @param max maximum value
/// @param default_val default value
void init(unsigned max_size, int base, T value, T min, T max, T default_val)
/// @param automatic_clamp
void init(unsigned max_size, int base, T value, T min, T max, T default_val,
bool automatic_clamp = true)
{
// purposely do not boundary check the min, max, and default values
EntryModel<T>::init(max_size, base, value);
EntryModel<T>::init(max_size, base, value, automatic_clamp);
// override type min/max values
EntryModel<T>::valueMin_ = min;
EntryModel<T>::valueMax_ = max;
Expand Down

0 comments on commit e81d237

Please sign in to comment.