intersegment_ptr.hpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044
  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
  4. // Software License, Version 1.0. (See accompanying file
  5. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // See http://www.boost.org/libs/interprocess for documentation.
  8. //
  9. //////////////////////////////////////////////////////////////////////////////
  10. #ifndef BOOST_INTERPROCESS_INTERSEGMENT_PTR_HPP
  11. #define BOOST_INTERPROCESS_INTERSEGMENT_PTR_HPP
  12. #ifndef BOOST_CONFIG_HPP
  13. # include <boost/config.hpp>
  14. #endif
  15. #
  16. #if defined(BOOST_HAS_PRAGMA_ONCE)
  17. # pragma once
  18. #endif
  19. #include <boost/interprocess/detail/config_begin.hpp>
  20. #include <boost/interprocess/detail/workaround.hpp>
  21. // interprocess
  22. #include <boost/interprocess/interprocess_fwd.hpp>
  23. #include <boost/interprocess/sync/scoped_lock.hpp>
  24. #include <boost/interprocess/sync/interprocess_mutex.hpp>
  25. #include <boost/interprocess/containers/flat_map.hpp>
  26. #include <boost/interprocess/containers/vector.hpp> //vector
  27. #include <boost/interprocess/containers/set.hpp> //set
  28. // interprocess/detail
  29. #include <boost/interprocess/detail/multi_segment_services.hpp>
  30. #include <boost/interprocess/detail/utilities.hpp>
  31. #include <boost/interprocess/detail/math_functions.hpp>
  32. #include <boost/interprocess/detail/cast_tags.hpp>
  33. #include <boost/interprocess/detail/mpl.hpp>
  34. // other boost
  35. #include <boost/core/no_exceptions_support.hpp>
  36. #include <boost/static_assert.hpp> //BOOST_STATIC_ASSERT
  37. #include <boost/integer/static_log2.hpp>
  38. #include <boost/assert.hpp> //BOOST_ASSERT
  39. // std
  40. #include <climits> //CHAR_BIT
  41. //!\file
  42. //!
  43. namespace boost {
  44. //Predeclarations
  45. template <class T>
  46. struct has_trivial_constructor;
  47. template <class T>
  48. struct has_trivial_destructor;
  49. namespace interprocess {
  50. template <class T>
  51. struct is_multisegment_ptr;
  52. struct intersegment_base
  53. {
  54. typedef intersegment_base self_t;
  55. BOOST_STATIC_ASSERT((sizeof(std::size_t) == sizeof(void*)));
  56. BOOST_STATIC_ASSERT((sizeof(void*)*CHAR_BIT == 32 || sizeof(void*)*CHAR_BIT == 64));
  57. static const std::size_t size_t_bits = (sizeof(void*)*CHAR_BIT == 32) ? 32 : 64;
  58. static const std::size_t ctrl_bits = 2;
  59. static const std::size_t align_bits = 12;
  60. static const std::size_t align = std::size_t(1) << align_bits;
  61. static const std::size_t max_segment_size_bits = size_t_bits - 2;
  62. static const std::size_t max_segment_size = std::size_t(1) << max_segment_size_bits;
  63. static const std::size_t begin_bits = max_segment_size_bits - align_bits;
  64. static const std::size_t pow_size_bits_helper = static_log2<max_segment_size_bits>::value;
  65. static const std::size_t pow_size_bits =
  66. (max_segment_size_bits == (std::size_t(1) << pow_size_bits_helper)) ?
  67. pow_size_bits_helper : pow_size_bits_helper + 1;
  68. static const std::size_t frc_size_bits =
  69. size_t_bits - ctrl_bits - begin_bits - pow_size_bits;
  70. BOOST_STATIC_ASSERT(((size_t_bits - pow_size_bits - frc_size_bits) >= ctrl_bits ));
  71. static const std::size_t relative_size_bits =
  72. size_t_bits - max_segment_size_bits - ctrl_bits;
  73. static const std::size_t is_pointee_outside = 0;
  74. static const std::size_t is_in_stack = 1;
  75. static const std::size_t is_relative = 2;
  76. static const std::size_t is_segmented = 3;
  77. static const std::size_t is_max_mode = 4;
  78. intersegment_base()
  79. {
  80. this->set_mode(is_pointee_outside);
  81. this->set_null();
  82. }
  83. struct relative_addressing
  84. {
  85. std::size_t ctrl : 2;
  86. std::size_t pow : pow_size_bits;
  87. std::size_t frc : frc_size_bits;
  88. std::size_t beg : begin_bits;
  89. std::ptrdiff_t off : sizeof(std::ptrdiff_t)*CHAR_BIT - 2;
  90. std::ptrdiff_t bits : 2;
  91. };
  92. struct direct_addressing
  93. {
  94. std::size_t ctrl : 2;
  95. std::size_t dummy : sizeof(std::size_t)*CHAR_BIT - 2;
  96. void * addr;
  97. };
  98. struct segmented_addressing
  99. {
  100. std::size_t ctrl : 2;
  101. std::size_t segment : sizeof(std::size_t)*CHAR_BIT - 2;
  102. std::size_t off : sizeof(std::size_t)*CHAR_BIT - 2;
  103. std::size_t bits : 2;
  104. };
  105. union members_t{
  106. relative_addressing relative;
  107. direct_addressing direct;
  108. segmented_addressing segmented;
  109. } members;
  110. BOOST_STATIC_ASSERT(sizeof(members_t) == 2*sizeof(std::size_t));
  111. void *relative_calculate_begin_addr() const
  112. {
  113. const std::size_t mask = ~(align - 1);
  114. std::size_t beg = this->members.relative.beg;
  115. return reinterpret_cast<void*>((((std::size_t)this) & mask) - (beg << align_bits));
  116. }
  117. void relative_set_begin_from_base(void *addr)
  118. {
  119. BOOST_ASSERT(addr < static_cast<void*>(this));
  120. std::size_t off = reinterpret_cast<char*>(this) - reinterpret_cast<char*>(addr);
  121. members.relative.beg = off >> align_bits;
  122. }
  123. //!Obtains the address pointed by the
  124. //!object
  125. std::size_t relative_size() const
  126. {
  127. std::size_t pow = members.relative.pow;
  128. std::size_t size = (std::size_t(1u) << pow);
  129. BOOST_ASSERT(pow >= frc_size_bits);
  130. size |= members.relative.frc << (pow - frc_size_bits);
  131. return size;
  132. }
  133. static std::size_t calculate_size(std::size_t orig_size, std::size_t &pow, std::size_t &frc)
  134. {
  135. if(orig_size < align)
  136. orig_size = align;
  137. orig_size = ipcdetail::get_rounded_size_po2(orig_size, align);
  138. pow = ipcdetail::floor_log2(orig_size);
  139. std::size_t low_size = (std::size_t(1) << pow);
  140. std::size_t diff = orig_size - low_size;
  141. BOOST_ASSERT(pow >= frc_size_bits);
  142. std::size_t rounded = ipcdetail::get_rounded_size_po2
  143. (diff, (std::size_t)(1u << (pow - frc_size_bits)));
  144. if(rounded == low_size){
  145. ++pow;
  146. frc = 0;
  147. rounded = 0;
  148. }
  149. else{
  150. frc = rounded >> (pow - frc_size_bits);
  151. }
  152. BOOST_ASSERT(((frc << (pow - frc_size_bits)) & (align-1))==0);
  153. return low_size + rounded;
  154. }
  155. std::size_t get_mode()const
  156. { return members.direct.ctrl; }
  157. void set_mode(std::size_t mode)
  158. {
  159. BOOST_ASSERT(mode < is_max_mode);
  160. members.direct.ctrl = mode;
  161. }
  162. //!Returns true if object represents
  163. //!null pointer
  164. bool is_null() const
  165. {
  166. return (this->get_mode() < is_relative) &&
  167. !members.direct.dummy &&
  168. !members.direct.addr;
  169. }
  170. //!Sets the object to represent
  171. //!the null pointer
  172. void set_null()
  173. {
  174. if(this->get_mode() >= is_relative){
  175. this->set_mode(is_pointee_outside);
  176. }
  177. members.direct.dummy = 0;
  178. members.direct.addr = 0;
  179. }
  180. static std::size_t round_size(std::size_t orig_size)
  181. {
  182. std::size_t pow, frc;
  183. return calculate_size(orig_size, pow, frc);
  184. }
  185. };
  186. //!Configures intersegment_ptr with the capability to address:
  187. //!2^(sizeof(std::size_t)*CHAR_BIT/2) segment groups
  188. //!2^(sizeof(std::size_t)*CHAR_BIT/2) segments per group.
  189. //!2^(sizeof(std::size_t)*CHAR_BIT/2)-1 bytes maximum per segment.
  190. //!The mapping is implemented through flat_maps synchronized with mutexes.
  191. template <class Mutex>
  192. struct flat_map_intersegment
  193. : public intersegment_base
  194. {
  195. typedef flat_map_intersegment<Mutex> self_t;
  196. void set_from_pointer(const volatile void *ptr)
  197. { this->set_from_pointer(const_cast<const void *>(ptr)); }
  198. //!Obtains the address pointed
  199. //!by the object
  200. void *to_raw_pointer() const
  201. {
  202. if(is_null()){
  203. return 0;
  204. }
  205. switch(this->get_mode()){
  206. case is_relative:
  207. return const_cast<char*>(reinterpret_cast<const char*>(this)) + members.relative.off;
  208. break;
  209. case is_segmented:
  210. {
  211. segment_info_t segment_info;
  212. std::size_t offset;
  213. void *this_base;
  214. get_segment_info_and_offset(this, segment_info, offset, this_base);
  215. char *base = static_cast<char*>(segment_info.group->address_of(this->members.segmented.segment));
  216. return base + this->members.segmented.off;
  217. }
  218. break;
  219. case is_in_stack:
  220. case is_pointee_outside:
  221. return members.direct.addr;
  222. break;
  223. default:
  224. return 0;
  225. break;
  226. }
  227. }
  228. //!Calculates the distance between two basic_intersegment_ptr-s.
  229. //!This only works with two basic_intersegment_ptr pointing
  230. //!to the same segment. Otherwise undefined
  231. std::ptrdiff_t diff(const self_t &other) const
  232. { return static_cast<char*>(this->to_raw_pointer()) - static_cast<char*>(other.to_raw_pointer()); }
  233. //!Returns true if both point to
  234. //!the same object
  235. bool equal(const self_t &y) const
  236. { return this->to_raw_pointer() == y.to_raw_pointer(); }
  237. //!Returns true if *this is less than other.
  238. //!This only works with two basic_intersegment_ptr pointing
  239. //!to the same segment group. Otherwise undefined. Never throws
  240. bool less(const self_t &y) const
  241. { return this->to_raw_pointer() < y.to_raw_pointer(); }
  242. void swap(self_t &other)
  243. {
  244. void *ptr_this = this->to_raw_pointer();
  245. void *ptr_other = other.to_raw_pointer();
  246. other.set_from_pointer(ptr_this);
  247. this->set_from_pointer(ptr_other);
  248. }
  249. //!Sets the object internals to represent the
  250. //!address pointed by ptr
  251. void set_from_pointer(const void *ptr)
  252. {
  253. if(!ptr){
  254. this->set_null();
  255. return;
  256. }
  257. std::size_t mode = this->get_mode();
  258. if(mode == is_in_stack){
  259. members.direct.addr = const_cast<void*>(ptr);
  260. return;
  261. }
  262. if(mode == is_relative){
  263. char *beg_addr = static_cast<char*>(this->relative_calculate_begin_addr());
  264. std::size_t seg_size = this->relative_size();
  265. if(ptr >= beg_addr && ptr < (beg_addr + seg_size)){
  266. members.relative.off = static_cast<const char*>(ptr) - reinterpret_cast<const char*>(this);
  267. return;
  268. }
  269. }
  270. std::size_t ptr_offset;
  271. std::size_t this_offset;
  272. segment_info_t ptr_info;
  273. segment_info_t this_info;
  274. void *ptr_base;
  275. void *this_base;
  276. get_segment_info_and_offset(this, this_info, this_offset, this_base);
  277. if(!this_info.group){
  278. this->set_mode(is_in_stack);
  279. this->members.direct.addr = const_cast<void*>(ptr);
  280. }
  281. else{
  282. get_segment_info_and_offset(ptr, ptr_info, ptr_offset, ptr_base);
  283. if(ptr_info.group != this_info.group){
  284. this->set_mode(is_pointee_outside);
  285. this->members.direct.addr = const_cast<void*>(ptr);
  286. }
  287. else if(ptr_info.id == this_info.id){
  288. this->set_mode(is_relative);
  289. members.relative.off = (static_cast<const char*>(ptr) - reinterpret_cast<const char*>(this));
  290. this->relative_set_begin_from_base(this_base);
  291. std::size_t pow, frc;
  292. std::size_t s = calculate_size(this_info.size, pow, frc);
  293. (void)s;
  294. BOOST_ASSERT(this_info.size == s);
  295. this->members.relative.pow = pow;
  296. this->members.relative.frc = frc;
  297. }
  298. else{
  299. this->set_mode(is_segmented);
  300. this->members.segmented.segment = ptr_info.id;
  301. this->members.segmented.off = ptr_offset;
  302. }
  303. }
  304. }
  305. //!Sets the object internals to represent the address pointed
  306. //!by another flat_map_intersegment
  307. void set_from_other(const self_t &other)
  308. {
  309. this->set_from_pointer(other.to_raw_pointer());
  310. }
  311. //!Increments internal
  312. //!offset
  313. void inc_offset(std::ptrdiff_t bytes)
  314. {
  315. this->set_from_pointer(static_cast<char*>(this->to_raw_pointer()) + bytes);
  316. }
  317. //!Decrements internal
  318. //!offset
  319. void dec_offset(std::ptrdiff_t bytes)
  320. {
  321. this->set_from_pointer(static_cast<char*>(this->to_raw_pointer()) - bytes);
  322. }
  323. //////////////////////////////////////
  324. //////////////////////////////////////
  325. //////////////////////////////////////
  326. flat_map_intersegment()
  327. : intersegment_base()
  328. {}
  329. ~flat_map_intersegment()
  330. {}
  331. private:
  332. class segment_group_t
  333. {
  334. struct segment_data
  335. {
  336. void *addr;
  337. std::size_t size;
  338. };
  339. vector<segment_data> m_segments;
  340. multi_segment_services &m_ms_services;
  341. public:
  342. segment_group_t(multi_segment_services &ms_services)
  343. : m_ms_services(ms_services)
  344. {}
  345. void push_back(void *addr, std::size_t size)
  346. {
  347. segment_data d = { addr, size };
  348. m_segments.push_back(d);
  349. }
  350. void pop_back()
  351. {
  352. BOOST_ASSERT(!m_segments.empty());
  353. m_segments.erase(--m_segments.end());
  354. }
  355. void *address_of(std::size_t segment_id)
  356. {
  357. BOOST_ASSERT(segment_id < (std::size_t)m_segments.size());
  358. return m_segments[segment_id].addr;
  359. }
  360. void clear_segments()
  361. { m_segments.clear(); }
  362. std::size_t get_size() const
  363. { return m_segments.size(); }
  364. multi_segment_services &get_multi_segment_services() const
  365. { return m_ms_services; }
  366. friend bool operator< (const segment_group_t&l, const segment_group_t &r)
  367. { return &l.m_ms_services < &r.m_ms_services; }
  368. };
  369. struct segment_info_t
  370. {
  371. std::size_t size;
  372. std::size_t id;
  373. segment_group_t *group;
  374. segment_info_t()
  375. : size(0), id(0), group(0)
  376. {}
  377. };
  378. typedef set<segment_group_t> segment_groups_t;
  379. typedef boost::interprocess::flat_map
  380. <const void *
  381. ,segment_info_t
  382. ,std::less<const void *> > ptr_to_segment_info_t;
  383. struct mappings_t : Mutex
  384. {
  385. //!Mutex to preserve integrity in multi-threaded
  386. //!enviroments
  387. typedef Mutex mutex_type;
  388. //!Maps base addresses and segment information
  389. //!(size and segment group and id)*
  390. ptr_to_segment_info_t m_ptr_to_segment_info;
  391. ~mappings_t()
  392. {
  393. //Check that all mappings have been erased
  394. BOOST_ASSERT(m_ptr_to_segment_info.empty());
  395. }
  396. };
  397. //Static members
  398. static mappings_t s_map;
  399. static segment_groups_t s_groups;
  400. public:
  401. typedef segment_group_t* segment_group_id;
  402. //!Returns the segment and offset
  403. //!of an address
  404. static void get_segment_info_and_offset(const void *ptr, segment_info_t &segment, std::size_t &offset, void *&base)
  405. {
  406. //------------------------------------------------------------------
  407. boost::interprocess::scoped_lock<typename mappings_t::mutex_type> lock(s_map);
  408. //------------------------------------------------------------------
  409. base = 0;
  410. if(s_map.m_ptr_to_segment_info.empty()){
  411. segment = segment_info_t();
  412. offset = reinterpret_cast<const char*>(ptr) - static_cast<const char*>(0);
  413. return;
  414. }
  415. //Find the first base address greater than ptr
  416. typename ptr_to_segment_info_t::iterator it
  417. = s_map.m_ptr_to_segment_info.upper_bound(ptr);
  418. if(it == s_map.m_ptr_to_segment_info.begin()){
  419. segment = segment_info_t();
  420. offset = reinterpret_cast<const char*>(ptr) - static_cast<const char *>(0);
  421. }
  422. //Go to the previous one
  423. --it;
  424. char * segment_base = const_cast<char*>(reinterpret_cast<const char*>(it->first));
  425. std::size_t segment_size = it->second.size;
  426. if(segment_base <= reinterpret_cast<const char*>(ptr) &&
  427. (segment_base + segment_size) >= reinterpret_cast<const char*>(ptr)){
  428. segment = it->second;
  429. offset = reinterpret_cast<const char*>(ptr) - segment_base;
  430. base = segment_base;
  431. }
  432. else{
  433. segment = segment_info_t();
  434. offset = reinterpret_cast<const char*>(ptr) - static_cast<const char*>(0);
  435. }
  436. }
  437. //!Associates a segment defined by group/id with a base address and size.
  438. //!Returns false if the group is not found or there is an error
  439. static void insert_mapping(segment_group_id group_id, void *ptr, std::size_t size)
  440. {
  441. //------------------------------------------------------------------
  442. boost::interprocess::scoped_lock<typename mappings_t::mutex_type> lock(s_map);
  443. //------------------------------------------------------------------
  444. typedef typename ptr_to_segment_info_t::value_type value_type;
  445. typedef typename ptr_to_segment_info_t::iterator iterator;
  446. typedef std::pair<iterator, bool> it_b_t;
  447. segment_info_t info;
  448. info.group = group_id;
  449. info.size = size;
  450. info.id = group_id->get_size();
  451. it_b_t ret = s_map.m_ptr_to_segment_info.insert(value_type(ptr, info));
  452. BOOST_ASSERT(ret.second);
  453. value_eraser<ptr_to_segment_info_t> v_eraser(s_map.m_ptr_to_segment_info, ret.first);
  454. group_id->push_back(ptr, size);
  455. v_eraser.release();
  456. }
  457. static bool erase_last_mapping(segment_group_id group_id)
  458. {
  459. //------------------------------------------------------------------
  460. boost::interprocess::scoped_lock<typename mappings_t::mutex_type> lock(s_map);
  461. //------------------------------------------------------------------
  462. if(!group_id->get_size()){
  463. return false;
  464. }
  465. else{
  466. void *addr = group_id->address_of(group_id->get_size()-1);
  467. group_id->pop_back();
  468. std::size_t erased = s_map.m_ptr_to_segment_info.erase(addr);
  469. (void)erased;
  470. BOOST_ASSERT(erased);
  471. return true;
  472. }
  473. }
  474. static segment_group_id new_segment_group(multi_segment_services *services)
  475. {
  476. { //------------------------------------------------------------------
  477. boost::interprocess::scoped_lock<typename mappings_t::mutex_type> lock(s_map);
  478. //------------------------------------------------------------------
  479. typedef typename segment_groups_t::iterator iterator;
  480. std::pair<iterator, bool> ret =
  481. s_groups.insert(segment_group_t(*services));
  482. BOOST_ASSERT(ret.second);
  483. return &*ret.first;
  484. }
  485. }
  486. static bool delete_group(segment_group_id id)
  487. {
  488. { //------------------------------------------------------------------
  489. boost::interprocess::scoped_lock<typename mappings_t::mutex_type> lock(s_map);
  490. //------------------------------------------------------------------
  491. bool success = 1u == s_groups.erase(segment_group_t(*id));
  492. if(success){
  493. typedef typename ptr_to_segment_info_t::iterator ptr_to_segment_info_it;
  494. ptr_to_segment_info_it it(s_map.m_ptr_to_segment_info.begin());
  495. while(it != s_map.m_ptr_to_segment_info.end()){
  496. if(it->second.group == id){
  497. it = s_map.m_ptr_to_segment_info.erase(it);
  498. }
  499. else{
  500. ++it;
  501. }
  502. }
  503. }
  504. return success;
  505. }
  506. }
  507. };
  508. //!Static map-segment_info associated with
  509. //!flat_map_intersegment<>
  510. template <class Mutex>
  511. typename flat_map_intersegment<Mutex>::mappings_t
  512. flat_map_intersegment<Mutex>::s_map;
  513. //!Static segment group container associated with
  514. //!flat_map_intersegment<>
  515. template <class Mutex>
  516. typename flat_map_intersegment<Mutex>::segment_groups_t
  517. flat_map_intersegment<Mutex>::s_groups;
  518. //!A smart pointer that can point to a pointee that resides in another memory
  519. //!memory mapped or shared memory segment.
  520. template <class T>
  521. class intersegment_ptr : public flat_map_intersegment<interprocess_mutex>
  522. {
  523. typedef flat_map_intersegment<interprocess_mutex> PT;
  524. typedef intersegment_ptr<T> self_t;
  525. typedef PT base_t;
  526. void unspecified_bool_type_func() const {}
  527. typedef void (self_t::*unspecified_bool_type)() const;
  528. public:
  529. typedef T * pointer;
  530. typedef typename ipcdetail::add_reference<T>::type reference;
  531. typedef T value_type;
  532. typedef std::ptrdiff_t difference_type;
  533. typedef std::random_access_iterator_tag iterator_category;
  534. public: //Public Functions
  535. //!Constructor from raw pointer (allows "0" pointer conversion).
  536. //!Never throws.
  537. intersegment_ptr(pointer ptr = 0)
  538. { base_t::set_from_pointer(ptr); }
  539. //!Constructor from other pointer.
  540. //!Never throws.
  541. template <class U>
  542. intersegment_ptr(U *ptr){ base_t::set_from_pointer(pointer(ptr)); }
  543. //!Constructor from other intersegment_ptr
  544. //!Never throws
  545. intersegment_ptr(const intersegment_ptr& ptr)
  546. { base_t::set_from_other(ptr); }
  547. //!Constructor from other intersegment_ptr. If pointers of pointee types are
  548. //!convertible, intersegment_ptrs will be convertibles. Never throws.
  549. template<class T2>
  550. intersegment_ptr(const intersegment_ptr<T2> &ptr)
  551. { pointer p(ptr.get()); (void)p; base_t::set_from_other(ptr); }
  552. //!Emulates static_cast operator.
  553. //!Never throws.
  554. template<class U>
  555. intersegment_ptr(const intersegment_ptr<U> &r, ipcdetail::static_cast_tag)
  556. { base_t::set_from_pointer(static_cast<T*>(r.get())); }
  557. //!Emulates const_cast operator.
  558. //!Never throws.
  559. template<class U>
  560. intersegment_ptr(const intersegment_ptr<U> &r, ipcdetail::const_cast_tag)
  561. { base_t::set_from_pointer(const_cast<T*>(r.get())); }
  562. //!Emulates dynamic_cast operator.
  563. //!Never throws.
  564. template<class U>
  565. intersegment_ptr(const intersegment_ptr<U> &r, ipcdetail::dynamic_cast_tag)
  566. { base_t::set_from_pointer(dynamic_cast<T*>(r.get())); }
  567. //!Emulates reinterpret_cast operator.
  568. //!Never throws.
  569. template<class U>
  570. intersegment_ptr(const intersegment_ptr<U> &r, ipcdetail::reinterpret_cast_tag)
  571. { base_t::set_from_pointer(reinterpret_cast<T*>(r.get())); }
  572. //!Obtains raw pointer from offset.
  573. //!Never throws.
  574. pointer get()const
  575. { return static_cast<pointer>(base_t::to_raw_pointer()); }
  576. //!Pointer-like -> operator. It can return 0 pointer.
  577. //!Never throws.
  578. pointer operator->() const
  579. { return self_t::get(); }
  580. //!Dereferencing operator, if it is a null intersegment_ptr behavior
  581. //!is undefined. Never throws.
  582. reference operator* () const
  583. { return *(self_t::get()); }
  584. //!Indexing operator.
  585. //!Never throws.
  586. reference operator[](std::ptrdiff_t idx) const
  587. { return self_t::get()[idx]; }
  588. //!Assignment from pointer (saves extra conversion).
  589. //!Never throws.
  590. intersegment_ptr& operator= (pointer from)
  591. { base_t::set_from_pointer(from); return *this; }
  592. //!Assignment from other intersegment_ptr.
  593. //!Never throws.
  594. intersegment_ptr& operator= (const intersegment_ptr &ptr)
  595. { base_t::set_from_other(ptr); return *this; }
  596. //!Assignment from related intersegment_ptr. If pointers of pointee types
  597. //!are assignable, intersegment_ptrs will be assignable. Never throws.
  598. template <class T2>
  599. intersegment_ptr& operator= (const intersegment_ptr<T2> & ptr)
  600. {
  601. pointer p(ptr.get()); (void)p;
  602. base_t::set_from_other(ptr); return *this;
  603. }
  604. //!intersegment_ptr + std::ptrdiff_t.
  605. //!Never throws.
  606. intersegment_ptr operator+ (std::ptrdiff_t idx) const
  607. {
  608. intersegment_ptr result (*this);
  609. result.inc_offset(idx*sizeof(T));
  610. return result;
  611. }
  612. //!intersegment_ptr - std::ptrdiff_t.
  613. //!Never throws.
  614. intersegment_ptr operator- (std::ptrdiff_t idx) const
  615. {
  616. intersegment_ptr result (*this);
  617. result.dec_offset(idx*sizeof(T));
  618. return result;
  619. }
  620. //!intersegment_ptr += std::ptrdiff_t.
  621. //!Never throws.
  622. intersegment_ptr &operator+= (std::ptrdiff_t offset)
  623. { base_t::inc_offset(offset*sizeof(T)); return *this; }
  624. //!intersegment_ptr -= std::ptrdiff_t.
  625. //!Never throws.
  626. intersegment_ptr &operator-= (std::ptrdiff_t offset)
  627. { base_t::dec_offset(offset*sizeof(T)); return *this; }
  628. //!++intersegment_ptr.
  629. //!Never throws.
  630. intersegment_ptr& operator++ (void)
  631. { base_t::inc_offset(sizeof(T)); return *this; }
  632. //!intersegment_ptr++.
  633. //!Never throws.
  634. intersegment_ptr operator++ (int)
  635. { intersegment_ptr temp(*this); ++*this; return temp; }
  636. //!--intersegment_ptr.
  637. //!Never throws.
  638. intersegment_ptr& operator-- (void)
  639. { base_t::dec_offset(sizeof(T)); return *this; }
  640. //!intersegment_ptr--.
  641. //!Never throws.
  642. intersegment_ptr operator-- (int)
  643. { intersegment_ptr temp(*this); --*this; return temp; }
  644. //!Safe bool conversion operator.
  645. //!Never throws.
  646. operator unspecified_bool_type() const
  647. { return base_t::is_null()? 0 : &self_t::unspecified_bool_type_func; }
  648. //!Not operator. Not needed in theory, but improves portability.
  649. //!Never throws.
  650. bool operator! () const
  651. { return base_t::is_null(); }
  652. //!Swaps two intersegment_ptr-s. More efficient than standard swap.
  653. //!Never throws.
  654. void swap(intersegment_ptr &other)
  655. { base_t::swap(other); }
  656. //!Calculates the distance between two intersegment_ptr-s.
  657. //!This only works with two basic_intersegment_ptr pointing
  658. //!to the same segment. Otherwise undefined
  659. template <class T2>
  660. std::ptrdiff_t _diff(const intersegment_ptr<T2> &other) const
  661. { return base_t::diff(other); }
  662. //!Returns true if both point to the
  663. //!same object
  664. template <class T2>
  665. bool _equal(const intersegment_ptr<T2>&other) const
  666. { return base_t::equal(other); }
  667. //!Returns true if *this is less than other.
  668. //!This only works with two basic_intersegment_ptr pointing
  669. //!to the same segment group. Otherwise undefined. Never throws
  670. template <class T2>
  671. bool _less(const intersegment_ptr<T2> &other) const
  672. { return base_t::less(other); }
  673. };
  674. //!Compares the equality of two intersegment_ptr-s.
  675. //!Never throws.
  676. template <class T1, class T2> inline
  677. bool operator ==(const intersegment_ptr<T1> &left,
  678. const intersegment_ptr<T2> &right)
  679. {
  680. //Make sure both pointers can be compared
  681. bool e = typename intersegment_ptr<T1>::pointer(0) ==
  682. typename intersegment_ptr<T2>::pointer(0);
  683. (void)e;
  684. return left._equal(right);
  685. }
  686. //!Returns true if *this is less than other.
  687. //!This only works with two basic_intersegment_ptr pointing
  688. //!to the same segment group. Otherwise undefined. Never throws
  689. template <class T1, class T2> inline
  690. bool operator <(const intersegment_ptr<T1> &left,
  691. const intersegment_ptr<T2> &right)
  692. {
  693. //Make sure both pointers can be compared
  694. bool e = typename intersegment_ptr<T1>::pointer(0) <
  695. typename intersegment_ptr<T2>::pointer(0);
  696. (void)e;
  697. return left._less(right);
  698. }
  699. template<class T1, class T2> inline
  700. bool operator!= (const intersegment_ptr<T1> &pt1,
  701. const intersegment_ptr<T2> &pt2)
  702. { return !(pt1 ==pt2); }
  703. //!intersegment_ptr<T1> <= intersegment_ptr<T2>.
  704. //!Never throws.
  705. template<class T1, class T2> inline
  706. bool operator<= (const intersegment_ptr<T1> &pt1,
  707. const intersegment_ptr<T2> &pt2)
  708. { return !(pt1 > pt2); }
  709. //!intersegment_ptr<T1> > intersegment_ptr<T2>.
  710. //!Never throws.
  711. template<class T1, class T2> inline
  712. bool operator> (const intersegment_ptr<T1> &pt1,
  713. const intersegment_ptr<T2> &pt2)
  714. { return (pt2 < pt1); }
  715. //!intersegment_ptr<T1> >= intersegment_ptr<T2>.
  716. //!Never throws.
  717. template<class T1, class T2> inline
  718. bool operator>= (const intersegment_ptr<T1> &pt1,
  719. const intersegment_ptr<T2> &pt2)
  720. { return !(pt1 < pt2); }
  721. //!operator<<
  722. template<class E, class T, class U> inline
  723. std::basic_ostream<E, T> & operator<<
  724. (std::basic_ostream<E, T> & os, const intersegment_ptr<U> & p)
  725. { return os << p.get(); }
  726. //!operator>>
  727. template<class E, class T, class U> inline
  728. std::basic_istream<E, T> & operator>>
  729. (std::basic_istream<E, T> & os, intersegment_ptr<U> & p)
  730. { U * tmp; return os >> tmp; p = tmp; }
  731. //!std::ptrdiff_t + intersegment_ptr.
  732. //!The result is another pointer of the same segment
  733. template<class T> inline
  734. intersegment_ptr<T> operator+
  735. (std::ptrdiff_t diff, const intersegment_ptr<T>& right)
  736. { return right + diff; }
  737. //!intersegment_ptr - intersegment_ptr.
  738. //!This only works with two intersegment_ptr-s that point to the
  739. //!same segment
  740. template <class T, class T2> inline
  741. std::ptrdiff_t operator- (const intersegment_ptr<T> &pt,
  742. const intersegment_ptr<T2> &pt2)
  743. { return pt._diff(pt2)/sizeof(T); }
  744. //! swap specialization
  745. template<class T> inline
  746. void swap (boost::interprocess::intersegment_ptr<T> &pt,
  747. boost::interprocess::intersegment_ptr<T> &pt2)
  748. { pt.swap(pt2); }
  749. //!to_raw_pointer() enables boost::mem_fn to recognize intersegment_ptr.
  750. //!Never throws.
  751. template<class T> inline
  752. T * to_raw_pointer(boost::interprocess::intersegment_ptr<T> const & p)
  753. { return p.get(); }
  754. //!Simulation of static_cast between pointers.
  755. //!Never throws.
  756. template<class T, class U> inline
  757. boost::interprocess::intersegment_ptr<T> static_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r)
  758. { return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::ipcdetail::static_cast_tag()); }
  759. //!Simulation of const_cast between pointers.
  760. //!Never throws.
  761. template<class T, class U> inline
  762. boost::interprocess::intersegment_ptr<T> const_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r)
  763. { return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::ipcdetail::const_cast_tag()); }
  764. //!Simulation of dynamic_cast between pointers.
  765. //!Never throws.
  766. template<class T, class U> inline
  767. boost::interprocess::intersegment_ptr<T> dynamic_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r)
  768. { return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::ipcdetail::dynamic_cast_tag()); }
  769. //!Simulation of reinterpret_cast between pointers.
  770. //!Never throws.
  771. template<class T, class U> inline
  772. boost::interprocess::intersegment_ptr<T> reinterpret_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r)
  773. { return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::ipcdetail::reinterpret_cast_tag()); }
  774. //!Trait class to detect if an smart pointer has
  775. //!multi-segment addressing capabilities.
  776. template <class T>
  777. struct is_multisegment_ptr
  778. <boost::interprocess::intersegment_ptr<T> >
  779. {
  780. static const bool value = true;
  781. };
  782. } //namespace interprocess {
  783. #if defined(_MSC_VER) && (_MSC_VER < 1400)
  784. //!to_raw_pointer() enables boost::mem_fn to recognize intersegment_ptr.
  785. //!Never throws.
  786. template<class T> inline
  787. T * to_raw_pointer(boost::interprocess::intersegment_ptr<T> const & p)
  788. { return p.get(); }
  789. #endif
  790. //!has_trivial_constructor<> == true_type specialization
  791. //!for optimizations
  792. template <class T>
  793. struct has_trivial_constructor
  794. < boost::interprocess::intersegment_ptr<T> >
  795. : public true_type{};
  796. //!has_trivial_destructor<> == true_type specialization
  797. //!for optimizations
  798. template <class T>
  799. struct has_trivial_destructor
  800. < boost::interprocess::intersegment_ptr<T> >
  801. : public true_type{};
  802. } //namespace boost {
  803. #if 0
  804. //bits
  805. //-> is_segmented
  806. //-> is_relative
  807. //-> is_in_stack
  808. //-> is_pointee_outside
  809. //Data
  810. //segmented:
  811. //
  812. // std::size_t ctrl : CTRL_BITS;
  813. // std::size_t segment : MAX_SEGMENT_BITS;
  814. // std::size_t offset;
  815. //RELATIVE_SIZE_BITS = SIZE_T_BITS -
  816. // MAX_SEGMENT_BITS -
  817. // CTRL_BITS 10 10
  818. //MAX_SEGMENT_SIZE = SIZE_T_BITS - ALIGN_BITS 20 52
  819. //SIZE_T_BITS - 1 - ALIGN_BITS 19 51
  820. //POW_SIZE_BITS = upper_log2
  821. // (SIZE_T_BITS - 1 - ALIGN_BITS) 5 6
  822. //FRC_SIZE_BITS = SIZE_T_BITS - CTRL_BITS
  823. // MAX_SEGMENT_SIZE_ALIGNBITS - POW_SIZE_BITS 6 5
  824. //relative:
  825. //
  826. // std::size_t ctrl : CTRL_BITS; 2 2
  827. // std::size_t size_pow : POW_SIZE_BITS 5 6
  828. // std::size_t size_frc : FRC_SIZE_BITS; 6 5
  829. // std::size_t start : MAX_SEGMENT_SIZE_ALIGNBITS;19 51
  830. // std::ptrdiff_t distance : SIZE_T_BITS; 32 64
  831. //direct:
  832. //
  833. // std::size_t ctrl : CTRL_BITS; 2 2
  834. // std::size_t dummy : SIZE_T_BITS - CTRL_BITS 30 62
  835. // void *addr : SIZE_T_BITS; 32 64
  836. //32 bits systems:
  837. //Page alignment: 2**12
  838. //
  839. //!Obtains the address pointed by the
  840. //!object
  841. void *to_raw_pointer() const
  842. {
  843. if(this->is_pointee_outside() || this->is_in_stack()){
  844. return raw_address();
  845. }
  846. else if(this->is_relative()){
  847. return (const_cast<char*>(reinterpret_cast<const char*>(this))) + this->relative_pointee_offset();
  848. }
  849. else{
  850. group_manager *m = get_segment_group_manager(addr);
  851. char *base = static_cast<char*>(m->get_id_address(this->segmented_id()));
  852. return base + this->segmented_offset();
  853. }
  854. }
  855. void set_from_pointer(const void *ptr)
  856. {
  857. if(!ptr){
  858. this->set_pointee_outside();
  859. this->raw_address(ptr);
  860. }
  861. else if(this->is_in_stack()){
  862. this->raw_address(ptr);
  863. }
  864. else if(this->is_relative() &&
  865. ( (ptr >= this->relative_start())
  866. &&(ptr < this->relative_start() + this->relative_size()))
  867. ){
  868. this->relative_offset(ptr - this);
  869. }
  870. else{
  871. segment_info_t ptr_info = get_id_from_addr(ptr);
  872. segment_info_t this_info = get_id_from_addr(this);
  873. if(ptr_info.segment_group != this_info.segment_group){
  874. if(!ptr_info.segment_group){
  875. this->set_in_stack();
  876. }
  877. else{
  878. this->set_pointee_outside();
  879. }
  880. }
  881. else if(ptr_info.segment_id == this_info.segment_id){
  882. set_relative();
  883. this->relative_size (ptr_info.size);
  884. this->relative_offset(static_cast<const char*>(ptr) - reinterpret_cast<const char*>(this));
  885. this->relative_start (ptr_info.base);
  886. }
  887. }
  888. }
  889. void set_from_other(const self_t &other)
  890. { this->set_from_pointer(other.to_raw_pointer()); }
  891. #endif
  892. #include <boost/interprocess/detail/config_end.hpp>
  893. #endif //#ifndef BOOST_INTERPROCESS_INTERSEGMENT_PTR_HPP