30#include <flow/util/util.hpp>
31#include <boost/interprocess/sync/named_mutex.hpp>
39#if defined(__GNUC__) && !defined(__clang__)
40# define IPC_SHM_ARENA_LEND_DETAIL_GCC_COMPILER 1
42# define IPC_SHM_ARENA_LEND_DETAIL_GCC_COMPILER 0
50#if IPC_SHM_ARENA_LEND_DETAIL_GCC_COMPILER
51# pragma GCC diagnostic push
52# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
223#if !(((defined(__GNUC__) || defined(__clang__)) && defined(__x86_64__)) || (defined(_MSC_VER) && defined(_M_X64)))
224 static_assert(
false,
"This pointer-tagging impl relies on the target architecture being x86-64 a/k/a AMD64.");
227#if (!defined(__GNUC__)) && (!defined(__clang__))
228 static_assert(
false,
"The bit-field code below is tested only with gcc and clang.");
233 static_assert(
sizeof(
void*) ==
sizeof(
rep_t),
"x86-64 should have 64-bit pointers.");
264 "Expecting bit-field to be packed tightly; not guaranteed by standard but in practice is.");
319 "Expecting bit-field to be packed tightly; not guaranteed by standard but in practice is.");
517template<
typename Repository_type,
bool CAN_STORE_RAW_PTR>
786 template<
typename Repository_type2,
bool CAN_STORE_RAW_PTR2>
815 constexpr size_t SLACK_SZ = 4 * 1024;
816 constexpr unsigned int N_OFFSET_MAGNITUDE_BITS
818 return (
size_t(1) << N_OFFSET_MAGNITUDE_BITS) - SLACK_SZ;
821template<
typename Repository_type,
bool CAN_STORE_RAW_PTR>
828template<
typename Repository_type,
bool CAN_STORE_RAW_PTR>
842 Repository::from_address(p, pool_id_or_0, pool_offset);
844 if (pool_id_or_0 == 0)
846 if constexpr(S_CAN_STORE_RAW_PTR)
852 m_rep.m_rep =
reinterpret_cast<rep_t>(p);
859 const auto sign_bits = m_rep.m_rep >> (Raw_ptr_rep::S_N_VAL_BITS - 1);
861 assert(((sign_bits ==
rep_t(0))
864 ((sign_bits +
rep_t(1)) == (
rep_t(1) << ((
sizeof(
rep_t) * 8) - Raw_ptr_rep::S_N_VAL_BITS + 1))))
865 &&
"A non-canonical raw pointer encountered.");
870 m_rep.m_raw_ptr_rep.m_selector_offset_else_raw =
rep_t(0);
883 m_rep.m_offset_ptr_rep.m_selector_offset_else_raw =
rep_t(1);
884 m_rep.m_offset_ptr_rep.m_pool_id = pool_id_or_0;
885 m_rep.m_offset_ptr_rep.m_pool_offset = pool_offset;
889template<
typename Repository_type,
bool CAN_STORE_RAW_PTR>
893template<
typename Repository_type,
bool CAN_STORE_RAW_PTR>
905 if constexpr(S_CAN_STORE_RAW_PTR)
908 m_rep.m_rep = src.
m_rep.m_rep;
935 m_rep.m_rep = src.
m_rep.m_rep;
940template<
typename Repository_type,
bool CAN_STORE_RAW_PTR>
945template<
typename Repository_type,
bool CAN_STORE_RAW_PTR>
950 static_assert(S_CAN_STORE_RAW_PTR,
951 "This helper method is meaningless, unless it is possible to store raw vaddrs. "
952 "Granted, we are static, so it would still work algorithmically speaking; but "
953 "this way protects from trying to call us in unqualified form for the wrong type at least.");
956 assert((rep.m_offset_ptr_rep.m_selector_offset_else_raw ==
rep_t(0))
957 &&
"Precondition to helper method = the selector bit <=> raw.");
960 if (rep.m_raw_ptr_rep.m_ext_sign_msb !=
rep_t(0))
962 rep.m_raw_ptr_rep.m_selector_offset_else_raw =
rep_t(1);
964 return reinterpret_cast<void*
>(rep.m_rep);
967template<
typename Repository_type,
bool CAN_STORE_RAW_PTR>
975 if constexpr(S_CAN_STORE_RAW_PTR)
977 if (rep.m_offset_ptr_rep.m_selector_offset_else_raw ==
rep_t(0))
979 return get_as_raw(rep);
986 assert((rep.m_offset_ptr_rep.m_selector_offset_else_raw ==
rep_t(1))
987 &&
"How'd we reach such a state in 1st place? Constructor shouldn't; increment() should not either.");
992 return Repository::to_address(rep.m_offset_ptr_rep.m_pool_id, rep.m_offset_ptr_rep.m_pool_offset);
995template<
typename Repository_type,
bool CAN_STORE_RAW_PTR>
999 return (m_rep.m_rep ==
rep_t(0)) ?
static_cast<void*
>(
nullptr) : get_if_not_null(m_rep);
1002template<
typename Repository_type,
bool CAN_STORE_RAW_PTR>
1005 if constexpr(S_CAN_STORE_RAW_PTR)
1008 return (m_rep.m_offset_ptr_rep.m_selector_offset_else_raw ==
pool_offset_t(0))
1009 && (m_rep.m_rep !=
rep_t(0));
1017template<
typename Repository_type,
bool CAN_STORE_RAW_PTR>
1020 return m_rep.m_rep !=
rep_t(0);
1023template<
typename Repository_type,
bool CAN_STORE_RAW_PTR>
1026 constexpr bool NO_RAW = !S_CAN_STORE_RAW_PTR;
1027 constexpr bool RESULT_EQ =
true;
1028 constexpr bool RESULT_NE =
false;
1070 const auto& other_rep = other.
m_rep;
1072 if (m_rep.m_rep == other_rep.m_rep)
1078 if constexpr(NO_RAW)
1114 return ((!to_bool()) || (!other.
to_bool()) || (is_raw() == other.
is_raw()))
1116 : (get() == other.
get());
1118 if (m_rep.m_rep ==
rep_t(0)) {
return RESULT_NE; }
1119 if (other_rep.m_rep ==
rep_t(0)) {
return RESULT_NE; }
1122 const bool is_raw = m_rep.m_offset_ptr_rep.m_selector_offset_else_raw ==
pool_offset_t(0);
1125 (other_rep.m_offset_ptr_rep.m_selector_offset_else_raw ==
pool_offset_t(0)))
1131 return (is_raw ? (get_as_raw(m_rep)
1133 Repository::to_address(other_rep.m_offset_ptr_rep.m_pool_id,
1134 other_rep.m_offset_ptr_rep.m_pool_offset))
1135 : (get_as_raw(other_rep)
1137 Repository::to_address(m_rep.m_offset_ptr_rep.m_pool_id,
1138 m_rep.m_offset_ptr_rep.m_pool_offset)))
1139 ? RESULT_EQ : RESULT_NE;
1186template<
typename Repository_type,
bool CAN_STORE_RAW_PTR>
1189 constexpr bool RESULT_LT =
true;
1190 constexpr bool RESULT_GE =
false;
1220 const auto& other_rep = other.
m_rep;
1221 const bool other_is_null = other_rep.m_rep ==
rep_t(0);
1228 if (m_rep.m_rep ==
rep_t(0))
1230 return other_is_null ? RESULT_GE : RESULT_LT;
1243 if constexpr(S_CAN_STORE_RAW_PTR)
1245 const bool is_raw = m_rep.m_offset_ptr_rep.m_selector_offset_else_raw ==
pool_offset_t(0);
1246 if (is_raw != (other_rep.m_offset_ptr_rep.m_selector_offset_else_raw ==
pool_offset_t(0)))
1251 return (is_raw ? (get_as_raw(m_rep)
1253 Repository::to_address(other_rep.m_offset_ptr_rep.m_pool_id,
1254 other_rep.m_offset_ptr_rep.m_pool_offset))
1255 : (get_as_raw(other_rep)
1257 Repository::to_address(m_rep.m_offset_ptr_rep.m_pool_id,
1258 m_rep.m_offset_ptr_rep.m_pool_offset)))
1259 ? RESULT_LT : RESULT_GE;
1270 return (get_as_raw(m_rep) < get_as_raw(other_rep)) ? RESULT_LT : RESULT_GE;
1277 assert((!is_raw()) &&
"Cannot be raw if !CAN_STORE_RAW_PTR.");
1278 assert((!other.
is_raw()) &&
"`other` cannot be raw if !CAN_STORE_RAW_PTR.");
1284 if (m_rep.m_offset_ptr_rep.m_pool_id == other_rep.m_offset_ptr_rep.m_pool_id)
1289 return (m_rep.m_offset_ptr_rep.m_pool_offset < other_rep.m_offset_ptr_rep.m_pool_offset)
1290 ? RESULT_LT : RESULT_GE;
1294 return (Repository::to_address(m_rep.m_offset_ptr_rep.m_pool_id, m_rep.m_offset_ptr_rep.m_pool_offset)
1296 Repository::to_address(other_rep.m_offset_ptr_rep.m_pool_id, other_rep.m_offset_ptr_rep.m_pool_offset))
1297 ? RESULT_LT : RESULT_GE;
1300template<
typename Repository_type,
bool CAN_STORE_RAW_PTR>
1304 constexpr bool RESULT_GT =
true;
1305 constexpr bool RESULT_LE =
false;
1313 const auto& other_rep = other.
m_rep;
1314 const bool other_is_null = other_rep.m_rep ==
rep_t(0);
1316 if (m_rep.m_rep ==
rep_t(0))
1327 if constexpr(S_CAN_STORE_RAW_PTR)
1329 const bool is_raw = m_rep.m_offset_ptr_rep.m_selector_offset_else_raw ==
pool_offset_t(0);
1330 if (is_raw != (other_rep.m_offset_ptr_rep.m_selector_offset_else_raw ==
pool_offset_t(0)))
1332 return (is_raw ? (get_as_raw(m_rep)
1334 Repository::to_address(other_rep.m_offset_ptr_rep.m_pool_id,
1335 other_rep.m_offset_ptr_rep.m_pool_offset))
1336 : (get_as_raw(other_rep)
1338 Repository::to_address(m_rep.m_offset_ptr_rep.m_pool_id,
1339 m_rep.m_offset_ptr_rep.m_pool_offset)))
1340 ? RESULT_GT : RESULT_LE;
1345 return (get_as_raw(m_rep) > get_as_raw(other_rep)) ? RESULT_GT : RESULT_LE;
1352 assert((!is_raw()) &&
"Cannot be raw if !CAN_STORE_RAW_PTR.");
1353 assert((!other.
is_raw()) &&
"`other` cannot be raw if !CAN_STORE_RAW_PTR.");
1359 if (m_rep.m_offset_ptr_rep.m_pool_id == other_rep.m_offset_ptr_rep.m_pool_id)
1361 return (m_rep.m_offset_ptr_rep.m_pool_offset > other_rep.m_offset_ptr_rep.m_pool_offset)
1362 ? RESULT_GT : RESULT_LE;
1366 return (Repository::to_address(m_rep.m_offset_ptr_rep.m_pool_id, m_rep.m_offset_ptr_rep.m_pool_offset)
1368 Repository::to_address(other_rep.m_offset_ptr_rep.m_pool_id, other_rep.m_offset_ptr_rep.m_pool_offset))
1369 ? RESULT_GT : RESULT_LE;
1372template<
typename Repository_type,
bool CAN_STORE_RAW_PTR>
1376 static_assert(std::is_signed_v<diff_t>,
"If diff_t is unsigned, we cannot properly subtract pointers.");
1378 using wide_offset_t = std::make_signed_t<rep_t>;
1389 constexpr auto as_t_ptr = [](
const void* ptr)
constexpr ->
auto {
return static_cast<const T*
>(ptr); };
1390 constexpr const T* T_NULLPTR =
nullptr;
1411 if (m_rep.m_rep ==
rep_t(0))
1415 return ret_t(T_NULLPTR - as_t_ptr(other.
get()));
1418 const auto& other_rep = other.
m_rep;
1419 if (other_rep.m_rep ==
rep_t(0))
1422 return ret_t(as_t_ptr(get_if_not_null(m_rep)) - T_NULLPTR);
1425 if constexpr(S_CAN_STORE_RAW_PTR)
1427 const bool is_raw = m_rep.m_offset_ptr_rep.m_selector_offset_else_raw ==
pool_offset_t(0);
1428 if (is_raw != (other_rep.m_offset_ptr_rep.m_selector_offset_else_raw ==
pool_offset_t(0)))
1430 return ret_t(is_raw ? (as_t_ptr(get_as_raw(m_rep))
1432 as_t_ptr(Repository::to_address(other_rep.m_offset_ptr_rep.m_pool_id,
1433 other_rep.m_offset_ptr_rep.m_pool_offset)))
1434 : (as_t_ptr(Repository::to_address(m_rep.m_offset_ptr_rep.m_pool_id,
1435 m_rep.m_offset_ptr_rep.m_pool_offset))
1437 as_t_ptr(get_as_raw(other_rep))));
1442 return ret_t(as_t_ptr(get_as_raw(m_rep)) - as_t_ptr(get_as_raw(other_rep)));
1449 assert((!is_raw()) &&
"Cannot be raw if !CAN_STORE_RAW_PTR.");
1450 assert((!other.
is_raw()) &&
"`other` cannot be raw if !CAN_STORE_RAW_PTR.");
1456 if (m_rep.m_offset_ptr_rep.m_pool_id == other_rep.m_offset_ptr_rep.m_pool_id)
1458 return ret_t((wide_offset_t(m_rep.m_offset_ptr_rep.m_pool_offset)
1459 - wide_offset_t(other_rep.m_offset_ptr_rep.m_pool_offset))
1460 / wide_offset_t(
sizeof(T)));
1470 return ret_t(as_t_ptr(Repository::to_address(m_rep.m_offset_ptr_rep.m_pool_id,
1471 m_rep.m_offset_ptr_rep.m_pool_offset))
1473 as_t_ptr(Repository::to_address(other_rep.m_offset_ptr_rep.m_pool_id,
1474 other_rep.m_offset_ptr_rep.m_pool_offset)));
1477template<
typename Repository_type,
bool CAN_STORE_RAW_PTR>
1480 static_assert(std::is_signed_v<diff_t>,
"If diff_t is unsigned, we cannot really decrement pointers.");
1483 if constexpr(S_CAN_STORE_RAW_PTR)
1485 if (m_rep.m_offset_ptr_rep.m_selector_offset_else_raw == 0)
1518 m_rep.m_rep += bytes;
1525 if (m_rep.m_rep ==
rep_t(0))
1534 assert((m_rep.m_offset_ptr_rep.m_selector_offset_else_raw ==
rep_t(1))
1535 &&
"How'd we reach such a state in 1st place? Constructor shouldn't; increment() should not either.");
1539 m_rep.m_offset_ptr_rep.m_pool_offset += bytes;
1549template<
typename Repository_type,
bool CAN_STORE_RAW_PTR>
1554 using boost::io::ios_all_saver;
1558 return os <<
"null";
1562 if constexpr(CAN_STORE_RAW_PTR)
1564 if (!val.
m_rep.m_offset_ptr_rep.m_selector_offset_else_raw)
1566 ios_all_saver saver(os);
1567 return os <<
"ext_sign_bit[" << val.
m_rep.m_raw_ptr_rep.m_ext_sign_msb <<
"]... val_bits[0x"
1568 << std::hex << val.
m_rep.m_raw_ptr_rep.m_val_bits <<
"]@" << val.
get();
1573 return os <<
"pool_id[" << val.
m_rep.m_offset_ptr_rep.m_pool_id
1574 <<
"]+[" << val.
m_rep.m_offset_ptr_rep.m_pool_offset <<
"]@" << val.
get();
1579#if IPC_SHM_ARENA_LEND_DETAIL_GCC_COMPILER
1580# pragma GCC diagnostic pop
1583#undef IPC_SHM_ARENA_LEND_DETAIL_GCC_COMPILER
Parameterization-independent aspects of Shm_pool_offset_ptr_data segregated in non-template base.
static constexpr unsigned int S_N_POOL_OFFSET_BITS
static constexpr size_t max_pool_size()
The max size of a SHM-pool such that any offset into it – including the one-past-the-last-byte offset...
static std::once_flag s_pool_id_shm_region_init_flag
Used with std::call_once() to ensure s_pool_id_shm_region_or_none is initialized no more than once.
int32_t diff_t
Analogous to difference_type in STL containers (but uses our naming conventions).
detail::pool_id_t pool_id_t
Pool ID type alias. Please see detail::pool_id_t doc header for discussion as to the chosen bit width...
static std::optional< boost::interprocess::named_mutex > s_pool_id_mutex_or_none
Initialized no more than once (in this process) by generate_pool_id(), a handle to a named-mutex prot...
static bipc::mapped_region s_pool_id_shm_region_or_none
Initialized no more than once (in this process) by generate_pool_id(), a handle to tiny SHM region st...
int32_t pool_offset_t
Pool offset type.
uint64_t rep_t
The unsigned integer type used to store Shm_pool_offset_ptr_data pointer payloads.
static pool_id_t generate_pool_id()
Returns a heretofore-unused pool ID so as to be used to identify (in a Shm_pool_offset_ptr_data::Repo...
static bipc::shared_memory_object s_pool_id_shm_obj_or_none
The SHM-object (pool) mapped by s_pool_id_shm_region_or_none.
Implementation core of Shm_pool_offset_ptr.
Shm_pool_offset_ptr_data & operator=(const Shm_pool_offset_ptr_data &src)
Assignment.
Offset_ptr_rep m_offset_ptr_rep
The bits viewed in the offset-ptr form.
bool less_than(Shm_pool_offset_ptr_data other) const
Returns true if and only if get() < other.get().
bool greater_than(Shm_pool_offset_ptr_data other) const
Returns true if and only if get() > other.get().
Base::rep_t rep_t
Short-hand from base.
Shm_pool_offset_ptr_data()
Construct with nullptr.
Raw_ptr_rep m_raw_ptr_rep
The bits viewed in the raw-ptr form.
diff_t distance_from(Shm_pool_offset_ptr_data other) const
Returns (essentially) get() minus other.get() in bytes; so (assuming no overflow issues) the value N ...
union { rep_t m_rep Representation
Type of m_rep.
void increment(diff_t bytes) noexcept
Increments *this by a number of bytes (which can be positive, negative, or zero).
Repository_type Repository
Short-hand for template parameter Repository_type; may be useful for generic programming.
bool equals(Shm_pool_offset_ptr_data other) const
Returns true if and only if get() == other.get(), albeit with certain acceptable exceptions and a bet...
void * get() const
Retrieves the pointer to the object, if there is one stored; otherwise nullptr.
bool to_bool() const
Returns false if and only if get() == nullptr (assuming *this is valid; otherwise formally undefined ...
static constexpr bool S_CAN_STORE_RAW_PTR
Short-hand for template parameter CAN_STORE_RAW_PTR; may be useful for generic programming.
Shm_pool_offset_ptr_data(const Shm_pool_offset_ptr_data &src)
Copy constructor.
friend std::ostream & operator<<(std::ostream &os, Shm_pool_offset_ptr_data< Repository_type2, CAN_STORE_RAW_PTR2 > val)
Friend of this class.
static void * get_as_raw(Representation rep)
Helper, surely inlined with any decent optimizer, that returns what get() would return if m_rep equal...
static void * get_if_not_null(Representation rep)
Helper a-la get_as_raw() but given only the pre-condition that rep is not zero (does not represent nu...
Representation m_rep
The raw bits.
bool is_raw() const
Returns whether the offset pointer holds a non-null, raw pointer; as opposed to an offset pointer or ...
Segregated private stuff for ipc::shm::arena_lend.
uint32_t pool_id_t
Pool ID type.
std::ostream & operator<<(std::ostream &os, Shm_pool_offset_ptr_data< Repository_type, CAN_STORE_RAW_PTR > val)
Prints string representation of the given Shm_pool_offset_ptr_data to the given ostream.
A bit-field overlaid over any rep_t, this represents a pointer with the selector MSB indicating a poo...
pool_id_t m_pool_id
If and only if m_selector_offset_else_raw: The pool ID.
pool_offset_t m_pool_offset
If and only if m_selector_offset_else_raw: The offset within pool IDed by m_pool_id.
rep_t m_selector_offset_else_raw
Either 0 (raw or null pointer; do not use the other bit members) or 1 (offset pointer).
A bit-field overlaid over any rep_t, this represents a pointer with the selector MSB indicating a ra-...
rep_t m_ext_sign_bits_except_msb
If !m_selector_offset_else_raw, and the entire value is not all-zero-bits: m_ext_sign_msb repeated.
static constexpr size_t S_N_VAL_BITS
rep_t m_selector_offset_else_raw
Either 0 (raw or null pointer; if all other bits are also 0, then do not use the other bit members) o...
rep_t m_ext_sign_msb
If !m_selector_offset_else_raw, and the entire value is not all-zero-bits: The most significant,...
rep_t m_val_bits
If !m_selector_offset_else_raw, and the entire value is not all-zero-bits: m_ext_sign_msb repeated ye...