Skip to content

Commit ad9357c

Browse files
proxictMarek Bogusovsky
authored and
Marek Bogusovsky
committed
Initial commit
0 parents  commit ad9357c

File tree

9 files changed

+386
-0
lines changed

9 files changed

+386
-0
lines changed

.clang-format

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
---
2+
AccessModifierOffset: '-4'
3+
AlignAfterOpenBracket: 'true'
4+
AlignConsecutiveAssignments: 'false'
5+
AlignConsecutiveDeclarations: 'false'
6+
AlignEscapedNewlinesLeft: 'false'
7+
AlignOperands: 'true'
8+
AlignTrailingComments: 'true'
9+
AllowAllParametersOfDeclarationOnNextLine: 'false'
10+
AllowShortBlocksOnASingleLine: 'false'
11+
AllowShortCaseLabelsOnASingleLine: 'false'
12+
AllowShortFunctionsOnASingleLine: Inline
13+
AllowShortIfStatementsOnASingleLine: 'false'
14+
AllowShortLoopsOnASingleLine: 'false'
15+
AlwaysBreakAfterDefinitionReturnType: None
16+
17+
AlwaysBreakAfterReturnType: None
18+
AlwaysBreakBeforeMultilineStrings: 'true'
19+
AlwaysBreakTemplateDeclarations: 'true'
20+
BinPackArguments: 'false'
21+
BinPackParameters: 'false'
22+
BreakAfterJavaFieldAnnotations: 'false'
23+
BreakBeforeBinaryOperators: None
24+
BreakBeforeBraces: Attach
25+
BreakBeforeTernaryOperators: 'true'
26+
BreakConstructorInitializersBeforeComma: 'true'
27+
BreakStringLiterals: 'true'
28+
ColumnLimit: '110'
29+
30+
ConstructorInitializerAllOnOneLineOrOnePerLine: 'false'
31+
ConstructorInitializerIndentWidth: '4'
32+
Cpp11BracedListStyle: 'false'
33+
DerivePointerAlignment: 'false'
34+
DisableFormat: 'false'
35+
ExperimentalAutoDetectBinPacking: 'false'
36+
IndentCaseLabels: 'false'
37+
IndentWidth: '4'
38+
IndentWrappedFunctionNames: 'false'
39+
JavaScriptQuotes: Leave
40+
KeepEmptyLinesAtTheStartOfBlocks: 'false'
41+
Language: Cpp
42+
MaxEmptyLinesToKeep: '1'
43+
NamespaceIndentation: Inner
44+
ObjCBlockIndentWidth: '4'
45+
PointerAlignment: Left
46+
ReflowComments: 'true'
47+
SortIncludes: 'true'
48+
SpaceAfterCStyleCast: 'false'
49+
SpaceBeforeAssignmentOperators: 'true'
50+
SpaceBeforeParens: ControlStatements
51+
SpaceInEmptyParentheses: 'false'
52+
SpacesInAngles: 'false'
53+
SpacesInCStyleCastParentheses: 'false'
54+
SpacesInContainerLiterals: 'false'
55+
SpacesInParentheses: 'false'
56+
SpacesInSquareBrackets: 'false'
57+
Standard: Cpp11
58+
TabWidth: '4'
59+
UseTab: Never
60+
PenaltyBreakComment: 130
61+
PenaltyBreakString: 1000
62+
63+
64+
IncludeCategories:
65+
- Regex: '^(<|"(gtest|isl|json)/)'
66+
Priority: 1
67+
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
68+
Priority: 2
69+
- Regex: '.\*'
70+
Priority: 3
71+
72+
...

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build

CMakeLists.txt

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
cmake_minimum_required(VERSION 3.0)
2+
project(constexpr-string VERSION 1.0.0 LANGUAGES CXX)
3+
set(platform ${CMAKE_SYSTEM_NAME})
4+
5+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -fPIC -fvisibility=hidden -Wno-stringop-overflow")
6+
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -Wextra -pedantic -pg -fprofile-arcs -Wno-stringop-overflow")
7+
8+
set(CMAKE_CXX_STANDARD 11)
9+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
10+
set(CMAKE_CXX_EXTENSIONS OFF)
11+
12+
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
13+
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
14+
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
15+
16+
add_library(constexpr-string INTERFACE)
17+
18+
target_include_directories(constexpr-string
19+
INTERFACE include
20+
)
21+
22+
if (BUILD_TESTS)
23+
add_subdirectory(test)
24+
endif()
25+

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2019 Marek Bogusovsky
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
![GitHub](https://img.shields.io/github/license/proxict/constexpr-string)
2+
3+
constexpr-string
4+
------------
5+
6+
This library provides a `ConstexprString` class which gives you the possibility to work with your strings in compile-time.
7+
8+
The class implements:
9+
- iterator over all string characters
10+
- size getter
11+
- concatenation with other strings
12+
- equality comparator
13+
- find
14+
- substr
15+
16+
Integration with CMake
17+
----------------------------
18+
```cmake
19+
add_subdirectory(external/constexpr-string)
20+
target_link_libraries(your-target
21+
PRIVATE constexpr-string
22+
)
23+
```
24+
25+
Tests can be allowed by setting `BUILD_TESTS` variable to `TRUE`:
26+
```bash
27+
mkdir -p build && cd build
28+
cmake -DBUILD_TESTS=1 ..
29+
```
30+
31+
How to use?
32+
-----------
33+
Just include the header and you're ready to go:
34+
```c++
35+
#include <iostream>
36+
#include <constexpr-string/constexpr-string.hpp>
37+
38+
struct IsHexChar {
39+
constexpr bool operator()(const char c) const {
40+
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
41+
}
42+
};
43+
44+
int main() {
45+
constexpr auto hexStr = String("8dd42e58184249a1974295b4bb97de9a");
46+
static_assert((hexStr.size() & 1) == 0, "This string must have even length");
47+
static_assert(hexStr.allOf(IsHexChar()), "This string may contain hex chars only");
48+
std::cout << hexStr.cStr() << std::endl;
49+
}
50+
```

compile_flags.txt

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
--language
2+
c++
3+
-std=c++11
4+
-Iinclude
5+
-Wall
6+
-Wextra
7+
-Wno-stringop-overflow
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
#ifndef PROXICT_CONSTEXPR_STRING_HPP_
2+
#define PROXICT_CONSTEXPR_STRING_HPP_
3+
#include <iostream>
4+
#include <type_traits>
5+
6+
template <bool TTest, typename TType = void>
7+
using EnableIf = typename std::enable_if<TTest, TType>::type;
8+
9+
template <int... Indices>
10+
struct IntSequence {};
11+
12+
template <typename T>
13+
struct append;
14+
15+
template <int... Indices>
16+
struct append<IntSequence<Indices...>> {
17+
using type = IntSequence<Indices..., sizeof...(Indices)>;
18+
};
19+
20+
template <int TSize>
21+
struct MakeIntSequenceImpl;
22+
23+
template <>
24+
struct MakeIntSequenceImpl<0> {
25+
using type = IntSequence<>;
26+
};
27+
28+
template <int TSize>
29+
using MakeIntSequence = typename MakeIntSequenceImpl<TSize>::type;
30+
31+
template <int TSize>
32+
struct MakeIntSequenceImpl : append<MakeIntSequence<TSize - 1>> {
33+
static_assert(TSize >= 0, "Integer sequence size must be positive");
34+
};
35+
36+
constexpr int cstrlen(const char* str) {
37+
return *str ? 1 + cstrlen(str + 1) : 0;
38+
}
39+
40+
constexpr bool cstreq(const char* a, const char* b) {
41+
return *a == *b && (*a == 0 || cstreq(a + 1, b + 1));
42+
}
43+
44+
template <int TSize>
45+
class ConstexprString final {
46+
public:
47+
static_assert(TSize >= -1, "Invalid string size");
48+
49+
constexpr explicit ConstexprString(const char* data)
50+
: ConstexprString(data, MakeIntSequence<TSize>()) {}
51+
52+
constexpr char operator[](const int index) const { return mData[index]; }
53+
54+
template <int TOtherSize, typename = EnableIf<TOtherSize <= TSize>>
55+
constexpr ConstexprString(const ConstexprString<TOtherSize>& s1,
56+
const ConstexprString<TSize - TOtherSize>& s2)
57+
: ConstexprString{ s1, s2, MakeIntSequence<TOtherSize>{}, MakeIntSequence<TSize - TOtherSize>{} } {}
58+
59+
constexpr const char* cStr() const noexcept { return mData; }
60+
61+
constexpr int size() const { return TSize; }
62+
63+
template <typename TPredicate>
64+
constexpr bool allOf(TPredicate&& p) const {
65+
return allOfInternal(0, p);
66+
}
67+
68+
template <int TOtherSize>
69+
constexpr ConstexprString<TSize + TOtherSize> operator+(const ConstexprString<TOtherSize>& rhs) const {
70+
return ConstexprString<TSize + TOtherSize>(*this, rhs);
71+
}
72+
73+
template <int TFrom, int TTo = TSize, typename = EnableIf<TFrom <= TTo>>
74+
constexpr ConstexprString<TTo - TFrom> substr() const {
75+
return ConstexprString<TTo - TFrom>(mData + TFrom, MakeIntSequence<TTo - TFrom>{});
76+
}
77+
78+
template <int TOtherSize>
79+
constexpr bool operator==(const ConstexprString<TOtherSize>& rhs) const {
80+
return size() == rhs.size() && cstreq(cStr(), rhs.cStr());
81+
}
82+
83+
template <int TOtherSize>
84+
constexpr bool operator!=(const ConstexprString<TOtherSize>& rhs) const {
85+
return !(*this == rhs);
86+
}
87+
88+
template <int TOtherSize, typename = EnableIf<TOtherSize - 1 <= TSize>>
89+
constexpr int find(char const (&str)[TOtherSize], const int pos = 0) const {
90+
return findInternal(pos, 0, str);
91+
}
92+
93+
constexpr int find(const char c, const int pos = 0) const { return findInternal(pos, c); }
94+
95+
constexpr const char* begin() const {
96+
return mData;
97+
}
98+
99+
constexpr const char* end() const {
100+
return mData + TSize;
101+
}
102+
103+
private:
104+
constexpr int findInternal(int index, const char c) const {
105+
return index < TSize ? (mData[index] == c ? index : findInternal(index + 1, c)) : -1;
106+
}
107+
108+
template <int TOtherSize>
109+
constexpr int findInternal(int index, int index2, char const (&str)[TOtherSize]) const {
110+
// clang-format off
111+
return index2 == TOtherSize - 1
112+
? index - TOtherSize + 1
113+
: (index < TSize ? (mData[index] == str[index2] ? findInternal(index + 1, index2 + 1, str) : findInternal(index + 1 - index2, 0, str)) : -1);
114+
// clang-format on
115+
}
116+
117+
template <int TNewSize>
118+
friend class ConstexprString;
119+
120+
template <typename TPredicate>
121+
constexpr bool allOfInternal(const int index, TPredicate&& p) const {
122+
return index < TSize ? (p(mData[index]) ? allOfInternal(index + 1, p) : false) : true;
123+
}
124+
125+
template <int... TPack>
126+
constexpr ConstexprString(const char* str, IntSequence<TPack...>)
127+
: mData{ str[TPack]..., '\0' } {}
128+
129+
template <int TOtherSize, int... TPack1, int... TPack2>
130+
constexpr ConstexprString(const ConstexprString<TOtherSize>& lhs,
131+
const ConstexprString<TSize - TOtherSize>& rhs,
132+
IntSequence<TPack1...>,
133+
IntSequence<TPack2...>)
134+
: mData{ lhs[TPack1]..., rhs[TPack2]..., '\0' } {}
135+
136+
char mData[TSize + 1];
137+
};
138+
139+
template <int TSize>
140+
constexpr ConstexprString<TSize - 1> String(char const (&str)[TSize]) {
141+
return ConstexprString<TSize - 1>(str);
142+
}
143+
144+
#endif // PROXICT_CONSTEXPR_STRING_HPP_

test/CMakeLists.txt

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
add_executable(unittests
2+
main.cpp
3+
)
4+
5+
target_link_libraries(unittests
6+
PRIVATE constexpr-string
7+
)

test/main.cpp

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#include <constexpr-string/constexpr-string.hpp>
2+
3+
#include <cstdio>
4+
5+
struct IsLowerCase {
6+
constexpr bool operator()(const char c) const { return c == ' ' || (c >= 'a' && c <= 'z'); }
7+
};
8+
9+
struct IsHexChar {
10+
constexpr bool operator()(const char c) const {
11+
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
12+
}
13+
};
14+
15+
int main() {
16+
constexpr auto hexStr = String("8dd42e58184249a1974295b4bb97de9a");
17+
static_assert((hexStr.size() & 1) == 0, "String must have even length");
18+
static_assert(hexStr.allOf(IsHexChar()), "String may contain hex chars only");
19+
20+
constexpr auto str = String("this is a test");
21+
static_assert(str.size() == 14, "Size failed");
22+
static_assert(str.allOf(IsLowerCase()), "Everything must be lowercase");
23+
24+
constexpr auto prefix = String("I think ");
25+
constexpr auto postfix = String(" string.");
26+
static constexpr auto sentence = prefix + str + postfix;
27+
28+
static_assert(sentence.size() == prefix.size() + str.size() + postfix.size(), "Concatenation failed");
29+
static_assert(sentence == String("I think this is a test string."), "");
30+
static_assert(sentence[sentence.size()] == 0, "String must be null terminated");
31+
32+
static_assert(sentence.substr<0, 1>() == String("I"), "substr failed");
33+
static_assert(sentence.substr<8, 22>() == String("this is a test"), "substr failed");
34+
static_assert(sentence.substr<23>() == String("string."), "substr failed");
35+
36+
static_assert(sentence.find('I') == 0, "find failed");
37+
static_assert(sentence.find('t') == 2, "find failed");
38+
static_assert(sentence.find('!') == -1, "find failed");
39+
static_assert(sentence.find('.') == sentence.size() - 1, "find failed");
40+
41+
static_assert(sentence.find('k', 6) == 6, "find failed");
42+
static_assert(sentence.find('k', 7) == -1, "find failed");
43+
static_assert(sentence.find('t', 0) == 2, "find failed");
44+
static_assert(sentence.find('t', 10) == 18, "find failed");
45+
static_assert(sentence.find("think", 0) == 2, "find failed");
46+
static_assert(sentence.find("think", 3) == -1, "find failed");
47+
static_assert(sentence.find("is", 5) == 10, "find failed");
48+
static_assert(sentence.find("is", 11) == 13, "find failed");
49+
50+
static_assert(sentence.find("abc") == -1, "find failed");
51+
static_assert(sentence.find("I think") == 0, "find failed");
52+
static_assert(sentence.find("think") == 2, "find failed");
53+
54+
static_assert(sentence.substr<8, 22>().find(" is a test") == 4, "find failed");
55+
static_assert(sentence.substr<8, 22>().find("is a test") == 5, "find failed");
56+
static_assert(sentence.substr<8, 22>().find("s a test") == 6, "find failed");
57+
58+
puts("Passed");
59+
}

0 commit comments

Comments
 (0)