Fairport
v1.0.38
|
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