CopyPastor

Detecting plagiarism made easy.

Score: 1; Reported for: Exact paragraph match Open both answers

Possible Plagiarism

Reposted on 2024-04-12
by tbxfreeware

Original Post

Original - Posted on 2024-04-09
by tbxfreeware



            
Present in both answers; Present only in the new answer; Present only in the old answer;

The answers for [Method 1](https://stackoverflow.com/a/78316154/22193627) and [Method 2](https://stackoverflow.com/a/78316160/22193627) both use the same test program. It's source code is listed below. It's a complete program that you can download, and then use to test the two different versions of the file `tbx.RomanNumeral.cpp` that appear in the answers for Method 1 and Method 2.
The testing functions are not critical to an understanding of Methods 1 and 2. Before reading further, therefore, it is recommended to read the answers for Method 1 and Method 2. Then, if you are interested, you can come back here, to check out the test routines.
#### Testing regime
The file `tbx.use_tests.RomanNumeral.cpp` contains two functions that test the conversion routines.
- `test_valid_Roman_numerals` – Test every valid Roman numeral! Convert every integer between 1 and 3999 into a Roman numeral and back again. Count (and report) the number of failures. - `test_invalid_Roman_numerals` – Attempt to convert a host of invalid Roman numerals. Report success or failure for each one.
The naive routines are perfect when it comes to valid Roman numerals. They fail badly, however, against the invalid ones.
Here is the output I obtained when I ran the tests against the naive conversion routine that lies at the heart of Method 2. These are the answers you get before applying the round-trip conversion that double-checks the result.
```lang-none Round-trip Conversion of Every Valid Roman Numeral
Failure count: 0

Detect Invalid Roman Numerals
Roman Numeral Integer Valid?
"" 0 false "garbage" 0 false "I I" 0 false "IL" 49 true "IC" 99 true "ID" 499 true "IM" 999 true "VX" 5 true "VL" 45 true "VC" 95 true "VD" 495 true "VM" 995 true "XD" 490 true "XM" 990 true "LC" 50 true "LD" 450 true "LM" 950 true "DM" 500 true "IVIV" 8 true "IXIX" 18 true "IXIV" 13 true "IVIX" 3 true "XCXL" 130 true "CDCM" 300 true "VV" 10 true "LL" 100 true "DD" 1000 true "IIII" 4 true "XXXX" 40 true "CCCC" 400 true "MMMM" 4000 true "IXX" 19 true "XCC" 190 true "CMM" 1900 true "IIV" 3 true "IIX" 8 true "XXL" 30 true "XXC" 80 true "CCD" 300 true "CCM" 800 true "VIX" 4 true "LXC" 40 true "DCM" 400 true ```
`IVIX` is 3? `DCM` is 400?
#### Source code
The following sections contain source code for the six files listed below. It was compiled for C++17.
1. _main.cpp_ – Setup log file, and run use tests. (There are only two lines.) 2. _tbx.use_tests.RomanNumeral.h_ – Declare entry point for use tests. 3. _tbx.use_tests.RomanNumeral.cpp_ – Implement use tests. 4. _tbx.RomanNumeral.h_ – Declare Roman numeral functions: `tbx::roman_numeral_to_int` and `tbx::is_roman_numeral`. Define the function template that handles the reverse conversion: `tbx::integer_to_roman_numeral`. 5. _tbx.utility.h_ – Declare utility functions. These are previously written functions from my "toolbox." Of the many functions provided by this header, only six are used by this program: `is_unqualified_short_int_long_v`, `OneTimeToggle`, `to_upper`, `to_upper_in_place`, `trim_whitespace`, and `trim_whitespace_view`. 6. _tbx.utility.cpp_ – Implement utility functions. The abridged version here includes only functions needed for this program.
#### 1. main.cpp
```lang-cpp // main.cpp #include <iostream> #include "tbx.use_tests.RomanNumeral.h"
int main() { auto& log{ std::cout }; // substitute log file, as needed return tbx::use_tests_RomanNumeral(log) ? 0 : 1; } // end file::main.cpp ```
#### 2. tbx.use_tests.RomanNumeral.h
```lang-cpp #pragma once
// tbx.use_tests.RomanNumeral.h #include <iostream> namespace tbx { bool use_tests_RomanNumeral(std::ostream& log); } // end file: tbx.use_tests.RomanNumeral.h ```
#### 3. tbx.use_tests.RomanNumeral.cpp
Comments in `tbx.use_tests.RomanNumeral.cpp` explain what is wrong with each of the invalid Roman numerals that is tested.
```lang-cpp // tbx.use_tests.RomanNumeral.cpp #include <iomanip> #include <iostream> #include <string>
#include "tbx.RomanNumeral.h" #include "tbx.utility.h"
namespace { bool test_valid_Roman_numerals(std::ostream& log) { log << "Round-trip Conversion of Every Valid Roman Numeral\n\n"; int n_failures{}; for (int n{ 1 }; n <= 3999; ++n) { auto r{ tbx::integer_to_roman_numeral(n) }; auto num{ tbx::roman_numeral_to_int(r) }; if (num != n) ++n_failures; } log << " Failure count: " << n_failures << "\n\n\n"; return n_failures == 0; } bool test_invalid_Roman_numeral(std::ostream& log, std::string const& r) { auto const n{ tbx::roman_numeral_to_int(r) }; auto const valid{ tbx::is_roman_numeral(r) }; log << " " << std::left << std::setw(11) << std::quoted(r) << " " << std::right << std::setw(9) << n << " " << std::left << std::boolalpha << valid << '\n'; return !valid; } bool test_invalid_Roman_numerals(std::ostream& log) { log << "Detect Invalid Roman Numerals\n\n" << " " << "Roman\n" << " " << std::left << std::setw(11) << "Numeral" << " " << std::right << std::setw(9) << "Integer" << " " << std::left << "Valid?" << "\n\n"; tbx::OneTimeToggle pass_all{ true }; pass_all = test_invalid_Roman_numeral(log, ""); // empty string pass_all = test_invalid_Roman_numeral(log, "garbage"); // yeah, garbage pass_all = test_invalid_Roman_numeral(log, "I I"); // space between symbols pass_all = test_invalid_Roman_numeral(log, "IL"); // invalid subtraction pass_all = test_invalid_Roman_numeral(log, "IC"); pass_all = test_invalid_Roman_numeral(log, "ID"); pass_all = test_invalid_Roman_numeral(log, "IM"); pass_all = test_invalid_Roman_numeral(log, "VX"); // only 'I`, 'X', and 'C' pass_all = test_invalid_Roman_numeral(log, "VL"); // can be subtracted pass_all = test_invalid_Roman_numeral(log, "VC"); pass_all = test_invalid_Roman_numeral(log, "VD"); pass_all = test_invalid_Roman_numeral(log, "VM"); pass_all = test_invalid_Roman_numeral(log, "XD"); pass_all = test_invalid_Roman_numeral(log, "XM"); pass_all = test_invalid_Roman_numeral(log, "LC"); pass_all = test_invalid_Roman_numeral(log, "LD"); pass_all = test_invalid_Roman_numeral(log, "LM"); pass_all = test_invalid_Roman_numeral(log, "DM"); pass_all = test_invalid_Roman_numeral(log, "IVIV"); // `I`, `X`, and `C` can only pass_all = test_invalid_Roman_numeral(log, "IXIX"); // be subtracted once in any pass_all = test_invalid_Roman_numeral(log, "IXIV"); // given Roman numeral pass_all = test_invalid_Roman_numeral(log, "IVIX"); pass_all = test_invalid_Roman_numeral(log, "XCXL"); pass_all = test_invalid_Roman_numeral(log, "CDCM"); pass_all = test_invalid_Roman_numeral(log, "VV"); // only 'I`, 'X', 'C' and 'M' pass_all = test_invalid_Roman_numeral(log, "LL"); // can be repeated pass_all = test_invalid_Roman_numeral(log, "DD"); pass_all = test_invalid_Roman_numeral(log, "IIII"); // too many repeats pass_all = test_invalid_Roman_numeral(log, "XXXX"); pass_all = test_invalid_Roman_numeral(log, "CCCC"); pass_all = test_invalid_Roman_numeral(log, "MMMM"); pass_all = test_invalid_Roman_numeral(log, "IXX"); // repetition and subtraction pass_all = test_invalid_Roman_numeral(log, "XCC"); // cannot be combined pass_all = test_invalid_Roman_numeral(log, "CMM"); pass_all = test_invalid_Roman_numeral(log, "IIV"); // "threshold" not increasing pass_all = test_invalid_Roman_numeral(log, "IIX"); pass_all = test_invalid_Roman_numeral(log, "XXL"); pass_all = test_invalid_Roman_numeral(log, "XXC"); pass_all = test_invalid_Roman_numeral(log, "CCD"); pass_all = test_invalid_Roman_numeral(log, "CCM"); pass_all = test_invalid_Roman_numeral(log, "VIX"); pass_all = test_invalid_Roman_numeral(log, "LXC"); pass_all = test_invalid_Roman_numeral(log, "DCM"); log << "\n\n"; return pass_all; } } namespace tbx { bool use_tests_RomanNumeral(std::ostream& log) { return test_valid_Roman_numerals(log) && test_invalid_Roman_numerals(log); } } // end file: tbx.use_tests.RomanNumeral.cpp ```
#### 4. tbx.RomanNumeral.h
The header `tbx.RomanNumeral.h` is provided below. The answers for Method 1 and Method 2 each have their own version of the corresponding implementation file, `tbx.RomanNumeral.cpp`.
```lang-cpp #pragma once
// tbx.RomanNumeral.h #include <algorithm> #include <cctype> #include <cstddef> #include <iostream> #include <iterator> #include <stdexcept> #include <string> #include <string_view> #include <type_traits> #include <unordered_map> #include <unordered_set>
#include "tbx.utility.h"
namespace tbx { //================================================================== // integer_to_roman_numeral //================================================================== template < typename IntType , typename = typename std::enable_if_t<tbx::is_unqualified_short_int_long_v<IntType>> > std::string integer_to_roman_numeral(IntType const n) { if (n < 1 || n > 3999) return ""; // sentinel value signals failure
static constexpr char const* const I[]{ "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" }; static constexpr char const* const X[]{ "", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC" }; static constexpr char const* const C[]{ "", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM" }; static constexpr char const* const M[]{ "", "M", "MM", "MMM" };
auto const v{ static_cast<std::size_t>(n) }; enum : std::size_t { fifteen = 15u }; std::string r; r.reserve(fifteen); // room enough for "MMMDCCCLXXXVIII", the widest Roman numeral r = M[v / 1000u]; r += C[(v % 1000u) / 100u]; r += X[(v % 100u) / 10u]; r += I[v % 10u];; return r; } //================================================================== // is_roman_numeral //================================================================== bool is_roman_numeral(std::string const& r);
//================================================================== // roman_numeral_to_int //================================================================== int roman_numeral_to_int(std::string r); } // end file: tbx.RomanNumeral.h ```
#### 5. tbx.utility.h
```lang-cpp #pragma once // tbx.utility.h #include <cstddef> #include <string> #include <string_view> #include <type_traits>
namespace tbx { auto to_upper(std::string s) noexcept -> std::string; void to_upper_in_place(std::string& s) noexcept; auto trim_whitespace(std::string const& s) -> std::string; auto trim_whitespace_view(std::string_view sv) noexcept -> std::string_view;
//================================================================== // is_unqualified_short_int_long // // short unsigned short // int unsigned int // long unsigned long // long long unsigned long long //================================================================== template <typename T> struct is_unqualified_short_int_long : std::bool_constant < std::is_same_v<T, short> || std::is_same_v<T, int> || std::is_same_v<T, long> || std::is_same_v<T, long long> || std::is_same_v<T, unsigned short> || std::is_same_v<T, unsigned int> || std::is_same_v<T, unsigned long> || std::is_same_v<T, unsigned long long> > {}; template <typename T> inline bool constexpr is_unqualified_short_int_long_v = tbx::is_unqualified_short_int_long<T>::value; template <typename T> inline bool constexpr is_short_int_long_v = tbx::is_unqualified_short_int_long<std::remove_cv<T>>::value;
//================================================================== // OneTimeToggle //================================================================== class OneTimeToggle { bool const initial_state; bool state; public: constexpr OneTimeToggle(bool const b) noexcept : initial_state{ b }, state{ b } {} constexpr bool operator() () const noexcept { return state; } constexpr operator bool() const noexcept { return state; } constexpr OneTimeToggle& operator= (bool const b) noexcept { if (b != initial_state) state = b; return *this; } constexpr void reset() { state = initial_state; } }; } // end file: tbx.utility.h ```
#### 6. tbx.utility.cpp
```lang-cpp // tbx.utility.cpp #include <algorithm> #include <cctype> #include <string> #include <string_view>
#include "tbx.utility.h"
namespace tbx { //================================================================== // to_upper //================================================================== std::string to_upper(std::string s) noexcept { tbx::to_upper_in_place(s); return s; } //================================================================== // to_upper_in_place //================================================================== void to_upper_in_place(std::string& s) noexcept { std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return static_cast<char>(std::toupper(c)); } ); } //================================================================== // trim_whitespace //================================================================== auto trim_whitespace(std::string const& s) -> std::string { return std::string{ trim_whitespace_view(s) }; } //================================================================== // trim_whitespace_view //================================================================== auto trim_whitespace_view(std::string_view sv) noexcept -> std::string_view { // Trim leading and trailing whitespace from string_view `sv`. auto const first{ sv.find_first_not_of(" \f\n\r\t\v") }; if (first == std::string_view::npos) return {}; auto const last{ sv.find_last_not_of(" \f\n\r\t\v") }; enum : std::string_view::size_type { one = 1u }; return sv.substr(first, (last - first + one)); } } // end file: tbx.utility.cpp ```
This answer is an appendix to the [answer posted here](https://stackoverflow.com/a/78300759/22193627).
It provides source code listings for the program in that answer.
The appendix was created because there was not enough room in the original answer to post the five files it uses.
#### main.cpp
```lang-cpp // main.cpp #include <iomanip> #include <iostream> #include <limits> #include <stdexcept> #include <string>
#include "RomanNumeral.h" #include "tbx.utility.h"
namespace { bool test_valid_Roman_numerals(std::ostream& log) { log << "Round-trip Conversion of Every Valid Roman Numeral\n\n"; int n_failures{}; for (int n{ 1 }; n <= 3999; ++n) { auto r{ roman_numeral::fromInteger(n) }; auto num{ roman_numeral::toDecimal(r) }; if (num != n) ++n_failures; } log << " Failure count: " << n_failures << "\n\n"; return n_failures == 0; } bool test_invalid_Roman_numeral(std::ostream& log, std::string const& r) { auto const d = roman_numeral::toDecimal(r); auto const v = roman_numeral::isValid(r); log << " " << std::left << std::setw(11) << std::quoted(r) << " " << std::right << std::setw(9) << d << " " << std::left << std::boolalpha << v << '\n'; return !v; } bool test_invalid_Roman_numerals(std::ostream& log) { log << "Detect Invalid Roman Numerals\n\n" << " " << "Roman\n" << " " << std::left << std::setw(11) << "Numeral" << " " << std::right << std::setw(9) << "toDecimal" << " " << std::left << "isValid" << "\n\n"; tbx::OneTimeToggle pass_all{ true }; pass_all = test_invalid_Roman_numeral(log, ""); // empty string pass_all = test_invalid_Roman_numeral(log, "garbage"); // yeah, garbage pass_all = test_invalid_Roman_numeral(log, "I I"); // space between symbols pass_all = test_invalid_Roman_numeral(log, "IL"); // invalid subtraction pass_all = test_invalid_Roman_numeral(log, "IC"); pass_all = test_invalid_Roman_numeral(log, "ID"); pass_all = test_invalid_Roman_numeral(log, "IM"); pass_all = test_invalid_Roman_numeral(log, "VX"); // only 'I`, 'X', and 'C' pass_all = test_invalid_Roman_numeral(log, "VL"); // can be subtracted pass_all = test_invalid_Roman_numeral(log, "VC"); pass_all = test_invalid_Roman_numeral(log, "VD"); pass_all = test_invalid_Roman_numeral(log, "VM"); pass_all = test_invalid_Roman_numeral(log, "XD"); pass_all = test_invalid_Roman_numeral(log, "XM"); pass_all = test_invalid_Roman_numeral(log, "LC"); pass_all = test_invalid_Roman_numeral(log, "LD"); pass_all = test_invalid_Roman_numeral(log, "LM"); pass_all = test_invalid_Roman_numeral(log, "DM"); pass_all = test_invalid_Roman_numeral(log, "IVIV"); // `I`, `X`, and `C` can only pass_all = test_invalid_Roman_numeral(log, "IXIX"); // be subtracted once in any pass_all = test_invalid_Roman_numeral(log, "IXIV"); // given Roman numeral pass_all = test_invalid_Roman_numeral(log, "IVIX"); pass_all = test_invalid_Roman_numeral(log, "XCXL"); pass_all = test_invalid_Roman_numeral(log, "CDCM"); pass_all = test_invalid_Roman_numeral(log, "VV"); // only 'I`, 'X', 'C' and 'M' pass_all = test_invalid_Roman_numeral(log, "LL"); // can be repeated pass_all = test_invalid_Roman_numeral(log, "DD"); pass_all = test_invalid_Roman_numeral(log, "IIII"); // too many repeats pass_all = test_invalid_Roman_numeral(log, "XXXX"); pass_all = test_invalid_Roman_numeral(log, "CCCC"); pass_all = test_invalid_Roman_numeral(log, "MMMM"); pass_all = test_invalid_Roman_numeral(log, "IXX"); // repetition and subtraction pass_all = test_invalid_Roman_numeral(log, "XCC"); // cannot be combined pass_all = test_invalid_Roman_numeral(log, "CMM"); pass_all = test_invalid_Roman_numeral(log, "IIV"); // "threshold" not increasing pass_all = test_invalid_Roman_numeral(log, "IIX"); pass_all = test_invalid_Roman_numeral(log, "XXL"); pass_all = test_invalid_Roman_numeral(log, "XXC"); pass_all = test_invalid_Roman_numeral(log, "CCD"); pass_all = test_invalid_Roman_numeral(log, "CCM"); pass_all = test_invalid_Roman_numeral(log, "VIX"); pass_all = test_invalid_Roman_numeral(log, "LXC"); pass_all = test_invalid_Roman_numeral(log, "DCM"); log << "\n\n"; return pass_all; } int get_int( std::string const& prompt, int const min, int const max, std::istream& ist, std::ostream& ost) { for (;;) { ost << prompt; if (int n{}; !(std::cin >> n)) { ost << "Invalid entry. Please reenter.\n\n"; ist.clear(); ist.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); } else if (n < min || n > max) { ost << "Invalid entry. Please reenter.\n" << "Entries must be between " << min << " and " << max << ".\n\n"; } else { ist.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); return n; } } } std::string get_Roman_numeral(std::istream& ist, std::ostream& ost) { std::string r; for (;;) { ost << "Enter a roman numeral: "; ist >> r; ost.put('\n'); if (roman_numeral::isValid(r)) break; ost << "Invalid entry. Please reenter.\n\n"; } ist.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); return r; } void select_error_processing_function( std::ostream& log, std::istream& ist, std::string& r) { char const* const menu { " is not a valid Roman numeral." "\n" "\nSelect an error processing function:" "\n" "\n 1. Reenter the Roman numeral" "\n 2. Throw an exception" "\n\n" }; enum { ReenterRomanNumeral = 1, ThrowException }; log << r << menu; int choice{ get_int("Choice? ", 1, 2, ist, log) }; log.put('\n'); switch (choice) { case ReenterRomanNumeral: r = get_Roman_numeral(ist, log); break; case ThrowException: throw std::runtime_error("Malformed Roman numeral: \"" + r + '"'); default: // std::unreachable(); break; } } bool test_Roman_numeral_entered_by_user( std::istream& ist, std::ostream& log) { log << "Roman Numeral to Integer Converter\n\n" " Enter a Roman numeral: "; std::string r; std::getline(ist, r); log.put('\n'); int num{}; while ((num = roman_numeral::toDecimal(r)) == 0) { try { select_error_processing_function(log, ist, r); } catch (std::exception const& e) { log << " Exception caught in function " "`test_Roman_numeral_entered_by_user`: " << e.what() << "\n\n"; return false; } } log << " " << r << " = " << num << "\n\n"; return true; } } int main() { auto& log{ std::cout }; // substitute log files, as needed auto& ist{ std::cin }; int exit_code{}, shift{};
// Each of the three tests gets its own bit in the `exit_code`, // where 0-valued bits indicate success. exit_code |= test_valid_Roman_numerals(log) ? 0 : 1 << shift++; exit_code |= test_invalid_Roman_numerals(log) ? 0 : 1 << shift++; exit_code |= test_Roman_numeral_entered_by_user(ist, log) ? 0 : 1 << shift++; return exit_code; // between 0 and 7 } // end file: main.cpp ```
#### RomanNumeral.h
```lang-cpp #pragma once // RomanNumeral.h // Functions designed per the specification at Stack Overflow // https://stackoverflow.com/q/17724887/22193627
#include <string>
namespace roman_numeral { bool isValid(std::string const& r); int value_from_map(char const symbol); int value_from_switch(char const symbol); int toDecimal( std::string r, int (*value)(char const symbol) = value_from_map); std::string fromInteger(int const n); } // end file: RomanNumeral.h ```
#### RomanNumeral.cpp
```lang-cpp // RomanNumeral.cpp #include <cstddef> #include <iterator> #include <string> #include <unordered_map> #include <unordered_set>
#include "RomanNumeral.h" #include "tbx.utility.h"
namespace { //================================================================== // is_repeatable //================================================================== bool is_repeatable(char const i) { return i == 'I' || i == 'X' || i == 'C' || i == 'M'; } //================================================================== // is_subtractive //================================================================== bool is_subtractive(char const i, char const vx) { return i == 'I' && vx == 'V' || i == 'I' && vx == 'X' || i == 'X' && vx == 'L' || i == 'X' && vx == 'C' || i == 'C' && vx == 'D' || i == 'C' && vx == 'M'; } } namespace roman_numeral { //================================================================== // fromInteger //================================================================== std::string fromInteger(int const n) { if (n < 1 || n > 3999) return ""; // sentinel value signals failure
static constexpr char const* const I[]{ "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" }; static constexpr char const* const X[]{ "", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC" }; static constexpr char const* const C[]{ "", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM" }; static constexpr char const* const M[]{ "", "M", "MM", "MMM" };
auto const v{ static_cast<std::size_t>(n) }; enum : std::size_t { fifteen = 15u }; std::string r; r.reserve(fifteen); // room enough for "MMMDCCCLXXXVIII", the widest Roman numeral r = M[v / 1000u]; r += C[(v % 1000u) / 100u]; r += X[(v % 100u) / 10u]; r += I[v % 10u];; return r; } //================================================================== // isValid //================================================================== bool isValid(std::string const& r) { return toDecimal(r, value_from_map) != 0; } //================================================================== // toDecimal //================================================================== int toDecimal(std::string r, int (*value)(char const symbol)) { r = tbx::to_upper(tbx::trim_whitespace(r));
// Fail if any of the characters in `r` are not valid Roman // numeral symbols. for (auto const& c : r) if (value(c) == 0) return 0; // sentinel value signals failure
// Handle short strings as special cases. enum : std::size_t { zero, one }; switch (r.length()) { case zero: return 0; // sentinel value signals failure case one: return value(r.front()); default: break; }
// Loop, scanning string `r` from right-to-left. auto trailer{ r.crbegin() }; auto t{ *trailer }; auto vt{ value(t) };
auto leader{ std::next(r.crbegin()) }; auto l{ *leader }; auto vl{ value(l) };
int sum{ vt }; int n_repeats{ 1 }; int threshold{ vt };
std::unordered_set<char> already_subtracted;
while (leader != r.crend()) { l = *leader; vl = value(l); t = *trailer; vt = value(t); if (vl < threshold) { if (!is_subtractive(l, t) || already_subtracted.count(l) || n_repeats != 1) return 0; // sentinel value signals failure sum -= vl; already_subtracted.insert(l); n_repeats = 0; threshold = 10 * vl; } else if (vl == threshold) { if (!is_repeatable(l) || ++n_repeats > 3) return 0; // sentinel value signals failure sum += vl; } else // vl > threshold { sum += vl; n_repeats = 1; threshold = vl; } ++leader; ++trailer; } return sum; } //================================================================== // value_from_map //================================================================== int value_from_map(char const symbol) { static const std::unordered_map<char, int> values = { { 'I', 1 }, { 'V', 5 }, { 'X', 10 }, { 'L', 50 }, { 'C', 100 }, { 'D', 500 }, { 'M', 1000 } }; if (auto const it{ values.find(symbol) }; it == values.end()) return 0; // sentinel value signals failure else return it->second; } //================================================================== // value_from_switch //================================================================== int value_from_switch(char const symbol) { switch (symbol) { case 'I': return 1; case 'V': return 5; case 'X': return 10; case 'L': return 50; case 'C': return 100; case 'D': return 500; case 'M': return 1000; default: break; } return 0; // sentinel value signals failure } } // end file: RomanNumeral.cpp ```
#### tbx.utility.h
```lang-cpp #pragma once // tbx.utility.h #include <string> #include <string_view>
namespace tbx { auto to_upper(std::string s) noexcept -> std::string; void to_upper_in_place(std::string& s) noexcept; auto trim_whitespace(std::string const& s) -> std::string; auto trim_whitespace_view(std::string_view sv) noexcept -> std::string_view;
//================================================================== // OneTimeToggle //================================================================== class OneTimeToggle { bool const initial_state; bool state; public: constexpr OneTimeToggle(bool const b) noexcept : initial_state{ b }, state{ b } {} constexpr bool operator() () const noexcept { return state; } constexpr operator bool() const noexcept { return state; } constexpr OneTimeToggle& operator= (bool const b) noexcept { if (b != initial_state) state = b; return *this; } constexpr void reset() { state = initial_state; } }; } // end file: tbx.utility.h ```
#### tbx.utility.cpp
```lang-cpp // tbx.utility.cpp #include <algorithm> #include <cctype> #include <string> #include <string_view>
#include "tbx.utility.h"
namespace tbx { //================================================================== // to_upper //================================================================== std::string to_upper(std::string s) noexcept { tbx::to_upper_in_place(s); return s; } //================================================================== // to_upper_in_place //================================================================== void to_upper_in_place(std::string& s) noexcept { std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return static_cast<char>(std::toupper(c)); } ); } //================================================================== // trim_whitespace //================================================================== auto trim_whitespace(std::string const& s) -> std::string { return std::string{ trim_whitespace_view(s) }; } //================================================================== // trim_whitespace_view //================================================================== auto trim_whitespace_view(std::string_view sv) noexcept -> std::string_view { // Trim leading and trailing whitespace from string_view `sv`. auto const first{ sv.find_first_not_of(" \f\n\r\t\v") }; if (first == std::string_view::npos) return {}; auto const last{ sv.find_last_not_of(" \f\n\r\t\v") }; enum : std::string_view::size_type { one = 1u }; return sv.substr(first, (last - first + one)); } } // end file: tbx.utility.cpp ```

        
Present in both answers; Present only in the new answer; Present only in the old answer;