Build system improvements
[ustl.git] / mostream.h
blob3bfd8ffd8b02e4b64723fbfa9deb4492fb9ead48
1 // This file is part of the ustl library, an STL implementation.
2 //
3 // Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net>
4 // This file is free software, distributed under the MIT License.
5 //
6 // mostream.h
8 #ifndef MOSTREAM_H_24A8C5397E0848216573E5670930FC9A
9 #define MOSTREAM_H_24A8C5397E0848216573E5670930FC9A
11 #include "memlink.h"
12 #include "uexception.h"
13 #include "utf8.h"
14 #include "uios.h"
15 #ifdef WANT_STREAM_BOUNDS_CHECKING
16 #include <typeinfo>
17 #endif
19 namespace ustl {
21 class istream;
22 class string;
24 /// \class ostream mostream.h ustl.h
25 /// \ingroup BinaryStreams
26 ///
27 /// \brief Helper class to write packed binary streams.
28 ///
29 /// This class contains a set of functions to write integral types into an
30 /// unstructured memory block. Packing binary file data can be done this
31 /// way, for instance. aligning the data is your responsibility, and can
32 /// be accomplished by proper ordering of writes and by calling \ref ostream::align.
33 /// Unaligned access is usually slower by orders of magnitude and,
34 /// on some architectures, such as PowerPC, can cause your program to crash.
35 /// Therefore, all write functions have asserts to check alignment.
36 /// See \ref istream documentation for rules on designing your data format.
37 /// Overwriting the end of the stream will also cause a crash (an assert in
38 /// debug builds). Oh, and don't be intimidated by the size of the inlines
39 /// here. In the assembly code the compiler will usually chop everything down
40 /// to five instructions each.
41 ///
42 /// Example code:
43 /// \code
44 /// memblock b;
45 /// ostream os (b);
46 /// os << boolVar << ios::talign<int>();
47 /// os << intVar << floatVar;
48 /// os.write (binaryData, binaryDataSize);
49 /// os.align();
50 /// b.resize (os.pos());
51 /// b.write_file ("test.file");
52 /// \endcode
53 ///
54 class ostream : public memlink, public ios_base {
55 public:
56 ostream (void);
57 ostream (void* p, size_type n);
58 explicit ostream (const memlink& source);
59 inline iterator end (void) { return (memlink::end()); }
60 inline const_iterator end (void) const { return (memlink::end()); }
61 inline void seek (uoff_t newPos);
62 inline void iseek (const_iterator newPos);
63 inline void skip (size_type nBytes);
64 inline uoff_t pos (void) const { return (m_Pos); }
65 inline iterator ipos (void) { return (begin() + pos()); }
66 inline const_iterator ipos (void) const { return (begin() + pos()); }
67 inline size_type remaining (void) const;
68 inline bool aligned (size_type grain = c_DefaultAlignment) const;
69 void verify_remaining (const char* op, const char* type, size_t n) const;
70 inline size_type align_size (size_type grain = c_DefaultAlignment) const;
71 void align (size_type grain = c_DefaultAlignment);
72 void write (const void* buffer, size_type size);
73 inline void write (const cmemlink& buf);
74 void write_strz (const char* str);
75 void read (istream& is);
76 inline void write (ostream& os) const { os.write (begin(), pos()); }
77 void text_write (ostringstream& os) const;
78 inline size_t stream_size (void) const { return (pos()); }
79 void insert (iterator start, size_type size);
80 void erase (iterator start, size_type size);
81 void swap (ostream& os);
82 template <typename T>
83 inline void iwrite (const T& v);
84 inline virtual size_type overflow (size_type = 1){ return (remaining()); }
85 virtual void unlink (void) throw();
86 inline void link (void* p, size_type n) { memlink::link (p, n); }
87 inline void link (memlink& l) { memlink::link (l.data(), l.writable_size()); }
88 inline void link (void* f, void* l) { memlink::link (f, l); }
89 inline void relink (void* p, size_type n) { memlink::relink (p, n); m_Pos = 0; }
90 inline void relink (memlink& l) { relink (l.data(), l.writable_size()); }
91 inline void seekp (off_t p, seekdir d = beg);
92 inline off_t tellp (void) const { return (pos()); }
93 protected:
94 inline void SetPos (uoff_t newPos) { m_Pos = newPos; }
95 private:
96 uoff_t m_Pos; ///< Current write position.
99 //----------------------------------------------------------------------
101 /// \class ostream_iterator mostream.h ustl.h
102 /// \ingroup BinaryStreamIterators
104 /// \brief An iterator over an ostream to use with uSTL algorithms.
106 template <typename T, typename Stream = ostream>
107 class ostream_iterator {
108 public:
109 typedef T value_type;
110 typedef ptrdiff_t difference_type;
111 typedef value_type* pointer;
112 typedef value_type& reference;
113 typedef ostream::size_type size_type;
114 public:
115 inline explicit ostream_iterator (Stream& os)
116 : m_Os (os) {}
117 inline ostream_iterator (const ostream_iterator& iter)
118 : m_Os (iter.m_Os) {}
119 /// Writes \p v into the stream.
120 inline ostream_iterator& operator= (const T& v)
121 { m_Os << v; return (*this); }
122 inline ostream_iterator& operator* (void) { return (*this); }
123 inline ostream_iterator& operator++ (void) { return (*this); }
124 inline ostream_iterator operator++ (int) { return (*this); }
125 inline ostream_iterator& operator+= (size_type n) { m_Os.skip (n); return (*this); }
126 inline bool operator== (const ostream_iterator& i) const
127 { return (m_Os.pos() == i.m_Os.pos()); }
128 inline bool operator< (const ostream_iterator& i) const
129 { return (m_Os.pos() < i.m_Os.pos()); }
130 private:
131 Stream& m_Os;
134 //----------------------------------------------------------------------
136 typedef ostream_iterator<utf8subchar_t> ostream_iterator_for_utf8;
137 typedef utf8out_iterator<ostream_iterator_for_utf8> utf8ostream_iterator;
139 /// Returns a UTF-8 adaptor writing to \p os.
140 inline utf8ostream_iterator utf8out (ostream& os)
142 ostream_iterator_for_utf8 si (os);
143 return (utf8ostream_iterator (si));
146 //----------------------------------------------------------------------
148 /// Move the write pointer to \p newPos
149 inline void ostream::seek (uoff_t newPos)
151 #ifdef WANT_STREAM_BOUNDS_CHECKING
152 if (newPos > size())
153 throw stream_bounds_exception ("seekp", "byte", pos(), newPos - pos(), size());
154 #else
155 assert (newPos <= size());
156 #endif
157 SetPos (newPos);
160 /// Sets the current write position to \p newPos
161 inline void ostream::iseek (const_iterator newPos)
163 seek (distance (begin(), const_cast<iterator>(newPos)));
166 /// Sets the current write position to \p p based on \p d.
167 inline void ostream::seekp (off_t p, seekdir d)
169 switch (d) {
170 case beg: seek (p); break;
171 case cur: seek (pos() + p); break;
172 case ios_base::end: seek (size() - p); break;
176 /// Skips \p nBytes without writing anything.
177 inline void ostream::skip (size_type nBytes)
179 seek (pos() + nBytes);
182 /// Returns number of bytes remaining in the write buffer.
183 inline ostream::size_type ostream::remaining (void) const
185 return (size() - pos());
188 /// Returns \c true if the write pointer is aligned on \p grain
189 inline bool ostream::aligned (size_type grain) const
191 assert (uintptr_t(begin()) % grain == 0 && "Streams should be attached aligned at the maximum element grain to avoid bus errors.");
192 return (pos() % grain == 0);
195 /// Returns the number of bytes to skip to be aligned on \p grain.
196 inline ostream::size_type ostream::align_size (size_type grain) const
198 return (Align (pos(), grain) - pos());
201 /// Writes the contents of \p buf into the stream as a raw dump.
202 inline void ostream::write (const cmemlink& buf)
204 write (buf.begin(), buf.size());
207 /// Writes type T into the stream via a direct pointer cast.
208 template <typename T>
209 inline void ostream::iwrite (const T& v)
211 assert (aligned (alignof (v)));
212 #ifdef WANT_STREAM_BOUNDS_CHECKING
213 verify_remaining ("write", typeid(v).name(), sizeof(T));
214 #else
215 assert (remaining() >= sizeof(T));
216 #endif
217 *reinterpret_cast<T*>(ipos()) = v;
218 SetPos (pos() + sizeof(T));
221 //----------------------------------------------------------------------
223 template <typename T> struct object_writer {
224 inline void operator()(ostream& os, const T& v) const { v.write (os); }
226 template <typename T> struct integral_object_writer {
227 inline void operator()(ostream& os, const T& v) const { os.iwrite (v); }
229 template <typename T>
230 inline ostream& operator<< (ostream& os, const T& v) {
231 typedef typename tm::Select <numeric_limits<T>::is_integral,
232 integral_object_writer<T>, object_writer<T> >::Result object_writer_t;
233 object_writer_t()(os, v);
234 return (os);
237 //----------------------------------------------------------------------
239 } // namespace ustl
241 #endif