UgMisc 0.3
Miscellaneous C++ header library
Loading...
Searching...
No Matches
samples_output.hpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: © 2026 Larry Chips <larry@larrychips.net>
3 * SPDX-Licence-Identifier: MIT
4 */
5#ifndef UGMISC_SAMPLES_OUTPUT_HPP
6#define UGMISC_SAMPLES_OUTPUT_HPP
26
27#include <iostream>
28#include <utility>
29#include <type_traits>
30
31
32enum SampleOutputTarget {
33 SAMPLE_NORMAL_OUTPUT = 1,
34 SAMPLE_TEST_OUTPUT = 2,
35 SAMPLE_ALWAYS_OUTPUT = 3,
36#ifdef UGMISC_SAMPLES_GENERATE_TEST_OUTPUT
37 SAMPLE_ACTIVE_OUTPUT = SAMPLE_TEST_OUTPUT,
38#else
39 SAMPLE_ACTIVE_OUTPUT = SAMPLE_NORMAL_OUTPUT,
40#endif
41 SAMPLE_DEFAULT_OUTPUT = SAMPLE_NORMAL_OUTPUT
42};
43
44
45template<typename, SampleOutputTarget = SAMPLE_DEFAULT_OUTPUT>
46class SampleOutput;
47
126template<typename OS, SampleOutputTarget Target>
127class SampleOutput {
128 OS& stream;
129
130 template<typename, SampleOutputTarget>
131 friend class SampleOutput;
132
133 static constexpr OS& autoStream() {
134 constexpr bool is_cout_type = std::is_same_v< OS, std::ostream >;
135 constexpr bool is_wcout_type = std::is_same_v< OS, std::wostream >;
136
137 if constexpr ( is_cout_type ) {
138 return std::cout;
139 } else if constexpr ( is_wcout_type ) {
140 return std::wcout;
141 } else {
142 static_assert(
143 false,
144 "Default init of ActiveOutput is only allowed for "
145 "ostream or wostream stream types."
146 );
147 }
148 }
149
150 template<typename T> constexpr void ignoreType() {};
151
152 constexpr bool doWrite(SampleOutputTarget tgt = Target) {
153 return tgt == SAMPLE_ACTIVE_OUTPUT || tgt == SAMPLE_ALWAYS_OUTPUT;
154 }
155
156 template<typename T>
157 constexpr void write(T&& v) {
158 if constexpr ( doWrite() ) {
159 stream << std::forward<T>(v);
160 } else {
161 // We still need this to fail if the actual write would not be
162 // allowed to happen at compile time.
163 // A compile error in the normal program is a compile error in the
164 // test program and vice-versa.
165 ignoreType<decltype(stream << std::forward<T>(v))>();
166 }
167 }
168
169public:
170 constexpr SampleOutput() : stream(autoStream()) { }
171 SampleOutput(const SampleOutput&) = default;
172 constexpr SampleOutput(OS& os) : stream(os) { }
173
182 template<typename T, SampleOutputTarget Tgt>
183 constexpr SampleOutput(const SampleOutput<T, Tgt>& other)
184 : stream(other.stream)
185 {
186 }
187
188 constexpr SampleOutput<OS, SAMPLE_NORMAL_OUTPUT> out() { return stream; }
189 constexpr auto normal() { return out(); }
190
191 constexpr SampleOutput<OS, SAMPLE_TEST_OUTPUT> expected() { return stream; }
192 constexpr auto expect() { return expected(); }
193
194 constexpr SampleOutput<OS, SAMPLE_ALWAYS_OUTPUT> always() { return stream; }
195 constexpr auto both() { return always(); }
196
197 template<typename T>
198 constexpr SampleOutput& operator<< (T&& v) {
199 write(std::forward<T>(v));
200 return *this;
201 }
202};
203
204template<typename T = std::ostream>
206
207template<typename T>
209
210template<typename T, SampleOutputTarget Tgt>
212
213
214#endif /* UGMISC_SAMPLES_OUTPUT_HPP */
constexpr SampleOutput(const SampleOutput< T, Tgt > &other)