1 /**********************************************************************
2 
3   Audacity: A Digital Audio Editor
4 
5   XMLMethodRegistry.cpp
6 
7   Paul Licameli
8 
9 **********************************************************************/
10 
11 #include "XMLMethodRegistry.h"
12 
13 #include "Identifier.h"
14 #include <wx/string.h>
15 
16 XMLMethodRegistryBase::XMLMethodRegistryBase() = default;
17 XMLMethodRegistryBase::~XMLMethodRegistryBase() = default;
18 
Register(std::string tag,TypeErasedObjectAccessor accessor)19 void XMLMethodRegistryBase::Register(
20    std::string tag, TypeErasedObjectAccessor accessor )
21 {
22    // Store string in a separate container from the map, so the map
23    // can be keyed by string_view.
24    // Beware small-string optimization!  Be sure strings don't relocate for
25    // growth of the container.  Use a list, not a vector.
26    auto &newtag = mTags.emplace_front(move(tag));
27    mTagTable[ newtag ] = move( accessor );
28 }
29 
CallObjectAccessor(const std::string_view & tag,void * p)30 XMLTagHandler *XMLMethodRegistryBase::CallObjectAccessor(
31    const std::string_view &tag, void *p )
32 {
33    const auto &table = mTagTable;
34    if (auto iter = table.find( tag ); iter != table.end())
35       if (auto &fn = iter->second)
36          return fn( p );
37    return nullptr;
38 }
39 
PushAccessor(TypeErasedAccessor accessor)40 void XMLMethodRegistryBase::PushAccessor( TypeErasedAccessor accessor )
41 {
42    mAccessors.emplace_back( move( accessor ) );
43 }
44 
Register(std::string tag,TypeErasedMutator mutator)45 void XMLMethodRegistryBase::Register(
46    std::string tag, TypeErasedMutator mutator )
47 {
48    // Similar to the other overload of Register
49    auto &newtag = mMutatorTags.emplace_front(move(tag));
50    mMutatorTable[ newtag ] = { mAccessors.size() - 1, move( mutator ) };
51 }
52 
CallAttributeHandler(const std::string_view & tag,void * p,const XMLAttributeValueView & value)53 bool XMLMethodRegistryBase::CallAttributeHandler( const std::string_view &tag,
54       void *p, const XMLAttributeValueView &value )
55 {
56    const auto &table = mMutatorTable;
57    if (auto iter = table.find(tag); iter != table.end())
58       // Tag is known
59       if (auto &pair = iter->second;
60           pair.second && pair.first < mAccessors.size() )
61          // Mutator is not null and accessor exists
62          if (auto &accessor = mAccessors[pair.first])
63             // Accessor is not null; compose accessor and mutator
64             return pair.second( accessor( p ), value ), true;
65    return false;
66 }
67 
RegisterAttributeWriter(TypeErasedWriter writer)68 void XMLMethodRegistryBase::RegisterAttributeWriter( TypeErasedWriter writer )
69 {
70    mAttributeWriterTable.emplace_back( move( writer ) );
71 }
72 
CallAttributeWriters(const void * p,XMLWriter & writer)73 void XMLMethodRegistryBase::CallAttributeWriters(
74    const void *p, XMLWriter &writer )
75 {
76    const auto &table = mAttributeWriterTable;
77    for ( auto &fn : table )
78       if (fn)
79          fn( p, writer );
80 }
81 
RegisterObjectWriter(TypeErasedWriter writer)82 void XMLMethodRegistryBase::RegisterObjectWriter( TypeErasedWriter writer )
83 {
84    mObjectWriterTable.emplace_back( move( writer ) );
85 }
86 
CallObjectWriters(const void * p,XMLWriter & writer)87 void XMLMethodRegistryBase::CallObjectWriters(
88    const void *p, XMLWriter &writer )
89 {
90    const auto &table = mObjectWriterTable;
91    for ( auto &fn : table )
92       if (fn)
93          fn( p, writer );
94 }
95