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
129template<typename OS, SampleOutputTarget Target>
130class SampleOutput {
131 OS& stream;
132
133 template<typename, SampleOutputTarget>
134 friend class SampleOutput;
135
136 static constexpr OS& autoStream() {
137 constexpr bool is_cout_type = std::is_same_v< OS, std::ostream >;
138 constexpr bool is_wcout_type = std::is_same_v< OS, std::wostream >;
139
140 if constexpr ( is_cout_type ) {
141 return std::cout;
142 } else if constexpr ( is_wcout_type ) {
143 return std::wcout;
144 } else {
145 static_assert(
146 false,
147 "Default init of ActiveOutput is only allowed for "
148 "ostream or wostream stream types."
149 );
150 }
151 }
152
153 template<typename T> constexpr void ignoreType() {};
154
155 constexpr bool doWrite(SampleOutputTarget tgt = Target) {
156 return tgt == SAMPLE_ACTIVE_OUTPUT || tgt == SAMPLE_ALWAYS_OUTPUT;
157 }
158
159 template<typename T>
160 constexpr void write(T&& v) {
161 if constexpr ( doWrite() ) {
162 stream << std::forward<T>(v);
163 } else {
164 // We still need this to fail if the actual write would not be
165 // allowed to happen at compile time.
166 // A compile error in the normal program is a compile error in the
167 // test program and vice-versa.
168 ignoreType<decltype(stream << std::forward<T>(v))>();
169 }
170 }
171
172public:
173 constexpr SampleOutput() : stream(autoStream()) { }
174 SampleOutput(const SampleOutput&) = default;
175 constexpr SampleOutput(OS& os) : stream(os) { }
176
188 template<typename T, SampleOutputTarget Tgt>
189 constexpr SampleOutput(const SampleOutput<T, Tgt>& other)
190 : stream(other.stream)
191 {
192 }
193
194 constexpr SampleOutput<OS, SAMPLE_NORMAL_OUTPUT> out() { return stream; }
195 constexpr auto normal() { return out(); }
196
197 constexpr SampleOutput<OS, SAMPLE_TEST_OUTPUT> expected() { return stream; }
198 constexpr auto expect() { return expected(); }
199
200 constexpr SampleOutput<OS, SAMPLE_ALWAYS_OUTPUT> always() { return stream; }
201 constexpr auto both() { return always(); }
202
203 template<typename T>
204 constexpr SampleOutput& operator<< (T&& v) {
205 write(std::forward<T>(v));
206 return *this;
207 }
208};
209
210template<typename T = std::ostream>
212
213template<typename T>
215
216template<typename T, SampleOutputTarget Tgt>
218
219
220#endif /* UGMISC_SAMPLES_OUTPUT_HPP */
constexpr SampleOutput(const SampleOutput< T, Tgt > &other)