Remove OuterC library

This commit is contained in:
Nomango 2020-02-15 17:32:32 +08:00
parent f1e0d59cea
commit 2c050cafba
89 changed files with 2330 additions and 6971 deletions

View File

@ -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" />

View File

@ -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>

View File

@ -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.

View File

@ -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);
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,8 +0,0 @@
// Copyright (c) 2019-2020 OuterC - Nomango
#pragma once
#include <cassert>
#include <cstdio>
#include <cwchar>
#define OC_ASSERT(EXPR) assert(EXPR)

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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;

View File

@ -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);
}
// 估算音频流大小

View File

@ -310,7 +310,7 @@ void HttpModule::DispatchResponseCallback()
if (callback)
{
callback(request.get(), response.get());
callback(request.Get(), response.Get());
}
}
}

View File

@ -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
{

View File

@ -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)

View File

@ -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

View File

@ -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;
}

View File

@ -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)
{
}
};

View File

@ -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

View File

@ -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)

View File

@ -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 获取所有名称相同的子角色

View File

@ -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;

View File

@ -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());
}

View File

@ -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_)

464
src/kiwano/core/Any.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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;
}

View File

@ -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>;

View File

@ -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));
}
};

View File

@ -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

388
src/kiwano/core/Function.h Normal file
View File

@ -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

View File

@ -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

32
src/kiwano/core/Json.h Normal file
View File

@ -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

View File

@ -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);

View File

@ -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());
}

View File

@ -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

View File

@ -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

View File

@ -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

52
src/kiwano/core/String.h Normal file
View File

@ -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

View File

@ -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;
}

View File

@ -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; ///< 毫秒

View File

@ -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>;

View File

@ -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

36
src/kiwano/core/Xml.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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_;

View File

@ -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))
{

View File

@ -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:

View File

@ -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());
}
}

View File

@ -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:

View File

@ -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());
}
}

View File

@ -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:

View File

@ -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, &currentFile_);

View File

@ -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());
}
}

View File

@ -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

View File

@ -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

View File

@ -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_;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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);
}

View File

@ -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"))

View File

@ -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