Start StringUtils, update build, add CLion config for code style.

This commit is contained in:
Kyle Isom 2023-10-14 17:56:26 -07:00
parent b28199553f
commit dd696e2c1f
19 changed files with 500 additions and 16 deletions

1
.gitignore vendored
View File

@ -1,4 +1,3 @@
.idea
.trunk .trunk
.vc .vc
.vscode .vscode

8
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@ -0,0 +1,42 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<Objective-C>
<option name="INDENT_NAMESPACE_MEMBERS" value="0" />
<option name="INDENT_C_STRUCT_MEMBERS" value="8" />
<option name="INDENT_CLASS_MEMBERS" value="8" />
<option name="FUNCTION_BRACE_PLACEMENT" value="2" />
<option name="FUNCTION_TOP_AFTER_RETURN_TYPE_WRAP" value="2" />
</Objective-C>
<files>
<extensions>
<pair source="cc" header="h" fileNamingConvention="PASCAL_CASE" />
<pair source="c" header="h" fileNamingConvention="NONE" />
<pair source="cu" header="cuh" fileNamingConvention="NONE" />
<pair source="ixx" header="" fileNamingConvention="NONE" />
<pair source="mxx" header="" fileNamingConvention="NONE" />
<pair source="cppm" header="" fileNamingConvention="NONE" />
<pair source="ccm" header="" fileNamingConvention="NONE" />
<pair source="cxxm" header="" fileNamingConvention="NONE" />
<pair source="c++m" header="" fileNamingConvention="NONE" />
</extensions>
</files>
<codeStyleSettings language="ObjectiveC">
<option name="BLANK_LINES_BEFORE_IMPORTS" value="2" />
<option name="BLANK_LINES_AFTER_IMPORTS" value="2" />
<option name="BLANK_LINES_AROUND_METHOD" value="0" />
<option name="BLANK_LINES_AROUND_METHOD_IN_INTERFACE" value="0" />
<option name="INDENT_CASE_FROM_SWITCH" value="false" />
<option name="ALIGN_GROUP_FIELD_DECLARATIONS" value="true" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<indentOptions>
<option name="INDENT_SIZE" value="8" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="8" />
<option name="USE_TAB_CHARACTER" value="true" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>

View File

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

6
.idea/copyright/ISC.xml Normal file
View File

@ -0,0 +1,6 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="Copyright &amp;#36;today.year K. Isom &lt;kyle@imap.cc&gt;&#10;&#10;Permission to use, copy, modify, and/or distribute this software for&#10;any purpose with or without fee is hereby granted, provided that the&#10;above copyright notice and this permission notice appear in all copies.&#10;&#10;THE SOFTWARE IS PROVIDED &quot;AS IS&quot; AND THE AUTHOR DISCLAIMS ALL&#10;WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED&#10;WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR&#10;BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES&#10;OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,&#10;WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,&#10;ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS&#10;SOFTWARE.&#10;" />
<option name="myName" value="ISC" />
</copyright>
</component>

View File

@ -0,0 +1,11 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
<option name="processCode" value="true" />
<option name="processLiterals" value="true" />
<option name="processComments" value="true" />
</inspection_tool>
</profile>
</component>

2
.idea/klib.iml Normal file
View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<module classpath="CMake" type="CPP_MODULE" version="4" />

4
.idea/misc.xml Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
</project>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/klib.iml" filepath="$PROJECT_DIR$/.idea/klib.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@ -346,7 +346,7 @@ uint8_t &
Arena::operator[](size_t index) Arena::operator[](size_t index)
{ {
if (index > this->size) { if (index > this->size) {
#if defined(DESKTOP_BUILD) and !defined(KLIB_NO_ASSERT) #if defined(KLIB_DESKTOP_BUILD) and !defined(KLIB_NO_ASSERT)
throw std::range_error("index out of range"); throw std::range_error("index out of range");
#else #else
abort(); abort();

View File

@ -330,7 +330,7 @@ uint8_t &
Buffer::operator[](size_t index) Buffer::operator[](size_t index)
{ {
if (index > this->length) { if (index > this->length) {
#if defined(DESKTOP_BUILD) and !defined(KLIB_NO_ASSERT) #if defined(KLIB_DESKTOP_BUILD) and !defined(KLIB_NO_ASSERT)
throw std::range_error("array index out of bounds"); throw std::range_error("array index out of bounds");
#else #else
abort(); abort();

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.25) cmake_minimum_required(VERSION 3.25)
project(klib LANGUAGES CXX project(klib LANGUAGES CXX
VERSION 0.0.1 VERSION 0.1.0
DESCRIPTION "Kyle's C++ library") DESCRIPTION "Kyle's C++ library")
set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD 14)
@ -25,27 +25,29 @@ else ()
# nothing special for gcc at the moment # nothing special for gcc at the moment
endif () endif ()
endif () endif ()
add_compile_options("-DDESKTOP_BUILD") add_compile_definitions(DKLIB_DESKTOP_BUILD)
add_compile_definitions(KLIB_VERSION=${PROJECT_VERSION})
set(HEADER_FILES set(HEADER_FILES klib.h
klib.h
Arena.h Arena.h
Buffer.h Buffer.h
Dictionary.h Dictionary.h
Exceptions.h Exceptions.h
Test.h StringUtil.h
TLV.h TLV.h
Test.h
WinHelpers.h) WinHelpers.h)
set(SOURCE_FILES set(SOURCE_FILES
Arena.cc Arena.cc
Buffer.cc Buffer.cc
Dictionary.cc
Exceptions.cc
Test.cc
TLV.cc
Commander.cc Commander.cc
Commander.h Commander.h
Dictionary.cc
Exceptions.cc
StringUtil.cc
TLV.cc
Test.cc
WinHelpers.cc) WinHelpers.cc)
if (APPLE) if (APPLE)
@ -76,6 +78,10 @@ add_executable(buffer_test bufferTest.cc)
target_link_libraries(buffer_test klib) target_link_libraries(buffer_test klib)
add_test(bufferTest buffer_test) add_test(bufferTest buffer_test)
add_executable(stringutil_test stringutil_test.cc)
target_link_libraries(stringutil_test klib)
add_test(stringutilTest stringutil_test)
include(CMakePackageConfigHelpers) include(CMakePackageConfigHelpers)
write_basic_package_version_file( write_basic_package_version_file(
klibConfig.cmake klibConfig.cmake

View File

@ -2,7 +2,7 @@
#include <cstdlib> #include <cstdlib>
#include "Dictionary.h" #include "Dictionary.h"
#if defined(DESKTOP_BUILD) #if defined(KLIB_DESKTOP_BUILD)
#include <iostream> #include <iostream>
#endif #endif
@ -133,7 +133,7 @@ Dictionary::spaceAvailable(uint8_t klen, uint8_t vlen)
std::ostream & std::ostream &
operator<<(std::ostream &os, const Dictionary &dictionary) operator<<(std::ostream &os, const Dictionary &dictionary)
{ {
#if defined(DESKTOP_BUILD) #if defined(KLIB_DESKTOP_BUILD)
uint8_t *cursor = (dictionary.arena).NewCursor(); uint8_t *cursor = (dictionary.arena).NewCursor();
TLV::Record rec; TLV::Record rec;

View File

@ -5,7 +5,7 @@ SOURCES := $(wildcard *.cc)
OBJS := Arena.o Dictionary.o TLV.o OBJS := Arena.o Dictionary.o TLV.o
CXX := clang++ CXX := clang++
CXXFLAGS := -g -std=c++14 -Werror -Wall -DDESKTOP_BUILD CXXFLAGS := -g -std=c++14 -Werror -Wall -DKLIB_DESKTOP_BUILD
.PHONY: all .PHONY: all
all: $(TARGET) $(TESTS) tags run-tests all: $(TARGET) $(TESTS) tags run-tests

165
StringUtil.cc Normal file
View File

@ -0,0 +1,165 @@
#include <iostream>
#include <sstream>
#include "StringUtil.h"
namespace klib {
/// namespace U contains utilities.
namespace U {
/// namespace S contains string-related functions.
namespace S {
/*
std::vector<std::string>
SplitKeyValuePair(std::string line, std::string delimiter)
{
std::string key;
std::string val;
auto pos = line.find(delimiter);
if (pos == std::string::npos) {
key = line;
val = "";
} else {
key = line.substr(0, pos);
val = line.substr(pos + 1, line.size() - pos - 2);
}
TrimWhitespace(key);
TrimWhitespace(val);
return {key, val};
}
std::vector<std::string>
SplitKeyValuePair(std::string line, char delimiter)
{
std::string key;
std::string val;
auto pos = line.find(delimiter);
if (pos == std::string::npos) {
key = line;
val = "";
} else {
key = line.substr(0, pos);
val = line.substr(pos + 1, line.size() - pos - 2);
}
TrimWhitespace(key);
TrimWhitespace(val);
return {key, val};
}
*/
void
TrimLeadingWhitespace(std::string &s)
{
s.erase(s.begin(),
std::find_if(s.begin(), s.end(),
[](unsigned char ch) {
return !std::isspace(ch);
}));
}
void
TrimTrailingWhitespace(std::string &s)
{
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
return !std::isspace(ch);
}).base(), s.end());
}
void
TrimWhitespace(std::string &s)
{
TrimLeadingWhitespace(s);
TrimTrailingWhitespace(s);
}
std::string
TrimLeadingWhitespaceDup(std::string s)
{
TrimLeadingWhitespace(s);
return s;
}
std::string
TrimTrailingWhitespaceDup(std::string s)
{
TrimTrailingWhitespace(s);
return s;
}
std::string
TrimWhitespaceDup(std::string s)
{
TrimWhitespace(s);
return s;
}
std::vector<std::string>
SplitN(std::string s, std::string delim, size_t maxCount)
{
std::vector<std::string> parts;
size_t ss = 0;
size_t se = 0;
for (ss = 0; s.size() != 0 && ss < s.size(); ss++) {
se = s.find(delim, ss);
if ((maxCount > 0) && (parts.size() == maxCount - 1)) {
se = s.size();
} else if (se == std::string::npos) {
se = s.size();
}
auto length = se - ss;
parts.push_back(s.substr(ss, length));
ss = se;
}
return parts;
}
std::ostream &
VectorToString(std::ostream &os, const std::vector<std::string> &svec)
{
os << "(";
os << svec.size();
os << ")";
os << "{";
for (size_t i = 0; i < svec.size(); i++) {
if (i > 0) os << ", ";
os << svec[i];
}
os << "}";
return os;
}
std::string
VectorToString(const std::vector<std::string> &svec)
{
std::stringstream ss;
VectorToString(ss, svec);
return ss.str();
}
} // namespace S
} // namespace U
} // namespace klib

105
StringUtil.h Normal file
View File

@ -0,0 +1,105 @@
///
/// \file StringUtil.h
/// \author kyle (kyle@midgard)
/// \created 2023-10-14
/// \brief StringUtil contains string utilities.
///
/// \section COPYRIGHT
/// Copyright 2023 K. Isom <kyle@imap.cc>
///
/// Permission to use, copy, modify, and/or distribute this software for
/// any purpose with or without fee is hereby granted, provided that the
/// above copyright notice and this permission notice appear in all copies.
///
/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
/// BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
/// OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
/// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
/// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
/// SOFTWARE.
///
#include <algorithm>
#include <string>
#include <vector>
#ifndef STRINGUTIL_H
#define STRINGUTIL_H
namespace klib {
/// namespace U contains utilities.
namespace U {
/// namespace S contains string-related functions.
namespace S {
/// Remove any whitespace at the beginning of the string. The string
/// is modified in-place.
void TrimLeadingWhitespace(std::string &s);
/// Remove any whitespace at the end of the string. The string is
/// modified in-place.
void TrimTrailingWhitespace(std::string &s);
/// Remove any whitespace at the beginning and end of the string. The
/// string is modified in-place.
void TrimWhitespace(std::string &s);
/// Remove any whitespace at the beginning of the string. The original
/// string isn't modified, and a copy is returned.
std::string TrimLeadingWhitespaceDup(std::string s);
/// Remove any whitespace at the end of the string. The original string
/// isn't modified, and a copy is returned.
std::string TrimTrailingWhitespaceDup(std::string s);
/// Remove any whitespace at the beginning and end of the string. The
/// original string isn't modified, and a copy is returned.
std::string TrimWhitespaceDup(std::string s);
/// Split a line into key and value pairs. If the delimiter isn't found,
/// the line is returned as the first element in the pair, and the second
/// element will be empty.
///
/// \param line A string representing a line in a file.
/// \param delimiter The string delimiter between the key and value.
/// \return The key and value, or {line, ""}.
std::vector<std::string> SplitKeyValuePair(std::string line, std::string delimiter);
/// Split a line into key and value pairs. If the delimiter isn't found,
/// the line is returned as the first element in the pair, and the second
/// element will be empty.
///
/// \param line A string representing a line in a file.
/// \param delimiter The character delimiter between the key and value.
/// \return The key and value.
std::vector<std::string> SplitKeyValuePair(std::string line, char delimiter);
std::vector<std::string> Split(std::string, std::string delimiter);
std::vector<std::string> Split(std::string, char delimiter);
std::vector<std::string> SplitN(std::string, std::string delimiter, size_t maxCount=0);
//std::vector<std::string> SplitN(std::string, char delimiter, size_t size_t maxCount=0);
std::ostream &VectorToString(std::ostream &os, const std::vector<std::string> &svec);
std::string VectorToString(const std::vector<std::string> &svec);
} // namespace S
} // namespace U
} // namespace klib
#endif // STRINGUTIL_H

View File

@ -13,7 +13,7 @@
namespace klib { namespace klib {
void void
TestAssert(bool condition, std::string message = "Assertion failed.") TestAssert(bool condition, std::string message)
{ {
#if defined(NDEBUG) || defined(KLIB_NO_ASSERT) #if defined(NDEBUG) || defined(KLIB_NO_ASSERT)
if (!condition) { if (!condition) {

117
stringutil_test.cc Normal file
View File

@ -0,0 +1,117 @@
///
/// \file stringutil_test.cc
/// \author kyle
/// \created 10/14/23
/// \brief Ensure the stringutil functions work.
///
/// \section COPYRIGHT
/// Copyright 2023 K. Isom <kyle@imap.cc>
///
/// Permission to use, copy, modify, and/or distribute this software for
/// any purpose with or without fee is hereby granted, provided that the
/// above copyright notice and this permission notice appear in all copies.
///
/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
/// BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
/// OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
/// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
/// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
/// SOFTWARE.
///
#include <iostream>
#include <sstream>
#include "StringUtil.h"
#include "Test.h"
using namespace klib;
static void
TestTrimming(std::string line, std::string lExpected, std::string rExpected, std::string expected)
{
std::string result;
std::string message;
result = U::S::TrimLeadingWhitespaceDup(line);
message = "TrimLeadingDup(\"" + line + "\"): '" + result + "'";
TestAssert(result == lExpected, message);
result = U::S::TrimTrailingWhitespaceDup(line);
message = "TrimTrailingDup(\"" + line + "\"): '" + result + "'";
TestAssert(result == rExpected, message);
result = U::S::TrimWhitespaceDup(line);
message = "TrimDup(\"" + line + "\"): '" + result + "'";
TestAssert(result == expected, message);
result = line;
U::S::TrimLeadingWhitespace(result);
message = "TrimLeadingDup(\"" + line + "\"): '" + result + "'";
TestAssert(result == lExpected, message);
result = line;
U::S::TrimTrailingWhitespace(result);
message = "TrimTrailingDup(\"" + line + "\"): '" + result + "'";
TestAssert(result == rExpected, message);
result = line;
U::S::TrimWhitespace(result);
message = "TrimDup(\"" + line + "\"): '" + result + "'";
TestAssert(result == expected, message);
}
static std::string
vec2string(std::vector<std::string> v)
{
std::stringstream ss;
ss << "(";
ss << v.size();
ss << ")";
ss << "{";
for (size_t i = 0; i < v.size(); i++) {
if (i > 0) ss << ", ";
ss << v[i];
}
ss << "}";
return ss.str();
}
static void
TestSplit(std::string line, std::string delim, size_t maxCount, std::vector<std::string> expected)
{
std::cout << "test split\n";
std::cout << "\t line: \"" << line << "\"\n";
std::cout << "\t delim: \"" << delim << "\"\n";
std::cout << "\t count: " << maxCount << "\n";
std::cout << "\texpect: " << vec2string(expected) << "\n";
auto result = U::S::SplitN(line, delim, maxCount);
std::cout << "\tresult: " << U::S::VectorToString(result) << "\n";
TestAssert(result == expected, U::S::VectorToString(result));
std::cout << "OK!\n";
}
int
main()
{
TestTrimming(" foo\t ", "foo\t ", " foo", "foo");
TestTrimming(" foo\tbar ", "foo\tbar ", " foo\tbar", "foo\tbar");
TestSplit("abc:def:ghij:klm", ":", 0,
std::vector<std::string>{"abc", "def", "ghij", "klm"});
TestSplit("abc:def:ghij:klm", ":", 3,
std::vector<std::string>{"abc", "def", "ghij:klm"});
TestSplit("abc:def:ghij:klm", ":", 2,
std::vector<std::string>{"abc", "def:ghij:klm"});
TestSplit("abc:def:ghij:klm", ":", 1,
std::vector<std::string>{"abc:def:ghij:klm"});
}