Skip to content

Commit 6815f9a

Browse files
committed
Use smart pointers in child list
1 parent cd88d54 commit 6815f9a

File tree

16 files changed

+155
-123
lines changed

16 files changed

+155
-123
lines changed

.github/workflows/test.yml

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,31 +17,29 @@ jobs:
1717
fail-fast: false
1818
matrix:
1919
compiler: [native, llvm]
20-
os: [ubuntu-latest, macos-latest, windows-latest]
21-
exclude:
22-
- os: macos-latest
23-
compiler: native
20+
os: [ubuntu-latest, windows-latest]
21+
2422
steps:
2523
- name: Checkout code
2624
uses: actions/checkout@v4
2725

2826
- name: Install CMake
2927
uses: lukka/get-cmake@latest
3028

31-
- name: Install LLVM and Clang
32-
uses: KyleMayes/install-llvm-action@v2
33-
with:
34-
version: "20"
35-
env: true
36-
if: ${{ matrix.compiler == 'llvm'}}
29+
- name: Use LLVM and Clang for Linux
30+
run: |
31+
echo "CC=clang-18" >> $GITHUB_ENV
32+
echo "CXX=clang++-18" >> $GITHUB_ENV
33+
if: ${{ matrix.os == 'ubuntu-latest' && matrix.compiler != 'native'}}
3734

38-
- name: Configure for native compiler
39-
run: cmake -B build -DCPPSPEC_BUILD_TESTS=YES
40-
if: ${{ matrix.compiler == 'native'}}
35+
- name: Use LLVM and Clang for Windows
36+
run: |
37+
echo "CC=clang" >> $GITHUB_ENV
38+
echo "CXX=clang++" >> $GITHUB_ENV
39+
if: ${{ matrix.os == 'windows-latest' && matrix.compiler != 'native'}}
4140

42-
- name: Configure for non-native compiler
43-
run: cmake -B build -G Ninja -DCPPSPEC_BUILD_TESTS=YES -DCMAKE_C_COMPILER="$CC" -DCMAKE_CXX_COMPILER="$CXX"
44-
if: ${{ matrix.compiler != 'native'}}
41+
- name: Configure
42+
run: cmake -B build -DCPPSPEC_BUILD_TESTS=YES
4543

4644
- name: Build
4745
run: cmake --build build --config Release

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
build*
2+
.cache
3+
.vscode

.pre-commit-config.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,3 @@ repos:
88
hooks:
99
- id: clang-format
1010
types_or: [c, c++]
11-
files: 'include/.*(?<!\.hpp)$'

CMakeLists.txt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@ target_link_libraries(c++spec INTERFACE
3939
cxx-prettyprint
4040
argparse
4141
)
42-
target_compile_options(c++spec INTERFACE -Wno-missing-template-arg-list-after-template-kw -Wno-dollar-in-identifier-extension)
42+
43+
if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
44+
target_compile_options(c++spec INTERFACE -Wno-missing-template-arg-list-after-template-kw -Wno-dollar-in-identifier-extension)
45+
endif()
4346

4447
FILE(GLOB_RECURSE c++spec_headers ${CMAKE_CURRENT_LIST_DIR}/include/*.hpp)
4548

@@ -57,7 +60,7 @@ function(add_spec source_file)
5760
cmake_path(GET source_file STEM spec_name)
5861
add_executable(${spec_name} ${source_file})
5962
target_link_libraries(${spec_name} c++spec)
60-
63+
target_compile_features(${spec_name} PRIVATE cxx_std_23)
6164
set_target_properties(${spec_name} PROPERTIES
6265
CXX_STANDARD 23
6366
CXX_STANDARD_REQUIRED YES

examples/CMakeLists.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
add_compile_options(-Wall -Wextra -Wpedantic)
1+
set(CMAKE_CXX_STANDARD 23)
2+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
3+
4+
if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
5+
add_compile_options(-Wall -Wextra -Wpedantic)
6+
endif()
27

38
add_subdirectory(sample)
49
#add_subdirectory(skip)

include/class_description.hpp

Lines changed: 61 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,27 @@ class ClassDescription : public Description {
4343
std::source_location location = std::source_location::current())
4444
: Description(location, description), block(block), subject(T()) {}
4545

46-
ClassDescription(T subject, Block block, std::source_location location = std::source_location::current())
46+
ClassDescription(const char* description,
47+
T& subject,
48+
Block block,
49+
std::source_location location = std::source_location::current())
50+
: Description(location, description), block(block), subject(subject) {}
51+
52+
template <Util::not_c_string U>
53+
ClassDescription(U& subject, Block block, std::source_location location = std::source_location::current())
4754
: Description(location, Pretty::to_word(subject)),
4855
block(block),
4956
type(" : " + Util::demangle(typeid(T).name())),
5057
subject(subject) {}
5158

5259
ClassDescription(const char* description,
53-
T subject,
60+
T&& subject,
5461
Block block,
5562
std::source_location location = std::source_location::current())
56-
: Description(location, description), block(block), subject(subject) {}
63+
: Description(location, description), block(block), subject(std::move(subject)) {}
5764

58-
ClassDescription(T&& subject, Block block, std::source_location location = std::source_location::current())
65+
template <Util::not_c_string U>
66+
ClassDescription(U&& subject, Block block, std::source_location location = std::source_location::current())
5967
: Description(location, Pretty::to_word(subject)),
6068
block(block),
6169
type(" : " + Util::demangle(typeid(T).name())),
@@ -89,53 +97,59 @@ class ClassDescription : public Description {
8997

9098
template <class U, class B>
9199
ClassDescription<U>& context(const char* description,
92-
U subject,
100+
U& subject,
93101
B block,
94102
std::source_location location = std::source_location::current());
103+
104+
template <class U, class B>
105+
ClassDescription<U>& context(U& subject, B block, std::source_location location = std::source_location::current()) {
106+
return this->context("", subject, block, location);
107+
}
108+
95109
template <class U, class B>
96110
ClassDescription<U>& context(const char* description,
97-
U& subject,
111+
U&& subject,
98112
B block,
99113
std::source_location location = std::source_location::current());
100-
template <class U, class B>
101-
ClassDescription<U>& context(U subject, B block, std::source_location location = std::source_location::current());
102114

115+
template <class U, class B>
116+
ClassDescription<U>& context(U&& subject, B block, std::source_location location = std::source_location::current()) {
117+
return this->context("", subject, block, location);
118+
}
103119
void run() override;
104120

105121
[[nodiscard]] std::string get_subject_type() const noexcept override { return type; }
106122
};
107123

124+
template <Util::not_c_string U>
125+
ClassDescription(U&, std::function<void(ClassDescription<U>&)>, std::source_location) -> ClassDescription<U>;
126+
127+
template <Util::not_c_string U>
128+
ClassDescription(U&&, std::function<void(ClassDescription<U>&)>, std::source_location) -> ClassDescription<U>;
129+
108130
template <class T>
109131
using ClassContext = ClassDescription<T>;
110132

111133
template <class T>
112134
template <class U, class B>
113135
ClassContext<U>& ClassDescription<T>::context(const char* description,
114-
U subject,
136+
U& subject,
115137
B block,
116138
std::source_location location) {
117-
auto* context = new ClassContext<U>(description, subject, block, location);
118-
context->set_parent(this);
139+
auto* context = this->make_child<ClassContext<U>>(description, subject, block, location);
119140
context->ClassContext<U>::before_eaches = this->before_eaches;
120141
context->ClassContext<U>::after_eaches = this->after_eaches;
121142
context->timed_run();
122143
return *context;
123144
}
124145

125-
template <class T>
126-
template <class U, class B>
127-
ClassContext<U>& ClassDescription<T>::context(U subject, B block, std::source_location location) {
128-
return this->context("", std::forward<U>(subject), block, location);
129-
}
130-
131146
template <class T>
132147
template <class U, class B>
133148
ClassContext<U>& ClassDescription<T>::context(const char* description,
134-
U& subject,
149+
U&& subject,
135150
B block,
136151
std::source_location location) {
137-
auto* context = new ClassContext<U>(description, subject, block, location);
138-
context->set_parent(this);
152+
auto* context = this->make_child<ClassContext<U>>(description, subject, block, location);
139153
context->ClassContext<U>::before_eaches = this->before_eaches;
140154
context->ClassContext<U>::after_eaches = this->after_eaches;
141155
context->timed_run();
@@ -145,31 +159,43 @@ ClassContext<U>& ClassDescription<T>::context(const char* description,
145159
template <class T>
146160
template <class U, class B>
147161
ClassContext<T>& ClassDescription<T>::context(const char* description, B block, std::source_location location) {
148-
auto* context = new ClassContext<T>(description, this->subject, block, location);
149-
context->set_parent(this);
162+
auto* context = this->make_child<ClassContext<T>>(description, this->subject, block, location);
163+
context->before_eaches = this->before_eaches;
164+
context->after_eaches = this->after_eaches;
165+
context->timed_run();
166+
return *context;
167+
}
168+
169+
template <Util::not_c_string T, class B>
170+
ClassContext<T>& Description::context(T& subject, B block, std::source_location location) {
171+
auto* context = this->make_child<ClassContext<T>>(subject, block, location);
150172
context->before_eaches = this->before_eaches;
151173
context->after_eaches = this->after_eaches;
152174
context->timed_run();
153175
return *context;
154176
}
155177

156178
template <class T, class B>
157-
requires(!std::is_same_v<T, const char*>)
158-
ClassContext<T>& Description::context(T subject, B block, std::source_location location) {
159-
auto* context = new ClassContext<T>(subject, block, location);
160-
context->set_parent(this);
161-
context->set_location(location);
179+
ClassContext<T>& Description::context(const char* description, T& subject, B block, std::source_location location) {
180+
auto* context = this->make_child<ClassContext<T>>(description, subject, block, location);
181+
context->before_eaches = this->before_eaches;
182+
context->after_eaches = this->after_eaches;
183+
context->timed_run();
184+
return *context;
185+
}
186+
187+
template <Util::not_c_string T, class B>
188+
ClassContext<T>& Description::context(T&& subject, B block, std::source_location location) {
189+
auto* context = this->make_child<ClassContext<T>>(subject, block, location);
162190
context->before_eaches = this->before_eaches;
163191
context->after_eaches = this->after_eaches;
164192
context->timed_run();
165193
return *context;
166194
}
167195

168196
template <class T, class B>
169-
ClassContext<T>& Description::context(const char* description, T subject, B block, std::source_location location) {
170-
auto* context = new ClassContext<T>(description, subject, block, location);
171-
context->set_parent(this);
172-
context->set_location(location);
197+
ClassContext<T>& Description::context(const char* description, T&& subject, B block, std::source_location location) {
198+
auto* context = this->make_child<ClassContext<T>>(description, subject, block, location);
173199
context->before_eaches = this->before_eaches;
174200
context->after_eaches = this->after_eaches;
175201
context->timed_run();
@@ -180,8 +206,7 @@ template <class T, typename U>
180206
ClassContext<T>& Description::context(std::initializer_list<U> init_list,
181207
std::function<void(ClassDescription<T>&)> block,
182208
std::source_location location) {
183-
auto* context = new ClassContext<T>(T(init_list), block, location);
184-
context->set_parent(this);
209+
auto* context = this->make_child<ClassContext<T>>(T(init_list), block, location);
185210
context->before_eaches = this->before_eaches;
186211
context->after_eaches = this->after_eaches;
187212
context->timed_run();
@@ -211,7 +236,7 @@ ClassContext<T>& Description::context(std::initializer_list<U> init_list,
211236
*/
212237
template <class T>
213238
ItCD<T>& ClassDescription<T>::it(const char* name, std::function<void(ItCD<T>&)> block, std::source_location location) {
214-
auto* it = new ItCD<T>(*this, location, this->subject, name, block);
239+
auto* it = this->make_child<ItCD<T>>(location, this->subject, name, block);
215240
it->timed_run();
216241
exec_after_eaches();
217242
exec_before_eaches();
@@ -241,7 +266,7 @@ ItCD<T>& ClassDescription<T>::it(const char* name, std::function<void(ItCD<T>&)>
241266
*/
242267
template <class T>
243268
ItCD<T>& ClassDescription<T>::it(std::function<void(ItCD<T>&)> block, std::source_location location) {
244-
auto* it = new ItCD<T>(*this, location, this->subject, block);
269+
auto* it = this->make_child<ItCD<T>>(location, this->subject, block);
245270
it->timed_run();
246271
exec_after_eaches();
247272
exec_before_eaches();
@@ -256,17 +281,10 @@ void ClassDescription<T>::run() {
256281
}
257282
}
258283

259-
template <class T>
260-
ExpectationValue<T> ItCD<T>::is_expected() {
261-
auto cd = this->get_parent_as<ClassDescription<T>>();
262-
ExpectationValue<T> expectation(*this, cd->subject, std::source_location::current());
263-
return expectation;
264-
}
265-
266284
template <class T>
267285
void ItCD<T>::run() {
268286
this->block(*this);
269-
auto cd = this->get_parent_as<ClassDescription<T>>();
287+
auto* cd = this->get_parent_as<ClassDescription<T>>();
270288
cd->reset_lets();
271289
}
272290

include/description.hpp

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
namespace CppSpec {
1616

17-
template <typename T>
17+
template <class T>
1818
class ClassDescription; // forward-declaration for ClassDescription
1919

2020
class Description : public Runnable {
@@ -35,12 +35,6 @@ class Description : public Runnable {
3535
protected:
3636
std::string description;
3737

38-
Description(std::source_location location, std::string&& description) noexcept
39-
: Runnable(location), description(std::move(description)) {}
40-
41-
Description(Runnable& parent, std::source_location location, const char* description, Block block) noexcept
42-
: Runnable(parent, location), block(block), description(description) {}
43-
4438
void exec_before_eaches();
4539
void exec_after_eaches();
4640

@@ -53,6 +47,12 @@ class Description : public Runnable {
5347
this->set_location(location);
5448
}
5549

50+
Description(std::source_location location, std::string&& description) noexcept
51+
: Runnable(location), description(std::move(description)) {}
52+
53+
Description(std::source_location location, const char* description, Block block) noexcept
54+
: Runnable(location), block(block), description(description) {}
55+
5656
/********* Specify/It *********/
5757

5858
ItD& it(const char* description, ItD::Block body, std::source_location location = std::source_location::current());
@@ -63,13 +63,21 @@ class Description : public Runnable {
6363
template <class T = std::nullptr_t>
6464
Description& context(const char* name, Block body, std::source_location location = std::source_location::current());
6565

66+
template <Util::not_c_string T, class B>
67+
ClassDescription<T>& context(T& subject, B block, std::source_location location = std::source_location::current());
68+
6669
template <class T, class B>
67-
requires(!std::is_same_v<T, const char*>)
68-
ClassDescription<T>& context(T subject, B block, std::source_location location = std::source_location::current());
70+
ClassDescription<T>& context(const char* description,
71+
T& subject,
72+
B block,
73+
std::source_location location = std::source_location::current());
74+
75+
template <Util::not_c_string T, class B>
76+
ClassDescription<T>& context(T&& subject, B block, std::source_location location = std::source_location::current());
6977

7078
template <class T, class B>
7179
ClassDescription<T>& context(const char* description,
72-
T subject,
80+
T&& subject,
7381
B block,
7482
std::source_location location = std::source_location::current());
7583

@@ -111,15 +119,15 @@ using Context = Description;
111119
/*========= Description::it =========*/
112120

113121
inline ItD& Description::it(const char* description, ItD::Block block, std::source_location location) {
114-
auto* it = new ItD(*this, location, description, block);
122+
auto it = this->make_child<ItD>(location, description, block);
115123
it->timed_run();
116124
exec_after_eaches();
117125
exec_before_eaches();
118126
return *it;
119127
}
120128

121129
inline ItD& Description::it(ItD::Block block, std::source_location location) {
122-
auto* it = new ItD(*this, location, block);
130+
auto* it = this->make_child<ItD>(location, block);
123131
it->timed_run();
124132
exec_after_eaches();
125133
exec_before_eaches();
@@ -130,7 +138,7 @@ inline ItD& Description::it(ItD::Block block, std::source_location location) {
130138

131139
template <class T>
132140
inline Context& Description::context(const char* description, Block body, std::source_location location) {
133-
auto* context = new Context(*this, location, description, body);
141+
auto* context = this->make_child<Context>(location, description, body);
134142
context->before_eaches = this->before_eaches;
135143
context->after_eaches = this->after_eaches;
136144
context->timed_run();

include/formatters/formatters_base.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ class BaseFormatter {
5858
}
5959

6060
void format_children(Runnable& runnable) {
61-
for (auto child : runnable.get_children()) {
62-
if (Runnable* runnable = dynamic_cast<Runnable*>(child)) {
61+
for (auto& child : runnable.get_children()) {
62+
if (Runnable* runnable = dynamic_cast<Runnable*>(child.get())) {
6363
this->format(*runnable);
6464
}
6565
}

0 commit comments

Comments
 (0)