diff --git a/include/eepp/system/inifile.hpp b/include/eepp/system/inifile.hpp index 97958da45..d1d5e055a 100644 --- a/include/eepp/system/inifile.hpp +++ b/include/eepp/system/inifile.hpp @@ -16,12 +16,12 @@ #ifndef EE_SYSTEM_INIFILE_HPP #define EE_SYSTEM_INIFILE_HPP +#include #include #include #include #include #include -#include namespace EE { namespace System { @@ -32,13 +32,13 @@ class EE_API IniFile { enum errors { noID = -1 }; /** Initialize and load the ini file from path */ - IniFile( const std::string& iniPath = "", bool autoLoad = true ); + IniFile( std::string_view iniPath = {}, bool autoLoad = true ); /** Initialize and load the ini file from memory */ IniFile( const Uint8* RAWData, const Uint32& size, bool autoLoad = true ); /** Initialize and load the ini file from a pack file */ - IniFile( Pack* Pack, const std::string& iniPackPath, bool autoLoad = true ); + IniFile( Pack* Pack, std::string_view iniPackPath, bool autoLoad = true ); /** Initialize and load the ini file from a stream */ IniFile( IOStream& stream, bool autoLoad = true ); @@ -46,19 +46,19 @@ class EE_API IniFile { virtual ~IniFile() {} /** Loads an ini file from path */ - bool loadFromFile( const std::string& iniPath ); + bool loadFromFile( std::string_view iniPath ); /** Loads an ini file from memory */ bool loadFromMemory( const Uint8* RAWData, const Uint32& size ); /** Loads an ini file from a pack file */ - bool loadFromPack( Pack* Pack, const std::string& iniPackPath ); + bool loadFromPack( Pack* Pack, std::string_view iniPackPath ); /** Loads an ini file from a stream */ bool loadFromStream( IOStream& stream ); /** Sets mPath of ini file to read and write from. */ - void path( const std::string& newPath ) { mPath = newPath; } + void path( std::string_view newPath ) { mPath.assign( newPath ); } /** @return The ini file path */ const std::string& path() const { return mPath; } @@ -77,22 +77,16 @@ class EE_API IniFile { void clear(); /** @return index of specified key, or noID if not found. */ - long findKey( const std::string& keyname ) const; - - long findKey( const std::string_view& keyname ) const; + long findKey( std::string_view keyname ) const; /** @return index of specified value, in the specified key, or noID if not found. */ - long findValue( unsigned const keyID, const std::string& valuename ) const; - - long findValue( unsigned const keyID, const std::string_view& valuename ) const; + long findValue( unsigned const keyID, std::string_view valuename ) const; /** @return number of Keys currently in the ini. */ - unsigned getNumKeys() const { return (unsigned int)mNames.size(); } + unsigned getNumKeys() const { return (unsigned int)mKeys.size(); } /** Add a key name. */ - unsigned addKeyName( const std::string& keyname ); - - unsigned addKeyName( const std::string_view& keyname ); + unsigned addKeyName( std::string_view keyname ); /** @return key Names by index. */ std::string getKeyName( unsigned const keyID ) const; @@ -101,45 +95,45 @@ class EE_API IniFile { unsigned getNumValues( unsigned const keyID ); /** @return number of values stored for specified key from its name. */ - unsigned getNumValues( const std::string& keyname ); + unsigned getNumValues( std::string_view keyname ); /** @return value name by index for a given keyname or keyID. */ std::string getValueName( unsigned const keyID, unsigned const valueID ) const; /** @return A value name from keyname and valueId */ - std::string getValueName( const std::string& keyname, unsigned const valueID ) const; + std::string getValueName( std::string_view keyname, unsigned const valueID ) const; /** Gets value of [keyname] valuename =. ** Overloaded to return std::string, int, and double. ** @return defValue if key/value not found otherwise the value obtained. */ std::string getValue( unsigned const keyID, unsigned const valueID, - const std::string& defValue = "" ) const; + std::string_view defValue = {} ) const; /** Gets a value from a keyname and valuename */ - std::string getValue( const std::string& keyname, const std::string& valuename, - const std::string& defValue = "" ) const; + std::string getValue( std::string_view keyname, std::string_view valuename, + std::string_view defValue = {} ) const; /** Gets the value as integer */ - int getValueI( const std::string& keyname, const std::string& valuename, + int getValueI( std::string_view keyname, std::string_view valuename, int const defValue = 0 ) const; /** Gets the value as an unsigned long */ - unsigned long getValueU( const std::string& keyname, const std::string& valuename, + unsigned long getValueU( std::string_view keyname, std::string_view valuename, unsigned long const defValue = 0 ) const; /** Gets the value as boolean */ - bool getValueB( const std::string& keyname, const std::string& valuename, + bool getValueB( std::string_view keyname, std::string_view valuename, bool const defValue = false ) const; /** Gets the value as double */ - double getValueF( const std::string& keyname, const std::string& valuename, + double getValueF( std::string_view keyname, std::string_view valuename, double const defValue = 0.0 ) const; /** Sets value of [keyname] valuename =. ** Specify the optional parameter as false (0) if you do not want it to create ** the key if it doesn't exist. @return true if data entered, false otherwise. ** Overloaded to accept std::string, int, and double. */ - bool setValue( unsigned const keyID, unsigned const valueID, const std::string& value ); + bool setValue( unsigned const keyID, unsigned const valueID, std::string_view value ); /** Sets the value from a keyname and a valuename * @param keyname The key name @@ -147,11 +141,8 @@ class EE_API IniFile { * @param value The value to assign * @param create If true it will create the keyname if doesn't exists */ - bool setValue( const std::string& keyname, const std::string& valuename, - const std::string& value, bool create = true ); - - bool setValue( const std::string_view& keyname, const std::string_view& valuename, - const std::string_view& value, bool create = true ); + bool setValue( std::string_view keyname, std::string_view valuename, std::string_view value, + bool create = true ); /** Sets a integer value from a keyname and a valuename * @param keyname The key name @@ -159,7 +150,7 @@ class EE_API IniFile { * @param value The value to assign * @param create If true it will create the keyname if doesn't exists */ - bool setValueI( const std::string& keyname, const std::string& valuename, int const value, + bool setValueI( std::string_view keyname, std::string_view valuename, int const value, bool create = true ); /** Sets a unsigned long value from a keyname and a valuename @@ -168,8 +159,8 @@ class EE_API IniFile { * @param value The value to assign * @param create If true it will create the keyname if doesn't exists */ - bool setValueU( const std::string& keyname, const std::string& valuename, - unsigned long const value, bool create = true ); + bool setValueU( std::string_view keyname, std::string_view valuename, unsigned long const value, + bool create = true ); /** Sets a boolean value from a keyname and a valuename * @param keyname The key name @@ -177,7 +168,7 @@ class EE_API IniFile { * @param value The value to assign * @param create If true it will create the keyname if doesn't exists */ - bool setValueB( const std::string& keyname, const std::string& valuename, bool const value, + bool setValueB( std::string_view keyname, std::string_view valuename, bool const value, bool create = true ) { return setValueI( keyname, valuename, int( value ), create ); } @@ -188,19 +179,19 @@ class EE_API IniFile { * @param value The value to assign * @param create If true it will create the keyname if doesn't exists */ - bool setValueF( const std::string& keyname, const std::string& valuename, double const value, + bool setValueF( std::string_view keyname, std::string_view valuename, double const value, bool create = true ); /** Sets a formatted value from a keyname and a valuename */ - bool setValueV( const std::string& keyname, const std::string& valuename, char* format, ... ); + bool setValueV( std::string_view keyname, std::string_view valuename, char* format, ... ); /** Deletes specified value. ** @return true if value existed and deleted, false otherwise. */ - bool deleteValue( const std::string& keyname, const std::string& valuename ); + bool deleteValue( std::string_view keyname, std::string_view valuename ); /** Deletes specified key and all values contained within. ** @return true if key existed and deleted, false otherwise. */ - bool deleteKey( const std::string& keyname ); + bool deleteKey( std::string_view keyname ); /** Header comment functions. ** Header comments are those comments before the first key. @@ -208,7 +199,7 @@ class EE_API IniFile { unsigned numHeaderComments() { return (unsigned int)mComments.size(); } /** Add a header comment. */ - void addHeaderComment( const std::string& comment ); + void addHeaderComment( std::string_view comment ); /** Return a header comment. */ std::string getHeaderComment( unsigned const commentID ) const; @@ -221,12 +212,12 @@ class EE_API IniFile { std::map getKeyMap( const unsigned& keyID ) const; - std::map getKeyMap( const std::string& keyname ) const; + std::map getKeyMap( std::string_view keyname ) const; std::unordered_map getKeyUnorderedMap( const unsigned& keyID ) const; std::unordered_map - getKeyUnorderedMap( const std::string& keyname ) const; + getKeyUnorderedMap( std::string_view keyname ) const; /** Key comment functions. ** Key comments are those comments within a key. Any comments @@ -235,44 +226,45 @@ class EE_API IniFile { ** the IniFile::writeFile() is called. ** Number of key comments. */ unsigned getNumKeyComments( unsigned const keyID ) const; - unsigned getNumKeyComments( const std::string& keyname ) const; + unsigned getNumKeyComments( std::string_view keyname ) const; /** Add a key comment.*/ - bool addKeyComment( unsigned const keyID, const std::string& comment ); - bool addKeyComment( unsigned const keyID, const std::string_view& comment ); - bool addKeyComment( const std::string& keyname, const std::string& comment ); - bool addKeyComment( const std::string_view& keyname, const std::string_view& comment ); + bool addKeyComment( unsigned const keyID, std::string_view comment ); + bool addKeyComment( std::string_view keyname, std::string_view comment ); /** Return a key comment. */ std::string getKeyComment( unsigned const keyID, unsigned const commentID ) const; - std::string getKeyComment( const std::string& keyname, unsigned const commentID ) const; + std::string getKeyComment( std::string_view keyname, unsigned const commentID ) const; /** Delete a key comment. */ bool deleteKeyComment( unsigned const keyID, unsigned const commentID ); - bool deleteKeyComment( const std::string& keyname, unsigned const commentID ); + bool deleteKeyComment( std::string_view keyname, unsigned const commentID ); /** Delete all comments for a key. */ bool deleteKeyComments( unsigned const keyID ); - bool deleteKeyComments( const std::string& keyname ); + bool deleteKeyComments( std::string_view keyname ); bool iniParsed() { return mIniRead; } - bool keyExists( const std::string& keyname ) const; + bool keyExists( std::string_view keyname ) const; - bool keyValueExists( const std::string& keyname, const std::string& valuename ) const; + bool keyValueExists( std::string_view keyname, std::string_view valuename ) const; private: bool mIniRead{ false }; std::string mPath; std::string mBuffer; - struct key { - std::vector names; - std::vector values; - std::vector comments; + struct value { + std::string name; + std::string data; }; - std::vector mKeys; - std::vector mNames; - std::vector mComments; + struct key { + std::string name; + SmallVector values; + SmallVector comments; + }; + SmallVector mKeys; + SmallVector mComments; }; }} // namespace EE::System diff --git a/include/eepp/ui/doc/documentview.hpp b/include/eepp/ui/doc/documentview.hpp index 29d3f0441..9ed5b720a 100644 --- a/include/eepp/ui/doc/documentview.hpp +++ b/include/eepp/ui/doc/documentview.hpp @@ -37,7 +37,7 @@ class EE_API DocumentView { struct VisibleLineInfo { VisibleIndex visibleIndex{ VisibleIndex::invalid }; Float paddingStart{ 0 }; - std::vector visualLines; + SmallVector visualLines; }; struct VisibleLineRange { diff --git a/src/eepp/system/inifile.cpp b/src/eepp/system/inifile.cpp index e1366636a..c4f0c2b37 100644 --- a/src/eepp/system/inifile.cpp +++ b/src/eepp/system/inifile.cpp @@ -14,7 +14,7 @@ namespace EE { namespace System { -IniFile::IniFile( const std::string& iniPath, bool autoLoad ) { +IniFile::IniFile( std::string_view iniPath, bool autoLoad ) { if ( autoLoad ) loadFromFile( iniPath ); else @@ -26,7 +26,7 @@ IniFile::IniFile( const Uint8* RAWData, const Uint32& size, bool autoLoad ) { loadFromMemory( RAWData, size ); } -IniFile::IniFile( Pack* Pack, const std::string& iniPackPath, bool autoLoad ) { +IniFile::IniFile( Pack* Pack, std::string_view iniPackPath, bool autoLoad ) { if ( autoLoad ) loadFromPack( Pack, iniPackPath ); } @@ -36,11 +36,12 @@ IniFile::IniFile( IOStream& stream, bool autoLoad ) { loadFromStream( stream ); } -bool IniFile::loadFromPack( Pack* Pack, const std::string& iniPackPath ) { - if ( NULL != Pack && Pack->isOpen() && -1 != Pack->exists( iniPackPath ) ) { +bool IniFile::loadFromPack( Pack* Pack, std::string_view iniPackPath ) { + std::string path( iniPackPath ); + if ( NULL != Pack && Pack->isOpen() && -1 != Pack->exists( path ) ) { ScopedBuffer buffer; - Pack->extractFileToMemory( iniPackPath, buffer ); + Pack->extractFileToMemory( path, buffer ); return loadFromMemory( buffer.get(), buffer.length() ); } @@ -66,14 +67,14 @@ bool IniFile::loadFromMemory( const Uint8* RAWData, const Uint32& size ) { return loadFromStream( f ); } -bool IniFile::loadFromFile( const std::string& iniPath ) { +bool IniFile::loadFromFile( std::string_view iniPath ) { path( iniPath ); - if ( FileSystem::fileExists( iniPath ) ) { + if ( FileSystem::fileExists( mPath ) ) { IOStreamFile f( mPath ); return loadFromStream( f ); } else if ( PackRegistry::instance()->isFallbackToPacksActive() ) { - std::string tPath( iniPath ); + std::string tPath( mPath ); Pack* tPack = PackRegistry::instance()->exists( tPath ); @@ -149,7 +150,7 @@ bool IniFile::readFile() { break; case ';': case '#': - if ( !mNames.size() ) + if ( mKeys.empty() ) addHeaderComment( std::string{ line.substr( pLeft + 1 ) } ); else addKeyComment( keyname, std::string{ line.substr( pLeft + 1 ) } ); @@ -158,7 +159,7 @@ bool IniFile::readFile() { } } - if ( mNames.size() ) { + if ( !mKeys.empty() ) { mIniRead = true; return true; @@ -176,132 +177,113 @@ bool IniFile::writeStream( IOStream& stream ) { if ( !stream.isOpen() ) return false; - unsigned commentID, keyID, valueID; - std::string str; + static constexpr char commentPrefix = ';'; + static constexpr char keyPrefix = '['; + static constexpr char keySuffix[] = "]\n"; + static constexpr char valueSeparator = '='; + static constexpr char newline = '\n'; // Write header mComments. - for ( commentID = 0; commentID < mComments.size(); ++commentID ) { - str = ';' + mComments[commentID] + '\n'; - stream.write( str.c_str(), str.size() ); + for ( const auto& comment : mComments ) { + stream.write( &commentPrefix, 1 ); + stream.write( comment.data(), comment.size() ); + stream.write( &newline, 1 ); } - if ( mComments.size() ) { - str = "\n"; - stream.write( str.c_str(), str.size() ); - } + if ( !mComments.empty() ) + stream.write( &newline, 1 ); // Write Keys and values. - for ( keyID = 0; keyID < mKeys.size(); ++keyID ) { - str = '[' + mNames[keyID] + ']' + '\n'; - stream.write( str.c_str(), str.size() ); + for ( const auto& key : mKeys ) { + stream.write( &keyPrefix, 1 ); + stream.write( key.name.data(), key.name.size() ); + stream.write( keySuffix, sizeof( keySuffix ) - 1 ); // Comments. - for ( commentID = 0; commentID < mKeys[keyID].comments.size(); ++commentID ) { - str = ';' + mKeys[keyID].comments[commentID] + '\n'; - stream.write( str.c_str(), str.size() ); + for ( const auto& comment : key.comments ) { + stream.write( &commentPrefix, 1 ); + stream.write( comment.data(), comment.size() ); + stream.write( &newline, 1 ); } // Values. - for ( valueID = 0; valueID < mKeys[keyID].names.size(); ++valueID ) { - str = mKeys[keyID].names[valueID] + '=' + mKeys[keyID].values[valueID] + '\n'; - stream.write( str.c_str(), str.size() ); + for ( const auto& value : key.values ) { + stream.write( value.name.data(), value.name.size() ); + stream.write( &valueSeparator, 1 ); + stream.write( value.data.data(), value.data.size() ); + stream.write( &newline, 1 ); } - str = "\n"; - stream.write( str.c_str(), str.size() ); + stream.write( &newline, 1 ); } return true; } -long IniFile::findKey( const std::string& keyname ) const { - for ( unsigned keyID = 0; keyID < mNames.size(); ++keyID ) - if ( mNames[keyID] == keyname ) +long IniFile::findKey( std::string_view keyname ) const { + for ( unsigned keyID = 0; keyID < mKeys.size(); ++keyID ) + if ( mKeys[keyID].name == keyname ) return long( keyID ); return noID; } -long IniFile::findKey( const std::string_view& keyname ) const { - for ( unsigned keyID = 0; keyID < mNames.size(); ++keyID ) - if ( mNames[keyID] == keyname ) - return long( keyID ); - return noID; -} - -long IniFile::findValue( unsigned const keyID, const std::string& valuename ) const { +long IniFile::findValue( const unsigned int keyID, std::string_view valuename ) const { if ( !mKeys.size() || keyID >= mKeys.size() ) return noID; - for ( unsigned valueID = 0; valueID < mKeys[keyID].names.size(); ++valueID ) - if ( mKeys[keyID].names[valueID] == valuename ) + for ( unsigned valueID = 0; valueID < mKeys[keyID].values.size(); ++valueID ) + if ( mKeys[keyID].values[valueID].name == valuename ) return long( valueID ); return noID; } -long IniFile::findValue( const unsigned int keyID, const std::string_view& valuename ) const { - if ( !mKeys.size() || keyID >= mKeys.size() ) - return noID; - - for ( unsigned valueID = 0; valueID < mKeys[keyID].names.size(); ++valueID ) - if ( mKeys[keyID].names[valueID] == valuename ) - return long( valueID ); - return noID; -} - -unsigned IniFile::addKeyName( const std::string& keyname ) { - mNames.resize( mNames.size() + 1, keyname ); - mKeys.resize( mKeys.size() + 1 ); - return (unsigned int)( mNames.size() - 1 ); -} - -unsigned int IniFile::addKeyName( const std::string_view& keyname ) { - mNames.resize( mNames.size() + 1, std::string{ keyname } ); - mKeys.resize( mKeys.size() + 1 ); - return (unsigned int)( mNames.size() - 1 ); +unsigned int IniFile::addKeyName( std::string_view keyname ) { + mKeys.push_back( { std::string{ keyname }, {}, {} } ); + return (unsigned int)( mKeys.size() - 1 ); } std::string IniFile::getKeyName( unsigned const keyID ) const { - if ( keyID < mNames.size() ) - return mNames[keyID]; + if ( keyID < mKeys.size() ) + return mKeys[keyID].name; else return ""; } unsigned IniFile::getNumValues( unsigned const keyID ) { if ( keyID < mKeys.size() ) - return (unsigned int)mKeys[keyID].names.size(); + return (unsigned int)mKeys[keyID].values.size(); return 0; } -unsigned IniFile::getNumValues( const std::string& keyname ) { +unsigned IniFile::getNumValues( std::string_view keyname ) { long keyID = findKey( keyname ); if ( keyID == noID ) return 0; - return (unsigned int)mKeys[keyID].names.size(); + return (unsigned int)mKeys[keyID].values.size(); } std::string IniFile::getValueName( unsigned const keyID, unsigned const valueID ) const { - if ( keyID < mKeys.size() && valueID < mKeys[keyID].names.size() ) - return mKeys[keyID].names[valueID]; + if ( keyID < mKeys.size() && valueID < mKeys[keyID].values.size() ) + return mKeys[keyID].values[valueID].name; return ""; } -std::string IniFile::getValueName( const std::string& keyname, unsigned const valueID ) const { +std::string IniFile::getValueName( std::string_view keyname, unsigned const valueID ) const { long keyID = findKey( keyname ); if ( keyID == noID ) return ""; return getValueName( keyID, valueID ); } -bool IniFile::setValue( unsigned const keyID, unsigned const valueID, const std::string& value ) { - if ( keyID < mKeys.size() && valueID < mKeys[keyID].names.size() ) - mKeys[keyID].values[valueID] = value; +bool IniFile::setValue( unsigned const keyID, unsigned const valueID, std::string_view value ) { + if ( keyID < mKeys.size() && valueID < mKeys[keyID].values.size() ) + mKeys[keyID].values[valueID].data.assign( value ); return false; } -bool IniFile::setValue( const std::string& keyname, const std::string& valuename, - const std::string& value, bool create ) { +bool IniFile::setValue( std::string_view keyname, std::string_view valuename, + std::string_view value, bool create ) { long keyID = findKey( keyname ); if ( keyID == noID ) { if ( create ) @@ -314,37 +296,14 @@ bool IniFile::setValue( const std::string& keyname, const std::string& valuename if ( valueID == noID ) { if ( !create ) return false; - mKeys[keyID].names.resize( mKeys[keyID].names.size() + 1, valuename ); - mKeys[keyID].values.resize( mKeys[keyID].values.size() + 1, value ); + mKeys[keyID].values.push_back( { std::string{ valuename }, std::string{ value } } ); } else - mKeys[keyID].values[valueID] = value; + mKeys[keyID].values[valueID].data.assign( value ); return true; } -bool IniFile::setValue( const std::string_view& keyname, const std::string_view& valuename, - const std::string_view& value, bool create ) { - long keyID = findKey( keyname ); - if ( keyID == noID ) { - if ( create ) - keyID = long( addKeyName( std::string{ keyname } ) ); - else - return false; - } - - long valueID = findValue( unsigned( keyID ), valuename ); - if ( valueID == noID ) { - if ( !create ) - return false; - mKeys[keyID].names.resize( mKeys[keyID].names.size() + 1, std::string{ valuename } ); - mKeys[keyID].values.resize( mKeys[keyID].values.size() + 1, std::string{ value } ); - } else - mKeys[keyID].values[valueID] = value; - - return true; -} - -bool IniFile::setValueI( const std::string& keyname, const std::string& valuename, int const value, +bool IniFile::setValueI( std::string_view keyname, std::string_view valuename, int const value, bool create ) { char svalue[MAX_VALUEDATA]; @@ -352,7 +311,7 @@ bool IniFile::setValueI( const std::string& keyname, const std::string& valuenam return setValue( keyname, valuename, svalue, create ); } -bool IniFile::setValueU( const std::string& keyname, const std::string& valuename, +bool IniFile::setValueU( std::string_view keyname, std::string_view valuename, const unsigned long value, bool create ) { char svalue[MAX_VALUEDATA]; @@ -360,16 +319,15 @@ bool IniFile::setValueU( const std::string& keyname, const std::string& valuenam return setValue( keyname, valuename, svalue, create ); } -bool IniFile::setValueF( const std::string& keyname, const std::string& valuename, - double const value, bool create ) { +bool IniFile::setValueF( std::string_view keyname, std::string_view valuename, double const value, + bool create ) { char svalue[MAX_VALUEDATA]; String::formatBuffer( svalue, MAX_VALUEDATA, "%f", value ); return setValue( keyname, valuename, svalue, create ); } -bool IniFile::setValueV( const std::string& keyname, const std::string& valuename, char* format, - ... ) { +bool IniFile::setValueV( std::string_view keyname, std::string_view valuename, char* format, ... ) { va_list args; char value[MAX_VALUEDATA]; @@ -384,26 +342,26 @@ bool IniFile::setValueV( const std::string& keyname, const std::string& valuenam } std::string IniFile::getValue( unsigned const keyID, unsigned const valueID, - const std::string& defValue ) const { - if ( keyID < mKeys.size() && valueID < mKeys[keyID].names.size() ) - return mKeys[keyID].values[valueID]; - return defValue; + std::string_view defValue ) const { + if ( keyID < mKeys.size() && valueID < mKeys[keyID].values.size() ) + return mKeys[keyID].values[valueID].data; + return std::string{ defValue }; } -std::string IniFile::getValue( const std::string& keyname, const std::string& valuename, - const std::string& defValue ) const { +std::string IniFile::getValue( std::string_view keyname, std::string_view valuename, + std::string_view defValue ) const { long keyID = findKey( keyname ); if ( keyID == noID ) - return defValue; + return std::string{ defValue }; long valueID = findValue( unsigned( keyID ), valuename ); if ( valueID == noID ) - return defValue; + return std::string{ defValue }; - return mKeys[keyID].values[valueID]; + return mKeys[keyID].values[valueID].data; } -int IniFile::getValueI( const std::string& keyname, const std::string& valuename, +int IniFile::getValueI( std::string_view keyname, std::string_view valuename, int const defValue ) const { char svalue[MAX_VALUEDATA]; @@ -411,7 +369,7 @@ int IniFile::getValueI( const std::string& keyname, const std::string& valuename return atoi( getValue( keyname, valuename, svalue ).c_str() ); } -unsigned long IniFile::getValueU( const std::string& keyname, const std::string& valuename, +unsigned long IniFile::getValueU( std::string_view keyname, std::string_view valuename, const unsigned long defValue ) const { char svalue[MAX_VALUEDATA]; @@ -419,14 +377,14 @@ unsigned long IniFile::getValueU( const std::string& keyname, const std::string& return atoi( getValue( keyname, valuename, svalue ).c_str() ); } -bool IniFile::getValueB( const std::string& keyname, const std::string& valuename, +bool IniFile::getValueB( std::string_view keyname, std::string_view valuename, const bool defValue ) const { std::string val = getValue( keyname, valuename, defValue ? "1" : "0" ); char fist = !val.empty() ? val[0] : '0'; return fist == '1' || fist == 't' || fist == 'y' || fist == 'T' || fist == 'Y'; } -double IniFile::getValueF( const std::string& keyname, const std::string& valuename, +double IniFile::getValueF( std::string_view keyname, std::string_view valuename, double const defValue ) const { char svalue[MAX_VALUEDATA]; @@ -434,7 +392,7 @@ double IniFile::getValueF( const std::string& keyname, const std::string& valuen return atof( getValue( keyname, valuename, svalue ).c_str() ); } -bool IniFile::deleteValue( const std::string& keyname, const std::string& valuename ) { +bool IniFile::deleteValue( std::string_view keyname, std::string_view valuename ) { long keyID = findKey( keyname ); if ( keyID == noID ) return false; @@ -443,37 +401,30 @@ bool IniFile::deleteValue( const std::string& keyname, const std::string& valuen if ( valueID == noID ) return false; - // This looks strange, but is necessary. - std::vector::iterator npos = mKeys[keyID].names.begin() + valueID; - std::vector::iterator vpos = mKeys[keyID].values.begin() + valueID; - mKeys[keyID].names.erase( npos, npos + 1 ); - mKeys[keyID].values.erase( vpos, vpos + 1 ); + auto pos = mKeys[keyID].values.begin() + valueID; + mKeys[keyID].values.erase( pos ); return true; } -bool IniFile::deleteKey( const std::string& keyname ) { +bool IniFile::deleteKey( std::string_view keyname ) { long keyID = findKey( keyname ); if ( keyID == noID ) return false; - std::vector::iterator npos = mNames.begin() + keyID; - std::vector::iterator kpos = mKeys.begin() + keyID; - mNames.erase( npos, npos + 1 ); - mKeys.erase( kpos, kpos + 1 ); + mKeys.erase( mKeys.begin() + keyID ); return true; } void IniFile::clear() { mIniRead = false; - mNames.clear(); mKeys.clear(); mComments.clear(); } -void IniFile::addHeaderComment( const std::string& comment ) { - mComments.resize( mComments.size() + 1, comment ); +void IniFile::addHeaderComment( std::string_view comment ) { + mComments.emplace_back( comment ); } std::string IniFile::getHeaderComment( unsigned const commentID ) const { @@ -484,7 +435,7 @@ std::string IniFile::getHeaderComment( unsigned const commentID ) const { bool IniFile::deleteHeaderComment( unsigned commentID ) { if ( commentID < mComments.size() ) { - std::vector::iterator cpos = mComments.begin() + commentID; + auto cpos = mComments.begin() + commentID; mComments.erase( cpos, cpos + 1 ); return true; } @@ -494,15 +445,15 @@ bool IniFile::deleteHeaderComment( unsigned commentID ) { std::map IniFile::getKeyMap( const unsigned& keyID ) const { std::map map; if ( keyID < mKeys.size() ) { - for ( size_t i = 0; i < mKeys[keyID].names.size(); i++ ) { - map[mKeys[keyID].names[i]] = mKeys[keyID].values[i]; + for ( const auto& value : mKeys[keyID].values ) { + map[value.name] = value.data; } return map; } return {}; } -std::map IniFile::getKeyMap( const std::string& keyname ) const { +std::map IniFile::getKeyMap( std::string_view keyname ) const { long keyID = findKey( keyname ); if ( keyID != noID ) return getKeyMap( keyID ); @@ -513,8 +464,9 @@ std::unordered_map IniFile::getKeyUnorderedMap( const unsigned& keyID ) const { std::unordered_map map; if ( keyID < mKeys.size() ) { - for ( size_t i = 0; i < mKeys[keyID].names.size(); i++ ) { - map[mKeys[keyID].names[i]] = mKeys[keyID].values[i]; + map.reserve( mKeys[keyID].values.size() ); + for ( const auto& value : mKeys[keyID].values ) { + map.emplace( value.name, value.data ); } return map; } @@ -522,7 +474,7 @@ IniFile::getKeyUnorderedMap( const unsigned& keyID ) const { } std::unordered_map -IniFile::getKeyUnorderedMap( const std::string& keyname ) const { +IniFile::getKeyUnorderedMap( std::string_view keyname ) const { long keyID = findKey( keyname ); if ( keyID != noID ) return getKeyUnorderedMap( keyID ); @@ -535,37 +487,22 @@ unsigned IniFile::getNumKeyComments( unsigned const keyID ) const { return 0; } -unsigned IniFile::getNumKeyComments( const std::string& keyname ) const { +unsigned IniFile::getNumKeyComments( std::string_view keyname ) const { long keyID = findKey( keyname ); if ( keyID == noID ) return 0; return (unsigned int)mKeys[keyID].comments.size(); } -bool IniFile::addKeyComment( unsigned const keyID, const std::string& comment ) { +bool IniFile::addKeyComment( unsigned const keyID, std::string_view comment ) { if ( keyID < mKeys.size() ) { - mKeys[keyID].comments.resize( mKeys[keyID].comments.size() + 1, comment ); + mKeys[keyID].comments.emplace_back( comment ); return true; } return false; } -bool IniFile::addKeyComment( unsigned const keyID, const std::string_view& comment ) { - if ( keyID < mKeys.size() ) { - mKeys[keyID].comments.resize( mKeys[keyID].comments.size() + 1, std::string{ comment } ); - return true; - } - return false; -} - -bool IniFile::addKeyComment( const std::string& keyname, const std::string& comment ) { - long keyID = findKey( keyname ); - if ( keyID == noID ) - return false; - return addKeyComment( unsigned( keyID ), comment ); -} - -bool IniFile::addKeyComment( const std::string_view& keyname, const std::string_view& comment ) { +bool IniFile::addKeyComment( std::string_view keyname, std::string_view comment ) { long keyID = findKey( keyname ); if ( keyID == noID ) return false; @@ -578,7 +515,7 @@ std::string IniFile::getKeyComment( unsigned const keyID, unsigned const comment return ""; } -std::string IniFile::getKeyComment( const std::string& keyname, unsigned const commentID ) const { +std::string IniFile::getKeyComment( std::string_view keyname, unsigned const commentID ) const { long keyID = findKey( keyname ); if ( keyID == noID ) return ""; @@ -587,14 +524,14 @@ std::string IniFile::getKeyComment( const std::string& keyname, unsigned const c bool IniFile::deleteKeyComment( unsigned const keyID, unsigned const commentID ) { if ( keyID < mKeys.size() && commentID < mKeys[keyID].comments.size() ) { - std::vector::iterator cpos = mKeys[keyID].comments.begin() + commentID; + auto cpos = mKeys[keyID].comments.begin() + commentID; mKeys[keyID].comments.erase( cpos, cpos + 1 ); return true; } return false; } -bool IniFile::deleteKeyComment( const std::string& keyname, unsigned const commentID ) { +bool IniFile::deleteKeyComment( std::string_view keyname, unsigned const commentID ) { long keyID = findKey( keyname ); if ( keyID == noID ) return false; @@ -609,18 +546,18 @@ bool IniFile::deleteKeyComments( unsigned const keyID ) { return false; } -bool IniFile::deleteKeyComments( const std::string& keyname ) { +bool IniFile::deleteKeyComments( std::string_view keyname ) { long keyID = findKey( keyname ); if ( keyID == noID ) return false; return deleteKeyComments( unsigned( keyID ) ); } -bool IniFile::keyExists( const std::string& keyname ) const { +bool IniFile::keyExists( std::string_view keyname ) const { return findKey( keyname ) != noID; } -bool IniFile::keyValueExists( const std::string& keyname, const std::string& valuename ) const { +bool IniFile::keyValueExists( std::string_view keyname, std::string_view valuename ) const { long keyID = findKey( keyname ); if ( keyID == noID ) return false; diff --git a/src/tests/unit_tests/inifile_tests.cpp b/src/tests/unit_tests/inifile_tests.cpp new file mode 100644 index 000000000..48e1aeb84 --- /dev/null +++ b/src/tests/unit_tests/inifile_tests.cpp @@ -0,0 +1,107 @@ +#include "utest.hpp" + +#include +#include + +using namespace EE::System; + +UTEST( IniFile, preservesInsertionOrderAndSerializes ) { + IniFile ini( "", false ); + ini.addHeaderComment( "header" ); + ini.setValue( std::string_view{ "project" }, std::string_view{ "path" }, + std::string_view{ "/tmp/project" } ); + ini.setValue( std::string_view{ "project" }, std::string_view{ "session" }, + std::string_view{ "open" } ); + ini.addKeyComment( std::string_view{ "project" }, std::string_view{ "state" } ); + ini.setValueI( "editor", "tab_width", 4 ); + + IOStreamString stream; + EXPECT_TRUE( ini.writeStream( stream ) ); + EXPECT_STDSTREQ( ";header\n\n[project]\n;state\npath=/tmp/project\nsession=open\n\n" + "[editor]\ntab_width=4\n\n", + stream.getStream() ); + + EXPECT_EQ( 2u, ini.getNumKeys() ); + EXPECT_STDSTREQ( "project", ini.getKeyName( 0 ) ); + EXPECT_STDSTREQ( "session", ini.getValueName( 0, 1 ) ); + EXPECT_STDSTREQ( "open", ini.getValue( 0, 1 ) ); +} + +UTEST( IniFile, parsesUpdatesAndDeletesValues ) { + const std::string source = + "[project]\npath=/tmp/project\nsession=open\n\n[editor]\ntab_width=4\n"; + IniFile ini( reinterpret_cast( source.data() ), + static_cast( source.size() ) ); + + EXPECT_TRUE( ini.iniParsed() ); + EXPECT_TRUE( ini.setValue( std::string_view{ "project" }, std::string_view{ "session" }, + std::string_view{ "closed" } ) ); + EXPECT_TRUE( ini.deleteValue( "project", "path" ) ); + EXPECT_EQ( 1u, ini.getNumValues( "project" ) ); + EXPECT_STDSTREQ( "closed", ini.getValue( "project", "session" ) ); + EXPECT_TRUE( ini.deleteKey( "editor" ) ); + EXPECT_EQ( 1u, ini.getNumKeys() ); +} + +UTEST( IniFile, ecodeProjectStateRoundTripsByteForByte ) { + IniFile project( "/tmp/project.cfg", false ); + auto set = [&project]( std::string_view key, std::string_view name, std::string_view data ) { + return project.setValue( key, name, data ); + }; + + EXPECT_TRUE( set( "path", "folder_path", "/home/user/projects/eepp/" ) ); + project.setValueB( "project_tree", "show_hidden_files", true ); + project.setValueB( "document", "use_global_settings", false ); + EXPECT_TRUE( set( "document", "h_ext_language_type", "cpp" ) ); + project.setValueB( "document", "trim_trailing_whitespaces", true ); + project.setValueB( "document", "force_new_line_at_end_of_file", true ); + project.setValueB( "document", "auto_detect_indent_type", false ); + EXPECT_TRUE( set( "document", "auto_indent", "keep-indentation" ) ); + project.setValueB( "document", "write_bom", false ); + project.setValueI( "document", "indent_width", 4 ); + project.setValueB( "document", "indent_spaces", false ); + EXPECT_TRUE( set( "document", "line_endings", "LF" ) ); + project.setValueI( "document", "tab_width", 4 ); + project.setValueI( "document", "line_breaking_column", 100 ); + EXPECT_TRUE( set( "build", "build_name", "eepp-linux-ninja" ) ); + EXPECT_TRUE( set( "build", "build_type", "release" ) ); + EXPECT_TRUE( set( "build", "run_name", "ecode" ) ); + EXPECT_TRUE( set( + "nodes", "documents", + R"({"type":"splitter","first":{"type":"tabwidget","files":[{"type":"editor","path":"/home/user/projects/eepp/src/tools/ecode/appconfig.cpp"}]},"last":{"type":"tabwidget","files":[]}})" ) ); + EXPECT_TRUE( set( "languages_extensions", ".h", "cpp" ) ); + EXPECT_TRUE( set( "languages_extensions", ".inl", "cpp" ) ); + + const std::string expected = + "[path]\nfolder_path=/home/user/projects/eepp/\n\n" + "[project_tree]\nshow_hidden_files=1\n\n" + "[document]\nuse_global_settings=0\nh_ext_language_type=cpp\n" + "trim_trailing_whitespaces=1\nforce_new_line_at_end_of_file=1\n" + "auto_detect_indent_type=0\nauto_indent=keep-indentation\nwrite_bom=0\n" + "indent_width=4\nindent_spaces=0\nline_endings=LF\ntab_width=4\n" + "line_breaking_column=100\n\n" + "[build]\nbuild_name=eepp-linux-ninja\nbuild_type=release\nrun_name=ecode\n\n" + "[nodes]\ndocuments={\"type\":\"splitter\",\"first\":{\"type\":\"tabwidget\"," + "\"files\":[{\"type\":\"editor\",\"path\":\"/home/user/projects/eepp/src/tools/" + "ecode/appconfig.cpp\"}]},\"last\":{\"type\":\"tabwidget\",\"files\":[]}}\n\n" + "[languages_extensions]\n.h=cpp\n.inl=cpp\n\n"; + + IOStreamString firstWrite; + EXPECT_TRUE( project.writeStream( firstWrite ) ); + EXPECT_STDSTREQ( expected, firstWrite.getStream() ); + + IniFile reloaded( reinterpret_cast( expected.data() ), + static_cast( expected.size() ) ); + EXPECT_TRUE( reloaded.iniParsed() ); + EXPECT_STDSTREQ( "/home/user/projects/eepp/", reloaded.getValue( "path", "folder_path" ) ); + EXPECT_EQ( 100, reloaded.getValueI( "document", "line_breaking_column" ) ); + EXPECT_TRUE( reloaded.getValueB( "project_tree", "show_hidden_files" ) ); + EXPECT_FALSE( reloaded.setValue( std::string_view{ "missing" }, std::string_view{ "value" }, + std::string_view{ "data" }, false ) ); + EXPECT_TRUE( reloaded.setValue( std::string_view{ "build" }, std::string_view{ "run_name" }, + std::string_view{ "ecode" }, false ) ); + + IOStreamString secondWrite; + EXPECT_TRUE( reloaded.writeStream( secondWrite ) ); + EXPECT_STDSTREQ( expected, secondWrite.getStream() ); +} diff --git a/src/tools/ecode/projectbuild.cpp b/src/tools/ecode/projectbuild.cpp index 8232866e8..f06dc239f 100644 --- a/src/tools/ecode/projectbuild.cpp +++ b/src/tools/ecode/projectbuild.cpp @@ -735,7 +735,7 @@ void ProjectBuildManager::cancelRun() { mProcessRun->kill(); } -ProjectBuildConfiguration ProjectBuildManager::getConfig() const { +const ProjectBuildConfiguration& ProjectBuildManager::getConfig() const { return mConfig; } diff --git a/src/tools/ecode/projectbuild.hpp b/src/tools/ecode/projectbuild.hpp index 27001d456..9f1f23666 100644 --- a/src/tools/ecode/projectbuild.hpp +++ b/src/tools/ecode/projectbuild.hpp @@ -326,7 +326,7 @@ class ProjectBuildManager { void cancelRun(); - ProjectBuildConfiguration getConfig() const; + const ProjectBuildConfiguration& getConfig() const; void setConfig( const ProjectBuildConfiguration& config );