Virtual Testbed
Ship dynamics simulator for extreme conditions
bstream.hh
1 #ifndef VTESTBED_BASE_BSTREAM_HH
2 #define VTESTBED_BASE_BSTREAM_HH
3 
4 #include <cstddef>
5 #include <cstdint>
6 #include <limits>
7 #include <iterator>
8 #include <streambuf>
9 #include <type_traits>
10 #include <vtestbed/base/byte_order.hh>
11 
12 #define VTB_PUT_GET(type) \
13  inline bstream& operator<<(type rhs) { this->do_write(rhs); return *this; } \
14  inline bstream& operator>>(type& rhs) { this->do_read(rhs); return *this; }
15 
16 #define VTB_METHOD_TYPE(type, method) decltype(::std::declval<type>().method)
17 
18 namespace vtb {
19 
20  namespace base {
21 
22  template <class T>
23  struct has_begin_end: public std::false_type {};
24 
25  template <class T>
27 
28  class bstream {
29 
30  public:
31  using char_type = char;
33  using size_type = std::uint64_t;
35 
36  private:
38 
39  private:
40  streambuf* _buffer = nullptr;
41 
42  public:
43 
44  inline explicit bstream(streambuf* buffer): _buffer(buffer) {}
45  inline streambuf* rdbuf() { return this->_buffer; }
46  inline const streambuf* rdbuf() const { return this->_buffer; }
47 
48  inline streambuf*
49  rdbuf(streambuf* rhs) {
50  streambuf* old = this->_buffer;
51  this->_buffer = rhs;
52  return old;
53  }
54 
55  inline void sync() { this->_buffer->pubsync(); }
56  inline void flush() { this->sync(); }
57 
58  inline void
59  write(const char_type* s, size_type n) {
60  this->_buffer->sputn(s, n);
61  }
62 
63  inline void
64  read(char_type* s, size_type n) {
65  this->_buffer->sgetn(s, n);
66  }
67 
68  bstream() = default;
69  ~bstream() = default;
70  bstream(bstream&&) = default;
71  bstream& operator=(bstream&&) = default;
72  bstream(const bstream&) = delete;
73  bstream& operator=(const bstream&) = delete;
74 
75  template <class Ch, class Tr>
76  typename std::enable_if<sizeof(Ch)==sizeof(char_type),bstream&>::type
77  operator<<(const std::basic_string<Ch,Tr>& rhs) {
78  if (rhs.size() > size_limit::max()) { this->throw_length(); }
79  size_type size = static_cast<size_type>(rhs.size());
80  this->do_write(size);
81  this->write(reinterpret_cast<const char_type*>(rhs.data()), size);
82  return *this;
83  }
84 
85  template <class Ch, class Tr>
86  typename std::enable_if<sizeof(Ch)==sizeof(char_type),bstream&>::type
87  operator>>(std::basic_string<Ch,Tr>& rhs) {
88  size_type size = 0;
89  this->do_read(size);
90  if (size > size_limit::max()) { this->throw_length(); }
91  rhs.resize(size);
92  this->read(reinterpret_cast<char_type*>(&rhs[0]), size);
93  return *this;
94  }
95 
96  template <class T>
98  operator<<(const T& rhs) {
99  size_type s = std::distance(rhs.begin(), rhs.end());
100  if (s > size_limit::max()) { this->throw_length(); }
101  size_type size = static_cast<size_type>(s);
102  this->do_write(size);
103  for (const auto& value : rhs) { *this << value; }
104  return *this;
105  }
106 
107  template <class T>
109  operator>>(T& rhs) {
110  size_type size = 0;
111  this->do_read(size);
112  if (size > size_limit::max()) { this->throw_length(); }
113  rhs.reserve(size);
114  for (size_type i=0; i<size; ++i) {
115  rhs.emplace_back();
116  *this >> rhs.back();
117  }
118  return *this;
119  }
120 
121  inline bstream&
122  operator<<(float rhs) {
123  this->do_write(static_cast<double>(rhs));
124  return *this;
125  }
126 
127  inline bstream&
128  operator>>(float& rhs) {
129  double tmp{};
130  this->do_read(tmp);
131  rhs = static_cast<float>(tmp);
132  return *this;
133  }
134 
135  VTB_PUT_GET(std::uint8_t);
136  VTB_PUT_GET(std::uint16_t);
137  VTB_PUT_GET(std::uint32_t);
138  VTB_PUT_GET(std::uint64_t);
139  VTB_PUT_GET(std::int8_t);
140  VTB_PUT_GET(std::int16_t);
141  VTB_PUT_GET(std::int32_t);
142  VTB_PUT_GET(std::int64_t);
143  VTB_PUT_GET(char);
144  VTB_PUT_GET(double);
145 
146  private:
147 
148  template <class T>
149  inline void
150  do_write(T value) {
151  static_assert(std::is_integral<T>::value ||
153  std::numeric_limits<T>::is_iec559), "bad type");
154  bytes<T> u;
155  u.orig = value;
156  u.swap();
157  this->write(u.bytes, sizeof(T)*sizeof(char_type));
158  }
159 
160  template <class T>
161  inline void
162  do_read(T& value) {
163  static_assert(std::is_integral<T>::value ||
165  std::numeric_limits<T>::is_iec559), "bad type");
166  bytes<T> u;
167  this->read(u.bytes, sizeof(T)*sizeof(char_type));
168  u.swap();
169  value = u.orig;
170  }
171 
172  inline void
173  throw_length() {
174  throw std::length_error("bstream");
175  }
176 
177  };
178 
179  }
180 
181  namespace core {
182 
183  typedef ::vtb::base::bstream bstream;
184 
185  }
186 
187 }
188 
189 #undef VTB_PUT_GET
190 #undef VTB_METHOD_TYPE
191 
192 #endif // vim:filetype=cpp
T max(T... args)
Main namespace.
Definition: convert.hh:9