diff --git a/src/kiwano-imgui/ImGuiModule.cpp b/src/kiwano-imgui/ImGuiModule.cpp index d5025254..ccfe6a28 100644 --- a/src/kiwano-imgui/ImGuiModule.cpp +++ b/src/kiwano-imgui/ImGuiModule.cpp @@ -28,7 +28,7 @@ void ImGuiModule::SetupModule() // Setup Dear ImGui style ImGui::StyleColorsDark(); - window_ = Application::GetInstance().GetMainWindow(); + window_ = Application::GetInstance().GetWindow(); // Setup Platform/Renderer bindings io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) diff --git a/src/kiwano/2d/Canvas.cpp b/src/kiwano/2d/Canvas.cpp index aa9a0694..1cbbd781 100644 --- a/src/kiwano/2d/Canvas.cpp +++ b/src/kiwano/2d/Canvas.cpp @@ -26,7 +26,7 @@ namespace kiwano CanvasPtr Canvas::Create(const Size& size) { - void* mem = memory::Alloc(); + void* mem = memory::Alloc(sizeof(Canvas)); CanvasPtr ptr = ::new (mem) Canvas; if (ptr) { diff --git a/src/kiwano/base/component/Button.cpp b/src/kiwano/base/component/Button.cpp index c37e207b..a8150917 100644 --- a/src/kiwano/base/component/Button.cpp +++ b/src/kiwano/base/component/Button.cpp @@ -62,14 +62,14 @@ void Button::SetStatus(Status status) if (status == Status::Normal) { - Application::GetInstance().GetMainWindow()->SetCursor(CursorType::Arrow); + Application::GetInstance().GetWindow()->SetCursor(CursorType::Arrow); if (mouse_out_callback_) mouse_out_callback_(this, GetBoundActor()); } else if (status == Status::Hover) { - Application::GetInstance().GetMainWindow()->SetCursor(CursorType::Hand); + Application::GetInstance().GetWindow()->SetCursor(CursorType::Hand); if (old_status != Status::Pressed) { diff --git a/src/kiwano/core/Allocator.cpp b/src/kiwano/core/Allocator.cpp index 99c37088..2fe02281 100644 --- a/src/kiwano/core/Allocator.cpp +++ b/src/kiwano/core/Allocator.cpp @@ -27,6 +27,26 @@ namespace memory MemoryAllocator* current_allocator_ = nullptr; +MemoryAllocator* GetGlobalAllocator() +{ + class KGE_API GlobalAllocator : public MemoryAllocator + { + public: + virtual void* Alloc(size_t size) override + { + return ::operator new(size); + } + + virtual void Free(void* ptr, size_t size) override + { + ::operator delete(ptr, size); + } + }; + + static GlobalAllocator global_allocator; + return &global_allocator; +} + MemoryAllocator* GetAllocator() { if (!current_allocator_) @@ -42,21 +62,5 @@ void SetAllocator(MemoryAllocator* allocator) current_allocator_ = allocator; } -GlobalAllocator* GetGlobalAllocator() -{ - static GlobalAllocator global_allocator; - return &global_allocator; -} - -void* GlobalAllocator::Alloc(size_t size) -{ - return ::malloc(size); -} - -void GlobalAllocator::Free(void* ptr) -{ - ::free(ptr); -} - } // namespace memory } // namespace kiwano diff --git a/src/kiwano/core/Allocator.h b/src/kiwano/core/Allocator.h index f114290c..e733a963 100644 --- a/src/kiwano/core/Allocator.h +++ b/src/kiwano/core/Allocator.h @@ -19,8 +19,9 @@ // THE SOFTWARE. #pragma once -#include -#include +#include // std::forward +#include // std::numeric_limits +#include // std::addressof #include namespace kiwano @@ -39,7 +40,7 @@ public: /// \~chinese /// @brief 释放内存 - virtual void Free(void* ptr) = 0; + virtual void Free(void* ptr, size_t size) = 0; }; /// \~chinese @@ -52,30 +53,32 @@ void SetAllocator(MemoryAllocator* allocator); /// \~chinese /// @brief 使用当前内存分配器分配内存 -template -inline void* Alloc() +inline void* Alloc(size_t size) { - return memory::GetAllocator()->Alloc(sizeof(_Ty)); + return memory::GetAllocator()->Alloc(size); } /// \~chinese /// @brief 使用当前内存分配器释放内存 -inline void Free(void* ptr) +inline void Free(void* ptr, size_t size) { - return memory::GetAllocator()->Free(ptr); + memory::GetAllocator()->Free(ptr, size); } /// \~chinese -/// @brief 使用当前内存分配器创建对象 -template -inline _Ty* New() +/// @brief 构造对象 +template +inline _Ty* Construct(void* ptr, _Args&&... args) { - void* ptr = memory::Alloc<_Ty>(); - if (ptr) - { - return ::new (ptr) _Ty; - } - return nullptr; + return ::new (ptr) _Ty(std::forward<_Args>(args)...); +} + +/// \~chinese +/// @brief 销毁对象 +template +inline void Destroy(_Ty* ptr) +{ + ptr->~_Ty(); } /// \~chinese @@ -83,10 +86,10 @@ inline _Ty* New() template inline _Ty* New(_Args&&... args) { - void* ptr = memory::Alloc<_Ty>(); + void* ptr = memory::Alloc(sizeof(_Ty)); if (ptr) { - return ::new (ptr) _Ty(std::forward<_Args>(args)...); + return memory::Construct<_Ty>(ptr, std::forward<_Args>(args)...); } return nullptr; } @@ -98,28 +101,119 @@ inline void Delete(_Ty* ptr) { if (ptr) { - ptr->~_Ty(); - memory::Free(ptr); + memory::Destroy<_Ty>(ptr); + memory::Free(ptr, sizeof(_Ty)); } } + /// \~chinese -/// @brief 全局内存分配器,使用malloc和free分配内存 -class KGE_API GlobalAllocator : public MemoryAllocator +/// @brief 分配器 +template +class Allocator { public: - /// \~chinese - /// @brief 申请内存 - virtual void* Alloc(size_t size) override; + typedef _Ty value_type; + typedef _Ty* pointer; + typedef const _Ty* const_pointer; + typedef _Ty& reference; + typedef const _Ty& const_reference; - /// \~chinese - /// @brief 释放内存 - virtual void Free(void* ptr) override; + using size_type = size_t; + using difference_type = ptrdiff_t; + + template + struct rebind + { + using other = Allocator<_Other>; + }; + + Allocator() noexcept {} + + Allocator(const Allocator&) noexcept = default; + + template + Allocator(const Allocator<_Other>&) noexcept + { + } + + inline _Ty* allocate(size_t count) + { + if (count > 0) + { + return static_cast<_Ty*>(memory::Alloc(sizeof(_Ty) * count)); + } + return nullptr; + } + + inline void* allocate(size_t count, const void*) + { + return allocate(count); + } + + inline void deallocate(void* ptr, size_t count) + { + memory::Free(ptr, sizeof(_Ty) * count); + } + + template + inline void construct(_UTy* ptr, _Args&&... args) + { + memory::Construct<_UTy>(ptr, std::forward<_Args>(args)...); + } + + template + inline void destroy(_UTy* ptr) + { + memory::Destroy<_UTy>(ptr); + } + + size_t max_size() const noexcept + { + return std::numeric_limits::max() / sizeof(_Ty); + } + + _Ty* address(_Ty& val) const noexcept + { + return std::addressof(val); + } + + const _Ty* address(const _Ty& val) const noexcept + { + return std::addressof(val); + } }; -/// \~chinese -/// @brief 获取全局内存分配器 -GlobalAllocator* GetGlobalAllocator(); +// Allocator +template <> +class Allocator +{ +public: + using value_type = void; + typedef void* pointer; + typedef const void* const_pointer; + + using size_type = size_t; + using difference_type = ptrdiff_t; + + template + struct rebind + { + using other = Allocator<_Other>; + }; +}; + +template +bool operator==(const Allocator<_Ty>&, const Allocator<_Other>&) noexcept +{ + return true; +} + +template +bool operator!=(const Allocator<_Ty>&, const Allocator<_Other>&) noexcept +{ + return false; +} } // namespace memory } // namespace kiwano diff --git a/src/kiwano/platform/Application.cpp b/src/kiwano/platform/Application.cpp index 3aeec82c..5a9edfc8 100644 --- a/src/kiwano/platform/Application.cpp +++ b/src/kiwano/platform/Application.cpp @@ -19,9 +19,8 @@ // THE SOFTWARE. #include -#include -#include #include +#include #include #include #include @@ -39,9 +38,6 @@ Application::Application() , is_paused_(false) , time_scale_(1.f) { - Use(Renderer::GetInstance()); - Use(Input::GetInstance()); - Use(Director::GetInstance()); } Application::~Application() @@ -49,25 +45,22 @@ Application::~Application() this->Destroy(); } -void Application::Run(RunnerPtr runner, bool debug) +void Application::Run(RunnerPtr runner) { KGE_ASSERT(runner); runner_ = runner; running_ = true; is_paused_ = false; + // Initialize runner + runner->InitSettings(); + // Setup all modules for (auto c : modules_) { c->SetupModule(); } - if (debug) - { - Director::GetInstance().ShowDebugInfo(true); - Renderer::GetInstance().GetContext().SetCollectingStatus(true); - } - // Everything is ready runner->OnReady(); @@ -128,16 +121,19 @@ void Application::Destroy() runner_ = nullptr; } - // Clear all resources + // Clear user resources Director::GetInstance().ClearStages(); ResourceCache::GetInstance().Clear(); - TextureCache::GetInstance().Clear(); for (auto iter = modules_.rbegin(); iter != modules_.rend(); ++iter) { (*iter)->DestroyModule(); } modules_.clear(); + + // Clear device resources + TextureCache::GetInstance().Clear(); + Renderer::GetInstance().Destroy(); } void Application::Use(Module& module) diff --git a/src/kiwano/platform/Application.h b/src/kiwano/platform/Application.h index f893e2bb..1107cde5 100644 --- a/src/kiwano/platform/Application.h +++ b/src/kiwano/platform/Application.h @@ -58,7 +58,7 @@ public: * @param debug 是否启用调试模式 * @note 该函数是阻塞的,应用程序结束时函数返回 */ - void Run(RunnerPtr runner, bool debug = false); + void Run(RunnerPtr runner); /** * \~chinese @@ -99,9 +99,9 @@ public: /** * \~chinese - * @brief 获取主窗口 + * @brief 获取窗口 */ - WindowPtr GetMainWindow() const; + WindowPtr GetWindow() const; /** * \~chinese @@ -183,10 +183,10 @@ inline RunnerPtr Application::GetRunner() const return runner_; } -inline WindowPtr Application::GetMainWindow() const +inline WindowPtr Application::GetWindow() const { KGE_ASSERT(runner_); - return runner_->GetMainWindow(); + return runner_->GetWindow(); } inline TickerPtr Application::GetFrameTicker() const diff --git a/src/kiwano/platform/Runner.cpp b/src/kiwano/platform/Runner.cpp index d5519f22..a289b6a5 100644 --- a/src/kiwano/platform/Runner.cpp +++ b/src/kiwano/platform/Runner.cpp @@ -20,24 +20,25 @@ #include #include +#include #include - -#define KGE_MAX_SKIP_FRAMES 10 +#include +#include namespace kiwano { -RunnerPtr Runner::Create(WindowPtr main_window) +RunnerPtr Runner::Create(Settings settings) { RunnerPtr ptr = memory::New(); if (ptr) { - ptr->SetMainWindow(main_window); + ptr->SetSettings(settings); } return ptr; } -RunnerPtr Runner::Create(WindowPtr main_window, Function on_ready, Function on_destroy) +RunnerPtr Runner::Create(Settings settings, Function on_ready, Function on_destroy) { class CallbackRunner : public Runner { @@ -63,7 +64,7 @@ RunnerPtr Runner::Create(WindowPtr main_window, Function on_ready, Funct { ptr->on_ready = on_ready; ptr->on_destroy = on_destroy; - ptr->SetMainWindow(main_window); + ptr->SetSettings(settings); } return ptr; } @@ -72,6 +73,36 @@ Runner::Runner() {} Runner::~Runner() {} +void Runner::InitSettings() +{ + if (settings_.debug_mode) + { + // Show console window before creating main window + Logger::GetInstance().ShowConsole(true); + } + + // Create game window + WindowPtr window = + Window::Create(settings_.title, settings_.width, settings_.height, settings_.icon, settings_.resizable); + SetWindow(window); + + // Update renderer settings + Renderer::GetInstance().MakeContextForWindow(window); + Renderer::GetInstance().SetClearColor(settings_.bg_color); + Renderer::GetInstance().SetVSyncEnabled(settings_.vsync_enabled); + + // Use defaut modules + Application::GetInstance().Use(Input::GetInstance()); + Application::GetInstance().Use(Director::GetInstance()); + + // Enable debug mode + if (settings_.debug_mode) + { + Director::GetInstance().ShowDebugInfo(true); + Renderer::GetInstance().GetContext().SetCollectingStatus(true); + } +} + bool Runner::MainLoop(Duration dt) { if (!main_window_) @@ -79,7 +110,7 @@ bool Runner::MainLoop(Duration dt) if (main_window_->ShouldClose()) { - if (this->OnClosing()) + if (this->OnClose()) return false; main_window_->SetShouldClose(false); diff --git a/src/kiwano/platform/Runner.h b/src/kiwano/platform/Runner.h index c21801a9..db1a6d38 100644 --- a/src/kiwano/platform/Runner.h +++ b/src/kiwano/platform/Runner.h @@ -22,6 +22,8 @@ #include #include #include +#include +#include namespace kiwano { @@ -30,26 +32,52 @@ class Application; KGE_DECLARE_SMART_PTR(Runner); +/** + * \~chinese + * @brief 游戏设置 + */ +struct Settings +{ + uint32_t width; ///< 窗口宽度 + uint32_t height; ///< 窗口高度 + String title; ///< 窗口标题 + uint32_t icon; ///< 窗口图标 + bool resizable; ///< 窗口大小可调整 + Color bg_color; ///< 窗口背景色 + bool vsync_enabled; ///< 垂直同步 + bool debug_mode; ///< 调试模式 + + Settings() + : width(800) + , height(600) + , title("Kiwano") + , icon() + , resizable(false) + , bg_color(Color::Black) + , vsync_enabled(true) + , debug_mode(false) + { + } +}; + /** * \~chinese * @brief 程序运行器 */ class KGE_API Runner : public ObjectBase { - friend class Application; - public: /// \~chinese /// @brief 创建程序运行器 /// @param main_window 主窗口 - static RunnerPtr Create(WindowPtr main_window); + static RunnerPtr Create(Settings settings); /// \~chinese /// @brief 创建程序运行器 /// @param main_window 主窗口 /// @param on_ready 应用程序初始化完成后执行的回调函数 /// @param on_destroy 应用程序销毁时执行的回调函数 - static RunnerPtr Create(WindowPtr main_window, Function on_ready, Function on_destroy = nullptr); + static RunnerPtr Create(Settings settings, Function on_ready, Function on_destroy = nullptr); Runner(); @@ -69,7 +97,7 @@ public: /// @brief 应用程序关闭处理 /// @details 重载该函数以处理用户关闭应用程序时的行为,如保存用户数据等 /// @return 返回true允许用户关闭程序,否则阻止程序关闭 - virtual bool OnClosing(); + virtual bool OnClose(); /// \~chinese /// @brief 应用程序主循环 @@ -79,14 +107,29 @@ public: virtual bool MainLoop(Duration dt); /// \~chinese - /// @brief 获取主窗口 - WindowPtr GetMainWindow() const; + /// @brief 获取窗口 + WindowPtr GetWindow() const; /// \~chinese - /// @brief 设置主窗口 - void SetMainWindow(WindowPtr window); + /// @brief 设置窗口 + void SetWindow(WindowPtr window); + + /// \~chinese + /// @brief 获取设置 + Settings GetSettings() const; + +protected: + /// \~chinese + /// @brief 修改设置 + void SetSettings(Settings settings); private: + friend class Application; + + void InitSettings(); + +private: + Settings settings_; WindowPtr main_window_; }; @@ -94,19 +137,29 @@ inline void Runner::OnReady() {} inline void Runner::OnDestroy() {} -inline bool Runner::OnClosing() +inline bool Runner::OnClose() { return true; } -inline WindowPtr Runner::GetMainWindow() const +inline WindowPtr Runner::GetWindow() const { return main_window_; } -inline void Runner::SetMainWindow(WindowPtr window) +inline void Runner::SetWindow(WindowPtr window) { main_window_ = window; } +inline Settings Runner::GetSettings() const +{ + return settings_; +} + +inline void Runner::SetSettings(Settings settings) +{ + settings_ = settings; +} + } // namespace kiwano diff --git a/src/kiwano/platform/win32/WindowImpl.cpp b/src/kiwano/platform/win32/WindowImpl.cpp index 1aba29ef..6cba0482 100644 --- a/src/kiwano/platform/win32/WindowImpl.cpp +++ b/src/kiwano/platform/win32/WindowImpl.cpp @@ -269,21 +269,6 @@ void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height, ::ShowWindow(handle_, SW_SHOWNORMAL); ::UpdateWindow(handle_); - - // Initialize Direct3D resources - auto d3d_res = graphics::directx::GetD3DDeviceResources(); - - HRESULT hr = d3d_res->Initialize(handle_); - - // Initialize Direct2D resources - if (SUCCEEDED(hr)) - { - auto d2d_res = graphics::directx::GetD2DDeviceResources(); - - hr = d2d_res->Initialize(d3d_res->GetDXGIDevice(), d3d_res->GetDXGISwapChain()); - } - - KGE_THROW_IF_FAILED(hr, "Create DirectX resources failed"); } void WindowWin32Impl::PumpEvents() diff --git a/src/kiwano/render/DirectX/RendererImpl.cpp b/src/kiwano/render/DirectX/RendererImpl.cpp index 49f496d8..571f9213 100644 --- a/src/kiwano/render/DirectX/RendererImpl.cpp +++ b/src/kiwano/render/DirectX/RendererImpl.cpp @@ -58,11 +58,41 @@ void RendererImpl::MakeContextForWindow(WindowPtr window) HWND target_window = window->GetHandle(); output_size_ = window->GetSize(); - d2d_res_ = graphics::directx::GetD2DDeviceResources(); - d3d_res_ = graphics::directx::GetD3DDeviceResources(); - HRESULT hr = target_window ? S_OK : E_FAIL; + // Initialize Direct3D resources + if (SUCCEEDED(hr)) + { + auto d3d_res = graphics::directx::GetD3DDeviceResources(); + + hr = d3d_res->Initialize(target_window); + if (FAILED(hr)) + { + d3d_res->DiscardResources(); + } + else + { + d3d_res_ = d3d_res; + } + } + + // Initialize Direct2D resources + if (SUCCEEDED(hr)) + { + auto d2d_res = graphics::directx::GetD2DDeviceResources(); + + hr = d2d_res->Initialize(d3d_res_->GetDXGIDevice(), d3d_res_->GetDXGISwapChain()); + if (FAILED(hr)) + { + d2d_res->DiscardResources(); + } + else + { + d2d_res_ = d2d_res; + } + } + + // Initialize other device resources if (SUCCEEDED(hr)) { @@ -114,15 +144,23 @@ void RendererImpl::Destroy() { KGE_SYS_LOG("Destroying device resources"); - d2d_res_->GetDWriteFactory()->UnregisterFontFileLoader(res_font_file_loader_.Get()); - res_font_file_loader_.Reset(); + if (d2d_res_) + { + d2d_res_->GetDWriteFactory()->UnregisterFontFileLoader(res_font_file_loader_.Get()); + res_font_file_loader_.Reset(); - d2d_res_->GetDWriteFactory()->UnregisterFontCollectionLoader(res_font_collection_loader_.Get()); - res_font_collection_loader_.Reset(); + d2d_res_->GetDWriteFactory()->UnregisterFontCollectionLoader(res_font_collection_loader_.Get()); + res_font_collection_loader_.Reset(); - render_ctx_.Reset(); - d2d_res_.Reset(); - d3d_res_.Reset(); + render_ctx_.Reset(); + d2d_res_->DiscardResources(); + } + + if (d3d_res_) + { + d3d_res_->DiscardResources(); + d3d_res_.Reset(); + } ::CoUninitialize(); } diff --git a/src/kiwano/render/DirectX/RendererImpl.h b/src/kiwano/render/DirectX/RendererImpl.h index edddaa45..8825d135 100644 --- a/src/kiwano/render/DirectX/RendererImpl.h +++ b/src/kiwano/render/DirectX/RendererImpl.h @@ -79,13 +79,13 @@ public: void Resize(uint32_t width, uint32_t height) override; -protected: - RendererImpl(); - void MakeContextForWindow(WindowPtr window) override; void Destroy() override; +protected: + RendererImpl(); + private: using ID2DDeviceResources = kiwano::graphics::directx::ID2DDeviceResources; using ID3DDeviceResources = kiwano::graphics::directx::ID3DDeviceResources; diff --git a/src/kiwano/render/Renderer.cpp b/src/kiwano/render/Renderer.cpp index a95d65d4..ef165491 100644 --- a/src/kiwano/render/Renderer.cpp +++ b/src/kiwano/render/Renderer.cpp @@ -31,22 +31,6 @@ Renderer::Renderer() { } -void Renderer::SetupModule() -{ - WindowPtr window = Application::GetInstance().GetMainWindow(); - MakeContextForWindow(window); -} - -void Renderer::DestroyModule() -{ - Destroy(); -} - -void Renderer::HandleEvent(Event* evt) -{ - // DO NOTHING -} - void Renderer::BeginDraw() { KGE_ASSERT(render_ctx_); diff --git a/src/kiwano/render/Renderer.h b/src/kiwano/render/Renderer.h index a42b3c7c..742cfb11 100644 --- a/src/kiwano/render/Renderer.h +++ b/src/kiwano/render/Renderer.h @@ -44,7 +44,7 @@ namespace kiwano * \~chinese * @brief 渲染器 */ -class KGE_API Renderer : public EventModule +class KGE_API Renderer : public Noncopyable { public: /// \~chinese @@ -235,20 +235,17 @@ public: /// @throw kiwano::SystemError 呈现失败时抛出 virtual void Present() = 0; -public: - void SetupModule() override; + /// \~chinese + /// @brief 为窗口创建渲染上下文 + virtual void MakeContextForWindow(WindowPtr window) = 0; - void DestroyModule() override; - - void HandleEvent(Event* evt) override; + /// \~chinese + /// @brief 销毁渲染器资源 + virtual void Destroy() = 0; protected: Renderer(); - virtual void MakeContextForWindow(WindowPtr window) = 0; - - virtual void Destroy() = 0; - protected: bool vsync_; Color clear_color_; diff --git a/src/kiwano/utils/ConfigIni.cpp b/src/kiwano/utils/ConfigIni.cpp index 1b70c758..1ad2c3a9 100644 --- a/src/kiwano/utils/ConfigIni.cpp +++ b/src/kiwano/utils/ConfigIni.cpp @@ -39,7 +39,7 @@ StringView Trim(StringView str) while (std::isspace(str[end - 1])) --end; - if (end - start) + if (end > start) return StringView(str.Data() + start, end - start); } return StringView(); @@ -158,16 +158,20 @@ bool ConfigIni::Save(std::ostream& os) std::sort(keys.begin(), keys.end()); // Output to ini - for (const auto& key : keys) + std::ostream::sentry ok(os); + if (ok) { - os << '[' << key << ']' << std::endl; - for (const auto& pair : sections_[key]) + for (const auto& key : keys) { - os << pair.first << " = " << pair.second << std::endl; + os << '[' << key << ']' << std::endl; + for (const auto& pair : sections_[key]) + { + os << pair.first << " = " << pair.second << std::endl; + } + os << std::endl; } - os << std::endl; } - return false; + return !os.fail(); } ConfigIni::SectionMap ConfigIni::GetSectionMap() const @@ -177,23 +181,20 @@ ConfigIni::SectionMap ConfigIni::GetSectionMap() const ConfigIni::ValueMap ConfigIni::GetSection(const String& section) const { - auto iter = sections_.find(section); - if (iter != sections_.end()) - return iter->second; + if (HasSection(section)) + { + return sections_.at(section); + } return ValueMap(); } -String ConfigIni::GetString(const String& section_name, const String& key) const +String ConfigIni::GetString(const String& section, const String& key, const String& default_value) const { - if (HasSection(section_name)) + if (HasKey(section, key)) { - const auto& section = sections_.at(section_name); - - auto iter_key = section.find(key); - if (iter_key != section.end()) - return iter_key->second; + return sections_.at(section).at(key); } - return String(); + return default_value; } float ConfigIni::GetFloat(const String& section, const String& key, float default_value) const @@ -274,7 +275,7 @@ bool ConfigIni::HasSection(const String& section) const return !!sections_.count(section); } -bool ConfigIni::HasValue(const String& section, const String& key) const +bool ConfigIni::HasKey(const String& section, const String& key) const { if (HasSection(section)) { @@ -324,6 +325,22 @@ void ConfigIni::SetBool(const String& section, const String& key, bool value) SetString(section, key, value ? "true" : "false"); } +void ConfigIni::DeleteSection(const String& section) +{ + if (HasSection(section)) + { + sections_.erase(section); + } +} + +void ConfigIni::DeleteKey(const String& section, const String& key) +{ + if (HasKey(section, key)) + { + sections_.at(section).erase(key); + } +} + ConfigIni::ValueMap& ConfigIni::operator[](const String& section) { if (!HasSection(section)) diff --git a/src/kiwano/utils/ConfigIni.h b/src/kiwano/utils/ConfigIni.h index e83434f2..07cc18a0 100644 --- a/src/kiwano/utils/ConfigIni.h +++ b/src/kiwano/utils/ConfigIni.h @@ -39,7 +39,7 @@ public: /// \~chinese /// @brief 键值字典 - typedef Map ValueMap; + typedef UnorderedMap ValueMap; /// \~chinese /// @brief Section字典 @@ -65,6 +65,17 @@ public: /// @param os 输出流 bool Save(std::ostream& os); + /// \~chinese + /// @brief 是否存在section + /// @param section section的名称 + bool HasSection(const String& section) const; + + /// \~chinese + /// @brief 是否存在值 + /// @param section section的名称 + /// @param key key的名称 + bool HasKey(const String& section, const String& key) const; + /// \~chinese /// @brief 获取所有section SectionMap GetSectionMap() const; @@ -78,7 +89,7 @@ public: /// @brief 获取值 /// @param section section的名称 /// @param key key的名称 - String GetString(const String& section, const String& key) const; + String GetString(const String& section, const String& key, const String& default_value = String()) const; /// \~chinese /// @brief 获取值 @@ -108,17 +119,6 @@ public: /// @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字典 @@ -165,6 +165,17 @@ public: /// @param value 值 void SetBool(const String& section, const String& key, bool value); + /// \~chinese + /// @brief 删除section + /// @param section section的名称 + void DeleteSection(const String& section); + + /// \~chinese + /// @brief 删除值 + /// @param section section的名称 + /// @param key key的名称 + void DeleteKey(const String& section, const String& key); + ValueMap& operator[](const String& section); const ValueMap& operator[](const String& section) const;