Flow 1.0.1
Flow project: Full implementation reference.
string_ostream.hpp
Go to the documentation of this file.
1/* Flow
2 * Copyright 2023 Akamai Technologies, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the
5 * "License"); you may not use this file except in
6 * compliance with the License. You may obtain a copy
7 * of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in
12 * writing, software distributed under the License is
13 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
14 * CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing
16 * permissions and limitations under the License. */
17
18/// @file
19#pragma once
20
22#include <boost/iostreams/stream.hpp>
23#include <boost/iostreams/stream_buffer.hpp>
24#include <boost/iostreams/device/back_inserter.hpp>
25
26
27namespace flow::util
28{
29
30/**
31 * Similar to `ostringstream` but allows fast read-only access directly into the `std::string` being written;
32 * and some limited write access to that string. Also it can take over an existing `std::string`.
33 *
34 * `ostringstream` is fine, except for the giant flaw that is the fact that the essentially only way to read the string
35 * is to call `ostringstream::str()` which returns a copy, not a reference.
36 *
37 * @todo Consider using `alt_sstream` in boost.format; it doesn't seem to have public documentation but isn't in
38 * a `detail` directory either. So that's interesting. It might have better performance than the implementation
39 * here (by being more "direct" probably). Then again it might not.
40 *
41 * ### Thread safety ###
42 * This provides the same level of thread safety as `ostringstream`. That is, you should use a mutex if planning
43 * concurrent read/write access to the same object.
44 */
46 private boost::noncopyable
47{
48public:
49 // Constructors/destructor.
50
51 /**
52 * Wraps either the given `std::string` or a newly created empty string if a null pointer is passed.
53 *
54 * @param target_str
55 * Pointer to the string of which to take ownership; null to use an internal string currently blank.
56 * If non-null is passed, any subsequnt access to `*target_str` except via this class's API results in
57 * undefined behavior. (It should go without saying, but using `const_cast` or equivalents counts as being
58 * outside the bounds of this class's API.)
59 */
60 explicit String_ostream(std::string* target_str = 0);
61
62 // Methods.
63
64 /**
65 * Access to stream that will write to owned string.
66 *
67 * @return Stream.
68 */
69 std::ostream& os();
70
71 /**
72 * Read-only access to stream that will write to owned string.
73 *
74 * @return Read-only reference to stream.
75 */
76 const std::ostream& os() const;
77
78 /**
79 * Read-only access to the string being wrapped.
80 *
81 * The reference's value never changes for `*this` object. The string's value may change, if one writes to
82 * `os()` or does str_clear(), etc.
83 *
84 * ### Rationale ###
85 * Why return `const string&` instead of util::String_view? Answer: By definition we are backed by an `std::string`,
86 * either our own or one user actively passed to ctor. Hence it's unnecessary obfuscation; plus it can lead to
87 * errors, like if the user thinks a returned object's `String_view::size()` will auto-adjust based on what happens
88 * to the wrapped `std::string` subsequently. If they want a `String_view`, they can always just construct one, just
89 * as we would inside here anyway.
90 *
91 * @return Read-only reference to string; the address therein is guaranteed to always be the same given a `*this`.
92 */
93 const std::string& str() const;
94
95 /**
96 * Performs `std::string::clear()` on the object returned by `str()`. The latter is `const`, so you may not
97 * call `clear()` directly.
98 *
99 * @note `clear()` is a frequently desired operation, which is why access to it is provided as a special case.
100 * It is intentional that no read-write version of str() is provided for arbitrary write operations.
101 */
102 void str_clear();
103
104private:
105 // Types.
106
107 /// Short-hand for an `ostream` writing to which will append to an std::string it is adapting.
108 using String_appender_ostream = boost::iostreams::stream<boost::iostreams::back_insert_device<std::string>>;
109
110 // Data.
111
112 /**
113 * Underlying string to use if user chooses not to pass in their own in constructor. Otherwise unused.
114 * (Could use `unique_ptr` to avoid even allocating it if not needed; but the memory use of an empty
115 * string is negligible, and this is otherwise equally fast or faster and leads to simpler code.)
116 */
117 std::string m_own_target_str;
118
119 /// Pointer to the target string. Emptied at construction and in str_clear() *only*.
120 std::string* m_target;
121
122 /// Inserter into #m_target.
123 boost::iostreams::back_insert_device<std::string> m_target_inserter;
124
125 /// Appender `ostream` into #m_target by way of #m_target_inserter. Write/`flush` here to write to #m_target.
127}; // class String_ostream
128
129} // namespace flow::util
Similar to ostringstream but allows fast read-only access directly into the std::string being written...
std::string m_own_target_str
Underlying string to use if user chooses not to pass in their own in constructor.
void str_clear()
Performs std::string::clear() on the object returned by str().
String_ostream(std::string *target_str=0)
Wraps either the given std::string or a newly created empty string if a null pointer is passed.
boost::iostreams::stream< boost::iostreams::back_insert_device< std::string > > String_appender_ostream
Short-hand for an ostream writing to which will append to an std::string it is adapting.
std::ostream & os()
Access to stream that will write to owned string.
const std::string & str() const
Read-only access to the string being wrapped.
boost::iostreams::back_insert_device< std::string > m_target_inserter
Inserter into m_target.
String_appender_ostream m_target_appender_ostream
Appender ostream into m_target by way of m_target_inserter. Write/flush here to write to m_target.
std::string * m_target
Pointer to the target string. Emptied at construction and in str_clear() only.
Flow module containing miscellaneous general-use facilities that don't fit into any other Flow module...
Definition: basic_blob.hpp:29