Flow-IPC 1.0.0
Flow-IPC project: Full implementation reference.
Public Member Functions | Static Public Member Functions | Static Public Attributes | Private Attributes | Friends | Related Functions | List of all members
ipc::util::Shared_name Class Reference

String-wrapping abstraction representing a name uniquely distinguishing a kernel-persistent entity from all others in the system, or a fragment of such a name. More...

#include <shared_name.hpp>

Collaboration diagram for ipc::util::Shared_name:
[legend]

Public Member Functions

 Shared_name ()
 Constructs empty() name.
 
 Shared_name (const Shared_name &src)
 Copy-constructs from an existing Shared_name. More...
 
 Shared_name (Shared_name &&src_moved)
 Move-constructs from an existing Shared_name, which is made empty() if not already so. More...
 
template<typename Input_it >
 Shared_name (Input_it begin, Input_it end)
 Copy-constructs from a char range given as a pair of random-iterators; in particular const char*s work. More...
 
Shared_nameoperator= (const Shared_name &src)
 Copy-assigns from an existing Shared_name. More...
 
Shared_nameoperator= (Shared_name &&src_moved)
 Move-assigns from an existing Shared_name. More...
 
const std::string & str () const
 Returns (sans copying) ref to immutable entire wrapped name string, suitable to pass into sys calls when naming supported shared resources assuming absolute() == true. More...
 
const char * native_str () const
 Returns (sans copying) pointer to NUL-terminated wrapped name string, suitable to pass into sys calls when naming supported shared resources assuming absolute() == true. More...
 
size_t size () const
 Returns str().size(). More...
 
bool empty () const
 Returns true if and only if str().empty() == true. More...
 
bool has_trailing_separator () const
 Returns true if and only if !this->empty(), and str() ends with the S_SEPARATOR character. More...
 
bool absolute () const
 Returns true if and only if the first character is S_SEPARATOR. More...
 
void clear ()
 Makes it so empty() == true. More...
 
bool sanitized () const
 Returns true if and only if the contained name/fragment is sanitized according to length, legal characters, and similar. More...
 
bool sanitize ()
 Best-effort attempt to turn sanitized() from false to true, unless it is already true; returns the final value of sanitized() indicating whether it was successful. More...
 
Shared_nameoperator/= (const Shared_name &src_to_append)
 Appends a folder separator followed by the given other Shared_name. More...
 
template<typename Source >
Shared_nameoperator/= (const Source &raw_name_to_append)
 Simply appends a folder separator followed by raw_name_to_append to the current value of str(). More...
 
Shared_nameoperator/= (const char *raw_name_to_append)
 Similar to the overload that takes const Source&, but takes NUL-terminated string instead. More...
 
Shared_nameoperator+= (const Shared_name &src_to_append)
 Appends the given other Shared_name. More...
 
template<typename Source >
Shared_nameoperator+= (const Source &raw_name_to_append)
 Simply appends raw_name_to_append to the current value of str(). More...
 
Shared_nameoperator+= (const char *raw_name_to_append)
 Similar to the overload that takes const Source&, but takes NUL-terminated string instead. More...
 

Static Public Member Functions

template<typename Source >
static Shared_name ct (const Source &src)
 Copy-constructs from a char-sequence container (including string, util::String_view, vector<char>). More...
 
static Shared_name ct (const char *src)
 Copy-constructs from a NUL-terminated const char* string. More...
 
static Shared_name ct (std::string &&src_moved)
 Destructively move-constructs from an std::string, emptying that source object. More...
 

Static Public Attributes

static const Shared_name S_EMPTY
 A (default-cted) Shared_name. May be useful for functions returning const Shared_name&. More...
 
static const size_t S_MAX_LENGTH = 75
 Max value of size() such that, if str() used to name a supported shared resource, sys call safely won't barf. More...
 
static const char S_SEPARATOR = '_'
 Character we use, by convention, to separate conceptual folders within str(). More...
 
static const Shared_name S_ROOT_MAGIC = Shared_name::ct("libipc")
 A Shared_name fragment, with no S_SEPARATOR characters inside, to be used in any Shared_name maintained by ipc itself as the leading path component. More...
 
static const Shared_name S_SENTINEL = Shared_name::ct("0")
 A Shared_name fragment, with no S_SEPARATOR characters inside, that represents a path component that shall be different from any other generated string at the same path depth in the same context; and represents a sentinel. More...
 
static const Shared_name S_1ST_OR_ONLY = Shared_name::ct("1")
 A Shared_name fragment, with no S_SEPARATOR characters inside, that represents a path component that (1) is not S_SENTINEL and (2) is suggested as the first or only unique ID of items at the same depth in the same context. More...
 
static const Shared_name S_RESOURCE_TYPE_ID_SHM = Shared_name::ct("shm")
 Relative-folder fragment (no separators) identifying the resource type for: SHM pools. More...
 
static const Shared_name S_RESOURCE_TYPE_ID_MUTEX = Shared_name::ct("mtx")
 Relative-folder fragment (no separators) identifying the resource type for: boost.interprocess named mutex. More...
 

Private Attributes

std::string m_raw_name
 The name or name fragment; see str(). More...
 

Friends

void swap (Shared_name &val1, Shared_name &val2)
 Swaps two objects. More...
 

Related Functions

(Note that these are not member functions.)

Shared_name operator/ (const Shared_name &src1, const Shared_name &src2)
 Returns new object equal to Shared_name(src1) /= src2. More...
 
template<typename Source >
Shared_name operator/ (const Shared_name &src1, const Source &raw_src2)
 Returns new object equal to Shared_name(src1) /= raw_src2. More...
 
Shared_name operator/ (const Shared_name &src1, const char *raw_src2)
 Returns new object equal to Shared_name(src1) /= raw_src2. More...
 
template<typename Source >
Shared_name operator/ (const Source &raw_src1, const Shared_name &src2)
 Returns new object equal to Shared_name(raw_src1) /= src2. More...
 
Shared_name operator/ (const char *raw_src1, const Shared_name &src2)
 Returns new object equal to Shared_name(raw_src1) /= src2. More...
 
Shared_name operator+ (const Shared_name &src1, const Shared_name &src2)
 Returns new object equal to Shared_name(src1) += src2. More...
 
template<typename Source >
Shared_name operator+ (const Shared_name &src1, const Source &raw_src2)
 Returns new object equal to Shared_name(src1) += raw_src2. More...
 
Shared_name operator+ (const Shared_name &src1, const char *raw_src2)
 Returns new object equal to Shared_name(src1) += raw_src2. More...
 
template<typename Source >
Shared_name operator+ (const Source &raw_src1, const Shared_name &src2)
 Returns new object equal to Shared_name(src2) with raw_src1 pre-pended to it. More...
 
Shared_name operator+ (const char *raw_src1, const Shared_name &src2)
 Returns new object equal to Shared_name(src2) with raw_src1 pre-pended to it. More...
 
std::ostream & operator<< (std::ostream &os, const Shared_name &val)
 Prints embellished string representation of the given Shared_name to the given ostream. More...
 
std::istream & operator>> (std::istream &is, Shared_name &val)
 Reads Shared_name from the given istream; equivalent to reading string into Shared_name::str(). More...
 
size_t hash_value (const Shared_name &val)
 Hasher of Shared_name for boost.unordered et al. More...
 
void swap (Shared_name &val1, Shared_name &val2)
 Swaps two objects. More...
 

Detailed Description

String-wrapping abstraction representing a name uniquely distinguishing a kernel-persistent entity from all others in the system, or a fragment of such a name.

Conceptually it relates to std::string similarly to how filesystem::path does.

This is a very simple class in terms of what logic it actually adds: it encapsulates an std::string and allows for, basically, string operations like concatenation, with some syntactic sugar added for a simple folder convention. However, the design context (namely, how shared resources are named and why) is less trivial, and this doc header is a good place to get into those topics as well. Hence, we first cover practical aspects, with the architectural context referenced only as needed. Then, below that, there's an architecture discussion about naming in general.

Construction/assignment from and conversion to strings/similar

Interanally it stores an std::string.

Conversion: That string is accessible by const& via str() and similarly the NUL-terminated native_str(). Also there is an ostream<< printer; do note it does not simply print str() but rather a beautified version. (ostream>> input is also provided but is identical to ostream >> string.)

Construction/assignment: It comes with standard default/copy/move ctors and assignment. There is also a constructor that takes two iterators-to-char (including 2 const char*). However, construction from string (including destuctive move-construction), util::String_view, NUL-terminated const char*, vector<char> (etc.) is available exclusively in the form of static quasi-ctors ct(). Lastly: To assign please use move ctor: existing_sh_name = Shared_name::ct(src).

Rationale: C++ ADL semantics cause a ton of super-annoying problems – especially inside ipc::transport namespace itself – where compilers will auto-convert, e.g., a string to Shared_name without being asked to do so at all. For example, one sees operator << string output the string in "beautified" form, because a Shared_name is constructed implicitly and then printed via its <<. I (ygoldfel), then, took a cue from boost.asio's IP address classes which use static quasi-ctors to avoid any such issues. (The alternative was to fine-tune the ctor set a-la filesystem::path, with conversion traits and all kinds of craziness.)

Practical Shared_name matters

A shared resource in this context is some entity (such as a SHM-mapped addressable area; or a POSIX message queue) that can be opened for further access by potentially 2+ processes simultaneously. When opening (at least), the shared resource is referred to – in the associated opening sys call or similar – by a string name, and the name works equally from those 2+ processes. Shared_name stores such a string. It is also suitable for fragments of these names, including prefixes, suffixes, or middle parts. Therefore – much like boost::filesystem::path is basically a string wrapper – Shared_name is just a string wrapper. In fact the std::string it stores is accessible through str() by reference.

All standard string-like operations (generally, the +=, /=, +, and / operations) are equally performant and not any smarter than the corresponding string concatenation ops (the / variants just add a separator character). The same holds for all operations, except see the next section. In particular, all characters are allowed in any position, and there is no max length enforced. Hence, the user may assume max possible performance and zero restrictions, with the exception of:

Conventions understood/enforced by Shared_name

As noted, generally the class allows everything and does nothing smart that std::string wouldn't do. This is for flexibility and performance and is inspired by boost::filesystem::path. However, there is optional support for some simple conventions. First let's discuss those conventions:

In Flow-IPC, Shared_name is to be used for all shared resource types needed. (These are not enumerated here.) Different resource types might have different rules for (1) characters allowed; and (2) max length allowed; so that if this is violated, a creation/opening sys call (or similar) will fail with an error. Therefore, the following conventions are understood and represent the union of known system restrictions, so that sanitized() names will work for all known resource types. Also, some conventions are for human usability. In total, these conventions are understood:

How does Shared_name actually use the knowledge of these conventions? To reiterate: normally, it does not care. The only parts of its API that do care are as follows:

Note
The Flow-IPC library user is unlikely to directly pass a Shared_name into a sys call or similar. Probably Flow-IPC internals will do it for the user. Therefore, the likeliest pattern for the user to encounter in public Flow-IPC APIs is: When initially naming some transport object, a constructor or factory will take a relative (absolute() == false) Shared_name prepared by the user. Within that relative fragment, the user is to use the folder conventions above (via /= or / operators perhaps) if needed. Inside Flow-IPC, the impl can then construct an absolute name by internally pre-pending stuff to the user-constructed fragment. If you have ensured the name is sanitized(), then it will not fail on account of a bad name. If you have not, then it may still not fail: sanitized() is a conservative criterion and may be too stringent for some resource types and OS calls. It is up to you to either ensure sanitized() or otherwise worry about the possibility of a bad name (illegal characters, excessive length).

Thread safety

Shared_name has the same safety under concurrency as std::string (i.e., if you intend on writing while reading/writing same *this concurrently, synchronized access is necessary to avoid corruption and other standard thread safety violations).

Architecture discussion / shared name convention synopsis

As promised, we've covered the practical aspects of Shared_name first. Now let's discuss the larger design. Note that while this does inform some of Shared_name API (which is quite simple), really the discussion has wider implications, and this doc header merely seems like a good place for it. It would've been okay to split off much of the below info into ipc::session somewhere, but... maybe that's better... but the human in me (ygoldfel) feels you'll want to know this now, here, even though for formal appropriateness maybe it should be moved. In any case here it is:

As noted before, there are N shared resource types, and Shared_name is to be used for all of them. At minimum, then:

When designing Flow-IPC, we decided that if would be helpful for humans if we immediately made this more stringent by enforcing the following stronger requirement as well:

Further, some things are made easier if the distinctness restriction (2 distinct names <=> 2 distinct objects at each given point in time) is made more stringent by extending it to all time; resulting in:

Note
Shared resources are assumed to be kernel-persistent, which means the slate is wiped with each system boot. Hence "all time" really means "within the relevant uptime."

Practically speaking, then, how do we enable these distinctness guarantees, in absolute names (i.e., names to be passed, usually internally by Flow-IPC, into sys calls/similar)? Firstly, the resource type for the object referred to by each absolute name should be encoded in a standard prefix inside the name; a simple distinct constant for each resource type works. There should be a handful at most of these possible values. This will guarantee non-clashing between different types of resource.

That only leaves the distinct-across-all-time requirement. However, it's outside the scope of this header to explain how that's achieved, as it involves ipc::session and other concepts and is just a large topic.

For convenience, we now summarize the resulting absolute shared name convention, as of this writing, without a full rationale and with references to other doc headers if appropriate. In order, the characters of a shared name in the Flow-IPC convention are as follows. Use session::build_conventional_shared_name() to construct a path with these semantics.

  1. Leading S_SEPARATOR. Indicates a full (absolute) name or prefix thereof.
  2. A certain constant magic string, S_ROOT_MAGIC, indicating ipc is operating. (E.g., if... uh... emacs likes to put stuff in, say, SHM, at a certain SHM path, hopefully it won't clash with us accidentally.)
  3. A S_SEPARATOR.
  4. Hard-coded resource type constant. Indicates resource type. E.g., something like "posixq" might mean a POSIX message queue. The (quite few) possible values for this are stored internally in Flow-IPC.
  5. A S_SEPARATOR.
  6. Session-server application name. This brief name is 1-1 with all distinct executables supported by Flow-IPC. See ipc::session for details.
  7. A S_SEPARATOR.
  8. Server-namespace. This uniquely identifies the server application instance across all time, for a given session-server application name. See ipc::session for how this value is computed. In the rare case where the resource applies to all server-namespaces, use special value S_SENTINEL.
  9. A S_SEPARATOR.
  10. What comes next depends on the scope of this particular resource.
    • Relevant to a given session A-B (where A and B are processes that can converse with each other), a/k/a per-session scope:
      1. Session-client application name. Analogous to session-server application name but for the supported clients. See ipc::session for details.
      2. A S_SEPARATOR.
      3. Client-namespace. Given everything up to this point, uniquely identifies client application instance across all time (like server-namespace above, basically). See ipc::session for how it's computed.
    • Relevant to no particular process pair A-B, but does apply only to a given session-client application, a/k/a per-client-app scope:
      1. Session-client application name, as just above.
      2. A S_SEPARATOR.
      3. The reserved client-namespace, S_SENTINEL, indicating no particular session-client.
    • Global (not limited to any smaller scope above), a/k/a global scope. This is intended largely for internal Flow-IPC needs, as of this writing.
      1. The reserved session-client application name, S_SENTINEL, indicating no particular client application.
  11. A S_SEPARATOR.
  12. The rest of the name depends on the convention decided for that particular resource type and hence outside our scope here; see doc header for the relevant class corresponding to a shared resource type of interest.
    • For each object, determine the scope (the 3 possibilities and resulting naming conventions are just above).
    • Keep using the basic folder convention, with non-empty folder names and S_SEPARATOR as separator.
    • When uniqueness is desired, the 1->2->3... technique is typically used (always remembering that such an auto-ID must be safely generated across all participating processes in system).

In rare cases a Shared_name will be used outside the ipc::session paradigm, such as for a lower-level purpose that nevertheless requires a shared-resource name (e.g., for a lower-level-use SHM pool). In that case the following shall be equal to S_SENTINEL: session-server application name; server-namespace. The components subsequent to that shall be as-if it's a global-scope resource; hence: S_SENTINEL. build_conventional_non_session_based_share_name() shall construct such a name.

Note
camelCase: As of this writing, S_SEPARATOR is _ (because / is not available for native reasons). So, when it comes up, the convention is to use camelCase for tokens between nearby separators. Briefly: start with lower case; do not word-smoosh; each new word after word 1 is to begin with exactly 1 capital or number; an acronym is to be treated as a single word. Examples of compliant tokens: httpUrlConnectionV44Beta, tableIdent. These are bad: httpURLConnection (wrong acronym convention), HTTPURLConnection (ditto), tableident (word-smooshing).

Rationale for max length handling

As noted in the public section of this doc header: S_MAX_LENGTH is a part of sanitized() criteria; it is not enforced by Shared_name itself outside of sanitized() and sanitize(). It is up to the Shared_name user (which may, and usually is, internal Flow-IPC code) to actually ensure sanitized() is true – or otherwise avoid system API errors on account of bad names. All we choose to do, regarding the length aspect, is choose one conservatively low so that:

To wit, then, current tally of relevant resource types:

So that puts us at 107 without the "prefix slack." Applying a prefix slack of 32 characters gives us: 107 - 32 = 75.

Definition at line 241 of file shared_name.hpp.

Constructor & Destructor Documentation

◆ Shared_name() [1/3]

ipc::util::Shared_name::Shared_name ( const Shared_name src)
default

Copy-constructs from an existing Shared_name.

Parameters
srcSource object.

◆ Shared_name() [2/3]

ipc::util::Shared_name::Shared_name ( Shared_name &&  src_moved)
default

Move-constructs from an existing Shared_name, which is made empty() if not already so.

Parameters
src_movedSource object, which is potentially modified.

◆ Shared_name() [3/3]

template<typename Input_it >
ipc::util::Shared_name::Shared_name ( Input_it  begin,
Input_it  end 
)
explicit

Copy-constructs from a char range given as a pair of random-iterators; in particular const char*s work.

Template Parameters
Input_itAn STL-compliant random iterator type. In particular const char* works.
Parameters
beginStart of range to copy.
endOne past last element in range to copy (begin to copy nothing).

Definition at line 667 of file shared_name.hpp.

Member Function Documentation

◆ absolute()

bool ipc::util::Shared_name::absolute ( ) const

Returns true if and only if the first character is S_SEPARATOR.

By Flow-IPC convention, any name actually passed to a sys call in order to name a shared resource has absolute() == true. Note, however, that absolute() being true does not necessarily mean str() is the full name of a resource: it may well still be a fragment (a prefix) of some eventual name passed to a sys call. To obtain the full name one would append more stuff.

Returns
See above.

Definition at line 165 of file shared_name.cpp.

References m_raw_name, and S_SEPARATOR.

Referenced by ipc::transport::Blob_stream_mq_base_impl< Persistent_mq_handle >::mq_sentinel_name().

Here is the caller graph for this function:

◆ clear()

void ipc::util::Shared_name::clear ( )

Makes it so empty() == true.

Definition at line 170 of file shared_name.cpp.

References m_raw_name.

Referenced by ipc::transport::Posix_mq_handle::operator=().

Here is the caller graph for this function:

◆ ct() [1/3]

Shared_name ipc::util::Shared_name::ct ( const char *  src)
static

Copy-constructs from a NUL-terminated const char* string.

Rationale

See class doc header for rationale as-to why this is a static ctor as opposed to a regular ctor.

Template Parameters
SourceSee above.
Parameters
srcString to copy.
Returns
The new object.

Definition at line 52 of file shared_name.cpp.

References m_raw_name.

◆ ct() [2/3]

template<typename Source >
Shared_name ipc::util::Shared_name::ct ( const Source &  src)
static

Copy-constructs from a char-sequence container (including string, util::String_view, vector<char>).

This overload shall be used on a non-&& arg if ct(const char*) does not apply.

Specifically the returned object's internal std::string is constructed as: std::string s(raw_name). As a result, whatever most-performant available single-arg ctor basic_string makes available is forwarded-to. (E.g., C++17 has a String_view_like ctor which is overload-resolved-to only when it most makes sense.)

Rationale

See class doc header for rationale as-to why this is a static ctor as opposed to a regular ctor.

Template Parameters
SourceSee above.
Parameters
srcString to copy.
Returns
The new object.

Definition at line 674 of file shared_name.hpp.

References m_raw_name.

Referenced by ipc::session::Session_server_impl< Session_server_t, Server_session_t >::async_accept(), ipc::session::shm::classic::Server_session_impl< S_MQ_TYPE_OR_NONE, S_TRANSMIT_NATIVE_HANDLES, Mdt_payload >::async_accept_log_in(), ipc::session::Client_session_impl< S_MQ_TYPE_OR_NONE, S_TRANSMIT_NATIVE_HANDLES, Mdt_payload, S_SHM_TYPE_OR_NONE, S_GRACEFUL_FINISH_REQUIRED_V >::async_connect(), ipc::session::shm::classic::Client_session_impl< S_MQ_TYPE_OR_NONE, S_TRANSMIT_NATIVE_HANDLES, Mdt_payload >::async_connect(), ipc::session::Session_base< S_MQ_TYPE_OR_NONE, S_TRANSMIT_NATIVE_HANDLES, Mdt_payload >::cur_ns_store_mutex_absolute_name(), ipc::session::decompose_conventional_shared_name(), ipc::util::for_each_persistent_impl(), ipc::session::shm::classic::Session_server< S_MQ_TYPE_OR_NONE, S_TRANSMIT_NATIVE_HANDLES, Mdt_payload >::init_app_shm_as_needed(), ipc::session::shm::arena_lend::jemalloc::Session_server< S_MQ_TYPE_OR_NONE, S_TRANSMIT_NATIVE_HANDLES, Mdt_payload >::init_app_shm_as_needed(), ipc::session::shm::arena_lend::jemalloc::Session_impl< Session_impl_t >::init_shm(), ipc::session::Server_session_impl< S_MQ_TYPE_OR_NONE, S_TRANSMIT_NATIVE_HANDLES, Mdt_payload, S_SHM_TYPE_OR_NONE, S_SHM_MAX_HNDL_SZ, S_GRACEFUL_FINISH_REQUIRED_V >::make_channel_mqs(), ipc::session::Client_session_impl< S_MQ_TYPE_OR_NONE, S_TRANSMIT_NATIVE_HANDLES, Mdt_payload, S_SHM_TYPE_OR_NONE, S_GRACEFUL_FINISH_REQUIRED_V >::on_master_channel_init_open_channel(), ipc::session::Client_session_impl< S_MQ_TYPE_OR_NONE, S_TRANSMIT_NATIVE_HANDLES, Mdt_payload, S_SHM_TYPE_OR_NONE, S_GRACEFUL_FINISH_REQUIRED_V >::on_master_channel_log_in_rsp(), ipc::session::Client_session_impl< S_MQ_TYPE_OR_NONE, S_TRANSMIT_NATIVE_HANDLES, Mdt_payload, S_SHM_TYPE_OR_NONE, S_GRACEFUL_FINISH_REQUIRED_V >::on_master_channel_open_channel_req(), ipc::session::Client_session_impl< S_MQ_TYPE_OR_NONE, S_TRANSMIT_NATIVE_HANDLES, Mdt_payload, S_SHM_TYPE_OR_NONE, S_GRACEFUL_FINISH_REQUIRED_V >::open_channel(), operator+(), operator/(), operator>>(), ipc::session::Session_base< S_MQ_TYPE_OR_NONE, S_TRANSMIT_NATIVE_HANDLES, Mdt_payload >::session_master_socket_stream_acceptor_absolute_name(), and ipc::session::Session_server_impl< Session_server_t, Server_session_t >::Session_server_impl().

Here is the caller graph for this function:

◆ ct() [3/3]

Shared_name ipc::util::Shared_name::ct ( std::string &&  src_moved)
static

Destructively move-constructs from an std::string, emptying that source object.

Rationale

See class doc header for rationale as-to why this is a static ctor as opposed to a regular ctor.

Parameters
src_movedString to move (make-.empty()).
Returns
The new object.

Definition at line 59 of file shared_name.cpp.

References m_raw_name.

◆ empty()

bool ipc::util::Shared_name::empty ( ) const

◆ has_trailing_separator()

bool ipc::util::Shared_name::has_trailing_separator ( ) const

Returns true if and only if !this->empty(), and str() ends with the S_SEPARATOR character.

Returns
See above.

Definition at line 160 of file shared_name.cpp.

References empty(), m_raw_name, and S_SEPARATOR.

Here is the call graph for this function:

◆ native_str()

const char * ipc::util::Shared_name::native_str ( ) const

Returns (sans copying) pointer to NUL-terminated wrapped name string, suitable to pass into sys calls when naming supported shared resources assuming absolute() == true.

If you require an std::string (such as for some fancy boost.interprocess call) See also str().

Why isn't it named c_str()?

It was, but capnp::StringPtr (and similar/derived classes such as capnp::Text::Reader) has a "clever" operator T() conversion operator that is enabled for all T that have .c_str(); and its implementation relies on being able to symmetrically construct T(const char*) – like std::string. We intentionally lack that. Hence renamed this away from .c_str(). This may appear like kow-towing to capnp's quirks, but actually conceivably that's a pattern people use, so let's not break it.

Returns
See above.

Definition at line 145 of file shared_name.cpp.

References m_raw_name.

Referenced by ipc::shm::classic::Pool_arena::Pool_arena(), ipc::transport::Bipc_mq_handle::remove_persistent(), and ipc::util::remove_persistent_shm_pool().

Here is the caller graph for this function:

◆ operator+=() [1/3]

Shared_name & ipc::util::Shared_name::operator+= ( const char *  raw_name_to_append)

Similar to the overload that takes const Source&, but takes NUL-terminated string instead.

See that doc header.

Parameters
raw_name_to_appendThing to append.
Returns
*this.

Definition at line 69 of file shared_name.cpp.

References m_raw_name.

◆ operator+=() [2/3]

Shared_name & ipc::util::Shared_name::operator+= ( const Shared_name src_to_append)

Appends the given other Shared_name.

Functionally equivalent to return *this += src_to_append.str());. If there's any reason to suspect the resulting name might be too long, execute sanitize() afterwards and ensure that returns true.

It is stylistically (and possibly for performance) better to use /= rather than manually appending a separator and then src_to_append (with this +=).

See Rationale(s) for operator/=(), as they apply here.

Parameters
src_to_appendThing to append.
Returns
*this.

Definition at line 77 of file shared_name.cpp.

References operator+=(), and str().

Referenced by operator+=(), and operator/=().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ operator+=() [3/3]

template<typename Source >
Shared_name & ipc::util::Shared_name::operator+= ( const Source &  raw_name_to_append)

Simply appends raw_name_to_append to the current value of str().

Specifically the internal std::string is modified as: s += raw_name_to_append. As a result, whatever most-performant available (single-arg by definition) operator+= that basic_string makes available is forwarded-to. (E.g., C++17 has a String_view_like appender which is overload-resolved-to only when it most makes sense.)

If there's any reason to suspect the resulting name might be too long, execute sanitize() afterwards and ensure that returns true.

It is stylistically (and possibly for performance) better to use /= rather than manually appending a separator and then src_to_append (with this +=).

See Rationale(s) for operator/=(), as they apply here.

Template Parameters
SourceSee above.
Parameters
raw_name_to_appendThing to append.
Returns
*this.

Definition at line 687 of file shared_name.hpp.

References m_raw_name.

◆ operator/=() [1/3]

Shared_name & ipc::util::Shared_name::operator/= ( const char *  raw_name_to_append)

Similar to the overload that takes const Source&, but takes NUL-terminated string instead.

See that doc header.

Parameters
raw_name_to_appendThing to append after appending separator.
Returns
*this.

Definition at line 83 of file shared_name.cpp.

References operator/=().

Here is the call graph for this function:

◆ operator/=() [2/3]

Shared_name & ipc::util::Shared_name::operator/= ( const Shared_name src_to_append)

Appends a folder separator followed by the given other Shared_name.

Functionally equivalent to return *this += (string(1, S_SEPARATOR) + src_to_append.str());. If there's any reason to suspect this->str() already ends in S_SEPARATOR, and/or that the resulting name might be too long, execute sanitize() afterwards and ensure that returns true.

It is stylistically (and possibly for performance) better to use this rather than manually appending a separator and then src_to_append (with +=).

Rationale for not doing something smarter like avoiding a double-separator due to concatenation

Basically we want things to be as fast as possible by default; and that is to make it as close to trivial string concatenation as possible. If more paranoia is required, we want the user to intentionally use sanitize() or sanitized().

Parameters
src_to_appendThing to append after appending separator.
Returns
*this.

Rationale for having this /= as opposed to only the version taking Source, or vice versa

If we had only the one taking Shared_name, then tried to use += X, where X is std::string or const char* or util::String_view, it'd have to (implicitly) construct a Shared_name first, and that is a bit slower.

If we had only the one taking Source (e.g., String_view), and user wanted to append a Shared_name, they'd have to use X.str() explicitly, losing a bit of syntactic sugar.

Same deal with += and the binary (+, /) derivations of these.

Definition at line 91 of file shared_name.cpp.

References operator/=(), and str().

Referenced by operator/=().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ operator/=() [3/3]

template<typename Source >
Shared_name & ipc::util::Shared_name::operator/= ( const Source &  raw_name_to_append)

Simply appends a folder separator followed by raw_name_to_append to the current value of str().

Specifically the internal std::string is modified as: s += S_SEPARATOR; s += raw_name_to_append. As a result, whatever most-performant available (single-arg by definition) operator+= that basic_string makes available is forwarded-to for the 2nd +=. (E.g., C++17 has a String_view_like appender which is overload-resolved-to only when it most makes sense.)

If there's any reason to suspect this->str() already ends in S_SEPARATOR, and/or that the resulting name might be too long, execute sanitize() afterwards and ensure that returns true.

It is stylistically (and possibly for performance) better to use this rather than manually appending a separator and then src_to_append (with +=).

See Rationale(s) for the other operator/=(), as they apply here.

Template Parameters
SourceSee above.
Parameters
raw_name_to_appendThing to append after appending separator.
Returns
*this.

Definition at line 696 of file shared_name.hpp.

References m_raw_name, operator+=(), and S_SEPARATOR.

Here is the call graph for this function:

◆ operator=() [1/2]

Shared_name & ipc::util::Shared_name::operator= ( const Shared_name src)
default

Copy-assigns from an existing Shared_name.

Parameters
srcSource object.
Returns
*this.

◆ operator=() [2/2]

Shared_name & ipc::util::Shared_name::operator= ( Shared_name &&  src_moved)
default

Move-assigns from an existing Shared_name.

Parameters
src_movedSource object, which is potentially modified.
Returns
*this.

◆ sanitize()

bool ipc::util::Shared_name::sanitize ( )

Best-effort attempt to turn sanitized() from false to true, unless it is already true; returns the final value of sanitized() indicating whether it was successful.

If false returned, then the final value of str() will equal the initial value.

This utility should be used very judiciously and with full knowledge of what it actually does. It should not be used "just in case" or "prophylactically" but only with full knowledge of where the current value of str() might originate. For example, it might come from some user input. Another example involves, perhaps, concatenating two path fragments in such a way as to potentially yield a double-S_SEPARATOR situation: sanitize() after this would get collapse the separators into just 1 separator. Yet another example is simply that if one combines two paths which don't exceed S_MAX_LENGTH, but the result might exceed it: running sanitize() and ensuring it returns true guaranteed one didn't accidentally exceed S_MAX_LENGTH.

In other words, use it when you want it to do what it, in fact, does. And that is:

  • Any '/' (forward-slash) character, as a special case, is transformed into S_SEPARATOR.
  • After any character replacements above: Any sequence of 2 or more S_SEPARATOR characters is collapsed into one S_SEPARATOR.

Things it does not do, except the above:

  • No legal or illegal character is changed (except '/' and separator collapsing).
  • It doesn't truncate to try to bring length to S_MAX_LENGTH or less.

However, the method's return value is still significant, in that if it is "still" false, then you know you have a real problem – yet if it's true, then it didn't do anything destructive to make it so.

Note, again, that the above replacements are "undone" if false is returned. In other words, the function won't sanitize "halfway."

Performance

There is at most one linear scan through str(). In addition, though only if actual sanitizing (by changing str()) might be necessary: an allocation, copy of str(), and deallocation may be performed. Overall, it is linear-time regardless, plus those potential alloc/dealloc ops.

Returns
What sanitized() would return just before returning from the present function.

Definition at line 221 of file shared_name.cpp.

References empty(), m_raw_name, S_MAX_LENGTH, S_SEPARATOR, and size().

Here is the call graph for this function:

◆ sanitized()

bool ipc::util::Shared_name::sanitized ( ) const

Returns true if and only if the contained name/fragment is sanitized according to length, legal characters, and similar.

More precisely, a sanitized *this satisfies all of the following:

  • There are no illegal characters. (E.g., in particular, some characters would not be accepted when naming a SHM object in Linux.)
    • In particular, only S_SEPARATOR is used as a folder separator.
  • There is no more than 1 instance of S_SEPARATOR character in a row.
  • size() does not exceed S_MAX_LENGTH.

Performance

It is linear-time, with at most one scan through str().

Returns
See above.

Definition at line 175 of file shared_name.cpp.

References m_raw_name, S_MAX_LENGTH, S_SEPARATOR, and size().

Here is the call graph for this function:

◆ size()

size_t ipc::util::Shared_name::size ( ) const

Returns str().size().

Returns
See above.

Definition at line 150 of file shared_name.cpp.

References m_raw_name.

Referenced by ipc::session::shm::arena_lend::jemalloc::Session_server< S_MQ_TYPE_OR_NONE, S_TRANSMIT_NATIVE_HANDLES, Mdt_payload >::cleanup(), ipc::transport::asio_local_stream_socket::endpoint_at_shared_name(), sanitize(), and sanitized().

Here is the caller graph for this function:

◆ str()

const std::string & ipc::util::Shared_name::str ( ) const

Returns (sans copying) ref to immutable entire wrapped name string, suitable to pass into sys calls when naming supported shared resources assuming absolute() == true.

If you require a NUL-terminated string (such as for a native call), use native_str().

Note
Returning a util::String_view seemed pointless, as one can always be constructed easily by the caller, and in any case – for the time being at least – some/many APIs that take non-C-strings will take std::string as opposed to a util::String_view.
Returns
See above.

Definition at line 140 of file shared_name.cpp.

References m_raw_name.

Referenced by ipc::session::Server_session_impl< S_MQ_TYPE_OR_NONE, S_TRANSMIT_NATIVE_HANDLES, Mdt_payload, S_SHM_TYPE_OR_NONE, S_SHM_MAX_HNDL_SZ, S_GRACEFUL_FINISH_REQUIRED_V >::async_accept_log_in(), ipc::session::shm::arena_lend::jemalloc::Client_session_impl< S_MQ_TYPE_OR_NONE, S_TRANSMIT_NATIVE_HANDLES, Mdt_payload >::cleanup(), ipc::session::shm::arena_lend::jemalloc::Session_server< S_MQ_TYPE_OR_NONE, S_TRANSMIT_NATIVE_HANDLES, Mdt_payload >::cleanup(), ipc::session::decompose_conventional_shared_name(), ipc::transport::asio_local_stream_socket::endpoint_at_shared_name(), hash_value(), ipc::session::shm::arena_lend::jemalloc::Session_impl< Session_impl_t >::init_shm(), ipc::session::Server_session_impl< S_MQ_TYPE_OR_NONE, S_TRANSMIT_NATIVE_HANDLES, Mdt_payload, S_SHM_TYPE_OR_NONE, S_SHM_MAX_HNDL_SZ, S_GRACEFUL_FINISH_REQUIRED_V >::mdt_builder(), ipc::session::Server_session_impl< S_MQ_TYPE_OR_NONE, S_TRANSMIT_NATIVE_HANDLES, Mdt_payload, S_SHM_TYPE_OR_NONE, S_SHM_MAX_HNDL_SZ, S_GRACEFUL_FINISH_REQUIRED_V >::on_master_channel_open_channel_req(), ipc::transport::Native_socket_stream_acceptor::on_next_peer_socket_or_error(), operator+(), operator+=(), operator/=(), ipc::util::operator<(), operator<<(), ipc::util::operator==(), and ipc::util::remove_each_persistent_with_name_prefix().

Here is the caller graph for this function:

Friends And Related Function Documentation

◆ hash_value()

size_t hash_value ( const Shared_name val)
related

Hasher of Shared_name for boost.unordered et al.

Parameters
valObject to hash.
Returns
See above.

Definition at line 412 of file shared_name.cpp.

References str().

Here is the call graph for this function:

◆ operator+() [1/5]

Shared_name operator+ ( const char *  raw_src1,
const Shared_name src2 
)
related

Returns new object equal to Shared_name(src2) with raw_src1 pre-pended to it.

Parameters
raw_src1String to precede the appended src2.
src2Object to append.
Returns
See above.

Definition at line 105 of file shared_name.cpp.

References ipc::util::operator+().

Here is the call graph for this function:

◆ operator+() [2/5]

Shared_name operator+ ( const Shared_name src1,
const char *  raw_src2 
)
related

Returns new object equal to Shared_name(src1) += raw_src2.

Parameters
src1Object to precede the appended raw_src2.
raw_src2String to append.
Returns
See above.

Definition at line 97 of file shared_name.cpp.

References ipc::util::operator+().

Here is the call graph for this function:

◆ operator+() [3/5]

Shared_name operator+ ( const Shared_name src1,
const Shared_name src2 
)
related

Returns new object equal to Shared_name(src1) += src2.

Parameters
src1Object to precede the appended src2.
src2Object to append.
Returns
See above.

Definition at line 113 of file shared_name.cpp.

References str().

Here is the call graph for this function:

◆ operator+() [4/5]

template<typename Source >
Shared_name operator+ ( const Shared_name src1,
const Source &  raw_src2 
)
related

Returns new object equal to Shared_name(src1) += raw_src2.

Template Parameters
SourceSee Shared_name::operator+=() similar overload.
Parameters
src1Object to precede the appended raw_src2.
raw_src2String to append.
Returns
See above.

Definition at line 708 of file shared_name.hpp.

◆ operator+() [5/5]

template<typename Source >
Shared_name operator+ ( const Source &  raw_src1,
const Shared_name src2 
)
related

Returns new object equal to Shared_name(src2) with raw_src1 pre-pended to it.

Template Parameters
SourceSee Shared_name::operator+=() similar overload.
Parameters
raw_src1String to precede the appended src2.
src2Object to append.
Returns
See above.

Definition at line 716 of file shared_name.hpp.

References ct().

Here is the call graph for this function:

◆ operator/() [1/5]

Shared_name operator/ ( const char *  raw_src1,
const Shared_name src2 
)
related

Returns new object equal to Shared_name(raw_src1) /= src2.

Parameters
raw_src1String to precede the appended separator and src2.
src2Object to append after separator.
Returns
See above.

Definition at line 127 of file shared_name.cpp.

References ipc::util::operator/().

Here is the call graph for this function:

◆ operator/() [2/5]

Shared_name operator/ ( const Shared_name src1,
const char *  raw_src2 
)
related

Returns new object equal to Shared_name(src1) /= raw_src2.

Parameters
src1Object to precede the appended separator and raw_src2.
raw_src2String to append after separator.
Returns
See above.

Definition at line 119 of file shared_name.cpp.

References ipc::util::operator/().

Here is the call graph for this function:

◆ operator/() [3/5]

Shared_name operator/ ( const Shared_name src1,
const Shared_name src2 
)
related

Returns new object equal to Shared_name(src1) /= src2.

Parameters
src1Object to precede the appended separator and src2.
src2Object to append after separator.
Returns
See above.

Definition at line 135 of file shared_name.cpp.

◆ operator/() [4/5]

template<typename Source >
Shared_name operator/ ( const Shared_name src1,
const Source &  raw_src2 
)
related

Returns new object equal to Shared_name(src1) /= raw_src2.

Template Parameters
SourceSee Shared_name::operator/=() similar overload.
Parameters
src1Object to precede the appended separator and raw_src2.
raw_src2String to append after separator.
Returns
See above.

Definition at line 724 of file shared_name.hpp.

◆ operator/() [5/5]

template<typename Source >
Shared_name operator/ ( const Source &  raw_src1,
const Shared_name src2 
)
related

Returns new object equal to Shared_name(raw_src1) /= src2.

Template Parameters
SourceSee Shared_name::operator/=() similar overload.
Parameters
raw_src1String to precede the appended separator and src2.
src2Object to append after separator.
Returns
See above.

Definition at line 732 of file shared_name.hpp.

References ct().

Here is the call graph for this function:

◆ operator<<()

std::ostream & operator<< ( std::ostream &  os,
const Shared_name val 
)
related

Prints embellished string representation of the given Shared_name to the given ostream.

Warning
This is not equivalent to writing Shared_name::str(); as of this writing it includes not just str() but also the number of characters in it as a decimal and a separator, for convenience in test/debug, to visually detect names approaching certain length limits. If you wish to output val.str(), then output... well... val.str().
Todo:
Does Shared_name operator>> and operator<< being asymmetrical get one into trouble when using Shared_name with boost.program_options (or flow::cfg which is built on top of it)? Look into it. It may be necessary to make operator<< equal to that of ostream << string after all; though the added niceties of the current << semantics may still at least be available via some explicit accessor.
Parameters
osStream to which to write.
valObject to serialize.
Returns
os.

Definition at line 353 of file shared_name.cpp.

References str().

Here is the call graph for this function:

◆ operator>>()

std::istream & operator>> ( std::istream &  is,
Shared_name val 
)
related

Reads Shared_name from the given istream; equivalent to reading string into Shared_name::str().

Parameters
isStream to read.
valObject to which to deserialize.
Returns
is.

Definition at line 364 of file shared_name.cpp.

References ct().

Here is the call graph for this function:

◆ swap [1/2]

void swap ( Shared_name val1,
Shared_name val2 
)
friend

Swaps two objects.

Constant-time. Suitable for standard ADL-swap pattern using std::swap; swap(val1, val2);.

Parameters
val1Object.
val2Object.

Definition at line 420 of file shared_name.cpp.

◆ swap() [2/2]

void swap ( Shared_name val1,
Shared_name val2 
)
related

Swaps two objects.

Constant-time. Suitable for standard ADL-swap pattern using std::swap; swap(val1, val2);.

Parameters
val1Object.
val2Object.

Definition at line 420 of file shared_name.cpp.

Member Data Documentation

◆ m_raw_name

std::string ipc::util::Shared_name::m_raw_name
private

The name or name fragment; see str().

Todo:
Consider providing a ref-to-mutable accessor to Shared_name::m_raw_name (or just make public). There are pros and cons; the basic pro being that Shared_name is meant to be a very thin wrapper around std::string, so it might make sense to allow for in-place modification without supplying some kind of reduced subset of string API. Suggest doing this to-do if a practical desire comes about.

Definition at line 659 of file shared_name.hpp.

Referenced by absolute(), clear(), ct(), empty(), has_trailing_separator(), native_str(), operator+=(), operator/=(), sanitize(), sanitized(), size(), and str().

◆ S_1ST_OR_ONLY

const Shared_name ipc::util::Shared_name::S_1ST_OR_ONLY = Shared_name::ct("1")
static

A Shared_name fragment, with no S_SEPARATOR characters inside, that represents a path component that (1) is not S_SENTINEL and (2) is suggested as the first or only unique ID of items at the same depth in the same context.

In actual fact it equals 1; and typically (though not necessarily – other conventions may exist) generated strings shall be 1, 2, ..., of which the former is S_1ST_OR_ONLY.

So if S_SENTINEL means "not a thing" or "special thing to be treated not like a normal thing", then S_1ST_OR_ONLY means "a normal thing, of which there may be only one, and this is the first one so created."

Suggested use pattern

This is most useful when, at this path level, you currently only have reason to have one object. Then you can name it S_1ST_OR_ONLY without relying on a magic string 1. However, if in the future there is reason to add more objects at the same level, then remove the use of S_1ST_OR_ONLY and instead use a uint or atomic<uint> data member that starts at simply the numeric 1, ++ing it each time a new object is added (and converting it via Shared_name::ct(std::to_string(x)) to string). The first object will have the same name as before, compatibly, while subsequent ones will be efficiently named uniquely.

Is this cheesy and reliant on the fact that this constant is, in fact, a string conversion of the number one? Yes, but the above pattern works and is reasonably efficient. I (ygoldfel) considered making this a super-general API that keeps generating unique IDs, but it just seemed like overkill given the simplicity of the task. Converting back from Shared_name, generating a new ++ed one, then converting back – while providing a simple-enough API to ensure atomicity – seemed inferior to just letting people maintain a compatible atomic<uint>, when and if desired, and using S_1ST_OR_ONLY until then.

Definition at line 309 of file shared_name.hpp.

Referenced by ipc::session::shm::classic::Server_session_impl< S_MQ_TYPE_OR_NONE, S_TRANSMIT_NATIVE_HANDLES, Mdt_payload >::async_accept_log_in(), ipc::session::shm::classic::Client_session_impl< S_MQ_TYPE_OR_NONE, S_TRANSMIT_NATIVE_HANDLES, Mdt_payload >::async_connect(), and ipc::session::shm::classic::Session_server< S_MQ_TYPE_OR_NONE, S_TRANSMIT_NATIVE_HANDLES, Mdt_payload >::init_app_shm_as_needed().

◆ S_EMPTY

const Shared_name ipc::util::Shared_name::S_EMPTY
static

◆ S_MAX_LENGTH

const size_t ipc::util::Shared_name::S_MAX_LENGTH = 75
static

Max value of size() such that, if str() used to name a supported shared resource, sys call safely won't barf.

Todo:
Shared_name::S_MAX_LENGTH currently applies to all shared resource types, but it'd be a useful feature to have different limits depending on OS/whatever limitations for particular resources types such as SHM object names versus queue names versus whatever.
Todo:
Research real limits on Shared_name::S_MAX_LENGTH for different real resource types; choose something for MAX_LENGTH that leaves enough slack to avoid running into trouble when making actual sys calls; as discussed in the at-internal section of Shared_name doc header about this topic. Explain here how we get to the limit ultimately chosen. The limit as of this writing is 64, but real research is needed.

Definition at line 263 of file shared_name.hpp.

Referenced by sanitize(), and sanitized().

◆ S_RESOURCE_TYPE_ID_MUTEX

const Shared_name ipc::util::Shared_name::S_RESOURCE_TYPE_ID_MUTEX = Shared_name::ct("mtx")
static

Relative-folder fragment (no separators) identifying the resource type for: boost.interprocess named mutex.

Definition at line 315 of file shared_name.hpp.

Referenced by ipc::session::Session_base< S_MQ_TYPE_OR_NONE, S_TRANSMIT_NATIVE_HANDLES, Mdt_payload >::cur_ns_store_mutex_absolute_name().

◆ S_RESOURCE_TYPE_ID_SHM

const Shared_name ipc::util::Shared_name::S_RESOURCE_TYPE_ID_SHM = Shared_name::ct("shm")
static

◆ S_ROOT_MAGIC

const Shared_name ipc::util::Shared_name::S_ROOT_MAGIC = Shared_name::ct("libipc")
static

A Shared_name fragment, with no S_SEPARATOR characters inside, to be used in any Shared_name maintained by ipc itself as the leading path component.

Definition at line 272 of file shared_name.hpp.

Referenced by ipc::util::build_conventional_non_session_based_shared_name(), ipc::session::build_conventional_shared_name_prefix(), and ipc::session::decompose_conventional_shared_name().

◆ S_SENTINEL

const Shared_name ipc::util::Shared_name::S_SENTINEL = Shared_name::ct("0")
static

◆ S_SEPARATOR

const char ipc::util::Shared_name::S_SEPARATOR = '_'
static

The documentation for this class was generated from the following files: