00001
00002
00013 #ifndef EFORMAT_PAGEDMEMORY_H
00014 #define EFORMAT_PAGEDMEMORY_H
00015
00016 #include <stdint.h>
00017 #include <sys/uio.h>
00018 #include "eformat/util.h"
00019 #include "eformat/TooBigCountIssue.h"
00020 #include "eformat/NotAlignedIssue.h"
00021 #include "eformat/OutOfBoundsIssue.h"
00022
00026 #define CAST32(x) reinterpret_cast<const uint32_t*>(x)
00027
00028 namespace eformat {
00029
00039 template <unsigned int TMAXPAGES=128> class PagedMemory {
00040
00041 public:
00042
00043 static const unsigned int MAXPAGES;
00044
00045 public:
00046
00061 PagedMemory (const struct iovec* pages, size_t count);
00062
00066 inline const struct iovec* pages (void) const { return m_iovec; }
00067
00071 inline size_t count (void) const { return m_count; }
00072
00076 inline size_t size (void) const { return m_size; }
00077
00078 public:
00079
00086 typedef struct node_t {
00087 const struct iovec* page;
00088 size_t start;
00089 size_t end;
00090 node_t* previous;
00091 node_t* next;
00092 } node_t;
00093
00094 public:
00095
00101 class const_iterator {
00102
00103 private:
00104
00105 friend class PagedMemory;
00106
00115 const_iterator (const node_t* node, size_t offset)
00116 : m_node(node), m_off(offset) {}
00117
00118
00119 public:
00120
00125 const_iterator () : m_node(), m_off() {}
00126
00132 const_iterator (const const_iterator& other)
00133 : m_node(other.m_node), m_off(other.m_off) {}
00134
00138 ~const_iterator () {}
00139
00145 const_iterator& operator= (const const_iterator& other);
00146
00152 bool operator!= (const const_iterator& other) const;
00153
00159 inline bool operator== (const const_iterator& other) const
00160 { return !(*this != other); }
00161
00167 uint32_t operator[] (size_t pos) const;
00168
00175 uint32_t at (size_t pos) const;
00176
00182 inline uint32_t operator* (void) const
00183 { return CAST32(m_node->page->iov_base)[m_off-m_node->start]; }
00184
00189 const_iterator& operator++ (void);
00190
00195 const_iterator& operator-- ();
00196
00202 const_iterator& operator+= (size_t offset);
00203
00209 const_iterator& operator-= (size_t offset);
00210
00216 inline bool operator< (const const_iterator& other) const
00217 { return m_off < other.m_off; }
00218
00224 inline bool operator> (const const_iterator& other) const
00225 { return m_off > other.m_off; }
00226
00232 inline int32_t operator- (const const_iterator& other) const
00233 { return (int32_t)m_off - (int32_t)other.m_off; }
00234
00235 private:
00236
00237 const node_t* m_node;
00238 size_t m_off;
00239
00240 };
00241
00242 public:
00243
00249 inline const_iterator begin (void) const
00250 { return const_iterator(m_node, 0); }
00251
00257 inline const_iterator end (void) const
00258 { return const_iterator(&m_node[m_count], m_size); }
00259
00260 private:
00261
00262 const struct iovec* m_iovec;
00263 size_t m_count;
00264 node_t m_node[TMAXPAGES];
00265 size_t m_size;
00266
00267 };
00268
00269 }
00270
00271 template <unsigned int TMAXPAGES> const unsigned int
00272 eformat::PagedMemory<TMAXPAGES>::MAXPAGES = TMAXPAGES;
00273
00274 template <unsigned int TMAXPAGES> eformat::PagedMemory<TMAXPAGES>::PagedMemory
00275 (const struct iovec* pages, size_t count)
00276 : m_iovec(pages),
00277 m_count(count),
00278 m_size(0)
00279 {
00280 if (m_count > MAXPAGES) {
00281
00282 throw EFORMAT_TOO_BIG_COUNT(count, MAXPAGES);
00283 }
00284 for (size_t i=0; i<count; ++i) {
00285 m_node[i].page = &pages[i];
00286 if (pages[i].iov_len % 4 != 0) {
00287
00288 throw EFORMAT_NOT_ALIGNED(pages[i].iov_base, pages[i].iov_len);
00289 }
00290 m_node[i].start = m_size;
00291 m_size += pages[i].iov_len >> 2;
00292 m_node[i].end = m_size;
00293 if (i > 0) m_node[i].previous = &m_node[i-1];
00294 else m_node[i].previous = 0;
00295 if (i < (count-1) ) m_node[i].next = &m_node[i+1];
00296 else m_node[i].next = 0;
00297 }
00298 }
00299
00300 template <unsigned int TMAXPAGES> typename eformat::PagedMemory<TMAXPAGES>::const_iterator&
00301 eformat::PagedMemory<TMAXPAGES>::const_iterator::operator=
00302 (const typename eformat::PagedMemory<TMAXPAGES>::const_iterator& other)
00303 {
00304 m_node = other.m_node;
00305 m_off = other.m_off;
00306 return *this;
00307 }
00308
00309 template <unsigned int TMAXPAGES>
00310 bool eformat::PagedMemory<TMAXPAGES>::const_iterator::operator!=
00311 (const typename eformat::PagedMemory<TMAXPAGES>::const_iterator& other) const
00312 {
00313 return (m_node == other.m_node && m_off == other.m_off)?false:true;
00314 }
00315
00316 template <unsigned int TMAXPAGES>
00317 uint32_t eformat::PagedMemory<TMAXPAGES>::const_iterator::operator[]
00318 (size_t pos) const
00319 {
00320 if (m_off + pos < m_node->end) {
00321 return CAST32(m_node->page->iov_base)[(m_off+pos)-m_node->start];
00322 }
00323
00324 const_iterator it = *this;
00325 it += pos;
00326 return *it;
00327 }
00328
00329 template <unsigned int TMAXPAGES>
00330 uint32_t eformat::PagedMemory<TMAXPAGES>::const_iterator::at (size_t pos) const
00331 {
00332
00333 if (m_off + pos < m_node->end) {
00334 return CAST32(m_node->page->iov_base)[(m_off+pos)-m_node->start];
00335 }
00336
00337
00338 if (!m_node || (m_node->next == 0 && (m_off+pos) >= m_node->end))
00339 throw EFORMAT_OUT_OF_BOUNDS(0, pos << 2);
00340
00341
00342
00343 const_iterator it = *this;
00344 it += pos;
00345 return it.at(0);
00346 }
00347
00348 template <unsigned int TMAXPAGES> typename eformat::PagedMemory<TMAXPAGES>::const_iterator&
00349 eformat::PagedMemory<TMAXPAGES>::const_iterator::operator++ (void)
00350 {
00351 ++m_off;
00352 if ( m_off >= (m_node->end) ) {
00353 if (!m_node->next) {
00354 m_off = m_node->end;
00355 return *this;
00356 }
00357 m_node = m_node->next;
00358 m_off = m_node->start;
00359 }
00360 return *this;
00361 }
00362
00363 template <unsigned int TMAXPAGES> typename eformat::PagedMemory<TMAXPAGES>::const_iterator&
00364 eformat::PagedMemory<TMAXPAGES>::const_iterator::operator-- (void)
00365 {
00366 --m_off;
00367 if ( m_off < (m_node->start) ) {
00368 if (!m_node->previous) {
00369 m_off = m_node->start;
00370 return *this;
00371 }
00372 m_node = m_node->previous;
00373 m_off = m_node->end - 1;
00374 }
00375 return *this;
00376 }
00377
00378 template <unsigned int TMAXPAGES> typename eformat::PagedMemory<TMAXPAGES>::const_iterator&
00379 eformat::PagedMemory<TMAXPAGES>::const_iterator::operator+= (size_t offset)
00380 {
00381 size_t aim = offset + m_off;
00382 while (aim >= (m_node->end)) {
00383 if (m_node->next) m_node = m_node->next;
00384 else {
00385 m_off = m_node->end;
00386 return *this;
00387 }
00388 }
00389 m_off = aim;
00390 return *this;
00391 }
00392
00393 template <unsigned int TMAXPAGES> typename eformat::PagedMemory<TMAXPAGES>::const_iterator&
00394 eformat::PagedMemory<TMAXPAGES>::const_iterator::operator-= (size_t offset)
00395 {
00396 size_t aim = m_off - offset;
00397 while (aim < (m_node->start)) {
00398 if (m_node->previous) m_node = m_node->previous;
00399 else {
00400 m_off = m_node->start;
00401 return *this;
00402 }
00403 }
00404 m_off = aim;
00405 return *this;
00406 }
00407
00408 #endif