Fairport  v1.0.38
fairport/ndb/node.h
Go to the documentation of this file.
00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 #ifndef FAIRPORT_NDB_NODE_H
00010 #define FAIRPORT_NDB_NODE_H
00011 
00012 #include <vector>
00013 #include <algorithm>
00014 #include <functional>
00015 #include <memory>
00016 #include <cassert>
00017 #include <boost/iterator/transform_iterator.hpp>
00018 #include <boost/iostreams/concepts.hpp>
00019 #ifdef _MSC_VER
00020 #pragma warning(push)
00021 #pragma warning(disable:4244)
00022 #endif
00023 #include <boost/iostreams/stream.hpp>
00024 #ifdef _MSC_VER
00025 #pragma warning(pop)
00026 #endif
00027 
00028 #include "fairport/util/util.h"
00029 #include "fairport/util/btree.h"
00030 
00031 #include "fairport/ndb/database_iface.h"
00032 
00033 #ifdef _MSC_VER
00034 #pragma warning(push)
00035 #pragma warning(disable:4250)
00036 #endif
00037 
00038 namespace fairport
00039 {
00040 
00043 
00061 class node_impl : public std::tr1::enable_shared_from_this<node_impl>
00062 {
00063 public:
00069     node_impl(const shared_db_ptr& db, const node_info& info)
00070         : m_id(info.id), m_original_data_id(info.data_bid), m_original_sub_id(info.sub_bid), m_original_parent_id(info.parent_id), m_parent_id(info.parent_id), m_db(db) { }
00071 
00077     node_impl(const std::tr1::shared_ptr<node_impl>& container_node, const subnode_info& info)
00078         : m_id(info.id), m_original_data_id(info.data_bid), m_original_sub_id(info.sub_bid), m_original_parent_id(0), m_parent_id(0), m_pcontainer_node(container_node), m_db(container_node->m_db) { }
00079 
00082     node_id get_id() const { return m_id; }
00085     block_id get_data_id() const;
00088     block_id get_sub_id() const;
00089 
00096     node_id get_parent_id() const { return m_parent_id; }
00097 
00100     bool is_subnode() const { return m_pcontainer_node; }
00101 
00104     std::tr1::shared_ptr<data_block> get_data_block() const
00105         { ensure_data_block(); return m_pdata; }
00108     std::tr1::shared_ptr<subnode_block> get_subnode_block() const 
00109         { ensure_sub_block(); return m_psub; }
00110   
00113     shared_db_ptr get_db() const { return m_db; }
00114 
00122     size_t read(std::vector<byte>& buffer, ulong offset) const;
00123     
00130     template<typename T> T read(ulong offset) const;
00131 
00142     size_t read(std::vector<byte>& buffer, uint page_num, ulong offset) const;
00143     
00150     template<typename T> T read(uint page_num, ulong offset) const;
00151 
00157     size_t read_raw(byte* pdest_buffer, size_t size, ulong offset) const;
00158 
00161     size_t size() const;
00162 
00167     size_t get_page_size(uint page_num) const;
00168 
00172     uint get_page_count() const;
00173 
00174     // iterate over subnodes
00177     const_subnodeinfo_iterator subnode_info_begin() const;
00180     const_subnodeinfo_iterator subnode_info_end() const;
00181 
00186     node lookup(node_id id) const;
00187 
00188 private:
00189     node_impl& operator=(const node_impl& other); // = delete
00190 
00193     data_block* ensure_data_block() const;
00196     subnode_block* ensure_sub_block() const;
00197 
00198     const node_id m_id;             
00199     block_id m_original_data_id;    
00200     block_id m_original_sub_id;     
00201     node_id m_original_parent_id;   
00202 
00203     mutable std::tr1::shared_ptr<data_block> m_pdata;    
00204     mutable std::tr1::shared_ptr<subnode_block> m_psub;  
00205     node_id m_parent_id;                            
00206 
00207     std::tr1::shared_ptr<node_impl> m_pcontainer_node;   
00208 
00209     shared_db_ptr m_db; 
00210 };
00211 
00220 class subnode_transform_info : public std::unary_function<subnode_info, node>
00221 {
00222 public:
00225     subnode_transform_info(const std::tr1::shared_ptr<node_impl>& parent)
00226         : m_parent(parent) { }
00227 
00231     node operator()(const subnode_info& info) const;
00232 
00233 private:
00234     std::tr1::shared_ptr<node_impl> m_parent; 
00235 };
00236 
00243 class node_stream_device : public boost::iostreams::device<boost::iostreams::input_seekable>
00244 {
00245 public:
00247     node_stream_device() : m_pos(0) { }
00248 
00253     std::streamsize read(char* pbuffer, std::streamsize n); 
00254 
00259     std::streampos seek(boost::iostreams::stream_offset off, std::ios_base::seekdir way);
00260 
00261 private:
00262     friend class node;
00264     node_stream_device(std::tr1::shared_ptr<node_impl>& _node) : m_pos(0), m_pnode(_node) { }
00265 
00266     std::streamsize m_pos;              
00267     std::tr1::shared_ptr<node_impl> m_pnode; 
00268 };
00269 
00273 typedef boost::iostreams::stream<node_stream_device> node_stream;
00274 
00296 class node
00297 {
00298 public:
00301     typedef boost::transform_iterator<subnode_transform_info, const_subnodeinfo_iterator> subnode_iterator;
00302 
00304     node(const shared_db_ptr& db, const node_info& info)
00305         : m_pimpl(new node_impl(db, info)) { }
00306 
00312     node(const node& container_node, const subnode_info& info)
00313         : m_pimpl(new node_impl(container_node.m_pimpl, info)) { }
00315     node(const std::tr1::shared_ptr<node_impl>& container_node, const subnode_info& info)
00316         : m_pimpl(new node_impl(container_node, info)) { }
00317 
00323     node(const node& other)
00324         : m_pimpl(other.m_pimpl) { }
00325 
00327     node_id get_id() const { return m_pimpl->get_id(); }
00329     block_id get_data_id() const { return m_pimpl->get_data_id(); }
00331     block_id get_sub_id() const { return m_pimpl->get_sub_id(); }
00332 
00334     node_id get_parent_id() const { return m_pimpl->get_parent_id(); } 
00336     bool is_subnode() const { return m_pimpl->is_subnode(); } 
00337 
00339     std::tr1::shared_ptr<data_block> get_data_block() const
00340         { return m_pimpl->get_data_block(); }
00342     std::tr1::shared_ptr<subnode_block> get_subnode_block() const 
00343         { return m_pimpl->get_subnode_block(); } 
00344 
00346     shared_db_ptr get_db() const { return m_pimpl->get_db(); }
00347 
00349     size_t read(std::vector<byte>& buffer, ulong offset) const
00350         { return m_pimpl->read(buffer, offset); }
00352     template<typename T> T read(ulong offset) const
00353         { return m_pimpl->read<T>(offset); }
00355     size_t read(std::vector<byte>& buffer, uint page_num, ulong offset) const
00356         { return m_pimpl->read(buffer, page_num, offset); }
00358     template<typename T> T read(uint page_num, ulong offset) const
00359         { return m_pimpl->read<T>(page_num, offset); }
00360 
00370     node_stream_device open_as_stream()
00371         { return node_stream_device(m_pimpl); }
00372 
00374     size_t size() const { return m_pimpl->size(); }
00376     size_t get_page_size(uint page_num) const 
00377         { return m_pimpl->get_page_size(page_num); }
00379     uint get_page_count() const { return m_pimpl->get_page_count(); }
00380 
00381     // iterate over subnodes
00383     const_subnodeinfo_iterator subnode_info_begin() const
00384         { return m_pimpl->subnode_info_begin(); }
00386     const_subnodeinfo_iterator subnode_info_end() const
00387         { return m_pimpl->subnode_info_end(); } 
00388     
00396     subnode_iterator subnode_begin() const
00397         { return boost::make_transform_iterator(subnode_info_begin(), subnode_transform_info(m_pimpl)); }
00398  
00406     subnode_iterator subnode_end() const
00407         { return boost::make_transform_iterator(subnode_info_end(), subnode_transform_info(m_pimpl)); }
00408 
00410     node lookup(node_id id) const
00411         { return m_pimpl->lookup(id); }
00412 
00413 private:
00414     std::tr1::shared_ptr<node_impl> m_pimpl; 
00415 };
00416 
00419 
00440 class block
00441 {
00442 public:
00446     block(const shared_db_ptr& db, const block_info& info)
00447         : m_modified(false), m_size(info.size), m_id(info.id), m_address(info.address), m_db(db) { }
00448 
00449     virtual ~block() { }
00450 
00453     virtual bool is_internal() const = 0;
00454 
00457     size_t get_disk_size() const { return m_size; }
00458 
00461     block_id get_id() const { return m_id; }
00462 
00465     ulonglong get_address() const { return m_address; }
00466 
00467 protected:
00468     shared_db_ptr get_db_ptr() const { return shared_db_ptr(m_db); }
00469     virtual void trim() { }
00470 
00471     bool m_modified;        
00472     size_t m_size;          
00473     block_id m_id;          
00474     ulonglong m_address;    
00475 
00476     weak_db_ptr m_db;
00477 };
00478 
00486 class data_block : public block
00487 {
00488 public:
00493     data_block(const shared_db_ptr& db, const block_info& info, size_t total_size)
00494         : block(db, info), m_total_size(total_size) { }
00495     virtual ~data_block() { }
00496 
00504     size_t read(std::vector<byte>& buffer, ulong offset) const;
00505 
00512     template<typename T> T read(ulong offset) const;
00513 
00519     virtual size_t read_raw(byte* pdest_buffer, size_t size, ulong offset) const = 0;
00520 
00524     virtual uint get_page_count() const = 0;
00525 
00531     virtual std::tr1::shared_ptr<external_block> get_page(uint page_num) const = 0;
00532 
00535     size_t get_total_size() const { return m_total_size; }
00536 
00537 protected:
00538     size_t m_total_size;    
00539 };
00540 
00553 class extended_block : 
00554     public data_block, 
00555     public std::tr1::enable_shared_from_this<extended_block>
00556 {
00557 public:
00567 #ifndef BOOST_NO_RVALUE_REFERENCES
00568     extended_block(const shared_db_ptr& db, const block_info& info, ushort level, size_t total_size, size_t child_max_total_size, ulong page_max_count, ulong child_page_max_count, std::vector<block_id> bi)
00569         : data_block(db, info, total_size), m_child_max_total_size(child_max_total_size), m_child_max_page_count(child_page_max_count), m_max_page_count(page_max_count), m_level(level), m_block_info(std::move(bi)), m_child_blocks(m_block_info.size()) { }
00570 #else
00571     extended_block(const shared_db_ptr& db, const block_info& info, ushort level, size_t total_size, size_t child_max_total_size, ulong page_max_count, ulong child_page_max_count, const std::vector<block_id>& bi)
00572         : data_block(db, info, total_size), m_child_max_total_size(child_max_total_size), m_child_max_page_count(child_page_max_count), m_max_page_count(page_max_count), m_level(level), m_block_info(bi), m_child_blocks(m_block_info.size()) { }
00573 #endif
00574 
00575     size_t read_raw(byte* pdest_buffer, size_t size, ulong offset) const;
00576     
00577     uint get_page_count() const;
00578     std::tr1::shared_ptr<external_block> get_page(uint page_num) const;
00579     
00585     ushort get_level() const { return m_level; }
00586     bool is_internal() const { return true; }
00587 
00588 private:
00589     extended_block& operator=(const extended_block& other); // = delete
00590     data_block* get_child_block(uint index) const;
00591 
00592     const size_t m_child_max_total_size;    
00593     const ulong m_child_max_page_count;     
00594     const ulong m_max_page_count;           
00595 
00597     size_t get_max_size() const { return m_child_max_total_size * m_max_page_count; }
00598 
00599     const ushort m_level;                   
00600     std::vector<block_id> m_block_info;     
00601     mutable std::vector<std::tr1::shared_ptr<data_block> > m_child_blocks; 
00602 };
00603 
00611 class external_block : 
00612     public data_block, 
00613     public std::tr1::enable_shared_from_this<external_block>
00614 {
00615 public:
00621 #ifndef BOOST_NO_RVALUE_REFERENCES
00622     external_block(const shared_db_ptr& db, const block_info& info, size_t max_size, std::vector<byte> buffer)
00623         : data_block(db, info, info.size), m_max_size(max_size), m_buffer(std::move(buffer)) { }
00624 #else
00625     external_block(const shared_db_ptr& db, const block_info& info, size_t max_size, const std::vector<byte>& buffer)
00626         : data_block(db, info, info.size), m_max_size(max_size), m_buffer(buffer) { }
00627 #endif
00628 
00629     size_t read_raw(byte* pdest_buffer, size_t size, ulong offset) const;
00630 
00631     uint get_page_count() const { return 1; }
00632     std::tr1::shared_ptr<external_block> get_page(uint page_num) const;
00633 
00634     bool is_internal() const { return false; }
00635 
00636 private:
00637     external_block& operator=(const external_block& other); // = delete
00638 
00639     const size_t m_max_size;
00640     size_t get_max_size() const { return m_max_size; }
00641 
00642     std::vector<byte> m_buffer;
00643 };
00644 
00645 
00656 class subnode_block : 
00657     public block, 
00658     public virtual btree_node<node_id, subnode_info>
00659 {
00660 public:
00665     subnode_block(const shared_db_ptr& db, const block_info& info, ushort level)
00666         : block(db, info), m_level(level) { }
00667 
00668     virtual ~subnode_block() { }
00669 
00672     ushort get_level() const { return m_level; }
00673 
00674     bool is_internal() const { return true; }
00675     
00676 protected:
00677     ushort m_level; 
00678 };
00679 
00692 class subnode_nonleaf_block : 
00693     public subnode_block, 
00694     public btree_node_nonleaf<node_id, subnode_info>, 
00695     public std::tr1::enable_shared_from_this<subnode_nonleaf_block>
00696 {
00697 public:
00702 #ifndef BOOST_NO_RVALUE_REFERENCES
00703     subnode_nonleaf_block(const shared_db_ptr& db, const block_info& info, std::vector<std::pair<node_id, block_id> > subblocks)
00704         : subnode_block(db, info, 1), m_subnode_info(std::move(subblocks)), m_child_blocks(m_subnode_info.size()) { }
00705 #else
00706     subnode_nonleaf_block(const shared_db_ptr& db, const block_info& info, const std::vector<std::pair<node_id, block_id> >& subblocks)
00707         : subnode_block(db, info, 1), m_subnode_info(subblocks), m_child_blocks(m_subnode_info.size()) { }
00708 #endif
00709 
00710     // btree_node_nonleaf implementation
00711     const node_id& get_key(uint pos) const
00712         { return m_subnode_info[pos].first; }
00713     subnode_block* get_child(uint pos);
00714     const subnode_block* get_child(uint pos) const;
00715     uint num_values() const { return m_subnode_info.size(); }
00716     
00717 private:
00718     std::vector<std::pair<node_id, block_id> > m_subnode_info;           
00719     mutable std::vector<std::tr1::shared_ptr<subnode_block> > m_child_blocks; 
00720 };
00721 
00729 class subnode_leaf_block : 
00730     public subnode_block, 
00731     public btree_node_leaf<node_id, subnode_info>, 
00732     public std::tr1::enable_shared_from_this<subnode_leaf_block>
00733 {
00734 public:
00739 #ifndef BOOST_NO_RVALUE_REFERENCES
00740     subnode_leaf_block(const shared_db_ptr& db, const block_info& info, std::vector<std::pair<node_id, subnode_info> > subnodes)
00741         : subnode_block(db, info, 0), m_subnodes(std::move(subnodes)) { }
00742 #else
00743     subnode_leaf_block(const shared_db_ptr& db, const block_info& info, const std::vector<std::pair<node_id, subnode_info> >& subnodes)
00744         : subnode_block(db, info, 0), m_subnodes(subnodes) { }
00745 #endif
00746 
00747     // btree_node_leaf implementation
00748     const subnode_info& get_value(uint pos) const 
00749         { return m_subnodes[pos].second; }
00750     const node_id& get_key(uint pos) const
00751         { return m_subnodes[pos].first; }
00752     uint num_values() const
00753         { return m_subnodes.size(); }
00754 
00755 private:
00756     std::vector<std::pair<node_id, subnode_info> > m_subnodes;   
00757 };
00758 
00759 } // end fairport namespace
00760 
00761 inline fairport::node fairport::subnode_transform_info::operator()(const fairport::subnode_info& info) const
00762 { 
00763     return node(m_parent, info); 
00764 }
00765 
00766 inline fairport::block_id fairport::node_impl::get_data_id() const
00767 { 
00768     if(m_pdata)
00769         return m_pdata->get_id();
00770     
00771     return m_original_data_id;
00772 }
00773 
00774 inline fairport::block_id fairport::node_impl::get_sub_id() const
00775 { 
00776     if(m_psub)
00777         return m_psub->get_id();
00778     
00779     return m_original_sub_id;
00780 }
00781 
00782 inline size_t fairport::node_impl::size() const
00783 {
00784     return ensure_data_block()->get_total_size();
00785 }
00786 
00787 inline size_t fairport::node_impl::get_page_size(uint page_num) const
00788 {
00789     return ensure_data_block()->get_page(page_num)->get_total_size();
00790 }
00791     
00792 inline fairport::uint fairport::node_impl::get_page_count() const 
00793 { 
00794     return ensure_data_block()->get_page_count(); 
00795 }
00796 
00797 inline size_t fairport::node_impl::read(std::vector<byte>& buffer, ulong offset) const
00798 { 
00799     return ensure_data_block()->read(buffer, offset); 
00800 }
00801 
00802 inline size_t fairport::node_impl::read_raw(byte* pdest_buffer, size_t size, ulong offset) const
00803 { 
00804     return ensure_data_block()->read_raw(pdest_buffer, size, offset); 
00805 }
00806 
00807 template<typename T> 
00808 inline T fairport::node_impl::read(ulong offset) const
00809 {
00810     return ensure_data_block()->read<T>(offset); 
00811 }
00812     
00813 inline size_t fairport::node_impl::read(std::vector<byte>& buffer, uint page_num, ulong offset) const
00814 { 
00815     return ensure_data_block()->get_page(page_num)->read(buffer, offset); 
00816 }
00817 
00818 template<typename T> 
00819 inline T fairport::node_impl::read(uint page_num, ulong offset) const
00820 {
00821     return ensure_data_block()->get_page(page_num)->read<T>(offset); 
00822 }
00823 
00824 inline fairport::data_block* fairport::node_impl::ensure_data_block() const
00825 { 
00826     if(!m_pdata) 
00827         m_pdata = m_db->read_data_block(m_original_data_id); 
00828 
00829     return m_pdata.get();
00830 }
00831     
00832 inline fairport::subnode_block* fairport::node_impl::ensure_sub_block() const
00833 { 
00834     if(!m_psub) 
00835         m_psub = m_db->read_subnode_block(m_original_sub_id); 
00836 
00837     return m_psub.get();
00838 }
00839 
00840 inline std::streamsize fairport::node_stream_device::read(char* pbuffer, std::streamsize n)
00841 {
00842     size_t read = m_pnode->read_raw(reinterpret_cast<byte*>(pbuffer), static_cast<size_t>(n), static_cast<size_t>(m_pos));
00843     m_pos += read;
00844 
00845     if(read)
00846         return read;
00847     else
00848         return -1;
00849 }
00850 
00851 inline std::streampos fairport::node_stream_device::seek(boost::iostreams::stream_offset off, std::ios_base::seekdir way)
00852 {
00853 #if defined(_MSC_VER) && (_MSC_VER < 1600)
00854 #pragma warning(push)
00855 #pragma warning(disable:4244)
00856 #endif
00857     if(way == std::ios_base::beg)
00858             m_pos = off;
00859     else if(way == std::ios_base::end)
00860         m_pos = m_pnode->size() + off;
00861     else
00862         m_pos += off;
00863 #if defined(_MSC_VER) && (_MSC_VER < 1600)
00864 #pragma warning(pop)
00865 #endif
00866 
00867     if(m_pos < 0)
00868         m_pos = 0;
00869     else if(static_cast<size_t>(m_pos) > m_pnode->size())
00870         m_pos = m_pnode->size();
00871 
00872     return m_pos;
00873 }
00874 
00875 inline fairport::subnode_block* fairport::subnode_nonleaf_block::get_child(uint pos)
00876 {
00877     if(m_child_blocks[pos] == NULL)
00878     {
00879         m_child_blocks[pos] = get_db_ptr()->read_subnode_block(m_subnode_info[pos].second);
00880     }
00881 
00882     return m_child_blocks[pos].get();
00883 }
00884 
00885 inline const fairport::subnode_block* fairport::subnode_nonleaf_block::get_child(uint pos) const
00886 {
00887     if(m_child_blocks[pos] == NULL)
00888     {
00889         m_child_blocks[pos] = get_db_ptr()->read_subnode_block(m_subnode_info[pos].second);
00890     }
00891 
00892     return m_child_blocks[pos].get();
00893 }
00894 
00895 inline size_t fairport::data_block::read(std::vector<byte>& buffer, ulong offset) const
00896 {
00897     size_t read_size = buffer.size();
00898     
00899     if(read_size > 0)
00900     {
00901         if(offset >= get_total_size())
00902             throw std::out_of_range("offset >= size()");
00903 
00904         read_size = read_raw(&buffer[0], read_size, offset);
00905     }
00906 
00907     return read_size;
00908 }
00909 
00910 template<typename T> 
00911 inline T fairport::data_block::read(ulong offset) const
00912 {
00913     if(offset >= get_total_size())
00914         throw std::out_of_range("offset >= size()");
00915     if(sizeof(T) + offset > get_total_size())
00916         throw std::out_of_range("sizeof(T) + offset >= size()");
00917 
00918     T t;
00919     read_raw(reinterpret_cast<byte*>(&t), sizeof(T), offset);
00920 
00921     return t;
00922 }
00923 
00924 inline fairport::uint fairport::extended_block::get_page_count() const
00925 {
00926     assert(m_child_max_total_size % m_child_max_page_count == 0);
00927     uint page_size = m_child_max_total_size / m_child_max_page_count;
00928     uint page_count = (get_total_size() / page_size) + ((get_total_size() % page_size) != 0 ? 1 : 0);
00929     assert(get_level() == 2 || page_count == m_block_info.size());
00930 
00931     return page_count;
00932 }
00933 
00934 inline fairport::data_block* fairport::extended_block::get_child_block(uint index) const
00935 {
00936     if(index >= m_child_blocks.size())
00937         throw std::out_of_range("index >= m_child_blocks.size()");
00938 
00939     if(m_child_blocks[index] == NULL)
00940     {
00941         m_child_blocks[index] = get_db_ptr()->read_data_block(m_block_info[index]);
00942     }
00943 
00944     return m_child_blocks[index].get();
00945 }
00946 
00947 inline std::tr1::shared_ptr<fairport::external_block> fairport::extended_block::get_page(uint page_num) const
00948 {
00949     uint page = page_num / m_child_max_page_count;
00950     return get_child_block(page)->get_page(page_num % m_child_max_page_count);
00951 }
00952 
00953 inline std::tr1::shared_ptr<fairport::external_block> fairport::external_block::get_page(uint index) const
00954 {
00955     if(index != 0)
00956         throw std::out_of_range("index > 0");
00957 
00958     return std::tr1::const_pointer_cast<external_block>(this->shared_from_this());
00959 }
00960 
00961 inline size_t fairport::external_block::read_raw(byte* pdest_buffer, size_t size, ulong offset) const
00962 {
00963     size_t read_size = size;
00964 
00965     assert(offset <= get_total_size());
00966 
00967     if(offset + size > get_total_size())
00968         read_size = get_total_size() - offset;
00969 
00970     memcpy(pdest_buffer, &m_buffer[offset], read_size);
00971 
00972     return read_size;
00973 }
00974 
00975 inline size_t fairport::extended_block::read_raw(byte* pdest_buffer, size_t size, ulong offset) const
00976 {
00977     assert(offset <= get_total_size());
00978 
00979     if(offset + size > get_total_size())
00980         size = get_total_size() - offset;
00981 
00982     byte* pend = pdest_buffer + size;
00983 
00984     size_t total_bytes_read = 0;
00985 
00986     while(pdest_buffer != pend)
00987     {
00988         // the child this read starts on
00989         uint child_pos = offset / m_child_max_total_size;
00990         // offset into the child block this read starts on
00991         ulong child_offset = offset % m_child_max_total_size;
00992 
00993         // call into our child to read the data
00994         size_t bytes_read = get_child_block(child_pos)->read_raw(pdest_buffer, size, child_offset);
00995         assert(bytes_read <= size);
00996     
00997         // adjust pointers accordingly
00998         pdest_buffer += bytes_read;
00999         offset += bytes_read;
01000         size -= bytes_read;
01001         total_bytes_read += bytes_read;
01002 
01003         assert(pdest_buffer <= pend);
01004     }
01005 
01006     return total_bytes_read;
01007 }
01008 
01009 inline fairport::const_subnodeinfo_iterator fairport::node_impl::subnode_info_begin() const
01010 {
01011     const subnode_block* pblock = ensure_sub_block();
01012     return pblock->begin();
01013 }
01014 
01015 inline fairport::const_subnodeinfo_iterator fairport::node_impl::subnode_info_end() const
01016 {
01017     const subnode_block* pblock = ensure_sub_block();
01018     return pblock->end();
01019 }
01020 
01021 inline fairport::node fairport::node_impl::lookup(node_id id) const
01022 {
01023     return node(std::tr1::const_pointer_cast<node_impl>(shared_from_this()), ensure_sub_block()->lookup(id));
01024 }
01025 
01026 #ifdef _MSC_VER
01027 #pragma warning(pop)
01028 #endif
01029 
01030 #endif