GCC Code Coverage Report


Directory: gridformat/
File: gridformat/common/output_stream.hpp
Date: 2024-11-10 16:24:00
Exec Total Coverage
Lines: 34 34 100.0%
Functions: 36 51 70.6%
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 138959 explicit OutputStream(std::ostream& s)
30 138959 : _stream{s}
31 138959 {}
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 408146 void write(std::span<T, size> data) {
51 408146 _write_chars(std::as_bytes(data));
52 408146 }
53
54 template<std::size_t size>
55 15655 void write(std::span<const char, size> data) {
56 15655 _write_chars(data.data(), data.size());
57 15655 }
58
59 private:
60 template<typename Byte, std::size_t size>
61 408145 void _write_chars(std::span<const Byte, size> data) {
62 static_assert(sizeof(Byte) == sizeof(char));
63 408145 const char* chars = reinterpret_cast<const char*>(data.data());
64 408145 _stream.write(chars, data.size());
65 408145 }
66
67 15655 void _write_chars(const char* chars, std::size_t size) {
68 15655 _stream.write(chars, size);
69 15655 }
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 138962 explicit OutputStreamWrapperBase(S&& s)
97 138962 : _stream{std::forward<S>(s)}
98 138962 {}
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 145157 void _write_raw(std::span<T, size> data) {
108 145157 _stream.write(data);
109 145157 }
110
111 Storage _stream;
112 };
113
114 } // namespace GridFormat
115
116 #endif // GRIDFORMAT_COMMON_STREAM_HPP_
117