GCC Code Coverage Report


Directory: gridformat/
File: gridformat/common/output_stream.hpp
Date: 2026-10-12 17:50:57
Exec Total Coverage
Lines: 34 34 100.0%
Functions: 36 53 67.9%
Branches: 0 0 -%

Line Branch Exec Source
1 // SPDX-FileCopyrightText: 2022-2023 Dennis Gläser <dennis.glaeser@iws.uni-stuttgart.de>
2 // SPDX-License-Identifier: MIT
3 /*!
4 * \file
5 * \ingroup Common
6 * \brief Helper classes & wrappers around output streams
7 */
8 #ifndef GRIDFORMAT_COMMON_STREAM_HPP_
9 #define GRIDFORMAT_COMMON_STREAM_HPP_
10
11 #include <span>
12 #include <limits>
13 #include <ostream>
14 #include <concepts>
15 #include <type_traits>
16
17 #include <gridformat/common/concepts.hpp>
18
19 namespace GridFormat {
20
21 /*!
22 * \ingroup Common
23 * \brief Wrapper around an output stream to expose our required interface
24 * We require being able to write spans into output streams, and use
25 * our desired precision for formatted output of floating point values.
26 */
27 class OutputStream {
28 public:
29 149083 explicit OutputStream(std::ostream& s)
30 149083 : _stream{s}
31 149083 {}
32
33 template<Concepts::StreamableWith<std::ostream> T>
34 requires(not Concepts::Scalar<T>)
35 3 OutputStream& operator<<(const T& t) {
36 3 _stream << t;
37 3 return *this;
38 }
39
40 template<Concepts::Scalar T>
41 4 OutputStream& operator<<(const T& t) {
42 4 auto orig_precision = _stream.precision();
43 4 _stream.precision(std::numeric_limits<T>::digits10);
44 4 _stream << t;
45 4 _stream.precision(orig_precision);
46 4 return *this;
47 }
48
49 template<typename T, std::size_t size>
50 436768 void write(std::span<T, size> data) {
51 436768 _write_chars(std::as_bytes(data));
52 436768 }
53
54 template<std::size_t size>
55 17249 void write(std::span<const char, size> data) {
56 17249 _write_chars(data.data(), data.size());
57 17249 }
58
59 private:
60 template<typename Byte, std::size_t size>
61 436767 void _write_chars(std::span<const Byte, size> data) {
62 static_assert(sizeof(Byte) == sizeof(char));
63 436767 const char* chars = reinterpret_cast<const char*>(data.data());
64 436767 _stream.write(chars, data.size());
65 436767 }
66
67 17249 void _write_chars(const char* chars, std::size_t size) {
68 17249 _stream.write(chars, size);
69 17249 }
70
71 std::ostream& _stream;
72 };
73
74 #ifndef DOXYGEN
75 namespace Detail {
76
77 template<typename T> struct OutputStreamStorage : std::type_identity<T&> {};
78 template<std::derived_from<std::ostream> T> struct OutputStreamStorage<T> : std::type_identity<OutputStream> {};
79
80 } // namespace Detail
81 #endif // DOXYGEN
82
83 /*!
84 * \ingroup Common
85 * \brief Base class for wrappers around output streams.
86 * Makes it possible to wrap both instances of OutputStream or std::ostream.
87 */
88 template<typename OStream>
89 class OutputStreamWrapperBase {
90 using Storage = typename Detail::OutputStreamStorage<OStream>::type;
91 using Stream = std::remove_cvref_t<Storage>;
92
93 public:
94 template<typename S>
95 requires(std::constructible_from<Storage, S>)
96 149086 explicit OutputStreamWrapperBase(S&& s)
97 149086 : _stream{std::forward<S>(s)}
98 149086 {}
99
100 protected:
101 template<Concepts::StreamableWith<Stream> T>
102 6 void _write_formatted(const T& t) {
103 6 _stream << t;
104 6 }
105
106 template<typename T, std::size_t size>
107 155975 void _write_raw(std::span<T, size> data) {
108 155975 _stream.write(data);
109 155975 }
110
111 Storage _stream;
112 };
113
114 } // namespace GridFormat
115
116 #endif // GRIDFORMAT_COMMON_STREAM_HPP_
117