[deploy] Merge pull request #54 from KiwanoEngine/dev
Add StringView and ConfigIni
This commit is contained in:
		
						commit
						394c74d5e5
					
				|  | @ -96,9 +96,9 @@ | ||||||
|     <ClInclude Include="..\..\src\kiwano\render\TextStyle.hpp" /> |     <ClInclude Include="..\..\src\kiwano\render\TextStyle.hpp" /> | ||||||
|     <ClInclude Include="..\..\src\kiwano\render\Texture.h" /> |     <ClInclude Include="..\..\src\kiwano\render\Texture.h" /> | ||||||
|     <ClInclude Include="..\..\src\kiwano\render\TextureCache.h" /> |     <ClInclude Include="..\..\src\kiwano\render\TextureCache.h" /> | ||||||
|  |     <ClInclude Include="..\..\src\kiwano\utils\ConfigIni.h" /> | ||||||
|     <ClInclude Include="..\..\src\kiwano\utils\EventTicker.h" /> |     <ClInclude Include="..\..\src\kiwano\utils\EventTicker.h" /> | ||||||
|     <ClInclude Include="..\..\src\kiwano\utils\Json.h" /> |     <ClInclude Include="..\..\src\kiwano\utils\Json.h" /> | ||||||
|     <ClInclude Include="..\..\src\kiwano\utils\LocalStorage.h" /> |  | ||||||
|     <ClInclude Include="..\..\src\kiwano\utils\Logger.h" /> |     <ClInclude Include="..\..\src\kiwano\utils\Logger.h" /> | ||||||
|     <ClInclude Include="..\..\src\kiwano\utils\ResourceCache.h" /> |     <ClInclude Include="..\..\src\kiwano\utils\ResourceCache.h" /> | ||||||
|     <ClInclude Include="..\..\src\kiwano\utils\Task.h" /> |     <ClInclude Include="..\..\src\kiwano\utils\Task.h" /> | ||||||
|  | @ -174,8 +174,8 @@ | ||||||
|     <ClCompile Include="..\..\src\kiwano\render\TextLayout.cpp" /> |     <ClCompile Include="..\..\src\kiwano\render\TextLayout.cpp" /> | ||||||
|     <ClCompile Include="..\..\src\kiwano\render\Texture.cpp" /> |     <ClCompile Include="..\..\src\kiwano\render\Texture.cpp" /> | ||||||
|     <ClCompile Include="..\..\src\kiwano\render\TextureCache.cpp" /> |     <ClCompile Include="..\..\src\kiwano\render\TextureCache.cpp" /> | ||||||
|  |     <ClCompile Include="..\..\src\kiwano\utils\ConfigIni.cpp" /> | ||||||
|     <ClCompile Include="..\..\src\kiwano\utils\EventTicker.cpp" /> |     <ClCompile Include="..\..\src\kiwano\utils\EventTicker.cpp" /> | ||||||
|     <ClCompile Include="..\..\src\kiwano\utils\LocalStorage.cpp" /> |  | ||||||
|     <ClCompile Include="..\..\src\kiwano\utils\Logger.cpp" /> |     <ClCompile Include="..\..\src\kiwano\utils\Logger.cpp" /> | ||||||
|     <ClCompile Include="..\..\src\kiwano\utils\ResourceCache.cpp" /> |     <ClCompile Include="..\..\src\kiwano\utils\ResourceCache.cpp" /> | ||||||
|     <ClCompile Include="..\..\src\kiwano\utils\Task.cpp" /> |     <ClCompile Include="..\..\src\kiwano\utils\Task.cpp" /> | ||||||
|  |  | ||||||
|  | @ -105,9 +105,6 @@ | ||||||
|     <ClInclude Include="..\..\src\kiwano\2d\action\ActionWalk.h"> |     <ClInclude Include="..\..\src\kiwano\2d\action\ActionWalk.h"> | ||||||
|       <Filter>2d\action</Filter> |       <Filter>2d\action</Filter> | ||||||
|     </ClInclude> |     </ClInclude> | ||||||
|     <ClInclude Include="..\..\src\kiwano\utils\LocalStorage.h"> |  | ||||||
|       <Filter>utils</Filter> |  | ||||||
|     </ClInclude> |  | ||||||
|     <ClInclude Include="..\..\src\kiwano\utils\UserData.h"> |     <ClInclude Include="..\..\src\kiwano\utils\UserData.h"> | ||||||
|       <Filter>utils</Filter> |       <Filter>utils</Filter> | ||||||
|     </ClInclude> |     </ClInclude> | ||||||
|  | @ -351,6 +348,9 @@ | ||||||
|     <ClInclude Include="..\..\src\kiwano\base\component\ComponentManager.h"> |     <ClInclude Include="..\..\src\kiwano\base\component\ComponentManager.h"> | ||||||
|       <Filter>base\component</Filter> |       <Filter>base\component</Filter> | ||||||
|     </ClInclude> |     </ClInclude> | ||||||
|  |     <ClInclude Include="..\..\src\kiwano\utils\ConfigIni.h"> | ||||||
|  |       <Filter>utils</Filter> | ||||||
|  |     </ClInclude> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <ClCompile Include="..\..\src\kiwano\2d\Canvas.cpp"> |     <ClCompile Include="..\..\src\kiwano\2d\Canvas.cpp"> | ||||||
|  | @ -401,9 +401,6 @@ | ||||||
|     <ClCompile Include="..\..\src\kiwano\2d\action\ActionWalk.cpp"> |     <ClCompile Include="..\..\src\kiwano\2d\action\ActionWalk.cpp"> | ||||||
|       <Filter>2d\action</Filter> |       <Filter>2d\action</Filter> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
|     <ClCompile Include="..\..\src\kiwano\utils\LocalStorage.cpp"> |  | ||||||
|       <Filter>utils</Filter> |  | ||||||
|     </ClCompile> |  | ||||||
|     <ClCompile Include="..\..\src\kiwano\utils\UserData.cpp"> |     <ClCompile Include="..\..\src\kiwano\utils\UserData.cpp"> | ||||||
|       <Filter>utils</Filter> |       <Filter>utils</Filter> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
|  | @ -575,6 +572,9 @@ | ||||||
|     <ClCompile Include="..\..\src\kiwano\base\component\ComponentManager.cpp"> |     <ClCompile Include="..\..\src\kiwano\base\component\ComponentManager.cpp"> | ||||||
|       <Filter>base\component</Filter> |       <Filter>base\component</Filter> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
|  |     <ClCompile Include="..\..\src\kiwano\utils\ConfigIni.cpp"> | ||||||
|  |       <Filter>utils</Filter> | ||||||
|  |     </ClCompile> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <None Include="suppress_warning.ruleset" /> |     <None Include="suppress_warning.ruleset" /> | ||||||
|  |  | ||||||
|  | @ -20,17 +20,24 @@ | ||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| #include <string> | #include <string> | ||||||
|  | #include <type_traits> | ||||||
| 
 | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
|  | /// \~chinese
 | ||||||
|  | /// @brief »ù´¡×Ö·û´®ÈÝÆ÷
 | ||||||
|  | template <typename CharTy> | ||||||
|  | using BasicString = std::basic_string<CharTy>; | ||||||
|  | 
 | ||||||
| /// \~chinese
 | /// \~chinese
 | ||||||
| /// @brief 字符串容器
 | /// @brief 字符串容器
 | ||||||
| using String = std::string; | using String = BasicString<char>; | ||||||
| 
 | 
 | ||||||
| /// \~chinese
 | /// \~chinese
 | ||||||
| /// @brief 宽字符串容器
 | /// @brief 宽字符串容器
 | ||||||
| using WideString = std::wstring; | using WideString = BasicString<wchar_t>; | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| namespace strings | namespace strings | ||||||
| { | { | ||||||
|  | @ -53,4 +60,351 @@ WideString NarrowToWide(const String& str); | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | /// \~chinese
 | ||||||
|  | /// @brief »ù´¡³£×Ö·û´®ÊÓͼ
 | ||||||
|  | template <typename CharTy> | ||||||
|  | class BasicStringView | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     using value_type = CharTy; | ||||||
|  |     using pointer = CharTy*; | ||||||
|  |     using const_pointer = const CharTy*; | ||||||
|  |     using reference = CharTy&; | ||||||
|  |     using const_reference = const CharTy&; | ||||||
|  |     using traits_type = std::char_traits<CharTy>; | ||||||
|  |     using size_type = std::size_t; | ||||||
|  |     using string_type = BasicString<CharTy>; | ||||||
|  | 
 | ||||||
|  |     BasicStringView() | ||||||
|  |         : ptr_(nullptr) | ||||||
|  |         , count_(0) | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     BasicStringView(const_pointer c_str) | ||||||
|  |     { | ||||||
|  |         ptr_ = c_str; | ||||||
|  |         if (c_str) | ||||||
|  |         { | ||||||
|  |             count_ = traits_type::length(c_str); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             count_ = 0; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     BasicStringView(const_pointer c_str, size_type count) | ||||||
|  |     { | ||||||
|  |         ptr_ = c_str; | ||||||
|  |         if (c_str) | ||||||
|  |         { | ||||||
|  |             count_ = count; | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             count_ = 0; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     BasicStringView(const string_type& str) | ||||||
|  |         : ptr_(str.c_str()) | ||||||
|  |         , count_(str.length()) | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     BasicStringView(const BasicStringView& rhs) | ||||||
|  |         : ptr_(rhs.ptr_) | ||||||
|  |         , count_(rhs.count_) | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline const value_type* Data() const | ||||||
|  |     { | ||||||
|  |         return ptr_; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline bool IsEmpty() const | ||||||
|  |     { | ||||||
|  |         return !ptr_ || !count_; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline size_type Find(value_type ch) const | ||||||
|  |     { | ||||||
|  |         const auto ptr = traits_type::find(ptr_, count_, ch); | ||||||
|  |         if (ptr) | ||||||
|  |         { | ||||||
|  |             return ptr - ptr_; | ||||||
|  |         } | ||||||
|  |         return string_type::npos; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline BasicStringView SubStr(size_type pos, size_type count = string_type::npos) const | ||||||
|  |     { | ||||||
|  |         if (pos >= count_) | ||||||
|  |             return BasicStringView(); | ||||||
|  | 
 | ||||||
|  |         if (count == string_type::npos) | ||||||
|  |             return BasicStringView(ptr_ + pos, count_ - pos); | ||||||
|  | 
 | ||||||
|  |         KGE_ASSERT(pos + count <= count_); | ||||||
|  |         return BasicStringView(ptr_ + pos, count); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline size_type GetLength() const | ||||||
|  |     { | ||||||
|  |         return count_; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline value_type At(size_type index) const | ||||||
|  |     { | ||||||
|  |         return operator[](index); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline value_type operator[](size_type index) const | ||||||
|  |     { | ||||||
|  |         if (IsEmpty() || index >= count_) | ||||||
|  |             throw std::out_of_range("operator[] out of index"); | ||||||
|  |         return ptr_[index]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline operator string_type() const | ||||||
|  |     { | ||||||
|  |         return string_type(ptr_, count_); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline BasicStringView& operator=(const BasicStringView& rhs) | ||||||
|  |     { | ||||||
|  |         ptr_ = rhs.ptr_; | ||||||
|  |         count_ = rhs.count_; | ||||||
|  |         return *this; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  |     //
 | ||||||
|  |     // Iterators for BasicStringView
 | ||||||
|  |     //
 | ||||||
|  |     class Iterator | ||||||
|  |     { | ||||||
|  |         const value_type* ptr_; | ||||||
|  |         size_type         pos_; | ||||||
|  |         size_type         count_; | ||||||
|  | 
 | ||||||
|  |     public: | ||||||
|  |         using iterator_category = std::random_access_iterator_tag; | ||||||
|  |         using value_type        = value_type; | ||||||
|  |         using pointer           = value_type*; | ||||||
|  |         using reference         = value_type&; | ||||||
|  |         using difference_type   = ptrdiff_t; | ||||||
|  | 
 | ||||||
|  |         inline Iterator(pointer ptr, size_type pos, size_type count) | ||||||
|  |             : ptr_(ptr) | ||||||
|  |             , pos_(pos) | ||||||
|  |             , count_(count) | ||||||
|  |         { | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         inline Iterator(const Iterator& rhs) | ||||||
|  |             : ptr_(rhs.ptr_) | ||||||
|  |             , pos_(rhs.pos_) | ||||||
|  |             , count_(rhs.count_) | ||||||
|  |         { | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         inline Iterator& operator=(const Iterator& rhs) | ||||||
|  |         { | ||||||
|  |             ptr_ = rhs.ptr_; | ||||||
|  |             pos_ = rhs.pos_; | ||||||
|  |             count_ = rhs.count_; | ||||||
|  |             return *this; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         inline const value_type& operator*() const | ||||||
|  |         { | ||||||
|  |             KGE_ASSERT(pos_ < count_); | ||||||
|  |             return ptr_[pos_]; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         inline const value_type* operator->() const | ||||||
|  |         { | ||||||
|  |             return std::pointer_traits<pointer>::pointer_to(**this); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         inline Iterator& operator+=(size_type count) | ||||||
|  |         { | ||||||
|  |             KGE_ASSERT(pos_ + count >= 0 && pos_ + count <= count_); | ||||||
|  |             pos_ += count; | ||||||
|  |             return (*this); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         inline Iterator& operator-=(size_type count) | ||||||
|  |         { | ||||||
|  |             KGE_ASSERT(pos_ - count >= 0 && pos_ - count <= count_); | ||||||
|  |             pos_ -= count; | ||||||
|  |             return (*this); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         inline const Iterator operator+(size_type count) const | ||||||
|  |         { | ||||||
|  |             Iterator iter(*this); | ||||||
|  |             iter += count; | ||||||
|  |             return iter; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         inline const Iterator& operator-(size_type count) const | ||||||
|  |         { | ||||||
|  |             Iterator iter(*this); | ||||||
|  |             iter -= count; | ||||||
|  |             return iter; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         inline Iterator& operator++() | ||||||
|  |         { | ||||||
|  |             KGE_ASSERT(pos_ < count_); | ||||||
|  |             ++pos_; | ||||||
|  |             return (*this); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         inline Iterator operator++(int) | ||||||
|  |         { | ||||||
|  |             Iterator old = (*this); | ||||||
|  |             ++(*this); | ||||||
|  |             return old; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         inline Iterator& operator--() | ||||||
|  |         { | ||||||
|  |             KGE_ASSERT(pos_ > 0); | ||||||
|  |             --pos_; | ||||||
|  |             return (*this); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         inline Iterator operator--(int) | ||||||
|  |         { | ||||||
|  |             Iterator old = (*this); | ||||||
|  |             --(*this); | ||||||
|  |             return old; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         inline const value_type& operator[](size_type index) const | ||||||
|  |         { | ||||||
|  |             Iterator iter = (*this + index); | ||||||
|  |             return iter.ptr_[iter.pos_]; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         inline difference_type operator-(const Iterator& other) const | ||||||
|  |         { | ||||||
|  |             KGE_ASSERT(ptr_ == other.ptr_ && count_ == other.count_); | ||||||
|  |             return static_cast<difference_type>(pos_ - other.pos_); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         inline bool operator==(const Iterator& other) const | ||||||
|  |         { | ||||||
|  |             return ptr_ == other.ptr_ && pos_ == other.pos_ && count_ == other.count_; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         inline bool operator!=(const Iterator& other) const | ||||||
|  |         { | ||||||
|  |             return !(*this == other); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         inline bool operator<(const Iterator& other) const | ||||||
|  |         { | ||||||
|  |             return ptr_ < other.ptr_ || pos_ < other.pos_ || count_ < other.count_; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         inline bool operator<=(const Iterator& other) const | ||||||
|  |         { | ||||||
|  |             return (*this < other) || (*this == other); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         inline bool operator>(const Iterator& other) const | ||||||
|  |         { | ||||||
|  |             return !(*this <= other); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         inline bool operator>=(const Iterator& other) const | ||||||
|  |         { | ||||||
|  |             return !(*this < other); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         inline operator bool() const | ||||||
|  |         { | ||||||
|  |             return ptr_ != nullptr && pos_ != count_; | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     using const_iterator         = Iterator; | ||||||
|  |     using iterator               = const_iterator; | ||||||
|  |     using const_reverse_iterator = std::reverse_iterator<const_iterator>; | ||||||
|  |     using reverse_iterator       = const_reverse_iterator; | ||||||
|  | 
 | ||||||
|  |     inline const_iterator begin() const | ||||||
|  |     { | ||||||
|  |         return const_iterator(ptr_, 0, count_); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline const_iterator cbegin() const | ||||||
|  |     { | ||||||
|  |         return begin(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline const_iterator end() const | ||||||
|  |     { | ||||||
|  |         return const_iterator(ptr_, count_, count_); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline const_iterator cend() const | ||||||
|  |     { | ||||||
|  |         return end(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline const_reverse_iterator rbegin() const | ||||||
|  |     { | ||||||
|  |         return const_reverse_iterator(end()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline const_reverse_iterator crbegin() const | ||||||
|  |     { | ||||||
|  |         return rbegin(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline const_reverse_iterator rend() const | ||||||
|  |     { | ||||||
|  |         return const_reverse_iterator(begin()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline const_reverse_iterator crend() const | ||||||
|  |     { | ||||||
|  |         return rend(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline const value_type& front() const | ||||||
|  |     { | ||||||
|  |         if (IsEmpty()) | ||||||
|  |             throw std::out_of_range("front() called on empty list"); | ||||||
|  |         return ptr_[0]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline const value_type& back() const | ||||||
|  |     { | ||||||
|  |         if (IsEmpty()) | ||||||
|  |             throw std::out_of_range("back() called on empty list"); | ||||||
|  |         return ptr_[count_]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     const value_type* ptr_; | ||||||
|  |     size_type         count_; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /// \~chinese
 | ||||||
|  | /// @brief ×Ö·û´®ÊÓͼ
 | ||||||
|  | using StringView = BasicStringView<char>; | ||||||
|  | 
 | ||||||
|  | /// \~chinese
 | ||||||
|  | /// @brief ¿í×Ö·û´®ÊÓͼ
 | ||||||
|  | using WideStringView = BasicStringView<wchar_t>; | ||||||
|  | 
 | ||||||
| }  // namespace kiwano
 | }  // namespace kiwano
 | ||||||
|  |  | ||||||
|  | @ -263,17 +263,17 @@ inline void Duration::SetMilliseconds(int64_t ms) | ||||||
| 
 | 
 | ||||||
| inline void Duration::SetSeconds(float seconds) | inline void Duration::SetSeconds(float seconds) | ||||||
| { | { | ||||||
|     milliseconds_ = static_cast<long>(seconds * 1000.f); |     milliseconds_ = static_cast<int64_t>(seconds * 1000.f); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| inline void Duration::SetMinutes(float minutes) | inline void Duration::SetMinutes(float minutes) | ||||||
| { | { | ||||||
|     milliseconds_ = static_cast<long>(minutes * 60 * 1000.f); |     milliseconds_ = static_cast<int64_t>(minutes * 60 * 1000.f); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| inline void Duration::SetHours(float hours) | inline void Duration::SetHours(float hours) | ||||||
| { | { | ||||||
|     milliseconds_ = static_cast<long>(hours * 60 * 60 * 1000.f); |     milliseconds_ = static_cast<int64_t>(hours * 60 * 60 * 1000.f); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| inline bool Time::IsZero() const | inline bool Time::IsZero() const | ||||||
|  |  | ||||||
|  | @ -127,7 +127,6 @@ | ||||||
| //
 | //
 | ||||||
| 
 | 
 | ||||||
| #include <kiwano/utils/Logger.h> | #include <kiwano/utils/Logger.h> | ||||||
| #include <kiwano/utils/LocalStorage.h> |  | ||||||
| #include <kiwano/utils/ResourceCache.h> | #include <kiwano/utils/ResourceCache.h> | ||||||
| #include <kiwano/utils/UserData.h> | #include <kiwano/utils/UserData.h> | ||||||
| #include <kiwano/utils/Timer.h> | #include <kiwano/utils/Timer.h> | ||||||
|  | @ -135,3 +134,4 @@ | ||||||
| #include <kiwano/utils/EventTicker.h> | #include <kiwano/utils/EventTicker.h> | ||||||
| #include <kiwano/utils/Task.h> | #include <kiwano/utils/Task.h> | ||||||
| #include <kiwano/utils/TaskScheduler.h> | #include <kiwano/utils/TaskScheduler.h> | ||||||
|  | #include <kiwano/utils/ConfigIni.h> | ||||||
|  |  | ||||||
|  | @ -42,9 +42,6 @@ Application::Application() | ||||||
|     Use(Renderer::GetInstance()); |     Use(Renderer::GetInstance()); | ||||||
|     Use(Input::GetInstance()); |     Use(Input::GetInstance()); | ||||||
|     Use(Director::GetInstance()); |     Use(Director::GetInstance()); | ||||||
| 
 |  | ||||||
|     ticker_ = Ticker::Create(0); |  | ||||||
|     ticker_->Tick(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Application::~Application() | Application::~Application() | ||||||
|  | @ -76,11 +73,27 @@ void Application::Run(RunnerPtr runner, bool debug) | ||||||
| 
 | 
 | ||||||
|     while (running_) |     while (running_) | ||||||
|     { |     { | ||||||
|         if (ticker_->Tick()) |         if (!frame_ticker_) | ||||||
|         { |         { | ||||||
|             if (!runner->MainLoop(ticker_->GetDeltaTime())) |             frame_ticker_ = Ticker::Create(0); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (frame_ticker_->Tick()) | ||||||
|  |         { | ||||||
|  |             // Execute main loop
 | ||||||
|  |             if (!runner->MainLoop(frame_ticker_->GetDeltaTime())) | ||||||
|                 running_ = false; |                 running_ = false; | ||||||
|         } |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             // Releases CPU
 | ||||||
|  |             Duration total_dt = frame_ticker_->GetDeltaTime() + frame_ticker_->GetErrorTime(); | ||||||
|  |             Duration sleep_dt = frame_ticker_->GetInterval() - total_dt; | ||||||
|  |             if (sleep_dt.Milliseconds() > 1LL) | ||||||
|  |             { | ||||||
|  |                 sleep_dt.Sleep(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     this->Destroy(); |     this->Destroy(); | ||||||
|  | @ -89,19 +102,17 @@ void Application::Run(RunnerPtr runner, bool debug) | ||||||
| void Application::Pause() | void Application::Pause() | ||||||
| { | { | ||||||
|     is_paused_ = true; |     is_paused_ = true; | ||||||
|     if (ticker_) | 
 | ||||||
|     { |     if (frame_ticker_) | ||||||
|         ticker_->Pause(); |         frame_ticker_->Pause(); | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Application::Resume() | void Application::Resume() | ||||||
| { | { | ||||||
|     is_paused_ = false; |     is_paused_ = false; | ||||||
|     if (ticker_) | 
 | ||||||
|     { |     if (frame_ticker_) | ||||||
|         ticker_->Resume(); |         frame_ticker_->Resume(); | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Application::Quit() | void Application::Quit() | ||||||
|  |  | ||||||
|  | @ -78,6 +78,19 @@ public: | ||||||
|      */ |      */ | ||||||
|     void Quit(); |     void Quit(); | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |      * \~chinese | ||||||
|  |      * @brief 获取暂停状态 | ||||||
|  |      */ | ||||||
|  |     bool IsPaused() const; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * \~chinese | ||||||
|  |      * @brief 添加模块 | ||||||
|  |      * @param[in] module 模块 | ||||||
|  |      */ | ||||||
|  |     void Use(Module& module); | ||||||
|  | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * \~chinese |      * \~chinese | ||||||
|      * @brief 获取程序运行器 |      * @brief 获取程序运行器 | ||||||
|  | @ -92,22 +105,15 @@ public: | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * \~chinese |      * \~chinese | ||||||
|      * @brief 获取报时器 |      * @brief 获取帧报时器 | ||||||
|      */ |      */ | ||||||
|     TickerPtr GetTicker() const; |     TickerPtr GetFrameTicker() const; | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * \~chinese |      * \~chinese | ||||||
|      * @brief 获取暂停状态 |      * @brief 设置帧报时器 | ||||||
|      */ |      */ | ||||||
|     bool IsPaused() const; |     void SetFrameTicker(TickerPtr ticker); | ||||||
| 
 |  | ||||||
|     /**
 |  | ||||||
|      * \~chinese |  | ||||||
|      * @brief 添加模块 |  | ||||||
|      * @param[in] module 模块 |  | ||||||
|      */ |  | ||||||
|     void Use(Module& module); |  | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * \~chinese |      * \~chinese | ||||||
|  | @ -166,7 +172,7 @@ private: | ||||||
|     bool                    is_paused_; |     bool                    is_paused_; | ||||||
|     float                   time_scale_; |     float                   time_scale_; | ||||||
|     RunnerPtr               runner_; |     RunnerPtr               runner_; | ||||||
|     TickerPtr               ticker_; |     TickerPtr               frame_ticker_; | ||||||
|     List<Module*>           modules_; |     List<Module*>           modules_; | ||||||
|     std::mutex              perform_mutex_; |     std::mutex              perform_mutex_; | ||||||
|     Queue<Function<void()>> functions_to_perform_; |     Queue<Function<void()>> functions_to_perform_; | ||||||
|  | @ -183,9 +189,14 @@ inline WindowPtr Application::GetMainWindow() const | ||||||
|     return runner_->GetMainWindow(); |     return runner_->GetMainWindow(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| inline TickerPtr Application::GetTicker() const | inline TickerPtr Application::GetFrameTicker() const | ||||||
| { | { | ||||||
|     return ticker_; |     return frame_ticker_; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline void Application::SetFrameTicker(TickerPtr ticker) | ||||||
|  | { | ||||||
|  |     frame_ticker_ = ticker; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| inline bool Application::IsPaused() const | inline bool Application::IsPaused() const | ||||||
|  |  | ||||||
|  | @ -34,6 +34,8 @@ | ||||||
| #include <Windowsx.h>  // GET_X_LPARAM, GET_Y_LPARAM
 | #include <Windowsx.h>  // GET_X_LPARAM, GET_Y_LPARAM
 | ||||||
| #include <imm.h>       // ImmAssociateContext
 | #include <imm.h>       // ImmAssociateContext
 | ||||||
| #pragma comment(lib, "imm32.lib") | #pragma comment(lib, "imm32.lib") | ||||||
|  | #include <timeapi.h>  // timeBeginPeriod, timeEndPeriod
 | ||||||
|  | #pragma comment(lib, "winmm.lib") | ||||||
| 
 | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
| { | { | ||||||
|  | @ -185,6 +187,8 @@ WindowWin32Impl::WindowWin32Impl() | ||||||
|     // F1 - F12
 |     // F1 - F12
 | ||||||
|     for (size_t i = 0; i < 12; ++i) |     for (size_t i = 0; i < 12; ++i) | ||||||
|         key_map_[VK_F1 + i] = KeyCode(size_t(KeyCode::F1) + i); |         key_map_[VK_F1 + i] = KeyCode(size_t(KeyCode::F1) + i); | ||||||
|  | 
 | ||||||
|  |     ::timeBeginPeriod(0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| WindowWin32Impl::~WindowWin32Impl() | WindowWin32Impl::~WindowWin32Impl() | ||||||
|  | @ -194,6 +198,8 @@ WindowWin32Impl::~WindowWin32Impl() | ||||||
|         ::DestroyWindow(handle_); |         ::DestroyWindow(handle_); | ||||||
|         handle_ = nullptr; |         handle_ = nullptr; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     ::timeEndPeriod(0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable) | void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable) | ||||||
|  |  | ||||||
|  | @ -0,0 +1,372 @@ | ||||||
|  | // Copyright (c) 2016-2018 Kiwano - Nomango
 | ||||||
|  | //
 | ||||||
|  | // Permission is hereby granted, free of charge, to any person obtaining a copy
 | ||||||
|  | // of this software and associated documentation files (the "Software"), to deal
 | ||||||
|  | // in the Software without restriction, including without limitation the rights
 | ||||||
|  | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | ||||||
|  | // copies of the Software, and to permit persons to whom the Software is
 | ||||||
|  | // furnished to do so, subject to the following conditions:
 | ||||||
|  | //
 | ||||||
|  | // The above copyright notice and this permission notice shall be included in
 | ||||||
|  | // all copies or substantial portions of the Software.
 | ||||||
|  | //
 | ||||||
|  | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | ||||||
|  | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | ||||||
|  | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | ||||||
|  | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | ||||||
|  | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | ||||||
|  | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | ||||||
|  | // THE SOFTWARE.
 | ||||||
|  | 
 | ||||||
|  | #include <kiwano/utils/ConfigIni.h> | ||||||
|  | #include <kiwano/core/Exception.h> | ||||||
|  | #include <fstream>  // std::ifstream, std::ofstream
 | ||||||
|  | #include <algorithm>  // std::sort, std::for_each
 | ||||||
|  | #include <cctype>  // std::isspace
 | ||||||
|  | 
 | ||||||
|  | #define KGE_DEFAULT_INI_SECTION_NAME "default" | ||||||
|  | 
 | ||||||
|  | namespace kiwano | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | StringView Trim(StringView str) | ||||||
|  | { | ||||||
|  |     if (!str.IsEmpty()) | ||||||
|  |     { | ||||||
|  |         std::size_t start = 0, end = str.GetLength(); | ||||||
|  |         while (std::isspace(str[start])) | ||||||
|  |             ++start; | ||||||
|  |         while (std::isspace(str[end - 1])) | ||||||
|  |             --end; | ||||||
|  | 
 | ||||||
|  |         if (end - start) | ||||||
|  |             return StringView(str.Data() + start, end - start); | ||||||
|  |     } | ||||||
|  |     return StringView(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class IniParser | ||||||
|  | { | ||||||
|  |     StringView line_; | ||||||
|  | public: | ||||||
|  |     IniParser(StringView line) | ||||||
|  |         : line_(line) | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool ClearComment() | ||||||
|  |     { | ||||||
|  |         auto pos = line_.Find(';'); | ||||||
|  |         if (pos != String::npos) | ||||||
|  |         { | ||||||
|  |             if (pos == 0) | ||||||
|  |                 return true; | ||||||
|  | 
 | ||||||
|  |             if (std::isspace(line_[pos - 1])) | ||||||
|  |             { | ||||||
|  |                 line_ = Trim(line_.SubStr(0, pos - 1)); | ||||||
|  |                 return line_.IsEmpty(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool IsSection() const | ||||||
|  |     { | ||||||
|  |         return line_[0] == '[' && line_.GetLength() > 2 && line_[line_.GetLength() - 1] == ']'; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     StringView GetSectionName() const | ||||||
|  |     { | ||||||
|  |         return Trim(line_.SubStr(1, line_.GetLength() - 2)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool GetKeyValue(StringView* key, StringView* value) | ||||||
|  |     { | ||||||
|  |         auto pos = line_.Find('='); | ||||||
|  |         if (pos == String::npos) | ||||||
|  |             return false; | ||||||
|  | 
 | ||||||
|  |         *key = Trim(line_.SubStr(0, pos)); | ||||||
|  |         *value = Trim(line_.SubStr(pos + 1)); | ||||||
|  | 
 | ||||||
|  |         return !(*key).IsEmpty() && !(*value).IsEmpty(); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | ConfigIniPtr ConfigIni::Create(const String& file_path) | ||||||
|  | { | ||||||
|  |     ConfigIniPtr ptr = memory::New<ConfigIni>(); | ||||||
|  |     if (ptr) | ||||||
|  |     { | ||||||
|  |         if (!ptr->Load(file_path)) | ||||||
|  |         { | ||||||
|  |             return nullptr; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return ptr; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool ConfigIni::Load(const String& file_path) | ||||||
|  | { | ||||||
|  |     std::ifstream ifs(file_path); | ||||||
|  | 
 | ||||||
|  |     if (ifs.is_open()) | ||||||
|  |     { | ||||||
|  |         return Load(ifs); | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool ConfigIni::Load(std::istream& istream) | ||||||
|  | { | ||||||
|  |     try | ||||||
|  |     { | ||||||
|  |         String section = KGE_DEFAULT_INI_SECTION_NAME; | ||||||
|  |         for (String line; std::getline(istream, line);) | ||||||
|  |         { | ||||||
|  |             ParseLine(line, §ion); | ||||||
|  |         } | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |     catch (Exception) | ||||||
|  |     { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool ConfigIni::Save(const String& file_path) | ||||||
|  | { | ||||||
|  |     std::ofstream ofs(file_path); | ||||||
|  | 
 | ||||||
|  |     if (ofs.is_open()) | ||||||
|  |     { | ||||||
|  |         return Save(ofs); | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool ConfigIni::Save(std::ostream& os) | ||||||
|  | { | ||||||
|  |     // Get all keys
 | ||||||
|  |     Vector<String> keys; | ||||||
|  |     keys.reserve(sections_.size()); | ||||||
|  |     std::for_each(sections_.begin(), sections_.end(), [&](SectionMap::value_type& pair) { keys.push_back(pair.first); }); | ||||||
|  | 
 | ||||||
|  |     // Sort for keys
 | ||||||
|  |     std::sort(keys.begin(), keys.end()); | ||||||
|  | 
 | ||||||
|  |     // Output to ini
 | ||||||
|  |     for (const auto& key : keys) | ||||||
|  |     { | ||||||
|  |         os << '[' << key << ']' << std::endl; | ||||||
|  |         for (const auto& pair : sections_[key]) | ||||||
|  |         { | ||||||
|  |             os << pair.first << " = " << pair.second << std::endl; | ||||||
|  |         } | ||||||
|  |         os << std::endl; | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ConfigIni::SectionMap ConfigIni::GetSectionMap() const | ||||||
|  | { | ||||||
|  |     return sections_; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ConfigIni::ValueMap ConfigIni::GetSection(const String& section) const | ||||||
|  | { | ||||||
|  |     auto iter = sections_.find(section); | ||||||
|  |     if (iter != sections_.end()) | ||||||
|  |         return iter->second; | ||||||
|  |     return ValueMap(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | String ConfigIni::GetString(const String& section_name, const String& key) const | ||||||
|  | { | ||||||
|  |     if (HasSection(section_name)) | ||||||
|  |     { | ||||||
|  |         const auto& section = sections_.at(section_name); | ||||||
|  | 
 | ||||||
|  |         auto iter_key = section.find(key); | ||||||
|  |         if (iter_key != section.end()) | ||||||
|  |             return iter_key->second; | ||||||
|  |     } | ||||||
|  |     return String(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | float ConfigIni::GetFloat(const String& section, const String& key, float default_value) const | ||||||
|  | { | ||||||
|  |     String str = GetString(section, key); | ||||||
|  |     if (str.empty()) | ||||||
|  |         return default_value; | ||||||
|  | 
 | ||||||
|  |     try | ||||||
|  |     { | ||||||
|  |         std::size_t pos   = 0; | ||||||
|  |         float       value = std::stof(str, &pos); | ||||||
|  |         if (pos == str.size()) | ||||||
|  |             return value; | ||||||
|  |     } | ||||||
|  |     catch (std::invalid_argument) | ||||||
|  |     { | ||||||
|  |         return default_value; | ||||||
|  |     } | ||||||
|  |     return default_value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | double ConfigIni::GetDouble(const String& section, const String& key, double default_value) const | ||||||
|  | { | ||||||
|  |     String str = GetString(section, key); | ||||||
|  |     if (str.empty()) | ||||||
|  |         return default_value; | ||||||
|  | 
 | ||||||
|  |     try | ||||||
|  |     { | ||||||
|  |         std::size_t pos   = 0; | ||||||
|  |         double      value = std::stod(str, &pos); | ||||||
|  |         if (pos == str.size()) | ||||||
|  |             return value; | ||||||
|  |     } | ||||||
|  |     catch (std::invalid_argument) | ||||||
|  |     { | ||||||
|  |         return default_value; | ||||||
|  |     } | ||||||
|  |     return default_value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int ConfigIni::GetInt(const String& section, const String& key, int default_value) const | ||||||
|  | { | ||||||
|  |     String str = GetString(section, key); | ||||||
|  |     if (str.empty()) | ||||||
|  |         return default_value; | ||||||
|  | 
 | ||||||
|  |     try | ||||||
|  |     { | ||||||
|  |         std::size_t pos   = 0; | ||||||
|  |         int         value = std::stoi(str, &pos); | ||||||
|  |         if (pos == str.size()) | ||||||
|  |             return value; | ||||||
|  |     } | ||||||
|  |     catch (std::invalid_argument) | ||||||
|  |     { | ||||||
|  |         return default_value; | ||||||
|  |     } | ||||||
|  |     return default_value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool ConfigIni::GetBool(const String& section, const String& key, bool default_value) const | ||||||
|  | { | ||||||
|  |     String str = GetString(section, key); | ||||||
|  |     if (!str.empty()) | ||||||
|  |     { | ||||||
|  |         if (str == "true" || str == "1") | ||||||
|  |             return true; | ||||||
|  |         else if (str == "false" || str == "0") | ||||||
|  |             return false; | ||||||
|  |     } | ||||||
|  |     return default_value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool ConfigIni::HasSection(const String& section) const | ||||||
|  | { | ||||||
|  |     return !!sections_.count(section); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool ConfigIni::HasValue(const String& section, const String& key) const | ||||||
|  | { | ||||||
|  |     if (HasSection(section)) | ||||||
|  |     { | ||||||
|  |         return !!sections_.at(section).count(section); | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ConfigIni::SetSectionMap(const SectionMap& sections) | ||||||
|  | { | ||||||
|  |     sections_ = sections; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ConfigIni::SetSection(const String& section, const ValueMap& values) | ||||||
|  | { | ||||||
|  |     sections_.insert(std::make_pair(section, values)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ConfigIni::SetString(const String& section, const String& key, const String& value) | ||||||
|  | { | ||||||
|  |     if (HasSection(section)) | ||||||
|  |         sections_[section].insert(std::make_pair(key, value)); | ||||||
|  |     else | ||||||
|  |         SetSection(section, ValueMap{ { key, value } }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ConfigIni::SetFloat(const String& section, const String& key, float value) | ||||||
|  | { | ||||||
|  |     String str = std::to_string(value); | ||||||
|  |     SetString(section, key, str); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ConfigIni::SetDouble(const String& section, const String& key, double value) | ||||||
|  | { | ||||||
|  |     String str = std::to_string(value); | ||||||
|  |     SetString(section, key, str); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ConfigIni::SetInt(const String& section, const String& key, int value) | ||||||
|  | { | ||||||
|  |     String str = std::to_string(value); | ||||||
|  |     SetString(section, key, str); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ConfigIni::SetBool(const String& section, const String& key, bool value) | ||||||
|  | { | ||||||
|  |     SetString(section, key, value ? "true" : "false"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ConfigIni::ValueMap& ConfigIni::operator[](const String& section) | ||||||
|  | { | ||||||
|  |     if (!HasSection(section)) | ||||||
|  |     { | ||||||
|  |         sections_.insert(std::make_pair(section, ValueMap())); | ||||||
|  |     } | ||||||
|  |     return sections_[section]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const ConfigIni::ValueMap& ConfigIni::operator[](const String& section) const | ||||||
|  | { | ||||||
|  |     if (!HasSection(section)) | ||||||
|  |     { | ||||||
|  |         const_cast<SectionMap&>(sections_).insert(std::make_pair(section, ValueMap())); | ||||||
|  |     } | ||||||
|  |     return sections_.at(section); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ConfigIni::ParseLine(StringView line, String* section) | ||||||
|  | { | ||||||
|  |     line = Trim(line); | ||||||
|  |     if (line.IsEmpty()) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |     IniParser parser(line); | ||||||
|  |     if (parser.ClearComment()) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |     if (parser.IsSection()) | ||||||
|  |     { | ||||||
|  |         auto name = parser.GetSectionName(); | ||||||
|  |         if (name.IsEmpty()) | ||||||
|  |             throw Exception("Empty section name"); | ||||||
|  |         *section = name; | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     StringView key, value; | ||||||
|  |     if (!parser.GetKeyValue(&key, &value)) | ||||||
|  |     { | ||||||
|  |         throw Exception("Parse key-value failed"); | ||||||
|  |     } | ||||||
|  |     SetString(*section, key, value); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | }  // namespace kiwano
 | ||||||
|  | @ -0,0 +1,179 @@ | ||||||
|  | // Copyright (c) 2016-2018 Kiwano - Nomango
 | ||||||
|  | //
 | ||||||
|  | // Permission is hereby granted, free of charge, to any person obtaining a copy
 | ||||||
|  | // of this software and associated documentation files (the "Software"), to deal
 | ||||||
|  | // in the Software without restriction, including without limitation the rights
 | ||||||
|  | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | ||||||
|  | // copies of the Software, and to permit persons to whom the Software is
 | ||||||
|  | // furnished to do so, subject to the following conditions:
 | ||||||
|  | //
 | ||||||
|  | // The above copyright notice and this permission notice shall be included in
 | ||||||
|  | // all copies or substantial portions of the Software.
 | ||||||
|  | //
 | ||||||
|  | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | ||||||
|  | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | ||||||
|  | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | ||||||
|  | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | ||||||
|  | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | ||||||
|  | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | ||||||
|  | // THE SOFTWARE.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | #include <kiwano/core/Common.h> | ||||||
|  | #include <kiwano/base/ObjectBase.h> | ||||||
|  | 
 | ||||||
|  | namespace kiwano | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | KGE_DECLARE_SMART_PTR(ConfigIni); | ||||||
|  | 
 | ||||||
|  | /// \~chinese
 | ||||||
|  | /// @brief ini格式文件
 | ||||||
|  | class KGE_API ConfigIni : public ObjectBase | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 加载 ini 文件
 | ||||||
|  |     /// @param file_path 文件路径
 | ||||||
|  |     static ConfigIniPtr Create(const String& file_path); | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 键值字典
 | ||||||
|  |     typedef Map<String, String> ValueMap; | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief Section字典
 | ||||||
|  |     typedef UnorderedMap<String, ValueMap> SectionMap; | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 加载 ini 文件
 | ||||||
|  |     /// @param file_path 文件路径
 | ||||||
|  |     bool Load(const String& file_path); | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 加载 ini 文件
 | ||||||
|  |     /// @param is 输入流
 | ||||||
|  |     bool Load(std::istream& is); | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 保存至 ini 文件
 | ||||||
|  |     /// @param file_path 文件路径
 | ||||||
|  |     bool Save(const String& file_path); | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 保存至 ini 文件
 | ||||||
|  |     /// @param os 输出流
 | ||||||
|  |     bool Save(std::ostream& os); | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 获取所有section
 | ||||||
|  |     SectionMap GetSectionMap() const; | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 获取section
 | ||||||
|  |     /// @param section section的名称
 | ||||||
|  |     ValueMap GetSection(const String& section) const; | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 获取值
 | ||||||
|  |     /// @param section section的名称
 | ||||||
|  |     /// @param key key的名称
 | ||||||
|  |     String GetString(const String& section, const String& key) const; | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 获取值
 | ||||||
|  |     /// @param section section的名称
 | ||||||
|  |     /// @param key key的名称
 | ||||||
|  |     /// @param default_value 不存在时的默认值
 | ||||||
|  |     float GetFloat(const String& section, const String& key, float default_value = 0.0f) const; | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 获取值
 | ||||||
|  |     /// @param section section的名称
 | ||||||
|  |     /// @param key key的名称
 | ||||||
|  |     /// @param default_value 不存在时的默认值
 | ||||||
|  |     double GetDouble(const String& section, const String& key, double default_value = 0.0) const; | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 获取值
 | ||||||
|  |     /// @param section section的名称
 | ||||||
|  |     /// @param key key的名称
 | ||||||
|  |     /// @param default_value 不存在时的默认值
 | ||||||
|  |     int GetInt(const String& section, const String& key, int default_value = 0) const; | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 获取值
 | ||||||
|  |     /// @param section section的名称
 | ||||||
|  |     /// @param key key的名称
 | ||||||
|  |     /// @param default_value 不存在时的默认值
 | ||||||
|  |     bool GetBool(const String& section, const String& key, bool default_value = false) const; | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 是否存在section
 | ||||||
|  |     /// @param section section的名称
 | ||||||
|  |     bool HasSection(const String& section) const; | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 是否存在值
 | ||||||
|  |     /// @param section section的名称
 | ||||||
|  |     /// @param key key的名称
 | ||||||
|  |     bool HasValue(const String& section, const String& key) const; | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 设置所有section
 | ||||||
|  |     /// @param sections section字典
 | ||||||
|  |     void SetSectionMap(const SectionMap& sections); | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 设置section
 | ||||||
|  |     /// @param section section的名称
 | ||||||
|  |     /// @param values 键值字典
 | ||||||
|  |     void SetSection(const String& section, const ValueMap& values); | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 设置值
 | ||||||
|  |     /// @param section section的名称
 | ||||||
|  |     /// @param key key的名称
 | ||||||
|  |     /// @param value 值
 | ||||||
|  |     void SetString(const String& section, const String& key, const String& value); | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 设置值
 | ||||||
|  |     /// @param section section的名称
 | ||||||
|  |     /// @param key key的名称
 | ||||||
|  |     /// @param value 值
 | ||||||
|  |     void SetFloat(const String& section, const String& key, float value); | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 设置值
 | ||||||
|  |     /// @param section section的名称
 | ||||||
|  |     /// @param key key的名称
 | ||||||
|  |     /// @param value 值
 | ||||||
|  |     void SetDouble(const String& section, const String& key, double value); | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 设置值
 | ||||||
|  |     /// @param section section的名称
 | ||||||
|  |     /// @param key key的名称
 | ||||||
|  |     /// @param value 值
 | ||||||
|  |     void SetInt(const String& section, const String& key, int value); | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 设置值
 | ||||||
|  |     /// @param section section的名称
 | ||||||
|  |     /// @param key key的名称
 | ||||||
|  |     /// @param value 值
 | ||||||
|  |     void SetBool(const String& section, const String& key, bool value); | ||||||
|  | 
 | ||||||
|  |     ValueMap& operator[](const String& section); | ||||||
|  | 
 | ||||||
|  |     const ValueMap& operator[](const String& section) const; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     void ParseLine(StringView line, String* section); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     SectionMap sections_; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | }  // namespace kiwano
 | ||||||
|  | @ -1,106 +0,0 @@ | ||||||
| // Copyright (c) 2016-2018 Kiwano - Nomango
 |  | ||||||
| //
 |  | ||||||
| // Permission is hereby granted, free of charge, to any person obtaining a copy
 |  | ||||||
| // of this software and associated documentation files (the "Software"), to deal
 |  | ||||||
| // in the Software without restriction, including without limitation the rights
 |  | ||||||
| // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 |  | ||||||
| // copies of the Software, and to permit persons to whom the Software is
 |  | ||||||
| // furnished to do so, subject to the following conditions:
 |  | ||||||
| //
 |  | ||||||
| // The above copyright notice and this permission notice shall be included in
 |  | ||||||
| // all copies or substantial portions of the Software.
 |  | ||||||
| //
 |  | ||||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 |  | ||||||
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 |  | ||||||
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 |  | ||||||
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 |  | ||||||
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 |  | ||||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 |  | ||||||
| // THE SOFTWARE.
 |  | ||||||
| 
 |  | ||||||
| #include <kiwano/utils/LocalStorage.h> |  | ||||||
| 
 |  | ||||||
| namespace kiwano |  | ||||||
| { |  | ||||||
| 
 |  | ||||||
| LocalStorage::LocalStorage(const String& file_path, const String& field) |  | ||||||
| { |  | ||||||
|     SetFilePath(file_path); |  | ||||||
|     SetFieldName(field); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool LocalStorage::Exists(const String& key) const |  | ||||||
| { |  | ||||||
|     char temp[256] = { 0 }; |  | ||||||
|     ::GetPrivateProfileStringA(field_name_.c_str(), key.c_str(), "", temp, 255, file_path_.c_str()); |  | ||||||
|     return temp[0] == '\0'; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool LocalStorage::SaveInt(const String& key, int val) const |  | ||||||
| { |  | ||||||
|     BOOL ret = |  | ||||||
|         ::WritePrivateProfileStringA(field_name_.c_str(), key.c_str(), std::to_string(val).c_str(), file_path_.c_str()); |  | ||||||
|     return ret == TRUE; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool LocalStorage::SaveFloat(const String& key, float val) const |  | ||||||
| { |  | ||||||
|     BOOL ret = |  | ||||||
|         ::WritePrivateProfileStringA(field_name_.c_str(), key.c_str(), std::to_string(val).c_str(), file_path_.c_str()); |  | ||||||
|     return ret == TRUE; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool LocalStorage::SaveDouble(const String& key, double val) const |  | ||||||
| { |  | ||||||
|     BOOL ret = |  | ||||||
|         ::WritePrivateProfileStringA(field_name_.c_str(), key.c_str(), std::to_string(val).c_str(), file_path_.c_str()); |  | ||||||
|     return ret == TRUE; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool LocalStorage::SaveBool(const String& key, bool val) const |  | ||||||
| { |  | ||||||
|     BOOL ret = ::WritePrivateProfileStringA(field_name_.c_str(), key.c_str(), (val ? "1" : "0"), file_path_.c_str()); |  | ||||||
|     return ret == TRUE; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool LocalStorage::SaveString(const String& key, const String& val) const |  | ||||||
| { |  | ||||||
|     BOOL ret = ::WritePrivateProfileStringA(field_name_.c_str(), key.c_str(), val.c_str(), file_path_.c_str()); |  | ||||||
|     return ret == TRUE; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int LocalStorage::GetInt(const String& key, int default_value) const |  | ||||||
| { |  | ||||||
|     return ::GetPrivateProfileIntA(field_name_.c_str(), key.c_str(), default_value, file_path_.c_str()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| float LocalStorage::GetFloat(const String& key, float default_value) const |  | ||||||
| { |  | ||||||
|     char   temp[32]    = { 0 }; |  | ||||||
|     String default_str = std::to_string(default_value); |  | ||||||
|     ::GetPrivateProfileStringA(field_name_.c_str(), key.c_str(), default_str.c_str(), temp, 31, file_path_.c_str()); |  | ||||||
|     return std::stof(temp); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| double LocalStorage::GetDouble(const String& key, double default_value) const |  | ||||||
| { |  | ||||||
|     char   temp[32]    = { 0 }; |  | ||||||
|     String default_str = std::to_string(default_value); |  | ||||||
|     ::GetPrivateProfileStringA(field_name_.c_str(), key.c_str(), default_str.c_str(), temp, 31, file_path_.c_str()); |  | ||||||
|     return std::stod(temp); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool LocalStorage::GetBool(const String& key, bool default_value) const |  | ||||||
| { |  | ||||||
|     int nValue = ::GetPrivateProfileIntA(field_name_.c_str(), key.c_str(), default_value ? 1 : 0, file_path_.c_str()); |  | ||||||
|     return nValue == TRUE; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| String LocalStorage::GetString(const String& key, const String& default_value) const |  | ||||||
| { |  | ||||||
|     char temp[256] = { 0 }; |  | ||||||
|     ::GetPrivateProfileStringA(field_name_.c_str(), key.c_str(), default_value.c_str(), temp, 255, file_path_.c_str()); |  | ||||||
|     return temp; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| }  // namespace kiwano
 |  | ||||||
|  | @ -1,163 +0,0 @@ | ||||||
| // Copyright (c) 2016-2018 Kiwano - Nomango
 |  | ||||||
| //
 |  | ||||||
| // Permission is hereby granted, free of charge, to any person obtaining a copy
 |  | ||||||
| // of this software and associated documentation files (the "Software"), to deal
 |  | ||||||
| // in the Software without restriction, including without limitation the rights
 |  | ||||||
| // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 |  | ||||||
| // copies of the Software, and to permit persons to whom the Software is
 |  | ||||||
| // furnished to do so, subject to the following conditions:
 |  | ||||||
| //
 |  | ||||||
| // The above copyright notice and this permission notice shall be included in
 |  | ||||||
| // all copies or substantial portions of the Software.
 |  | ||||||
| //
 |  | ||||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 |  | ||||||
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 |  | ||||||
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 |  | ||||||
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 |  | ||||||
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 |  | ||||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 |  | ||||||
| // THE SOFTWARE.
 |  | ||||||
| 
 |  | ||||||
| #pragma once |  | ||||||
| #include <kiwano/core/Common.h> |  | ||||||
| #include <kiwano/base/ObjectBase.h> |  | ||||||
| 
 |  | ||||||
| namespace kiwano |  | ||||||
| { |  | ||||||
| 
 |  | ||||||
| KGE_DECLARE_SMART_PTR(LocalStorage); |  | ||||||
| 
 |  | ||||||
| /// \~chinese
 |  | ||||||
| /// @brief 本地存储
 |  | ||||||
| /// @details LocalStorage是一个简易的持久化工具,存放(字符串-值)的键值对
 |  | ||||||
| /// 支持的数据类型包括 (bool | int | float | double | String)
 |  | ||||||
| /// 例如, 保存游戏最高分, 以便下次进行游戏时读取:
 |  | ||||||
| ///   @code
 |  | ||||||
| ///     LocalStorage data;                      // 创建数据对象
 |  | ||||||
| ///     data.SaveInt("best-score", 20);        // 保存最高分 20
 |  | ||||||
| ///     int best = data.GetInt("best-score");  // 读取之前储存的最高分
 |  | ||||||
| ///   @endcode
 |  | ||||||
| class KGE_API LocalStorage : public ObjectBase |  | ||||||
| { |  | ||||||
| public: |  | ||||||
|     /// \~chinese
 |  | ||||||
|     /// @brief 构建本地存储对象
 |  | ||||||
|     /// @param file_path 文件储存路径
 |  | ||||||
|     /// @param field 字段名
 |  | ||||||
|     LocalStorage(const String& file_path = "data.ini", const String& field = "defalut"); |  | ||||||
| 
 |  | ||||||
|     /// \~chinese
 |  | ||||||
|     /// @brief 获取文件储存路径
 |  | ||||||
|     const String& GetFilePath() const; |  | ||||||
| 
 |  | ||||||
|     /// \~chinese
 |  | ||||||
|     /// @brief 设置文件储存路径
 |  | ||||||
|     void SetFilePath(const String& file_path); |  | ||||||
| 
 |  | ||||||
|     /// \~chinese
 |  | ||||||
|     /// @brief 获取字段名
 |  | ||||||
|     const String& GetFieldName() const; |  | ||||||
| 
 |  | ||||||
|     /// \~chinese
 |  | ||||||
|     /// @brief 设置字段名
 |  | ||||||
|     void SetFieldName(const String& field); |  | ||||||
| 
 |  | ||||||
|     /// \~chinese
 |  | ||||||
|     /// @brief 判断键对应的数据是否存在
 |  | ||||||
|     bool Exists(const String& key) const; |  | ||||||
| 
 |  | ||||||
|     /// \~chinese
 |  | ||||||
|     /// @brief 保存 int 类型的值
 |  | ||||||
|     /// @param key 键
 |  | ||||||
|     /// @param val 值
 |  | ||||||
|     /// @return 操作是否成功
 |  | ||||||
|     bool SaveInt(const String& key, int val) const; |  | ||||||
| 
 |  | ||||||
|     /// \~chinese
 |  | ||||||
|     /// @brief 保存 float 类型的值
 |  | ||||||
|     /// @param key 键
 |  | ||||||
|     /// @param val 值
 |  | ||||||
|     /// @return 操作是否成功
 |  | ||||||
|     bool SaveFloat(const String& key, float val) const; |  | ||||||
| 
 |  | ||||||
|     /// \~chinese
 |  | ||||||
|     /// @brief 保存 double 类型的值
 |  | ||||||
|     /// @param key 键
 |  | ||||||
|     /// @param val 值
 |  | ||||||
|     /// @return 操作是否成功
 |  | ||||||
|     bool SaveDouble(const String& key, double val) const; |  | ||||||
| 
 |  | ||||||
|     /// \~chinese
 |  | ||||||
|     /// @brief 保存 bool 类型的值
 |  | ||||||
|     /// @param key 键
 |  | ||||||
|     /// @param val 值
 |  | ||||||
|     /// @return 操作是否成功
 |  | ||||||
|     bool SaveBool(const String& key, bool val) const; |  | ||||||
| 
 |  | ||||||
|     /// \~chinese
 |  | ||||||
|     /// @brief 保存 String 类型的值
 |  | ||||||
|     /// @param key 键
 |  | ||||||
|     /// @param val 值
 |  | ||||||
|     /// @return 操作是否成功
 |  | ||||||
|     bool SaveString(const String& key, const String& val) const; |  | ||||||
| 
 |  | ||||||
|     /// \~chinese
 |  | ||||||
|     /// @brief 获取 int 类型的值
 |  | ||||||
|     /// @param key 键
 |  | ||||||
|     /// @param default_value 值不存在时返回的默认值
 |  | ||||||
|     /// @return 值
 |  | ||||||
|     int GetInt(const String& key, int default_value = 0) const; |  | ||||||
| 
 |  | ||||||
|     /// \~chinese
 |  | ||||||
|     /// @brief 获取 float 类型的值
 |  | ||||||
|     /// @param key 键
 |  | ||||||
|     /// @param default_value 值不存在时返回的默认值
 |  | ||||||
|     /// @return 值
 |  | ||||||
|     float GetFloat(const String& key, float default_value = 0.0f) const; |  | ||||||
| 
 |  | ||||||
|     /// \~chinese
 |  | ||||||
|     /// @brief 获取 double 类型的值
 |  | ||||||
|     /// @param key 键
 |  | ||||||
|     /// @param default_value 值不存在时返回的默认值
 |  | ||||||
|     /// @return 值
 |  | ||||||
|     double GetDouble(const String& key, double default_value = 0.0) const; |  | ||||||
| 
 |  | ||||||
|     /// \~chinese
 |  | ||||||
|     /// @brief 获取 bool 类型的值
 |  | ||||||
|     /// @param key 键
 |  | ||||||
|     /// @param default_value 值不存在时返回的默认值
 |  | ||||||
|     /// @return 值
 |  | ||||||
|     bool GetBool(const String& key, bool default_value = false) const; |  | ||||||
| 
 |  | ||||||
|     /// \~chinese
 |  | ||||||
|     /// @brief 获取 字符串 类型的值
 |  | ||||||
|     /// @param key 键
 |  | ||||||
|     /// @param default_value 值不存在时返回的默认值
 |  | ||||||
|     /// @return 值
 |  | ||||||
|     String GetString(const String& key, const String& default_value = String()) const; |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     String file_path_; |  | ||||||
|     String field_name_; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| inline const String& LocalStorage::GetFilePath() const |  | ||||||
| { |  | ||||||
|     return file_path_; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| inline const String& LocalStorage::GetFieldName() const |  | ||||||
| { |  | ||||||
|     return field_name_; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| inline void LocalStorage::SetFilePath(const String& file_path) |  | ||||||
| { |  | ||||||
|     file_path_ = file_path; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| inline void LocalStorage::SetFieldName(const String& field_name) |  | ||||||
| { |  | ||||||
|     field_name_ = field_name; |  | ||||||
| } |  | ||||||
| }  // namespace kiwano
 |  | ||||||
|  | @ -65,9 +65,16 @@ bool Ticker::Tick(Duration dt) | ||||||
|     if (ticked_count_ == total_tick_count_) |     if (ticked_count_ == total_tick_count_) | ||||||
|         return false; |         return false; | ||||||
| 
 | 
 | ||||||
|  |     if (interval_.IsZero()) | ||||||
|  |     { | ||||||
|  |         delta_time_ = dt; | ||||||
|  |         ++ticked_count_; | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     elapsed_time_ += dt; |     elapsed_time_ += dt; | ||||||
| 
 | 
 | ||||||
|     if (elapsed_time_ + error_time_ > interval_) |     if (elapsed_time_ + error_time_ >= interval_) | ||||||
|     { |     { | ||||||
|         delta_time_   = elapsed_time_; |         delta_time_   = elapsed_time_; | ||||||
|         error_time_   = (elapsed_time_ + error_time_) - interval_; |         error_time_   = (elapsed_time_ + error_time_) - interval_; | ||||||
|  |  | ||||||
|  | @ -87,6 +87,10 @@ public: | ||||||
|     /// @brief 设置报时间隔
 |     /// @brief 设置报时间隔
 | ||||||
|     void SetInterval(Duration interval); |     void SetInterval(Duration interval); | ||||||
| 
 | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 获取时间误差
 | ||||||
|  |     Duration GetErrorTime() const; | ||||||
|  | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 获取计时器
 |     /// @brief 获取计时器
 | ||||||
|     TimerPtr GetTimer(); |     TimerPtr GetTimer(); | ||||||
|  | @ -140,4 +144,9 @@ inline void Ticker::SetInterval(Duration interval) | ||||||
|     interval_ = interval; |     interval_ = interval; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | inline Duration Ticker::GetErrorTime() const | ||||||
|  | { | ||||||
|  |     return error_time_; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| }  // namespace kiwano
 | }  // namespace kiwano
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue