feat: add hex
This commit is contained in:
@@ -16,6 +16,7 @@ set_target_properties(cpputils PROPERTIES
|
|||||||
|
|
||||||
target_sources(cpputils
|
target_sources(cpputils
|
||||||
PRIVATE
|
PRIVATE
|
||||||
|
src/hex.cpp
|
||||||
src/uuid.cpp
|
src/uuid.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -28,6 +29,7 @@ target_compile_features(cpputils PUBLIC cxx_std_17)
|
|||||||
if(BUILD_TESTS)
|
if(BUILD_TESTS)
|
||||||
add_executable(cpputils_tests
|
add_executable(cpputils_tests
|
||||||
tests/test_main.cpp
|
tests/test_main.cpp
|
||||||
|
tests/test_hex.cpp
|
||||||
tests/test_uuid.cpp)
|
tests/test_uuid.cpp)
|
||||||
|
|
||||||
target_include_directories(cpputils_tests PRIVATE
|
target_include_directories(cpputils_tests PRIVATE
|
||||||
|
|||||||
58
include/cpputils/hex.h
Normal file
58
include/cpputils/hex.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace cpputils {
|
||||||
|
|
||||||
|
namespace hex {
|
||||||
|
|
||||||
|
std::string toHex(std::string const& input);
|
||||||
|
std::string fromHex(std::string const& input);
|
||||||
|
|
||||||
|
constexpr int hexVal(char c) {
|
||||||
|
switch (c) {
|
||||||
|
case '0':
|
||||||
|
return 0;
|
||||||
|
case '1':
|
||||||
|
return 1;
|
||||||
|
case '2':
|
||||||
|
return 2;
|
||||||
|
case '3':
|
||||||
|
return 3;
|
||||||
|
case '4':
|
||||||
|
return 4;
|
||||||
|
case '5':
|
||||||
|
return 5;
|
||||||
|
case '6':
|
||||||
|
return 6;
|
||||||
|
case '7':
|
||||||
|
return 7;
|
||||||
|
case '8':
|
||||||
|
return 8;
|
||||||
|
case '9':
|
||||||
|
return 9;
|
||||||
|
case 'a':
|
||||||
|
case 'A':
|
||||||
|
return 10;
|
||||||
|
case 'b':
|
||||||
|
case 'B':
|
||||||
|
return 11;
|
||||||
|
case 'c':
|
||||||
|
case 'C':
|
||||||
|
return 12;
|
||||||
|
case 'd':
|
||||||
|
case 'D':
|
||||||
|
return 13;
|
||||||
|
case 'e':
|
||||||
|
case 'E':
|
||||||
|
return 14;
|
||||||
|
case 'f':
|
||||||
|
case 'F':
|
||||||
|
return 15;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace hex
|
||||||
|
} // namespace cpputils
|
||||||
38
src/hex.cpp
Normal file
38
src/hex.cpp
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#include <cpputils/hex.h>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <ios>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace cpputils {
|
||||||
|
namespace hex {
|
||||||
|
|
||||||
|
std::string toHex(std::string const& input) {
|
||||||
|
std::stringstream ss;
|
||||||
|
for (auto c : input) {
|
||||||
|
ss << std::hex << std::setw(2) << std::setfill('0')
|
||||||
|
<< static_cast<unsigned int>(static_cast<unsigned char>(c));
|
||||||
|
}
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string fromHex(std::string const& input) {
|
||||||
|
if (input.size() % 2 != 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
std::string out;
|
||||||
|
out.reserve(input.size() / 2);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < input.size(); i += 2) {
|
||||||
|
int hi = hexVal(input[i]);
|
||||||
|
int lo = hexVal(input[i + 1]);
|
||||||
|
if (hi < 0 || lo < 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
out.push_back(static_cast<char>((hi << 4) | lo));
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace hex
|
||||||
|
} // namespace cpputils
|
||||||
81
tests/test_hex.cpp
Normal file
81
tests/test_hex.cpp
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
#include "catch.hpp"
|
||||||
|
|
||||||
|
#include <cpputils/hex.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
using namespace cpputils::hex;
|
||||||
|
|
||||||
|
TEST_CASE("Hex conversion round-trip works", "[hex]") {
|
||||||
|
std::string original = "Hello, World!";
|
||||||
|
std::string hex = toHex(original);
|
||||||
|
std::string result = fromHex(hex);
|
||||||
|
|
||||||
|
REQUIRE(result == original);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Empty string conversion", "[hex]") {
|
||||||
|
std::string empty = "";
|
||||||
|
std::string hex = toHex(empty);
|
||||||
|
std::string result = fromHex(hex);
|
||||||
|
|
||||||
|
REQUIRE(hex.empty());
|
||||||
|
REQUIRE(result.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Single character conversion", "[hex]") {
|
||||||
|
std::string single = "A";
|
||||||
|
std::string hex = toHex(single);
|
||||||
|
std::string result = fromHex(hex);
|
||||||
|
|
||||||
|
REQUIRE(result == single);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Non-printable ASCII characters", "[hex]") {
|
||||||
|
std::string nonPrintable;
|
||||||
|
for (char c = 0; c < 32; ++c) {
|
||||||
|
nonPrintable += c;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string hex = toHex(nonPrintable);
|
||||||
|
std::string result = fromHex(hex);
|
||||||
|
|
||||||
|
REQUIRE(result == nonPrintable);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Extended ASCII characters", "[hex]") {
|
||||||
|
std::string extended;
|
||||||
|
for (unsigned char c = 128; c < 255; ++c) {
|
||||||
|
extended += static_cast<char>(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string hex = toHex(extended);
|
||||||
|
std::string result = fromHex(hex);
|
||||||
|
|
||||||
|
REQUIRE(result == extended);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Hex string with lowercase and uppercase letters", "[hex]") {
|
||||||
|
std::string original = "abcABC123";
|
||||||
|
std::string hex = toHex(original);
|
||||||
|
std::string result = fromHex(hex);
|
||||||
|
|
||||||
|
REQUIRE(result == original);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Odd-length hex string should fail", "[hex]") {
|
||||||
|
std::string invalidHex = "A";
|
||||||
|
REQUIRE(fromHex(invalidHex).empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Hex string with invalid characters should fail", "[hex]") {
|
||||||
|
std::string invalidHex = "ZZ";
|
||||||
|
REQUIRE(fromHex(invalidHex).empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Large string conversion", "[hex]") {
|
||||||
|
std::string large(10000, 'x');
|
||||||
|
std::string hex = toHex(large);
|
||||||
|
std::string result = fromHex(hex);
|
||||||
|
|
||||||
|
REQUIRE(result == large);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user