An Atom is like a String, except that its much cheaper to copy/store/compare, and the semantics of compare are queer. More...
#include <Atom.h>
Public Member Functions | |
constexpr | Atom () noexcept |
nonvirtual constexpr bool | empty () const |
nonvirtual void | clear () |
template<Common::IAnyOf< String, wstring, typename ATOM_MANAGER::AtomInternalType > T> | |
nonvirtual T | As () const |
nonvirtual String | ToString () const |
An Atom is like a String, except that its much cheaper to copy/store/compare, and the semantics of compare are queer.
An Atom is a wrapper on an underlying String object. You can always extract the original String.
The name 'atom' comes from LISP, and how it represented symbol names.
An Atom is much cheaper to copy/store and compare than a String. However - note that the compare is NOT the same as the traditional string compare. One Atom is equal to another IFF the underlying Strings would be equal. But the < behavior is very arbitrary. The only guarantee is that its consistent for the lifetime of the ATOM_MANAGER.
Note converting a String to an Atom maybe expensive, but if you can store the values as Atoms, future lookups with something like a hashtable can be much faster.
Atom can even be used with Set_Bitstring () – esp if you don’t use generic Atom<> but one with its own custom arena!
Design Choice: In some ways, this could be more powerful if the Atom construction took a ATOM_MANAGER as parameter. Then we could store the pointer, and do wholesale clearing / throwing away of atom names. But to make that work would have a lot of cost (always passing in extra param to construction), and tracking that pointer in each atom instance (would have to use shared_ptr to manage lifetimes or somehow assure lifetimes of atoms longer than their owning manager.
That might make sense todo, but would have a lot of cost. It COULD be done in the future (this API would then just be a type specialization).
But that's not where we start.
Extending Atom type and funky Managers
In HealthFrame, we use 'atoms' for user-defined strings, but specially formatted strings like C00013044, or H342341 are concepts. Also - the objects returned internally are concepts. This fits perfectly. You can use: struct AtomManager_Concepts { typedef ConceptKey AtomInternalType; static constexpr Concept kEmpty = ConceptKey(); static AtomInternalType Intern (const String& s); static String Extract (AtomInternalType atomI); }; and then use for struct Concept : Atom<AtomManager_Concepts> { // just constructors /forwarding Concept () = default; Concept (const String& s) = default; Concept (const Concept& concept) = default; Concept (const ConceptKey& concept) = default; // and access concept key inline ConceptKey GetConceptKey () const { return _GetInternalRep (); } }; AtomManager_Concepts::Intern () just indirects to AtomManager_Default::Intern () and then differently, and Extract() can look at the fields of the concept key and either algorithmically generate a name or indirect to AtomManager_Default::Extract ();
Atom's are compared in a way that will NOT in general be the same as print name compare. In general, their comparison will persist for app lifetime.
|
constexprnoexcept |
|
constexpr |
This corresponds to an empty string. An 'empty' Atom can be constructed with:
void Stroika::Foundation::DataExchange::Atom< ATOM_MANAGER >::clear | ( | ) |
nonvirtual T Stroika::Foundation::DataExchange::Atom< ATOM_MANAGER >::As | ( | ) | const |
Template on <T> only defined for T == String T == wstring AtomInternalType
String Stroika::Foundation::DataExchange::Atom< ATOM_MANAGER >::ToString | ( | ) | const |