TPIE

2362a60
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/types.h>
28 #include <tpie/exception.h>
29 #include <limits>
30 #include <cassert>
31 
32 namespace tpie {
33 
34 template <typename child_t>
35 class stream_crtp {
36 public:
38  enum offset_type {
39  beginning,
40  end,
41  current
42  };
43 
50  inline void seek(stream_offset_type offset, offset_type whence=beginning) throw(stream_exception) {
51  assert(self().get_file().is_open());
52  if (whence == end)
53  offset += self().size();
54  else if (whence == current) {
55  // are we seeking into the current block?
56  if (offset >= 0 || static_cast<stream_size_type>(-offset) <= m_index) {
57  stream_size_type new_index = static_cast<stream_offset_type>(offset+m_index);
58 
59  if (new_index < self().get_file().block_items()) {
60  self().update_vars();
61  m_index = static_cast<memory_size_type>(new_index);
62  return;
63  }
64  }
65 
66  offset += self().offset();
67  }
68  if (0 > offset || (stream_size_type)offset > self().size())
69  throw io_exception("Tried to seek out of file");
70  self().update_vars();
71  stream_size_type b = static_cast<stream_size_type>(offset) / self().get_file().block_items();
72  m_index = static_cast<memory_size_type>(offset - b* self().get_file().block_items());
73  if (b == self().get_block().number) {
74  m_nextBlock = std::numeric_limits<stream_size_type>::max();
75  m_nextIndex = std::numeric_limits<memory_size_type>::max();
76  assert(self().offset() == (stream_size_type)offset);
77  return;
78  }
79  m_nextBlock = b;
81  m_index = std::numeric_limits<memory_size_type>::max();
82  assert(self().offset() == (stream_size_type)offset);
83  }
84 
90  inline stream_size_type offset() const throw() {
91  assert(self().get_file().is_open());
92  if (m_nextBlock == std::numeric_limits<stream_size_type>::max())
93  return m_index + m_blockStartIndex;
94  return m_nextIndex + m_nextBlock * self().get_file().block_items();
95  }
96 
108  inline bool can_read() const throw() {
109  assert(self().get_file().is_open());
110  if (m_index < self().get_block().size ) return true;
111  return offset() < self().size();
112  }
113 
119  inline bool can_read_back() const throw() {
120  assert(self().get_file().is_open());
121  if (m_nextBlock == std::numeric_limits<stream_size_type>::max())
122  return m_index > 0 || m_blockStartIndex > 0;
123  else
124  return m_nextIndex > 0 || m_nextBlock > 0;
125  }
126 
132  inline stream_size_type size() const throw() {
133  // XXX update_vars changes internal state in a way that is not visible
134  // through the class interface.
135  // therefore, a const_cast is warranted.
136  const_cast<child_t&>(self()).update_vars();
137  return self().get_file().file_size();
138  }
139 
140 protected:
141  inline void initialize() {
142  m_nextBlock = std::numeric_limits<stream_size_type>::max();
143  m_nextIndex = std::numeric_limits<memory_size_type>::max();
144  m_index = std::numeric_limits<memory_size_type>::max();
145  }
146 
162  // Since this is called from file<T>::stream and file_stream<T>, we cannot
163  // have the implementation in its own object.
164  template <typename IT, typename Stream>
165  static inline void read_array(Stream & stream, const IT & start, const IT & end) throw(stream_exception) {
166  typedef typename Stream::item_type T;
167  IT i = start;
168  while (i != end) {
169  if (stream.m_index >= stream.block_items()) {
170  // check to make sure we have enough items in the stream
171  stream_size_type offs = stream.offset();
172  if (offs >= stream.size()
173  || offs + (end-i) > stream.size()) {
174 
175  throw end_of_stream_exception();
176  }
177 
178  // fetch next block from disk
179  stream.update_block();
180  }
181 
182  T * src = reinterpret_cast<T*>(stream.get_block().data) + stream.m_index;
183 
184  // either read the rest of the block or until `end'
185  memory_size_type count = std::min(stream.block_items()-stream.m_index, static_cast<memory_size_type>(end-i));
186 
187  std::copy(src, src + count, i);
188 
189  // advance output iterator
190  i += count;
191 
192  // advance input position
193  stream.m_index += count;
194  }
195  }
196 
209  // See read_array note above.
210  template <typename IT, typename Stream>
211  static inline void write_array(Stream & stream, const IT & start, const IT & end) throw(stream_exception) {
212  typedef typename Stream::item_type T;
213  IT i = start;
214  while (i != end) {
215  if (stream.m_index >= stream.block_items()) stream.update_block();
216 
217  size_t streamRemaining = end - i;
218  size_t blockRemaining = stream.block_items()-stream.m_index;
219 
220  IT till = (blockRemaining < streamRemaining) ? (i + blockRemaining) : end;
221 
222  T * dest = reinterpret_cast<T*>(stream.get_block().data) + stream.m_index;
223 
224  std::copy(i, till, dest);
225 
226  stream.m_index += till - i;
227  stream.write_update();
228  i = till;
229  }
230  }
231 
240  void update_block();
241 
244  memory_size_type m_index;
248  stream_size_type m_nextBlock;
251  memory_size_type m_nextIndex;
255  stream_size_type m_blockStartIndex;
256 
257 private:
258  inline child_t & self() {return *static_cast<child_t*>(this);}
259  inline const child_t & self() const {return *static_cast<const child_t*>(this);}
260 };
261 
262 } // namespace tpie
263 
264 #endif // __TPIE_STREAM_CRTP_H__
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:248
static void write_array(Stream &stream, const IT &start, const IT &end)
Write several items to the stream.
Definition: stream_crtp.h:211
Typesafe bitflags.
static void read_array(Stream &stream, const IT &start, const IT &end)
Reads several items from the stream.
Definition: stream_crtp.h:165
stream_size_type offset() const
Calculate the current offset in the stream.
Definition: stream_crtp.h:90
offset_type
Type describing how we should interpret the offset supplied to seek.
Definition: stream_crtp.h:38
memory_size_type m_index
Item index into the current block, or maxint if we don't have a block.
Definition: stream_crtp.h:244
Exception classes.
memory_size_type m_nextIndex
After a cross-block seek: Item index into next block.
Definition: stream_crtp.h:251
void seek(stream_offset_type offset, offset_type whence=beginning)
Moves the logical offset in the stream.
Definition: stream_crtp.h:50
bool can_read_back() const
Check if we can read an item with read_back().
Definition: stream_crtp.h:119
bool can_read() const
Check if we can read an item with read().
Definition: stream_crtp.h:108
void update_block()
Fetch block from disk as indicated by m_nextBlock, writing old block to disk if needed.
stream_size_type m_blockStartIndex
The file-level item index of the first item in the current block.
Definition: stream_crtp.h:255
stream_size_type size() const
Get the size of the file measured in items.
Definition: stream_crtp.h:132