Remove OuterC library
This commit is contained in:
parent
f1e0d59cea
commit
2c050cafba
|
|
@ -12,6 +12,7 @@
|
|||
<ClInclude Include="..\..\src\kiwano\2d\Button.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\2d\Frame.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\2d\GifSprite.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\Any.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\Common.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\Director.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\event\Event.h" />
|
||||
|
|
@ -20,10 +21,15 @@
|
|||
<ClInclude Include="..\..\src\kiwano\core\event\MouseEvent.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\event\WindowEvent.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\Exception.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\Function.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\IntrusiveList.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\Json.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\Keys.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\Library.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\Singleton.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\String.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\Time.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\core\Xml.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\kiwano.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\config.h" />
|
||||
<ClInclude Include="..\..\src\kiwano\macros.h" />
|
||||
|
|
@ -129,6 +135,7 @@
|
|||
<ClCompile Include="..\..\src\kiwano\core\ObjectBase.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\core\RefCounter.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\core\Resource.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\core\String.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\core\Time.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\core\Timer.cpp" />
|
||||
<ClCompile Include="..\..\src\kiwano\core\TimerManager.cpp" />
|
||||
|
|
|
|||
|
|
@ -300,6 +300,24 @@
|
|||
<ClInclude Include="..\..\src\kiwano\platform\Runner.h">
|
||||
<Filter>platform</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\core\Function.h">
|
||||
<Filter>core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\core\String.h">
|
||||
<Filter>core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\core\Any.h">
|
||||
<Filter>core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\core\Json.h">
|
||||
<Filter>core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\core\Xml.h">
|
||||
<Filter>core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\kiwano\core\IntrusiveList.h">
|
||||
<Filter>core</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\kiwano\2d\Canvas.cpp">
|
||||
|
|
@ -512,5 +530,8 @@
|
|||
<ClCompile Include="..\..\src\kiwano\platform\Runner.cpp">
|
||||
<Filter>platform</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\kiwano\core\String.cpp">
|
||||
<Filter>core</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019 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.
|
||||
|
|
@ -1,511 +0,0 @@
|
|||
// Copyright (c) 2019-2020 OuterC - Nomango
|
||||
|
||||
#pragma once
|
||||
#include <typeinfo>
|
||||
#include <type_traits>
|
||||
#include <exception>
|
||||
|
||||
namespace oc
|
||||
{
|
||||
|
||||
class bad_any_cast : public std::exception
|
||||
{
|
||||
public:
|
||||
bad_any_cast() {}
|
||||
|
||||
virtual const char* what() const override
|
||||
{
|
||||
return "bad any_cast";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class any
|
||||
{
|
||||
public:
|
||||
any() : storage_{}
|
||||
{
|
||||
}
|
||||
|
||||
template <
|
||||
typename _Ty,
|
||||
typename _Decayed = typename std::decay<_Ty>::type,
|
||||
typename std::enable_if<std::is_copy_constructible<_Decayed>::value, int>::type = 0
|
||||
>
|
||||
any(_Ty&& val) : storage_{}
|
||||
{
|
||||
emplace<_Decayed>(std::forward<_Ty>(val));
|
||||
}
|
||||
|
||||
template <
|
||||
typename _Ty,
|
||||
typename... _Args
|
||||
>
|
||||
any(_Args&&... args) : storage_{}
|
||||
{
|
||||
using _Decayed = typename std::decay<_Ty>::type;
|
||||
|
||||
reset();
|
||||
emplace_decayed<_Decayed>(std::forward<_Args>(args)...);
|
||||
}
|
||||
|
||||
any(const any& rhs) : storage_{}
|
||||
{
|
||||
copy_from(rhs);
|
||||
}
|
||||
|
||||
any(any&& rhs) noexcept : storage_{}
|
||||
{
|
||||
move_from(std::move(rhs));
|
||||
}
|
||||
|
||||
~any()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
inline const type_info& type() const noexcept
|
||||
{
|
||||
const type_info* const info = typeinfo();
|
||||
if (info)
|
||||
{
|
||||
return *info;
|
||||
}
|
||||
return typeid(void);
|
||||
}
|
||||
|
||||
inline bool has_value() const noexcept
|
||||
{
|
||||
return typeinfo() != nullptr;
|
||||
}
|
||||
|
||||
template <
|
||||
typename _Ty,
|
||||
typename... _Args
|
||||
>
|
||||
void emplace(_Args&&... args)
|
||||
{
|
||||
using _Decayed = typename std::decay<_Ty>::type;
|
||||
|
||||
reset();
|
||||
emplace_decayed<_Decayed>(std::forward<_Args>(args)...);
|
||||
}
|
||||
|
||||
void swap(any& rhs) noexcept
|
||||
{
|
||||
any old = static_cast<any&&>(rhs);
|
||||
rhs = static_cast<any&&>(*this);
|
||||
*this = static_cast<any&&>(old);
|
||||
}
|
||||
|
||||
inline void reset() noexcept
|
||||
{
|
||||
tidy();
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
_Ty* cast_pointer() noexcept
|
||||
{
|
||||
return const_cast<_Ty*>(const_cast<const any*>(this)->cast_pointer<_Ty>());
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
const _Ty* cast_pointer() const noexcept
|
||||
{
|
||||
static_assert(!std::is_void<_Ty>::value, "oc::any cannot contain void");
|
||||
|
||||
const type_info* const info = typeinfo();
|
||||
if (info && (*info == typeid(std::decay<_Ty>::type)))
|
||||
{
|
||||
if (has_small_type())
|
||||
{
|
||||
return static_cast<const _Ty*>(small_data());
|
||||
}
|
||||
else
|
||||
{
|
||||
return static_cast<const _Ty*>(big_data());
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
_Ty cast()
|
||||
{
|
||||
using _Decayed = typename std::decay<_Ty>::type;
|
||||
|
||||
const auto ptr = cast_pointer<_Decayed>();
|
||||
if (!ptr)
|
||||
{
|
||||
throw bad_any_cast{};
|
||||
}
|
||||
return static_cast<_Ty>(*ptr);
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
_Ty cast() const
|
||||
{
|
||||
using _Decayed = typename std::decay<_Ty>::type;
|
||||
|
||||
const auto ptr = cast_pointer<_Decayed>();
|
||||
if (!ptr)
|
||||
{
|
||||
throw bad_any_cast{};
|
||||
}
|
||||
return static_cast<_Ty>(*ptr);
|
||||
}
|
||||
|
||||
any& operator=(const any& rhs)
|
||||
{
|
||||
*this = any(rhs);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
any& operator=(any&& rhs) noexcept
|
||||
{
|
||||
reset();
|
||||
move_from(std::move(rhs));
|
||||
return (*this);
|
||||
}
|
||||
|
||||
protected:
|
||||
const type_info*& typeinfo()
|
||||
{
|
||||
return storage_.small_.info_;
|
||||
}
|
||||
|
||||
const type_info* typeinfo() const
|
||||
{
|
||||
return storage_.small_.info_;
|
||||
}
|
||||
|
||||
template <
|
||||
typename _Decayed,
|
||||
typename... _Args
|
||||
>
|
||||
inline void emplace_decayed(_Args&&... args)
|
||||
{
|
||||
store<_Decayed>(decayed_is_small<_Decayed>{}, std::forward<_Args>(args)...);
|
||||
}
|
||||
|
||||
template <
|
||||
typename _Decayed,
|
||||
typename... _Args
|
||||
>
|
||||
void store(std::true_type, _Args&&... args)
|
||||
{
|
||||
storage_.is_small_ = true;
|
||||
typeinfo() = &typeid(_Decayed);
|
||||
small_rtti() = small_storage_rtti::make<_Decayed>();
|
||||
|
||||
::new (small_data()) _Decayed(std::forward<_Args>(args)...);
|
||||
}
|
||||
|
||||
template <
|
||||
typename _Decayed,
|
||||
typename... _Args
|
||||
>
|
||||
void store(std::false_type, _Args&&... args)
|
||||
{
|
||||
storage_.is_small_ = false;
|
||||
typeinfo() = &typeid(_Decayed);
|
||||
big_rtti() = big_storage_rtti::make<_Decayed>();
|
||||
|
||||
big_data() = ::new _Decayed(std::forward<_Args>(args)...);
|
||||
}
|
||||
|
||||
void tidy() noexcept
|
||||
{
|
||||
if (has_value())
|
||||
{
|
||||
if (has_small_type())
|
||||
{
|
||||
small_rtti().destroy(small_data());
|
||||
}
|
||||
else
|
||||
{
|
||||
big_rtti().destroy(big_data());
|
||||
big_data() = nullptr;
|
||||
}
|
||||
typeinfo() = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void copy_from(const any& rhs)
|
||||
{
|
||||
if (rhs.has_value())
|
||||
{
|
||||
typeinfo() = rhs.typeinfo();
|
||||
storage_.is_small_ = rhs.storage_.is_small_;
|
||||
|
||||
if (rhs.has_small_type())
|
||||
{
|
||||
small_rtti() = rhs.small_rtti();
|
||||
small_rtti().copy(small_data(), rhs.small_data());
|
||||
}
|
||||
else
|
||||
{
|
||||
big_rtti() = rhs.big_rtti();
|
||||
big_data() = big_rtti().copy(rhs.big_data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void move_from(any&& rhs) noexcept
|
||||
{
|
||||
if (rhs.has_value())
|
||||
{
|
||||
typeinfo() = rhs.typeinfo();
|
||||
storage_.is_small_ = rhs.storage_.is_small_;
|
||||
|
||||
if (rhs.has_small_type())
|
||||
{
|
||||
small_rtti() = rhs.small_rtti();
|
||||
small_rtti().move(small_data(), rhs.small_data());
|
||||
}
|
||||
else
|
||||
{
|
||||
big_rtti() = rhs.big_rtti();
|
||||
big_data() = rhs.big_data();
|
||||
rhs.typeinfo() = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void* small_data()
|
||||
{
|
||||
return storage_.small_.buffer_;
|
||||
}
|
||||
|
||||
inline const void* small_data() const
|
||||
{
|
||||
return storage_.small_.buffer_;
|
||||
}
|
||||
|
||||
inline void*& big_data()
|
||||
{
|
||||
return storage_.big_.ptr_;
|
||||
}
|
||||
|
||||
inline void* big_data() const
|
||||
{
|
||||
return storage_.big_.ptr_;
|
||||
}
|
||||
|
||||
inline bool has_small_type() const
|
||||
{
|
||||
return storage_.is_small_;
|
||||
}
|
||||
|
||||
protected:
|
||||
static const auto ANY_SMALL_SPACE_SIZE = 8U;
|
||||
|
||||
template <typename _Ty>
|
||||
struct decayed_is_small : public std::bool_constant<sizeof(_Ty) <= ANY_SMALL_SPACE_SIZE>
|
||||
{
|
||||
};
|
||||
|
||||
struct big_storage_rtti
|
||||
{
|
||||
using destroy_func = void(void*);
|
||||
using copy_func = void*(const void*);
|
||||
|
||||
big_storage_rtti()
|
||||
{
|
||||
destroy = nullptr;
|
||||
copy = nullptr;
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
static inline big_storage_rtti make()
|
||||
{
|
||||
big_storage_rtti rtti;
|
||||
rtti.destroy = &big_storage_rtti::destroy_impl<_Ty>;
|
||||
rtti.copy = &big_storage_rtti::copy_impl<_Ty>;
|
||||
return rtti;
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
static void destroy_impl(void* const ptr) noexcept
|
||||
{
|
||||
::delete static_cast<_Ty*>(ptr);
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
static void* copy_impl(const void* const ptr) noexcept
|
||||
{
|
||||
return ::new _Ty(*static_cast<const _Ty*>(ptr));
|
||||
}
|
||||
|
||||
destroy_func* destroy;
|
||||
copy_func* copy;
|
||||
};
|
||||
|
||||
struct small_storage_rtti
|
||||
{
|
||||
using destroy_func = void(void*);
|
||||
using copy_func = void* (void*, const void*);
|
||||
using move_func = void*(void*, void*);
|
||||
|
||||
small_storage_rtti()
|
||||
{
|
||||
destroy = nullptr;
|
||||
copy = nullptr;
|
||||
move = nullptr;
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
static inline small_storage_rtti make()
|
||||
{
|
||||
small_storage_rtti rtti;
|
||||
rtti.destroy = &small_storage_rtti::destroy_impl<_Ty>;
|
||||
rtti.copy = &small_storage_rtti::copy_impl<_Ty>;
|
||||
rtti.move = &small_storage_rtti::move_impl<_Ty>;
|
||||
return rtti;
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
static void destroy_impl(void* const ptr) noexcept
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
_Ty& obj = *(static_cast<_Ty* const>(ptr));
|
||||
obj.~_Ty();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
static void* copy_impl(void* const target, const void* const ptr) noexcept
|
||||
{
|
||||
return ::new (static_cast<_Ty*>(target)) _Ty(*static_cast<const _Ty*>(ptr));
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
static void* move_impl(void* const target, void* const ptr) noexcept
|
||||
{
|
||||
return ::new (static_cast<_Ty*>(target)) _Ty(std::move(*static_cast<_Ty*>(ptr)));
|
||||
}
|
||||
|
||||
destroy_func* destroy;
|
||||
copy_func* copy;
|
||||
move_func* move;
|
||||
};
|
||||
|
||||
protected:
|
||||
inline small_storage_rtti& small_rtti()
|
||||
{
|
||||
return storage_.small_.rtti_;
|
||||
}
|
||||
|
||||
inline const small_storage_rtti& small_rtti() const
|
||||
{
|
||||
return storage_.small_.rtti_;
|
||||
}
|
||||
|
||||
inline big_storage_rtti& big_rtti()
|
||||
{
|
||||
return storage_.big_.rtti_;
|
||||
}
|
||||
|
||||
inline const big_storage_rtti& big_rtti() const
|
||||
{
|
||||
return storage_.big_.rtti_;
|
||||
}
|
||||
|
||||
protected:
|
||||
struct small_storage
|
||||
{
|
||||
const type_info* info_;
|
||||
small_storage_rtti rtti_;
|
||||
char buffer_[ANY_SMALL_SPACE_SIZE];
|
||||
};
|
||||
|
||||
struct big_storage
|
||||
{
|
||||
const type_info* info_;
|
||||
big_storage_rtti rtti_;
|
||||
void* ptr_;
|
||||
};
|
||||
|
||||
struct storage
|
||||
{
|
||||
bool is_small_;
|
||||
union
|
||||
{
|
||||
small_storage small_;
|
||||
big_storage big_;
|
||||
};
|
||||
|
||||
storage() : is_small_(false), small_() {} // fix error C2280 for VisualStudio 2015
|
||||
};
|
||||
|
||||
storage storage_;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// any_cast functions
|
||||
//
|
||||
|
||||
template <typename _Ty>
|
||||
_Ty* any_cast(any* const a) noexcept
|
||||
{
|
||||
return a->cast_pointer<_Ty>();
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
const _Ty* any_cast(const any* const a) noexcept
|
||||
{
|
||||
return a->cast_pointer<_Ty>();
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
_Ty any_cast(any& a)
|
||||
{
|
||||
using _Decayed = typename std::decay<_Ty>::type;
|
||||
|
||||
const auto ptr = any_cast<_Decayed>(&a);
|
||||
if (!ptr)
|
||||
{
|
||||
throw bad_any_cast{};
|
||||
}
|
||||
return static_cast<_Ty>(*ptr);
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
const _Ty any_cast(const any& a)
|
||||
{
|
||||
using _Decayed = typename std::decay<_Ty>::type;
|
||||
|
||||
const auto ptr = any_cast<_Decayed>(&a);
|
||||
if (!ptr)
|
||||
{
|
||||
throw bad_any_cast{};
|
||||
}
|
||||
return static_cast<_Ty>(*ptr);
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
_Ty any_cast(any&& a)
|
||||
{
|
||||
using _Decayed = typename std::decay<_Ty>::type;
|
||||
|
||||
const auto ptr = any_cast<_Decayed>(&a);
|
||||
if (!ptr)
|
||||
{
|
||||
throw bad_any_cast{};
|
||||
}
|
||||
return static_cast<_Ty>(std::move(*ptr));
|
||||
}
|
||||
|
||||
} // namespace oc
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
inline void swap(oc::any& lhs, oc::any& rhs) noexcept
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,169 +0,0 @@
|
|||
// Copyright (c) 2019-2020 OuterC - Nomango
|
||||
|
||||
#pragma once
|
||||
#include "function/details.h"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace oc
|
||||
{
|
||||
|
||||
class bad_function_call : public ::std::exception
|
||||
{
|
||||
public:
|
||||
bad_function_call() {}
|
||||
|
||||
virtual const char* what() const override
|
||||
{
|
||||
return "bad function call";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename _Ty>
|
||||
class function;
|
||||
|
||||
template<typename _Ret, typename... _Args>
|
||||
class function<_Ret(_Args...)>
|
||||
{
|
||||
public:
|
||||
function()
|
||||
: callable_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
function(std::nullptr_t)
|
||||
: callable_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
function(const function& rhs)
|
||||
: callable_(rhs.callable_)
|
||||
{
|
||||
if (callable_) callable_->retain();
|
||||
}
|
||||
|
||||
function(function&& rhs) noexcept
|
||||
: callable_(rhs.callable_)
|
||||
{
|
||||
rhs.callable_ = nullptr;
|
||||
}
|
||||
|
||||
function(_Ret(*func)(_Args...))
|
||||
{
|
||||
callable_ = __function_detail::proxy_callable<_Ret(*)(_Args...), _Ret, _Args...>::make(::std::move(func));
|
||||
if (callable_) callable_->retain();
|
||||
}
|
||||
|
||||
template<
|
||||
typename _Ty,
|
||||
typename = typename ::std::enable_if<__function_detail::is_callable<_Ty, _Ret, _Args...>::value, int>::type>
|
||||
function(_Ty val)
|
||||
{
|
||||
callable_ = __function_detail::proxy_callable<_Ty, _Ret, _Args...>::make(::std::move(val));
|
||||
if (callable_) callable_->retain();
|
||||
}
|
||||
|
||||
template<typename _Ty,
|
||||
typename _Uty,
|
||||
typename = typename ::std::enable_if<::std::is_same<_Ty, _Uty>::value || ::std::is_base_of<_Ty, _Uty>::value, int>::type>
|
||||
function(_Uty* ptr, _Ret(_Ty::* func)(_Args...))
|
||||
{
|
||||
callable_ = __function_detail::proxy_mem_callable<_Ty, _Ret, _Args...>::make(ptr, func);
|
||||
if (callable_) callable_->retain();
|
||||
}
|
||||
|
||||
template<typename _Ty,
|
||||
typename _Uty,
|
||||
typename = typename ::std::enable_if<::std::is_same<_Ty, _Uty>::value || ::std::is_base_of<_Ty, _Uty>::value, int>::type>
|
||||
function(_Uty* ptr, _Ret(_Ty::* func)(_Args...) const)
|
||||
{
|
||||
callable_ = __function_detail::proxy_const_mem_callable<_Ty, _Ret, _Args...>::make(ptr, func);
|
||||
if (callable_) callable_->retain();
|
||||
}
|
||||
|
||||
~function()
|
||||
{
|
||||
tidy();
|
||||
}
|
||||
|
||||
inline void swap(const function& rhs)
|
||||
{
|
||||
std::swap(callable_, rhs.callable_);
|
||||
}
|
||||
|
||||
inline _Ret operator()(_Args... args) const
|
||||
{
|
||||
if (!callable_)
|
||||
throw bad_function_call();
|
||||
return callable_->invoke(::std::forward<_Args>(args)...);
|
||||
}
|
||||
|
||||
inline operator bool() const
|
||||
{
|
||||
return !!callable_;
|
||||
}
|
||||
|
||||
inline function& operator=(const function& rhs)
|
||||
{
|
||||
tidy();
|
||||
callable_ = rhs.callable_;
|
||||
if (callable_) callable_->retain();
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline function& operator=(function&& rhs)
|
||||
{
|
||||
tidy();
|
||||
callable_ = rhs.callable_;
|
||||
rhs.callable_ = nullptr;
|
||||
return (*this);
|
||||
}
|
||||
|
||||
private:
|
||||
inline void tidy()
|
||||
{
|
||||
if (callable_)
|
||||
{
|
||||
callable_->release();
|
||||
callable_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
__function_detail::callable<_Ret, _Args...>* callable_;
|
||||
};
|
||||
|
||||
template<typename _Ty,
|
||||
typename _Uty,
|
||||
typename = typename std::enable_if<
|
||||
std::is_same<_Ty, _Uty>::value || std::is_base_of<_Ty, _Uty>::value, int
|
||||
>::type,
|
||||
typename _Ret,
|
||||
typename... _Args
|
||||
>
|
||||
inline function<_Ret(_Args...)> closure(_Uty* ptr, _Ret(_Ty::* func)(_Args...))
|
||||
{
|
||||
return function<_Ret(_Args...)>(ptr, func);
|
||||
}
|
||||
|
||||
template<typename _Ty,
|
||||
typename _Uty,
|
||||
typename = typename std::enable_if<
|
||||
std::is_same<_Ty, _Uty>::value || std::is_base_of<_Ty, _Uty>::value, int
|
||||
>::type,
|
||||
typename _Ret,
|
||||
typename... _Args
|
||||
>
|
||||
inline function<_Ret(_Args...)> closure(_Uty* ptr, _Ret(_Ty::* func)(_Args...) const)
|
||||
{
|
||||
return function<_Ret(_Args...)>(ptr, func);
|
||||
}
|
||||
|
||||
|
||||
template<typename _Ret, typename... _Args>
|
||||
inline void swap(oc::function<_Ret(_Args...)>& lhs, oc::function<_Ret(_Args...)>& rhs) noexcept
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
} // namespace oc
|
||||
|
|
@ -1,168 +0,0 @@
|
|||
// Copyright (c) 2019-2020 OuterC - Nomango
|
||||
|
||||
#pragma once
|
||||
#include <type_traits>
|
||||
|
||||
namespace oc
|
||||
{
|
||||
namespace __function_detail
|
||||
{
|
||||
|
||||
template <typename _Ty, typename _Ret, typename... _Args>
|
||||
struct is_callable_helper
|
||||
{
|
||||
template <typename _Uty, _Ret(_Uty::*)(_Args...)>
|
||||
struct class_mem;
|
||||
|
||||
template <typename _Uty, _Ret(_Uty::*)(_Args...) const>
|
||||
struct class_const_mem;
|
||||
|
||||
template <typename _Uty>
|
||||
static int test(...);
|
||||
|
||||
template <typename _Uty>
|
||||
static char test(class_mem<_Uty, &_Uty::operator()>*);
|
||||
|
||||
template <typename _Uty>
|
||||
static char test(class_const_mem<_Uty, &_Uty::operator()>*);
|
||||
|
||||
template<
|
||||
typename _Uty,
|
||||
typename _Uret = typename std::decay<decltype(std::declval<_Uty>().operator()(std::declval<_Args>()...))>::type,
|
||||
typename = typename std::enable_if<std::is_convertible<_Ret, _Uret>::value>::type
|
||||
>
|
||||
static char test(int);
|
||||
|
||||
static constexpr bool value = sizeof(test<_Ty>(0)) == sizeof(char);
|
||||
};
|
||||
|
||||
template<typename _Ty, typename _Ret, typename... _Args>
|
||||
struct is_callable
|
||||
: public ::std::bool_constant<is_callable_helper<_Ty, _Ret, _Args...>::value>
|
||||
{
|
||||
};
|
||||
|
||||
//
|
||||
// callable
|
||||
//
|
||||
|
||||
template<typename _Ret, typename... _Args>
|
||||
class callable
|
||||
{
|
||||
public:
|
||||
virtual ~callable() {}
|
||||
|
||||
virtual void retain() = 0;
|
||||
virtual void release() = 0;
|
||||
virtual _Ret invoke(_Args... args) const = 0;
|
||||
};
|
||||
|
||||
template<typename _Ret, typename... _Args>
|
||||
class ref_count_callable
|
||||
: public callable<_Ret, _Args...>
|
||||
{
|
||||
public:
|
||||
ref_count_callable() : ref_count_(0) {}
|
||||
|
||||
virtual void retain() override
|
||||
{
|
||||
++ref_count_;
|
||||
}
|
||||
|
||||
virtual void release() override
|
||||
{
|
||||
--ref_count_;
|
||||
if (ref_count_ <= 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int ref_count_;
|
||||
};
|
||||
|
||||
template<typename _Ty, typename _Ret, typename... _Args>
|
||||
class proxy_callable
|
||||
: public ref_count_callable<_Ret, _Args...>
|
||||
{
|
||||
public:
|
||||
proxy_callable(_Ty&& val)
|
||||
: callee_(::std::move(val))
|
||||
{
|
||||
}
|
||||
|
||||
virtual _Ret invoke(_Args... args) const override
|
||||
{
|
||||
return callee_(::std::forward<_Args&&>(args)...);
|
||||
}
|
||||
|
||||
static inline callable<_Ret, _Args...>* make(_Ty&& val)
|
||||
{
|
||||
return new (::std::nothrow) proxy_callable<_Ty, _Ret, _Args...>(::std::move(val));
|
||||
}
|
||||
|
||||
private:
|
||||
_Ty callee_;
|
||||
};
|
||||
|
||||
template<typename _Ty, typename _Ret, typename... _Args>
|
||||
class proxy_mem_callable
|
||||
: public ref_count_callable<_Ret, _Args...>
|
||||
{
|
||||
public:
|
||||
typedef _Ret(_Ty::* _FuncType)(_Args...);
|
||||
|
||||
virtual _Ret invoke(_Args... args) const override
|
||||
{
|
||||
return (ptr_->*func_)(::std::forward<_Args>(args)...);
|
||||
}
|
||||
|
||||
static inline callable<_Ret, _Args...>* make(_Ty* ptr, _FuncType func)
|
||||
{
|
||||
return new (::std::nothrow) proxy_mem_callable<_Ty, _Ret, _Args...>(ptr, func);
|
||||
}
|
||||
|
||||
protected:
|
||||
proxy_mem_callable(_Ty* ptr, _FuncType func)
|
||||
: ptr_(ptr)
|
||||
, func_(func)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
_Ty* ptr_;
|
||||
_FuncType func_;
|
||||
};
|
||||
|
||||
template<typename _Ty, typename _Ret, typename... _Args>
|
||||
class proxy_const_mem_callable
|
||||
: public ref_count_callable<_Ret, _Args...>
|
||||
{
|
||||
public:
|
||||
typedef _Ret(_Ty::* _FuncType)(_Args...) const;
|
||||
|
||||
virtual _Ret invoke(_Args... args) const override
|
||||
{
|
||||
return (ptr_->*func_)(::std::forward<_Args>(args)...);
|
||||
}
|
||||
|
||||
static inline callable<_Ret, _Args...>* make(_Ty* ptr, _FuncType func)
|
||||
{
|
||||
return new (::std::nothrow) proxy_const_mem_callable<_Ty, _Ret, _Args...>(ptr, func);
|
||||
}
|
||||
|
||||
protected:
|
||||
proxy_const_mem_callable(_Ty* ptr, _FuncType func)
|
||||
: ptr_(ptr)
|
||||
, func_(func)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
_Ty* ptr_;
|
||||
_FuncType func_;
|
||||
};
|
||||
|
||||
} // namespace __function_detail
|
||||
} // namespace oc
|
||||
|
|
@ -1,258 +0,0 @@
|
|||
// Copyright (c) 2019-2020 OuterC - Nomango
|
||||
|
||||
#pragma once
|
||||
#include <type_traits>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
#include "macros.h"
|
||||
|
||||
namespace oc
|
||||
{
|
||||
|
||||
template <typename _Ty, typename _PTy = typename std::pointer_traits<_Ty>::pointer>
|
||||
class intrusive_list;
|
||||
|
||||
template <typename _Ty, typename _PTy = typename std::pointer_traits<_Ty>::pointer>
|
||||
class intrusive_list_item
|
||||
{
|
||||
public:
|
||||
using pointer = _PTy;
|
||||
|
||||
intrusive_list_item() : prev_(nullptr), next_(nullptr) {}
|
||||
intrusive_list_item(pointer rhs) : prev_(nullptr), next_(nullptr) { if (rhs) { prev_ = rhs->prev_; next_ = rhs->next_; } }
|
||||
|
||||
const pointer prev_item() const { return prev_; }
|
||||
pointer prev_item() { return prev_; }
|
||||
const pointer next_item() const { return next_; }
|
||||
pointer next_item() { return next_; }
|
||||
|
||||
private:
|
||||
pointer prev_;
|
||||
pointer next_;
|
||||
|
||||
friend class intrusive_list<_Ty, _PTy>;
|
||||
};
|
||||
|
||||
|
||||
template <typename _Ty, typename _PTy>
|
||||
class intrusive_list
|
||||
{
|
||||
public:
|
||||
using value_type = typename std::pointer_traits<_PTy>::element_type;
|
||||
using pointer = _PTy;
|
||||
using reference = value_type&;
|
||||
|
||||
intrusive_list() : first_(), last_() {}
|
||||
~intrusive_list() { clear(); }
|
||||
|
||||
const pointer first_item() const { return first_; }
|
||||
pointer first_item() { return first_; }
|
||||
const pointer last_item() const { return last_; }
|
||||
pointer last_item() { return last_; }
|
||||
|
||||
inline bool empty() const
|
||||
{
|
||||
return first_ == nullptr;
|
||||
}
|
||||
|
||||
void push_back(pointer child)
|
||||
{
|
||||
if (child->prev_)
|
||||
child->prev_->next_ = child->next_;
|
||||
if (child->next_)
|
||||
child->next_->prev_ = child->prev_;
|
||||
|
||||
child->prev_ = last_;
|
||||
child->next_ = nullptr;
|
||||
|
||||
if (first_)
|
||||
{
|
||||
last_->next_ = child;
|
||||
}
|
||||
else
|
||||
{
|
||||
first_ = child;
|
||||
}
|
||||
|
||||
last_ = child;
|
||||
}
|
||||
|
||||
void push_front(pointer child)
|
||||
{
|
||||
if (child->prev_)
|
||||
child->prev_->next_ = child->next_;
|
||||
if (child->next_)
|
||||
child->next_->prev_ = child->prev_;
|
||||
|
||||
child->prev_ = nullptr;
|
||||
child->next_ = first_;
|
||||
|
||||
if (first_)
|
||||
{
|
||||
first_->prev_ = child;
|
||||
}
|
||||
else
|
||||
{
|
||||
last_ = child;
|
||||
}
|
||||
|
||||
first_ = child;
|
||||
}
|
||||
|
||||
void insert_before(pointer child, pointer before)
|
||||
{
|
||||
if (child->prev_)
|
||||
child->prev_->next_ = child->next_;
|
||||
if (child->next_)
|
||||
child->next_->prev_ = child->prev_;
|
||||
|
||||
if (before->prev_)
|
||||
before->prev_->next_ = child;
|
||||
else
|
||||
first_ = child;
|
||||
|
||||
child->prev_ = before->prev_;
|
||||
child->next_ = before;
|
||||
before->prev_ = child;
|
||||
}
|
||||
|
||||
void insert_after(pointer child, pointer after)
|
||||
{
|
||||
if (child->prev_)
|
||||
child->prev_->next_ = child->next_;
|
||||
if (child->next_)
|
||||
child->next_->prev_ = child->prev_;
|
||||
|
||||
if (after->next_)
|
||||
after->next_->prev_ = child;
|
||||
else
|
||||
last_ = child;
|
||||
|
||||
child->next_ = after->next_;
|
||||
child->prev_ = after;
|
||||
after->next_ = child;
|
||||
}
|
||||
|
||||
void remove(pointer child)
|
||||
{
|
||||
if (child->next_)
|
||||
{
|
||||
child->next_->prev_ = child->prev_;
|
||||
}
|
||||
else
|
||||
{
|
||||
last_ = child->prev_;
|
||||
}
|
||||
|
||||
if (child->prev_)
|
||||
{
|
||||
child->prev_->next_ = child->next_;
|
||||
}
|
||||
else
|
||||
{
|
||||
first_ = child->next_;
|
||||
}
|
||||
|
||||
child->prev_ = nullptr;
|
||||
child->next_ = nullptr;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
pointer p = first_;
|
||||
while (p)
|
||||
{
|
||||
pointer tmp = p;
|
||||
p = p->next_;
|
||||
if (tmp)
|
||||
{
|
||||
tmp->next_ = nullptr;
|
||||
tmp->prev_ = nullptr;
|
||||
}
|
||||
}
|
||||
first_ = nullptr;
|
||||
last_ = nullptr;
|
||||
}
|
||||
|
||||
void check_list()
|
||||
{
|
||||
if (!first_)
|
||||
return;
|
||||
|
||||
int pos = 0;
|
||||
pointer p = first_;
|
||||
pointer tmp = p;
|
||||
do
|
||||
{
|
||||
tmp = p;
|
||||
p = p->next_;
|
||||
++pos;
|
||||
|
||||
if (p)
|
||||
{
|
||||
OC_ASSERT(p->prev_ == tmp && "Check list failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
OC_ASSERT(tmp == last_ && "Check list failed");
|
||||
}
|
||||
} while (p);
|
||||
}
|
||||
|
||||
public:
|
||||
// Iterator
|
||||
template <typename _PTy>
|
||||
struct iterator_impl
|
||||
{
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using value_type = typename std::pointer_traits<_PTy>::element_type;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = _PTy;
|
||||
using reference = value_type&;
|
||||
|
||||
inline iterator_impl(pointer ptr = nullptr, bool is_end = false) : base_(ptr), is_end_(is_end) {}
|
||||
|
||||
inline pointer base() const { OC_ASSERT(!is_end_); return const_cast<pointer&>(base_); }
|
||||
inline reference operator*() const { OC_ASSERT(base_ && !is_end_); return const_cast<reference>(*base_); }
|
||||
inline pointer operator->() const { OC_ASSERT(base_ && !is_end_); return const_cast<pointer&>(base_); }
|
||||
inline iterator_impl& operator++() { OC_ASSERT(base_ && !is_end_); pointer next = base_->next_item(); if (next) base_ = next; else is_end_ = true; return (*this); }
|
||||
inline iterator_impl operator++(int) { iterator_impl old = (*this); ++(*this); return old; }
|
||||
inline iterator_impl& operator--() { OC_ASSERT(base_); if (is_end_) is_end_ = false; else base_ = pointer(base_->prev_item()); return (*this); }
|
||||
inline iterator_impl operator--(int) { iterator_impl old = (*this); --(*this); return old; }
|
||||
inline bool operator==(iterator_impl const& other) const { return base_ == other.base_ && is_end_ == other.is_end_; }
|
||||
inline bool operator!=(iterator_impl const& other) const { return !(*this == other); }
|
||||
inline operator bool() const { return base_ != nullptr && !is_end_; }
|
||||
|
||||
private:
|
||||
bool is_end_;
|
||||
pointer base_;
|
||||
};
|
||||
|
||||
using iterator = iterator_impl<pointer>;
|
||||
using const_iterator = iterator_impl<const pointer>;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
inline iterator begin() { return iterator(first_item(), first_item() == nullptr); }
|
||||
inline const_iterator begin() const { return const_iterator(first_item(), first_item() == nullptr); }
|
||||
inline const_iterator cbegin() const { return begin(); }
|
||||
inline iterator end() { return iterator(last_item(), true); }
|
||||
inline const_iterator end() const { return const_iterator(last_item(), true); }
|
||||
inline const_iterator cend() const { return end(); }
|
||||
inline reverse_iterator rbegin() { return reverse_iterator(end()); }
|
||||
inline const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
|
||||
inline const_reverse_iterator crbegin() const { return rbegin(); }
|
||||
inline reverse_iterator rend() { return reverse_iterator(begin()); }
|
||||
inline const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
|
||||
inline const_reverse_iterator crend() const { return rend(); }
|
||||
inline pointer front() { if (empty()) throw std::out_of_range("front() called on empty intrusive_list"); return first_item(); }
|
||||
inline const pointer front() const { if (empty()) throw std::out_of_range("front() called on empty intrusive_list"); return first_item(); }
|
||||
inline pointer back() { if (empty()) throw std::out_of_range("back() called on empty intrusive_list"); return last_item(); }
|
||||
inline const pointer back() const { if (empty()) throw std::out_of_range("back() called on empty intrusive_list"); return last_item(); }
|
||||
|
||||
private:
|
||||
pointer first_;
|
||||
pointer last_;
|
||||
};
|
||||
|
||||
} // namespace oc
|
||||
|
|
@ -1,201 +0,0 @@
|
|||
// Copyright (c) 2019-2020 OuterC - Nomango
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining lhs 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 <utility>
|
||||
#include <type_traits>
|
||||
#include <atomic>
|
||||
#include "macros.h"
|
||||
|
||||
namespace oc
|
||||
{
|
||||
|
||||
template <typename _Ty, typename _ProxyTy>
|
||||
class intrusive_ptr
|
||||
{
|
||||
public:
|
||||
using value_type = _Ty;
|
||||
using pointer_type = _Ty*;
|
||||
using const_pointer_type = const _Ty*;
|
||||
using reference_type = _Ty&;
|
||||
using const_reference_type = const _Ty&;
|
||||
using ref_proxy_type = _ProxyTy;
|
||||
|
||||
intrusive_ptr() noexcept : ptr_(nullptr) {}
|
||||
intrusive_ptr(std::nullptr_t) noexcept : ptr_(nullptr) {}
|
||||
intrusive_ptr(pointer_type p) : ptr_(p) { typename ref_proxy_type::add_ref(ptr_); }
|
||||
intrusive_ptr(const intrusive_ptr& other) : ptr_(other.ptr_) { typename ref_proxy_type::add_ref(ptr_); }
|
||||
intrusive_ptr(intrusive_ptr&& other) noexcept : ptr_(nullptr) { swap(other); }
|
||||
~intrusive_ptr() { tidy(); }
|
||||
|
||||
template <typename _UTy>
|
||||
intrusive_ptr(const intrusive_ptr<_UTy, ref_proxy_type>& other) { ptr_ = const_cast<pointer_type>(dynamic_cast<const_pointer_type>(other.get())); typename ref_proxy_type::add_ref(ptr_); }
|
||||
|
||||
inline pointer_type get() noexcept { return ptr_; }
|
||||
inline const_pointer_type get() const noexcept { return ptr_; }
|
||||
inline void reset(pointer_type ptr = nullptr) { if (ptr) intrusive_ptr(ptr).swap(*this); else tidy(); }
|
||||
inline void swap(intrusive_ptr& other) noexcept { std::swap(ptr_, other.ptr_); }
|
||||
|
||||
inline pointer_type operator ->() { OC_ASSERT(ptr_ != nullptr && "Invalid pointer"); return ptr_; }
|
||||
inline const_pointer_type operator ->() const { OC_ASSERT(ptr_ != nullptr && "Invalid pointer"); return ptr_; }
|
||||
inline reference_type operator *() { OC_ASSERT(ptr_ != nullptr && "Invalid pointer"); return *ptr_; }
|
||||
inline const_reference_type operator *() const { OC_ASSERT(ptr_ != nullptr && "Invalid pointer"); return *ptr_; }
|
||||
inline pointer_type* operator &() { OC_ASSERT(ptr_ == nullptr && "Memory leak"); return &ptr_; }
|
||||
inline operator bool() const noexcept { return ptr_ != nullptr; }
|
||||
inline bool operator !() const noexcept { return ptr_ == 0; }
|
||||
|
||||
inline intrusive_ptr& operator=(const intrusive_ptr& other) { if (other.ptr_ != ptr_) intrusive_ptr(other).swap(*this); return (*this); }
|
||||
inline intrusive_ptr& operator=(intrusive_ptr&& other) noexcept { if (other.ptr_ != ptr_) other.swap(*this); return (*this); }
|
||||
inline intrusive_ptr& operator=(pointer_type p) { if (p != ptr_) intrusive_ptr(p).swap(*this); return (*this); }
|
||||
inline intrusive_ptr& operator=(std::nullptr_t) { tidy(); return *this; }
|
||||
|
||||
private:
|
||||
void tidy()
|
||||
{
|
||||
typename ref_proxy_type::release(ptr_);
|
||||
ptr_ = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
pointer_type ptr_;
|
||||
};
|
||||
|
||||
template <class _Ty, class _UTy, class _ProxyTy>
|
||||
inline bool operator==(intrusive_ptr<_Ty, _ProxyTy> const& lhs, intrusive_ptr<_UTy, _ProxyTy> const& rhs) noexcept
|
||||
{
|
||||
return lhs.get() == rhs.get();
|
||||
}
|
||||
|
||||
template <class _Ty, class _ProxyTy>
|
||||
inline bool operator==(intrusive_ptr<_Ty, _ProxyTy> const& lhs, _Ty* rhs) noexcept
|
||||
{
|
||||
return lhs.get() == rhs;
|
||||
}
|
||||
|
||||
template <class _Ty, class _ProxyTy>
|
||||
inline bool operator==(_Ty* lhs, intrusive_ptr<_Ty, _ProxyTy> const& rhs) noexcept
|
||||
{
|
||||
return lhs == rhs.get();
|
||||
}
|
||||
|
||||
template <class _Ty, class _ProxyTy>
|
||||
inline bool operator==(intrusive_ptr<_Ty, _ProxyTy> const& lhs, std::nullptr_t) noexcept
|
||||
{
|
||||
return !static_cast<bool>(lhs);
|
||||
}
|
||||
|
||||
template <class _Ty, class _ProxyTy>
|
||||
inline bool operator==(std::nullptr_t, intrusive_ptr<_Ty, _ProxyTy> const& rhs) noexcept
|
||||
{
|
||||
return !static_cast<bool>(rhs);
|
||||
}
|
||||
|
||||
template <class _Ty, class _UTy, class _ProxyTy>
|
||||
inline bool operator!=(intrusive_ptr<_Ty, _ProxyTy> const& lhs, intrusive_ptr<_UTy, _ProxyTy> const& rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template <class _Ty, class _ProxyTy>
|
||||
inline bool operator!=(intrusive_ptr<_Ty, _ProxyTy> const& lhs, _Ty* rhs) noexcept
|
||||
{
|
||||
return lhs.get() != rhs;
|
||||
}
|
||||
|
||||
template <class _Ty, class _ProxyTy>
|
||||
inline bool operator!=(_Ty* lhs, intrusive_ptr<_Ty, _ProxyTy> const& rhs) noexcept
|
||||
{
|
||||
return lhs != rhs.get();
|
||||
}
|
||||
|
||||
template <class _Ty, class _ProxyTy>
|
||||
inline bool operator!=(intrusive_ptr<_Ty, _ProxyTy> const& lhs, std::nullptr_t) noexcept
|
||||
{
|
||||
return static_cast<bool>(lhs);
|
||||
}
|
||||
|
||||
template <class _Ty, class _ProxyTy>
|
||||
inline bool operator!=(std::nullptr_t, intrusive_ptr<_Ty, _ProxyTy> const& rhs) noexcept
|
||||
{
|
||||
return static_cast<bool>(rhs);
|
||||
}
|
||||
|
||||
template <class _Ty, class _UTy, class _ProxyTy>
|
||||
inline bool operator<(intrusive_ptr<_Ty, _ProxyTy> const& lhs, intrusive_ptr<_UTy, _ProxyTy> const& rhs) noexcept
|
||||
{
|
||||
return lhs.get() < rhs.get();
|
||||
}
|
||||
|
||||
// template class cannot specialize std::swap,
|
||||
// so implement a swap Function in oc namespace
|
||||
template <class _Ty, class _ProxyTy>
|
||||
inline void swap(intrusive_ptr<_Ty, _ProxyTy>& lhs, intrusive_ptr<_Ty, _ProxyTy>& rhs) noexcept
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
|
||||
class intrusive_ref
|
||||
{
|
||||
public:
|
||||
void add_ref()
|
||||
{
|
||||
++ref_count_;
|
||||
}
|
||||
|
||||
void release()
|
||||
{
|
||||
--ref_count_;
|
||||
if (ref_count_ == 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
int16_t get_ref() const
|
||||
{
|
||||
return ref_count_;
|
||||
}
|
||||
|
||||
protected:
|
||||
intrusive_ref()
|
||||
: ref_count_(0)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<int16_t> ref_count_;
|
||||
};
|
||||
|
||||
|
||||
class intrusive_ref_proxy
|
||||
{
|
||||
public:
|
||||
static inline void add_ref(intrusive_ref* ptr) { if (ptr) ptr->add_ref(); }
|
||||
|
||||
static inline void release(intrusive_ref* ptr) { if (ptr) ptr->release(); }
|
||||
};
|
||||
|
||||
template<
|
||||
typename _Ty,
|
||||
typename = typename std::enable_if<std::is_base_of<intrusive_ref, _Ty>::value, int>::type>
|
||||
using intrusive_ref_ptr = intrusive_ptr<_Ty, intrusive_ref_proxy>;
|
||||
|
||||
} // namespace oc
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
// Copyright (c) 2019-2020 OuterC - Nomango
|
||||
|
||||
#pragma once
|
||||
#include <map>
|
||||
#include "vector.h"
|
||||
#include "string.h"
|
||||
#include "json/basic_json.h"
|
||||
|
||||
namespace oc
|
||||
{
|
||||
|
||||
using json = oc::basic_json<std::map, oc::vector, oc::string, int, double, bool, std::allocator>;
|
||||
using wjson = oc::basic_json<std::map, oc::vector, oc::wstring, int, double, bool, std::allocator>;
|
||||
|
||||
} // namespace oc
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template<>
|
||||
struct hash<::oc::json>
|
||||
{
|
||||
size_t operator()(const ::oc::json& json) const
|
||||
{
|
||||
return hash<::oc::json::string_type>{}(json.dump());
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct hash<::oc::wjson>
|
||||
{
|
||||
size_t operator()(const ::oc::wjson& json) const
|
||||
{
|
||||
return hash<::oc::wjson::string_type>{}(json.dump());
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
inline void swap<::oc::json>(::oc::json& lhs, ::oc::json& rhs) noexcept
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void swap<::oc::wjson>(::oc::wjson& lhs, ::oc::wjson& rhs) noexcept
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,929 +0,0 @@
|
|||
// Copyright (c) 2019-2020 OuterC - Nomango
|
||||
|
||||
#pragma once
|
||||
#include "json_exception.h"
|
||||
#include "json_value.h"
|
||||
#include "json_iterator.h"
|
||||
#include "json_serializer.h"
|
||||
#include "json_parser.h"
|
||||
#include "json_value_getter.h"
|
||||
|
||||
namespace oc
|
||||
{
|
||||
|
||||
#define OC_DECLARE_BASIC_JSON_TEMPLATE\
|
||||
template <\
|
||||
template <class _Kty, class _Ty, class ..._Args> typename _ObjectTy, \
|
||||
template <class _Kty, class ..._Args> typename _ArrayTy, \
|
||||
typename _StringTy, \
|
||||
typename _IntegerTy, \
|
||||
typename _FloatTy, \
|
||||
typename _BooleanTy, \
|
||||
template <class _Ty> typename _Allocator>
|
||||
|
||||
#define OC_DECLARE_BASIC_JSON_TPL_ARGS \
|
||||
_ObjectTy, _ArrayTy, _StringTy, _IntegerTy, _FloatTy, _BooleanTy, _Allocator
|
||||
|
||||
|
||||
OC_DECLARE_BASIC_JSON_TEMPLATE
|
||||
class basic_json;
|
||||
|
||||
|
||||
//
|
||||
// is_basic_json
|
||||
//
|
||||
|
||||
template <typename>
|
||||
struct is_basic_json
|
||||
: std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
OC_DECLARE_BASIC_JSON_TEMPLATE
|
||||
struct is_basic_json< basic_json<OC_DECLARE_BASIC_JSON_TPL_ARGS> >
|
||||
: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
OC_DECLARE_BASIC_JSON_TEMPLATE
|
||||
class basic_json
|
||||
{
|
||||
friend struct __json_detail::iterator_impl<basic_json>;
|
||||
friend struct __json_detail::iterator_impl<const basic_json>;
|
||||
friend struct __json_detail::json_serializer<basic_json>;
|
||||
friend struct __json_detail::json_parser<basic_json>;
|
||||
friend struct __json_detail::json_value_getter<basic_json>;
|
||||
|
||||
public:
|
||||
template <typename _Ty>
|
||||
using allocator_type = _Allocator<_Ty>;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using string_type = _StringTy;
|
||||
using char_type = typename _StringTy::value_type;
|
||||
using integer_type = _IntegerTy;
|
||||
using float_type = _FloatTy;
|
||||
using boolean_type = _BooleanTy;
|
||||
using array_type = typename _ArrayTy<basic_json, allocator_type<basic_json>>;
|
||||
using object_type = typename _ObjectTy<string_type, basic_json, std::less<string_type>, allocator_type<std::pair<const string_type, basic_json>>>;
|
||||
using initializer_list = std::initializer_list<basic_json>;
|
||||
|
||||
using iterator = __json_detail::iterator_impl<basic_json>;
|
||||
using const_iterator = __json_detail::iterator_impl<const basic_json>;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
public:
|
||||
basic_json() {}
|
||||
|
||||
basic_json(std::nullptr_t) {}
|
||||
|
||||
basic_json(const json_type type) : value_(type) {}
|
||||
|
||||
basic_json(basic_json const& other) : value_(other.value_) {}
|
||||
|
||||
basic_json(basic_json&& other) noexcept : value_(std::move(other.value_))
|
||||
{
|
||||
// invalidate payload
|
||||
other.value_.type = json_type::NIL;
|
||||
other.value_.data.object = nullptr;
|
||||
}
|
||||
|
||||
basic_json(string_type const& value) : value_(value) {}
|
||||
|
||||
template <
|
||||
typename _CompatibleTy,
|
||||
typename std::enable_if<std::is_constructible<string_type, _CompatibleTy>::value, int>::type = 0>
|
||||
basic_json(const _CompatibleTy& value)
|
||||
{
|
||||
value_.type = json_type::STRING;
|
||||
value_.data.string = value_.template create<string_type>(value);
|
||||
}
|
||||
|
||||
basic_json(array_type const& arr)
|
||||
: value_(arr)
|
||||
{
|
||||
}
|
||||
|
||||
basic_json(object_type const& object)
|
||||
: value_(object)
|
||||
{
|
||||
}
|
||||
|
||||
basic_json(integer_type value)
|
||||
: value_(value)
|
||||
{
|
||||
}
|
||||
|
||||
template <
|
||||
typename _IntegerTy,
|
||||
typename std::enable_if<std::is_integral<_IntegerTy>::value, int>::type = 0>
|
||||
basic_json(_IntegerTy value)
|
||||
: value_(static_cast<integer_type>(value))
|
||||
{
|
||||
}
|
||||
|
||||
basic_json(float_type value)
|
||||
: value_(value)
|
||||
{
|
||||
}
|
||||
|
||||
template <
|
||||
typename _FloatingTy,
|
||||
typename std::enable_if<std::is_floating_point<_FloatingTy>::value, int>::type = 0>
|
||||
basic_json(_FloatingTy value)
|
||||
: value_(static_cast<float_type>(value))
|
||||
{
|
||||
}
|
||||
|
||||
basic_json(boolean_type value)
|
||||
: value_(value)
|
||||
{
|
||||
}
|
||||
|
||||
basic_json(initializer_list const& init_list)
|
||||
{
|
||||
bool is_an_object = std::all_of(init_list.begin(), init_list.end(), [](const basic_json& json)
|
||||
{
|
||||
return (json.is_array() && json.size() == 2 && json[0].is_string());
|
||||
});
|
||||
|
||||
if (is_an_object)
|
||||
{
|
||||
value_ = json_type::OBJECT;
|
||||
|
||||
std::for_each(init_list.begin(), init_list.end(), [this](const basic_json& json)
|
||||
{
|
||||
value_.data.object->emplace(
|
||||
*((*json.value_.data.vector)[0].value_.data.string),
|
||||
(*json.value_.data.vector)[1]
|
||||
);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
value_ = json_type::VECTOR;
|
||||
value_.data.vector->reserve(init_list.size());
|
||||
value_.data.vector->assign(init_list.begin(), init_list.end());
|
||||
}
|
||||
}
|
||||
|
||||
static inline basic_json object(initializer_list const& init_list)
|
||||
{
|
||||
if (init_list.size() != 2 || !(*init_list.begin()).is_string())
|
||||
{
|
||||
throw json_type_error("cannot create object from initializer_list");
|
||||
}
|
||||
|
||||
basic_json json;
|
||||
json.value_ = json_type::OBJECT;
|
||||
json.value_.data.object->emplace(*((*init_list.begin()).value_.data.string), *(init_list.begin() + 1));
|
||||
return json;
|
||||
}
|
||||
|
||||
static inline basic_json array(initializer_list const& init_list)
|
||||
{
|
||||
basic_json json;
|
||||
json.value_ = json_type::VECTOR;
|
||||
|
||||
if (init_list.size())
|
||||
{
|
||||
json.value_.data.vector->reserve(init_list.size());
|
||||
json.value_.data.vector->assign(init_list.begin(), init_list.end());
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
inline bool is_object() const { return value_.type == json_type::OBJECT; }
|
||||
|
||||
inline bool is_array() const { return value_.type == json_type::VECTOR; }
|
||||
|
||||
inline bool is_string() const { return value_.type == json_type::STRING; }
|
||||
|
||||
inline bool is_boolean() const { return value_.type == json_type::BOOL; }
|
||||
|
||||
inline bool is_integer() const { return value_.type == json_type::INTEGER; }
|
||||
|
||||
inline bool is_float() const { return value_.type == json_type::FLOAT; }
|
||||
|
||||
inline bool is_number() const { return is_integer() || is_float(); }
|
||||
|
||||
inline bool is_null() const { return value_.type == json_type::NIL; }
|
||||
|
||||
inline json_type type() const { return value_.type; }
|
||||
|
||||
inline string_type type_name() const
|
||||
{
|
||||
switch (type())
|
||||
{
|
||||
case json_type::OBJECT:
|
||||
return string_type(L"object");
|
||||
case json_type::VECTOR:
|
||||
return string_type(L"array");
|
||||
case json_type::STRING:
|
||||
return string_type(L"string");
|
||||
case json_type::INTEGER:
|
||||
return string_type(L"integer");
|
||||
case json_type::FLOAT:
|
||||
return string_type(L"float");
|
||||
case json_type::BOOL:
|
||||
return string_type(L"boolean");
|
||||
case json_type::NIL:
|
||||
return string_type(L"null");
|
||||
}
|
||||
return string_type();
|
||||
}
|
||||
|
||||
inline void swap(basic_json& rhs) { value_.swap(rhs.value_); }
|
||||
|
||||
public:
|
||||
|
||||
inline iterator begin() { iterator iter(this); iter.set_begin(); return iter; }
|
||||
inline const_iterator begin() const { return cbegin(); }
|
||||
inline const_iterator cbegin() const { const_iterator iter(this); iter.set_begin(); return iter; }
|
||||
inline iterator end() { iterator iter(this); iter.set_end(); return iter; }
|
||||
inline const_iterator end() const { return cend(); }
|
||||
inline const_iterator cend() const { const_iterator iter(this); iter.set_end(); return iter; }
|
||||
inline reverse_iterator rbegin() { return reverse_iterator(end()); }
|
||||
inline const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
|
||||
inline const_reverse_iterator crbegin() const { return rbegin(); }
|
||||
inline reverse_iterator rend() { return reverse_iterator(begin()); }
|
||||
inline const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
|
||||
inline const_reverse_iterator crend() const { return rend(); }
|
||||
|
||||
public:
|
||||
inline size_type size() const
|
||||
{
|
||||
switch (type())
|
||||
{
|
||||
case json_type::NIL:
|
||||
return 0;
|
||||
case json_type::VECTOR:
|
||||
return value_.data.vector->size();
|
||||
case json_type::OBJECT:
|
||||
return value_.data.object->size();
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool empty() const
|
||||
{
|
||||
if (is_null())
|
||||
return true;
|
||||
|
||||
if (is_object())
|
||||
return value_.data.object->empty();
|
||||
|
||||
if (is_array())
|
||||
return value_.data.vector->empty();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename _Kty>
|
||||
inline const_iterator find(_Kty && key) const
|
||||
{
|
||||
if (is_object())
|
||||
{
|
||||
const_iterator iter;
|
||||
iter.object_iter = value_.data.object->find(std::forward<_Kty>(key));
|
||||
return iter;
|
||||
}
|
||||
return cend();
|
||||
}
|
||||
|
||||
template <typename _Kty>
|
||||
inline size_type count(_Kty && key) const
|
||||
{
|
||||
return is_object() ? value_.data.object->count(std::forward<_Kty>(key)) : 0;
|
||||
}
|
||||
|
||||
inline size_type erase(const typename object_type::key_type& key)
|
||||
{
|
||||
if (!is_object())
|
||||
{
|
||||
throw json_invalid_key("cannot use erase() with non-object value");
|
||||
}
|
||||
return value_.data.object->erase(key);
|
||||
}
|
||||
|
||||
inline void erase(const size_type index)
|
||||
{
|
||||
if (!is_array())
|
||||
{
|
||||
throw json_invalid_key("cannot use erase() with non-array value");
|
||||
}
|
||||
value_.data.vector->erase(value_.data.vector->begin() + static_cast<difference_type>(index));
|
||||
}
|
||||
|
||||
template<
|
||||
class _IteratorTy,
|
||||
typename std::enable_if<
|
||||
std::is_same<_IteratorTy, iterator>::value ||
|
||||
std::is_same<_IteratorTy, const_iterator>::value, int
|
||||
>::type = 0>
|
||||
inline _IteratorTy erase(_IteratorTy pos)
|
||||
{
|
||||
_IteratorTy result = end();
|
||||
|
||||
switch (type())
|
||||
{
|
||||
case json_type::OBJECT:
|
||||
{
|
||||
result.object_iter = value_.data.object->erase(pos.object_iter);
|
||||
break;
|
||||
}
|
||||
|
||||
case json_type::VECTOR:
|
||||
{
|
||||
result.array_iter = value_.data.vector->erase(pos.array_iter);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw json_invalid_iterator("cannot use erase() with non-object & non-array value");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<
|
||||
class _IteratorTy,
|
||||
typename std::enable_if<
|
||||
std::is_same<_IteratorTy, iterator>::value ||
|
||||
std::is_same<_IteratorTy, const_iterator>::value, int
|
||||
>::type = 0>
|
||||
inline _IteratorTy erase(_IteratorTy first, _IteratorTy last)
|
||||
{
|
||||
_IteratorTy result = end();
|
||||
|
||||
switch (type())
|
||||
{
|
||||
case json_type::OBJECT:
|
||||
{
|
||||
result.object_iter = value_.data.object->erase(first.object_iter, last.object_iter);
|
||||
break;
|
||||
}
|
||||
|
||||
case json_type::VECTOR:
|
||||
{
|
||||
result.array_iter = value_.data.vector->erase(first.array_iter, last.array_iter);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw json_invalid_iterator("cannot use erase() with non-object & non-array value");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void push_back(basic_json&& json)
|
||||
{
|
||||
if (!is_null() && !is_array())
|
||||
{
|
||||
throw json_type_error("cannot use push_back() with non-array value");
|
||||
}
|
||||
|
||||
if (is_null())
|
||||
{
|
||||
value_ = json_type::VECTOR;
|
||||
}
|
||||
|
||||
value_.data.vector->push_back(std::move(json));
|
||||
}
|
||||
|
||||
inline basic_json& operator+=(basic_json&& json)
|
||||
{
|
||||
push_back(std::move(json));
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline void clear()
|
||||
{
|
||||
switch (type())
|
||||
{
|
||||
case json_type::INTEGER:
|
||||
{
|
||||
value_.data.number_integer = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case json_type::FLOAT:
|
||||
{
|
||||
value_.data.number_float = static_cast<float_type>(0.0);
|
||||
break;
|
||||
}
|
||||
|
||||
case json_type::BOOL:
|
||||
{
|
||||
value_.data.boolean = false;
|
||||
break;
|
||||
}
|
||||
|
||||
case json_type::STRING:
|
||||
{
|
||||
value_.data.string->clear();
|
||||
break;
|
||||
}
|
||||
|
||||
case json_type::VECTOR:
|
||||
{
|
||||
value_.data.vector->clear();
|
||||
break;
|
||||
}
|
||||
|
||||
case json_type::OBJECT:
|
||||
{
|
||||
value_.data.object->clear();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
// GET value functions
|
||||
|
||||
inline bool get_value(boolean_type& val) const
|
||||
{
|
||||
if (is_boolean())
|
||||
{
|
||||
val = value_.data.boolean;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool get_value(integer_type& val) const
|
||||
{
|
||||
if (is_integer())
|
||||
{
|
||||
val = value_.data.number_integer;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool get_value(float_type& val) const
|
||||
{
|
||||
if (is_float())
|
||||
{
|
||||
val = value_.data.number_float;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <
|
||||
typename _IntegerTy,
|
||||
typename std::enable_if<std::is_integral<_IntegerTy>::value, int>::type = 0>
|
||||
inline bool get_value(_IntegerTy& val) const
|
||||
{
|
||||
if (is_integer())
|
||||
{
|
||||
val = static_cast<_IntegerTy>(value_.data.number_integer);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <
|
||||
typename _FloatingTy,
|
||||
typename std::enable_if<std::is_floating_point<_FloatingTy>::value, int>::type = 0>
|
||||
inline bool get_value(_FloatingTy& val) const
|
||||
{
|
||||
if (is_float())
|
||||
{
|
||||
val = static_cast<_FloatingTy>(value_.data.number_float);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool get_value(array_type& val) const
|
||||
{
|
||||
if (is_array())
|
||||
{
|
||||
val.assign((*value_.data.vector).begin(), (*value_.data.vector).end());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool get_value(string_type& val) const
|
||||
{
|
||||
if (is_string())
|
||||
{
|
||||
val.assign(*value_.data.string);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool get_value(object_type& val) const
|
||||
{
|
||||
if (is_object())
|
||||
{
|
||||
val.assign(*value_.data.object);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean_type as_bool() const
|
||||
{
|
||||
if (!is_boolean()) throw json_type_error("json value must be boolean");
|
||||
return value_.data.boolean;
|
||||
}
|
||||
|
||||
integer_type as_int() const
|
||||
{
|
||||
if (!is_integer()) throw json_type_error("json value must be integer");
|
||||
return value_.data.number_integer;
|
||||
}
|
||||
|
||||
float_type as_float() const
|
||||
{
|
||||
if (!is_float()) throw json_type_error("json value must be float");
|
||||
return value_.data.number_float;
|
||||
}
|
||||
|
||||
const array_type& as_array() const
|
||||
{
|
||||
if (!is_array()) throw json_type_error("json value must be array");
|
||||
return *value_.data.vector;
|
||||
}
|
||||
|
||||
const string_type& as_string() const
|
||||
{
|
||||
if (!is_string()) throw json_type_error("json value must be string");
|
||||
return *value_.data.string;
|
||||
}
|
||||
|
||||
const object_type& as_object() const
|
||||
{
|
||||
if (!is_object()) throw json_type_error("json value must be object");
|
||||
return *value_.data.object;
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
_Ty get() const
|
||||
{
|
||||
_Ty value;
|
||||
__json_detail::json_value_getter<basic_json>::assign(*this, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public:
|
||||
// operator= functions
|
||||
|
||||
inline basic_json& operator=(basic_json const& other)
|
||||
{
|
||||
value_ = other.value_;
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline basic_json& operator=(basic_json&& other) noexcept
|
||||
{
|
||||
value_ = std::move(other.value_);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline basic_json& operator=(std::nullptr_t)
|
||||
{
|
||||
value_ = nullptr;
|
||||
return (*this);
|
||||
}
|
||||
|
||||
public:
|
||||
// operator[] functions
|
||||
|
||||
inline basic_json& operator[](size_type index)
|
||||
{
|
||||
if (is_null())
|
||||
{
|
||||
value_ = json_type::VECTOR;
|
||||
}
|
||||
|
||||
if (!is_array())
|
||||
{
|
||||
throw json_invalid_key("operator[] called on a non-array object");
|
||||
}
|
||||
|
||||
if (index >= value_.data.vector->size())
|
||||
{
|
||||
value_.data.vector->insert(value_.data.vector->end(),
|
||||
index - value_.data.vector->size() + 1,
|
||||
basic_json()
|
||||
);
|
||||
}
|
||||
return (*value_.data.vector)[index];
|
||||
}
|
||||
|
||||
inline basic_json& operator[](size_type index) const
|
||||
{
|
||||
if (!is_array())
|
||||
{
|
||||
throw json_invalid_key("operator[] called on a non-array type");
|
||||
}
|
||||
|
||||
if (index >= value_.data.vector->size())
|
||||
{
|
||||
throw std::out_of_range("operator[] index out of range");
|
||||
}
|
||||
return (*value_.data.vector)[index];
|
||||
}
|
||||
|
||||
inline basic_json& operator[](const typename object_type::key_type& key)
|
||||
{
|
||||
if (is_null())
|
||||
{
|
||||
value_ = json_type::OBJECT;
|
||||
}
|
||||
|
||||
if (!is_object())
|
||||
{
|
||||
throw json_invalid_key("operator[] called on a non-object type");
|
||||
}
|
||||
return (*value_.data.object)[key];
|
||||
}
|
||||
|
||||
inline basic_json& operator[](const typename object_type::key_type& key) const
|
||||
{
|
||||
if (!is_object())
|
||||
{
|
||||
throw json_invalid_key("operator[] called on a non-object object");
|
||||
}
|
||||
|
||||
auto iter = value_.data.object->find(key);
|
||||
if (iter == value_.data.object->end())
|
||||
{
|
||||
throw std::out_of_range("operator[] key out of range");
|
||||
}
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
template <typename _CharT>
|
||||
inline basic_json& operator[](_CharT* key)
|
||||
{
|
||||
if (is_null())
|
||||
{
|
||||
value_ = json_type::OBJECT;
|
||||
}
|
||||
|
||||
if (!is_object())
|
||||
{
|
||||
throw json_invalid_key("operator[] called on a non-object object");
|
||||
}
|
||||
return (*value_.data.object)[key];
|
||||
}
|
||||
|
||||
template <typename _CharT>
|
||||
inline basic_json& operator[](_CharT* key) const
|
||||
{
|
||||
if (!is_object())
|
||||
{
|
||||
throw json_invalid_key("operator[] called on a non-object object");
|
||||
}
|
||||
|
||||
auto iter = value_.data.object->find(key);
|
||||
if (iter == value_.data.object->end())
|
||||
{
|
||||
throw std::out_of_range("operator[] key out of range");
|
||||
}
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
public:
|
||||
// implicitly convert functions
|
||||
|
||||
inline operator boolean_type () const
|
||||
{
|
||||
return as_bool();
|
||||
}
|
||||
|
||||
inline operator integer_type () const
|
||||
{
|
||||
return as_int();
|
||||
}
|
||||
|
||||
inline operator float_type () const
|
||||
{
|
||||
return as_float();
|
||||
}
|
||||
|
||||
inline operator const array_type& () const
|
||||
{
|
||||
return as_array();
|
||||
}
|
||||
|
||||
inline operator const string_type& () const
|
||||
{
|
||||
return as_string();
|
||||
}
|
||||
|
||||
inline operator const object_type& () const
|
||||
{
|
||||
return as_object();
|
||||
}
|
||||
|
||||
public:
|
||||
// dumps functions
|
||||
|
||||
string_type dump(
|
||||
const int indent = -1,
|
||||
const char_type indent_char = ' ',
|
||||
const bool char_escape = true) const
|
||||
{
|
||||
string_type result;
|
||||
__json_detail::string_output_adapter<string_type> adapter(result);
|
||||
dump(&adapter, indent, indent_char, char_escape);
|
||||
return result;
|
||||
}
|
||||
|
||||
void dump(
|
||||
__json_detail::output_adapter<char_type>* adapter,
|
||||
const int indent = -1,
|
||||
const char_type indent_char = ' ',
|
||||
const bool char_escape = true) const
|
||||
{
|
||||
__json_detail::json_serializer<basic_json>(adapter, indent_char).dump(*this, (indent >= 0), char_escape, static_cast<uint32_t>(indent));
|
||||
}
|
||||
|
||||
friend std::basic_ostream<char_type>& operator<<(std::basic_ostream<char_type>& out, const basic_json& json)
|
||||
{
|
||||
using char_type = typename std::basic_ostream<char_type>::char_type;
|
||||
|
||||
const bool pretty_print = (out.width() > 0);
|
||||
const auto indentation = (pretty_print ? out.width() : 0);
|
||||
out.width(0);
|
||||
|
||||
__json_detail::stream_output_adapter<char_type> adapter(out);
|
||||
__json_detail::json_serializer<basic_json>(&adapter, out.fill()).dump(json, pretty_print, true, static_cast<uint32_t>(indentation));
|
||||
return out;
|
||||
}
|
||||
|
||||
public:
|
||||
// parse functions
|
||||
|
||||
static inline basic_json parse(const string_type& str)
|
||||
{
|
||||
__json_detail::string_input_adapter<string_type> adapter(str);
|
||||
return parse(&adapter);
|
||||
}
|
||||
|
||||
static inline basic_json parse(const char_type* str)
|
||||
{
|
||||
__json_detail::buffer_input_adapter<char_type> adapter(str);
|
||||
return parse(&adapter);
|
||||
}
|
||||
|
||||
static inline basic_json parse(std::FILE* file)
|
||||
{
|
||||
__json_detail::file_input_adapter<char_type> adapter(file);
|
||||
return parse(&adapter);
|
||||
}
|
||||
|
||||
static inline basic_json parse(__json_detail::input_adapter<char_type>* adapter)
|
||||
{
|
||||
basic_json result;
|
||||
__json_detail::json_parser<basic_json>(adapter).parse(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
friend std::basic_istream<char_type>&
|
||||
operator>>(std::basic_istream<char_type>& in, basic_json& json)
|
||||
{
|
||||
__json_detail::stream_input_adapter<char_type> adapter(in);
|
||||
__json_detail::json_parser<basic_json>(&adapter).parse(json);
|
||||
return in;
|
||||
}
|
||||
|
||||
public:
|
||||
// compare functions
|
||||
|
||||
friend bool operator==(const basic_json& lhs, const basic_json& rhs)
|
||||
{
|
||||
const auto lhs_type = lhs.type();
|
||||
const auto rhs_type = rhs.type();
|
||||
|
||||
if (lhs_type == rhs_type)
|
||||
{
|
||||
switch (lhs_type)
|
||||
{
|
||||
case json_type::VECTOR:
|
||||
return (*lhs.value_.data.vector == *rhs.value_.data.vector);
|
||||
|
||||
case json_type::OBJECT:
|
||||
return (*lhs.value_.data.object == *rhs.value_.data.object);
|
||||
|
||||
case json_type::NIL:
|
||||
return true;
|
||||
|
||||
case json_type::STRING:
|
||||
return (*lhs.value_.data.string == *rhs.value_.data.string);
|
||||
|
||||
case json_type::BOOL:
|
||||
return (lhs.value_.data.boolean == rhs.value_.data.boolean);
|
||||
|
||||
case json_type::INTEGER:
|
||||
return (lhs.value_.data.number_integer == rhs.value_.data.number_integer);
|
||||
|
||||
case json_type::FLOAT:
|
||||
return (lhs.value_.data.number_float == rhs.value_.data.number_float);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (lhs_type == json_type::INTEGER && rhs_type == json_type::FLOAT)
|
||||
{
|
||||
return (static_cast<float_type>(lhs.value_.data.number_integer) == rhs.value_.data.number_float);
|
||||
}
|
||||
else if (lhs_type == json_type::FLOAT && rhs_type == json_type::INTEGER)
|
||||
{
|
||||
return (lhs.value_.data.number_float == static_cast<float_type>(rhs.value_.data.number_integer));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
friend bool operator!=(const basic_json& lhs, const basic_json& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
friend bool operator<(const basic_json& lhs, const basic_json& rhs)
|
||||
{
|
||||
const auto lhs_type = lhs.type();
|
||||
const auto rhs_type = rhs.type();
|
||||
|
||||
if (lhs_type == rhs_type)
|
||||
{
|
||||
switch (lhs_type)
|
||||
{
|
||||
case json_type::VECTOR:
|
||||
return (*lhs.value_.data.vector) < (*rhs.value_.data.vector);
|
||||
|
||||
case json_type::OBJECT:
|
||||
return (*lhs.value_.data.object) < (*rhs.value_.data.object);
|
||||
|
||||
case json_type::NIL:
|
||||
return false;
|
||||
|
||||
case json_type::STRING:
|
||||
return (*lhs.value_.data.string) < (*rhs.value_.data.string);
|
||||
|
||||
case json_type::BOOL:
|
||||
return (lhs.value_.data.boolean < rhs.value_.data.boolean);
|
||||
|
||||
case json_type::INTEGER:
|
||||
return (lhs.value_.data.number_integer < rhs.value_.data.number_integer);
|
||||
|
||||
case json_type::FLOAT:
|
||||
return (lhs.value_.data.number_float < rhs.value_.data.number_float);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (lhs_type == json_type::INTEGER && rhs_type == json_type::FLOAT)
|
||||
{
|
||||
return (static_cast<float_type>(lhs.value_.data.number_integer) < rhs.value_.data.number_float);
|
||||
}
|
||||
else if (lhs_type == json_type::FLOAT && rhs_type == json_type::INTEGER)
|
||||
{
|
||||
return (lhs.value_.data.number_float < static_cast<float_type>(rhs.value_.data.number_integer));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
friend bool operator<=(const basic_json& lhs, const basic_json& rhs)
|
||||
{
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
friend bool operator>(const basic_json& lhs, const basic_json& rhs)
|
||||
{
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
friend bool operator>=(const basic_json& lhs, const basic_json& rhs)
|
||||
{
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
private:
|
||||
__json_detail::json_value<basic_json> value_;
|
||||
};
|
||||
|
||||
} // namespace oc
|
||||
|
||||
#undef OC_DECLARE_BASIC_JSON_TEMPLATE
|
||||
#undef OC_DECLARE_BASIC_JSON_TPL_ARGS
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
// Copyright (c) 2019-2020 OuterC - Nomango
|
||||
|
||||
#pragma once
|
||||
#include <stdexcept>
|
||||
#include "json_value.h"
|
||||
|
||||
namespace oc
|
||||
{
|
||||
|
||||
class json_exception
|
||||
: public std::runtime_error
|
||||
{
|
||||
public:
|
||||
json_exception(const char* message)
|
||||
: std::runtime_error(message)
|
||||
{}
|
||||
};
|
||||
|
||||
class json_type_error
|
||||
: public json_exception
|
||||
{
|
||||
public:
|
||||
json_type_error(const char* message) : json_exception(message) {}
|
||||
};
|
||||
|
||||
class json_invalid_key
|
||||
: public json_exception
|
||||
{
|
||||
public:
|
||||
json_invalid_key(const char* message) : json_exception(message) {}
|
||||
};
|
||||
|
||||
class json_invalid_iterator
|
||||
: public json_exception
|
||||
{
|
||||
public:
|
||||
json_invalid_iterator(const char* message) : json_exception(message) {}
|
||||
};
|
||||
|
||||
class json_parse_error
|
||||
: public json_exception
|
||||
{
|
||||
public:
|
||||
json_parse_error(const char* message) : json_exception(message) {}
|
||||
};
|
||||
|
||||
} // namespace oc
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
// Copyright (c) 2019-2020 OuterC - Nomango
|
||||
|
||||
#pragma once
|
||||
#include <iosfwd>
|
||||
|
||||
namespace oc
|
||||
{
|
||||
namespace __json_detail
|
||||
{
|
||||
|
||||
template <typename _CharTy>
|
||||
struct input_adapter
|
||||
{
|
||||
using char_type = _CharTy;
|
||||
using char_traits = std::char_traits<char_type>;
|
||||
|
||||
virtual typename char_traits::int_type get_char() = 0;
|
||||
virtual ~input_adapter() = default;
|
||||
};
|
||||
|
||||
template <typename _CharTy>
|
||||
struct file_input_adapter
|
||||
: public input_adapter<_CharTy>
|
||||
{
|
||||
using char_type = typename input_adapter<_CharTy>::char_type;
|
||||
using char_traits = typename input_adapter<_CharTy>::char_traits;
|
||||
|
||||
file_input_adapter(std::FILE* file) : file(file) {}
|
||||
|
||||
virtual typename char_traits::int_type get_char() override
|
||||
{
|
||||
return std::fgetc(file);
|
||||
}
|
||||
|
||||
private:
|
||||
std::FILE* file;
|
||||
};
|
||||
|
||||
template <typename _CharTy>
|
||||
struct stream_input_adapter
|
||||
: public input_adapter<_CharTy>
|
||||
{
|
||||
using char_type = typename input_adapter<_CharTy>::char_type;
|
||||
using char_traits = typename input_adapter<_CharTy>::char_traits;
|
||||
|
||||
stream_input_adapter(std::basic_istream<char_type>& stream) : stream(stream), streambuf(*stream.rdbuf()) {}
|
||||
|
||||
virtual typename char_traits::int_type get_char() override
|
||||
{
|
||||
auto ch = streambuf.sbumpc();
|
||||
if (ch == EOF)
|
||||
{
|
||||
stream.clear(stream.rdstate() | std::ios::eofbit);
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
virtual ~stream_input_adapter()
|
||||
{
|
||||
stream.clear(stream.rdstate() & std::ios::eofbit);
|
||||
}
|
||||
|
||||
private:
|
||||
std::basic_istream<char_type>& stream;
|
||||
std::basic_streambuf<char_type>& streambuf;
|
||||
};
|
||||
|
||||
template <typename _StringTy>
|
||||
struct string_input_adapter
|
||||
: public input_adapter<typename _StringTy::value_type>
|
||||
{
|
||||
using char_type = typename input_adapter<typename _StringTy::value_type>::char_type;
|
||||
using char_traits = typename input_adapter<typename _StringTy::value_type>::char_traits;
|
||||
|
||||
string_input_adapter(const _StringTy& str) : str(str), index(0) {}
|
||||
|
||||
virtual typename char_traits::int_type get_char() override
|
||||
{
|
||||
if (index == str.size())
|
||||
return char_traits::eof();
|
||||
return str[index++];
|
||||
}
|
||||
|
||||
private:
|
||||
const _StringTy& str;
|
||||
typename _StringTy::size_type index;
|
||||
};
|
||||
|
||||
template <typename _CharTy>
|
||||
struct buffer_input_adapter
|
||||
: public input_adapter<_CharTy>
|
||||
{
|
||||
using char_type = typename input_adapter<_CharTy>::char_type;
|
||||
using char_traits = typename input_adapter<_CharTy>::char_traits;
|
||||
|
||||
buffer_input_adapter(const _CharTy* str) : str(str), index(0) {}
|
||||
|
||||
virtual typename char_traits::int_type get_char() override
|
||||
{
|
||||
if (str[index] == '\0')
|
||||
return char_traits::eof();
|
||||
return str[index++];
|
||||
}
|
||||
|
||||
private:
|
||||
const char_type* str;
|
||||
uint32_t index;
|
||||
};
|
||||
|
||||
} // namespace __json_detail
|
||||
|
||||
} // namespace oc
|
||||
|
|
@ -1,377 +0,0 @@
|
|||
// Copyright (c) 2019-2020 OuterC - Nomango
|
||||
|
||||
#pragma once
|
||||
#include <cctype>
|
||||
|
||||
namespace oc
|
||||
{
|
||||
namespace __json_detail
|
||||
{
|
||||
|
||||
struct primitive_iterator
|
||||
{
|
||||
using difference_type = ptrdiff_t;
|
||||
|
||||
inline primitive_iterator(difference_type it = 0) : it_(it) {}
|
||||
|
||||
inline void set_begin() { it_ = 0; }
|
||||
inline void set_end() { it_ = 1; }
|
||||
|
||||
inline primitive_iterator& operator++() { ++it_; return *this; }
|
||||
|
||||
inline primitive_iterator operator++(int) { primitive_iterator old(it_); ++(*this); return old; }
|
||||
|
||||
inline primitive_iterator& operator--() { --it_; return (*this); }
|
||||
inline primitive_iterator operator--(int) { primitive_iterator old = (*this); --(*this); return old; }
|
||||
|
||||
inline bool operator==(primitive_iterator const& other) const { return it_ == other.it_; }
|
||||
inline bool operator!=(primitive_iterator const& other) const { return !(*this == other); }
|
||||
|
||||
inline const primitive_iterator operator+(difference_type off) const { return primitive_iterator(it_ + off); }
|
||||
inline const primitive_iterator operator-(difference_type off) const { return primitive_iterator(it_ - off); }
|
||||
|
||||
inline primitive_iterator& operator+=(difference_type off) { it_ += off; return (*this); }
|
||||
inline primitive_iterator& operator-=(difference_type off) { it_ -= off; return (*this); }
|
||||
|
||||
inline difference_type operator-(primitive_iterator const& other) const { return it_ - other.it_; }
|
||||
|
||||
inline bool operator<(primitive_iterator const& other) const { return it_ < other.it_; }
|
||||
inline bool operator<=(primitive_iterator const& other) const { return it_ <= other.it_; }
|
||||
inline bool operator>(primitive_iterator const& other) const { return it_ > other.it_; }
|
||||
inline bool operator>=(primitive_iterator const& other) const { return it_ >= other.it_; }
|
||||
|
||||
private:
|
||||
difference_type it_;
|
||||
};
|
||||
|
||||
template <typename _BasicJsonTy>
|
||||
struct iterator_impl
|
||||
{
|
||||
friend _BasicJsonTy;
|
||||
|
||||
using string_type = typename _BasicJsonTy::string_type;
|
||||
using char_type = typename _BasicJsonTy::char_type;
|
||||
using integer_type = typename _BasicJsonTy::integer_type;
|
||||
using float_type = typename _BasicJsonTy::float_type;
|
||||
using boolean_type = typename _BasicJsonTy::boolean_type;
|
||||
using array_type = typename _BasicJsonTy::array_type;
|
||||
using object_type = typename _BasicJsonTy::object_type;
|
||||
|
||||
using value_type = _BasicJsonTy;
|
||||
using difference_type = ptrdiff_t;
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
|
||||
using array_iterator = typename _BasicJsonTy::array_type::iterator;
|
||||
using object_iterator = typename _BasicJsonTy::object_type::iterator;
|
||||
|
||||
inline iterator_impl(pointer json = nullptr) : data_(json), primitive_iter(0), array_iter(), object_iter() {}
|
||||
|
||||
inline iterator_impl(const iterator_impl& rhs) : iterator_impl()
|
||||
{
|
||||
operator=(rhs);
|
||||
}
|
||||
|
||||
~iterator_impl() {}
|
||||
|
||||
inline iterator_impl& operator=(const iterator_impl& rhs)
|
||||
{
|
||||
data_ = rhs.data_;
|
||||
if (data_)
|
||||
{
|
||||
switch (data_->type())
|
||||
{
|
||||
case json_type::OBJECT:
|
||||
object_iter = rhs.object_iter;
|
||||
break;
|
||||
case json_type::VECTOR:
|
||||
array_iter = rhs.array_iter;
|
||||
break;
|
||||
default:
|
||||
primitive_iter = rhs.primitive_iter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline reference operator*() const
|
||||
{
|
||||
check_data();
|
||||
check_iterator();
|
||||
switch (data_->type())
|
||||
{
|
||||
case json_type::OBJECT:
|
||||
return (object_iter->second);
|
||||
case json_type::VECTOR:
|
||||
return (*array_iter);
|
||||
default:
|
||||
return *data_;
|
||||
}
|
||||
}
|
||||
|
||||
inline pointer operator->() const
|
||||
{
|
||||
check_data();
|
||||
check_iterator();
|
||||
switch (data_->type())
|
||||
{
|
||||
case json_type::OBJECT:
|
||||
return &(object_iter->second);
|
||||
case json_type::VECTOR:
|
||||
return &(*array_iter);
|
||||
default:
|
||||
return data_;
|
||||
}
|
||||
}
|
||||
|
||||
inline const typename object_type::key_type& key() const
|
||||
{
|
||||
check_data();
|
||||
check_iterator();
|
||||
if (!data_->is_object())
|
||||
throw json_invalid_iterator("cannot use key() with non-object type");
|
||||
return object_iter->first;
|
||||
}
|
||||
|
||||
inline reference value() const
|
||||
{
|
||||
return operator*();
|
||||
}
|
||||
|
||||
inline void set_begin()
|
||||
{
|
||||
check_data();
|
||||
|
||||
switch (data_->type())
|
||||
{
|
||||
case json_type::OBJECT:
|
||||
{
|
||||
object_iter = data_->value_.data.object->begin();
|
||||
break;
|
||||
}
|
||||
case json_type::VECTOR:
|
||||
{
|
||||
array_iter = data_->value_.data.vector->begin();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
primitive_iter.set_begin();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void set_end()
|
||||
{
|
||||
check_data();
|
||||
|
||||
switch (data_->type())
|
||||
{
|
||||
case json_type::OBJECT:
|
||||
{
|
||||
object_iter = data_->value_.data.object->end();
|
||||
break;
|
||||
}
|
||||
case json_type::VECTOR:
|
||||
{
|
||||
array_iter = data_->value_.data.vector->end();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
primitive_iter.set_end();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline iterator_impl operator++(int) { iterator_impl old = (*this); ++(*this); return old; }
|
||||
inline iterator_impl& operator++()
|
||||
{
|
||||
check_data();
|
||||
|
||||
switch (data_->type())
|
||||
{
|
||||
case json_type::OBJECT:
|
||||
{
|
||||
std::advance(object_iter, 1);
|
||||
break;
|
||||
}
|
||||
case json_type::VECTOR:
|
||||
{
|
||||
std::advance(array_iter, 1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
++primitive_iter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline iterator_impl operator--(int) { iterator_impl old = (*this); --(*this); return old; }
|
||||
inline iterator_impl& operator--()
|
||||
{
|
||||
check_data();
|
||||
|
||||
switch (data_->type())
|
||||
{
|
||||
case json_type::OBJECT:
|
||||
{
|
||||
std::advance(object_iter, -1);
|
||||
break;
|
||||
}
|
||||
case json_type::VECTOR:
|
||||
{
|
||||
std::advance(array_iter, -1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
--primitive_iter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline const iterator_impl operator-(difference_type off) const { return operator+(-off); }
|
||||
inline const iterator_impl operator+(difference_type off) const { iterator_impl ret(*this); ret += off; return ret; }
|
||||
|
||||
inline iterator_impl& operator-=(difference_type off) { return operator+=(-off); }
|
||||
inline iterator_impl& operator+=(difference_type off)
|
||||
{
|
||||
check_data();
|
||||
|
||||
switch (data_->type())
|
||||
{
|
||||
case json_type::OBJECT:
|
||||
{
|
||||
throw json_invalid_iterator("cannot use offsets with object type");
|
||||
break;
|
||||
}
|
||||
case json_type::VECTOR:
|
||||
{
|
||||
std::advance(array_iter, off);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
primitive_iter += off;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bool operator!=(iterator_impl const& other) const { return !(*this == other); }
|
||||
inline bool operator==(iterator_impl const& other) const
|
||||
{
|
||||
check_data();
|
||||
other.check_data();
|
||||
|
||||
if (data_ != other.data_)
|
||||
throw json_invalid_iterator("cannot compare iterators of different objects");
|
||||
|
||||
switch (data_->type())
|
||||
{
|
||||
case json_type::OBJECT:
|
||||
{
|
||||
return object_iter == other.object_iter;
|
||||
}
|
||||
case json_type::VECTOR:
|
||||
{
|
||||
return array_iter == other.array_iter;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return primitive_iter == other.primitive_iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline bool operator>(iterator_impl const& other) const { return other.operator<(*this); }
|
||||
inline bool operator>=(iterator_impl const& other) const { return !operator<(other); }
|
||||
inline bool operator<=(iterator_impl const& other) const { return !other.operator<(*this); }
|
||||
inline bool operator<(iterator_impl const& other) const
|
||||
{
|
||||
check_data();
|
||||
other.check_data();
|
||||
|
||||
if (data_ != other.data_)
|
||||
throw json_invalid_iterator("cannot compare iterators of different objects");
|
||||
|
||||
switch (data_->type())
|
||||
{
|
||||
case json_type::OBJECT:
|
||||
throw json_invalid_iterator("cannot compare iterators with object type");
|
||||
case json_type::VECTOR:
|
||||
return array_iter < other.array_iter;
|
||||
default:
|
||||
return primitive_iter < other.primitive_iter;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
inline void check_data() const
|
||||
{
|
||||
if (data_ == nullptr)
|
||||
{
|
||||
throw json_invalid_iterator("iterator contains an empty object");
|
||||
}
|
||||
}
|
||||
|
||||
inline void check_iterator() const
|
||||
{
|
||||
switch (data_->type())
|
||||
{
|
||||
case json_type::OBJECT:
|
||||
if (object_iter == data_->value_.data.object->end())
|
||||
{
|
||||
throw std::out_of_range("iterator out of range");
|
||||
}
|
||||
break;
|
||||
case json_type::VECTOR:
|
||||
if (array_iter == data_->value_.data.vector->end())
|
||||
{
|
||||
throw std::out_of_range("iterator out of range");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (primitive_iter == 1)
|
||||
{
|
||||
throw std::out_of_range("iterator out of range");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
pointer data_;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
array_iterator array_iter;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
object_iterator object_iter;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
primitive_iterator primitive_iter; // for other types
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace __json_detail
|
||||
|
||||
} // namespace oc
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
// Copyright (c) 2019-2020 OuterC - Nomango
|
||||
|
||||
#pragma once
|
||||
#include <iosfwd>
|
||||
|
||||
namespace oc
|
||||
{
|
||||
namespace __json_detail
|
||||
{
|
||||
|
||||
template <typename _CharTy>
|
||||
struct output_adapter
|
||||
{
|
||||
using char_type = _CharTy;
|
||||
using char_traits = std::char_traits<char_type>;
|
||||
|
||||
virtual void write(const _CharTy ch) = 0;
|
||||
virtual void write(const _CharTy* str, uint32_t size) = 0;
|
||||
virtual void write(const _CharTy* str)
|
||||
{
|
||||
const auto size = char_traits::length(str);
|
||||
write(str, static_cast<uint32_t>(size));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _StringTy>
|
||||
struct string_output_adapter
|
||||
: public output_adapter<typename _StringTy::value_type>
|
||||
{
|
||||
using char_type = typename _StringTy::value_type;
|
||||
using size_type = typename _StringTy::size_type;
|
||||
using char_traits = std::char_traits<char_type>;
|
||||
|
||||
string_output_adapter(_StringTy& str) : str_(str) {}
|
||||
|
||||
virtual void write(const char_type ch) override
|
||||
{
|
||||
str_.push_back(ch);
|
||||
}
|
||||
|
||||
virtual void write(const char_type* str, uint32_t size) override
|
||||
{
|
||||
str_.append(str, static_cast<size_type>(size));
|
||||
}
|
||||
|
||||
private:
|
||||
_StringTy& str_;
|
||||
};
|
||||
|
||||
template <typename _CharTy>
|
||||
struct stream_output_adapter
|
||||
: public output_adapter<_CharTy>
|
||||
{
|
||||
using char_type = _CharTy;
|
||||
using size_type = typename std::streamsize;
|
||||
using char_traits = std::char_traits<char_type>;
|
||||
|
||||
stream_output_adapter(std::basic_ostream<char_type>& stream) : stream_(stream) {}
|
||||
|
||||
virtual void write(const char_type ch) override
|
||||
{
|
||||
stream_.put(ch);
|
||||
}
|
||||
|
||||
virtual void write(const char_type* str, uint32_t size) override
|
||||
{
|
||||
stream_.write(str, static_cast<size_type>(size));
|
||||
}
|
||||
|
||||
private:
|
||||
std::basic_ostream<char_type>& stream_;
|
||||
};
|
||||
|
||||
} // namespace __json_detail
|
||||
|
||||
} // namespace oc
|
||||
|
|
@ -1,567 +0,0 @@
|
|||
// Copyright (c) 2019-2020 OuterC - Nomango
|
||||
|
||||
#pragma once
|
||||
#include "json_intput_adapter.h"
|
||||
|
||||
namespace oc
|
||||
{
|
||||
namespace __json_detail
|
||||
{
|
||||
|
||||
enum class token_type
|
||||
{
|
||||
UNINITIALIZED,
|
||||
|
||||
LITERAL_TRUE,
|
||||
LITERAL_FALSE,
|
||||
LITERAL_NULL,
|
||||
|
||||
VALUE_STRING,
|
||||
VALUE_INTEGER,
|
||||
VALUE_FLOAT,
|
||||
|
||||
BEGIN_ARRAY,
|
||||
END_ARRAY,
|
||||
|
||||
BEGIN_OBJECT,
|
||||
END_OBJECT,
|
||||
|
||||
NAME_SEPARATOR,
|
||||
VALUE_SEPARATOR,
|
||||
|
||||
PARSE_ERROR,
|
||||
|
||||
END_OF_INPUT
|
||||
};
|
||||
|
||||
template <typename _BasicJsonTy>
|
||||
struct json_lexer
|
||||
{
|
||||
using string_type = typename _BasicJsonTy::string_type;
|
||||
using char_type = typename _BasicJsonTy::char_type;
|
||||
using integer_type = typename _BasicJsonTy::integer_type;
|
||||
using float_type = typename _BasicJsonTy::float_type;
|
||||
using boolean_type = typename _BasicJsonTy::boolean_type;
|
||||
using array_type = typename _BasicJsonTy::array_type;
|
||||
using object_type = typename _BasicJsonTy::object_type;
|
||||
using char_traits = std::char_traits<char_type>;
|
||||
|
||||
json_lexer(input_adapter<char_type>* adapter) : adapter(adapter)
|
||||
{
|
||||
// read first char
|
||||
read_next();
|
||||
}
|
||||
|
||||
typename char_traits::int_type read_next()
|
||||
{
|
||||
current = adapter->get_char();
|
||||
return current;
|
||||
}
|
||||
|
||||
void skip_spaces()
|
||||
{
|
||||
while (current == ' ' || current == '\t' || current == '\n' || current == '\r')
|
||||
{
|
||||
read_next();
|
||||
}
|
||||
}
|
||||
|
||||
token_type scan()
|
||||
{
|
||||
skip_spaces();
|
||||
|
||||
token_type result = token_type::UNINITIALIZED;
|
||||
switch (current)
|
||||
{
|
||||
case '[':
|
||||
result = token_type::BEGIN_ARRAY;
|
||||
break;
|
||||
case ']':
|
||||
result = token_type::END_ARRAY;
|
||||
break;
|
||||
case '{':
|
||||
result = token_type::BEGIN_OBJECT;
|
||||
break;
|
||||
case '}':
|
||||
result = token_type::END_OBJECT;
|
||||
break;
|
||||
case ':':
|
||||
result = token_type::NAME_SEPARATOR;
|
||||
break;
|
||||
case ',':
|
||||
result = token_type::VALUE_SEPARATOR;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
return scan_literal("true", token_type::LITERAL_TRUE);
|
||||
case 'f':
|
||||
return scan_literal("false", token_type::LITERAL_FALSE);
|
||||
case 'n':
|
||||
return scan_literal("null", token_type::LITERAL_NULL);
|
||||
|
||||
case '\"':
|
||||
return scan_string();
|
||||
|
||||
case '-':
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
return scan_number();
|
||||
|
||||
case '\0':
|
||||
case char_traits::eof():
|
||||
return token_type::END_OF_INPUT;
|
||||
|
||||
// unexpected char
|
||||
default:
|
||||
return token_type::PARSE_ERROR;
|
||||
}
|
||||
|
||||
// skip current char
|
||||
read_next();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
token_type scan_literal(const char_type* text, token_type result)
|
||||
{
|
||||
for (uint32_t i = 0; text[i] != '\0'; ++i)
|
||||
{
|
||||
if (text[i] != char_traits::to_char_type(current))
|
||||
{
|
||||
return token_type::PARSE_ERROR;
|
||||
}
|
||||
read_next();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
token_type scan_string()
|
||||
{
|
||||
if (current != '\"')
|
||||
return token_type::PARSE_ERROR;
|
||||
|
||||
string_buffer.clear();
|
||||
|
||||
while (true)
|
||||
{
|
||||
const auto ch = read_next();
|
||||
switch (ch)
|
||||
{
|
||||
case char_traits::eof():
|
||||
{
|
||||
// unexpected end
|
||||
return token_type::PARSE_ERROR;
|
||||
}
|
||||
|
||||
case '\"':
|
||||
{
|
||||
// skip last `\"`
|
||||
read_next();
|
||||
return token_type::VALUE_STRING;
|
||||
}
|
||||
|
||||
case 0x00:
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
case 0x04:
|
||||
case 0x05:
|
||||
case 0x06:
|
||||
case 0x07:
|
||||
case 0x08:
|
||||
case 0x09:
|
||||
case 0x0A:
|
||||
case 0x0B:
|
||||
case 0x0C:
|
||||
case 0x0D:
|
||||
case 0x0E:
|
||||
case 0x0F:
|
||||
case 0x10:
|
||||
case 0x11:
|
||||
case 0x12:
|
||||
case 0x13:
|
||||
case 0x14:
|
||||
case 0x15:
|
||||
case 0x16:
|
||||
case 0x17:
|
||||
case 0x18:
|
||||
case 0x19:
|
||||
case 0x1A:
|
||||
case 0x1B:
|
||||
case 0x1C:
|
||||
case 0x1D:
|
||||
case 0x1E:
|
||||
case 0x1F:
|
||||
{
|
||||
// invalid control character
|
||||
return token_type::PARSE_ERROR;
|
||||
}
|
||||
|
||||
case '\\':
|
||||
{
|
||||
switch (read_next())
|
||||
{
|
||||
case '\"':
|
||||
string_buffer.push_back('\"');
|
||||
break;
|
||||
case '\\':
|
||||
string_buffer.push_back('\\');
|
||||
break;
|
||||
case '/':
|
||||
string_buffer.push_back('/');
|
||||
break;
|
||||
case 'b':
|
||||
string_buffer.push_back('\b');
|
||||
break;
|
||||
case 'f':
|
||||
string_buffer.push_back('\f');
|
||||
break;
|
||||
case 'n':
|
||||
string_buffer.push_back('\n');
|
||||
break;
|
||||
case 'r':
|
||||
string_buffer.push_back('\r');
|
||||
break;
|
||||
case 't':
|
||||
string_buffer.push_back('\t');
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
{
|
||||
// unicode escapes
|
||||
uint16_t byte = 0;
|
||||
|
||||
for (const auto factor : { 12, 8, 4, 0 })
|
||||
{
|
||||
const auto n = read_next();
|
||||
if (n >= L'0' && n <= L'9')
|
||||
{
|
||||
byte += ((n - L'0') << factor);
|
||||
}
|
||||
else if (n >= L'A' && n <= L'F')
|
||||
{
|
||||
byte += ((n - L'A' + 10) << factor);
|
||||
}
|
||||
else if (n >= L'a' && n <= L'f')
|
||||
{
|
||||
byte += ((n - L'a' + 10) << factor);
|
||||
}
|
||||
else
|
||||
{
|
||||
// '\u' must be followed by 4 hex digits
|
||||
return token_type::PARSE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
string_buffer.push_back(char_traits::to_char_type(byte));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
return token_type::PARSE_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
if (ch > 0x1F && ch < 0x7F)
|
||||
{
|
||||
string_buffer.push_back(char_traits::to_char_type(ch));
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
return token_type::PARSE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
token_type scan_number()
|
||||
{
|
||||
is_negative = false;
|
||||
number_value = static_cast<float_type>(0.0);
|
||||
|
||||
if (current == '-')
|
||||
{
|
||||
return scan_negative();
|
||||
}
|
||||
|
||||
if (current == '0')
|
||||
{
|
||||
return scan_zero();
|
||||
}
|
||||
|
||||
return scan_integer();
|
||||
}
|
||||
|
||||
token_type scan_negative()
|
||||
{
|
||||
if (current == '-')
|
||||
{
|
||||
is_negative = true;
|
||||
read_next();
|
||||
|
||||
return scan_integer();
|
||||
}
|
||||
return token_type::PARSE_ERROR;
|
||||
}
|
||||
|
||||
token_type scan_zero()
|
||||
{
|
||||
if (current == '0')
|
||||
{
|
||||
if (read_next() == '.')
|
||||
return scan_float();
|
||||
else
|
||||
return token_type::VALUE_INTEGER;
|
||||
}
|
||||
return token_type::PARSE_ERROR;
|
||||
}
|
||||
|
||||
token_type scan_integer()
|
||||
{
|
||||
if (std::isdigit(current))
|
||||
{
|
||||
number_value = static_cast<float_type>(current - '0');
|
||||
|
||||
while (true)
|
||||
{
|
||||
const auto ch = read_next();
|
||||
if (ch == '.')
|
||||
return scan_float();
|
||||
|
||||
if (ch == 'e' || ch == 'E')
|
||||
return scan_exponent();
|
||||
|
||||
if (std::isdigit(ch))
|
||||
number_value = number_value * 10 + (ch - '0');
|
||||
else
|
||||
break;
|
||||
}
|
||||
return token_type::VALUE_INTEGER;
|
||||
}
|
||||
return token_type::PARSE_ERROR;
|
||||
}
|
||||
|
||||
token_type scan_float()
|
||||
{
|
||||
if (current != '.')
|
||||
return token_type::PARSE_ERROR;
|
||||
|
||||
if (std::isdigit(read_next()))
|
||||
{
|
||||
float_type fraction = static_cast<float_type>(0.1);
|
||||
number_value += static_cast<float_type>(current - '0') * fraction;
|
||||
|
||||
while (true)
|
||||
{
|
||||
const auto ch = read_next();
|
||||
if (ch == 'e' || ch == 'E')
|
||||
return scan_exponent();
|
||||
|
||||
if (std::isdigit(ch))
|
||||
{
|
||||
fraction *= static_cast<float_type>(0.1);
|
||||
number_value += static_cast<float_type>(ch - '0') * fraction;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
return token_type::VALUE_FLOAT;
|
||||
}
|
||||
return token_type::PARSE_ERROR;
|
||||
}
|
||||
|
||||
token_type scan_exponent()
|
||||
{
|
||||
if (current != 'e' && current != 'E')
|
||||
return token_type::PARSE_ERROR;
|
||||
|
||||
// skip current char
|
||||
read_next();
|
||||
|
||||
if ((std::isdigit(current) && current != '0') || (current == '-') || (current == '+'))
|
||||
{
|
||||
float_type core = 10;
|
||||
if (current == '+')
|
||||
{
|
||||
read_next();
|
||||
}
|
||||
else if (current == '-')
|
||||
{
|
||||
core = static_cast<float_type>(0.1);
|
||||
read_next();
|
||||
}
|
||||
|
||||
uint32_t exponent = static_cast<uint32_t>(current - '0');
|
||||
while (std::isdigit(read_next()))
|
||||
{
|
||||
exponent = (exponent * 10) + static_cast<uint32_t>(current - '0');
|
||||
}
|
||||
|
||||
float_type power = 1;
|
||||
for (; exponent; exponent >>= 1, core *= core)
|
||||
if (exponent & 1)
|
||||
power *= core;
|
||||
|
||||
number_value *= power;
|
||||
return token_type::VALUE_FLOAT;
|
||||
}
|
||||
return token_type::PARSE_ERROR;
|
||||
}
|
||||
|
||||
integer_type token_to_integer() const
|
||||
{
|
||||
integer_type integer = static_cast<integer_type>(number_value);
|
||||
return is_negative ? -integer : integer;
|
||||
}
|
||||
|
||||
float_type token_to_float() const
|
||||
{
|
||||
return is_negative ? -number_value : number_value;
|
||||
}
|
||||
|
||||
string_type token_to_string() const
|
||||
{
|
||||
return string_buffer;
|
||||
}
|
||||
|
||||
private:
|
||||
input_adapter<char_type>* adapter;
|
||||
typename char_traits::int_type current;
|
||||
|
||||
bool is_negative;
|
||||
float_type number_value;
|
||||
string_type string_buffer;
|
||||
};
|
||||
|
||||
|
||||
template <typename _BasicJsonTy>
|
||||
struct json_parser
|
||||
{
|
||||
using string_type = typename _BasicJsonTy::string_type;
|
||||
using char_type = typename _BasicJsonTy::char_type;
|
||||
using integer_type = typename _BasicJsonTy::integer_type;
|
||||
using float_type = typename _BasicJsonTy::float_type;
|
||||
using boolean_type = typename _BasicJsonTy::boolean_type;
|
||||
using array_type = typename _BasicJsonTy::array_type;
|
||||
using object_type = typename _BasicJsonTy::object_type;
|
||||
using char_traits = std::char_traits<char_type>;
|
||||
|
||||
json_parser(input_adapter<char_type>* adapter)
|
||||
: lexer(adapter)
|
||||
, last_token(token_type::UNINITIALIZED)
|
||||
{}
|
||||
|
||||
void parse(_BasicJsonTy& json)
|
||||
{
|
||||
parse_value(json);
|
||||
|
||||
if (get_token() != token_type::END_OF_INPUT)
|
||||
throw json_parse_error("unexpected token, expect end");
|
||||
}
|
||||
|
||||
private:
|
||||
token_type get_token()
|
||||
{
|
||||
last_token = lexer.scan();
|
||||
return last_token;
|
||||
}
|
||||
|
||||
void parse_value(_BasicJsonTy& json)
|
||||
{
|
||||
switch (get_token())
|
||||
{
|
||||
case token_type::LITERAL_TRUE:
|
||||
json = json_type::BOOL;
|
||||
json.value_.data.boolean = true;
|
||||
break;
|
||||
|
||||
case token_type::LITERAL_FALSE:
|
||||
json = json_type::BOOL;
|
||||
json.value_.data.boolean = false;
|
||||
break;
|
||||
|
||||
case token_type::LITERAL_NULL:
|
||||
json = json_type::NIL;
|
||||
break;
|
||||
|
||||
case token_type::VALUE_STRING:
|
||||
json = lexer.token_to_string();
|
||||
break;
|
||||
|
||||
case token_type::VALUE_INTEGER:
|
||||
json = lexer.token_to_integer();
|
||||
break;
|
||||
|
||||
case token_type::VALUE_FLOAT:
|
||||
json = lexer.token_to_float();
|
||||
break;
|
||||
|
||||
case token_type::BEGIN_ARRAY:
|
||||
json = json_type::VECTOR;
|
||||
while (true)
|
||||
{
|
||||
json.value_.data.vector->push_back(_BasicJsonTy());
|
||||
parse_value(json.value_.data.vector->back());
|
||||
|
||||
// read ','
|
||||
if (get_token() != token_type::VALUE_SEPARATOR)
|
||||
break;
|
||||
}
|
||||
if (last_token != token_type::END_ARRAY)
|
||||
throw json_parse_error("unexpected token in array");
|
||||
break;
|
||||
|
||||
case token_type::BEGIN_OBJECT:
|
||||
json = json_type::OBJECT;
|
||||
while (true)
|
||||
{
|
||||
if (get_token() != token_type::VALUE_STRING)
|
||||
break;
|
||||
string_type key = lexer.token_to_string();
|
||||
|
||||
if (get_token() != token_type::NAME_SEPARATOR)
|
||||
break;
|
||||
|
||||
_BasicJsonTy object;
|
||||
parse_value(object);
|
||||
json.value_.data.object->insert(std::make_pair(key, object));
|
||||
|
||||
// read ','
|
||||
if (get_token() != token_type::VALUE_SEPARATOR)
|
||||
break;
|
||||
}
|
||||
if (last_token != token_type::END_OBJECT)
|
||||
throw json_parse_error("unexpected token in object");
|
||||
break;
|
||||
|
||||
default:
|
||||
// unexpected token
|
||||
throw json_parse_error("unexpected token");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
json_lexer<_BasicJsonTy> lexer;
|
||||
token_type last_token;
|
||||
};
|
||||
|
||||
} // namespace __json_detail
|
||||
|
||||
} // namespace oc
|
||||
|
|
@ -1,421 +0,0 @@
|
|||
// Copyright (c) 2019-2020 OuterC - Nomango
|
||||
|
||||
#pragma once
|
||||
#include "json_output_adapter.h"
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
namespace oc
|
||||
{
|
||||
|
||||
namespace __json_detail
|
||||
{
|
||||
|
||||
template <typename _CharTy>
|
||||
struct json_literaler
|
||||
{
|
||||
using char_type = _CharTy;
|
||||
using string_type = const char_type*;
|
||||
|
||||
static inline string_type value_separator() { return ",\n"; }
|
||||
|
||||
static inline string_type empty_object() { return "{}"; }
|
||||
static inline string_type object_begin() { return "{\n"; }
|
||||
static inline string_type object_key_begin() { return "\": "; }
|
||||
|
||||
static inline string_type empty_array() { return "[]"; }
|
||||
static inline string_type array_begin() { return "[\n"; }
|
||||
|
||||
static inline string_type literal_true() { return "true"; }
|
||||
static inline string_type literal_false() { return "false"; }
|
||||
static inline string_type literal_null() { return "null"; }
|
||||
|
||||
static inline string_type escape_t() { return "\\t"; }
|
||||
static inline string_type escape_r() { return "\\r"; }
|
||||
static inline string_type escape_n() { return "\\n"; }
|
||||
static inline string_type escape_b() { return "\\b"; }
|
||||
static inline string_type escape_f() { return "\\f"; }
|
||||
static inline string_type escape_quote() { return "\\\""; }
|
||||
static inline string_type escape_slash() { return "\\\\"; }
|
||||
|
||||
template <typename _FloatTy>
|
||||
static inline void sprint_float(char_type* buff, const _FloatTy value)
|
||||
{
|
||||
const auto digits = std::numeric_limits<_FloatTy>::max_digits10;
|
||||
const auto len = ::_scprintf("%.*g", digits, value);
|
||||
if (len)
|
||||
{
|
||||
buff[0] = '\0';
|
||||
::sprintf_s(buff, size_t(len) + 1, "%.*g", digits, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
buff[0] = '0';
|
||||
buff[1] = '.';
|
||||
buff[2] = '0';
|
||||
buff[3] = '\0';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct json_literaler<wchar_t>
|
||||
{
|
||||
using char_type = wchar_t;
|
||||
using string_type = const char_type*;
|
||||
|
||||
static inline string_type value_separator() { return L",\n"; }
|
||||
|
||||
static inline string_type empty_object() { return L"{}"; }
|
||||
static inline string_type object_begin() { return L"{\n"; }
|
||||
static inline string_type object_key_begin() { return L"\":"; }
|
||||
|
||||
static inline string_type empty_array() { return L"[]"; }
|
||||
static inline string_type array_begin() { return L"[\n"; }
|
||||
|
||||
static inline string_type literal_true() { return L"true"; }
|
||||
static inline string_type literal_false() { return L"false"; }
|
||||
static inline string_type literal_null() { return L"null"; }
|
||||
|
||||
static inline string_type escape_t() { return L"\\t"; }
|
||||
static inline string_type escape_r() { return L"\\r"; }
|
||||
static inline string_type escape_n() { return L"\\n"; }
|
||||
static inline string_type escape_b() { return L"\\b"; }
|
||||
static inline string_type escape_f() { return L"\\f"; }
|
||||
static inline string_type escape_quote() { return L"\\\""; }
|
||||
static inline string_type escape_slash() { return L"\\\\"; }
|
||||
|
||||
template <typename _FloatTy>
|
||||
static inline void sprint_float(char_type* buff, const _FloatTy value)
|
||||
{
|
||||
const auto digits = std::numeric_limits<_FloatTy>::max_digits10;
|
||||
const auto len = ::_scwprintf(L"%.*g", digits, value);
|
||||
if (len)
|
||||
{
|
||||
buff[0] = '\0';
|
||||
::swprintf_s(buff, size_t(len) + 1, L"%.*g", digits, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
buff[0] = '0';
|
||||
buff[1] = '.';
|
||||
buff[2] = '0';
|
||||
buff[3] = '\0';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _BasicJsonTy>
|
||||
struct json_serializer
|
||||
{
|
||||
using string_type = typename _BasicJsonTy::string_type;
|
||||
using char_type = typename _BasicJsonTy::char_type;
|
||||
using integer_type = typename _BasicJsonTy::integer_type;
|
||||
using float_type = typename _BasicJsonTy::float_type;
|
||||
using boolean_type = typename _BasicJsonTy::boolean_type;
|
||||
using array_type = typename _BasicJsonTy::array_type;
|
||||
using object_type = typename _BasicJsonTy::object_type;
|
||||
using literaler = json_literaler<char_type>;
|
||||
|
||||
json_serializer(output_adapter<char_type>* out, const char_type indent_char)
|
||||
: out(out)
|
||||
, indent_char(indent_char)
|
||||
, indent_string(32, indent_char)
|
||||
{}
|
||||
|
||||
void dump(
|
||||
const _BasicJsonTy& json,
|
||||
const bool pretty_print,
|
||||
const bool char_escape,
|
||||
const uint32_t indent_step,
|
||||
const uint32_t current_indent = 0)
|
||||
{
|
||||
switch (json.type())
|
||||
{
|
||||
case json_type::OBJECT:
|
||||
{
|
||||
auto& object = *json.value_.data.object;
|
||||
|
||||
if (object.empty())
|
||||
{
|
||||
out->write(literaler::empty_object());
|
||||
return;
|
||||
}
|
||||
|
||||
if (pretty_print)
|
||||
{
|
||||
out->write(literaler::object_begin());
|
||||
|
||||
const auto new_indent = current_indent + indent_step;
|
||||
if (indent_string.size() < new_indent)
|
||||
{
|
||||
indent_string.resize(indent_string.size() * 2, indent_char);
|
||||
}
|
||||
|
||||
auto iter = object.cbegin();
|
||||
const auto size = object.size();
|
||||
for (uint32_t i = 0; i < size; ++i, ++iter)
|
||||
{
|
||||
out->write(indent_string.c_str(), new_indent);
|
||||
out->write('\"');
|
||||
out->write(iter->first.c_str());
|
||||
out->write(literaler::object_key_begin());
|
||||
out->write(' ');
|
||||
dump(iter->second, pretty_print, char_escape, indent_step, new_indent);
|
||||
|
||||
// not last element
|
||||
if (i != size - 1)
|
||||
out->write(literaler::value_separator());
|
||||
}
|
||||
|
||||
out->write('\n');
|
||||
out->write(indent_string.c_str(), current_indent);
|
||||
out->write('}');
|
||||
}
|
||||
else
|
||||
{
|
||||
out->write('{');
|
||||
|
||||
auto iter = object.cbegin();
|
||||
const auto size = object.size();
|
||||
for (uint32_t i = 0; i < size; ++i, ++iter)
|
||||
{
|
||||
out->write('\"');
|
||||
out->write(iter->first.c_str());
|
||||
out->write(literaler::object_key_begin());
|
||||
dump(iter->second, pretty_print, char_escape, indent_step, current_indent);
|
||||
|
||||
// not last element
|
||||
if (i != size - 1)
|
||||
out->write(',');
|
||||
}
|
||||
|
||||
out->write('}');
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
case json_type::VECTOR:
|
||||
{
|
||||
auto& vector = *json.value_.data.vector;
|
||||
|
||||
if (vector.empty())
|
||||
{
|
||||
out->write(literaler::empty_array());
|
||||
return;
|
||||
}
|
||||
|
||||
if (pretty_print)
|
||||
{
|
||||
out->write(literaler::array_begin());
|
||||
|
||||
const auto new_indent = current_indent + indent_step;
|
||||
if (indent_string.size() < new_indent)
|
||||
{
|
||||
indent_string.resize(indent_string.size() * 2, indent_char);
|
||||
}
|
||||
|
||||
auto iter = vector.cbegin();
|
||||
const auto size = vector.size();
|
||||
for (uint32_t i = 0; i < size; ++i, ++iter)
|
||||
{
|
||||
out->write(indent_string.c_str(), new_indent);
|
||||
dump(*iter, pretty_print, char_escape, indent_step, new_indent);
|
||||
|
||||
// not last element
|
||||
if (i != size - 1)
|
||||
out->write(literaler::value_separator());
|
||||
}
|
||||
|
||||
out->write('\n');
|
||||
out->write(indent_string.c_str(), current_indent);
|
||||
out->write(']');
|
||||
}
|
||||
else
|
||||
{
|
||||
out->write('[');
|
||||
|
||||
auto iter = vector.cbegin();
|
||||
const auto size = vector.size();
|
||||
for (uint32_t i = 0; i < size; ++i, ++iter)
|
||||
{
|
||||
dump(*iter, pretty_print, char_escape, indent_step, current_indent);
|
||||
// not last element
|
||||
if (i != size - 1)
|
||||
out->write(',');
|
||||
}
|
||||
|
||||
out->write(']');
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
case json_type::STRING:
|
||||
{
|
||||
out->write('\"');
|
||||
dump_string(*json.value_.data.string, char_escape);
|
||||
out->write('\"');
|
||||
return;
|
||||
}
|
||||
|
||||
case json_type::BOOL:
|
||||
{
|
||||
if (json.value_.data.boolean)
|
||||
{
|
||||
out->write(literaler::literal_true());
|
||||
}
|
||||
else
|
||||
{
|
||||
out->write(literaler::literal_false());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
case json_type::INTEGER:
|
||||
{
|
||||
dump_integer(json.value_.data.number_integer);
|
||||
return;
|
||||
}
|
||||
|
||||
case json_type::FLOAT:
|
||||
{
|
||||
dump_float(json.value_.data.number_float);
|
||||
return;
|
||||
}
|
||||
|
||||
case json_type::NIL:
|
||||
{
|
||||
out->write(literaler::literal_null());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dump_integer(integer_type val)
|
||||
{
|
||||
if (val == 0)
|
||||
{
|
||||
out->write('0');
|
||||
return;
|
||||
}
|
||||
|
||||
auto uval = static_cast<std::make_unsigned_t<integer_type>>(val);
|
||||
|
||||
if (val < 0)
|
||||
uval = 0 - uval;
|
||||
|
||||
if (number_buffer == nullptr)
|
||||
number_buffer.reset(new number_buffer_type);
|
||||
|
||||
auto next = (*number_buffer).rbegin();
|
||||
*next = '\0';
|
||||
|
||||
do
|
||||
{
|
||||
*(++next) = static_cast<char_type>('0' + uval % 10);
|
||||
uval /= 10;
|
||||
} while (uval != 0);
|
||||
|
||||
if (val < 0)
|
||||
*(++next) = '-';
|
||||
|
||||
out->write(&(*next));
|
||||
}
|
||||
|
||||
void dump_float(float_type val)
|
||||
{
|
||||
if (number_buffer == nullptr)
|
||||
number_buffer.reset(new number_buffer_type);
|
||||
|
||||
literaler::sprint_float((*number_buffer).data(), val);
|
||||
out->write((*number_buffer).data());
|
||||
}
|
||||
|
||||
void dump_string(const string_type & val, const bool char_escape)
|
||||
{
|
||||
for (const auto& ch : val)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case '\t':
|
||||
{
|
||||
out->write(literaler::escape_t());
|
||||
break;
|
||||
}
|
||||
|
||||
case '\r':
|
||||
{
|
||||
out->write(literaler::escape_r());
|
||||
break;
|
||||
}
|
||||
|
||||
case '\n':
|
||||
{
|
||||
out->write(literaler::escape_n());
|
||||
break;
|
||||
}
|
||||
|
||||
case '\b':
|
||||
{
|
||||
out->write(literaler::escape_b());
|
||||
break;
|
||||
}
|
||||
|
||||
case '\f':
|
||||
{
|
||||
out->write(literaler::escape_f());
|
||||
break;
|
||||
}
|
||||
|
||||
case '\"':
|
||||
{
|
||||
out->write(literaler::escape_quote());
|
||||
break;
|
||||
}
|
||||
|
||||
case '\\':
|
||||
{
|
||||
out->write(literaler::escape_slash());
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
uint32_t char_byte = static_cast<uint32_t>(ch);
|
||||
if (char_byte > 0x1F && (!char_escape || char_byte < 0x7F))
|
||||
{
|
||||
out->write(ch);
|
||||
}
|
||||
else
|
||||
{
|
||||
char_type escaped[7] = { '\\', 'u', 0 };
|
||||
|
||||
uint8_t index = 2;
|
||||
for (const auto factor : { 12, 8, 4, 0 })
|
||||
{
|
||||
char_type code = ((char_byte >> factor) & 0x0F);
|
||||
code += (code < 0x0A) ? '0' : 'a' - 0x0A;
|
||||
escaped[index++] = code;
|
||||
}
|
||||
out->write(escaped);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
output_adapter<char_type>* out;
|
||||
char_type indent_char;
|
||||
string_type indent_string;
|
||||
|
||||
using number_buffer_type = std::array<char_type, 21>;
|
||||
std::unique_ptr<number_buffer_type> number_buffer;
|
||||
};
|
||||
|
||||
} // namespace __json_detail
|
||||
|
||||
} // namespace oc
|
||||
|
|
@ -1,240 +0,0 @@
|
|||
// Copyright (c) 2019-2020 OuterC - Nomango
|
||||
|
||||
#pragma once
|
||||
#include <type_traits>
|
||||
#include <memory>
|
||||
|
||||
namespace oc
|
||||
{
|
||||
|
||||
enum class json_type
|
||||
{
|
||||
INTEGER,
|
||||
FLOAT,
|
||||
STRING,
|
||||
VECTOR,
|
||||
OBJECT,
|
||||
BOOL,
|
||||
NIL,
|
||||
};
|
||||
|
||||
namespace __json_detail
|
||||
{
|
||||
|
||||
template <typename _BasicJsonTy>
|
||||
struct json_value
|
||||
{
|
||||
using string_type = typename _BasicJsonTy::string_type;
|
||||
using char_type = typename _BasicJsonTy::char_type;
|
||||
using integer_type = typename _BasicJsonTy::integer_type;
|
||||
using float_type = typename _BasicJsonTy::float_type;
|
||||
using boolean_type = typename _BasicJsonTy::boolean_type;
|
||||
using array_type = typename _BasicJsonTy::array_type;
|
||||
using object_type = typename _BasicJsonTy::object_type;
|
||||
|
||||
json_type type;
|
||||
union
|
||||
{
|
||||
object_type* object;
|
||||
array_type* vector;
|
||||
string_type* string;
|
||||
integer_type number_integer;
|
||||
float_type number_float;
|
||||
boolean_type boolean;
|
||||
} data;
|
||||
|
||||
json_value()
|
||||
{
|
||||
type = json_type::NIL;
|
||||
data.object = nullptr;
|
||||
}
|
||||
|
||||
json_value(std::nullptr_t)
|
||||
{
|
||||
type = json_type::NIL;
|
||||
data.object = nullptr;
|
||||
}
|
||||
|
||||
json_value(const object_type& value)
|
||||
{
|
||||
type = json_type::OBJECT;
|
||||
data.object = create<object_type>(value);
|
||||
}
|
||||
|
||||
json_value(const array_type& value)
|
||||
{
|
||||
type = json_type::VECTOR;
|
||||
data.vector = create<array_type>(value);
|
||||
}
|
||||
|
||||
json_value(const string_type& value)
|
||||
{
|
||||
type = json_type::STRING;
|
||||
data.string = create<string_type>(value);
|
||||
}
|
||||
|
||||
template <typename _CharT>
|
||||
json_value(const _CharT* str)
|
||||
{
|
||||
type = json_type::STRING;
|
||||
data.string = create<string_type>(str);
|
||||
}
|
||||
|
||||
json_value(const integer_type value)
|
||||
{
|
||||
type = json_type::INTEGER;
|
||||
data.number_integer = value;
|
||||
}
|
||||
|
||||
json_value(const float_type value)
|
||||
{
|
||||
type = json_type::FLOAT;
|
||||
data.number_float = value;
|
||||
}
|
||||
|
||||
json_value(const boolean_type value)
|
||||
{
|
||||
type = json_type::BOOL;
|
||||
data.boolean = value;
|
||||
}
|
||||
|
||||
json_value(const json_type value_type)
|
||||
{
|
||||
type = value_type;
|
||||
switch (type)
|
||||
{
|
||||
case json_type::OBJECT:
|
||||
data.object = create<object_type>();
|
||||
break;
|
||||
case json_type::VECTOR:
|
||||
data.vector = create<array_type>();
|
||||
break;
|
||||
case json_type::STRING:
|
||||
data.string = create<string_type>();
|
||||
break;
|
||||
case json_type::INTEGER:
|
||||
data.number_integer = integer_type(0);
|
||||
break;
|
||||
case json_type::FLOAT:
|
||||
data.number_float = float_type(0.0);
|
||||
break;
|
||||
case json_type::BOOL:
|
||||
data.boolean = boolean_type(false);
|
||||
break;
|
||||
default:
|
||||
data.object = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
json_value(json_value const& other)
|
||||
{
|
||||
type = other.type;
|
||||
|
||||
switch (other.type)
|
||||
{
|
||||
case json_type::OBJECT:
|
||||
data.object = create<object_type>(*other.data.object);
|
||||
break;
|
||||
case json_type::VECTOR:
|
||||
data.vector = create<array_type>(*other.data.vector);
|
||||
break;
|
||||
case json_type::STRING:
|
||||
data.string = create<string_type>(*other.data.string);
|
||||
break;
|
||||
case json_type::INTEGER:
|
||||
data.number_integer = other.data.number_integer;
|
||||
break;
|
||||
case json_type::FLOAT:
|
||||
data.number_float = other.data.number_float;
|
||||
break;
|
||||
case json_type::BOOL:
|
||||
data.boolean = other.data.boolean;
|
||||
break;
|
||||
default:
|
||||
data.object = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
json_value(json_value&& other) noexcept
|
||||
{
|
||||
type = other.type;
|
||||
data = other.data;
|
||||
other.type = json_type::NIL;
|
||||
other.data.object = nullptr;
|
||||
}
|
||||
|
||||
~json_value()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void swap(json_value& other)
|
||||
{
|
||||
std::swap(type, other.type);
|
||||
std::swap(data, other.data);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case json_type::OBJECT:
|
||||
destroy<object_type>(data.object);
|
||||
break;
|
||||
case json_type::VECTOR:
|
||||
destroy<array_type>(data.vector);
|
||||
break;
|
||||
case json_type::STRING:
|
||||
destroy<string_type>(data.string);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename _Ty, typename ..._Args>
|
||||
inline _Ty* create(_Args&&... args)
|
||||
{
|
||||
using allocator_type = typename _BasicJsonTy::template allocator_type<_Ty>;
|
||||
using allocator_traits = std::allocator_traits<allocator_type>;
|
||||
|
||||
allocator_type allocator;
|
||||
_Ty* ptr = allocator_traits::allocate(allocator, 1);
|
||||
allocator_traits::construct(allocator, ptr, std::forward<_Args>(args)...);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
inline void destroy(_Ty* ptr)
|
||||
{
|
||||
using allocator_type = typename _BasicJsonTy::template allocator_type<_Ty>;
|
||||
using allocator_traits = std::allocator_traits<allocator_type>;
|
||||
|
||||
allocator_type allocator;
|
||||
allocator_traits::destroy(allocator, ptr);
|
||||
allocator_traits::deallocate(allocator, ptr, 1);
|
||||
}
|
||||
|
||||
inline json_value& operator=(json_value const& other)
|
||||
{
|
||||
json_value{ other }.swap(*this);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline json_value& operator=(json_value&& other) noexcept
|
||||
{
|
||||
clear();
|
||||
type = other.type;
|
||||
data = std::move(other.data);
|
||||
// invalidate payload
|
||||
other.type = json_type::NIL;
|
||||
other.data.object = nullptr;
|
||||
return (*this);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace __json_detail
|
||||
|
||||
} // namespace oc
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
// Copyright (c) 2019-2020 OuterC - Nomango
|
||||
|
||||
#pragma once
|
||||
#include "json_value.h"
|
||||
|
||||
namespace oc
|
||||
{
|
||||
namespace __json_detail
|
||||
{
|
||||
|
||||
template <typename _BasicJsonTy>
|
||||
struct json_value_getter
|
||||
{
|
||||
using string_type = typename _BasicJsonTy::string_type;
|
||||
using char_type = typename _BasicJsonTy::char_type;
|
||||
using integer_type = typename _BasicJsonTy::integer_type;
|
||||
using float_type = typename _BasicJsonTy::float_type;
|
||||
using boolean_type = typename _BasicJsonTy::boolean_type;
|
||||
using array_type = typename _BasicJsonTy::array_type;
|
||||
using object_type = typename _BasicJsonTy::object_type;
|
||||
|
||||
static inline void assign(const _BasicJsonTy& json, object_type& value)
|
||||
{
|
||||
if (!json.is_object()) throw json_type_error("json value type must be object");
|
||||
value = *json.value_.data.object;
|
||||
}
|
||||
|
||||
static inline void assign(const _BasicJsonTy& json, array_type& value)
|
||||
{
|
||||
if (!json.is_array()) throw json_type_error("json value type must be array");
|
||||
value = *json.value_.data.vector;
|
||||
}
|
||||
|
||||
static inline void assign(const _BasicJsonTy& json, string_type& value)
|
||||
{
|
||||
if (!json.is_string()) throw json_type_error("json value type must be string");
|
||||
value = *json.value_.data.string;
|
||||
}
|
||||
|
||||
static inline void assign(const _BasicJsonTy& json, boolean_type& value)
|
||||
{
|
||||
if (!json.is_boolean()) throw json_type_error("json value type must be boolean");
|
||||
value = json.value_.data.boolean;
|
||||
}
|
||||
|
||||
static inline void assign(const _BasicJsonTy& json, integer_type& value)
|
||||
{
|
||||
if (!json.is_integer()) throw json_type_error("json value type must be integer");
|
||||
value = json.value_.data.number_integer;
|
||||
}
|
||||
|
||||
template <
|
||||
typename _IntegerTy,
|
||||
typename std::enable_if<std::is_integral<_IntegerTy>::value, int>::type = 0>
|
||||
static inline void assign(const _BasicJsonTy& json, _IntegerTy& value)
|
||||
{
|
||||
if (!json.is_integer()) throw json_type_error("json value type must be integer");
|
||||
value = static_cast<_IntegerTy>(json.value_.data.number_integer);
|
||||
}
|
||||
|
||||
static inline void assign(const _BasicJsonTy& json, float_type& value)
|
||||
{
|
||||
if (!json.is_float()) throw json_type_error("json value type must be float");
|
||||
value = json.value_.data.number_float;
|
||||
}
|
||||
|
||||
template <
|
||||
typename _FloatingTy,
|
||||
typename std::enable_if<std::is_floating_point<_FloatingTy>::value, int>::type = 0>
|
||||
static inline void assign(const _BasicJsonTy& json, _FloatingTy& value)
|
||||
{
|
||||
if (!json.is_float()) throw json_type_error("json value type must be float");
|
||||
value = static_cast<_FloatingTy>(json.value_.data.number_float);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace __json_detail
|
||||
|
||||
} // namespace oc
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
// Copyright (c) 2019-2020 OuterC - Nomango
|
||||
|
||||
#pragma once
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cwchar>
|
||||
|
||||
#define OC_ASSERT(EXPR) assert(EXPR)
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
// Copyright (c) 2019-2020 OuterC - Nomango
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace oc
|
||||
{
|
||||
|
||||
class noncopyable
|
||||
{
|
||||
protected:
|
||||
noncopyable() = default;
|
||||
|
||||
private:
|
||||
noncopyable(const noncopyable&) = delete;
|
||||
|
||||
noncopyable& operator=(const noncopyable&) = delete;
|
||||
};
|
||||
|
||||
} // namespace oc
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
// Copyright (c) 2019-2020 OuterC - Nomango
|
||||
|
||||
#pragma once
|
||||
#include "macros.h"
|
||||
#include "vector.h"
|
||||
#include "string.h"
|
||||
#include "any.h"
|
||||
#include "function.h"
|
||||
#include "noncopyable.h"
|
||||
#include "singleton.h"
|
||||
#include "intrusive_ptr.h"
|
||||
#include "intrusive_list.h"
|
||||
#include "json.h"
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
// Copyright (c) 2019-2020 OuterC - Nomango
|
||||
|
||||
#pragma once
|
||||
|
||||
// Class that will implement the singleton mode must use the macro in its delare file
|
||||
|
||||
#ifndef OC_DECLARE_SINGLETON
|
||||
#define OC_DECLARE_SINGLETON( CLASS ) \
|
||||
friend ::oc::singleton< CLASS >;
|
||||
#endif
|
||||
|
||||
namespace oc
|
||||
{
|
||||
|
||||
template <typename _Ty>
|
||||
struct singleton
|
||||
{
|
||||
protected:
|
||||
singleton() = default;
|
||||
singleton(const singleton&) = delete;
|
||||
singleton& operator=(const singleton&) = delete;
|
||||
|
||||
private:
|
||||
struct object_creator
|
||||
{
|
||||
object_creator()
|
||||
{
|
||||
(void)singleton<_Ty>::instance();
|
||||
}
|
||||
|
||||
inline void dummy() const {}
|
||||
};
|
||||
static object_creator creator_;
|
||||
|
||||
public:
|
||||
using object_type = _Ty;
|
||||
|
||||
static inline object_type& instance()
|
||||
{
|
||||
static object_type instance;
|
||||
creator_.dummy();
|
||||
return instance;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _Ty>
|
||||
typename singleton<_Ty>::object_creator singleton<_Ty>::creator_;
|
||||
|
||||
|
||||
} // namespace oc
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,178 +0,0 @@
|
|||
// Copyright (c) 2019-2020 OuterC - Nomango
|
||||
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include "vector/details.h"
|
||||
|
||||
namespace oc
|
||||
{
|
||||
|
||||
//
|
||||
// vector<>
|
||||
// Lightweight std::vector<>-like class
|
||||
//
|
||||
template <typename _Ty, typename _Alloc = std::allocator<_Ty>>
|
||||
class vector
|
||||
{
|
||||
public:
|
||||
using value_type = _Ty;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using iterator = value_type*;
|
||||
using const_iterator = const value_type*;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
using allocator_type = typename _Alloc;
|
||||
using manager = typename __vector_details::vector_memory_manager<_Ty, _Alloc>;
|
||||
using initializer_list = std::initializer_list<value_type>;
|
||||
|
||||
public:
|
||||
inline vector() : size_(0), capacity_(0), data_(nullptr) { }
|
||||
inline vector(size_type count) : vector() { reserve(count); }
|
||||
inline vector(size_type count, const _Ty& val) : vector() { assign(count, val); }
|
||||
inline vector(initializer_list list) : vector() { assign(list); }
|
||||
inline vector(const vector& src) : vector() { assign(src); }
|
||||
inline vector(vector&& src) noexcept : vector() { swap(src); }
|
||||
inline ~vector() { destroy(); }
|
||||
|
||||
template <typename _Iter>
|
||||
inline vector(_Iter first, _Iter last) : vector() { assign(first, last); }
|
||||
|
||||
inline vector& operator=(const vector& src) { if (&src != this) { resize(src.size_); manager::copy_n(begin(), src.cbegin(), size_); } return (*this); }
|
||||
inline vector& operator=(vector&& src) noexcept { swap(src); return *this; }
|
||||
inline vector& operator=(initializer_list list) { if (list.size()) { assign(list.begin(), list.end()); } else clear(); return (*this); }
|
||||
|
||||
inline vector& assign(size_type count, const _Ty& val) { if (count > 0) { resize(count); manager::fill_n(begin(), count, val); } else clear(); return (*this); }
|
||||
inline vector& assign(const vector& src) { return operator=(src); }
|
||||
inline vector& assign(initializer_list list) { return operator=(list); }
|
||||
|
||||
template <typename _Iter>
|
||||
inline void assign(_Iter first, _Iter last) { auto diff = std::distance(first, last); resize((size_type)diff); auto data = begin(); while (first != last) (*data++) = (*first++); }
|
||||
|
||||
inline void clear() { destroy(); size_ = capacity_ = 0; data_ = nullptr; }
|
||||
inline void swap(vector& rhs) noexcept { std::swap(size_, rhs.size_); std::swap(capacity_, rhs.capacity_); std::swap(data_, rhs.data_); }
|
||||
|
||||
inline void resize(size_type new_size) { resize(new_size, _Ty()); }
|
||||
void resize(size_type new_size, const _Ty& v);
|
||||
void reserve(size_type new_capacity);
|
||||
|
||||
inline void push_back(const _Ty& val) { resize(size_ + 1, val); }
|
||||
inline void pop_back() { if (empty()) throw std::out_of_range("pop() called on empty vector"); resize(size_ - 1); }
|
||||
inline void push_front(const _Ty& val) { if (size_ == 0) push_back(val); else insert(begin(), val); }
|
||||
|
||||
inline iterator erase(const_iterator where) { return erase(where, where + 1); }
|
||||
iterator erase(const_iterator first, const_iterator last);
|
||||
|
||||
iterator insert(const_iterator where, const _Ty& v);
|
||||
|
||||
inline bool empty() const { return size_ == 0; }
|
||||
inline size_type size() const { return size_; }
|
||||
inline size_type size_in_bytes() const { return size_ * ((size_type)sizeof(_Ty)); }
|
||||
inline size_type max_size() const { return std::numeric_limits<difference_type>::max(); }
|
||||
inline size_type capacity() const { return capacity_; }
|
||||
inline reference operator[](size_type off) { if (off < 0 || off >= size_) throw std::out_of_range("vector subscript out of range"); return data_[off]; }
|
||||
inline const_reference operator[](size_type off) const { if (off < 0 || off >= size_) throw std::out_of_range("vector subscript out of range"); return data_[off]; }
|
||||
|
||||
|
||||
inline bool contains(const _Ty& v) const { auto data = cbegin(); const auto data_end = cend(); while (data != data_end) if (*(data++) == v) return true; return false; }
|
||||
inline size_type index_of(const_iterator it) const { check_offset(it - cbegin(), "invalid array position"); return it - data_; }
|
||||
|
||||
inline iterator begin() { return iterator(data_); }
|
||||
inline const_iterator begin() const { return const_iterator(data_); }
|
||||
inline const_iterator cbegin() const { return begin(); }
|
||||
inline iterator end() { return iterator(data_ + size_); }
|
||||
inline const_iterator end() const { return const_iterator(data_ + size_); }
|
||||
inline const_iterator cend() const { return end(); }
|
||||
inline reverse_iterator rbegin() { return reverse_iterator(end()); }
|
||||
inline const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
|
||||
inline const_reverse_iterator crbegin() const { return rbegin(); }
|
||||
inline reverse_iterator rend() { return reverse_iterator(begin()); }
|
||||
inline const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
|
||||
inline const_reverse_iterator crend() const { return rend(); }
|
||||
inline reference front() { if (empty()) throw std::out_of_range("front() called on empty array"); return data_[0]; }
|
||||
inline const_reference front() const { if (empty()) throw std::out_of_range("front() called on empty array"); return data_[0]; }
|
||||
inline reference back() { if (empty()) throw std::out_of_range("back() called on empty array"); return data_[size_ - 1]; }
|
||||
inline const_reference back() const { if (empty()) throw std::out_of_range("back() called on empty array"); return data_[size_ - 1]; }
|
||||
|
||||
private:
|
||||
inline size_type grow_capacity(size_type sz) const { size_type new_capacity = capacity_ ? (capacity_ + capacity_ / 2) : 8; return new_capacity > sz ? new_capacity : sz; }
|
||||
inline void check_offset(const size_type off) const { if (off < 0 || off >= size_) throw std::out_of_range("invalid vector position"); }
|
||||
|
||||
inline void destroy() { manager::destroy(data_, size_); manager::deallocate(data_, capacity_); }
|
||||
protected:
|
||||
size_type size_;
|
||||
size_type capacity_;
|
||||
_Ty* data_;
|
||||
};
|
||||
|
||||
template<typename _Ty, typename _Alloc>
|
||||
void vector<_Ty, _Alloc>::resize(size_type new_size, const _Ty& val)
|
||||
{
|
||||
if (new_size > size_)
|
||||
{
|
||||
if (new_size > capacity_)
|
||||
{
|
||||
reserve(grow_capacity(new_size));
|
||||
}
|
||||
manager::construct(begin() + size_, new_size - size_, val);
|
||||
}
|
||||
else
|
||||
{
|
||||
manager::destroy(begin() + new_size, size_ - new_size);
|
||||
}
|
||||
size_ = new_size;
|
||||
}
|
||||
|
||||
template<typename _Ty, typename _Alloc>
|
||||
void vector<_Ty, _Alloc>::reserve(size_type new_capacity)
|
||||
{
|
||||
if (new_capacity <= capacity_)
|
||||
return;
|
||||
|
||||
auto new_data = manager::allocate(new_capacity);
|
||||
if (data_)
|
||||
{
|
||||
manager::construct_n(new_data, data_, size_/* only construct needed size */);
|
||||
/* destroy old memory, but not resize */
|
||||
destroy();
|
||||
}
|
||||
data_ = new_data;
|
||||
capacity_ = new_capacity;
|
||||
}
|
||||
|
||||
template<typename _Ty, typename _Alloc>
|
||||
typename vector<_Ty, _Alloc>::iterator
|
||||
vector<_Ty, _Alloc>::erase(const_iterator first, const_iterator last)
|
||||
{
|
||||
const auto off = first - begin();
|
||||
const auto count = last - first;
|
||||
|
||||
if (count != 0)
|
||||
{
|
||||
check_offset(off);
|
||||
|
||||
manager::move(begin() + off, begin() + off + count, size_ - off - count);
|
||||
resize(size_ - count); // do destruction
|
||||
}
|
||||
return begin() + off;
|
||||
}
|
||||
|
||||
template<typename _Ty, typename _Alloc>
|
||||
typename vector<_Ty, _Alloc>::iterator
|
||||
vector<_Ty, _Alloc>::insert(const_iterator where, const _Ty& v)
|
||||
{
|
||||
const auto off = where - begin();
|
||||
const auto insert_at = begin() + off;
|
||||
|
||||
check_offset(off);
|
||||
|
||||
resize(size_ + 1);
|
||||
manager::move(insert_at + 1, insert_at, size_ - off - 1);
|
||||
data_[off] = v;
|
||||
return begin() + off;
|
||||
}
|
||||
|
||||
} // namespace oc
|
||||
|
|
@ -1,172 +0,0 @@
|
|||
// Copyright (c) 2019-2020 OuterC - Nomango
|
||||
|
||||
#pragma once
|
||||
#include <type_traits>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
namespace oc
|
||||
{
|
||||
|
||||
namespace __vector_details
|
||||
{
|
||||
|
||||
// vector_memory_manager<> with memory operations
|
||||
template<typename _Ty, typename _Alloc, bool _IsTrivial = std::is_trivial<_Ty>::value>
|
||||
struct vector_memory_manager;
|
||||
|
||||
|
||||
//
|
||||
// vector_memory_manager for common type
|
||||
//
|
||||
template<typename _Ty, typename _Alloc>
|
||||
struct vector_memory_manager<_Ty, _Alloc, true>
|
||||
{
|
||||
using value_type = _Ty;
|
||||
using size_type = size_t;
|
||||
using allocator_type = typename _Alloc;
|
||||
|
||||
static void fill_n(value_type* const dest, ptrdiff_t count, const value_type& val)
|
||||
{
|
||||
for (ptrdiff_t i = 0; i < count; ++i)
|
||||
std::memcpy(std::addressof(dest[i]), std::addressof(val), sizeof(value_type));
|
||||
}
|
||||
|
||||
static void copy_n(value_type* const dest, const value_type* src, ptrdiff_t count)
|
||||
{
|
||||
if (src == dest)
|
||||
return;
|
||||
std::memcpy(dest, src, count * sizeof(value_type));
|
||||
}
|
||||
|
||||
static void move(value_type* const dest, const value_type* src, ptrdiff_t count)
|
||||
{
|
||||
if (src == dest)
|
||||
return;
|
||||
std::memmove(dest, src, count * sizeof(value_type));
|
||||
}
|
||||
|
||||
static void construct(value_type* const ptr, ptrdiff_t count, const value_type& val)
|
||||
{
|
||||
fill_n(ptr, count, val);
|
||||
}
|
||||
|
||||
static void construct_n(value_type* const ptr, const value_type* src, ptrdiff_t count)
|
||||
{
|
||||
copy_n(ptr, src, count);
|
||||
}
|
||||
|
||||
static void destroy(value_type* const ptr, ptrdiff_t count)
|
||||
{
|
||||
}
|
||||
|
||||
static value_type* allocate(ptrdiff_t count)
|
||||
{
|
||||
return get_allocator().allocate(count);
|
||||
}
|
||||
|
||||
static void deallocate(value_type*& ptr, ptrdiff_t count)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
get_allocator().deallocate(ptr, count);
|
||||
ptr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static inline allocator_type& get_allocator()
|
||||
{
|
||||
static allocator_type allocator_;
|
||||
return allocator_;
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// vector_memory_manager for classes
|
||||
//
|
||||
template<typename _Ty, typename _Alloc>
|
||||
struct vector_memory_manager<_Ty, _Alloc, false>
|
||||
{
|
||||
using value_type = _Ty;
|
||||
using size_type = size_t;
|
||||
using allocator_type = typename _Alloc;
|
||||
|
||||
static void fill_n(value_type* const dest, ptrdiff_t count, const value_type& val)
|
||||
{
|
||||
// Avoid warning C4996
|
||||
// std::fill_n(dest, count, val);
|
||||
for (ptrdiff_t i = 0; i < count; ++i)
|
||||
dest[i] = val;
|
||||
}
|
||||
|
||||
static void copy_n(value_type* const dest, const value_type* src, ptrdiff_t count)
|
||||
{
|
||||
if (src == dest)
|
||||
return;
|
||||
|
||||
// Avoid warning C4996
|
||||
// std::copy_n(src, count, dest);
|
||||
for (ptrdiff_t i = 0; i < count; ++i)
|
||||
dest[i] = src[i];
|
||||
}
|
||||
|
||||
static void move(value_type* const dest, const value_type* src, ptrdiff_t count)
|
||||
{
|
||||
if (src == dest)
|
||||
return;
|
||||
|
||||
if (dest > src && dest < src + count)
|
||||
{
|
||||
// Avoid warning C4996
|
||||
// std::copy_backward(src, src + count, dest);
|
||||
for (ptrdiff_t i = 0; i < count; ++i)
|
||||
dest[count - i - 1] = src[count - i - 1];
|
||||
}
|
||||
else
|
||||
copy_n(dest, src, count);
|
||||
}
|
||||
|
||||
static void construct(value_type* const ptr, ptrdiff_t count, const value_type& val)
|
||||
{
|
||||
for (ptrdiff_t i = 0; i < count; ++i)
|
||||
get_allocator().construct(std::addressof(ptr[i]), val);
|
||||
}
|
||||
|
||||
static void construct_n(value_type* const ptr, const value_type* src, ptrdiff_t count)
|
||||
{
|
||||
for (ptrdiff_t i = 0; i < count; ++i)
|
||||
get_allocator().construct(std::addressof(ptr[i]), src[i]);
|
||||
}
|
||||
|
||||
static void destroy(value_type* const ptr, ptrdiff_t count)
|
||||
{
|
||||
for (ptrdiff_t i = 0; i < count; ++i)
|
||||
get_allocator().destroy(std::addressof(ptr[i]));
|
||||
}
|
||||
|
||||
static value_type* allocate(ptrdiff_t count)
|
||||
{
|
||||
return get_allocator().allocate(count);
|
||||
}
|
||||
|
||||
static void deallocate(value_type*& ptr, ptrdiff_t count)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
get_allocator().deallocate(ptr, count);
|
||||
ptr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static inline allocator_type& get_allocator()
|
||||
{
|
||||
static allocator_type allocator_;
|
||||
return allocator_;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace __vector_details
|
||||
} // namespace oc
|
||||
|
|
@ -51,7 +51,7 @@ void AudioModule::SetupModule()
|
|||
hr = x_audio2_->CreateMasteringVoice(&mastering_voice_);
|
||||
}
|
||||
|
||||
ThrowIfFailed(hr, "Create audio resources failed");
|
||||
KGE_THROW_IF_FAILED(hr, "Create audio resources failed");
|
||||
}
|
||||
|
||||
void AudioModule::DestroyModule()
|
||||
|
|
|
|||
|
|
@ -43,9 +43,9 @@ SoundPlayer::~SoundPlayer()
|
|||
|
||||
size_t SoundPlayer::Load(String const& file_path)
|
||||
{
|
||||
int hash_code = static_cast<int>(file_path.hash());
|
||||
if (sound_cache_.end() != sound_cache_.find(hash_code))
|
||||
return hash_code;
|
||||
size_t hash = std::hash<String>()(file_path);
|
||||
if (sound_cache_.end() != sound_cache_.find(hash))
|
||||
return hash;
|
||||
|
||||
SoundPtr sound = new (std::nothrow) Sound;
|
||||
|
||||
|
|
@ -54,8 +54,8 @@ size_t SoundPlayer::Load(String const& file_path)
|
|||
if (sound->Load(file_path))
|
||||
{
|
||||
sound->SetVolume(volume_);
|
||||
sound_cache_.insert(std::make_pair(hash_code, sound));
|
||||
return hash_code;
|
||||
sound_cache_.insert(std::make_pair(hash, sound));
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -76,11 +76,11 @@ HRESULT Transcoder::LoadMediaFile(String const& file_path)
|
|||
|
||||
ComPtr<IMFSourceReader> reader;
|
||||
|
||||
hr = dlls::MediaFoundation::Get().MFCreateSourceReaderFromURL(MultiByteToWide(file_path).c_str(), nullptr, &reader);
|
||||
hr = dlls::MediaFoundation::Get().MFCreateSourceReaderFromURL(string::ToWide(file_path).c_str(), nullptr, &reader);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = ReadSource(reader.get());
|
||||
hr = ReadSource(reader.Get());
|
||||
}
|
||||
|
||||
return hr;
|
||||
|
|
@ -111,17 +111,17 @@ HRESULT Transcoder::LoadMediaResource(Resource const& res)
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = dlls::MediaFoundation::Get().MFCreateMFByteStreamOnStream(stream.get(), &byte_stream);
|
||||
hr = dlls::MediaFoundation::Get().MFCreateMFByteStreamOnStream(stream.Get(), &byte_stream);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = dlls::MediaFoundation::Get().MFCreateSourceReaderFromByteStream(byte_stream.get(), nullptr, &reader);
|
||||
hr = dlls::MediaFoundation::Get().MFCreateSourceReaderFromByteStream(byte_stream.Get(), nullptr, &reader);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = ReadSource(reader.get());
|
||||
hr = ReadSource(reader.Get());
|
||||
}
|
||||
|
||||
return hr;
|
||||
|
|
@ -150,7 +150,7 @@ HRESULT Transcoder::ReadSource(IMFSourceReader* reader)
|
|||
// 设置 source reader 的媒体类型,它将使用合适的解码器去解码这个音频
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = reader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, partial_type.get());
|
||||
hr = reader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, partial_type.Get());
|
||||
}
|
||||
|
||||
// 从 IMFMediaType 中获取 WAVEFORMAT 结构
|
||||
|
|
@ -170,7 +170,7 @@ HRESULT Transcoder::ReadSource(IMFSourceReader* reader)
|
|||
{
|
||||
uint32_t size = 0;
|
||||
hr = dlls::MediaFoundation::Get().MFCreateWaveFormatExFromMFMediaType(
|
||||
uncompressed_type.get(), &wave_format_, &size, (DWORD)MFWaveFormatExConvertFlag_Normal);
|
||||
uncompressed_type.Get(), &wave_format_, &size, (DWORD)MFWaveFormatExConvertFlag_Normal);
|
||||
}
|
||||
|
||||
// 估算音频流大小
|
||||
|
|
|
|||
|
|
@ -310,7 +310,7 @@ void HttpModule::DispatchResponseCallback()
|
|||
|
||||
if (callback)
|
||||
{
|
||||
callback(request.get(), response.get());
|
||||
callback(request.Get(), response.Get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
#pragma once
|
||||
#include <kiwano/core/Common.h>
|
||||
#include <kiwano/core/ObjectBase.h>
|
||||
#include <kiwano/core/SmartPtr.hpp>
|
||||
#include <kiwano/core/Json.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ Fixture* Body::AddCircleShape(float radius, float density, float friction, float
|
|||
Fixture::Param param(density, friction, restitution, is_sensor);
|
||||
FixturePtr fixture = Fixture::CreateCircle(this, param, radius);
|
||||
AddFixture(fixture);
|
||||
return fixture.get();
|
||||
return fixture.Get();
|
||||
}
|
||||
|
||||
Fixture* Body::AddRectShape(Vec2 const& size, float density, float friction, float restitution, bool is_sensor)
|
||||
|
|
@ -92,7 +92,7 @@ Fixture* Body::AddRectShape(Vec2 const& size, float density, float friction, flo
|
|||
Fixture::Param param(density, friction, restitution, is_sensor);
|
||||
FixturePtr fixture = Fixture::CreateRect(this, param, size);
|
||||
AddFixture(fixture);
|
||||
return fixture.get();
|
||||
return fixture.Get();
|
||||
}
|
||||
|
||||
Fixture* Body::AddPolygonShape(Vector<Point> const& vertexs, float density, float friction, float restitution,
|
||||
|
|
@ -101,7 +101,7 @@ Fixture* Body::AddPolygonShape(Vector<Point> const& vertexs, float density, floa
|
|||
Fixture::Param param(density, friction, restitution, is_sensor);
|
||||
FixturePtr fixture = Fixture::CreatePolygon(this, param, vertexs);
|
||||
AddFixture(fixture);
|
||||
return fixture.get();
|
||||
return fixture.Get();
|
||||
}
|
||||
|
||||
Fixture* Body::AddEdgeShape(Point const& p1, Point const& p2, float density, float friction, float restitution,
|
||||
|
|
@ -110,7 +110,7 @@ Fixture* Body::AddEdgeShape(Point const& p1, Point const& p2, float density, flo
|
|||
Fixture::Param param(density, friction, restitution, is_sensor);
|
||||
FixturePtr fixture = Fixture::CreateEdge(this, param, p1, p2);
|
||||
AddFixture(fixture);
|
||||
return fixture.get();
|
||||
return fixture.Get();
|
||||
}
|
||||
|
||||
Fixture* Body::AddChainShape(Vector<Point> const& vertexs, bool loop, float density, float friction, float restitution,
|
||||
|
|
@ -119,7 +119,7 @@ Fixture* Body::AddChainShape(Vector<Point> const& vertexs, bool loop, float dens
|
|||
Fixture::Param param(density, friction, restitution, is_sensor);
|
||||
FixturePtr fixture = Fixture::CreateChain(this, param, vertexs, loop);
|
||||
AddFixture(fixture);
|
||||
return fixture.get();
|
||||
return fixture.Get();
|
||||
}
|
||||
|
||||
void Body::RemoveFixture(FixturePtr fixture)
|
||||
|
|
|
|||
|
|
@ -343,12 +343,12 @@ private:
|
|||
|
||||
inline BodyPtr Body::Create(World* world, ActorPtr actor, Type type)
|
||||
{
|
||||
return Body::Create(world, actor.get(), type);
|
||||
return Body::Create(world, actor.Get(), type);
|
||||
}
|
||||
|
||||
inline bool Body::InitBody(World* world, ActorPtr actor)
|
||||
{
|
||||
return InitBody(world, actor.get());
|
||||
return InitBody(world, actor.Get());
|
||||
}
|
||||
|
||||
inline FixtureList Body::GetFixtureList() const
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ FixturePtr CreateFixture(Body* body, b2Shape* shape, const Fixture::Param& param
|
|||
b2Fixture* fixture = b2body->CreateFixture(&fd);
|
||||
if (fixture)
|
||||
{
|
||||
fixture->SetUserData(ptr.get());
|
||||
fixture->SetUserData(ptr.Get());
|
||||
ptr->SetB2Fixture(fixture);
|
||||
return ptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,8 +81,8 @@ public:
|
|||
}
|
||||
|
||||
ParamBase(BodyPtr body_a, BodyPtr body_b)
|
||||
: body_a(body_a.get())
|
||||
, body_b(body_b.get())
|
||||
: body_a(body_a.Get())
|
||||
, body_b(body_b.Get())
|
||||
{
|
||||
}
|
||||
};
|
||||
|
|
@ -146,7 +146,7 @@ public:
|
|||
|
||||
Param(BodyPtr body_a, BodyPtr body_b, Point const& anchor_a, Point const& anchor_b, float frequency_hz = 0.f,
|
||||
float damping_ratio = 0.f)
|
||||
: Param(body_a.get(), body_b.get(), anchor_a, anchor_b, frequency_hz, damping_ratio)
|
||||
: Param(body_a.Get(), body_b.Get(), anchor_a, anchor_b, frequency_hz, damping_ratio)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
|
@ -211,7 +211,7 @@ public:
|
|||
}
|
||||
|
||||
Param(BodyPtr body_a, BodyPtr body_b, Point const& anchor, float max_force = 0.f, float max_torque = 0.f)
|
||||
: Param(body_a.get(), body_b.get(), anchor, max_force, max_torque)
|
||||
: Param(body_a.Get(), body_b.Get(), anchor, max_force, max_torque)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
|
@ -270,7 +270,7 @@ public:
|
|||
}
|
||||
|
||||
Param(JointPtr joint_a, JointPtr joint_b, float ratio = 1.f)
|
||||
: Param(joint_a.get(), joint_b.get(), ratio)
|
||||
: Param(joint_a.Get(), joint_b.Get(), ratio)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
|
@ -323,7 +323,7 @@ public:
|
|||
|
||||
Param(BodyPtr body_a, BodyPtr body_b, float max_force = 0.f, float max_torque = 0.f,
|
||||
float correction_factor = 0.3f)
|
||||
: Param(body_a.get(), body_b.get(), max_force, max_torque, correction_factor)
|
||||
: Param(body_a.Get(), body_b.Get(), max_force, max_torque, correction_factor)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
|
@ -396,7 +396,7 @@ public:
|
|||
Param(BodyPtr body_a, BodyPtr body_b, Point const& anchor, Vec2 const& axis, bool enable_limit = false,
|
||||
float lower_translation = 0.0f, float upper_translation = 0.0f, bool enable_motor = false,
|
||||
float max_motor_force = 0.0f, float motor_speed = 0.0f)
|
||||
: Param(body_a.get(), body_b.get(), anchor, axis, enable_limit, lower_translation, upper_translation,
|
||||
: Param(body_a.Get(), body_b.Get(), anchor, axis, enable_limit, lower_translation, upper_translation,
|
||||
enable_motor, max_motor_force, motor_speed)
|
||||
{
|
||||
}
|
||||
|
|
@ -502,7 +502,7 @@ public:
|
|||
|
||||
Param(BodyPtr body_a, BodyPtr body_b, Point const& anchor_a, Point const& anchor_b,
|
||||
Point const& ground_anchor_a, Point const& ground_anchor_b, float ratio = 1.0f)
|
||||
: Param(body_a.get(), body_b.get(), anchor_a, anchor_b, ground_anchor_a, ground_anchor_b, ratio)
|
||||
: Param(body_a.Get(), body_b.Get(), anchor_a, anchor_b, ground_anchor_a, ground_anchor_b, ratio)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
|
@ -585,7 +585,7 @@ public:
|
|||
Param(BodyPtr body_a, BodyPtr body_b, Point const& anchor, bool enable_limit = false, float lower_angle = 0.0f,
|
||||
float upper_angle = 0.0f, bool enable_motor = false, float max_motor_torque = 0.0f,
|
||||
float motor_speed = 0.0f)
|
||||
: Param(body_a.get(), body_b.get(), anchor, enable_limit, lower_angle, upper_angle, enable_motor,
|
||||
: Param(body_a.Get(), body_b.Get(), anchor, enable_limit, lower_angle, upper_angle, enable_motor,
|
||||
max_motor_torque, motor_speed)
|
||||
{
|
||||
}
|
||||
|
|
@ -687,7 +687,7 @@ public:
|
|||
|
||||
Param(BodyPtr body_a, BodyPtr body_b, Point const& local_anchor_a, Point const& local_anchor_b,
|
||||
float max_length = 0.f)
|
||||
: Param(body_a.get(), body_b.get(), local_anchor_a, local_anchor_b, max_length)
|
||||
: Param(body_a.Get(), body_b.Get(), local_anchor_a, local_anchor_b, max_length)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
|
@ -738,7 +738,7 @@ public:
|
|||
}
|
||||
|
||||
Param(BodyPtr body_a, BodyPtr body_b, Point const& anchor, float frequency_hz = 0.f, float damping_ratio = 0.f)
|
||||
: Param(body_a.get(), body_b.get(), anchor, frequency_hz, damping_ratio)
|
||||
: Param(body_a.Get(), body_b.Get(), anchor, frequency_hz, damping_ratio)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
|
@ -813,7 +813,7 @@ public:
|
|||
Param(BodyPtr body_a, BodyPtr body_b, Point const& anchor, Vec2 const& axis, float frequency_hz = 2.0f,
|
||||
float damping_ratio = 0.7f, bool enable_motor = false, float max_motor_torque = 0.0f,
|
||||
float motor_speed = 0.0f)
|
||||
: Param(body_a.get(), body_b.get(), anchor, axis, frequency_hz, damping_ratio, enable_motor,
|
||||
: Param(body_a.Get(), body_b.Get(), anchor, axis, frequency_hz, damping_ratio, enable_motor,
|
||||
max_motor_torque, motor_speed)
|
||||
{
|
||||
}
|
||||
|
|
@ -918,7 +918,7 @@ public:
|
|||
|
||||
Param(BodyPtr body_a, BodyPtr body_b, Point const& target, float max_force, float frequency_hz = 5.0f,
|
||||
float damping_ratio = 0.7f)
|
||||
: Param(body_a.get(), body_b.get(), target, max_force, frequency_hz, damping_ratio)
|
||||
: Param(body_a.Get(), body_b.Get(), target, max_force, frequency_hz, damping_ratio)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ public:
|
|||
contact.SetB2Contact(b2contact);
|
||||
|
||||
ContactBeginEventPtr evt = new ContactBeginEvent(contact);
|
||||
world_->DispatchEvent(evt.get());
|
||||
world_->DispatchEvent(evt.Get());
|
||||
}
|
||||
|
||||
void EndContact(b2Contact* b2contact) override
|
||||
|
|
@ -77,7 +77,7 @@ public:
|
|||
contact.SetB2Contact(b2contact);
|
||||
|
||||
ContactEndEventPtr evt = new ContactEndEvent(contact);
|
||||
world_->DispatchEvent(evt.get());
|
||||
world_->DispatchEvent(evt.Get());
|
||||
}
|
||||
|
||||
void PreSolve(b2Contact* contact, const b2Manifold* oldManifold) override
|
||||
|
|
|
|||
|
|
@ -83,12 +83,12 @@ void Actor::Update(Duration dt)
|
|||
OnUpdate(dt);
|
||||
}
|
||||
|
||||
if (!children_.empty())
|
||||
if (!children_.IsEmpty())
|
||||
{
|
||||
ActorPtr next;
|
||||
for (auto child = children_.first_item(); child; child = next)
|
||||
for (auto child = children_.GetFirst(); child; child = next)
|
||||
{
|
||||
next = child->next_item();
|
||||
next = child->GetNext();
|
||||
child->Update(dt);
|
||||
}
|
||||
}
|
||||
|
|
@ -101,7 +101,7 @@ void Actor::Render(RenderContext& ctx)
|
|||
|
||||
UpdateTransform();
|
||||
|
||||
if (children_.empty())
|
||||
if (children_.IsEmpty())
|
||||
{
|
||||
if (CheckVisibility(ctx))
|
||||
{
|
||||
|
|
@ -112,14 +112,14 @@ void Actor::Render(RenderContext& ctx)
|
|||
else
|
||||
{
|
||||
// render children those are less than 0 in Z-Order
|
||||
Actor* child = children_.first_item().get();
|
||||
ActorPtr child = children_.GetFirst();
|
||||
while (child)
|
||||
{
|
||||
if (child->GetZOrder() >= 0)
|
||||
break;
|
||||
|
||||
child->Render(ctx);
|
||||
child = child->next_item().get();
|
||||
child = child->GetNext();
|
||||
}
|
||||
|
||||
if (CheckVisibility(ctx))
|
||||
|
|
@ -131,7 +131,7 @@ void Actor::Render(RenderContext& ctx)
|
|||
while (child)
|
||||
{
|
||||
child->Render(ctx);
|
||||
child = child->next_item().get();
|
||||
child = child->GetNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -157,9 +157,9 @@ void Actor::RenderBorder(RenderContext& ctx)
|
|||
ctx.DrawRectangle(bounds, nullptr, 2.f);
|
||||
}
|
||||
|
||||
for (auto child = children_.first_item(); child; child = child->next_item())
|
||||
for (auto& child : children_)
|
||||
{
|
||||
child->RenderBorder(ctx);
|
||||
child.RenderBorder(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -187,7 +187,7 @@ bool Actor::DispatchEvent(Event* evt)
|
|||
return true;
|
||||
|
||||
// Dispatch to children those are greater than 0 in Z-Order
|
||||
Actor* child = children_.last_item().get();
|
||||
ActorPtr child = children_.GetLast();
|
||||
while (child)
|
||||
{
|
||||
if (child->GetZOrder() < 0)
|
||||
|
|
@ -196,7 +196,7 @@ bool Actor::DispatchEvent(Event* evt)
|
|||
if (!child->DispatchEvent(evt))
|
||||
return false;
|
||||
|
||||
child = child->prev_item().get();
|
||||
child = child->GetPrev();
|
||||
}
|
||||
|
||||
if (!EventDispatcher::DispatchEvent(evt))
|
||||
|
|
@ -209,7 +209,7 @@ bool Actor::DispatchEvent(Event* evt)
|
|||
if (!child->DispatchEvent(evt))
|
||||
return false;
|
||||
|
||||
child = child->prev_item().get();
|
||||
child = child->GetPrev();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -228,7 +228,7 @@ void Actor::HandleEvent(Event* evt)
|
|||
|
||||
MouseHoverEventPtr hover = new MouseHoverEvent;
|
||||
hover->pos = mouse_evt->pos;
|
||||
EventDispatcher::DispatchEvent(hover.get());
|
||||
EventDispatcher::DispatchEvent(hover.Get());
|
||||
}
|
||||
else if (hover_ && !contains)
|
||||
{
|
||||
|
|
@ -237,7 +237,7 @@ void Actor::HandleEvent(Event* evt)
|
|||
|
||||
MouseOutEventPtr out = new MouseOutEvent;
|
||||
out->pos = mouse_evt->pos;
|
||||
EventDispatcher::DispatchEvent(out.get());
|
||||
EventDispatcher::DispatchEvent(out.Get());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -255,7 +255,7 @@ void Actor::HandleEvent(Event* evt)
|
|||
MouseClickEventPtr click = new MouseClickEvent;
|
||||
click->pos = mouse_up_evt->pos;
|
||||
click->button = mouse_up_evt->button;
|
||||
EventDispatcher::DispatchEvent(click.get());
|
||||
EventDispatcher::DispatchEvent(click.Get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -304,8 +304,8 @@ void Actor::UpdateTransform() const
|
|||
}
|
||||
|
||||
// update children's transform
|
||||
for (auto child = children_.first_item().get(); child; child = child->next_item().get())
|
||||
child->dirty_transform_ = true;
|
||||
for (const auto& child : children_)
|
||||
child.dirty_transform_ = true;
|
||||
}
|
||||
|
||||
void Actor::UpdateOpacity()
|
||||
|
|
@ -319,9 +319,9 @@ void Actor::UpdateOpacity()
|
|||
displayed_opacity_ = opacity_;
|
||||
}
|
||||
|
||||
for (Actor* child = children_.first_item().get(); child; child = child->next_item().get())
|
||||
for (auto& child : children_)
|
||||
{
|
||||
child->UpdateOpacity();
|
||||
child.UpdateOpacity();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -330,9 +330,9 @@ void Actor::SetStage(Stage* stage)
|
|||
if (stage_ != stage)
|
||||
{
|
||||
stage_ = stage;
|
||||
for (Actor* child = children_.first_item().get(); child; child = child->next_item().get())
|
||||
for (auto& child : children_)
|
||||
{
|
||||
child->stage_ = stage;
|
||||
child.stage_ = stage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -343,28 +343,28 @@ void Actor::Reorder()
|
|||
{
|
||||
ActorPtr me = this;
|
||||
|
||||
parent_->children_.remove(me);
|
||||
parent_->children_.Remove(me.Get());
|
||||
|
||||
Actor* sibling = parent_->children_.last_item().get();
|
||||
ActorPtr sibling = parent_->children_.GetLast();
|
||||
|
||||
if (sibling && sibling->GetZOrder() > z_order_)
|
||||
{
|
||||
sibling = sibling->prev_item().get();
|
||||
sibling = sibling->GetPrev();
|
||||
while (sibling)
|
||||
{
|
||||
if (sibling->GetZOrder() <= z_order_)
|
||||
break;
|
||||
sibling = sibling->prev_item().get();
|
||||
sibling = sibling->GetPrev();
|
||||
}
|
||||
}
|
||||
|
||||
if (sibling)
|
||||
{
|
||||
parent_->children_.insert_after(me, sibling);
|
||||
parent_->children_.InsertAfter(me.Get(), sibling);
|
||||
}
|
||||
else
|
||||
{
|
||||
parent_->children_.push_front(me);
|
||||
parent_->children_.PushFront(me.Get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -520,7 +520,7 @@ void Actor::AddChild(Actor* child, int zorder)
|
|||
|
||||
#endif // KGE_DEBUG
|
||||
|
||||
children_.push_back(child);
|
||||
children_.PushBack(child);
|
||||
child->parent_ = this;
|
||||
child->SetStage(this->stage_);
|
||||
|
||||
|
|
@ -533,7 +533,7 @@ void Actor::AddChild(Actor* child, int zorder)
|
|||
|
||||
void Actor::AddChild(ActorPtr child, int zorder)
|
||||
{
|
||||
AddChild(child.get());
|
||||
AddChild(child.Get());
|
||||
}
|
||||
|
||||
void Actor::AddChildren(Vector<ActorPtr> const& children)
|
||||
|
|
@ -559,25 +559,25 @@ Vector<ActorPtr> Actor::GetChildren(String const& name) const
|
|||
Vector<ActorPtr> children;
|
||||
size_t hash_code = std::hash<String>{}(name);
|
||||
|
||||
for (auto child = children_.first_item().get(); child; child = child->next_item().get())
|
||||
for (const auto& child : children_)
|
||||
{
|
||||
if (child->hash_name_ == hash_code && child->IsName(name))
|
||||
if (child.hash_name_ == hash_code && child.IsName(name))
|
||||
{
|
||||
children.push_back(const_cast<Actor*>(child));
|
||||
children.push_back(const_cast<Actor*>(&child));
|
||||
}
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
Actor* Actor::GetChild(String const& name) const
|
||||
ActorPtr Actor::GetChild(String const& name) const
|
||||
{
|
||||
size_t hash_code = std::hash<String>{}(name);
|
||||
|
||||
for (auto child = children_.first_item().get(); child; child = child->next_item().get())
|
||||
for (const auto& child : children_)
|
||||
{
|
||||
if (child->hash_name_ == hash_code && child->IsName(name))
|
||||
if (child.hash_name_ == hash_code && child.IsName(name))
|
||||
{
|
||||
return const_cast<Actor*>(child);
|
||||
return const_cast<Actor*>(&child);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
|
|
@ -603,14 +603,14 @@ void Actor::RemoveFromParent()
|
|||
|
||||
void Actor::RemoveChild(ActorPtr child)
|
||||
{
|
||||
RemoveChild(child.get());
|
||||
RemoveChild(child.Get());
|
||||
}
|
||||
|
||||
void Actor::RemoveChild(Actor* child)
|
||||
{
|
||||
KGE_ASSERT(child && "Actor::RemoveChild failed, NULL pointer exception");
|
||||
|
||||
if (children_.empty())
|
||||
if (children_.IsEmpty())
|
||||
return;
|
||||
|
||||
if (child)
|
||||
|
|
@ -618,23 +618,23 @@ void Actor::RemoveChild(Actor* child)
|
|||
child->parent_ = nullptr;
|
||||
if (child->stage_)
|
||||
child->SetStage(nullptr);
|
||||
children_.remove(ActorPtr(child));
|
||||
children_.Remove(child);
|
||||
}
|
||||
}
|
||||
|
||||
void Actor::RemoveChildren(String const& child_name)
|
||||
{
|
||||
if (children_.empty())
|
||||
if (children_.IsEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
size_t hash_code = std::hash<String>{}(child_name);
|
||||
|
||||
Actor* next;
|
||||
for (Actor* child = children_.first_item().get(); child; child = next)
|
||||
ActorPtr next;
|
||||
for (ActorPtr child = children_.GetFirst(); child; child = next)
|
||||
{
|
||||
next = child->next_item().get();
|
||||
next = child->GetNext();
|
||||
|
||||
if (child->hash_name_ == hash_code && child->IsName(child_name))
|
||||
{
|
||||
|
|
@ -645,7 +645,7 @@ void Actor::RemoveChildren(String const& child_name)
|
|||
|
||||
void Actor::RemoveAllChildren()
|
||||
{
|
||||
children_.clear();
|
||||
children_.Clear();
|
||||
}
|
||||
|
||||
void Actor::SetResponsible(bool enable)
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include <kiwano/core/ObjectBase.h>
|
||||
#include <kiwano/core/Time.h>
|
||||
#include <kiwano/core/TimerManager.h>
|
||||
#include <kiwano/core/IntrusiveList.h>
|
||||
#include <kiwano/math/Math.h>
|
||||
|
||||
namespace kiwano
|
||||
|
|
@ -55,7 +56,7 @@ class KGE_API Actor
|
|||
, public TimerManager
|
||||
, public ActionManager
|
||||
, public EventDispatcher
|
||||
, protected IntrusiveListItem<ActorPtr>
|
||||
, protected IntrusiveListValue<ActorPtr>
|
||||
{
|
||||
friend class Director;
|
||||
friend class Transition;
|
||||
|
|
@ -334,7 +335,7 @@ public:
|
|||
|
||||
/// \~chinese
|
||||
/// @brief 获取名称相同的子角色
|
||||
Actor* GetChild(String const& name) const;
|
||||
ActorPtr GetChild(String const& name) const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取所有名称相同的子角色
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include <kiwano/core/ObjectBase.h>
|
||||
#include <kiwano/core/SmartPtr.hpp>
|
||||
#include <kiwano/core/Time.h>
|
||||
#include <kiwano/core/IntrusiveList.h>
|
||||
#include <kiwano/math/Math.h>
|
||||
|
||||
namespace kiwano
|
||||
|
|
@ -46,7 +47,7 @@ KGE_DECLARE_SMART_PTR(Action);
|
|||
/// @brief 动画
|
||||
class KGE_API Action
|
||||
: public virtual ObjectBase
|
||||
, protected IntrusiveListItem<ActionPtr>
|
||||
, protected IntrusiveListValue<ActionPtr>
|
||||
{
|
||||
friend class ActionManager;
|
||||
friend class ActionGroup;
|
||||
|
|
|
|||
|
|
@ -49,23 +49,25 @@ ActionGroup::~ActionGroup() {}
|
|||
|
||||
void ActionGroup::Init(Actor* target)
|
||||
{
|
||||
if (actions_.empty())
|
||||
if (actions_.IsEmpty())
|
||||
{
|
||||
Done();
|
||||
return;
|
||||
}
|
||||
|
||||
current_ = actions_.first_item();
|
||||
current_->Restart(target); // init first action
|
||||
|
||||
if (sync_)
|
||||
{
|
||||
// init all actions
|
||||
for (; current_; current_ = current_->next_item())
|
||||
for (current_ = actions_.GetFirst(); current_; current_ = current_->GetNext())
|
||||
{
|
||||
current_->Restart(target);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
current_ = actions_.GetFirst();
|
||||
current_->Restart(target); // init first action
|
||||
}
|
||||
}
|
||||
|
||||
void ActionGroup::Update(Actor* target, Duration dt)
|
||||
|
|
@ -78,7 +80,7 @@ void ActionGroup::Update(Actor* target, Duration dt)
|
|||
|
||||
if (current_->IsDone())
|
||||
{
|
||||
current_ = current_->next_item();
|
||||
current_ = current_->GetNext();
|
||||
|
||||
if (current_)
|
||||
current_->Restart(target); // init next action
|
||||
|
|
@ -90,7 +92,7 @@ void ActionGroup::Update(Actor* target, Duration dt)
|
|||
else
|
||||
{
|
||||
bool done = true;
|
||||
for (current_ = actions_.first_item(); current_; current_ = current_->next_item())
|
||||
for (current_ = actions_.GetFirst(); current_; current_ = current_->GetNext())
|
||||
{
|
||||
if (!current_->IsDone())
|
||||
{
|
||||
|
|
@ -110,7 +112,7 @@ void ActionGroup::AddAction(ActionPtr action)
|
|||
{
|
||||
if (action)
|
||||
{
|
||||
actions_.push_back(action);
|
||||
actions_.PushBack(action);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -123,9 +125,9 @@ void ActionGroup::AddActions(Vector<ActionPtr> const& actions)
|
|||
ActionPtr ActionGroup::Clone() const
|
||||
{
|
||||
Vector<ActionPtr> actions;
|
||||
if (!actions_.empty())
|
||||
if (!actions_.IsEmpty())
|
||||
{
|
||||
for (auto action = actions_.last_item(); action; action = action->prev_item())
|
||||
for (auto action = actions_.GetLast(); action; action = action->GetPrev())
|
||||
{
|
||||
actions.push_back(action->Clone());
|
||||
}
|
||||
|
|
@ -136,9 +138,9 @@ ActionPtr ActionGroup::Clone() const
|
|||
ActionPtr ActionGroup::Reverse() const
|
||||
{
|
||||
Vector<ActionPtr> actions;
|
||||
if (!actions_.empty())
|
||||
if (!actions_.IsEmpty())
|
||||
{
|
||||
for (auto action = actions_.last_item(); action; action = action->prev_item())
|
||||
for (auto action = actions_.GetLast(); action; action = action->GetPrev())
|
||||
{
|
||||
actions.push_back(action->Reverse());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,25 +26,25 @@ namespace kiwano
|
|||
{
|
||||
void ActionManager::UpdateActions(Actor* target, Duration dt)
|
||||
{
|
||||
if (actions_.empty() || !target)
|
||||
if (actions_.IsEmpty() || !target)
|
||||
return;
|
||||
|
||||
ActionPtr next;
|
||||
for (auto action = actions_.first_item(); action; action = next)
|
||||
for (auto action = actions_.GetFirst(); action; action = next)
|
||||
{
|
||||
next = action->next_item();
|
||||
next = action->GetNext();
|
||||
|
||||
if (action->IsRunning())
|
||||
action->UpdateStep(target, dt);
|
||||
|
||||
if (action->IsRemoveable())
|
||||
actions_.remove(action);
|
||||
actions_.Remove(action);
|
||||
}
|
||||
}
|
||||
|
||||
Action* ActionManager::AddAction(ActionPtr action)
|
||||
{
|
||||
return AddAction(action.get());
|
||||
return AddAction(action.Get());
|
||||
}
|
||||
|
||||
Action* ActionManager::AddAction(Action* action)
|
||||
|
|
@ -53,14 +53,14 @@ Action* ActionManager::AddAction(Action* action)
|
|||
|
||||
if (action)
|
||||
{
|
||||
actions_.push_back(action);
|
||||
actions_.PushBack(action);
|
||||
}
|
||||
return action;
|
||||
}
|
||||
|
||||
void ActionManager::ResumeAllActions()
|
||||
{
|
||||
if (actions_.empty())
|
||||
if (actions_.IsEmpty())
|
||||
return;
|
||||
|
||||
for (auto& action : actions_)
|
||||
|
|
@ -71,7 +71,7 @@ void ActionManager::ResumeAllActions()
|
|||
|
||||
void ActionManager::PauseAllActions()
|
||||
{
|
||||
if (actions_.empty())
|
||||
if (actions_.IsEmpty())
|
||||
return;
|
||||
|
||||
for (auto& action : actions_)
|
||||
|
|
@ -82,7 +82,7 @@ void ActionManager::PauseAllActions()
|
|||
|
||||
void ActionManager::StopAllActions()
|
||||
{
|
||||
if (actions_.empty())
|
||||
if (actions_.IsEmpty())
|
||||
return;
|
||||
|
||||
for (auto& action : actions_)
|
||||
|
|
@ -93,7 +93,7 @@ void ActionManager::StopAllActions()
|
|||
|
||||
ActionPtr ActionManager::GetAction(String const& name)
|
||||
{
|
||||
if (actions_.empty())
|
||||
if (actions_.IsEmpty())
|
||||
return nullptr;
|
||||
|
||||
for (auto& action : actions_)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,464 @@
|
|||
// 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 <typeinfo>
|
||||
#include <type_traits>
|
||||
#include <exception>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 可储存单个任意对象的容器
|
||||
class Any
|
||||
{
|
||||
public:
|
||||
Any()
|
||||
: storage_{}
|
||||
{
|
||||
}
|
||||
|
||||
template <typename _Ty, typename _Decayed = typename std::decay<_Ty>::type,
|
||||
typename std::enable_if<std::is_copy_constructible<_Decayed>::value, int>::type = 0>
|
||||
Any(_Ty&& val)
|
||||
: storage_{}
|
||||
{
|
||||
Emplace<_Decayed>(std::forward<_Ty>(val));
|
||||
}
|
||||
|
||||
template <typename _Ty, typename... _Args>
|
||||
Any(_Args&&... args)
|
||||
: storage_{}
|
||||
{
|
||||
using _Decayed = typename std::decay<_Ty>::type;
|
||||
|
||||
Clear();
|
||||
EmplaceDecayed<_Decayed>(std::forward<_Args>(args)...);
|
||||
}
|
||||
|
||||
Any(const Any& rhs)
|
||||
: storage_{}
|
||||
{
|
||||
CopyFrom(rhs);
|
||||
}
|
||||
|
||||
Any(Any&& rhs) noexcept
|
||||
: storage_{}
|
||||
{
|
||||
MoveFrome(std::move(rhs));
|
||||
}
|
||||
|
||||
~Any()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取含有对象类型
|
||||
inline const type_info& GetType() const noexcept
|
||||
{
|
||||
const type_info* const info = GetTypeinfo();
|
||||
if (info)
|
||||
{
|
||||
return *info;
|
||||
}
|
||||
return typeid(void);
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 是否含有对象
|
||||
inline bool HasValue() const noexcept
|
||||
{
|
||||
return GetTypeinfo() != nullptr;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 从参数构造对象
|
||||
template <typename _Ty, typename... _Args>
|
||||
void Emplace(_Args&&... args)
|
||||
{
|
||||
using _Decayed = typename std::decay<_Ty>::type;
|
||||
|
||||
Clear();
|
||||
EmplaceDecayed<_Decayed>(std::forward<_Args>(args)...);
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 交换容器
|
||||
void Swap(Any& rhs) noexcept
|
||||
{
|
||||
Any old = std::move(rhs);
|
||||
rhs = std::move(*this);
|
||||
*this = std::move(old);
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 销毁所含对象
|
||||
inline void Clear() noexcept
|
||||
{
|
||||
Tidy();
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 转换为指定类型的指针
|
||||
template <typename _Ty>
|
||||
_Ty* CastPtr() noexcept
|
||||
{
|
||||
return const_cast<_Ty*>(const_cast<const Any*>(this)->CastPtr<_Ty>());
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 转换为指定类型的指针
|
||||
template <typename _Ty>
|
||||
const _Ty* CastPtr() const noexcept
|
||||
{
|
||||
static_assert(!std::is_void<_Ty>::value, "oc::Any cannot contain void");
|
||||
|
||||
const type_info* const info = GetTypeinfo();
|
||||
if (info && (*info == typeid(std::decay<_Ty>::type)))
|
||||
{
|
||||
if (HasSmallType())
|
||||
{
|
||||
return static_cast<const _Ty*>(GetSmallData());
|
||||
}
|
||||
else
|
||||
{
|
||||
return static_cast<const _Ty*>(GetBigData());
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 转换为指定类型
|
||||
/// @throw std::bad_cast 转换失败时抛出
|
||||
template <typename _Ty>
|
||||
_Ty Cast()
|
||||
{
|
||||
using _Decayed = typename std::decay<_Ty>::type;
|
||||
|
||||
const auto ptr = CastPtr<_Decayed>();
|
||||
if (!ptr)
|
||||
{
|
||||
throw std::bad_cast();
|
||||
}
|
||||
return static_cast<_Ty>(*ptr);
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 转换为指定类型
|
||||
/// @throw std::bad_cast 转换失败时抛出
|
||||
template <typename _Ty>
|
||||
_Ty Cast() const
|
||||
{
|
||||
using _Decayed = typename std::decay<_Ty>::type;
|
||||
|
||||
const auto ptr = CastPtr<_Decayed>();
|
||||
if (!ptr)
|
||||
{
|
||||
throw std::bad_cast();
|
||||
}
|
||||
return static_cast<_Ty>(*ptr);
|
||||
}
|
||||
|
||||
Any& operator=(const Any& rhs)
|
||||
{
|
||||
*this = Any(rhs);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
Any& operator=(Any&& rhs) noexcept
|
||||
{
|
||||
Clear();
|
||||
MoveFrome(std::move(rhs));
|
||||
return (*this);
|
||||
}
|
||||
|
||||
private:
|
||||
const type_info*& GetTypeinfo()
|
||||
{
|
||||
return storage_.small_.info_;
|
||||
}
|
||||
|
||||
const type_info* GetTypeinfo() const
|
||||
{
|
||||
return storage_.small_.info_;
|
||||
}
|
||||
|
||||
template <typename _Decayed, typename... _Args>
|
||||
inline void EmplaceDecayed(_Args&&... args)
|
||||
{
|
||||
Store<_Decayed>(IsSmallSize<_Decayed>{}, std::forward<_Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename _Decayed, typename... _Args>
|
||||
void Store(std::true_type, _Args&&... args)
|
||||
{
|
||||
storage_.is_small_ = true;
|
||||
GetTypeinfo() = &typeid(_Decayed);
|
||||
GetSmallRTTI() = SmallStorageRTTI::make<_Decayed>();
|
||||
|
||||
::new (GetSmallData()) _Decayed(std::forward<_Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename _Decayed, typename... _Args>
|
||||
void Store(std::false_type, _Args&&... args)
|
||||
{
|
||||
storage_.is_small_ = false;
|
||||
GetTypeinfo() = &typeid(_Decayed);
|
||||
GetBigRTTI() = BigStorageRTTI::make<_Decayed>();
|
||||
|
||||
GetBigData() = ::new _Decayed(std::forward<_Args>(args)...);
|
||||
}
|
||||
|
||||
void Tidy() noexcept
|
||||
{
|
||||
if (HasValue())
|
||||
{
|
||||
if (HasSmallType())
|
||||
{
|
||||
GetSmallRTTI().destroy(GetSmallData());
|
||||
}
|
||||
else
|
||||
{
|
||||
GetBigRTTI().destroy(GetBigData());
|
||||
GetBigData() = nullptr;
|
||||
}
|
||||
GetTypeinfo() = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void CopyFrom(const Any& rhs)
|
||||
{
|
||||
if (rhs.HasValue())
|
||||
{
|
||||
GetTypeinfo() = rhs.GetTypeinfo();
|
||||
storage_.is_small_ = rhs.storage_.is_small_;
|
||||
|
||||
if (rhs.HasSmallType())
|
||||
{
|
||||
GetSmallRTTI() = rhs.GetSmallRTTI();
|
||||
GetSmallRTTI().copy(GetSmallData(), rhs.GetSmallData());
|
||||
}
|
||||
else
|
||||
{
|
||||
GetBigRTTI() = rhs.GetBigRTTI();
|
||||
GetBigData() = GetBigRTTI().copy(rhs.GetBigData());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MoveFrome(Any&& rhs) noexcept
|
||||
{
|
||||
if (rhs.HasValue())
|
||||
{
|
||||
GetTypeinfo() = rhs.GetTypeinfo();
|
||||
storage_.is_small_ = rhs.storage_.is_small_;
|
||||
|
||||
if (rhs.HasSmallType())
|
||||
{
|
||||
GetSmallRTTI() = rhs.GetSmallRTTI();
|
||||
GetSmallRTTI().move(GetSmallData(), rhs.GetSmallData());
|
||||
}
|
||||
else
|
||||
{
|
||||
GetBigRTTI() = rhs.GetBigRTTI();
|
||||
GetBigData() = rhs.GetBigData();
|
||||
rhs.GetTypeinfo() = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void* GetSmallData()
|
||||
{
|
||||
return storage_.small_.buffer_;
|
||||
}
|
||||
|
||||
inline const void* GetSmallData() const
|
||||
{
|
||||
return storage_.small_.buffer_;
|
||||
}
|
||||
|
||||
inline void*& GetBigData()
|
||||
{
|
||||
return storage_.big_.ptr_;
|
||||
}
|
||||
|
||||
inline void* GetBigData() const
|
||||
{
|
||||
return storage_.big_.ptr_;
|
||||
}
|
||||
|
||||
inline bool HasSmallType() const
|
||||
{
|
||||
return storage_.is_small_;
|
||||
}
|
||||
|
||||
private:
|
||||
static const auto ANY_SMALL_SPACE_SIZE = 8U;
|
||||
|
||||
template <typename _Ty>
|
||||
struct IsSmallSize : public std::bool_constant<sizeof(_Ty) <= ANY_SMALL_SPACE_SIZE>
|
||||
{
|
||||
};
|
||||
|
||||
struct BigStorageRTTI
|
||||
{
|
||||
using DestroyFunc = void(void*);
|
||||
using CopyFunc = void*(const void*);
|
||||
|
||||
BigStorageRTTI()
|
||||
{
|
||||
destroy = nullptr;
|
||||
copy = nullptr;
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
static inline BigStorageRTTI make()
|
||||
{
|
||||
BigStorageRTTI rtti;
|
||||
rtti.destroy = &BigStorageRTTI::Destroy<_Ty>;
|
||||
rtti.copy = &BigStorageRTTI::Copy<_Ty>;
|
||||
return rtti;
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
static void Destroy(void* const ptr) noexcept
|
||||
{
|
||||
::delete static_cast<_Ty*>(ptr);
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
static void* Copy(const void* const ptr) noexcept
|
||||
{
|
||||
return ::new _Ty(*static_cast<const _Ty*>(ptr));
|
||||
}
|
||||
|
||||
DestroyFunc* destroy;
|
||||
CopyFunc* copy;
|
||||
};
|
||||
|
||||
struct SmallStorageRTTI
|
||||
{
|
||||
using DestroyFunc = void(void*);
|
||||
using CopyFunc = void*(void*, const void*);
|
||||
using MoveFunc = void*(void*, void*);
|
||||
|
||||
SmallStorageRTTI()
|
||||
{
|
||||
destroy = nullptr;
|
||||
copy = nullptr;
|
||||
move = nullptr;
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
static inline SmallStorageRTTI make()
|
||||
{
|
||||
SmallStorageRTTI rtti;
|
||||
rtti.destroy = &SmallStorageRTTI::Destroy<_Ty>;
|
||||
rtti.copy = &SmallStorageRTTI::Copy<_Ty>;
|
||||
rtti.move = &SmallStorageRTTI::Move<_Ty>;
|
||||
return rtti;
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
static void Destroy(void* const ptr) noexcept
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
_Ty& obj = *(static_cast<_Ty* const>(ptr));
|
||||
obj.~_Ty();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
static void* Copy(void* const target, const void* const ptr) noexcept
|
||||
{
|
||||
return ::new (static_cast<_Ty*>(target)) _Ty(*static_cast<const _Ty*>(ptr));
|
||||
}
|
||||
|
||||
template <typename _Ty>
|
||||
static void* Move(void* const target, void* const ptr) noexcept
|
||||
{
|
||||
return ::new (static_cast<_Ty*>(target)) _Ty(std::move(*static_cast<_Ty*>(ptr)));
|
||||
}
|
||||
|
||||
DestroyFunc* destroy;
|
||||
CopyFunc* copy;
|
||||
MoveFunc* move;
|
||||
};
|
||||
|
||||
private:
|
||||
inline SmallStorageRTTI& GetSmallRTTI()
|
||||
{
|
||||
return storage_.small_.rtti_;
|
||||
}
|
||||
|
||||
inline const SmallStorageRTTI& GetSmallRTTI() const
|
||||
{
|
||||
return storage_.small_.rtti_;
|
||||
}
|
||||
|
||||
inline BigStorageRTTI& GetBigRTTI()
|
||||
{
|
||||
return storage_.big_.rtti_;
|
||||
}
|
||||
|
||||
inline const BigStorageRTTI& GetBigRTTI() const
|
||||
{
|
||||
return storage_.big_.rtti_;
|
||||
}
|
||||
|
||||
private:
|
||||
struct SmallStorage
|
||||
{
|
||||
const type_info* info_;
|
||||
SmallStorageRTTI rtti_;
|
||||
char buffer_[ANY_SMALL_SPACE_SIZE];
|
||||
};
|
||||
|
||||
struct BigStorage
|
||||
{
|
||||
const type_info* info_;
|
||||
BigStorageRTTI rtti_;
|
||||
void* ptr_;
|
||||
};
|
||||
|
||||
struct Storage
|
||||
{
|
||||
bool is_small_;
|
||||
union
|
||||
{
|
||||
SmallStorage small_;
|
||||
BigStorage big_;
|
||||
};
|
||||
|
||||
Storage()
|
||||
: is_small_(false)
|
||||
, small_()
|
||||
{
|
||||
} // fix error C2280 for VisualStudio 2015
|
||||
};
|
||||
|
||||
Storage storage_;
|
||||
};
|
||||
|
||||
} // namespace kiwano
|
||||
|
|
@ -29,9 +29,10 @@
|
|||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <kiwano/macros.h>
|
||||
#include <kiwano/core/String.h>
|
||||
#include <kiwano/core/Function.h>
|
||||
#include <kiwano/core/Singleton.h>
|
||||
#include <3rd-party/OuterC/oc/oc.h>
|
||||
#include <3rd-party/nlohmann/json.hpp>
|
||||
#include <kiwano/core/Any.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
|
@ -44,14 +45,6 @@ using InputStream = std::istream;
|
|||
/// @brief 输出流
|
||||
using OutputStream = std::ostream;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 字符串容器
|
||||
using String = oc::string;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 宽字符串容器
|
||||
using WideString = oc::wstring;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 字符串流
|
||||
using StringStream = std::stringstream;
|
||||
|
|
@ -105,84 +98,17 @@ using Map = std::map<_Kty, _Ty, _Args...>;
|
|||
template <typename _Kty, typename _Ty, typename... _Args>
|
||||
using UnorderedMap = std::unordered_map<_Kty, _Ty, _Args...>;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 函数封装器
|
||||
template <typename _FuncTy>
|
||||
using Function = oc::function<_FuncTy>;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 单值容器
|
||||
using Any = oc::any;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 侵入式链表容器
|
||||
template <typename _Ty>
|
||||
using IntrusiveList = oc::intrusive_list<_Ty>;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 侵入式链表元素
|
||||
template <typename _Ty>
|
||||
using IntrusiveListItem = oc::intrusive_list_item<_Ty>;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 侵入式智能指针
|
||||
template <typename _Ty, typename _RefProxyTy>
|
||||
using IntrusivePtr = oc::intrusive_ptr<_Ty, _RefProxyTy>;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief JSON对象容器
|
||||
using Json = nlohmann::basic_json<Map, Vector, String>;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 不可拷贝对象
|
||||
using Noncopyable = oc::noncopyable;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 闭包函数
|
||||
template <typename _Ty, typename _Uty, typename _Ret, typename... _Args>
|
||||
inline Function<_Ret(_Args...)> Closure(_Uty* ptr, _Ret (_Ty::*func)(_Args...))
|
||||
class Noncopyable
|
||||
{
|
||||
return oc::closure(ptr, func);
|
||||
}
|
||||
protected:
|
||||
Noncopyable() = default;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 闭包函数
|
||||
template <typename _Ty, typename _Uty, typename _Ret, typename... _Args>
|
||||
inline Function<_Ret(_Args...)> Closure(_Uty* ptr, _Ret (_Ty::*func)(_Args...) const)
|
||||
{
|
||||
return oc::closure(ptr, func);
|
||||
}
|
||||
private:
|
||||
Noncopyable(const Noncopyable&) = delete;
|
||||
|
||||
#if defined(KGE_WIN32)
|
||||
|
||||
inline String WideToMultiByte(const WideString& str)
|
||||
{
|
||||
int chars_num = ::WideCharToMultiByte(CP_UTF8, 0, str.c_str(), -1, NULL, 0, NULL, NULL);
|
||||
if (chars_num)
|
||||
{
|
||||
String result;
|
||||
result.resize(chars_num);
|
||||
|
||||
::WideCharToMultiByte(CP_UTF8, 0, str.c_str(), -1, &result[0], chars_num, NULL, NULL);
|
||||
return result;
|
||||
}
|
||||
return String();
|
||||
}
|
||||
|
||||
inline WideString MultiByteToWide(const String& str)
|
||||
{
|
||||
int wchars_num = ::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
|
||||
if (wchars_num)
|
||||
{
|
||||
WideString result;
|
||||
result.resize(wchars_num);
|
||||
|
||||
::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, &result[0], wchars_num);
|
||||
return result;
|
||||
}
|
||||
return WideString();
|
||||
}
|
||||
|
||||
#endif // KGE_WIN32
|
||||
Noncopyable& operator=(const Noncopyable&) = delete;
|
||||
};
|
||||
|
||||
} // namespace kiwano
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ void Director::ShowDebugInfo(bool show)
|
|||
}
|
||||
else
|
||||
{
|
||||
debug_actor_.reset();
|
||||
debug_actor_.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -113,10 +113,10 @@ void Director::ClearStages()
|
|||
while (!stages_.empty())
|
||||
stages_.pop();
|
||||
|
||||
current_stage_.reset();
|
||||
next_stage_.reset();
|
||||
transition_.reset();
|
||||
debug_actor_.reset();
|
||||
current_stage_.Reset();
|
||||
next_stage_.Reset();
|
||||
transition_.Reset();
|
||||
debug_actor_.Reset();
|
||||
}
|
||||
|
||||
void Director::OnUpdate(Duration dt)
|
||||
|
|
|
|||
|
|
@ -25,19 +25,19 @@ namespace kiwano
|
|||
{
|
||||
bool EventDispatcher::DispatchEvent(Event* evt)
|
||||
{
|
||||
if (listeners_.empty())
|
||||
if (listeners_.IsEmpty())
|
||||
return true;
|
||||
|
||||
EventListenerPtr next;
|
||||
for (auto listener = listeners_.first_item(); listener; listener = next)
|
||||
for (auto listener = listeners_.GetFirst(); listener; listener = next)
|
||||
{
|
||||
next = listener->next_item();
|
||||
next = listener->GetNext();
|
||||
|
||||
if (listener->IsRunning())
|
||||
listener->Receive(evt);
|
||||
|
||||
if (listener->IsRemoveable())
|
||||
listeners_.remove(listener);
|
||||
listeners_.Remove(listener);
|
||||
|
||||
if (listener->IsSwallowEnabled())
|
||||
return false;
|
||||
|
|
@ -47,7 +47,7 @@ bool EventDispatcher::DispatchEvent(Event* evt)
|
|||
|
||||
EventListener* EventDispatcher::AddListener(EventListenerPtr listener)
|
||||
{
|
||||
return AddListener(listener.get());
|
||||
return AddListener(listener.Get());
|
||||
}
|
||||
|
||||
EventListener* EventDispatcher::AddListener(EventListener* listener)
|
||||
|
|
@ -56,7 +56,7 @@ EventListener* EventDispatcher::AddListener(EventListener* listener)
|
|||
|
||||
if (listener)
|
||||
{
|
||||
listeners_.push_back(listener);
|
||||
listeners_.PushBack(listener);
|
||||
}
|
||||
return listener;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include <kiwano/core/Common.h>
|
||||
#include <kiwano/core/ObjectBase.h>
|
||||
#include <kiwano/core/SmartPtr.hpp>
|
||||
#include <kiwano/core/IntrusiveList.h>
|
||||
#include <kiwano/core/event/Event.h>
|
||||
#include <kiwano/core/event/KeyEvent.h>
|
||||
#include <kiwano/core/event/MouseEvent.h>
|
||||
|
|
@ -39,7 +40,7 @@ KGE_DECLARE_SMART_PTR(EventListener);
|
|||
*/
|
||||
class KGE_API EventListener
|
||||
: public virtual ObjectBase
|
||||
, protected IntrusiveListItem<EventListenerPtr>
|
||||
, protected IntrusiveListValue<EventListenerPtr>
|
||||
{
|
||||
friend class EventDispatcher;
|
||||
friend IntrusiveList<EventListenerPtr>;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
#include <kiwano/core/Library.h>
|
||||
#include <kiwano/core/Logger.h>
|
||||
|
||||
#if defined(KGE_WIN32)
|
||||
#if defined(KGE_PLATFORM_WINDOWS)
|
||||
#include <comdef.h>
|
||||
|
||||
namespace kiwano
|
||||
|
|
@ -42,12 +42,7 @@ public:
|
|||
// converted to an ANSI string using the CP_ACP codepage.
|
||||
std::string message(int hr) const override
|
||||
{
|
||||
#ifdef _UNICODE
|
||||
auto message = WideToMultiByte(_com_error{ hr }.ErrorMessage());
|
||||
return message.c_str();
|
||||
#else
|
||||
return _com_error{ hr }.ErrorMessage();
|
||||
#endif
|
||||
return string::ToNarrow(_com_error{ hr }.ErrorMessage());
|
||||
}
|
||||
|
||||
// Make error_condition for error code (generic if possible)
|
||||
|
|
@ -60,7 +55,7 @@ public:
|
|||
return std::system_category().default_error_condition(HRESULT_CODE(hr));
|
||||
else
|
||||
// special error condition
|
||||
return { hr, com_category() };
|
||||
return make_error_condition(error_enum(hr));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -23,23 +23,35 @@
|
|||
#include <stdexcept>
|
||||
#include <system_error>
|
||||
|
||||
#define KGE_THROW(MESSAGE) \
|
||||
do \
|
||||
{ \
|
||||
kiwano::StackTracer().Print(); \
|
||||
throw std::runtime_error(MESSAGE); \
|
||||
#define KGE_THROW(MESSAGE) \
|
||||
do \
|
||||
{ \
|
||||
kiwano::StackTracer().Print(); \
|
||||
throw kiwano::RuntimeError(MESSAGE); \
|
||||
} while (0)
|
||||
|
||||
#define KGE_THROW_SYSTEM_ERROR(ERRCODE, MESSAGE) \
|
||||
do \
|
||||
{ \
|
||||
kiwano::StackTracer().Print(); \
|
||||
throw std::system_error(std::error_code(kiwano::error_enum(ERRCODE)), MESSAGE); \
|
||||
#define KGE_THROW_SYSTEM_ERROR(ERRCODE, MESSAGE) \
|
||||
do \
|
||||
{ \
|
||||
kiwano::StackTracer().Print(); \
|
||||
throw kiwano::SystemError(std::error_code(kiwano::error_enum(ERRCODE)), MESSAGE); \
|
||||
} while (0)
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 异常
|
||||
typedef std::exception Exception;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 运行时异常
|
||||
typedef std::runtime_error RuntimeError;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 系统异常
|
||||
typedef std::system_error SystemError;
|
||||
|
||||
class StackTracer
|
||||
{
|
||||
public:
|
||||
|
|
@ -48,7 +60,7 @@ public:
|
|||
void Print() const;
|
||||
};
|
||||
|
||||
#ifdef KGE_WIN32
|
||||
#ifdef KGE_PLATFORM_WINDOWS
|
||||
|
||||
// Enables classifying error codes
|
||||
// @note We don't bother listing all possible values
|
||||
|
|
@ -64,7 +76,7 @@ typedef std::errc error_enum;
|
|||
|
||||
} // namespace kiwano
|
||||
|
||||
#ifdef KGE_WIN32
|
||||
#ifdef KGE_PLATFORM_WINDOWS
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
|
@ -89,14 +101,12 @@ inline std::error_condition make_error_condition(kiwano::error_enum errc) noexce
|
|||
return std::error_condition(static_cast<int>(errc), kiwano::com_category());
|
||||
}
|
||||
|
||||
inline void ThrowIfFailed(HRESULT hr, const String& message)
|
||||
{
|
||||
if (FAILED(hr))
|
||||
{
|
||||
KGE_THROW_SYSTEM_ERROR(hr, message.c_str());
|
||||
#define KGE_THROW_IF_FAILED(HR, MESSAGE) \
|
||||
if (FAILED(HR)) \
|
||||
{ \
|
||||
KGE_THROW_SYSTEM_ERROR(HR, MESSAGE); \
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace kiwano
|
||||
|
||||
#endif // KGE_WIN32
|
||||
#endif // KGE_PLATFORM_WINDOWS
|
||||
|
|
|
|||
|
|
@ -0,0 +1,388 @@
|
|||
// 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 <typeinfo>
|
||||
#include <type_traits>
|
||||
#include <stdexcept>
|
||||
#include <functional>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
|
||||
template <typename _Ty, typename _Ret, typename... _Args>
|
||||
struct IsCallableHelper
|
||||
{
|
||||
template <typename _Uty, _Ret (_Uty::*)(_Args...)>
|
||||
struct ClassMember;
|
||||
|
||||
template <typename _Uty, _Ret (_Uty::*)(_Args...) const>
|
||||
struct ClassConstMember;
|
||||
|
||||
template <typename _Uty>
|
||||
static int Test(...);
|
||||
|
||||
template <typename _Uty>
|
||||
static char Test(ClassMember<_Uty, &_Uty::operator()>*);
|
||||
|
||||
template <typename _Uty>
|
||||
static char Test(ClassConstMember<_Uty, &_Uty::operator()>*);
|
||||
|
||||
template <
|
||||
typename _Uty,
|
||||
typename _Uret = typename std::decay<decltype(std::declval<_Uty>().operator()(std::declval<_Args>()...))>::type,
|
||||
typename = typename std::enable_if<std::is_convertible<_Ret, _Uret>::value>::type>
|
||||
static char Test(int);
|
||||
|
||||
static constexpr bool value = sizeof(Test<_Ty>(0)) == sizeof(char);
|
||||
};
|
||||
|
||||
template <typename _Ty, typename _Ret, typename... _Args>
|
||||
struct IsCallable : public std::bool_constant<IsCallableHelper<_Ty, _Ret, _Args...>::value>
|
||||
{
|
||||
};
|
||||
|
||||
//
|
||||
// Callable
|
||||
//
|
||||
|
||||
template <typename _Ret, typename... _Args>
|
||||
class Callable
|
||||
{
|
||||
public:
|
||||
virtual ~Callable() {}
|
||||
|
||||
virtual void Retain() = 0;
|
||||
virtual void Release() = 0;
|
||||
virtual _Ret Invoke(_Args&&... args) const = 0;
|
||||
|
||||
virtual const type_info& TargetType() const noexcept = 0;
|
||||
|
||||
virtual const void* Target(const type_info& type) const noexcept = 0;
|
||||
};
|
||||
|
||||
template <typename _Ret, typename... _Args>
|
||||
class RefCountCallable : public Callable<_Ret, _Args...>
|
||||
{
|
||||
public:
|
||||
RefCountCallable()
|
||||
: ref_count_(0)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Retain() override
|
||||
{
|
||||
++ref_count_;
|
||||
}
|
||||
|
||||
virtual void Release() override
|
||||
{
|
||||
--ref_count_;
|
||||
if (ref_count_ <= 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int ref_count_;
|
||||
};
|
||||
|
||||
template <typename _Ty, typename _Ret, typename... _Args>
|
||||
class ProxyCallable : public RefCountCallable<_Ret, _Args...>
|
||||
{
|
||||
public:
|
||||
ProxyCallable(_Ty&& val)
|
||||
: callee_(std::move(val))
|
||||
{
|
||||
}
|
||||
|
||||
virtual _Ret Invoke(_Args&&... args) const override
|
||||
{
|
||||
return std::invoke(callee_, std::forward<_Args>(args)...);
|
||||
}
|
||||
|
||||
virtual const type_info& TargetType() const noexcept
|
||||
{
|
||||
return typeid(_Ty);
|
||||
}
|
||||
|
||||
virtual const void* Target(const type_info& type) const noexcept
|
||||
{
|
||||
if (type == this->TargetType())
|
||||
return &callee_;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static inline Callable<_Ret, _Args...>* Make(_Ty&& val)
|
||||
{
|
||||
return new (std::nothrow) ProxyCallable<_Ty, _Ret, _Args...>(std::move(val));
|
||||
}
|
||||
|
||||
private:
|
||||
_Ty callee_;
|
||||
};
|
||||
|
||||
template <typename _Ty, typename _Ret, typename... _Args>
|
||||
class ProxyMemCallable : public RefCountCallable<_Ret, _Args...>
|
||||
{
|
||||
public:
|
||||
typedef _Ret (_Ty::*_FuncType)(_Args...);
|
||||
|
||||
virtual _Ret Invoke(_Args&&... args) const override
|
||||
{
|
||||
return std::invoke(func_, ptr_, std::forward<_Args>(args)...);
|
||||
}
|
||||
|
||||
virtual const type_info& TargetType() const noexcept
|
||||
{
|
||||
return typeid(ProxyMemCallable);
|
||||
}
|
||||
|
||||
virtual const void* Target(const type_info& type) const noexcept
|
||||
{
|
||||
if (type == this->TargetType())
|
||||
return this;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static inline Callable<_Ret, _Args...>* Make(_Ty* ptr, _FuncType func)
|
||||
{
|
||||
return new (std::nothrow) ProxyMemCallable<_Ty, _Ret, _Args...>(ptr, func);
|
||||
}
|
||||
|
||||
protected:
|
||||
ProxyMemCallable(_Ty* ptr, _FuncType func)
|
||||
: ptr_(ptr)
|
||||
, func_(func)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
_Ty* ptr_;
|
||||
_FuncType func_;
|
||||
};
|
||||
|
||||
template <typename _Ty, typename _Ret, typename... _Args>
|
||||
class ProxyConstMemCallable : public RefCountCallable<_Ret, _Args...>
|
||||
{
|
||||
public:
|
||||
typedef _Ret (_Ty::*_FuncType)(_Args...) const;
|
||||
|
||||
virtual _Ret Invoke(_Args&&... args) const override
|
||||
{
|
||||
return std::invoke(func_, ptr_, std::forward<_Args>(args)...);
|
||||
}
|
||||
|
||||
virtual const type_info& TargetType() const noexcept
|
||||
{
|
||||
return typeid(ProxyConstMemCallable);
|
||||
}
|
||||
|
||||
virtual const void* Target(const type_info& type) const noexcept
|
||||
{
|
||||
if (type == this->TargetType())
|
||||
return this;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static inline Callable<_Ret, _Args...>* Make(_Ty* ptr, _FuncType func)
|
||||
{
|
||||
return new (std::nothrow) ProxyConstMemCallable<_Ty, _Ret, _Args...>(ptr, func);
|
||||
}
|
||||
|
||||
protected:
|
||||
ProxyConstMemCallable(_Ty* ptr, _FuncType func)
|
||||
: ptr_(ptr)
|
||||
, func_(func)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
_Ty* ptr_;
|
||||
_FuncType func_;
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
template <typename _Ty>
|
||||
class Function;
|
||||
|
||||
template <typename _Ret, typename... _Args>
|
||||
class Function<_Ret(_Args...)>
|
||||
{
|
||||
public:
|
||||
Function()
|
||||
: callable_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
Function(std::nullptr_t)
|
||||
: callable_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
Function(const Function& rhs)
|
||||
: callable_(nullptr)
|
||||
{
|
||||
SetCallable(rhs.callable_);
|
||||
}
|
||||
|
||||
Function(Function&& rhs) noexcept
|
||||
: callable_(rhs.callable_)
|
||||
{
|
||||
rhs.callable_ = nullptr;
|
||||
}
|
||||
|
||||
Function(_Ret (*func)(_Args...))
|
||||
: callable_(nullptr)
|
||||
{
|
||||
SetCallable(details::ProxyCallable<_Ret (*)(_Args...), _Ret, _Args...>::Make(std::move(func)));
|
||||
}
|
||||
|
||||
template <typename _Ty,
|
||||
typename = typename std::enable_if<details::IsCallable<_Ty, _Ret, _Args...>::value, int>::type>
|
||||
Function(_Ty val)
|
||||
: callable_(nullptr)
|
||||
{
|
||||
SetCallable(details::ProxyCallable<_Ty, _Ret, _Args...>::Make(std::move(val)));
|
||||
}
|
||||
|
||||
template <typename _Ty, typename _Uty,
|
||||
typename = typename std::enable_if<std::is_same<_Ty, _Uty>::value || std::is_base_of<_Ty, _Uty>::value,
|
||||
int>::type>
|
||||
Function(_Uty* ptr, _Ret (_Ty::*func)(_Args...))
|
||||
: callable_(nullptr)
|
||||
{
|
||||
SetCallable(details::ProxyMemCallable<_Ty, _Ret, _Args...>::Make(ptr, func));
|
||||
}
|
||||
|
||||
template <typename _Ty, typename _Uty,
|
||||
typename = typename std::enable_if<std::is_same<_Ty, _Uty>::value || std::is_base_of<_Ty, _Uty>::value,
|
||||
int>::type>
|
||||
Function(_Uty* ptr, _Ret (_Ty::*func)(_Args...) const)
|
||||
: callable_(nullptr)
|
||||
{
|
||||
SetCallable(details::ProxyConstMemCallable<_Ty, _Ret, _Args...>::Make(ptr, func));
|
||||
}
|
||||
|
||||
~Function()
|
||||
{
|
||||
SetCallable(nullptr);
|
||||
}
|
||||
|
||||
inline _Ret operator()(_Args... args) const
|
||||
{
|
||||
if (!callable_)
|
||||
throw std::bad_function_call();
|
||||
return callable_->Invoke(std::forward<_Args>(args)...);
|
||||
}
|
||||
|
||||
inline operator bool() const
|
||||
{
|
||||
return !!callable_;
|
||||
}
|
||||
|
||||
inline Function& operator=(const Function& rhs)
|
||||
{
|
||||
SetCallable(rhs.callable_);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline Function& operator=(Function&& rhs)
|
||||
{
|
||||
SetCallable(nullptr);
|
||||
callable_ = rhs.callable_;
|
||||
rhs.callable_ = nullptr;
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline void swap(const Function& rhs)
|
||||
{
|
||||
std::swap(callable_, rhs.callable_);
|
||||
}
|
||||
|
||||
const type_info& target_type() const noexcept
|
||||
{
|
||||
return callable_->TargetType();
|
||||
}
|
||||
|
||||
template <class _Fx>
|
||||
_Fx* target() noexcept
|
||||
{
|
||||
return reinterpret_cast<_Fx*>(const_cast<void*>(callable_->Target(typeid(_Fx))));
|
||||
}
|
||||
|
||||
template <class _Fx>
|
||||
const _Fx* target() const noexcept
|
||||
{
|
||||
return reinterpret_cast<const _Fx*>(callable_->Target(typeid(_Fx)));
|
||||
}
|
||||
|
||||
private:
|
||||
inline void SetCallable(details::Callable<_Ret, _Args...>* callable)
|
||||
{
|
||||
if (callable_ != callable)
|
||||
{
|
||||
if (callable_)
|
||||
{
|
||||
callable_->Release();
|
||||
callable_ = nullptr;
|
||||
}
|
||||
|
||||
callable_ = callable;
|
||||
if (callable_)
|
||||
{
|
||||
callable_->Retain();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
details::Callable<_Ret, _Args...>* callable_;
|
||||
};
|
||||
|
||||
template <
|
||||
typename _Ty, typename _Uty,
|
||||
typename = typename std::enable_if<std::is_same<_Ty, _Uty>::value || std::is_base_of<_Ty, _Uty>::value, int>::type,
|
||||
typename _Ret, typename... _Args>
|
||||
inline Function<_Ret(_Args...)> Closure(_Uty* ptr, _Ret (_Ty::*func)(_Args...))
|
||||
{
|
||||
return Function<_Ret(_Args...)>(ptr, func);
|
||||
}
|
||||
|
||||
template <
|
||||
typename _Ty, typename _Uty,
|
||||
typename = typename std::enable_if<std::is_same<_Ty, _Uty>::value || std::is_base_of<_Ty, _Uty>::value, int>::type,
|
||||
typename _Ret, typename... _Args>
|
||||
inline Function<_Ret(_Args...)> Closure(_Uty* ptr, _Ret (_Ty::*func)(_Args...) const)
|
||||
{
|
||||
return Function<_Ret(_Args...)>(ptr, func);
|
||||
}
|
||||
|
||||
template <typename _Ret, typename... _Args>
|
||||
inline void swap(kiwano::Function<_Ret(_Args...)>& lhs, kiwano::Function<_Ret(_Args...)>& rhs) noexcept
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
} // namespace kiwano
|
||||
|
|
@ -0,0 +1,495 @@
|
|||
// 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 <type_traits>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
#include <kiwano/macros.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 侵入式链表
|
||||
template <typename _PtrTy>
|
||||
class IntrusiveList
|
||||
{
|
||||
public:
|
||||
using value_type = typename std::pointer_traits<_PtrTy>::element_type;
|
||||
using pointer = typename std::pointer_traits<_PtrTy>::pointer;
|
||||
using reference = value_type&;
|
||||
|
||||
IntrusiveList()
|
||||
: first_()
|
||||
, last_()
|
||||
{
|
||||
}
|
||||
|
||||
~IntrusiveList()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取首元素
|
||||
const pointer GetFirst() const
|
||||
{
|
||||
return first_;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取首元素
|
||||
pointer GetFirst()
|
||||
{
|
||||
return first_;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取尾元素
|
||||
const pointer GetLast() const
|
||||
{
|
||||
return last_;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取尾元素
|
||||
pointer GetLast()
|
||||
{
|
||||
return last_;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 链表是否为空
|
||||
inline bool IsEmpty() const
|
||||
{
|
||||
return first_ == nullptr;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 在链表尾部添加对象
|
||||
void PushBack(pointer child)
|
||||
{
|
||||
if (child->prev_)
|
||||
child->prev_->next_ = child->next_;
|
||||
if (child->next_)
|
||||
child->next_->prev_ = child->prev_;
|
||||
|
||||
child->prev_ = last_;
|
||||
child->next_ = nullptr;
|
||||
|
||||
if (first_)
|
||||
{
|
||||
last_->next_ = child;
|
||||
}
|
||||
else
|
||||
{
|
||||
first_ = child;
|
||||
}
|
||||
|
||||
last_ = child;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 在链表头部添加对象
|
||||
void PushFront(pointer child)
|
||||
{
|
||||
if (child->prev_)
|
||||
child->prev_->next_ = child->next_;
|
||||
if (child->next_)
|
||||
child->next_->prev_ = child->prev_;
|
||||
|
||||
child->prev_ = nullptr;
|
||||
child->next_ = first_;
|
||||
|
||||
if (first_)
|
||||
{
|
||||
first_->prev_ = child;
|
||||
}
|
||||
else
|
||||
{
|
||||
last_ = child;
|
||||
}
|
||||
|
||||
first_ = child;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 在链表的对象前插入新对象
|
||||
void InsertBefore(pointer child, pointer before)
|
||||
{
|
||||
if (child->prev_)
|
||||
child->prev_->next_ = child->next_;
|
||||
if (child->next_)
|
||||
child->next_->prev_ = child->prev_;
|
||||
|
||||
if (before->prev_)
|
||||
before->prev_->next_ = child;
|
||||
else
|
||||
first_ = child;
|
||||
|
||||
child->prev_ = before->prev_;
|
||||
child->next_ = before;
|
||||
before->prev_ = child;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 在链表的对象后插入新对象
|
||||
void InsertAfter(pointer child, pointer after)
|
||||
{
|
||||
if (child->prev_)
|
||||
child->prev_->next_ = child->next_;
|
||||
if (child->next_)
|
||||
child->next_->prev_ = child->prev_;
|
||||
|
||||
if (after->next_)
|
||||
after->next_->prev_ = child;
|
||||
else
|
||||
last_ = child;
|
||||
|
||||
child->next_ = after->next_;
|
||||
child->prev_ = after;
|
||||
after->next_ = child;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 移除对象
|
||||
void Remove(pointer child)
|
||||
{
|
||||
if (child->next_)
|
||||
{
|
||||
child->next_->prev_ = child->prev_;
|
||||
}
|
||||
else
|
||||
{
|
||||
last_ = child->prev_;
|
||||
}
|
||||
|
||||
if (child->prev_)
|
||||
{
|
||||
child->prev_->next_ = child->next_;
|
||||
}
|
||||
else
|
||||
{
|
||||
first_ = child->next_;
|
||||
}
|
||||
|
||||
child->prev_ = nullptr;
|
||||
child->next_ = nullptr;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 清空所有对象
|
||||
void Clear()
|
||||
{
|
||||
pointer p = first_;
|
||||
while (p)
|
||||
{
|
||||
pointer tmp = p;
|
||||
p = p->next_;
|
||||
if (tmp)
|
||||
{
|
||||
tmp->next_ = nullptr;
|
||||
tmp->prev_ = nullptr;
|
||||
}
|
||||
}
|
||||
first_ = nullptr;
|
||||
last_ = nullptr;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 检查链表是否有效
|
||||
bool CheckValid()
|
||||
{
|
||||
if (!first_)
|
||||
return true;
|
||||
|
||||
int pos = 0;
|
||||
pointer p = first_;
|
||||
pointer tmp = p;
|
||||
do
|
||||
{
|
||||
tmp = p;
|
||||
p = p->next_;
|
||||
++pos;
|
||||
|
||||
if (p)
|
||||
{
|
||||
if (p->prev_ != tmp)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tmp != last_)
|
||||
return false;
|
||||
}
|
||||
} while (p);
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
template <typename _PTy>
|
||||
struct Iterator
|
||||
{
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using pointer = _PTy;
|
||||
using reference = IntrusiveList::reference;
|
||||
using difference_type = ptrdiff_t;
|
||||
|
||||
inline Iterator(pointer ptr = nullptr, bool is_end = false)
|
||||
: base_(ptr)
|
||||
, is_end_(is_end)
|
||||
{
|
||||
}
|
||||
|
||||
inline pointer Get() const
|
||||
{
|
||||
KGE_ASSERT(!is_end_);
|
||||
return const_cast<pointer&>(base_);
|
||||
}
|
||||
|
||||
inline reference operator*() const
|
||||
{
|
||||
KGE_ASSERT(base_ && !is_end_);
|
||||
return const_cast<reference>(*base_);
|
||||
}
|
||||
|
||||
inline pointer operator->() const
|
||||
{
|
||||
KGE_ASSERT(base_ && !is_end_);
|
||||
return const_cast<pointer&>(base_);
|
||||
}
|
||||
|
||||
inline Iterator& operator++()
|
||||
{
|
||||
KGE_ASSERT(base_ && !is_end_);
|
||||
pointer next = base_->GetNext();
|
||||
if (next)
|
||||
base_ = next;
|
||||
else
|
||||
is_end_ = true;
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline Iterator operator++(int)
|
||||
{
|
||||
Iterator old = (*this);
|
||||
++(*this);
|
||||
return old;
|
||||
}
|
||||
|
||||
inline Iterator& operator--()
|
||||
{
|
||||
KGE_ASSERT(base_);
|
||||
if (is_end_)
|
||||
is_end_ = false;
|
||||
else
|
||||
base_ = base_->GetPrev();
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline Iterator operator--(int)
|
||||
{
|
||||
Iterator old = (*this);
|
||||
--(*this);
|
||||
return old;
|
||||
}
|
||||
|
||||
inline bool operator==(Iterator const& other) const
|
||||
{
|
||||
return base_ == other.base_ && is_end_ == other.is_end_;
|
||||
}
|
||||
|
||||
inline bool operator!=(Iterator const& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
inline operator bool() const
|
||||
{
|
||||
return base_ != nullptr && !is_end_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool is_end_;
|
||||
IntrusiveList::pointer base_;
|
||||
};
|
||||
|
||||
public:
|
||||
using iterator = Iterator<pointer>;
|
||||
using const_iterator = Iterator<const pointer>;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
inline iterator begin()
|
||||
{
|
||||
return iterator(first_, first_ == nullptr);
|
||||
}
|
||||
|
||||
inline const_iterator begin() const
|
||||
{
|
||||
return const_iterator(first_, first_ == nullptr);
|
||||
}
|
||||
|
||||
inline const_iterator cbegin() const
|
||||
{
|
||||
return begin();
|
||||
}
|
||||
|
||||
inline iterator end()
|
||||
{
|
||||
return iterator(last_, true);
|
||||
}
|
||||
|
||||
inline const_iterator end() const
|
||||
{
|
||||
return const_iterator(last_, true);
|
||||
}
|
||||
|
||||
inline const_iterator cend() const
|
||||
{
|
||||
return end();
|
||||
}
|
||||
|
||||
inline reverse_iterator rbegin()
|
||||
{
|
||||
return reverse_iterator(end());
|
||||
}
|
||||
|
||||
inline const_reverse_iterator rbegin() const
|
||||
{
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
|
||||
inline const_reverse_iterator crbegin() const
|
||||
{
|
||||
return rbegin();
|
||||
}
|
||||
|
||||
inline reverse_iterator rend()
|
||||
{
|
||||
return reverse_iterator(begin());
|
||||
}
|
||||
|
||||
inline const_reverse_iterator rend() const
|
||||
{
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
inline const_reverse_iterator crend() const
|
||||
{
|
||||
return rend();
|
||||
}
|
||||
|
||||
inline pointer front()
|
||||
{
|
||||
if (IsEmpty())
|
||||
throw std::out_of_range("front() called on empty list");
|
||||
return first_;
|
||||
}
|
||||
|
||||
inline const pointer front() const
|
||||
{
|
||||
if (IsEmpty())
|
||||
throw std::out_of_range("front() called on empty list");
|
||||
return first_;
|
||||
}
|
||||
|
||||
inline pointer back()
|
||||
{
|
||||
if (IsEmpty())
|
||||
throw std::out_of_range("back() called on empty list");
|
||||
return last_;
|
||||
}
|
||||
|
||||
inline const pointer back() const
|
||||
{
|
||||
if (IsEmpty())
|
||||
throw std::out_of_range("back() called on empty list");
|
||||
return last_;
|
||||
}
|
||||
|
||||
private:
|
||||
pointer first_;
|
||||
pointer last_;
|
||||
};
|
||||
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 侵入式链表元素
|
||||
template <typename _PtrTy>
|
||||
class IntrusiveListValue
|
||||
{
|
||||
public:
|
||||
using pointer = typename std::pointer_traits<_PtrTy>::pointer;
|
||||
|
||||
IntrusiveListValue()
|
||||
: prev_(nullptr)
|
||||
, next_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
IntrusiveListValue(pointer rhs)
|
||||
: prev_(nullptr)
|
||||
, next_(nullptr)
|
||||
{
|
||||
if (rhs)
|
||||
{
|
||||
prev_ = rhs->prev_;
|
||||
next_ = rhs->next_;
|
||||
}
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取前一元素
|
||||
const pointer GetPrev() const
|
||||
{
|
||||
return prev_;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取前一元素
|
||||
pointer GetPrev()
|
||||
{
|
||||
return prev_;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取下一元素
|
||||
const pointer GetNext() const
|
||||
{
|
||||
return next_;
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取下一元素
|
||||
pointer GetNext()
|
||||
{
|
||||
return next_;
|
||||
}
|
||||
|
||||
private:
|
||||
pointer prev_;
|
||||
pointer next_;
|
||||
|
||||
friend class IntrusiveList<_PtrTy>;
|
||||
};
|
||||
|
||||
} // namespace kiwano
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// 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 <3rd-party/nlohmann/json.hpp>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
||||
/// \~chinese
|
||||
/// @brief JSON对象容器
|
||||
using Json = nlohmann::basic_json<Map, Vector, String>;
|
||||
|
||||
} // namespace kiwano
|
||||
|
|
@ -137,7 +137,7 @@ const WORD red_bg = white | BACKGROUND_RED | BACKGROUND_INTENSITY;
|
|||
const WORD yellow_bg = BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY;
|
||||
const WORD white_bg = BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY;
|
||||
|
||||
const WORD reset = white;
|
||||
const WORD Reset = white;
|
||||
} // namespace console_colors
|
||||
|
||||
#define DECLARE_HANDLE_COLOR(NAME, HANDLE_NAME, COLOR) \
|
||||
|
|
@ -162,7 +162,7 @@ DECLARE_COLOR(green);
|
|||
DECLARE_COLOR(yellow);
|
||||
DECLARE_COLOR(blue);
|
||||
DECLARE_COLOR(white);
|
||||
DECLARE_COLOR(reset);
|
||||
DECLARE_COLOR(Reset);
|
||||
|
||||
DECLARE_BG_COLOR(red);
|
||||
DECLARE_BG_COLOR(green);
|
||||
|
|
|
|||
|
|
@ -18,8 +18,9 @@
|
|||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#include <kiwano/core/Logger.h>
|
||||
#include <kiwano/core/ObjectBase.h>
|
||||
#include <kiwano/core/Logger.h>
|
||||
#include <kiwano/core/Json.h>
|
||||
#include <typeinfo>
|
||||
|
||||
namespace kiwano
|
||||
|
|
@ -88,7 +89,7 @@ void ObjectBase::SetName(String const& name)
|
|||
|
||||
String ObjectBase::DumpObject()
|
||||
{
|
||||
return String::format("{ class=\"%s\" id=%d refcount=%d name=\"%s\" }", typeid(*this).name(), GetObjectID(),
|
||||
return string::Format("{ class=\"%s\" id=%d refcount=%d name=\"%s\" }", typeid(*this).name(), GetObjectID(),
|
||||
GetRefCount(), GetName().c_str());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <atomic>
|
||||
#include <kiwano/core/Common.h>
|
||||
#include <kiwano/macros.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
|
@ -41,7 +41,7 @@ public:
|
|||
|
||||
/// \~chinese
|
||||
/// @brief 获取引用计数
|
||||
long GetRefCount() const;
|
||||
uint32_t GetRefCount() const;
|
||||
|
||||
protected:
|
||||
RefCounter();
|
||||
|
|
@ -49,11 +49,12 @@ protected:
|
|||
virtual ~RefCounter();
|
||||
|
||||
private:
|
||||
long ref_count_;
|
||||
std::atomic<uint32_t> ref_count_;
|
||||
};
|
||||
|
||||
inline long RefCounter::GetRefCount() const
|
||||
inline uint32_t RefCounter::GetRefCount() const
|
||||
{
|
||||
return ref_count_;
|
||||
}
|
||||
|
||||
} // namespace kiwano
|
||||
|
|
|
|||
|
|
@ -19,24 +19,27 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
#include <kiwano/core/Common.h>
|
||||
#include <kiwano/core/RefCounter.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief 默认的智能指针代理
|
||||
* @brief 默认的智能指针引用计数代理
|
||||
*/
|
||||
struct DefaultSmartPtrRefProxy
|
||||
{
|
||||
static inline void add_ref(RefCounter* ptr)
|
||||
static inline void AddRef(RefCounter* ptr)
|
||||
{
|
||||
if (ptr)
|
||||
ptr->Retain();
|
||||
}
|
||||
|
||||
static inline void release(RefCounter* ptr)
|
||||
static inline void Release(RefCounter* ptr)
|
||||
{
|
||||
if (ptr)
|
||||
ptr->Release();
|
||||
|
|
@ -45,10 +48,232 @@ struct DefaultSmartPtrRefProxy
|
|||
|
||||
/**
|
||||
* \~chinese
|
||||
* @brief 智能指针
|
||||
* @brief 侵入式智能指针
|
||||
*/
|
||||
template <typename _Ty>
|
||||
using SmartPtr = IntrusivePtr<_Ty, DefaultSmartPtrRefProxy>;
|
||||
template <typename _Ty, typename _ProxyTy = DefaultSmartPtrRefProxy>
|
||||
class SmartPtr
|
||||
{
|
||||
public:
|
||||
using value_type = _Ty;
|
||||
using pointer_type = _Ty*;
|
||||
using const_pointer_type = const _Ty*;
|
||||
using reference_type = _Ty&;
|
||||
using const_reference_type = const _Ty&;
|
||||
|
||||
SmartPtr() noexcept
|
||||
: ptr_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
SmartPtr(std::nullptr_t) noexcept
|
||||
: ptr_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
SmartPtr(pointer_type p)
|
||||
: ptr_(p)
|
||||
{
|
||||
typename _ProxyTy::AddRef(ptr_);
|
||||
}
|
||||
|
||||
SmartPtr(const SmartPtr& other)
|
||||
: ptr_(other.ptr_)
|
||||
{
|
||||
typename _ProxyTy::AddRef(ptr_);
|
||||
}
|
||||
|
||||
SmartPtr(SmartPtr&& other) noexcept
|
||||
: ptr_(nullptr)
|
||||
{
|
||||
Swap(other);
|
||||
}
|
||||
|
||||
~SmartPtr()
|
||||
{
|
||||
Tidy();
|
||||
}
|
||||
|
||||
template <typename _UTy, typename std::enable_if<std::is_base_of<_Ty, _UTy>::value, int>::type = 0>
|
||||
SmartPtr(const SmartPtr<_UTy, _ProxyTy>& other)
|
||||
{
|
||||
ptr_ = const_cast<pointer_type>(dynamic_cast<const_pointer_type>(other.Get()));
|
||||
typename _ProxyTy::AddRef(ptr_);
|
||||
}
|
||||
|
||||
inline pointer_type Get() noexcept
|
||||
{
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
inline const_pointer_type Get() const noexcept
|
||||
{
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
inline void Reset(pointer_type ptr = nullptr)
|
||||
{
|
||||
if (ptr)
|
||||
SmartPtr(ptr).Swap(*this);
|
||||
else
|
||||
Tidy();
|
||||
}
|
||||
|
||||
inline void Swap(SmartPtr& other) noexcept
|
||||
{
|
||||
std::swap(ptr_, other.ptr_);
|
||||
}
|
||||
|
||||
inline pointer_type operator->()
|
||||
{
|
||||
KGE_ASSERT(ptr_ != nullptr && "Invalid pointer");
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
inline const_pointer_type operator->() const
|
||||
{
|
||||
KGE_ASSERT(ptr_ != nullptr && "Invalid pointer");
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
inline reference_type operator*()
|
||||
{
|
||||
KGE_ASSERT(ptr_ != nullptr && "Invalid pointer");
|
||||
return *ptr_;
|
||||
}
|
||||
|
||||
inline const_reference_type operator*() const
|
||||
{
|
||||
KGE_ASSERT(ptr_ != nullptr && "Invalid pointer");
|
||||
return *ptr_;
|
||||
}
|
||||
|
||||
inline pointer_type* operator&()
|
||||
{
|
||||
KGE_ASSERT(ptr_ == nullptr && "Memory leak");
|
||||
return &ptr_;
|
||||
}
|
||||
|
||||
inline operator bool() const noexcept
|
||||
{
|
||||
return ptr_ != nullptr;
|
||||
}
|
||||
|
||||
inline bool operator!() const noexcept
|
||||
{
|
||||
return ptr_ == 0;
|
||||
}
|
||||
|
||||
inline SmartPtr& operator=(const SmartPtr& other)
|
||||
{
|
||||
if (other.ptr_ != ptr_)
|
||||
SmartPtr(other).Swap(*this);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline SmartPtr& operator=(SmartPtr&& other) noexcept
|
||||
{
|
||||
if (other.ptr_ != ptr_)
|
||||
other.Swap(*this);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline SmartPtr& operator=(pointer_type p)
|
||||
{
|
||||
if (p != ptr_)
|
||||
SmartPtr(p).Swap(*this);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline SmartPtr& operator=(std::nullptr_t)
|
||||
{
|
||||
Tidy();
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
void Tidy()
|
||||
{
|
||||
typename _ProxyTy::Release(ptr_);
|
||||
ptr_ = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
pointer_type ptr_;
|
||||
};
|
||||
|
||||
template <class _Ty, class _UTy, class _ProxyTy>
|
||||
inline bool operator==(SmartPtr<_Ty, _ProxyTy> const& lhs, SmartPtr<_UTy, _ProxyTy> const& rhs) noexcept
|
||||
{
|
||||
return lhs.Get() == rhs.Get();
|
||||
}
|
||||
|
||||
template <class _Ty, class _ProxyTy>
|
||||
inline bool operator==(SmartPtr<_Ty, _ProxyTy> const& lhs, _Ty* rhs) noexcept
|
||||
{
|
||||
return lhs.Get() == rhs;
|
||||
}
|
||||
|
||||
template <class _Ty, class _ProxyTy>
|
||||
inline bool operator==(_Ty* lhs, SmartPtr<_Ty, _ProxyTy> const& rhs) noexcept
|
||||
{
|
||||
return lhs == rhs.Get();
|
||||
}
|
||||
|
||||
template <class _Ty, class _ProxyTy>
|
||||
inline bool operator==(SmartPtr<_Ty, _ProxyTy> const& lhs, std::nullptr_t) noexcept
|
||||
{
|
||||
return !static_cast<bool>(lhs);
|
||||
}
|
||||
|
||||
template <class _Ty, class _ProxyTy>
|
||||
inline bool operator==(std::nullptr_t, SmartPtr<_Ty, _ProxyTy> const& rhs) noexcept
|
||||
{
|
||||
return !static_cast<bool>(rhs);
|
||||
}
|
||||
|
||||
template <class _Ty, class _UTy, class _ProxyTy>
|
||||
inline bool operator!=(SmartPtr<_Ty, _ProxyTy> const& lhs, SmartPtr<_UTy, _ProxyTy> const& rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template <class _Ty, class _ProxyTy>
|
||||
inline bool operator!=(SmartPtr<_Ty, _ProxyTy> const& lhs, _Ty* rhs) noexcept
|
||||
{
|
||||
return lhs.Get() != rhs;
|
||||
}
|
||||
|
||||
template <class _Ty, class _ProxyTy>
|
||||
inline bool operator!=(_Ty* lhs, SmartPtr<_Ty, _ProxyTy> const& rhs) noexcept
|
||||
{
|
||||
return lhs != rhs.Get();
|
||||
}
|
||||
|
||||
template <class _Ty, class _ProxyTy>
|
||||
inline bool operator!=(SmartPtr<_Ty, _ProxyTy> const& lhs, std::nullptr_t) noexcept
|
||||
{
|
||||
return static_cast<bool>(lhs);
|
||||
}
|
||||
|
||||
template <class _Ty, class _ProxyTy>
|
||||
inline bool operator!=(std::nullptr_t, SmartPtr<_Ty, _ProxyTy> const& rhs) noexcept
|
||||
{
|
||||
return static_cast<bool>(rhs);
|
||||
}
|
||||
|
||||
template <class _Ty, class _UTy, class _ProxyTy>
|
||||
inline bool operator<(SmartPtr<_Ty, _ProxyTy> const& lhs, SmartPtr<_UTy, _ProxyTy> const& rhs) noexcept
|
||||
{
|
||||
return lhs.Get() < rhs.Get();
|
||||
}
|
||||
|
||||
// template class cannot specialize std::swap,
|
||||
// so implement a Swap Function in kiwano namespace
|
||||
template <class _Ty, class _ProxyTy>
|
||||
inline void swap(SmartPtr<_Ty, _ProxyTy>& lhs, SmartPtr<_Ty, _ProxyTy>& rhs) noexcept
|
||||
{
|
||||
lhs.Swap(rhs);
|
||||
}
|
||||
|
||||
} // namespace kiwano
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,93 @@
|
|||
// 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/macros.h>
|
||||
#include <kiwano/core/String.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
namespace string
|
||||
{
|
||||
|
||||
#if defined(KGE_PLATFORM_WINDOWS)
|
||||
|
||||
//
|
||||
// This 中文 comment will enable utf-8 encoding in Visual Studio
|
||||
// Otherwise 'CP_UTF8' cannot work
|
||||
//
|
||||
|
||||
String Format(const char* format, ...)
|
||||
{
|
||||
String result;
|
||||
if (format)
|
||||
{
|
||||
va_list args = nullptr;
|
||||
va_start(args, format);
|
||||
|
||||
const auto len = static_cast<size_t>(::_vscprintf(format, args) + 1);
|
||||
if (len)
|
||||
{
|
||||
result.resize(len);
|
||||
::_vsnprintf_s(&result[0], len, len, format, args);
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
String ToNarrow(const WideString& str)
|
||||
{
|
||||
if (str.empty())
|
||||
return String();
|
||||
|
||||
int chars_num = ::WideCharToMultiByte(CP_UTF8, 0, str.c_str(), -1, NULL, 0, NULL, NULL);
|
||||
if (chars_num)
|
||||
{
|
||||
String result;
|
||||
result.resize(chars_num);
|
||||
|
||||
::WideCharToMultiByte(CP_UTF8, 0, str.c_str(), -1, &result[0], chars_num, NULL, NULL);
|
||||
return result;
|
||||
}
|
||||
return String();
|
||||
}
|
||||
|
||||
WideString ToWide(const String& str)
|
||||
{
|
||||
if (str.empty())
|
||||
return WideString();
|
||||
|
||||
int chars_num = ::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
|
||||
if (chars_num)
|
||||
{
|
||||
WideString result;
|
||||
result.resize(chars_num);
|
||||
|
||||
::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, &result[0], chars_num);
|
||||
return result;
|
||||
}
|
||||
return WideString();
|
||||
}
|
||||
|
||||
#endif // KGE_PLATFORM_WINDOWS
|
||||
|
||||
} // namespace string
|
||||
} // namespace kiwano
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
// 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 <string>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 字符串容器
|
||||
using String = std::string;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 宽字符串容器
|
||||
using WideString = std::wstring;
|
||||
|
||||
namespace string
|
||||
{
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 格式化字符串
|
||||
String Format(const char* format, ...);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 宽字符串转窄字符串
|
||||
String ToNarrow(const WideString& str);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 窄字符串转宽字符串
|
||||
WideString ToWide(const String& str);
|
||||
|
||||
}
|
||||
|
||||
} // namespace kiwano
|
||||
|
|
@ -157,21 +157,21 @@ String Duration::ToString() const
|
|||
|
||||
if (hour)
|
||||
{
|
||||
result.append(String::parse(hour)).append("h");
|
||||
result.append(String::parse(min)).append("m");
|
||||
result.append(std::to_string(hour)).append("h");
|
||||
result.append(std::to_string(min)).append("m");
|
||||
}
|
||||
else if (min)
|
||||
{
|
||||
result.append(String::parse(min)).append("m");
|
||||
result.append(std::to_string(min)).append("m");
|
||||
}
|
||||
|
||||
if (ms != 0)
|
||||
{
|
||||
result.append(String::parse(static_cast<float>(sec) + static_cast<float>(ms) / 1000.f)).append("s");
|
||||
result.append(std::to_string(static_cast<float>(sec) + static_cast<float>(ms) / 1000.f)).append("s");
|
||||
}
|
||||
else if (sec != 0)
|
||||
{
|
||||
result.append(String::parse(sec)).append("s");
|
||||
result.append(std::to_string(sec)).append("s");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ struct KGE_API Duration
|
|||
/// 例如: "300ms", "-1.5h", "2h45m"
|
||||
/// 允许的时间单位有 "ms", "s", "m", "h"
|
||||
/// @return 解析出的时间段
|
||||
/// @throw std::runtime_error 传入一个不合法的格式时抛出
|
||||
/// @throw kiwano::RuntimeError 传入一个不合法的格式时抛出
|
||||
static Duration Parse(const String& str);
|
||||
|
||||
static const Duration Ms; ///< 毫秒
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#pragma once
|
||||
#include <kiwano/core/ObjectBase.h>
|
||||
#include <kiwano/core/Time.h>
|
||||
#include <kiwano/core/IntrusiveList.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
|
@ -33,7 +34,7 @@ KGE_DECLARE_SMART_PTR(Timer);
|
|||
/// @details 定时器用于每隔一段时间执行一次回调函数,且可以指定执行总次数
|
||||
class KGE_API Timer
|
||||
: public virtual ObjectBase
|
||||
, protected IntrusiveListItem<TimerPtr>
|
||||
, protected IntrusiveListValue<TimerPtr>
|
||||
{
|
||||
friend class TimerManager;
|
||||
friend IntrusiveList<TimerPtr>;
|
||||
|
|
|
|||
|
|
@ -25,18 +25,18 @@ namespace kiwano
|
|||
{
|
||||
void TimerManager::UpdateTimers(Duration dt)
|
||||
{
|
||||
if (timers_.empty())
|
||||
if (timers_.IsEmpty())
|
||||
return;
|
||||
|
||||
TimerPtr next;
|
||||
for (auto timer = timers_.first_item(); timer; timer = next)
|
||||
for (auto timer = timers_.GetFirst(); timer; timer = next)
|
||||
{
|
||||
next = timer->next_item();
|
||||
next = timer->GetNext();
|
||||
|
||||
timer->Update(dt);
|
||||
|
||||
if (timer->IsRemoveable())
|
||||
timers_.remove(timer);
|
||||
timers_.Remove(timer);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -58,15 +58,15 @@ Timer* TimerManager::AddTimer(TimerPtr timer)
|
|||
if (timer)
|
||||
{
|
||||
timer->Reset();
|
||||
timers_.push_back(timer);
|
||||
timers_.PushBack(timer);
|
||||
}
|
||||
|
||||
return timer.get();
|
||||
return timer.Get();
|
||||
}
|
||||
|
||||
void TimerManager::StopTimers(String const& name)
|
||||
{
|
||||
if (timers_.empty())
|
||||
if (timers_.IsEmpty())
|
||||
return;
|
||||
|
||||
for (auto& timer : timers_)
|
||||
|
|
@ -80,7 +80,7 @@ void TimerManager::StopTimers(String const& name)
|
|||
|
||||
void TimerManager::StartTimers(String const& name)
|
||||
{
|
||||
if (timers_.empty())
|
||||
if (timers_.IsEmpty())
|
||||
return;
|
||||
|
||||
for (auto& timer : timers_)
|
||||
|
|
@ -94,7 +94,7 @@ void TimerManager::StartTimers(String const& name)
|
|||
|
||||
void TimerManager::RemoveTimers(String const& name)
|
||||
{
|
||||
if (timers_.empty())
|
||||
if (timers_.IsEmpty())
|
||||
return;
|
||||
|
||||
for (auto& timer : timers_)
|
||||
|
|
@ -108,7 +108,7 @@ void TimerManager::RemoveTimers(String const& name)
|
|||
|
||||
void TimerManager::StopAllTimers()
|
||||
{
|
||||
if (timers_.empty())
|
||||
if (timers_.IsEmpty())
|
||||
return;
|
||||
|
||||
for (auto& timer : timers_)
|
||||
|
|
@ -119,7 +119,7 @@ void TimerManager::StopAllTimers()
|
|||
|
||||
void TimerManager::StartAllTimers()
|
||||
{
|
||||
if (timers_.empty())
|
||||
if (timers_.IsEmpty())
|
||||
return;
|
||||
|
||||
for (auto& timer : timers_)
|
||||
|
|
@ -130,7 +130,7 @@ void TimerManager::StartAllTimers()
|
|||
|
||||
void TimerManager::RemoveAllTimers()
|
||||
{
|
||||
timers_.clear();
|
||||
timers_.Clear();
|
||||
}
|
||||
|
||||
const TimerManager::Timers& TimerManager::GetAllTimers() const
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
// 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 <3rd-party/pugixml/pugixml.hpp>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
||||
/// \~chinese
|
||||
/// @brief XML文档
|
||||
using XmlDocument = pugi::xml_document;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief XML文档
|
||||
using XmlNode = pugi::xml_node;
|
||||
|
||||
} // namespace kiwano
|
||||
|
|
@ -25,19 +25,16 @@
|
|||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# define KGE_WIN32
|
||||
# ifdef _WIN64
|
||||
# define KGE_WIN64
|
||||
# endif
|
||||
# define KGE_PLATFORM_WINDOWS
|
||||
#elif __ANDROID__
|
||||
# define KGE_ANDROID
|
||||
# define KGE_PLATFORM_ANDROID
|
||||
#elif __linux__
|
||||
# define KGE_LINUX
|
||||
# define KGE_PLATFORM_LINUX
|
||||
#elif __APPLE__
|
||||
# if TARGET_OS_IPHONE
|
||||
# define KGE_IPHONE
|
||||
# define KGE_PLATFORM_IPHONE
|
||||
# elif TARGET_OS_MAC
|
||||
# define KGE_MACOS
|
||||
# define KGE_PLATFORM_MACOS
|
||||
# else
|
||||
# error "Unsupported Apple platform"
|
||||
# endif
|
||||
|
|
@ -65,7 +62,7 @@
|
|||
//
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef KGE_WIN32
|
||||
#ifdef KGE_PLATFORM_WINDOWS
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_NONE
|
||||
# undef KGE_RENDER_ENGINE
|
||||
|
|
@ -163,4 +160,10 @@ KGE_SUPPRESS_WARNING(4251)
|
|||
#include <wincodec.h>
|
||||
#include <windows.h>
|
||||
|
||||
#endif // KGE_WIN32
|
||||
#else
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
# error "DirectX render engine is not supported on current platform"
|
||||
#endif
|
||||
|
||||
#endif // KGE_PLATFORM_WINDOWS
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <array>
|
||||
#include <kiwano/core/Common.h>
|
||||
#include <kiwano/core/Module.h>
|
||||
#include <kiwano/core/Keys.h>
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ bool Runner::MainLoop()
|
|||
// Poll events
|
||||
while (EventPtr evt = main_window_->PollEvent())
|
||||
{
|
||||
app.DispatchEvent(evt.get());
|
||||
app.DispatchEvent(evt.Get());
|
||||
}
|
||||
|
||||
// Update & render
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ enum class CursorType
|
|||
};
|
||||
|
||||
|
||||
#if defined(KGE_WIN32)
|
||||
#if defined(KGE_PLATFORM_WINDOWS)
|
||||
typedef HWND WindowHandle;
|
||||
#endif
|
||||
|
||||
|
|
@ -67,7 +67,7 @@ public:
|
|||
* @param icon 图标资源ID
|
||||
* @param resizable 窗口大小可拉伸
|
||||
* @param fullscreen 全屏模式
|
||||
* @throw std::system_error 窗口创建失败时抛出
|
||||
* @throw kiwano::SystemError 窗口创建失败时抛出
|
||||
*/
|
||||
static WindowPtr Create(String const& title, uint32_t width, uint32_t height, uint32_t icon = 0,
|
||||
bool resizable = false, bool fullscreen = false);
|
||||
|
|
|
|||
|
|
@ -19,21 +19,22 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#include <Unknwnbase.h>
|
||||
#include <kiwano/core/Common.h>
|
||||
#include <type_traits>
|
||||
#include <kiwano/core/Common.h>
|
||||
#include <kiwano/core/SmartPtr.hpp>
|
||||
#include <Unknwnbase.h>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
struct ComPtrProxy
|
||||
{
|
||||
static inline void add_ref(IUnknown* ptr)
|
||||
static inline void AddRef(IUnknown* ptr)
|
||||
{
|
||||
if (ptr)
|
||||
ptr->AddRef();
|
||||
}
|
||||
|
||||
static inline void release(IUnknown* ptr)
|
||||
static inline void Release(IUnknown* ptr)
|
||||
{
|
||||
if (ptr)
|
||||
ptr->Release();
|
||||
|
|
@ -42,6 +43,6 @@ struct ComPtrProxy
|
|||
|
||||
// ComPtr<> is a smart pointer for COM
|
||||
template <typename _Ty, typename = typename std::enable_if<std::is_base_of<IUnknown, _Ty>::value, int>::type>
|
||||
using ComPtr = IntrusivePtr<_Ty, ComPtrProxy>;
|
||||
using ComPtr = SmartPtr<_Ty, ComPtrProxy>;
|
||||
|
||||
} // namespace kiwano
|
||||
|
|
|
|||
|
|
@ -20,8 +20,9 @@
|
|||
|
||||
#include <kiwano/platform/Window.h>
|
||||
|
||||
#if defined(KGE_WIN32)
|
||||
#if defined(KGE_PLATFORM_WINDOWS)
|
||||
|
||||
#include <array>
|
||||
#include <kiwano/core/Keys.h>
|
||||
#include <kiwano/core/Exception.h>
|
||||
#include <kiwano/core/Logger.h>
|
||||
|
|
@ -277,7 +278,7 @@ void WindowWin32Impl::Init(String const& title, uint32_t width, uint32_t height,
|
|||
height = win_height;
|
||||
}
|
||||
|
||||
WideString wide_title = MultiByteToWide(title);
|
||||
WideString wide_title = string::ToWide(title);
|
||||
|
||||
handle_ = ::CreateWindowExW(is_fullscreen_ ? WS_EX_TOPMOST : 0, L"KiwanoAppWnd", wide_title.c_str(), GetStyle(),
|
||||
left, top, width, height, nullptr, nullptr, hinst, nullptr);
|
||||
|
|
@ -320,7 +321,7 @@ void WindowWin32Impl::SetTitle(String const& title)
|
|||
{
|
||||
if (handle_)
|
||||
{
|
||||
WideString wide_title = MultiByteToWide(title);
|
||||
WideString wide_title = string::ToWide(title);
|
||||
::SetWindowTextW(handle_, wide_title.c_str());
|
||||
}
|
||||
}
|
||||
|
|
@ -633,7 +634,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA
|
|||
{
|
||||
KGE_SYS_LOG("Window title changed");
|
||||
|
||||
this->title_ = WideToMultiByte(reinterpret_cast<LPCWSTR>(lparam));
|
||||
this->title_ = string::ToNarrow(reinterpret_cast<LPCWSTR>(lparam));
|
||||
|
||||
WindowTitleChangedEventPtr evt = new WindowTitleChangedEvent;
|
||||
evt->title = this->title_;
|
||||
|
|
|
|||
|
|
@ -171,13 +171,13 @@ STDMETHODIMP D2DDeviceResources::QueryInterface(IID const& riid, void** object)
|
|||
|
||||
void D2DDeviceResources::DiscardResources()
|
||||
{
|
||||
factory_.reset();
|
||||
device_.reset();
|
||||
device_context_.reset();
|
||||
target_bitmap_.reset();
|
||||
factory_.Reset();
|
||||
device_.Reset();
|
||||
device_context_.Reset();
|
||||
target_bitmap_.Reset();
|
||||
|
||||
imaging_factory_.reset();
|
||||
dwrite_factory_.reset();
|
||||
imaging_factory_.Reset();
|
||||
dwrite_factory_.Reset();
|
||||
}
|
||||
|
||||
HRESULT D2DDeviceResources::CreateDeviceIndependentResources()
|
||||
|
|
@ -235,7 +235,7 @@ HRESULT D2DDeviceResources::CreateDeviceResources(_In_ ComPtr<IDXGIDevice> dxgi_
|
|||
// Create the Direct2D device object and a corresponding context.
|
||||
ComPtr<ID2D1Device> device;
|
||||
|
||||
HRESULT hr = factory_->CreateDevice(dxgi_device.get(), &device);
|
||||
HRESULT hr = factory_->CreateDevice(dxgi_device.Get(), &device);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
|
|
@ -269,7 +269,7 @@ HRESULT D2DDeviceResources::CreateWindowSizeDependentResources()
|
|||
{
|
||||
ComPtr<ID2D1Bitmap1> target;
|
||||
hr = device_context_->CreateBitmapFromDxgiSurface(
|
||||
dxgi_back_buffer.get(),
|
||||
dxgi_back_buffer.Get(),
|
||||
D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
|
||||
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED), dpi_, dpi_),
|
||||
&target);
|
||||
|
|
@ -277,7 +277,7 @@ HRESULT D2DDeviceResources::CreateWindowSizeDependentResources()
|
|||
if (SUCCEEDED(hr))
|
||||
{
|
||||
target_bitmap_ = target;
|
||||
device_context_->SetTarget(target_bitmap_.get());
|
||||
device_context_->SetTarget(target_bitmap_.Get());
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
|
|
@ -326,7 +326,7 @@ HRESULT D2DDeviceResources::CreateBitmapConverter(_Out_ ComPtr<IWICFormatConvert
|
|||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr =
|
||||
output->Initialize(source.get(), format, dither, palette.get(), alpha_threshold_percent, palette_translate);
|
||||
output->Initialize(source.Get(), format, dither, palette.Get(), alpha_threshold_percent, palette_translate);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
|
|
@ -345,7 +345,7 @@ HRESULT D2DDeviceResources::CreateBitmapFromConverter(_Out_ ComPtr<ID2D1Bitmap>&
|
|||
|
||||
ComPtr<ID2D1Bitmap> output;
|
||||
|
||||
HRESULT hr = device_context_->CreateBitmapFromWicBitmap(converter.get(), properties, &output);
|
||||
HRESULT hr = device_context_->CreateBitmapFromWicBitmap(converter.Get(), properties, &output);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
|
|
@ -393,7 +393,7 @@ HRESULT D2DDeviceResources::CreateBitmapDecoderFromResource(_Out_ ComPtr<IWICBit
|
|||
if (SUCCEEDED(hr))
|
||||
{
|
||||
ComPtr<IWICBitmapDecoder> decoder_output;
|
||||
hr = imaging_factory_->CreateDecoderFromStream(stream.get(), nullptr, WICDecodeMetadataCacheOnLoad,
|
||||
hr = imaging_factory_->CreateDecoderFromStream(stream.Get(), nullptr, WICDecodeMetadataCacheOnLoad,
|
||||
&decoder_output);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
|
|
@ -413,7 +413,7 @@ HRESULT D2DDeviceResources::CreateTextFormat(_Out_ ComPtr<IDWriteTextFormat>& te
|
|||
return E_UNEXPECTED;
|
||||
|
||||
ComPtr<IDWriteTextFormat> output;
|
||||
HRESULT hr = dwrite_factory_->CreateTextFormat(family, collection.get(), weight, style, stretch, font_size,
|
||||
HRESULT hr = dwrite_factory_->CreateTextFormat(family, collection.Get(), weight, style, stretch, font_size,
|
||||
L"", &output);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
|
|
@ -431,7 +431,7 @@ HRESULT D2DDeviceResources::CreateTextLayout(_Out_ ComPtr<IDWriteTextLayout>& te
|
|||
|
||||
ComPtr<IDWriteTextLayout> output;
|
||||
|
||||
HRESULT hr = dwrite_factory_->CreateTextLayout(text, length, text_format.get(), 0, 0, &output);
|
||||
HRESULT hr = dwrite_factory_->CreateTextLayout(text, length, text_format.Get(), 0, 0, &output);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -66,37 +66,37 @@ public:
|
|||
inline ID2D1Factory1* GetFactory()
|
||||
{
|
||||
KGE_ASSERT(factory_);
|
||||
return factory_.get();
|
||||
return factory_.Get();
|
||||
}
|
||||
|
||||
inline IWICImagingFactory* GetWICImagingFactory()
|
||||
{
|
||||
KGE_ASSERT(imaging_factory_);
|
||||
return imaging_factory_.get();
|
||||
return imaging_factory_.Get();
|
||||
}
|
||||
|
||||
inline IDWriteFactory* GetDWriteFactory()
|
||||
{
|
||||
KGE_ASSERT(dwrite_factory_);
|
||||
return dwrite_factory_.get();
|
||||
return dwrite_factory_.Get();
|
||||
}
|
||||
|
||||
inline ID2D1Device* GetDevice()
|
||||
{
|
||||
KGE_ASSERT(device_);
|
||||
return device_.get();
|
||||
return device_.Get();
|
||||
}
|
||||
|
||||
inline ID2D1DeviceContext* GetDeviceContext()
|
||||
{
|
||||
KGE_ASSERT(device_context_);
|
||||
return device_context_.get();
|
||||
return device_context_.Get();
|
||||
}
|
||||
|
||||
inline ID2D1Bitmap1* GetTargetBitmap()
|
||||
{
|
||||
KGE_ASSERT(target_bitmap_);
|
||||
return target_bitmap_.get();
|
||||
return target_bitmap_.Get();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -168,19 +168,19 @@ void D3D10DeviceResources::ClearRenderTarget(Color& clear_color)
|
|||
{
|
||||
KGE_ASSERT(device_ != nullptr && rt_view_ != nullptr && ds_view_ != nullptr);
|
||||
|
||||
auto rt_view = rt_view_.get();
|
||||
device_->OMSetRenderTargets(1, &rt_view, ds_view_.get());
|
||||
auto rt_view = rt_view_.Get();
|
||||
device_->OMSetRenderTargets(1, &rt_view, ds_view_.Get());
|
||||
device_->ClearRenderTargetView(rt_view, reinterpret_cast<float*>(&clear_color));
|
||||
}
|
||||
|
||||
void D3D10DeviceResources::DiscardResources()
|
||||
{
|
||||
device_.reset();
|
||||
rt_view_.reset();
|
||||
ds_view_.reset();
|
||||
dxgi_device_.reset();
|
||||
dxgi_swap_chain_.reset();
|
||||
dxgi_factory_.reset();
|
||||
device_.Reset();
|
||||
rt_view_.Reset();
|
||||
ds_view_.Reset();
|
||||
dxgi_device_.Reset();
|
||||
dxgi_swap_chain_.Reset();
|
||||
dxgi_factory_.Reset();
|
||||
|
||||
hwnd_ = nullptr;
|
||||
}
|
||||
|
|
@ -252,7 +252,7 @@ HRESULT D3D10DeviceResources::CreateDeviceResources()
|
|||
swap_chain_desc.Windowed = TRUE;
|
||||
swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
||||
|
||||
hr = dxgi_factory_->CreateSwapChain(device_.get(), &swap_chain_desc, &dxgi_swap_chain_);
|
||||
hr = dxgi_factory_->CreateSwapChain(device_.Get(), &swap_chain_desc, &dxgi_swap_chain_);
|
||||
}
|
||||
|
||||
return hr;
|
||||
|
|
@ -298,7 +298,7 @@ HRESULT D3D10DeviceResources::CreateWindowSizeDependentResources()
|
|||
renderDesc.Texture2D.MipSlice = 0;
|
||||
|
||||
rt_view_ = nullptr;
|
||||
hr = device_->CreateRenderTargetView(dxgi_back_buffer.get(), &renderDesc, &rt_view_);
|
||||
hr = device_->CreateRenderTargetView(dxgi_back_buffer.Get(), &renderDesc, &rt_view_);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -328,14 +328,14 @@ HRESULT D3D10DeviceResources::CreateWindowSizeDependentResources()
|
|||
desc.ViewDimension = D3D10_DSV_DIMENSION_TEXTURE2D;
|
||||
desc.Texture2D.MipSlice = 0;
|
||||
|
||||
ds_view_.reset();
|
||||
hr = device_->CreateDepthStencilView(depth_stencil.get(), &desc, &ds_view_);
|
||||
ds_view_.Reset();
|
||||
hr = device_->CreateDepthStencilView(depth_stencil.Get(), &desc, &ds_view_);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
ID3D10RenderTargetView* main_view = rt_view_.get();
|
||||
device_->OMSetRenderTargets(1, &main_view, ds_view_.get());
|
||||
ID3D10RenderTargetView* main_view = rt_view_.Get();
|
||||
device_->OMSetRenderTargets(1, &main_view, ds_view_.Get());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,32 +35,32 @@ public:
|
|||
inline ID3D10Device* GetDevice()
|
||||
{
|
||||
KGE_ASSERT(device_);
|
||||
return device_.get();
|
||||
return device_.Get();
|
||||
}
|
||||
inline ID3D10RenderTargetView* GetRenderTargetView()
|
||||
{
|
||||
KGE_ASSERT(rt_view_);
|
||||
return rt_view_.get();
|
||||
return rt_view_.Get();
|
||||
}
|
||||
inline ID3D10DepthStencilView* GetDepthStencilView()
|
||||
{
|
||||
KGE_ASSERT(ds_view_);
|
||||
return ds_view_.get();
|
||||
return ds_view_.Get();
|
||||
}
|
||||
inline IDXGIFactory* GetDXGIFactory()
|
||||
{
|
||||
KGE_ASSERT(dxgi_factory_);
|
||||
return dxgi_factory_.get();
|
||||
return dxgi_factory_.Get();
|
||||
}
|
||||
inline IDXGIDevice* GetDXGIDevice()
|
||||
{
|
||||
KGE_ASSERT(dxgi_device_);
|
||||
return dxgi_device_.get();
|
||||
return dxgi_device_.Get();
|
||||
}
|
||||
inline IDXGISwapChain* GetDXGISwapChain()
|
||||
{
|
||||
KGE_ASSERT(dxgi_swap_chain_);
|
||||
return dxgi_swap_chain_.get();
|
||||
return dxgi_swap_chain_.Get();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -160,20 +160,20 @@ void D3D11DeviceResources::ClearRenderTarget(Color& clear_color)
|
|||
{
|
||||
KGE_ASSERT(device_context_ != nullptr && rt_view_ != nullptr && ds_view_ != nullptr);
|
||||
|
||||
auto rt_view = rt_view_.get();
|
||||
device_context_->OMSetRenderTargets(1, &rt_view, ds_view_.get());
|
||||
auto rt_view = rt_view_.Get();
|
||||
device_context_->OMSetRenderTargets(1, &rt_view, ds_view_.Get());
|
||||
device_context_->ClearRenderTargetView(rt_view, reinterpret_cast<float*>(&clear_color));
|
||||
}
|
||||
|
||||
void D3D11DeviceResources::DiscardResources()
|
||||
{
|
||||
device_.reset();
|
||||
device_context_.reset();
|
||||
rt_view_.reset();
|
||||
ds_view_.reset();
|
||||
dxgi_device_.reset();
|
||||
dxgi_swap_chain_.reset();
|
||||
dxgi_factory_.reset();
|
||||
device_.Reset();
|
||||
device_context_.Reset();
|
||||
rt_view_.Reset();
|
||||
ds_view_.Reset();
|
||||
dxgi_device_.Reset();
|
||||
dxgi_swap_chain_.Reset();
|
||||
dxgi_factory_.Reset();
|
||||
|
||||
hwnd_ = nullptr;
|
||||
}
|
||||
|
|
@ -293,7 +293,7 @@ HRESULT D3D11DeviceResources::CreateDeviceResources()
|
|||
swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
||||
}
|
||||
|
||||
hr = dxgi_factory_->CreateSwapChain(device_.get(), &swap_chain_desc, &dxgi_swap_chain_);
|
||||
hr = dxgi_factory_->CreateSwapChain(device_.Get(), &swap_chain_desc, &dxgi_swap_chain_);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
|
@ -333,7 +333,7 @@ HRESULT D3D11DeviceResources::CreateWindowSizeDependentResources()
|
|||
if (SUCCEEDED(hr))
|
||||
{
|
||||
rt_view_ = nullptr;
|
||||
hr = device_->CreateRenderTargetView(dxgi_back_buffer.get(), nullptr, &rt_view_);
|
||||
hr = device_->CreateRenderTargetView(dxgi_back_buffer.Get(), nullptr, &rt_view_);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -353,14 +353,14 @@ HRESULT D3D11DeviceResources::CreateWindowSizeDependentResources()
|
|||
{
|
||||
CD3D11_DEPTH_STENCIL_VIEW_DESC desc(D3D11_DSV_DIMENSION_TEXTURE2D);
|
||||
|
||||
ds_view_.reset();
|
||||
hr = device_->CreateDepthStencilView(depth_stencil.get(), &desc, &ds_view_);
|
||||
ds_view_.Reset();
|
||||
hr = device_->CreateDepthStencilView(depth_stencil.Get(), &desc, &ds_view_);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
ID3D11RenderTargetView* main_view = rt_view_.get();
|
||||
device_context_->OMSetRenderTargets(1, &main_view, ds_view_.get());
|
||||
ID3D11RenderTargetView* main_view = rt_view_.Get();
|
||||
device_context_->OMSetRenderTargets(1, &main_view, ds_view_.Get());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,37 +35,37 @@ public:
|
|||
inline ID3D11Device* GetDevice()
|
||||
{
|
||||
KGE_ASSERT(device_);
|
||||
return device_.get();
|
||||
return device_.Get();
|
||||
}
|
||||
inline ID3D11DeviceContext* GetDeviceContext()
|
||||
{
|
||||
KGE_ASSERT(device_context_);
|
||||
return device_context_.get();
|
||||
return device_context_.Get();
|
||||
}
|
||||
inline ID3D11RenderTargetView* GetRenderTargetView()
|
||||
{
|
||||
KGE_ASSERT(rt_view_);
|
||||
return rt_view_.get();
|
||||
return rt_view_.Get();
|
||||
}
|
||||
inline ID3D11DepthStencilView* GetDepthStencilView()
|
||||
{
|
||||
KGE_ASSERT(ds_view_);
|
||||
return ds_view_.get();
|
||||
return ds_view_.Get();
|
||||
}
|
||||
inline IDXGIFactory* GetDXGIFactory()
|
||||
{
|
||||
KGE_ASSERT(dxgi_factory_);
|
||||
return dxgi_factory_.get();
|
||||
return dxgi_factory_.Get();
|
||||
}
|
||||
inline IDXGIDevice* GetDXGIDevice()
|
||||
{
|
||||
KGE_ASSERT(dxgi_device_);
|
||||
return dxgi_device_.get();
|
||||
return dxgi_device_.Get();
|
||||
}
|
||||
inline IDXGISwapChain* GetDXGISwapChain()
|
||||
{
|
||||
KGE_ASSERT(dxgi_swap_chain_);
|
||||
return dxgi_swap_chain_.get();
|
||||
return dxgi_swap_chain_.Get();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -305,7 +305,7 @@ HRESULT STDMETHODCALLTYPE FontFileEnumerator::MoveNext(_Out_ BOOL* hasCurrentFil
|
|||
|
||||
if (nextIndex_ < filePaths_.size())
|
||||
{
|
||||
WideString file_name = MultiByteToWide(filePaths_[nextIndex_]);
|
||||
WideString file_name = string::ToWide(filePaths_[nextIndex_]);
|
||||
|
||||
hr = pFactory_->CreateFontFileReference(file_name.c_str(), NULL, ¤tFile_);
|
||||
|
||||
|
|
|
|||
|
|
@ -38,10 +38,10 @@ HRESULT RenderContextImpl::CreateDeviceResources(ComPtr<ID2D1Factory> factory, C
|
|||
return E_INVALIDARG;
|
||||
|
||||
render_target_ = ctx;
|
||||
text_renderer_.reset();
|
||||
current_brush_.reset();
|
||||
text_renderer_.Reset();
|
||||
current_brush_.Reset();
|
||||
|
||||
HRESULT hr = ITextRenderer::Create(&text_renderer_, render_target_.get());
|
||||
HRESULT hr = ITextRenderer::Create(&text_renderer_, render_target_.Get());
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
|
|
@ -62,9 +62,9 @@ HRESULT RenderContextImpl::CreateDeviceResources(ComPtr<ID2D1Factory> factory, C
|
|||
|
||||
void RenderContextImpl::DiscardDeviceResources()
|
||||
{
|
||||
text_renderer_.reset();
|
||||
render_target_.reset();
|
||||
current_brush_.reset();
|
||||
text_renderer_.Reset();
|
||||
render_target_.Reset();
|
||||
current_brush_.Reset();
|
||||
}
|
||||
|
||||
bool RenderContextImpl::IsValid() const
|
||||
|
|
@ -86,7 +86,7 @@ void RenderContextImpl::BeginDraw()
|
|||
|
||||
void RenderContextImpl::EndDraw()
|
||||
{
|
||||
ThrowIfFailed(render_target_->EndDraw(), "ID2D1RenderTarget EndDraw failed");
|
||||
KGE_THROW_IF_FAILED(render_target_->EndDraw(), "ID2D1RenderTarget EndDraw failed");
|
||||
|
||||
RenderContext::EndDraw();
|
||||
|
||||
|
|
@ -103,7 +103,7 @@ void RenderContextImpl::DrawTexture(Texture const& texture, const Rect* src_rect
|
|||
? D2D1_BITMAP_INTERPOLATION_MODE_LINEAR
|
||||
: D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR;
|
||||
|
||||
render_target_->DrawBitmap(texture.GetBitmap().get(), dest_rect ? &DX::ConvertToRectF(*dest_rect) : nullptr,
|
||||
render_target_->DrawBitmap(texture.GetBitmap().Get(), dest_rect ? &DX::ConvertToRectF(*dest_rect) : nullptr,
|
||||
brush_opacity_, mode, src_rect ? &DX::ConvertToRectF(*src_rect) : nullptr);
|
||||
|
||||
IncreasePrimitivesCount();
|
||||
|
|
@ -133,10 +133,10 @@ void RenderContextImpl::DrawTextLayout(TextLayout const& layout, Point const& of
|
|||
}
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
ID2D1StrokeStyle* stroke_style = style.outline_stroke ? style.outline_stroke->GetStrokeStyle().get() : nullptr;
|
||||
ID2D1StrokeStyle* stroke_style = style.outline_stroke ? style.outline_stroke->GetStrokeStyle().Get() : nullptr;
|
||||
|
||||
hr = text_renderer_->DrawTextLayout(layout.GetTextLayout().get(), offset.x, offset.y, fill_brush.get(),
|
||||
outline_brush.get(), style.outline_width, stroke_style);
|
||||
hr = text_renderer_->DrawTextLayout(layout.GetTextLayout().Get(), offset.x, offset.y, fill_brush.Get(),
|
||||
outline_brush.Get(), style.outline_width, stroke_style);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
|
|
@ -156,8 +156,8 @@ void RenderContextImpl::DrawShape(Shape const& shape, StrokeStylePtr stroke, flo
|
|||
|
||||
if (shape.IsValid())
|
||||
{
|
||||
ID2D1StrokeStyle* stroke_style = stroke ? stroke->GetStrokeStyle().get() : nullptr;
|
||||
render_target_->DrawGeometry(shape.GetGeometry().get(), current_brush_->GetBrush().get(), stroke_width,
|
||||
ID2D1StrokeStyle* stroke_style = stroke ? stroke->GetStrokeStyle().Get() : nullptr;
|
||||
render_target_->DrawGeometry(shape.GetGeometry().Get(), current_brush_->GetBrush().Get(), stroke_width,
|
||||
stroke_style);
|
||||
|
||||
IncreasePrimitivesCount();
|
||||
|
|
@ -169,9 +169,9 @@ void RenderContextImpl::DrawLine(Point const& point1, Point const& point2, Strok
|
|||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
|
||||
|
||||
ID2D1StrokeStyle* stroke_style = stroke ? stroke->GetStrokeStyle().get() : nullptr;
|
||||
ID2D1StrokeStyle* stroke_style = stroke ? stroke->GetStrokeStyle().Get() : nullptr;
|
||||
render_target_->DrawLine(DX::ConvertToPoint2F(point1), DX::ConvertToPoint2F(point2),
|
||||
current_brush_->GetBrush().get(), stroke_width, stroke_style);
|
||||
current_brush_->GetBrush().Get(), stroke_width, stroke_style);
|
||||
|
||||
IncreasePrimitivesCount();
|
||||
}
|
||||
|
|
@ -181,8 +181,8 @@ void RenderContextImpl::DrawRectangle(Rect const& rect, StrokeStylePtr stroke, f
|
|||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
|
||||
|
||||
ID2D1StrokeStyle* stroke_style = stroke ? stroke->GetStrokeStyle().get() : nullptr;
|
||||
render_target_->DrawRectangle(DX::ConvertToRectF(rect), current_brush_->GetBrush().get(), stroke_width,
|
||||
ID2D1StrokeStyle* stroke_style = stroke ? stroke->GetStrokeStyle().Get() : nullptr;
|
||||
render_target_->DrawRectangle(DX::ConvertToRectF(rect), current_brush_->GetBrush().Get(), stroke_width,
|
||||
stroke_style);
|
||||
|
||||
IncreasePrimitivesCount();
|
||||
|
|
@ -194,9 +194,9 @@ void RenderContextImpl::DrawRoundedRectangle(Rect const& rect, Vec2 const& radiu
|
|||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
|
||||
|
||||
ID2D1StrokeStyle* stroke_style = stroke ? stroke->GetStrokeStyle().get() : nullptr;
|
||||
ID2D1StrokeStyle* stroke_style = stroke ? stroke->GetStrokeStyle().Get() : nullptr;
|
||||
render_target_->DrawRoundedRectangle(D2D1::RoundedRect(DX::ConvertToRectF(rect), radius.x, radius.y),
|
||||
current_brush_->GetBrush().get(), stroke_width, stroke_style);
|
||||
current_brush_->GetBrush().Get(), stroke_width, stroke_style);
|
||||
|
||||
IncreasePrimitivesCount();
|
||||
}
|
||||
|
|
@ -206,9 +206,9 @@ void RenderContextImpl::DrawEllipse(Point const& center, Vec2 const& radius, Str
|
|||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
|
||||
|
||||
ID2D1StrokeStyle* stroke_style = stroke ? stroke->GetStrokeStyle().get() : nullptr;
|
||||
ID2D1StrokeStyle* stroke_style = stroke ? stroke->GetStrokeStyle().Get() : nullptr;
|
||||
render_target_->DrawEllipse(D2D1::Ellipse(DX::ConvertToPoint2F(center), radius.x, radius.y),
|
||||
current_brush_->GetBrush().get(), stroke_width, stroke_style);
|
||||
current_brush_->GetBrush().Get(), stroke_width, stroke_style);
|
||||
|
||||
IncreasePrimitivesCount();
|
||||
}
|
||||
|
|
@ -220,7 +220,7 @@ void RenderContextImpl::FillShape(Shape const& shape)
|
|||
|
||||
if (shape.IsValid())
|
||||
{
|
||||
render_target_->FillGeometry(shape.GetGeometry().get(), current_brush_->GetBrush().get());
|
||||
render_target_->FillGeometry(shape.GetGeometry().Get(), current_brush_->GetBrush().Get());
|
||||
|
||||
IncreasePrimitivesCount();
|
||||
}
|
||||
|
|
@ -231,7 +231,7 @@ void RenderContextImpl::FillRectangle(Rect const& rect)
|
|||
KGE_ASSERT(render_target_ && "Render target has not been initialized!");
|
||||
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
|
||||
|
||||
render_target_->FillRectangle(DX::ConvertToRectF(rect), current_brush_->GetBrush().get());
|
||||
render_target_->FillRectangle(DX::ConvertToRectF(rect), current_brush_->GetBrush().Get());
|
||||
|
||||
IncreasePrimitivesCount();
|
||||
}
|
||||
|
|
@ -242,7 +242,7 @@ void RenderContextImpl::FillRoundedRectangle(Rect const& rect, Vec2 const& radiu
|
|||
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
|
||||
|
||||
render_target_->FillRoundedRectangle(D2D1::RoundedRect(DX::ConvertToRectF(rect), radius.x, radius.y),
|
||||
current_brush_->GetBrush().get());
|
||||
current_brush_->GetBrush().Get());
|
||||
|
||||
IncreasePrimitivesCount();
|
||||
}
|
||||
|
|
@ -253,7 +253,7 @@ void RenderContextImpl::FillEllipse(Point const& center, Vec2 const& radius)
|
|||
KGE_ASSERT(current_brush_ && "The brush used for rendering has not been set!");
|
||||
|
||||
render_target_->FillEllipse(D2D1::Ellipse(DX::ConvertToPoint2F(center), radius.x, radius.y),
|
||||
current_brush_->GetBrush().get());
|
||||
current_brush_->GetBrush().Get());
|
||||
|
||||
IncreasePrimitivesCount();
|
||||
}
|
||||
|
|
@ -271,7 +271,7 @@ void RenderContextImpl::CreateTexture(Texture& texture, math::Vec2T<uint32_t> si
|
|||
texture.SetBitmap(saved_bitmap);
|
||||
}
|
||||
|
||||
ThrowIfFailed(hr, "Create texture failed");
|
||||
KGE_THROW_IF_FAILED(hr, "Create texture failed");
|
||||
}
|
||||
|
||||
void RenderContextImpl::PushClipRect(Rect const& clip_rect)
|
||||
|
|
@ -302,7 +302,7 @@ void RenderContextImpl::PushLayer(Layer& layer)
|
|||
}
|
||||
else
|
||||
{
|
||||
ThrowIfFailed(hr, "Create ID2D1Layer failed");
|
||||
KGE_THROW_IF_FAILED(hr, "Create ID2D1Layer failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -313,11 +313,11 @@ void RenderContextImpl::PushLayer(Layer& layer)
|
|||
mask = layer.GetMaskShape()->GetGeometry();
|
||||
|
||||
render_target_->PushLayer(
|
||||
D2D1::LayerParameters(DX::ConvertToRectF(layer.GetClipRect()), mask.get(),
|
||||
D2D1::LayerParameters(DX::ConvertToRectF(layer.GetClipRect()), mask.Get(),
|
||||
antialias_ ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE : D2D1_ANTIALIAS_MODE_ALIASED,
|
||||
DX::ConvertToMatrix3x2F(layer.GetMaskTransform()), layer.GetOpacity(), nullptr,
|
||||
D2D1_LAYER_OPTIONS_NONE),
|
||||
layer.GetLayer().get());
|
||||
layer.GetLayer().Get());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -430,7 +430,7 @@ void RenderContextImpl::SaveDrawingState()
|
|||
|
||||
if (drawing_state_)
|
||||
{
|
||||
render_target_->SaveDrawingState(drawing_state_.get());
|
||||
render_target_->SaveDrawingState(drawing_state_.Get());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -440,7 +440,7 @@ void RenderContextImpl::RestoreDrawingState()
|
|||
|
||||
if (drawing_state_)
|
||||
{
|
||||
render_target_->RestoreDrawingState(drawing_state_.get());
|
||||
render_target_->RestoreDrawingState(drawing_state_.Get());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ void RendererImpl::MakeContextForWindow(WindowPtr window)
|
|||
{
|
||||
KGE_SYS_LOG("Creating device resources");
|
||||
|
||||
ThrowIfFailed(::CoInitialize(nullptr), "CoInitialize failed");
|
||||
KGE_THROW_IF_FAILED(::CoInitialize(nullptr), "CoInitialize failed");
|
||||
|
||||
HWND target_window = window->GetHandle();
|
||||
output_size_ = window->GetSize();
|
||||
|
|
@ -83,7 +83,7 @@ void RendererImpl::MakeContextForWindow(WindowPtr window)
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = d2d_res_->GetDWriteFactory()->RegisterFontCollectionLoader(font_collection_loader_.get());
|
||||
hr = d2d_res_->GetDWriteFactory()->RegisterFontCollectionLoader(font_collection_loader_.Get());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -94,40 +94,40 @@ void RendererImpl::MakeContextForWindow(WindowPtr window)
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = d2d_res_->GetDWriteFactory()->RegisterFontFileLoader(res_font_file_loader_.get());
|
||||
hr = d2d_res_->GetDWriteFactory()->RegisterFontFileLoader(res_font_file_loader_.Get());
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = IResourceFontCollectionLoader::Create(&res_font_collection_loader_,
|
||||
res_font_file_loader_.get());
|
||||
res_font_file_loader_.Get());
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = d2d_res_->GetDWriteFactory()->RegisterFontCollectionLoader(
|
||||
res_font_collection_loader_.get());
|
||||
res_font_collection_loader_.Get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ThrowIfFailed(hr, "Create render resources failed");
|
||||
KGE_THROW_IF_FAILED(hr, "Create render resources failed");
|
||||
}
|
||||
|
||||
void RendererImpl::Destroy()
|
||||
{
|
||||
KGE_SYS_LOG("Destroying device resources");
|
||||
|
||||
d2d_res_->GetDWriteFactory()->UnregisterFontFileLoader(res_font_file_loader_.get());
|
||||
res_font_file_loader_.reset();
|
||||
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_.Reset();
|
||||
d3d_res_.Reset();
|
||||
|
||||
::CoUninitialize();
|
||||
}
|
||||
|
|
@ -165,7 +165,7 @@ void RendererImpl::Present()
|
|||
hr = HandleDeviceLost();
|
||||
}
|
||||
|
||||
ThrowIfFailed(hr, "Unexpected DXGI exception");
|
||||
KGE_THROW_IF_FAILED(hr, "Unexpected DXGI exception");
|
||||
}
|
||||
|
||||
HRESULT RendererImpl::HandleDeviceLost()
|
||||
|
|
@ -202,7 +202,7 @@ void RendererImpl::CreateTexture(Texture& texture, String const& file_path)
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
WideString full_path = MultiByteToWide(FileSystem::GetInstance().GetFullPathForFile(file_path));
|
||||
WideString full_path = string::ToWide(FileSystem::GetInstance().GetFullPathForFile(file_path));
|
||||
|
||||
ComPtr<IWICBitmapDecoder> decoder;
|
||||
hr = d2d_res_->CreateBitmapDecoderFromFile(decoder, full_path.c_str());
|
||||
|
|
@ -235,7 +235,7 @@ void RendererImpl::CreateTexture(Texture& texture, String const& file_path)
|
|||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
ThrowIfFailed(hr, "Load texture failed");
|
||||
KGE_THROW_IF_FAILED(hr, "Load texture failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -307,7 +307,7 @@ void RendererImpl::CreateGifImage(GifImage& gif, String const& file_path)
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
WideString full_path = MultiByteToWide(FileSystem::GetInstance().GetFullPathForFile(file_path));
|
||||
WideString full_path = string::ToWide(FileSystem::GetInstance().GetFullPathForFile(file_path));
|
||||
|
||||
ComPtr<IWICBitmapDecoder> decoder;
|
||||
hr = d2d_res_->CreateBitmapDecoderFromFile(decoder, full_path.c_str());
|
||||
|
|
@ -543,7 +543,7 @@ void RendererImpl::CreateFontCollection(Font& font, String const& file_path)
|
|||
if (SUCCEEDED(hr))
|
||||
{
|
||||
ComPtr<IDWriteFontCollection> font_collection;
|
||||
hr = d2d_res_->GetDWriteFactory()->CreateCustomFontCollection(font_collection_loader_.get(), key, key_size,
|
||||
hr = d2d_res_->GetDWriteFactory()->CreateCustomFontCollection(font_collection_loader_.Get(), key, key_size,
|
||||
&font_collection);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
|
|
@ -553,7 +553,7 @@ void RendererImpl::CreateFontCollection(Font& font, String const& file_path)
|
|||
}
|
||||
}
|
||||
|
||||
ThrowIfFailed(hr, "Create font collection failed");
|
||||
KGE_THROW_IF_FAILED(hr, "Create font collection failed");
|
||||
}
|
||||
|
||||
void RendererImpl::CreateFontCollection(Font& font, Resource const& res)
|
||||
|
|
@ -574,7 +574,7 @@ void RendererImpl::CreateFontCollection(Font& font, Resource const& res)
|
|||
if (SUCCEEDED(hr))
|
||||
{
|
||||
ComPtr<IDWriteFontCollection> font_collection;
|
||||
hr = d2d_res_->GetDWriteFactory()->CreateCustomFontCollection(res_font_collection_loader_.get(), key,
|
||||
hr = d2d_res_->GetDWriteFactory()->CreateCustomFontCollection(res_font_collection_loader_.Get(), key,
|
||||
key_size, &font_collection);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
|
|
@ -584,7 +584,7 @@ void RendererImpl::CreateFontCollection(Font& font, Resource const& res)
|
|||
}
|
||||
}
|
||||
|
||||
ThrowIfFailed(hr, "Create font collection failed");
|
||||
KGE_THROW_IF_FAILED(hr, "Create font collection failed");
|
||||
}
|
||||
|
||||
void RendererImpl::CreateTextLayout(TextLayout& layout)
|
||||
|
|
@ -599,53 +599,108 @@ void RendererImpl::CreateTextLayout(TextLayout& layout)
|
|||
{
|
||||
layout.SetTextFormat(nullptr);
|
||||
layout.SetTextLayout(nullptr);
|
||||
layout.SetDirtyFlag(TextLayout::DirtyFlag::Updated);
|
||||
return;
|
||||
}
|
||||
|
||||
const TextStyle& style = layout.GetStyle();
|
||||
|
||||
if (!layout.GetTextFormat() || (layout.GetDirtyFlag() & TextLayout::DirtyFlag::DirtyFormat))
|
||||
{
|
||||
WideString font_family = style.font_family.empty() ? L"" : string::ToWide(style.font_family);
|
||||
DWRITE_FONT_WEIGHT font_weight = DWRITE_FONT_WEIGHT(style.font_weight);
|
||||
DWRITE_FONT_STYLE font_style = style.italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL;
|
||||
IDWriteFontCollection* collection = style.font ? style.font->GetCollection().Get() : nullptr;
|
||||
|
||||
ComPtr<IDWriteTextFormat> output;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
const TextStyle& style = layout.GetStyle();
|
||||
|
||||
hr = d2d_res_->CreateTextFormat(output, MultiByteToWide(style.font_family).c_str(),
|
||||
style.font ? style.font->GetCollection() : nullptr,
|
||||
DWRITE_FONT_WEIGHT(style.font_weight),
|
||||
style.italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL,
|
||||
hr = d2d_res_->CreateTextFormat(output, font_family.c_str(), collection, font_weight, font_style,
|
||||
DWRITE_FONT_STRETCH_NORMAL, style.font_size);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
layout.SetTextFormat(output);
|
||||
layout.SetDirtyFlag(layout.GetDirtyFlag() | TextLayout::DirtyFlag::DirtyLayout);
|
||||
}
|
||||
}
|
||||
|
||||
if (layout.GetDirtyFlag() & TextLayout::DirtyFlag::DirtyLayout)
|
||||
{
|
||||
ComPtr<IDWriteTextLayout> output;
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
|
||||
WideString text = MultiByteToWide(layout.GetText());
|
||||
WideString text = string::ToWide(layout.GetText());
|
||||
|
||||
hr = d2d_res_->CreateTextLayout(output, text.c_str(), text.length(), layout.GetTextFormat());
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = output->SetTextAlignment(DWRITE_TEXT_ALIGNMENT(style.alignment));
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
float wrap_width = style.wrap_width;
|
||||
bool enable_wrapping = (wrap_width > 0);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
if (enable_wrapping)
|
||||
{
|
||||
hr = output->SetWordWrapping(DWRITE_WORD_WRAPPING_WRAP);
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = output->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
if (enable_wrapping)
|
||||
{
|
||||
hr = output->SetMaxWidth(wrap_width);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fix the layout width when the text does not wrap
|
||||
DWRITE_TEXT_METRICS metrics;
|
||||
hr = output->GetMetrics(&metrics);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = output->SetMaxWidth(metrics.width);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
float spacing = style.line_spacing;
|
||||
if (spacing == 0.f)
|
||||
{
|
||||
hr = output->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_DEFAULT, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = output->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_UNIFORM, spacing, spacing * 0.8f);
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
layout.SetTextLayout(output);
|
||||
|
||||
layout.SetAlignment(layout.GetStyle().alignment);
|
||||
layout.SetWrapWidth(layout.GetStyle().wrap_width);
|
||||
layout.SetLineSpacing(layout.GetStyle().line_spacing);
|
||||
|
||||
layout.SetDirtyFlag(TextLayout::DirtyFlag::Clean);
|
||||
}
|
||||
}
|
||||
|
||||
ThrowIfFailed(hr, "Create text layout failed");
|
||||
layout.SetDirtyFlag(TextLayout::DirtyFlag::Updated);
|
||||
|
||||
KGE_THROW_IF_FAILED(hr, "Create text layout failed");
|
||||
}
|
||||
|
||||
void RendererImpl::CreateLineShape(Shape& shape, Point const& begin_pos, Point const& end_pos)
|
||||
|
|
@ -681,7 +736,7 @@ void RendererImpl::CreateLineShape(Shape& shape, Point const& begin_pos, Point c
|
|||
shape.SetGeometry(path_geo);
|
||||
}
|
||||
|
||||
ThrowIfFailed(hr, "Create ID2D1PathGeometry failed");
|
||||
KGE_THROW_IF_FAILED(hr, "Create ID2D1PathGeometry failed");
|
||||
}
|
||||
|
||||
void RendererImpl::CreateRectShape(Shape& shape, Rect const& rect)
|
||||
|
|
@ -703,7 +758,7 @@ void RendererImpl::CreateRectShape(Shape& shape, Rect const& rect)
|
|||
shape.SetGeometry(output);
|
||||
}
|
||||
|
||||
ThrowIfFailed(hr, "Create ID2D1RectangleGeometry failed");
|
||||
KGE_THROW_IF_FAILED(hr, "Create ID2D1RectangleGeometry failed");
|
||||
}
|
||||
|
||||
void RendererImpl::CreateRoundedRectShape(Shape& shape, Rect const& rect, Vec2 const& radius)
|
||||
|
|
@ -726,7 +781,7 @@ void RendererImpl::CreateRoundedRectShape(Shape& shape, Rect const& rect, Vec2 c
|
|||
shape.SetGeometry(output);
|
||||
}
|
||||
|
||||
ThrowIfFailed(hr, "Create ID2D1RoundedRectangleGeometry failed");
|
||||
KGE_THROW_IF_FAILED(hr, "Create ID2D1RoundedRectangleGeometry failed");
|
||||
}
|
||||
|
||||
void RendererImpl::CreateEllipseShape(Shape& shape, Point const& center, Vec2 const& radius)
|
||||
|
|
@ -749,7 +804,7 @@ void RendererImpl::CreateEllipseShape(Shape& shape, Point const& center, Vec2 co
|
|||
shape.SetGeometry(output);
|
||||
}
|
||||
|
||||
ThrowIfFailed(hr, "Create ID2D1EllipseGeometry failed");
|
||||
KGE_THROW_IF_FAILED(hr, "Create ID2D1EllipseGeometry failed");
|
||||
}
|
||||
|
||||
void RendererImpl::CreateShapeSink(ShapeSink& sink)
|
||||
|
|
@ -771,7 +826,7 @@ void RendererImpl::CreateShapeSink(ShapeSink& sink)
|
|||
sink.SetPathGeometry(output);
|
||||
}
|
||||
|
||||
ThrowIfFailed(hr, "Create ID2D1PathGeometry failed");
|
||||
KGE_THROW_IF_FAILED(hr, "Create ID2D1PathGeometry failed");
|
||||
}
|
||||
|
||||
void RendererImpl::CreateBrush(Brush& brush, Color const& color)
|
||||
|
|
@ -805,7 +860,7 @@ void RendererImpl::CreateBrush(Brush& brush, Color const& color)
|
|||
}
|
||||
}
|
||||
|
||||
ThrowIfFailed(hr, "Create ID2D1SolidBrush failed");
|
||||
KGE_THROW_IF_FAILED(hr, "Create ID2D1SolidBrush failed");
|
||||
}
|
||||
|
||||
void RendererImpl::CreateBrush(Brush& brush, LinearGradientStyle const& style)
|
||||
|
|
@ -828,7 +883,7 @@ void RendererImpl::CreateBrush(Brush& brush, LinearGradientStyle const& style)
|
|||
ComPtr<ID2D1LinearGradientBrush> output;
|
||||
hr = d2d_res_->GetDeviceContext()->CreateLinearGradientBrush(
|
||||
D2D1::LinearGradientBrushProperties(DX::ConvertToPoint2F(style.begin), DX::ConvertToPoint2F(style.end)),
|
||||
collection.get(), &output);
|
||||
collection.Get(), &output);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
|
|
@ -837,7 +892,7 @@ void RendererImpl::CreateBrush(Brush& brush, LinearGradientStyle const& style)
|
|||
}
|
||||
}
|
||||
|
||||
ThrowIfFailed(hr, "Create ID2D1LinearGradientBrush failed");
|
||||
KGE_THROW_IF_FAILED(hr, "Create ID2D1LinearGradientBrush failed");
|
||||
}
|
||||
|
||||
void RendererImpl::CreateBrush(Brush& brush, RadialGradientStyle const& style)
|
||||
|
|
@ -861,7 +916,7 @@ void RendererImpl::CreateBrush(Brush& brush, RadialGradientStyle const& style)
|
|||
hr = d2d_res_->GetDeviceContext()->CreateRadialGradientBrush(
|
||||
D2D1::RadialGradientBrushProperties(DX::ConvertToPoint2F(style.center),
|
||||
DX::ConvertToPoint2F(style.offset), style.radius.x, style.radius.y),
|
||||
collection.get(), &output);
|
||||
collection.Get(), &output);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
|
|
@ -870,11 +925,11 @@ void RendererImpl::CreateBrush(Brush& brush, RadialGradientStyle const& style)
|
|||
}
|
||||
}
|
||||
|
||||
ThrowIfFailed(hr, "Create ID2D1RadialGradientBrush failed");
|
||||
KGE_THROW_IF_FAILED(hr, "Create ID2D1RadialGradientBrush failed");
|
||||
}
|
||||
|
||||
void RendererImpl::CreateStrokeStyle(StrokeStyle& stroke_style, CapStyle cap, LineJoinStyle line_join,
|
||||
const float* dash_array, size_t dash_size, float dash_offset)
|
||||
const float* dash_array, size_t dash_size, float dash_offset)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
if (!d2d_res_)
|
||||
|
|
@ -897,7 +952,7 @@ void RendererImpl::CreateStrokeStyle(StrokeStyle& stroke_style, CapStyle cap, Li
|
|||
}
|
||||
}
|
||||
|
||||
ThrowIfFailed(hr, "Create ID2D1StrokeStyle failed");
|
||||
KGE_THROW_IF_FAILED(hr, "Create ID2D1StrokeStyle failed");
|
||||
}
|
||||
|
||||
TextureRenderContextPtr RendererImpl::CreateTextureRenderContext(const Size* desired_size)
|
||||
|
|
@ -966,7 +1021,7 @@ void RendererImpl::Resize(uint32_t width, uint32_t height)
|
|||
render_ctx_->Resize(output_size_);
|
||||
}
|
||||
|
||||
ThrowIfFailed(hr, "Resize render target failed");
|
||||
KGE_THROW_IF_FAILED(hr, "Resize render target failed");
|
||||
}
|
||||
|
||||
} // namespace kiwano
|
||||
|
|
|
|||
|
|
@ -132,13 +132,13 @@ inline RenderContext& RendererImpl::GetContext()
|
|||
inline ID2DDeviceResources* RendererImpl::GetD2DDeviceResources()
|
||||
{
|
||||
KGE_ASSERT(d2d_res_);
|
||||
return d2d_res_.get();
|
||||
return d2d_res_.Get();
|
||||
}
|
||||
|
||||
inline ID3DDeviceResources* RendererImpl::GetD3DDeviceResources()
|
||||
{
|
||||
KGE_ASSERT(d3d_res_);
|
||||
return d3d_res_.get();
|
||||
return d3d_res_.Get();
|
||||
}
|
||||
|
||||
} // namespace kiwano
|
||||
|
|
|
|||
|
|
@ -121,8 +121,8 @@ STDMETHODIMP TextRenderer::CreateDeviceResources(_In_ ID2D1RenderTarget* pRT)
|
|||
{
|
||||
HRESULT hr = E_FAIL;
|
||||
|
||||
pFactory_.reset();
|
||||
pRT_.reset();
|
||||
pFactory_.Reset();
|
||||
pRT_.Reset();
|
||||
|
||||
if (pRT)
|
||||
{
|
||||
|
|
@ -180,7 +180,7 @@ STDMETHODIMP TextRenderer::DrawGlyphRun(__maybenull void* clientDrawingContext,
|
|||
{
|
||||
hr = glyphRun->fontFace->GetGlyphRunOutline(
|
||||
glyphRun->fontEmSize, glyphRun->glyphIndices, glyphRun->glyphAdvances, glyphRun->glyphOffsets,
|
||||
glyphRun->glyphCount, glyphRun->isSideways, glyphRun->bidiLevel % 2, pSink.get());
|
||||
glyphRun->glyphCount, glyphRun->isSideways, glyphRun->bidiLevel % 2, pSink.Get());
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
|
|
@ -195,14 +195,14 @@ STDMETHODIMP TextRenderer::DrawGlyphRun(__maybenull void* clientDrawingContext,
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = pFactory_->CreateTransformedGeometry(pPathGeometry.get(), &matrix, &pTransformedGeometry);
|
||||
hr = pFactory_->CreateTransformedGeometry(pPathGeometry.Get(), &matrix, &pTransformedGeometry);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
pRT_->DrawGeometry(pTransformedGeometry.get(), pOutlineBrush_.get(),
|
||||
pRT_->DrawGeometry(pTransformedGeometry.Get(), pOutlineBrush_.Get(),
|
||||
fOutlineWidth_ * 2, // twice width for widening
|
||||
pCurrStrokeStyle_.get());
|
||||
pCurrStrokeStyle_.Get());
|
||||
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
|
|
@ -212,7 +212,7 @@ STDMETHODIMP TextRenderer::DrawGlyphRun(__maybenull void* clientDrawingContext,
|
|||
|
||||
if (SUCCEEDED(hr) && pFillBrush_)
|
||||
{
|
||||
pRT_->DrawGlyphRun(D2D1::Point2F(baselineOriginX, baselineOriginY), glyphRun, pFillBrush_.get());
|
||||
pRT_->DrawGlyphRun(D2D1::Point2F(baselineOriginX, baselineOriginY), glyphRun, pFillBrush_.Get());
|
||||
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
|
|
@ -238,20 +238,20 @@ STDMETHODIMP TextRenderer::DrawUnderline(__maybenull void* clientDrawingContext,
|
|||
ComPtr<ID2D1TransformedGeometry> pTransformedGeometry;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = pFactory_->CreateTransformedGeometry(pRectangleGeometry.get(), &matrix, &pTransformedGeometry);
|
||||
hr = pFactory_->CreateTransformedGeometry(pRectangleGeometry.Get(), &matrix, &pTransformedGeometry);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr) && pOutlineBrush_)
|
||||
{
|
||||
pRT_->DrawGeometry(pTransformedGeometry.get(), pOutlineBrush_.get(), fOutlineWidth_ * 2,
|
||||
pCurrStrokeStyle_.get());
|
||||
pRT_->DrawGeometry(pTransformedGeometry.Get(), pOutlineBrush_.Get(), fOutlineWidth_ * 2,
|
||||
pCurrStrokeStyle_.Get());
|
||||
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr) && pFillBrush_)
|
||||
{
|
||||
pRT_->FillGeometry(pTransformedGeometry.get(), pFillBrush_.get());
|
||||
pRT_->FillGeometry(pTransformedGeometry.Get(), pFillBrush_.Get());
|
||||
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
|
|
@ -278,20 +278,20 @@ STDMETHODIMP TextRenderer::DrawStrikethrough(__maybenull void* clientDrawingCont
|
|||
ComPtr<ID2D1TransformedGeometry> pTransformedGeometry;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = pFactory_->CreateTransformedGeometry(pRectangleGeometry.get(), &matrix, &pTransformedGeometry);
|
||||
hr = pFactory_->CreateTransformedGeometry(pRectangleGeometry.Get(), &matrix, &pTransformedGeometry);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr) && pOutlineBrush_)
|
||||
{
|
||||
pRT_->DrawGeometry(pTransformedGeometry.get(), pOutlineBrush_.get(), fOutlineWidth_ * 2,
|
||||
pCurrStrokeStyle_.get());
|
||||
pRT_->DrawGeometry(pTransformedGeometry.Get(), pOutlineBrush_.Get(), fOutlineWidth_ * 2,
|
||||
pCurrStrokeStyle_.Get());
|
||||
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr) && pFillBrush_)
|
||||
{
|
||||
pRT_->FillGeometry(pTransformedGeometry.get(), pFillBrush_.get());
|
||||
pRT_->FillGeometry(pTransformedGeometry.Get(), pFillBrush_.Get());
|
||||
|
||||
++cPrimitivesCount_;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,28 +67,28 @@ public:
|
|||
/// @brief 创建纹理内部资源
|
||||
/// @param[out] texture 纹理
|
||||
/// @param[in] file_path 图片路径
|
||||
/// @throw std::system_error 创建失败时抛出
|
||||
/// @throw kiwano::SystemError 创建失败时抛出
|
||||
virtual void CreateTexture(Texture& texture, String const& file_path) = 0;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 创建纹理内部资源
|
||||
/// @param[out] texture 纹理
|
||||
/// @param[in] resource 图片资源
|
||||
/// @throw std::system_error 创建失败时抛出
|
||||
/// @throw kiwano::SystemError 创建失败时抛出
|
||||
virtual void CreateTexture(Texture& texture, Resource const& resource) = 0;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 创建GIF图像内部资源
|
||||
/// @param[out] gif GIF图像
|
||||
/// @param[in] file_path 图片路径
|
||||
/// @throw std::system_error 创建失败时抛出
|
||||
/// @throw kiwano::SystemError 创建失败时抛出
|
||||
virtual void CreateGifImage(GifImage& gif, String const& file_path) = 0;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 创建GIF图像内部资源
|
||||
/// @param[out] gif GIF图像
|
||||
/// @param[in] resource 图片资源
|
||||
/// @throw std::system_error 创建失败时抛出
|
||||
/// @throw kiwano::SystemError 创建失败时抛出
|
||||
virtual void CreateGifImage(GifImage& gif, Resource const& resource) = 0;
|
||||
|
||||
/// \~chinese
|
||||
|
|
@ -96,27 +96,27 @@ public:
|
|||
/// @param[out] frame GIF图像帧
|
||||
/// @param[in] gif GIF图像
|
||||
/// @param[in] frame_index 帧下标
|
||||
/// @throw std::system_error 创建失败时抛出
|
||||
/// @throw kiwano::SystemError 创建失败时抛出
|
||||
virtual void CreateGifImageFrame(GifImage::Frame& frame, GifImage const& gif, size_t frame_index) = 0;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 创建字体集内部资源
|
||||
/// @param[out] font 字体
|
||||
/// @param[in] file_paths 字体文件路径
|
||||
/// @throw std::system_error 创建失败时抛出
|
||||
/// @throw kiwano::SystemError 创建失败时抛出
|
||||
virtual void CreateFontCollection(Font& font, String const& file_path) = 0;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 创建字体集内部资源
|
||||
/// @param[out] font 字体
|
||||
/// @param[in] res_arr 字体资源
|
||||
/// @throw std::system_error 创建失败时抛出
|
||||
/// @throw kiwano::SystemError 创建失败时抛出
|
||||
virtual void CreateFontCollection(Font& font, Resource const& res) = 0;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 创建文字布局内部资源
|
||||
/// @param[out] layout 字体布局
|
||||
/// @throw std::system_error 创建失败时抛出
|
||||
/// @throw kiwano::SystemError 创建失败时抛出
|
||||
virtual void CreateTextLayout(TextLayout& layout) = 0;
|
||||
|
||||
/// \~chinese
|
||||
|
|
@ -124,14 +124,14 @@ public:
|
|||
/// @param[out] shape 形状
|
||||
/// @param[in] begin_pos 线段起点
|
||||
/// @param[in] end_pos 线段终点
|
||||
/// @throw std::system_error 创建失败时抛出
|
||||
/// @throw kiwano::SystemError 创建失败时抛出
|
||||
virtual void CreateLineShape(Shape& shape, Point const& begin_pos, Point const& end_pos) = 0;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 创建矩形形状内部资源
|
||||
/// @param[out] shape 形状
|
||||
/// @param[in] rect 矩形大小
|
||||
/// @throw std::system_error 创建失败时抛出
|
||||
/// @throw kiwano::SystemError 创建失败时抛出
|
||||
virtual void CreateRectShape(Shape& shape, Rect const& rect) = 0;
|
||||
|
||||
/// \~chinese
|
||||
|
|
@ -139,7 +139,7 @@ public:
|
|||
/// @param[out] shape 形状
|
||||
/// @param[in] rect 矩形大小
|
||||
/// @param[in] radius 圆角半径
|
||||
/// @throw std::system_error 创建失败时抛出
|
||||
/// @throw kiwano::SystemError 创建失败时抛出
|
||||
virtual void CreateRoundedRectShape(Shape& shape, Rect const& rect, Vec2 const& radius) = 0;
|
||||
|
||||
/// \~chinese
|
||||
|
|
@ -147,34 +147,34 @@ public:
|
|||
/// @param[out] shape 形状
|
||||
/// @param[in] center 椭圆圆心
|
||||
/// @param[in] radius 椭圆半径
|
||||
/// @throw std::system_error 创建失败时抛出
|
||||
/// @throw kiwano::SystemError 创建失败时抛出
|
||||
virtual void CreateEllipseShape(Shape& shape, Point const& center, Vec2 const& radius) = 0;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 创建几何图形生成器内部资源
|
||||
/// @param[out] sink 形状生成器
|
||||
/// @throw std::system_error 创建失败时抛出
|
||||
/// @throw kiwano::SystemError 创建失败时抛出
|
||||
virtual void CreateShapeSink(ShapeSink& sink) = 0;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 创建纯色画刷内部资源
|
||||
/// @param[out] brush 画刷
|
||||
/// @param[in] color 颜色
|
||||
/// @throw std::system_error 创建失败时抛出
|
||||
/// @throw kiwano::SystemError 创建失败时抛出
|
||||
virtual void CreateBrush(Brush& brush, Color const& color) = 0;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 创建线性渐变画刷内部资源
|
||||
/// @param[out] brush 画刷
|
||||
/// @param[in] style 线性渐变样式
|
||||
/// @throw std::system_error 创建失败时抛出
|
||||
/// @throw kiwano::SystemError 创建失败时抛出
|
||||
virtual void CreateBrush(Brush& brush, LinearGradientStyle const& style) = 0;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 创建径向渐变画刷内部资源
|
||||
/// @param[out] brush 画刷
|
||||
/// @param[in] style 径向渐变样式
|
||||
/// @throw std::system_error 创建失败时抛出
|
||||
/// @throw kiwano::SystemError 创建失败时抛出
|
||||
virtual void CreateBrush(Brush& brush, RadialGradientStyle const& style) = 0;
|
||||
|
||||
/// \~chinese
|
||||
|
|
@ -185,7 +185,7 @@ public:
|
|||
/// @param[in] dash_array 虚线长度与间隙数组
|
||||
/// @param[in] dash_size 虚线数组大小
|
||||
/// @param[in] dash_offset 虚线偏移量
|
||||
/// @throw std::system_error 创建失败时抛出
|
||||
/// @throw kiwano::SystemError 创建失败时抛出
|
||||
virtual void CreateStrokeStyle(StrokeStyle& stroke_style, CapStyle cap, LineJoinStyle line_join,
|
||||
const float* dash_array, size_t dash_size, float dash_offset) = 0;
|
||||
|
||||
|
|
@ -193,7 +193,7 @@ public:
|
|||
/// @brief 创建纹理渲染上下文
|
||||
/// @param[in] desired_size 期望的输出大小
|
||||
/// @return 纹理渲染上下文
|
||||
/// @throw std::system_error 创建失败时抛出
|
||||
/// @throw kiwano::SystemError 创建失败时抛出
|
||||
virtual TextureRenderContextPtr CreateTextureRenderContext(const Size* desired_size = nullptr) = 0;
|
||||
|
||||
public:
|
||||
|
|
@ -219,7 +219,7 @@ public:
|
|||
|
||||
/// \~chinese
|
||||
/// @brief 将绘制内容呈现至窗口
|
||||
/// @throw std::system_error 呈现失败时抛出
|
||||
/// @throw kiwano::SystemError 呈现失败时抛出
|
||||
virtual void Present() = 0;
|
||||
|
||||
/// \~chinese
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ bool Shape::ComputePointAtLength(float length, Point& point, Vec2& tangent) cons
|
|||
void Shape::Clear()
|
||||
{
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
geo_.reset();
|
||||
geo_.Reset();
|
||||
#else
|
||||
return; // not supported
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -36,10 +36,10 @@ void ShapeSink::Open()
|
|||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
if (!IsOpened())
|
||||
{
|
||||
path_geo_.reset();
|
||||
path_geo_.Reset();
|
||||
Renderer::GetInstance().CreateShapeSink(*this);
|
||||
|
||||
ThrowIfFailed(path_geo_->Open(&sink_), "Open ID2D1GeometrySink failed");
|
||||
KGE_THROW_IF_FAILED(path_geo_->Open(&sink_), "Open ID2D1GeometrySink failed");
|
||||
}
|
||||
#else
|
||||
return; // not supported
|
||||
|
|
@ -51,8 +51,8 @@ void ShapeSink::Close()
|
|||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
if (IsOpened())
|
||||
{
|
||||
ThrowIfFailed(sink_->Close(), "Close ID2D1GeometrySink failed");
|
||||
sink_.reset();
|
||||
KGE_THROW_IF_FAILED(sink_->Close(), "Close ID2D1GeometrySink failed");
|
||||
sink_.Reset();
|
||||
}
|
||||
|
||||
shape_ = new Shape;
|
||||
|
|
@ -90,8 +90,8 @@ ShapeSink& ShapeSink::AddShape(ShapePtr input, const Matrix3x2* input_matrix)
|
|||
ComPtr<ID2D1Geometry> geo = input->GetGeometry();
|
||||
|
||||
HRESULT hr =
|
||||
geo->Outline(DX::ConvertToMatrix3x2F(input_matrix), D2D1_DEFAULT_FLATTENING_TOLERANCE, sink_.get());
|
||||
ThrowIfFailed(hr, "Get outline of ID2D1Geometry failed");
|
||||
geo->Outline(DX::ConvertToMatrix3x2F(input_matrix), D2D1_DEFAULT_FLATTENING_TOLERANCE, sink_.Get());
|
||||
KGE_THROW_IF_FAILED(hr, "Get outline of ID2D1Geometry failed");
|
||||
}
|
||||
return (*this);
|
||||
#else
|
||||
|
|
@ -196,9 +196,9 @@ ShapeSink& ShapeSink::Combine(ShapePtr shape_a, ShapePtr shape_b, CombineMode mo
|
|||
ComPtr<ID2D1Geometry> geo_a_raw = shape_a->geo_;
|
||||
ComPtr<ID2D1Geometry> geo_b_raw = shape_b->geo_;
|
||||
|
||||
HRESULT hr = geo_a_raw->CombineWithGeometry(geo_b_raw.get(), D2D1_COMBINE_MODE(mode),
|
||||
DX::ConvertToMatrix3x2F(matrix), sink_.get());
|
||||
ThrowIfFailed(hr, "Combine ID2D1Geometry failed");
|
||||
HRESULT hr = geo_a_raw->CombineWithGeometry(geo_b_raw.Get(), D2D1_COMBINE_MODE(mode),
|
||||
DX::ConvertToMatrix3x2F(matrix), sink_.Get());
|
||||
KGE_THROW_IF_FAILED(hr, "Combine ID2D1Geometry failed");
|
||||
}
|
||||
#else
|
||||
// not supported
|
||||
|
|
@ -211,7 +211,7 @@ void ShapeSink::Clear()
|
|||
Close();
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
path_geo_.reset();
|
||||
path_geo_.Reset();
|
||||
#else
|
||||
// not supported
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ void StrokeStyle::SetDashStyle(DashStyle dash_style)
|
|||
void StrokeStyle::SetDashStyle(const Vector<float>& dash_array)
|
||||
{
|
||||
dash_array_ = dash_array;
|
||||
style_.reset();
|
||||
style_.Reset();
|
||||
}
|
||||
|
||||
void StrokeStyle::SetDashStyle(const float* dash_array, size_t dash_size)
|
||||
|
|
@ -109,7 +109,7 @@ void StrokeStyle::SetDashStyle(const float* dash_array, size_t dash_size)
|
|||
dash_array_.clear();
|
||||
else
|
||||
dash_array_.assign(dash_array, dash_array + dash_size);
|
||||
style_.reset();
|
||||
style_.Reset();
|
||||
}
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
|
|
|
|||
|
|
@ -206,19 +206,19 @@ inline float StrokeStyle::GetDashOffset() const
|
|||
inline void StrokeStyle::SetCapStyle(CapStyle cap)
|
||||
{
|
||||
cap_ = cap;
|
||||
style_.reset();
|
||||
style_.Reset();
|
||||
}
|
||||
|
||||
inline void StrokeStyle::SetLineJoinStyle(LineJoinStyle line_join)
|
||||
{
|
||||
line_join_ = line_join;
|
||||
style_.reset();
|
||||
style_.Reset();
|
||||
}
|
||||
|
||||
inline void StrokeStyle::SetDashOffset(float dash_offset)
|
||||
{
|
||||
dash_offset_ = dash_offset;
|
||||
style_.reset();
|
||||
style_.Reset();
|
||||
}
|
||||
|
||||
inline bool StrokeStyle::IsValid() const
|
||||
|
|
|
|||
|
|
@ -136,81 +136,29 @@ Size TextLayout::GetLayoutSize() const
|
|||
|
||||
void TextLayout::SetWrapWidth(float wrap_width)
|
||||
{
|
||||
style_.wrap_width = wrap_width;
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
if (text_layout_)
|
||||
if (style_.wrap_width != wrap_width)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
bool enable_wrapping = (wrap_width > 0);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = text_layout_->SetWordWrapping(enable_wrapping ? DWRITE_WORD_WRAPPING_WRAP
|
||||
: DWRITE_WORD_WRAPPING_NO_WRAP);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
if (enable_wrapping)
|
||||
{
|
||||
hr = text_layout_->SetMaxWidth(wrap_width);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fix the layout width when the text does not wrap
|
||||
DWRITE_TEXT_METRICS metrics;
|
||||
hr = text_layout_->GetMetrics(&metrics);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = text_layout_->SetMaxWidth(metrics.width);
|
||||
}
|
||||
}
|
||||
}
|
||||
ThrowIfFailed(hr, "Apply word wrapping to text layout failed");
|
||||
style_.wrap_width = wrap_width;
|
||||
dirty_flag_ |= DirtyFlag::DirtyLayout;
|
||||
}
|
||||
#else
|
||||
return; // not supported
|
||||
#endif
|
||||
}
|
||||
|
||||
void TextLayout::SetLineSpacing(float line_spacing)
|
||||
{
|
||||
style_.line_spacing = line_spacing;
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
if (text_layout_)
|
||||
if (style_.line_spacing != line_spacing)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
if (line_spacing == 0.f)
|
||||
{
|
||||
hr = text_layout_->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_DEFAULT, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = text_layout_->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_UNIFORM, line_spacing, line_spacing * 0.8f);
|
||||
}
|
||||
ThrowIfFailed(hr, "Apply line spacing to text layout failed");
|
||||
style_.line_spacing = line_spacing;
|
||||
dirty_flag_ |= DirtyFlag::DirtyLayout;
|
||||
}
|
||||
#else
|
||||
return; // not supported
|
||||
#endif
|
||||
}
|
||||
|
||||
void TextLayout::SetAlignment(TextAlign align)
|
||||
{
|
||||
style_.alignment = align;
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
if (text_layout_)
|
||||
if (style_.alignment != align)
|
||||
{
|
||||
HRESULT hr = text_layout_->SetTextAlignment(DWRITE_TEXT_ALIGNMENT(align));
|
||||
ThrowIfFailed(hr, "Apply alignment style to text layout failed");
|
||||
style_.alignment = align;
|
||||
dirty_flag_ |= DirtyFlag::DirtyLayout;
|
||||
}
|
||||
#else
|
||||
return; // not supported
|
||||
#endif
|
||||
}
|
||||
|
||||
void TextLayout::SetUnderline(bool enable, uint32_t start, uint32_t length)
|
||||
|
|
@ -225,7 +173,7 @@ void TextLayout::SetUnderline(bool enable, uint32_t start, uint32_t length)
|
|||
{
|
||||
hr = text_layout_->SetUnderline(enable, { start, length });
|
||||
}
|
||||
ThrowIfFailed(hr, "Apply underline style to text layout failed");
|
||||
KGE_THROW_IF_FAILED(hr, "Apply underline style to text layout failed");
|
||||
#else
|
||||
return; // not supported
|
||||
#endif
|
||||
|
|
@ -243,7 +191,7 @@ void TextLayout::SetStrikethrough(bool enable, uint32_t start, uint32_t length)
|
|||
{
|
||||
hr = text_layout_->SetStrikethrough(enable, { start, length });
|
||||
}
|
||||
ThrowIfFailed(hr, "Apply strikethrough style to text layout failed");
|
||||
KGE_THROW_IF_FAILED(hr, "Apply strikethrough style to text layout failed");
|
||||
#else
|
||||
return; // not supported
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -107,9 +107,9 @@ void Texture::CopyFrom(TexturePtr copy_from)
|
|||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
if (IsValid() && copy_from)
|
||||
{
|
||||
HRESULT hr = bitmap_->CopyFromBitmap(nullptr, copy_from->GetBitmap().get(), nullptr);
|
||||
HRESULT hr = bitmap_->CopyFromBitmap(nullptr, copy_from->GetBitmap().Get(), nullptr);
|
||||
|
||||
ThrowIfFailed(hr, "Copy texture data failed");
|
||||
KGE_THROW_IF_FAILED(hr, "Copy texture data failed");
|
||||
}
|
||||
#else
|
||||
return; // not supported
|
||||
|
|
@ -122,11 +122,11 @@ void Texture::CopyFrom(TexturePtr copy_from, Rect const& src_rect, Point const&
|
|||
if (IsValid() && copy_from)
|
||||
{
|
||||
HRESULT hr = bitmap_->CopyFromBitmap(
|
||||
&D2D1::Point2U(uint32_t(dest_point.x), uint32_t(dest_point.y)), copy_from->GetBitmap().get(),
|
||||
&D2D1::Point2U(uint32_t(dest_point.x), uint32_t(dest_point.y)), copy_from->GetBitmap().Get(),
|
||||
&D2D1::RectU(uint32_t(src_rect.GetLeft()), uint32_t(src_rect.GetTop()), uint32_t(src_rect.GetRight()),
|
||||
uint32_t(src_rect.GetBottom())));
|
||||
|
||||
ThrowIfFailed(hr, "Copy texture data failed");
|
||||
KGE_THROW_IF_FAILED(hr, "Copy texture data failed");
|
||||
}
|
||||
#else
|
||||
return; // not supported
|
||||
|
|
|
|||
|
|
@ -57,7 +57,8 @@ TextureCache::~TextureCache() {}
|
|||
|
||||
TexturePtr TextureCache::AddOrGetTexture(String const& file_path)
|
||||
{
|
||||
return CreateOrGetCache<Texture>(texture_cache_, file_path, file_path.hash());
|
||||
size_t hash = std::hash<String>()(file_path);
|
||||
return CreateOrGetCache<Texture>(texture_cache_, file_path, hash);
|
||||
}
|
||||
|
||||
TexturePtr TextureCache::AddOrGetTexture(Resource const& res)
|
||||
|
|
@ -67,7 +68,8 @@ TexturePtr TextureCache::AddOrGetTexture(Resource const& res)
|
|||
|
||||
GifImagePtr TextureCache::AddOrGetGifImage(String const& file_path)
|
||||
{
|
||||
return CreateOrGetCache<GifImage>(gif_texture_cache_, file_path, file_path.hash());
|
||||
size_t hash = std::hash<String>()(file_path);
|
||||
return CreateOrGetCache<GifImage>(gif_texture_cache_, file_path, hash);
|
||||
}
|
||||
|
||||
GifImagePtr TextureCache::AddOrGetGifImage(Resource const& res)
|
||||
|
|
@ -77,7 +79,8 @@ GifImagePtr TextureCache::AddOrGetGifImage(Resource const& res)
|
|||
|
||||
void TextureCache::RemoveTexture(String const& file_path)
|
||||
{
|
||||
RemoveCache(texture_cache_, file_path.hash());
|
||||
size_t hash = std::hash<String>()(file_path);
|
||||
RemoveCache(texture_cache_, hash);
|
||||
}
|
||||
|
||||
void TextureCache::RemoveTexture(Resource const& res)
|
||||
|
|
@ -87,7 +90,8 @@ void TextureCache::RemoveTexture(Resource const& res)
|
|||
|
||||
void TextureCache::RemoveGifImage(String const& file_path)
|
||||
{
|
||||
RemoveCache(gif_texture_cache_, file_path.hash());
|
||||
size_t hash = std::hash<String>()(file_path);
|
||||
RemoveCache(gif_texture_cache_, hash);
|
||||
}
|
||||
|
||||
void TextureCache::RemoveGifImage(Resource const& res)
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ int LocalStorage::GetInt(String const& key, int default_value) const
|
|||
float LocalStorage::GetFloat(String const& key, float default_value) const
|
||||
{
|
||||
char temp[32] = { 0 };
|
||||
String default_str = String::parse(default_value);
|
||||
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);
|
||||
}
|
||||
|
|
@ -85,7 +85,7 @@ float LocalStorage::GetFloat(String const& key, float default_value) const
|
|||
double LocalStorage::GetDouble(String const& key, double default_value) const
|
||||
{
|
||||
char temp[32] = { 0 };
|
||||
String default_str = String::parse(default_value);
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ namespace resource_cache_01
|
|||
{
|
||||
|
||||
bool LoadJsonData(ResourceCache* loader, Json const& json_data);
|
||||
bool LoadXmlData(ResourceCache* loader, const pugi::xml_node& elem);
|
||||
bool LoadXmlData(ResourceCache* loader, const XmlNode& elem);
|
||||
|
||||
} // namespace resource_cache_01
|
||||
|
||||
|
|
@ -42,7 +42,7 @@ Map<String, Function<bool(ResourceCache*, Json const&)>> load_json_funcs = {
|
|||
{ "0.1", resource_cache_01::LoadJsonData },
|
||||
};
|
||||
|
||||
Map<String, Function<bool(ResourceCache*, const pugi::xml_node&)>> load_xml_funcs = {
|
||||
Map<String, Function<bool(ResourceCache*, const XmlNode&)>> load_xml_funcs = {
|
||||
{ "latest", resource_cache_01::LoadXmlData },
|
||||
{ "0.1", resource_cache_01::LoadXmlData },
|
||||
};
|
||||
|
|
@ -127,9 +127,9 @@ bool ResourceCache::LoadFromXmlFile(String const& file_path)
|
|||
|
||||
String full_path = FileSystem::GetInstance().GetFullPathForFile(file_path);
|
||||
|
||||
pugi::xml_document doc;
|
||||
pugi::xml_parse_result result = doc.load_file(full_path.c_str(), pugi::parse_default, pugi::encoding_auto);
|
||||
XmlDocument doc;
|
||||
|
||||
auto result = doc.load_file(full_path.c_str());
|
||||
if (result)
|
||||
{
|
||||
return LoadFromXml(doc);
|
||||
|
|
@ -141,9 +141,9 @@ bool ResourceCache::LoadFromXmlFile(String const& file_path)
|
|||
}
|
||||
}
|
||||
|
||||
bool ResourceCache::LoadFromXml(const pugi::xml_document& doc)
|
||||
bool ResourceCache::LoadFromXml(const XmlDocument& doc)
|
||||
{
|
||||
if (pugi::xml_node root = doc.child("resources"))
|
||||
if (XmlNode root = doc.child("resources"))
|
||||
{
|
||||
String version;
|
||||
if (auto version_node = root.child("version"))
|
||||
|
|
@ -313,7 +313,7 @@ bool LoadJsonData(ResourceCache* loader, Json const& json_data)
|
|||
GlobalData global_data;
|
||||
if (json_data.count("path"))
|
||||
{
|
||||
global_data.path = json_data["path"];
|
||||
global_data.path = json_data["path"].get<String>();
|
||||
}
|
||||
|
||||
if (json_data.count("images"))
|
||||
|
|
@ -385,7 +385,7 @@ bool LoadJsonData(ResourceCache* loader, Json const& json_data)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool LoadXmlData(ResourceCache* loader, const pugi::xml_node& elem)
|
||||
bool LoadXmlData(ResourceCache* loader, const XmlNode& elem)
|
||||
{
|
||||
GlobalData global_data;
|
||||
if (auto path = elem.child("path"))
|
||||
|
|
|
|||
|
|
@ -22,9 +22,10 @@
|
|||
#include <kiwano/2d/Frame.h>
|
||||
#include <kiwano/2d/FrameSequence.h>
|
||||
#include <kiwano/core/Resource.h>
|
||||
#include <kiwano/core/Json.h>
|
||||
#include <kiwano/core/Xml.h>
|
||||
#include <kiwano/render/Font.h>
|
||||
#include <kiwano/render/GifImage.h>
|
||||
#include <3rd-party/pugixml/pugixml.hpp>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
|
|
@ -54,7 +55,7 @@ public:
|
|||
/// \~chinese
|
||||
/// @brief 从 XML 文档对象加载资源信息
|
||||
/// @param doc XML文档对象
|
||||
bool LoadFromXml(pugi::xml_document const& doc);
|
||||
bool LoadFromXml(XmlDocument const& doc);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取资源
|
||||
|
|
@ -69,7 +70,7 @@ public:
|
|||
template <typename _Ty>
|
||||
SmartPtr<_Ty> Get(String const& id) const
|
||||
{
|
||||
return dynamic_cast<_Ty*>(Get(id).get());
|
||||
return dynamic_cast<_Ty*>(Get(id).Get());
|
||||
}
|
||||
|
||||
/// \~chinese
|
||||
|
|
|
|||
Loading…
Reference in New Issue