|
Flow-IPC 3.0.0
Flow-IPC project: Public API.
|
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>
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_name & | operator= (const Shared_name &src) |
| Copy-assigns from an existing Shared_name. More... | |
| Shared_name & | operator= (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. | |
| 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_name & | operator/= (const Shared_name &src_to_append) |
| Appends a folder separator followed by the given other Shared_name. More... | |
| template<typename Source > | |
| 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(). More... | |
| Shared_name & | operator+= (const Shared_name &src_to_append) |
| Appends the given other Shared_name. More... | |
| template<typename Source > | |
| Shared_name & | operator+= (const Source &raw_name_to_append) |
Simply appends raw_name_to_append to the current value of str(). More... | |
Static Public Member Functions | |
| template<typename Source > | |
| static Shared_name | ct (const Source &src) |
Copy-constructs from a char-sequence container such as string or util::String_view. 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... | |
| template<typename Integer > | |
| static Shared_name | ct_from_int (Integer src) |
| Constructs from a value of an integer type, efficiently converting to a string representation of the number in base 10. More... | |
Static Public Attributes | |
| static const Shared_name | S_EMPTY |
A (default-cted) Shared_name. May be useful for functions returning const Shared_name&. | |
| static constexpr 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 constexpr char | S_SEPARATOR = '_' |
| Character we use, by convention, to separate conceptual folders within str(). | |
| 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. | |
| 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. | |
| 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. | |
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... | |
| 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 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... | |
| 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... | |
| 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... | |
| bool | operator== (const Shared_name &val1, const Shared_name &val2) |
Returns true if and only if val1.str() == val2.str(). More... | |
| bool | operator!= (const Shared_name &val1, const Shared_name &val2) |
Negation of similar ==. More... | |
| bool | operator== (const Shared_name &val1, util::String_view val2) |
Returns true if and only if val1.str() == string(val2). More... | |
| bool | operator!= (const Shared_name &val1, util::String_view val2) |
Negation of similar ==. More... | |
| bool | operator== (util::String_view val1, const Shared_name &val2) |
Returns true if and only if string(val1) == val2.str(). More... | |
| bool | operator!= (util::String_view val1, const Shared_name &val2) |
Negation of similar ==. More... | |
| bool | operator< (const Shared_name &val1, const Shared_name &val2) |
Returns true if and only if val1.str() < val2.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... | |
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.
constexpr-ify Shared_name to the extent possible; it might even make a dent in perf in some contexts. Internally this is annoying until C++20, where std::string itself got constexpr-ified, as we use std::string internally; best left alone until then.Shared_name_view which would be to Shared_name as String_view is to string; and that could itself be constructed from a String_view (and therefore from const char* [+ length], etc.). The main work would arguably not be the creation of that class itself but rather (1) ensuring proper implicit conversion between the main class and the new one and (2) conversion of the many Flow-IPC APIs that take a const Shared_name& that would (hopefully in essentially non-user-code-breaking ways) instead take Shared_name_view.Internally 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. (istream>> input is also provided but is identical to istream >> 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*); use it for other char containers such as vector<char>. However, construction from string (including destructive move-construction), util::String_view, or NUL-terminated const char* 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.)
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:
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:
true if and only if the first char is S_SEPARATOR. By convention, you should not pass str() to a sys call/similar, unless absolute() == true.true if and only if str() is a valid name or name fragment (no illegal characters; does not exceed S_MAX_LENGTH; no multi-separator sequences).true.You should call them only when you specifically need some conventions checked or enforced. Otherwise Shared_name ops will be as dumb/fast as possible.
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).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).
|
default |
Copy-constructs from an existing Shared_name.
| src | Source object. |
|
default |
Move-constructs from an existing Shared_name, which is made empty() if not already so.
| src_moved | Source object, which is potentially modified. |
|
explicit |
Copy-constructs from a char range given as a pair of random-iterators; in particular const char*s work.
| Input_it | An STL-compliant random iterator type. In particular const char* works. |
| begin | Start of range to copy. |
| end | One past last element in range to copy (begin to copy nothing). |
| 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.
|
static |
Copy-constructs from a NUL-terminated const char* string.
See class doc header for rationale as-to why this is a static ctor as opposed to a regular ctor.
| src | String to copy. |
|
static |
Copy-constructs from a char-sequence container such as string or util::String_view.
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.) Hence Source must be something std::string can be constructed from in that way; e.g., vector<char> is not: use the 2-iterator ctor for that.
See class doc header for rationale as-to why this is a static ctor as opposed to a regular ctor.
| Source | See above. |
| src | String to copy. |
|
static |
Destructively move-constructs from an std::string, emptying that source object.
See class doc header for rationale as-to why this is a static ctor as opposed to a regular ctor.
| src_moved | String to move (make-.empty()). |
|
static |
Constructs from a value of an integer type, efficiently converting to a string representation of the number in base 10.
Note that a negative value yields a leading -, so the result is then not sanitized().
| Integer | Signed or unsigned integer type of bit width 8, 16, 32, or 64. In particular bool is not supported (will not compile); char/int8_t and unsigned char/uint8_t are supported. |
| src | Integer to convert. |
| bool ipc::util::Shared_name::empty | ( | ) | const |
| 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.
| 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), use str().
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.
| 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.
| src_to_append | Thing to append. |
*this. | 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.
| Source | See above. |
| raw_name_to_append | Thing to append. |
*this. | 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.
&src_to_append == this, is handled properly.It is stylistically (and possibly for performance) better to use this rather than manually appending a separator and then src_to_append (with +=).
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().
| src_to_append | Thing to append after appending separator. |
*this. | 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.
If raw_name_to_append represents a range of characters that overlaps that of pre-call str() – including their being equal – this API will act functionally as-if one made a string copy of raw_name_to_append first and appended (a separator and) that copy. (This is similar to the guarantees made by string append APIs.)
| Source | See above. |
| raw_name_to_append | Thing to append after appending separator. |
*this.
|
default |
|
default |
Move-assigns from an existing Shared_name.
| src_moved | Source object, which is potentially modified. |
*this. | 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 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:
Things it does not do, modulo the above:
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."
There is at most one linear scan through str(), an allocation of size()d buffer, and a dealloc of ~similar.
| 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:
It is linear-time, with at most one scan through 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().
std::string as opposed to a util::String_view.
|
related |
|
related |
Negation of similar ==.
| val1 | See ==. |
| val2 | See ==. |
|
related |
Negation of similar ==.
| val1 | See ==. |
| val2 | See ==. |
|
related |
Negation of similar ==.
| val1 | See ==. |
| val2 | See ==. |
|
related |
Returns new object equal to Shared_name(src1) += src2.
| src1 | Object to precede the appended src2. |
| src2 | Object to append. |
|
related |
Returns new object equal to Shared_name(src1) += raw_src2.
| Source | See Shared_name::operator+=() similar overload. |
| src1 | Object to precede the appended raw_src2. |
| raw_src2 | String to append. |
|
related |
Returns new object equal to Shared_name(src2) with raw_src1 pre-pended to it.
| Source | See Shared_name::operator+=() similar overload. |
| raw_src1 | String to precede the appended src2. |
| src2 | Object to append. |
|
related |
Returns new object equal to Shared_name(src1) /= src2.
| src1 | Object to precede the appended separator and src2. |
| src2 | Object to append after separator. |
|
related |
Returns new object equal to Shared_name(src1) /= raw_src2.
| Source | See Shared_name::operator/=() similar overload. |
| src1 | Object to precede the appended separator and raw_src2. |
| raw_src2 | String to append after separator. |
|
related |
Returns new object equal to Shared_name(raw_src1) /= src2.
| Source | See Shared_name::operator/=() similar overload. |
| raw_src1 | String to precede the appended separator and src2. |
| src2 | Object to append after separator. |
|
related |
Returns true if and only if val1.str() < val2.str().
Enables use of Shared_name in an std::map without jumping through any special hoops.
| val1 | Object to compare. |
| val2 | Object to compare. |
|
related |
Prints embellished string representation of the given Shared_name to the given ostream.
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. (An empty() name prints as null.) If you wish to output val.str(), then output... well... val.str().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.| os | Stream to which to write. |
| val | Object to serialize. |
os.
|
related |
Returns true if and only if val1.str() == val2.str().
Caution: this does not execute normalize() or anything like that.
| val1 | Object to compare. |
| val2 | Object to compare. |
|
related |
Returns true if and only if val1.str() == string(val2).
Caution: this does not execute normalize() or anything like that.
| val1 | Object to compare. |
| val2 | String to compare. |
|
related |
Returns true if and only if string(val1) == val2.str().
Caution: this does not execute normalize() or anything like that.
| val1 | String to compare. |
| val2 | Object to compare. |
|
related |
Reads Shared_name from the given istream; equivalent to reading string into Shared_name::str().
| is | Stream to read. |
| val | Object to which to deserialize. |
is.
|
related |
Swaps two objects.
Constant-time. Suitable for standard ADL-swap pattern using std::swap; swap(val1, val2);.
| val1 | Object. |
| val2 | Object. |
|
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."
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 again – 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.
|
staticconstexpr |
Max value of size() such that, if str() used to name a supported shared resource, sys call safely won't barf.
|
static |
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.
In actual fact it equals 0; and typically (though not necessarily – other conventions may exist) generated strings shall be 1, 2, ..., of which the former is S_1ST_OR_ONLY.