1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
|
/**********************************************************************
Audacity: A Digital Audio Editor
Identifier.h
Paul Licameli split from Types.h
**********************************************************************/
#ifndef __AUDACITY_IDENTIFIER__
#define __AUDACITY_IDENTIFIER__
#include <vector>
#include <wx/string.h>
//! An explicitly nonlocalized string, not meant for the user to see.
/*! String manipulations are discouraged, other than splitting and joining on separator characters.
Wherever GET is used to fetch the underlying wxString, there should be a comment explaining the need for it.
*/
class STRINGS_API Identifier
{
public:
Identifier() = default;
//! Allow implicit conversion to this class, but not from
Identifier(const wxString &str) : value{ str } {}
//! Allow implicit conversion to this class, but not from
Identifier(const wxChar *str) : value{ str } {}
//! Allow implicit conversion to this class, but not from
Identifier(const char *str) : value{ str } {}
// Copy construction and assignment
Identifier( const Identifier & ) = default;
Identifier &operator = ( const Identifier& ) = default;
// Move construction and assignment
Identifier( wxString && str )
{ value.swap( str ); }
Identifier( Identifier && id )
{ swap( id ); }
Identifier &operator= ( Identifier&& id )
{
if ( this != &id )
value.clear(), swap( id );
return *this;
}
// Implements moves
void swap( Identifier &id ) { value.swap( id.value ); }
//! Convenience for building concatenated identifiers.
/*! The list must have at least two members (so you don't easily circumvent the restrictions on
interconversions intended in TaggedIdentifier below) */
explicit
Identifier(std::initializer_list<Identifier> components, wxChar separator);
bool empty() const { return value.empty(); }
size_t size() const { return value.size(); }
size_t length() const { return value.length(); }
//! Explicit conversion to wxString, meant to be ugly-looking and demanding of a comment why it's correct
const wxString &GET() const { return value; }
std::vector< Identifier > split( wxChar separator ) const;
private:
wxString value;
};
//! Comparisons of Identifiers are case-sensitive
inline bool operator == ( const Identifier &x, const Identifier &y )
{ return x.GET() == y.GET(); }
inline bool operator != ( const Identifier &x, const Identifier &y )
{ return !(x == y); }
inline bool operator < ( const Identifier &x, const Identifier &y )
{ return x.GET() < y.GET(); }
inline bool operator > ( const Identifier &x, const Identifier &y )
{ return y < x; }
inline bool operator <= ( const Identifier &x, const Identifier &y )
{ return !(y < x); }
inline bool operator >= ( const Identifier &x, const Identifier &y )
{ return !(x < y); }
namespace std
{
template<> struct hash< Identifier > {
size_t operator () ( const Identifier &id ) const // noexcept
{ return hash<wxString>{}( id.GET() ); }
};
}
//! This lets you pass Identifier into wxFileConfig::Read
inline bool wxFromString(const wxString& str, Identifier *id)
{ if (id) { *id = str; return true; } else return false; }
//! This lets you pass Identifier into wxFileConfig::Write
inline wxString wxToString( const Identifier& str ) { return str.GET(); }
//! Template generates different TaggedIdentifier classes that don't interconvert implicitly
/*! The second template parameter determines whether comparisons are case
sensitive; default is case sensitive */
template<typename Tag, bool CaseSensitive = true >
class TaggedIdentifier : public Identifier
{
public:
using TagType = Tag;
using Identifier::Identifier;
TaggedIdentifier() = default;
//! Copy allowed only for the same Tag class and case sensitivity
TaggedIdentifier( const TaggedIdentifier& ) = default;
//! Move allowed only for the same Tag class and case sensitivity
TaggedIdentifier( TaggedIdentifier&& ) = default;
//! Copy allowed only for the same Tag class and case sensitivity
TaggedIdentifier& operator= ( const TaggedIdentifier& ) = default;
//! Move allowed only for the same Tag class and case sensitivity
TaggedIdentifier& operator= ( TaggedIdentifier&& ) = default;
//! Copy prohibited for other Tag classes or case sensitivity
template< typename Tag2, bool b >
TaggedIdentifier( const TaggedIdentifier<Tag2, b>& ) = delete;
//! Move prohibited for other Tag classes or case sensitivity
template< typename Tag2, bool b >
TaggedIdentifier( TaggedIdentifier<Tag2, b>&& ) = delete;
//! Copy prohibited for other Tag classes or case sensitivity
template< typename Tag2, bool b >
TaggedIdentifier& operator= ( const TaggedIdentifier<Tag2, b>& ) = delete;
//! Move prohibited for other Tag classes or case sensitivity
template< typename Tag2, bool b >
TaggedIdentifier& operator= ( TaggedIdentifier<Tag2, b>&& ) = delete;
/*! Allow implicit conversion to this class from un-tagged Identifier,
but not from; resolution will use other overloads above if argument has a tag */
TaggedIdentifier(const Identifier &str) : Identifier{ str } {}
//! Explicit conversion to another kind of TaggedIdentifier
template<typename String, typename = typename String::TagType>
String CONVERT() const
{ return String{ this->GET() }; }
};
/*! Comparison of a TaggedIdentifier with an Identifier is allowed, resolving
to one of the operators on Identifiers, but always case sensitive.
Comparison operators for two TaggedIdentifiers require the same tags and case sensitivity. */
template< typename Tag1, typename Tag2, bool b1, bool b2 >
inline bool operator == (
const TaggedIdentifier< Tag1, b1 > &x, const TaggedIdentifier< Tag2, b2 > &y )
{
static_assert( std::is_same_v< Tag1, Tag2 > && b1 == b2,
"TaggedIdentifiers with different tags or sensitivity are not comparable" );
// This test should be eliminated at compile time:
if ( b1 )
return x.GET(). Cmp ( y.GET() ) == 0;
else
return x.GET(). CmpNoCase ( y.GET() ) == 0;
}
template< typename Tag1, typename Tag2, bool b1, bool b2 >
inline bool operator != (
const TaggedIdentifier< Tag1, b1 > &x, const TaggedIdentifier< Tag2, b2 > &y )
{ return !(x == y); }
template< typename Tag1, typename Tag2, bool b1, bool b2 >
inline bool operator < (
const TaggedIdentifier< Tag1, b1 > &x, const TaggedIdentifier< Tag2, b2 > &y )
{
static_assert( std::is_same_v< Tag1, Tag2 > && b1 == b2,
"TaggedIdentifiers with different tags or sensitivity are not comparable" );
// This test should be eliminated at compile time:
if ( b1 )
return x.GET(). Cmp ( y.GET() ) < 0;
else
return x.GET(). CmpNoCase ( y.GET() ) < 0;
}
template< typename Tag1, typename Tag2, bool b1, bool b2 >
inline bool operator > (
const TaggedIdentifier< Tag1, b1 > &x, const TaggedIdentifier< Tag2, b2 > &y )
{ return y < x; }
template< typename Tag1, typename Tag2, bool b1, bool b2 >
inline bool operator <= (
const TaggedIdentifier< Tag1, b1 > &x, const TaggedIdentifier< Tag2, b2 > &y )
{ return !(y < x); }
template< typename Tag1, typename Tag2, bool b1, bool b2 >
inline bool operator >= (
const TaggedIdentifier< Tag1, b1 > &x, const TaggedIdentifier< Tag2, b2 > &y )
{ return !(x < y); }
namespace std
{
template<typename Tag, bool b > struct hash< TaggedIdentifier<Tag, b> >
: hash< Identifier > {};
}
/**************************************************************************//**
\brief type alias for identifying a Plugin supplied by a module, each module
defining its own interpretation of the strings, which may or may not be as a
file system path
********************************************************************************/
using PluginPath = wxString;
using PluginPaths = std::vector< PluginPath >;
// A key to be passed to wxConfigBase
using RegistryPath = wxString;
using RegistryPaths = std::vector< RegistryPath >;
class wxArrayStringEx;
//! File extension, not including any leading dot
using FileExtension = wxString;
using FileExtensions = wxArrayStringEx;
using FilePath = wxString;
using FilePaths = wxArrayStringEx;
struct CommandIdTag;
//! Identifies a menu command or macro. Case-insensitive comparison
using CommandID = TaggedIdentifier< CommandIdTag, false >;
using CommandIDs = std::vector<CommandID>;
struct ManualPageIDTag;
using ManualPageID = TaggedIdentifier< ManualPageIDTag >;
using NumericFormatID = TaggedIdentifier<struct NumericFormatIDTag>;
#endif
|