TPIE

11a2c2d
stream_crtp.h
Go to the documentation of this file.
1 // -*- mode: c++; tab-width: 4; indent-tabs-mode: t; eval: (progn (c-set-style "stroustrup") (c-set-offset 'innamespace 0)); -*-
2 // vi:set ts=4 sts=4 sw=4 noet :
3 // Copyright 2012 The TPIE development team
4 //
5 // This file is part of TPIE.
6 //
7 // TPIE is free software: you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License as published by the
9 // Free Software Foundation, either version 3 of the License, or (at your
10 // option) any later version.
11 //
12 // TPIE is distributed in the hope that it will be useful, but WITHOUT ANY
13 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 // License for more details.
16 //
17 // You should have received a copy of the GNU Lesser General Public License
18 // along with TPIE. If not, see <http://www.gnu.org/licenses/>
19 
23 
24 #ifndef __TPIE_STREAM_CRTP_H__
25 #define __TPIE_STREAM_CRTP_H__
26 
27 #include <tpie/tpie_export.h>
28 #include <tpie/types.h>
29 #include <tpie/exception.h>
30 #include <limits>
31 #include <cassert>
32 
33 namespace tpie {
34 
35 template <typename child_t>
36 class TPIE_EXPORT stream_crtp {
37 public:
39  enum offset_type {
40  beginning,
41  end,
42  current
43  };
44 
51  inline void seek(stream_offset_type offset, offset_type whence=beginning) {
52  assert(self().get_file().is_open());
53  if (whence == end)
54  offset += self().size();
55  else if (whence == current) {
56  // are we seeking into the current block?
57  if (offset >= 0 || static_cast<stream_size_type>(-offset) <= m_index) {
58  stream_size_type new_index = static_cast<stream_offset_type>(offset+m_index);
59 
60  if (new_index < self().get_file().block_items()) {
61  self().update_vars();
62  m_index = static_cast<memory_size_type>(new_index);
63  return;
64  }
65  }
66 
67  offset += self().offset();
68  }
69  if (0 > offset || (stream_size_type)offset > self().size())
70  throw io_exception("Tried to seek out of file");
71  self().update_vars();
72  stream_size_type b = static_cast<stream_size_type>(offset) / self().get_file().block_items();
73  m_index = static_cast<memory_size_type>(offset - b* self().get_file().block_items());
74  if (b == self().get_block().number) {
75  m_nextBlock = std::numeric_limits<stream_size_type>::max();
76  m_nextIndex = std::numeric_limits<memory_size_type>::max();
77  assert(self().offset() == (stream_size_type)offset);
78  return;
79  }
80  m_nextBlock = b;
81  m_nextIndex = m_index;
82  m_index = std::numeric_limits<memory_size_type>::max();
83  assert(self().offset() == (stream_size_type)offset);
84  }
85 
91  inline stream_size_type offset() const throw() {
92  assert(self().get_file().is_open());
93  if (m_nextBlock == std::numeric_limits<stream_size_type>::max())
94  return m_index + m_blockStartIndex;
95  return m_nextIndex + m_nextBlock * self().get_file().block_items();
96  }
97 
109  inline bool can_read() const throw() {
110  assert(self().get_file().is_open());
111  if (m_index < self().get_block().size ) return true;
112  return offset() < self().size();
113  }
114 
120  inline bool can_read_back() const throw() {
121  assert(self().get_file().is_open());
122  if (m_nextBlock == std::numeric_limits<stream_size_type>::max())
123  return m_index > 0 || m_blockStartIndex > 0;
124  else
125  return m_nextIndex > 0 || m_nextBlock > 0;
126  }
127 
133  inline stream_size_type size() const throw() {
134  // XXX update_vars changes internal state in a way that is not visible
135  // through the class interface.
136  // therefore, a const_cast is warranted.
137  const_cast<child_t&>(self()).update_vars();
138  return self().get_file().file_size();
139  }
140 
141 protected:
142  inline void initialize() {
143  m_nextBlock = std::numeric_limits<stream_size_type>::max();
144  m_nextIndex = std::numeric_limits<memory_size_type>::max();
145  m_index = std::numeric_limits<memory_size_type>::max();
146  }
147 
163  // Since this is called from file<T>::stream and file_stream<T>, we cannot
164  // have the implementation in its own object.
165  template <typename IT, typename Stream>
166  static inline void read_array(Stream & stream, const IT & start, const IT & end) {
167  typedef typename Stream::item_type T;
168  IT i = start;
169  while (i != end) {
170  if (stream.m_index >= stream.block_items()) {
171  // check to make sure we have enough items in the stream
172  stream_size_type offs = stream.offset();
173  if (offs >= stream.size()
174  || offs + (end-i) > stream.size()) {
175 
176  throw end_of_stream_exception();
177  }
178 
179  // fetch next block from disk
180  stream.update_block();
181  }
182 
183  T * src = reinterpret_cast<T*>(stream.get_block().data) + stream.m_index;
184 
185  // either read the rest of the block or until `end'
186  memory_size_type count = std::min(stream.block_items()-stream.m_index, static_cast<memory_size_type>(end-i));
187 
188  std::copy(src, src + count, i);
189 
190  // advance output iterator
191  i += count;
192 
193  // advance input position
194  stream.m_index += count;
195  }
196  }
197 
210  // See read_array note above.
211  template <typename IT, typename Stream>
212  static inline void write_array(Stream & stream, const IT & start, const IT & end) {
213  typedef typename Stream::item_type T;
214  IT i = start;
215  while (i != end) {
216  if (stream.m_index >= stream.block_items()) stream.update_block();
217 
218  size_t streamRemaining = end - i;
219  size_t blockRemaining = stream.block_items()-stream.m_index;
220 
221  IT till = (blockRemaining < streamRemaining) ? (i + blockRemaining) : end;
222 
223  T * dest = reinterpret_cast<T*>(stream.get_block().data) + stream.m_index;
224 
225  std::copy(i, till, dest);
226 
227  stream.m_index += till - i;
228  stream.write_update();
229  i = till;
230  }
231  }
232 
241  void update_block();
242 
245  memory_size_type m_index;
249  stream_size_type m_nextBlock;
252  memory_size_type m_nextIndex;
256  stream_size_type m_blockStartIndex;
257 
258 private:
259  inline child_t & self() {return *static_cast<child_t*>(this);}
260  inline const child_t & self() const {return *static_cast<const child_t*>(this);}
261 };
262 
263 } // namespace tpie
264 
265 #endif // __TPIE_STREAM_CRTP_H__
tpie::stream_crtp< stream >::offset_type
offset_type
Type describing how we should interpret the offset supplied to seek.
Definition: stream_crtp.h:39
tpie::stream_crtp::read_array
static void read_array(Stream &stream, const IT &start, const IT &end)
Reads several items from the stream.
Definition: stream_crtp.h:166
types.h
tpie::stream_crtp::seek
void seek(stream_offset_type offset, offset_type whence=beginning)
Moves the logical offset in the stream.
Definition: stream_crtp.h:51
tpie::stream_crtp::m_nextBlock
stream_size_type m_nextBlock
After a cross-block seek: Block index of next block, or maxint if the current block is good enough OR...
Definition: stream_crtp.h:249
tpie::stream_crtp::m_index
memory_size_type m_index
Item index into the current block, or maxint if we don't have a block.
Definition: stream_crtp.h:245
tpie::stream_crtp::can_read_back
bool can_read_back() const
Check if we can read an item with read_back().
Definition: stream_crtp.h:120
tpie::end_of_stream_exception
Definition: exception.h:62
tpie::stream_crtp
Definition: stream_crtp.h:36
tpie::stream_crtp::can_read
bool can_read() const
Check if we can read an item with read().
Definition: stream_crtp.h:109
tpie::stream_crtp::size
stream_size_type size() const
Get the size of the file measured in items.
Definition: stream_crtp.h:133
tpie::stream_crtp::write_array
static void write_array(Stream &stream, const IT &start, const IT &end)
Write several items to the stream.
Definition: stream_crtp.h:212
exception.h
tpie::io_exception
Definition: exception.h:50
tpie::stream_crtp::m_nextIndex
memory_size_type m_nextIndex
After a cross-block seek: Item index into next block.
Definition: stream_crtp.h:252
tpie::stream_crtp::m_blockStartIndex
stream_size_type m_blockStartIndex
The file-level item index of the first item in the current block.
Definition: stream_crtp.h:256
tpie
Definition: access_type.h:26
tpie::stream_crtp::offset
stream_size_type offset() const
Calculate the current offset in the stream.
Definition: stream_crtp.h:91