remove common & use OuterC instead
This commit is contained in:
		
							parent
							
								
									03edd40ecd
								
							
						
					
					
						commit
						b53f77af05
					
				|  | @ -15,16 +15,7 @@ | |||
|     <ClInclude Include="..\..\src\kiwano\core\Library.h" /> | ||||
|     <ClInclude Include="..\..\src\kiwano\core\win32\ComPtr.hpp" /> | ||||
|     <ClInclude Include="..\..\src\kiwano\core\win32\helper.h" /> | ||||
|     <ClInclude Include="..\..\src\kiwano\common\any.hpp" /> | ||||
|     <ClInclude Include="..\..\src\kiwano\common\basic_json.hpp" /> | ||||
|     <ClInclude Include="..\..\src\kiwano\common\function.hpp" /> | ||||
|     <ClInclude Include="..\..\src\kiwano\common\common.h" /> | ||||
|     <ClInclude Include="..\..\src\kiwano\common\intrusive_list.hpp" /> | ||||
|     <ClInclude Include="..\..\src\kiwano\common\intrusive_ptr.hpp" /> | ||||
|     <ClInclude Include="..\..\src\kiwano\common\noncopyable.hpp" /> | ||||
|     <ClInclude Include="..\..\src\kiwano\common\singleton.hpp" /> | ||||
|     <ClInclude Include="..\..\src\kiwano\common\string.hpp" /> | ||||
|     <ClInclude Include="..\..\src\kiwano\common\vector.hpp" /> | ||||
|     <ClInclude Include="..\..\src\kiwano\kiwano.h" /> | ||||
|     <ClInclude Include="..\..\src\kiwano\config.h" /> | ||||
|     <ClInclude Include="..\..\src\kiwano\macros.h" /> | ||||
|  |  | |||
|  | @ -150,30 +150,6 @@ | |||
|     <ClInclude Include="..\..\src\kiwano\2d\FrameSequence.h"> | ||||
|       <Filter>2d</Filter> | ||||
|     </ClInclude> | ||||
|     <ClInclude Include="..\..\src\kiwano\common\basic_json.hpp"> | ||||
|       <Filter>common</Filter> | ||||
|     </ClInclude> | ||||
|     <ClInclude Include="..\..\src\kiwano\common\function.hpp"> | ||||
|       <Filter>common</Filter> | ||||
|     </ClInclude> | ||||
|     <ClInclude Include="..\..\src\kiwano\common\intrusive_list.hpp"> | ||||
|       <Filter>common</Filter> | ||||
|     </ClInclude> | ||||
|     <ClInclude Include="..\..\src\kiwano\common\intrusive_ptr.hpp"> | ||||
|       <Filter>common</Filter> | ||||
|     </ClInclude> | ||||
|     <ClInclude Include="..\..\src\kiwano\common\noncopyable.hpp"> | ||||
|       <Filter>common</Filter> | ||||
|     </ClInclude> | ||||
|     <ClInclude Include="..\..\src\kiwano\common\singleton.hpp"> | ||||
|       <Filter>common</Filter> | ||||
|     </ClInclude> | ||||
|     <ClInclude Include="..\..\src\kiwano\common\string.hpp"> | ||||
|       <Filter>common</Filter> | ||||
|     </ClInclude> | ||||
|     <ClInclude Include="..\..\src\kiwano\common\vector.hpp"> | ||||
|       <Filter>common</Filter> | ||||
|     </ClInclude> | ||||
|     <ClInclude Include="..\..\src\kiwano\common\common.h"> | ||||
|       <Filter>common</Filter> | ||||
|     </ClInclude> | ||||
|  | @ -276,9 +252,6 @@ | |||
|     <ClInclude Include="..\..\src\kiwano\utils\LocalStorage.h"> | ||||
|       <Filter>utils</Filter> | ||||
|     </ClInclude> | ||||
|     <ClInclude Include="..\..\src\kiwano\common\any.hpp"> | ||||
|       <Filter>common</Filter> | ||||
|     </ClInclude> | ||||
|     <ClInclude Include="..\..\src\kiwano\utils\UserData.h"> | ||||
|       <Filter>utils</Filter> | ||||
|     </ClInclude> | ||||
|  |  | |||
|  | @ -0,0 +1,21 @@ | |||
| MIT License | ||||
| 
 | ||||
| Copyright (c) 2019 Nomango | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | ||||
| in the Software without restriction, including without limitation the rights | ||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
| copies of the Software, and to permit persons to whom the Software is | ||||
| furnished to do so, subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| SOFTWARE. | ||||
|  | @ -1,32 +1,11 @@ | |||
| // Copyright (c) 2018-2019 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.
 | ||||
| // Copyright (c) 2019-2020 OuterC - Nomango
 | ||||
| 
 | ||||
| #pragma once | ||||
| #include <typeinfo> | ||||
| #include <type_traits> | ||||
| #include <exception> | ||||
| 
 | ||||
| namespace kiwano | ||||
| { | ||||
| 
 | ||||
| namespace common | ||||
| namespace oc | ||||
| { | ||||
| 
 | ||||
| class bad_any_cast : public std::exception | ||||
|  | @ -133,7 +112,7 @@ public: | |||
| 	template <typename _Ty> | ||||
| 	const _Ty* cast_pointer() const noexcept | ||||
| 	{ | ||||
| 		static_assert(!std::is_void<_Ty>::value, "kiwano::any cannot contain void"); | ||||
| 		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))) | ||||
|  | @ -519,14 +498,14 @@ _Ty any_cast(any&& a) | |||
| 	return static_cast<_Ty>(std::move(*ptr)); | ||||
| } | ||||
| 
 | ||||
| }  // namespace common
 | ||||
| 
 | ||||
| }  // namespace kiwano
 | ||||
| }  // namespace oc
 | ||||
| 
 | ||||
| namespace std | ||||
| { | ||||
| 	inline void swap(kiwano::common::any& lhs, kiwano::common::any& rhs) noexcept | ||||
| 	{ | ||||
| 		lhs.swap(rhs); | ||||
| 	} | ||||
| 
 | ||||
| inline void swap(oc::any& lhs, oc::any& rhs) noexcept | ||||
| { | ||||
| 	lhs.swap(rhs); | ||||
| } | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,169 @@ | |||
| // 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
 | ||||
|  | @ -0,0 +1,168 @@ | |||
| // 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 (static_cast<_Ty*>(ptr_)->*func_)(::std::forward<_Args>(args)...); | ||||
| 	} | ||||
| 
 | ||||
| 	static inline callable<_Ret, _Args...>* make(void* ptr, _FuncType func) | ||||
| 	{ | ||||
| 		return new (::std::nothrow) proxy_mem_callable<_Ty, _Ret, _Args...>(ptr, func); | ||||
| 	} | ||||
| 
 | ||||
| protected: | ||||
| 	proxy_mem_callable(void* ptr, _FuncType func) | ||||
| 		: ptr_(ptr) | ||||
| 		, func_(func) | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| protected: | ||||
| 	void* 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 (static_cast<_Ty*>(ptr_)->*func_)(::std::forward<_Args>(args)...); | ||||
| 	} | ||||
| 
 | ||||
| 	static inline callable<_Ret, _Args...>* make(void* ptr, _FuncType func) | ||||
| 	{ | ||||
| 		return new (::std::nothrow) proxy_const_mem_callable<_Ty, _Ret, _Args...>(ptr, func); | ||||
| 	} | ||||
| 
 | ||||
| protected: | ||||
| 	proxy_const_mem_callable(void* ptr, _FuncType func) | ||||
| 		: ptr_(ptr) | ||||
| 		, func_(func) | ||||
| 	{ | ||||
| 	} | ||||
| 
 | ||||
| protected: | ||||
| 	void* ptr_; | ||||
| 	_FuncType func_; | ||||
| }; | ||||
| 
 | ||||
| }  // namespace __function_detail
 | ||||
| }  // namespace oc
 | ||||
|  | @ -0,0 +1,254 @@ | |||
| // 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_type			= _PTy; | ||||
| 	using const_pointer_type	= const _PTy; | ||||
| 
 | ||||
| 	intrusive_list_item()					: prev_(nullptr), next_(nullptr) {} | ||||
| 	intrusive_list_item(pointer_type rhs)	: prev_(nullptr), next_(nullptr) { if (rhs) { prev_ = rhs->prev_; next_ = rhs->next_; } } | ||||
| 
 | ||||
| 	const_pointer_type	prev_item() const	{ return prev_; } | ||||
| 	pointer_type		prev_item()			{ return prev_; } | ||||
| 	const_pointer_type	next_item() const	{ return next_; } | ||||
| 	pointer_type		next_item()			{ return next_; } | ||||
| 
 | ||||
| private: | ||||
| 	pointer_type prev_; | ||||
| 	pointer_type next_; | ||||
| 
 | ||||
| 	friend class intrusive_list<_Ty>; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| template <typename _Ty, typename _PTy> | ||||
| class intrusive_list | ||||
| { | ||||
| public: | ||||
| 	using pointer_type			= _PTy; | ||||
| 	using const_pointer_type	= const _PTy; | ||||
| 
 | ||||
| 	intrusive_list()							: first_(), last_() {} | ||||
| 	~intrusive_list()							{ clear(); } | ||||
| 
 | ||||
| 	const_pointer_type	first_item() const		{ return first_; } | ||||
| 	pointer_type		first_item()			{ return first_; } | ||||
| 	const_pointer_type	last_item() const		{ return last_; } | ||||
| 	pointer_type		last_item()				{ return last_; } | ||||
| 
 | ||||
| 	inline bool empty() const | ||||
| 	{ | ||||
| 		return first_ == nullptr; | ||||
| 	} | ||||
| 
 | ||||
| 	void push_back(pointer_type 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_type 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_type child, pointer_type 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_type child, pointer_type 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_type 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_type p = first_; | ||||
| 		while (p) | ||||
| 		{ | ||||
| 			pointer_type 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_type p = first_; | ||||
| 		pointer_type 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 pointer_type			= _PTy; | ||||
| 		using const_pointer_type	= const _PTy; | ||||
| 
 | ||||
| 		inline iterator_impl(pointer_type ptr = nullptr, bool is_end = false)	: base_(ptr), is_end_(is_end) {} | ||||
| 
 | ||||
| 		inline pointer_type		operator*() const								{ OC_ASSERT(base_ && !is_end_); return base_; } | ||||
| 		inline iterator_impl&	operator++()									{ OC_ASSERT(base_ && !is_end_); pointer_type 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_type(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_type base_; | ||||
| 	}; | ||||
| 
 | ||||
| 	using iterator					= iterator_impl<pointer_type>; | ||||
| 	using const_iterator			= iterator_impl<const pointer_type>; | ||||
| 	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_type				front()			{ if (empty()) throw std::out_of_range("front() called on empty intrusive_list"); return first_item(); } | ||||
| 	inline const_pointer_type		front() const	{ if (empty()) throw std::out_of_range("front() called on empty intrusive_list"); return first_item(); } | ||||
| 	inline pointer_type				back()			{ if (empty()) throw std::out_of_range("back() called on empty intrusive_list"); return last_item(); } | ||||
| 	inline const_pointer_type		back() const	{ if (empty()) throw std::out_of_range("back() called on empty intrusive_list"); return last_item(); } | ||||
| 
 | ||||
| private: | ||||
| 	pointer_type first_; | ||||
| 	pointer_type last_; | ||||
| }; | ||||
| 
 | ||||
| }  // namespace oc
 | ||||
|  | @ -0,0 +1,201 @@ | |||
| // 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
 | ||||
|  | @ -0,0 +1,50 @@ | |||
| // 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); | ||||
| } | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,929 @@ | |||
| // 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 | ||||
|  | @ -0,0 +1,47 @@ | |||
| // 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
 | ||||
|  | @ -0,0 +1,112 @@ | |||
| // 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
 | ||||
|  | @ -0,0 +1,377 @@ | |||
| // 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
 | ||||
|  | @ -0,0 +1,76 @@ | |||
| // 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
 | ||||
|  | @ -0,0 +1,567 @@ | |||
| // 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(L"true", token_type::LITERAL_TRUE); | ||||
| 		case 'f': | ||||
| 			return scan_literal(L"false", token_type::LITERAL_FALSE); | ||||
| 		case 'n': | ||||
| 			return scan_literal(L"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
 | ||||
|  | @ -0,0 +1,421 @@ | |||
| // 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
 | ||||
|  | @ -0,0 +1,240 @@ | |||
| // 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
 | ||||
|  | @ -0,0 +1,79 @@ | |||
| // 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
 | ||||
|  | @ -0,0 +1,8 @@ | |||
| // Copyright (c) 2019-2020 OuterC - Nomango
 | ||||
| 
 | ||||
| #pragma once | ||||
| #include <cassert> | ||||
| #include <cstdio> | ||||
| #include <cwchar> | ||||
| 
 | ||||
| #define OC_ASSERT(EXPR) assert(EXPR) | ||||
|  | @ -0,0 +1,19 @@ | |||
| // 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
 | ||||
|  | @ -0,0 +1,13 @@ | |||
| // 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" | ||||
|  | @ -0,0 +1,50 @@ | |||
| // Copyright (c) 2019-2020 OuterC - Nomango
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| // Class that will implement the singleton mode must use the macro in its delare file
 | ||||
| 
 | ||||
| #ifndef OC_DECLARE_SINGLETON | ||||
| #define OC_DECLARE_SINGLETON( CLASS ) \ | ||||
| 	friend ::oc::singleton< CLASS >; | ||||
| #endif | ||||
| 
 | ||||
| namespace oc | ||||
| { | ||||
| 
 | ||||
| template <typename _Ty> | ||||
| struct singleton | ||||
| { | ||||
| protected: | ||||
| 	singleton() = default; | ||||
| 	singleton(const singleton&) = delete; | ||||
| 	singleton& operator=(const singleton&) = delete; | ||||
| 
 | ||||
| private: | ||||
| 	struct object_creator | ||||
| 	{ | ||||
| 		object_creator() | ||||
| 		{ | ||||
| 			(void)singleton<_Ty>::instance(); | ||||
| 		} | ||||
| 
 | ||||
| 		inline void dummy() const {} | ||||
| 	}; | ||||
| 	static object_creator creator_; | ||||
| 
 | ||||
| public: | ||||
| 	using object_type = _Ty; | ||||
| 
 | ||||
| 	static inline object_type& instance() | ||||
| 	{ | ||||
| 		static object_type instance; | ||||
| 		creator_.dummy(); | ||||
| 		return instance; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| template <typename _Ty> | ||||
| typename singleton<_Ty>::object_creator singleton<_Ty>::creator_; | ||||
| 
 | ||||
| 
 | ||||
| }  // namespace oc
 | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -1,52 +1,18 @@ | |||
| // 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.
 | ||||
| // Copyright (c) 2019-2020 OuterC - Nomango
 | ||||
| 
 | ||||
| #pragma once | ||||
| #include <memory> | ||||
| #include <type_traits> | ||||
| #include <stdexcept> | ||||
| #include "vector/details.h" | ||||
| 
 | ||||
| namespace kiwano | ||||
| namespace oc | ||||
| { | ||||
| namespace common | ||||
| { | ||||
| 
 | ||||
| 
 | ||||
| //
 | ||||
| // vector_memory_manager<> with memory operations
 | ||||
| //
 | ||||
| namespace __vector_details | ||||
| { | ||||
| 	template<typename _Ty, typename _Alloc, bool _IsClassType = std::is_class<_Ty>::value> | ||||
| 	struct vector_memory_manager; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| //
 | ||||
| // vector<>
 | ||||
| // Lightweight std::vector<>-like class
 | ||||
| //
 | ||||
| template< | ||||
| 	typename _Ty, | ||||
| 	typename _Alloc = std::allocator<_Ty>, | ||||
| 	typename _Manager = __vector_details::vector_memory_manager<_Ty, _Alloc>> | ||||
| template <typename _Ty, typename _Alloc = std::allocator<_Ty>> | ||||
| class vector | ||||
| { | ||||
| public: | ||||
|  | @ -59,7 +25,7 @@ public: | |||
| 	using reverse_iterator			= std::reverse_iterator<iterator>; | ||||
| 	using const_reverse_iterator	= std::reverse_iterator<const_iterator>; | ||||
| 	using allocator_type			= typename _Alloc; | ||||
| 	using manager					= typename _Manager; | ||||
| 	using manager					= typename __vector_details::vector_memory_manager<_Ty, _Alloc>; | ||||
| 	using initializer_list			= std::initializer_list<value_type>; | ||||
| 
 | ||||
| public: | ||||
|  | @ -74,11 +40,11 @@ public: | |||
| 	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_data(begin(), src.cbegin(), size_); } return (*this); } | ||||
| 	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::copy_data(begin(), count, val); } else clear(); return (*this); } | ||||
| 	inline vector&		assign(size_type count, const _Ty& val)				{ if (count > 0) { resize(count); manager::copy(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); } | ||||
| 
 | ||||
|  | @ -140,8 +106,8 @@ protected: | |||
| 	_Ty*		data_; | ||||
| }; | ||||
| 
 | ||||
| template<typename _Ty, typename _Alloc, typename _Manager> | ||||
| void vector<_Ty, _Alloc, _Manager>::resize(size_type new_size, const _Ty& val) | ||||
| template<typename _Ty, typename _Alloc> | ||||
| void vector<_Ty, _Alloc>::resize(size_type new_size, const _Ty& val) | ||||
| { | ||||
| 	if (new_size > size_) | ||||
| 	{ | ||||
|  | @ -158,8 +124,8 @@ void vector<_Ty, _Alloc, _Manager>::resize(size_type new_size, const _Ty& val) | |||
| 	size_ = new_size; | ||||
| } | ||||
| 
 | ||||
| template<typename _Ty, typename _Alloc, typename _Manager> | ||||
| void vector<_Ty, _Alloc, _Manager>::reserve(size_type new_capacity) | ||||
| template<typename _Ty, typename _Alloc> | ||||
| void vector<_Ty, _Alloc>::reserve(size_type new_capacity) | ||||
| { | ||||
| 	if (new_capacity <= capacity_) | ||||
| 		return; | ||||
|  | @ -167,8 +133,7 @@ void vector<_Ty, _Alloc, _Manager>::reserve(size_type new_capacity) | |||
| 	auto new_data = manager::allocate(new_capacity); | ||||
| 	if (data_) | ||||
| 	{ | ||||
| 		manager::construct(new_data, size_/* only construct needed size */); | ||||
| 		manager::copy_data(new_data, data_, size_); | ||||
| 		manager::construct_n(new_data, data_, size_/* only construct needed size */); | ||||
| 		/* destroy old memory, but not resize */ | ||||
| 		destroy(); | ||||
| 	} | ||||
|  | @ -176,9 +141,9 @@ void vector<_Ty, _Alloc, _Manager>::reserve(size_type new_capacity) | |||
| 	capacity_ = new_capacity; | ||||
| } | ||||
| 
 | ||||
| template<typename _Ty, typename _Alloc, typename _Manager> | ||||
| typename vector<_Ty, _Alloc, _Manager>::iterator | ||||
| 	vector<_Ty, _Alloc, _Manager>::erase(const_iterator first, const_iterator last) | ||||
| 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; | ||||
|  | @ -187,15 +152,15 @@ typename vector<_Ty, _Alloc, _Manager>::iterator | |||
| 	{ | ||||
| 		check_offset(off); | ||||
| 
 | ||||
| 		manager::move_data(begin() + off, begin() + off + count, size_ - off - count); | ||||
| 		manager::move(begin() + off, begin() + off + count, size_ - off - count); | ||||
| 		resize(size_ - count);  // do destruction
 | ||||
| 	} | ||||
| 	return begin() + off; | ||||
| } | ||||
| 
 | ||||
| template<typename _Ty, typename _Alloc, typename _Manager> | ||||
| typename vector<_Ty, _Alloc, _Manager>::iterator | ||||
| 	vector<_Ty, _Alloc, _Manager>::insert(const_iterator where, const _Ty& v) | ||||
| 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; | ||||
|  | @ -203,86 +168,9 @@ typename vector<_Ty, _Alloc, _Manager>::iterator | |||
| 	check_offset(off); | ||||
| 		 | ||||
| 	resize(size_ + 1); | ||||
| 	manager::move_data(insert_at + 1, insert_at, size_ - off - 1); | ||||
| 	manager::move(insert_at + 1, insert_at, size_ - off - 1); | ||||
| 	data_[off] = v; | ||||
| 	return begin() + off; | ||||
| } | ||||
| 
 | ||||
| namespace __vector_details | ||||
| { | ||||
| 	//
 | ||||
| 	// vector_memory_manager for common type
 | ||||
| 	//
 | ||||
| 	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 copy_data(value_type* dest, const value_type* src, size_type count) { if (src == dest) return; ::memcpy(dest, src, size_type(count) * sizeof(value_type)); } | ||||
| 		static void copy_data(value_type* dest, size_type count, const value_type& val) { ::memset(dest, int(val), size_type(count) * sizeof(value_type)); } | ||||
| 		static void move_data(value_type* dest, const value_type* src, size_type count) { if (src == dest) return; ::memmove(dest, src, size_type(count) * sizeof(value_type)); } | ||||
| 
 | ||||
| 		static value_type* allocate(size_type count)									{ return get_allocator().allocate(count); } | ||||
| 		static void deallocate(value_type*& ptr, size_type count) { if (ptr)			{ get_allocator().deallocate(ptr, count); ptr = nullptr; } } | ||||
| 
 | ||||
| 		static void construct(value_type* ptr, size_type count)							{ } | ||||
| 		static void construct(value_type* ptr, size_type count, const value_type& val)	{ while (count) { --count; *(ptr + count) = val; } } | ||||
| 		static void destroy(value_type* ptr, size_type count)							{ } | ||||
| 
 | ||||
| 	private: | ||||
| 		static 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, true> | ||||
| 	{ | ||||
| 		using value_type		= _Ty; | ||||
| 		using size_type			= size_t; | ||||
| 		using allocator_type	= typename _Alloc; | ||||
| 
 | ||||
| 		static void copy_data(value_type* dest, const value_type* src, size_type count) { if (src == dest) return; while (count--) (*dest++) = (*src++); } | ||||
| 		static void copy_data(value_type* dest, size_type count, const value_type& val) { while (count--) (*dest++) = val; } | ||||
| 		static void move_data(value_type* dest, const value_type* src, size_type count) | ||||
| 		{ | ||||
| 			if (src == dest) return; | ||||
| 			if (dest > src && dest < src + count) | ||||
| 			{ | ||||
| 				src = src + count - 1; | ||||
| 				dest = dest + count - 1; | ||||
| 				while (count--) | ||||
| 					(*dest--) = (*src--); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				while (count--) | ||||
| 					(*dest++) = (*src++); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		static value_type* allocate(size_type count)									{ return get_allocator().allocate(count); } | ||||
| 		static void deallocate(value_type*& ptr, size_type count)						{ if (ptr) { get_allocator().deallocate(ptr, count); ptr = nullptr; } } | ||||
| 
 | ||||
| 		static void construct(value_type* ptr, size_type count)							{ construct(ptr, count, value_type()); } | ||||
| 		static void construct(value_type* ptr, size_type count, const value_type& val)	{ while (count) get_allocator().construct(ptr + (--count), val); } | ||||
| 		static void destroy(value_type* ptr, size_type count)							{ while (count) get_allocator().destroy(ptr + (--count)); } | ||||
| 
 | ||||
| 	private: | ||||
| 		static allocator_type& get_allocator() | ||||
| 		{ | ||||
| 			static allocator_type allocator_; | ||||
| 			return allocator_; | ||||
| 		} | ||||
| 	}; | ||||
| } | ||||
| 
 | ||||
| }  // namespace common
 | ||||
| }  // namespace kiwano
 | ||||
| }  // namespace oc
 | ||||
|  | @ -0,0 +1,79 @@ | |||
| // 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			copy(value_type* const dest, const size_type count, const value_type& val)			{ for (size_type i = 0; i < count; ++i) std::memcpy(&dest[i], &val, sizeof(value_type)); } | ||||
| 	static void			copy_n(value_type* const dest, const value_type* src, const size_type count)		{ if (src == dest) return; std::memcpy(dest, src, count * sizeof(value_type)); } | ||||
| 	static void			move(value_type* const dest, const value_type* src, const size_type count)			{ if (src == dest) return; std::memmove(dest, src, count * sizeof(value_type)); } | ||||
| 
 | ||||
| 	static void			construct(value_type* const ptr, const size_type count, const value_type& val)		{ copy(ptr, count, val); } | ||||
| 	static void			construct_n(value_type* const ptr, const value_type* src, const size_type count)	{ copy_n(ptr, src, count); } | ||||
| 	static void			destroy(value_type* const ptr, const size_type count)								{ } | ||||
| 
 | ||||
| 	static value_type*	allocate(const size_type count)														{ return get_allocator().allocate(count); } | ||||
| 	static void			deallocate(value_type*& ptr, const size_type count)									{ if (ptr) { get_allocator().deallocate(ptr, count); ptr = nullptr; } } | ||||
| 
 | ||||
| private: | ||||
| 	static 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			copy(value_type* const dest, const size_type count, const value_type& val)			{ std::fill_n(dest, count, val); } | ||||
| 	static void			copy_n(value_type* const dest, const value_type* src, const size_type count)		{ if (src == dest) return; std::copy_n(src, count, dest); } | ||||
| 	static void			move(value_type* const dest, const value_type* src, const size_type count)			{ if (src == dest) return; if (dest > src && dest < src + count) std::copy_backward(src, src + count, dest); else copy_n(dest, src, count); } | ||||
| 
 | ||||
| 	static void			construct(value_type* const ptr, const size_type count, const value_type& val)		{ for (size_type 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, const size_type count)	{ for (size_type i = 0; i < count; ++i) get_allocator().construct(std::addressof(ptr[i]), src[i]); } | ||||
| 	static void			destroy(value_type* const ptr, const size_type count)								{ for (size_type i = 0; i < count; ++i) get_allocator().destroy(std::addressof(ptr[i])); } | ||||
| 
 | ||||
| 	static value_type*	allocate(const size_type count)														{ return get_allocator().allocate(count); } | ||||
| 	static void			deallocate(value_type*& ptr, const size_type count)									{ if (ptr) { get_allocator().deallocate(ptr, count); ptr = nullptr; } } | ||||
| 
 | ||||
| private: | ||||
| 	static allocator_type& get_allocator() | ||||
| 	{ | ||||
| 		static allocator_type allocator_; | ||||
| 		return allocator_; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| }  // namespace __vector_details
 | ||||
| }  // namespace oc
 | ||||
|  | @ -19,7 +19,7 @@ | |||
| // THE SOFTWARE.
 | ||||
| 
 | ||||
| #pragma once | ||||
| #include <kiwano/common/singleton.hpp> | ||||
| #include <kiwano/common/common.h> | ||||
| #include <kiwano/core/Component.h> | ||||
| #include <kiwano/core/win32/ComPtr.hpp> | ||||
| #include <kiwano-audio/Transcoder.h> | ||||
|  | @ -33,7 +33,7 @@ namespace kiwano | |||
| 			: public Singleton<AudioEngine> | ||||
| 			, public ComponentBase | ||||
| 		{ | ||||
| 			KGE_DECLARE_SINGLETON(AudioEngine); | ||||
| 			OC_DECLARE_SINGLETON(AudioEngine); | ||||
| 
 | ||||
| 		public: | ||||
| 			// 开启设备
 | ||||
|  |  | |||
|  | @ -54,9 +54,9 @@ namespace kiwano | |||
| 
 | ||||
| 		bool Sound::Load(String const& file_path) | ||||
| 		{ | ||||
| 			if (!FileSystem::GetInstance()->IsFileExists(file_path)) | ||||
| 			if (!FileSystem::instance().IsFileExists(file_path)) | ||||
| 			{ | ||||
| 				KGE_WARNING_LOG(L"Media file '%s' not found", file_path.c_str()); | ||||
| 				KGE_WARN(L"Media file '%s' not found", file_path.c_str()); | ||||
| 				return false; | ||||
| 			} | ||||
| 
 | ||||
|  | @ -65,22 +65,22 @@ namespace kiwano | |||
| 				Close(); | ||||
| 			} | ||||
| 
 | ||||
| 			String full_path = FileSystem::GetInstance()->GetFullPathForFile(file_path); | ||||
| 			String full_path = FileSystem::instance().GetFullPathForFile(file_path); | ||||
| 
 | ||||
| 			HRESULT hr = transcoder_.LoadMediaFile(full_path); | ||||
| 
 | ||||
| 			if (FAILED(hr)) | ||||
| 			{ | ||||
| 				KGE_ERROR_LOG(L"Load media file failed with HRESULT of %08X", hr); | ||||
| 				KGE_ERROR(L"Load media file failed with HRESULT of %08X", hr); | ||||
| 				return false; | ||||
| 			} | ||||
| 
 | ||||
| 			hr = AudioEngine::GetInstance()->CreateVoice(&voice_, transcoder_.GetBuffer()); | ||||
| 			hr = AudioEngine::instance().CreateVoice(&voice_, transcoder_.GetBuffer()); | ||||
| 			if (FAILED(hr)) | ||||
| 			{ | ||||
| 				Close(); | ||||
| 
 | ||||
| 				KGE_ERROR_LOG(L"Create source voice failed with HRESULT of %08X", hr); | ||||
| 				KGE_ERROR(L"Create source voice failed with HRESULT of %08X", hr); | ||||
| 				return false; | ||||
| 			} | ||||
| 
 | ||||
|  | @ -99,16 +99,16 @@ namespace kiwano | |||
| 
 | ||||
| 			if (FAILED(hr)) | ||||
| 			{ | ||||
| 				KGE_ERROR_LOG(L"Load media resource failed with HRESULT of %08X", hr); | ||||
| 				KGE_ERROR(L"Load media resource failed with HRESULT of %08X", hr); | ||||
| 				return false; | ||||
| 			} | ||||
| 
 | ||||
| 			hr = AudioEngine::GetInstance()->CreateVoice(&voice_, transcoder_.GetBuffer()); | ||||
| 			hr = AudioEngine::instance().CreateVoice(&voice_, transcoder_.GetBuffer()); | ||||
| 			if (FAILED(hr)) | ||||
| 			{ | ||||
| 				Close(); | ||||
| 
 | ||||
| 				KGE_ERROR_LOG(L"Create source voice failed with HRESULT of %08X", hr); | ||||
| 				KGE_ERROR(L"Create source voice failed with HRESULT of %08X", hr); | ||||
| 				return false; | ||||
| 			} | ||||
| 
 | ||||
|  | @ -120,7 +120,7 @@ namespace kiwano | |||
| 		{ | ||||
| 			if (!opened_) | ||||
| 			{ | ||||
| 				KGE_ERROR_LOG(L"Sound must be opened first!"); | ||||
| 				KGE_ERROR(L"Sound must be opened first!"); | ||||
| 				return; | ||||
| 			} | ||||
| 
 | ||||
|  | @ -151,7 +151,7 @@ namespace kiwano | |||
| 
 | ||||
| 			if (FAILED(hr)) | ||||
| 			{ | ||||
| 				KGE_ERROR_LOG(L"Submitting source buffer failed with HRESULT of %08X", hr); | ||||
| 				KGE_ERROR(L"Submitting source buffer failed with HRESULT of %08X", hr); | ||||
| 			} | ||||
| 
 | ||||
| 			playing_ = SUCCEEDED(hr); | ||||
|  |  | |||
|  | @ -19,7 +19,6 @@ | |||
| // THE SOFTWARE.
 | ||||
| 
 | ||||
| #pragma once | ||||
| #include <kiwano/common/intrusive_ptr.hpp> | ||||
| #include <kiwano/core/ObjectBase.h> | ||||
| #include <kiwano/core/Resource.h> | ||||
| #include <kiwano-audio/Transcoder.h> | ||||
|  |  | |||
|  | @ -19,7 +19,6 @@ | |||
| // THE SOFTWARE.
 | ||||
| 
 | ||||
| #pragma once | ||||
| #include <kiwano/common/intrusive_ptr.hpp> | ||||
| #include <kiwano/core/ObjectBase.h> | ||||
| #include <kiwano-audio/Sound.h> | ||||
| 
 | ||||
|  |  | |||
|  | @ -23,7 +23,7 @@ | |||
| #endif | ||||
| 
 | ||||
| #include <kiwano/macros.h> | ||||
| #include <kiwano/common/string.hpp> | ||||
| #include <kiwano/common/common.h> | ||||
| #include <kiwano/core/Resource.h> | ||||
| #include <kiwano/core/Logger.h> | ||||
| #include <kiwano/core/win32/ComPtr.hpp> | ||||
|  | @ -108,7 +108,7 @@ namespace kiwano | |||
| 
 | ||||
| 			if (stream == nullptr) | ||||
| 			{ | ||||
| 				KGE_ERROR_LOG(L"SHCreateMemStream failed"); | ||||
| 				KGE_ERROR(L"SHCreateMemStream failed"); | ||||
| 				return E_OUTOFMEMORY; | ||||
| 			} | ||||
| 
 | ||||
|  | @ -225,7 +225,7 @@ namespace kiwano | |||
| 
 | ||||
| 				if (data == nullptr) | ||||
| 				{ | ||||
| 					KGE_ERROR_LOG(L"Low memory"); | ||||
| 					KGE_ERROR(L"Low memory"); | ||||
| 					hr = E_OUTOFMEMORY; | ||||
| 				} | ||||
| 				else | ||||
|  |  | |||
|  | @ -52,7 +52,7 @@ namespace kiwano | |||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					KGE_ERROR_LOG(L"Load xaudio2.dll failed"); | ||||
| 					KGE_ERROR(L"Load xaudio2.dll failed"); | ||||
| 					throw std::runtime_error("Load xaudio2.dll failed"); | ||||
| 				} | ||||
| 			} | ||||
|  |  | |||
|  | @ -1,8 +1,6 @@ | |||
| // Copyright (C) 2019 Nomango
 | ||||
| 
 | ||||
| #include <kiwano/common/common.h> | ||||
| #include <kiwano/common/Function.hpp> | ||||
| #include <kiwano/common/intrusive_ptr.hpp> | ||||
| #include <kiwano/platform/Window.h> | ||||
| #include <kiwano/platform/Input.h> | ||||
| #include <kiwano/renderer/Renderer.h> | ||||
|  | @ -45,9 +43,9 @@ namespace kiwano | |||
| 			//ImGui::StyleColorsClassic();
 | ||||
| 
 | ||||
| 			// Setup Platform/Renderer bindings
 | ||||
| 			Init(Window::GetInstance()->GetHandle()); | ||||
| 			Init(Window::instance().GetHandle()); | ||||
| 
 | ||||
| 			target_window_ = Renderer::GetInstance()->GetTargetWindow(); | ||||
| 			target_window_ = Renderer::instance().GetTargetWindow(); | ||||
| 		} | ||||
| 
 | ||||
| 		void ImGuiModule::DestroyComponent() | ||||
|  | @ -64,9 +62,9 @@ namespace kiwano | |||
| 			io.DeltaTime = dt.Seconds(); | ||||
| 
 | ||||
| 			// Read keyboard modifiers inputs
 | ||||
| 			io.KeyCtrl = Input::GetInstance()->IsDown(KeyCode::Ctrl); | ||||
| 			io.KeyShift = Input::GetInstance()->IsDown(KeyCode::Shift); | ||||
| 			io.KeyAlt = Input::GetInstance()->IsDown(KeyCode::Alt); | ||||
| 			io.KeyCtrl = Input::instance().IsDown(KeyCode::Ctrl); | ||||
| 			io.KeyShift = Input::instance().IsDown(KeyCode::Shift); | ||||
| 			io.KeyAlt = Input::instance().IsDown(KeyCode::Alt); | ||||
| 			io.KeySuper = false; | ||||
| 			// io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the WndProc handler below.
 | ||||
| 
 | ||||
|  | @ -106,7 +104,7 @@ namespace kiwano | |||
| 			io.KeyMap[ImGuiKey_Y] = KeyCode::Y; | ||||
| 			io.KeyMap[ImGuiKey_Z] = KeyCode::Z; | ||||
| 
 | ||||
| 			ImGui_Impl_Init(Renderer::GetInstance()); | ||||
| 			ImGui_Impl_Init(&Renderer::instance()); | ||||
| 		} | ||||
| 
 | ||||
| 		void ImGuiModule::BeforeRender() | ||||
|  | @ -213,7 +211,7 @@ namespace kiwano | |||
| 			KGE_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built!"); | ||||
| 
 | ||||
| 			// Setup display size (every frame to accommodate for window resizing)
 | ||||
| 			Size display_size = Renderer::GetInstance()->GetOutputSize(); | ||||
| 			Size display_size = Renderer::instance().GetOutputSize(); | ||||
| 			io.DisplaySize = ImVec2(display_size.x, display_size.y); | ||||
| 
 | ||||
| 			ImGui::NewFrame(); | ||||
|  | @ -238,7 +236,7 @@ namespace kiwano | |||
| 				::SetCursorPos(pos.x, pos.y); | ||||
| 			} | ||||
| 
 | ||||
| 			Point pos = Input::GetInstance()->GetMousePos(); | ||||
| 			Point pos = Input::instance().GetMousePos(); | ||||
| 			io.MousePos = ImVec2(pos.x, pos.y); | ||||
| 		} | ||||
| 
 | ||||
|  | @ -260,7 +258,7 @@ namespace kiwano | |||
| 			case ImGuiMouseCursor_Hand:         cursor = CursorType::Hand; break; | ||||
| 			} | ||||
| 
 | ||||
| 			Window::GetInstance()->SetCursor(cursor); | ||||
| 			Window::instance().SetCursor(cursor); | ||||
| 		} | ||||
| 		void ImGuiModule::UpdateGamepads() | ||||
| 		{ | ||||
|  |  | |||
|  | @ -20,7 +20,7 @@ | |||
| 
 | ||||
| #pragma once | ||||
| #include <kiwano/core/Component.h> | ||||
| #include <kiwano/common/singleton.hpp> | ||||
| #include <kiwano/common/common.h> | ||||
| 
 | ||||
| namespace kiwano | ||||
| { | ||||
|  | @ -32,7 +32,7 @@ namespace kiwano | |||
| 			, public UpdateComponent | ||||
| 			, public EventComponent | ||||
| 		{ | ||||
| 			KGE_DECLARE_SINGLETON(ImGuiModule); | ||||
| 			OC_DECLARE_SINGLETON(ImGuiModule); | ||||
| 
 | ||||
| 		private: | ||||
| 			void Init(HWND hwnd); | ||||
|  |  | |||
|  | @ -36,7 +36,7 @@ namespace | |||
| 
 | ||||
| 	uint32_t write_data(void* buffer, uint32_t size, uint32_t nmemb, void* userp) | ||||
| 	{ | ||||
| 		common::string* recv_buffer = (common::string*)userp; | ||||
| 		oc::string* recv_buffer = (oc::string*)userp; | ||||
| 		uint32_t total = size * nmemb; | ||||
| 
 | ||||
| 		// add data to the end of recv_buffer
 | ||||
|  | @ -46,10 +46,10 @@ namespace | |||
| 		return total; | ||||
| 	} | ||||
| 
 | ||||
| 	common::string convert_to_utf8(common::wstring const& str) | ||||
| 	oc::string convert_to_utf8(oc::wstring const& str) | ||||
| 	{ | ||||
| 		std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8_conv; | ||||
| 		common::string result; | ||||
| 		oc::string result; | ||||
| 
 | ||||
| 		try | ||||
| 		{ | ||||
|  | @ -63,10 +63,10 @@ namespace | |||
| 		return result; | ||||
| 	} | ||||
| 
 | ||||
| 	common::wstring convert_from_utf8(common::string const& str) | ||||
| 	oc::wstring convert_from_utf8(oc::string const& str) | ||||
| 	{ | ||||
| 		kiwano::string_convert<std::codecvt_utf8<wchar_t>> utf8_conv; | ||||
| 		common::wstring result; | ||||
| 		oc::string_convert<std::codecvt_utf8<wchar_t>> utf8_conv; | ||||
| 		oc::wstring result; | ||||
| 
 | ||||
| 		try | ||||
| 		{ | ||||
|  | @ -104,7 +104,7 @@ namespace | |||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		bool Init(HttpClient* client, Vector<common::string> const& headers, common::string const& url, common::string* response_data, common::string* response_header, char* error_buffer) | ||||
| 		bool Init(HttpClient* client, Vector<oc::string> const& headers, oc::string const& url, oc::string* response_data, oc::string* response_header, char* error_buffer) | ||||
| 		{ | ||||
| 			if (!SetOption(CURLOPT_ERRORBUFFER, error_buffer)) | ||||
| 				return false; | ||||
|  | @ -170,11 +170,11 @@ namespace | |||
| 	public: | ||||
| 		static inline bool GetRequest( | ||||
| 			HttpClient* client, | ||||
| 			Vector<common::string> const& headers, | ||||
| 			common::string const& url, | ||||
| 			Vector<oc::string> const& headers, | ||||
| 			oc::string const& url, | ||||
| 			long* response_code, | ||||
| 			common::string* response_data, | ||||
| 			common::string* response_header, | ||||
| 			oc::string* response_data, | ||||
| 			oc::string* response_header, | ||||
| 			char* error_buffer) | ||||
| 		{ | ||||
| 			Curl curl; | ||||
|  | @ -185,12 +185,12 @@ namespace | |||
| 
 | ||||
| 		static inline bool PostRequest( | ||||
| 			HttpClient* client, | ||||
| 			Vector<common::string> const& headers, | ||||
| 			common::string const& url, | ||||
| 			common::string const& request_data, | ||||
| 			Vector<oc::string> const& headers, | ||||
| 			oc::string const& url, | ||||
| 			oc::string const& request_data, | ||||
| 			long* response_code, | ||||
| 			common::string* response_data, | ||||
| 			common::string* response_header, | ||||
| 			oc::string* response_data, | ||||
| 			oc::string* response_header, | ||||
| 			char* error_buffer) | ||||
| 		{ | ||||
| 			Curl curl; | ||||
|  | @ -203,12 +203,12 @@ namespace | |||
| 
 | ||||
| 		static inline bool PutRequest( | ||||
| 			HttpClient* client, | ||||
| 			Vector<common::string> const& headers, | ||||
| 			common::string const& url, | ||||
| 			common::string const& request_data, | ||||
| 			Vector<oc::string> const& headers, | ||||
| 			oc::string const& url, | ||||
| 			oc::string const& request_data, | ||||
| 			long* response_code, | ||||
| 			common::string* response_data, | ||||
| 			common::string* response_header, | ||||
| 			oc::string* response_data, | ||||
| 			oc::string* response_header, | ||||
| 			char* error_buffer) | ||||
| 		{ | ||||
| 			Curl curl; | ||||
|  | @ -221,11 +221,11 @@ namespace | |||
| 
 | ||||
| 		static inline bool DeleteRequest( | ||||
| 			HttpClient* client, | ||||
| 			Vector<common::string> const& headers, | ||||
| 			common::string const& url, | ||||
| 			Vector<oc::string> const& headers, | ||||
| 			oc::string const& url, | ||||
| 			long* response_code, | ||||
| 			common::string* response_data, | ||||
| 			common::string* response_header, | ||||
| 			oc::string* response_data, | ||||
| 			oc::string* response_header, | ||||
| 			char* error_buffer) | ||||
| 		{ | ||||
| 			Curl curl; | ||||
|  | @ -307,13 +307,13 @@ namespace kiwano | |||
| 			bool ok = false; | ||||
| 			long response_code = 0; | ||||
| 			char error_message[256] = { 0 }; | ||||
| 			common::string response_header; | ||||
| 			common::string response_data; | ||||
| 			oc::string response_header; | ||||
| 			oc::string response_data; | ||||
| 
 | ||||
| 			common::string url = convert_to_utf8(request->GetUrl()); | ||||
| 			common::string data = convert_to_utf8(request->GetData()); | ||||
| 			oc::string url = convert_to_utf8(request->GetUrl()); | ||||
| 			oc::string data = convert_to_utf8(request->GetData()); | ||||
| 
 | ||||
| 			Vector<common::string> headers; | ||||
| 			Vector<oc::string> headers; | ||||
| 			headers.reserve(request->GetHeaders().size()); | ||||
| 			for (const auto& pair : request->GetHeaders()) | ||||
| 			{ | ||||
|  | @ -335,17 +335,17 @@ namespace kiwano | |||
| 				ok = Curl::DeleteRequest(this, headers, url, &response_code, &response_data, &response_header, error_message); | ||||
| 				break; | ||||
| 			default: | ||||
| 				KGE_ERROR_LOG(L"HttpClient: unknown request type, only GET, POST, PUT or DELETE is supported"); | ||||
| 				KGE_ERROR(L"HttpClient: unknown request type, only GET, POST, PUT or DELETE is supported"); | ||||
| 				return; | ||||
| 			} | ||||
| 
 | ||||
| 			response->SetResponseCode(response_code); | ||||
| 			response->SetHeader(string_to_wide(response_header)); | ||||
| 			response->SetHeader(oc::string_to_wide(response_header)); | ||||
| 			response->SetData(convert_from_utf8(response_data)); | ||||
| 			if (!ok) | ||||
| 			{ | ||||
| 				response->SetSucceed(false); | ||||
| 				response->SetError(string_to_wide(error_message)); | ||||
| 				response->SetError(oc::string_to_wide(error_message)); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
|  |  | |||
|  | @ -20,7 +20,6 @@ | |||
| 
 | ||||
| #pragma once | ||||
| #include <kiwano/common/common.h> | ||||
| #include <kiwano/common/singleton.hpp> | ||||
| #include <kiwano/core/Component.h> | ||||
| #include <mutex> | ||||
| #include <condition_variable> | ||||
|  | @ -33,7 +32,7 @@ namespace kiwano | |||
| 			: public Singleton<HttpClient> | ||||
| 			, public ComponentBase | ||||
| 		{ | ||||
| 			KGE_DECLARE_SINGLETON(HttpClient); | ||||
| 			OC_DECLARE_SINGLETON(HttpClient); | ||||
| 
 | ||||
| 		public: | ||||
| 			void Send(HttpRequestPtr request); | ||||
|  |  | |||
|  | @ -19,8 +19,7 @@ | |||
| // THE SOFTWARE.
 | ||||
| 
 | ||||
| #pragma once | ||||
| #include <kiwano/common/function.hpp> | ||||
| #include <kiwano/common/basic_json.hpp> | ||||
| #include <kiwano/common/common.h> | ||||
| #include <kiwano/core/ObjectBase.h> | ||||
| #include <kiwano/core/SmartPtr.hpp> | ||||
| 
 | ||||
|  |  | |||
|  | @ -481,7 +481,7 @@ namespace kiwano | |||
| 			{ | ||||
| 				if (parent == child) | ||||
| 				{ | ||||
| 					KGE_ERROR_LOG(L"A actor cannot be its own parent"); | ||||
| 					KGE_ERROR(L"A actor cannot be its own parent"); | ||||
| 					return; | ||||
| 				} | ||||
| 			} | ||||
|  |  | |||
|  | @ -31,7 +31,7 @@ namespace kiwano | |||
| 		, stroke_color_(Color::White) | ||||
| 		, stroke_style_(StrokeStyle::Miter) | ||||
| 	{ | ||||
| 		Renderer::GetInstance()->CreateTextureRenderTarget(rt_); | ||||
| 		Renderer::instance().CreateTextureRenderTarget(rt_); | ||||
| 	} | ||||
| 
 | ||||
| 	Canvas::~Canvas() | ||||
|  |  | |||
|  | @ -109,9 +109,9 @@ namespace kiwano | |||
| 		} | ||||
| #endif | ||||
| 
 | ||||
| 		ss << "Render: " << Renderer::GetInstance()->GetStatus().duration.Milliseconds() << "ms" << std::endl; | ||||
| 		ss << "Render: " << Renderer::instance().GetStatus().duration.Milliseconds() << "ms" << std::endl; | ||||
| 
 | ||||
| 		ss << "Primitives / sec: " << std::fixed << Renderer::GetInstance()->GetStatus().primitives * frame_time_.size() << std::endl; | ||||
| 		ss << "Primitives / sec: " << std::fixed << Renderer::instance().GetStatus().primitives * frame_time_.size() << std::endl; | ||||
| 
 | ||||
| 		ss << "Memory: "; | ||||
| 		{ | ||||
|  |  | |||
|  | @ -44,7 +44,7 @@ namespace kiwano | |||
| 
 | ||||
| 	bool Frame::Load(String const& file_path) | ||||
| 	{ | ||||
| 		Texture texture = TextureCache::GetInstance()->AddOrGetTexture(file_path); | ||||
| 		Texture texture = TextureCache::instance().AddOrGetTexture(file_path); | ||||
| 		if (texture.IsValid()) | ||||
| 		{ | ||||
| 			SetTexture(texture); | ||||
|  | @ -55,7 +55,7 @@ namespace kiwano | |||
| 
 | ||||
| 	bool Frame::Load(Resource const& res) | ||||
| 	{ | ||||
| 		Texture texture = TextureCache::GetInstance()->AddOrGetTexture(res); | ||||
| 		Texture texture = TextureCache::instance().AddOrGetTexture(res); | ||||
| 		if (texture.IsValid()) | ||||
| 		{ | ||||
| 			SetTexture(texture); | ||||
|  |  | |||
|  | @ -51,13 +51,13 @@ namespace kiwano | |||
| 
 | ||||
| 	bool GifSprite::Load(String const& file_path) | ||||
| 	{ | ||||
| 		GifImage texture = TextureCache::GetInstance()->AddOrGetGifImage(file_path); | ||||
| 		GifImage texture = TextureCache::instance().AddOrGetGifImage(file_path); | ||||
| 		return Load(texture); | ||||
| 	} | ||||
| 
 | ||||
| 	bool GifSprite::Load(Resource const& res) | ||||
| 	{ | ||||
| 		GifImage texture = TextureCache::GetInstance()->AddOrGetGifImage(res); | ||||
| 		GifImage texture = TextureCache::instance().AddOrGetGifImage(res); | ||||
| 		return Load(texture); | ||||
| 	} | ||||
| 
 | ||||
|  | @ -75,7 +75,7 @@ namespace kiwano | |||
| 
 | ||||
| 			if (!frame_rt_.IsValid()) | ||||
| 			{ | ||||
| 				Renderer::GetInstance()->CreateTextureRenderTarget(frame_rt_); | ||||
| 				Renderer::instance().CreateTextureRenderTarget(frame_rt_); | ||||
| 			} | ||||
| 
 | ||||
| 			if (gif_.GetFramesCount() > 0) | ||||
|  | @ -168,7 +168,7 @@ namespace kiwano | |||
| 
 | ||||
| 	void GifSprite::OverlayNextFrame() | ||||
| 	{ | ||||
| 		Renderer::GetInstance()->CreateGifImageFrame(frame_, gif_, next_index_); | ||||
| 		Renderer::instance().CreateGifImageFrame(frame_, gif_, next_index_); | ||||
| 		 | ||||
| 		if (frame_.disposal_type == GifImage::DisposalType::Previous) | ||||
| 		{ | ||||
|  |  | |||
|  | @ -29,7 +29,7 @@ namespace kiwano | |||
| 		SetStage(this); | ||||
| 
 | ||||
| 		SetAnchor(Vec2{ 0, 0 }); | ||||
| 		SetSize(Renderer::GetInstance()->GetOutputSize()); | ||||
| 		SetSize(Renderer::instance().GetOutputSize()); | ||||
| 	} | ||||
| 
 | ||||
| 	Stage::~Stage() | ||||
|  |  | |||
|  | @ -60,7 +60,7 @@ namespace kiwano | |||
| 
 | ||||
| 		out_stage_ = prev; | ||||
| 		in_stage_ = next; | ||||
| 		window_size_ = Renderer::GetInstance()->GetOutputSize(); | ||||
| 		window_size_ = Renderer::instance().GetOutputSize(); | ||||
| 
 | ||||
| 		if (in_stage_) | ||||
| 		{ | ||||
|  |  | |||
|  | @ -145,7 +145,7 @@ namespace kiwano | |||
| 		// 获取该动作的倒转
 | ||||
| 		virtual ActionPtr Reverse() const override | ||||
| 		{ | ||||
| 			KGE_ERROR_LOG(L"Reverse() not supported in ActionMoveTo"); | ||||
| 			KGE_ERROR(L"Reverse() not supported in ActionMoveTo"); | ||||
| 			return nullptr; | ||||
| 		} | ||||
| 
 | ||||
|  | @ -209,7 +209,7 @@ namespace kiwano | |||
| 		// 获取该动作的倒转
 | ||||
| 		virtual ActionPtr Reverse() const override | ||||
| 		{ | ||||
| 			KGE_ERROR_LOG(L"Reverse() not supported in ActionJumpTo"); | ||||
| 			KGE_ERROR(L"Reverse() not supported in ActionJumpTo"); | ||||
| 			return nullptr; | ||||
| 		} | ||||
| 
 | ||||
|  | @ -282,7 +282,7 @@ namespace kiwano | |||
| 		// 获取该动作的倒转
 | ||||
| 		virtual ActionPtr Reverse() const override | ||||
| 		{ | ||||
| 			KGE_ERROR_LOG(L"Reverse() not supported in ActionScaleTo"); | ||||
| 			KGE_ERROR(L"Reverse() not supported in ActionScaleTo"); | ||||
| 			return nullptr; | ||||
| 		} | ||||
| 
 | ||||
|  | @ -312,7 +312,7 @@ namespace kiwano | |||
| 		// 获取该动作的倒转
 | ||||
| 		virtual ActionPtr Reverse() const override | ||||
| 		{ | ||||
| 			KGE_ERROR_LOG(L"Reverse() not supported in ActionFadeTo"); | ||||
| 			KGE_ERROR(L"Reverse() not supported in ActionFadeTo"); | ||||
| 			return nullptr; | ||||
| 		} | ||||
| 
 | ||||
|  | @ -399,7 +399,7 @@ namespace kiwano | |||
| 		// 获取该动作的倒转
 | ||||
| 		virtual ActionPtr Reverse() const override | ||||
| 		{ | ||||
| 			KGE_ERROR_LOG(L"Reverse() not supported in ActionRotateTo"); | ||||
| 			KGE_ERROR(L"Reverse() not supported in ActionRotateTo"); | ||||
| 			return nullptr; | ||||
| 		} | ||||
| 
 | ||||
|  | @ -430,7 +430,7 @@ namespace kiwano | |||
| 		// 获取该动作的倒转
 | ||||
| 		ActionPtr Reverse() const override | ||||
| 		{ | ||||
| 			KGE_ERROR_LOG(L"Reverse() not supported in ActionCustom"); | ||||
| 			KGE_ERROR(L"Reverse() not supported in ActionCustom"); | ||||
| 			return nullptr; | ||||
| 		} | ||||
| 
 | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -28,24 +28,17 @@ | |||
| #include <unordered_map> | ||||
| #include <sstream> | ||||
| 
 | ||||
| #include <kiwano/common/vector.hpp> | ||||
| #include <kiwano/common/string.hpp> | ||||
| #include <kiwano/common/any.hpp> | ||||
| #include <kiwano/common/intrusive_list.hpp> | ||||
| #include <kiwano/common/intrusive_ptr.hpp> | ||||
| #include <kiwano/common/noncopyable.hpp> | ||||
| #include <kiwano/common/singleton.hpp> | ||||
| #include <kiwano/common/function.hpp> | ||||
| #include <kiwano/common/basic_json.hpp> | ||||
| #include <3rd-party/OuterC/oc/oc.h> | ||||
| #include <kiwano/macros.h> | ||||
| 
 | ||||
| namespace kiwano | ||||
| { | ||||
| 	using String = kiwano::common::wstring; | ||||
| 	using String = oc::wstring; | ||||
| 
 | ||||
| 	using StringStream = std::wstringstream; | ||||
| 
 | ||||
| 	template <typename _Ty, typename... _Args> | ||||
| 	using Vector = kiwano::common::vector<_Ty, _Args...>; | ||||
| 	using Vector = oc::vector<_Ty, _Args...>; | ||||
| 
 | ||||
| 	template <typename _Ty, typename... _Args> | ||||
| 	using List = std::list<_Ty, _Args...>; | ||||
|  | @ -72,37 +65,38 @@ namespace kiwano | |||
| 	using UnorderedMap = std::unordered_map<_Kty, _Ty, _Args...>; | ||||
| 
 | ||||
| 	template <typename _FuncTy> | ||||
| 	using Function = kiwano::common::function<_FuncTy>; | ||||
| 	using Function = oc::function<_FuncTy>; | ||||
| 
 | ||||
| 	using Any = kiwano::common::any; | ||||
| 	using Any = oc::any; | ||||
| 
 | ||||
| 	using Json = kiwano::common::basic_json<kiwano::Map, kiwano::Vector, kiwano::String, | ||||
| 		int, double, bool, std::allocator>; | ||||
| 	using Json = oc::basic_json<Map, Vector, String, int, double, bool, std::allocator>; | ||||
| 
 | ||||
| 	template <typename _Ty> | ||||
| 	using Singleton = common::singleton<_Ty>; | ||||
| 	using Singleton = oc::singleton<_Ty>; | ||||
| 
 | ||||
| 	template <typename _Ty> | ||||
| 	using IntrusiveList = common::intrusive_list<_Ty>; | ||||
| 	using IntrusiveList = oc::intrusive_list<_Ty>; | ||||
| 
 | ||||
| 	template <typename _Ty> | ||||
| 	using IntrusiveListItem = common::intrusive_list_item<_Ty>; | ||||
| } | ||||
| 	using IntrusiveListItem = oc::intrusive_list_item<_Ty>; | ||||
| 
 | ||||
| namespace std | ||||
| { | ||||
| 	template<> | ||||
| 	struct hash<::kiwano::Json> | ||||
| 	template <typename _Ty, typename _RefProxyTy> | ||||
| 	using IntrusivePtr = oc::intrusive_ptr<_Ty, _RefProxyTy>; | ||||
| 
 | ||||
| 	using Noncopyable = oc::noncopyable; | ||||
| 
 | ||||
| 
 | ||||
| 	// Closure
 | ||||
| 
 | ||||
| 	template<typename _Ty, typename _Uty, typename _Ret, typename... _Args> | ||||
| 	inline Function<_Ret(_Args...)> Closure(_Uty* ptr, _Ret(_Ty::* func)(_Args...)) | ||||
| 	{ | ||||
| 		size_t operator()(const ::kiwano::Json& json) const | ||||
| 		{ | ||||
| 			return hash<::kiwano::Json::string_type>{}(json.dump()); | ||||
| 		} | ||||
| 	}; | ||||
| 		return oc::closure(ptr, func); | ||||
| 	} | ||||
| 
 | ||||
| 	template<> | ||||
| 	inline void swap<::kiwano::Json>(::kiwano::Json& lhs, ::kiwano::Json& rhs) noexcept | ||||
| 	template<typename _Ty, typename _Uty, typename _Ret, typename... _Args> | ||||
| 	inline Function<_Ret(_Args...)> Closure(_Uty* ptr, _Ret(_Ty::* func)(_Args...) const) | ||||
| 	{ | ||||
| 		lhs.swap(rhs); | ||||
| 		return oc::closure(ptr, func); | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -1,355 +0,0 @@ | |||
| // Copyright (c) 2016-2018 Kiwano - Nomango
 | ||||
| // 
 | ||||
| // Permission is hereby granted, free of charge, to any person obtaining a copy
 | ||||
| // of this software and associated documentation files (the "Software"), to deal
 | ||||
| // in the Software without restriction, including without limitation the rights
 | ||||
| // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | ||||
| // copies of the Software, and to permit persons to whom the Software is
 | ||||
| // furnished to do so, subject to the following conditions:
 | ||||
| // 
 | ||||
| // The above copyright notice and this permission notice shall be included in
 | ||||
| // all copies or substantial portions of the Software.
 | ||||
| // 
 | ||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | ||||
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | ||||
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | ||||
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | ||||
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | ||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | ||||
| // THE SOFTWARE.
 | ||||
| 
 | ||||
| #pragma once | ||||
| #include <stdexcept> | ||||
| #include <type_traits> | ||||
| 
 | ||||
| namespace kiwano | ||||
| { | ||||
| 
 | ||||
| namespace common | ||||
| { | ||||
| //
 | ||||
| // function is a light weight ::std::function<>-like class
 | ||||
| //
 | ||||
| 
 | ||||
| namespace __function_detail | ||||
| { | ||||
| 	//
 | ||||
| 	// is_callable
 | ||||
| 	//
 | ||||
| 
 | ||||
| 	namespace __callable_detail | ||||
| 	{ | ||||
| 		template <typename _Ty, typename _Ret, typename... _Args> | ||||
| 		struct helper | ||||
| 		{ | ||||
| 			template <typename _Uty> static int test(...); | ||||
| 
 | ||||
| 			template <typename _Uty, _Ret(_Uty::*)(_Args...)> struct class_mem; | ||||
| 			template <typename _Uty> static char test(class_mem<_Uty, &_Uty::operator()>*); | ||||
| 
 | ||||
| 			template <typename _Uty, _Ret(_Uty::*)(_Args...) const> struct class_const_mem; | ||||
| 			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<__callable_detail::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 (static_cast<_Ty*>(ptr_)->*func_)(::std::forward<_Args>(args)...); | ||||
| 		} | ||||
| 
 | ||||
| 		static inline callable<_Ret, _Args...>* make(void* ptr, _FuncType func) | ||||
| 		{ | ||||
| 			return new (::std::nothrow) proxy_mem_callable<_Ty, _Ret, _Args...>(ptr, func); | ||||
| 		} | ||||
| 
 | ||||
| 	protected: | ||||
| 		proxy_mem_callable(void* ptr, _FuncType func) | ||||
| 			: ptr_(ptr) | ||||
| 			, func_(func) | ||||
| 		{ | ||||
| 		} | ||||
| 
 | ||||
| 	protected: | ||||
| 		void* 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 (static_cast<_Ty*>(ptr_)->*func_)(::std::forward<_Args>(args)...); | ||||
| 		} | ||||
| 
 | ||||
| 		static inline callable<_Ret, _Args...>* make(void* ptr, _FuncType func) | ||||
| 		{ | ||||
| 			return new (::std::nothrow) proxy_const_mem_callable<_Ty, _Ret, _Args...>(ptr, func); | ||||
| 		} | ||||
| 
 | ||||
| 	protected: | ||||
| 		proxy_const_mem_callable(void* ptr, _FuncType func) | ||||
| 			: ptr_(ptr) | ||||
| 			, func_(func) | ||||
| 		{ | ||||
| 		} | ||||
| 
 | ||||
| 	protected: | ||||
| 		void* ptr_; | ||||
| 		_FuncType func_; | ||||
| 	}; | ||||
| } | ||||
| 
 | ||||
| //
 | ||||
| // exceptions
 | ||||
| //
 | ||||
| class bad_function_call : public ::std::exception | ||||
| { | ||||
| public: | ||||
| 	bad_function_call() {} | ||||
| 
 | ||||
| 	virtual const char* what() const override | ||||
| 	{ | ||||
| 		return "bad function call"; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| //
 | ||||
| // function 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_(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_; | ||||
| }; | ||||
| 
 | ||||
| }  // namespace common
 | ||||
| 
 | ||||
| }  // namespace kiwano
 | ||||
| 
 | ||||
| namespace kiwano | ||||
| { | ||||
| 	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 common::function<_Ret(_Args...)> Closure(_Uty* ptr, _Ret(_Ty::* func)(_Args...)) | ||||
| 	{ | ||||
| 		return common::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 common::function<_Ret(_Args...)> Closure(_Uty* ptr, _Ret(_Ty::* func)(_Args...) const) | ||||
| 	{ | ||||
| 		return common::function<_Ret(_Args...)>(ptr, func); | ||||
| 	} | ||||
| } | ||||
|  | @ -1,315 +0,0 @@ | |||
| // Copyright (c) 2016-2018 Kiwano - Nomango
 | ||||
| // 
 | ||||
| // Permission is hereby granted, free of charge, to any person obtaining a copy
 | ||||
| // of this software and associated documentation files (the "Software"), to deal
 | ||||
| // in the Software without restriction, including without limitation the rights
 | ||||
| // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | ||||
| // copies of the Software, and to permit persons to whom the Software is
 | ||||
| // furnished to do so, subject to the following conditions:
 | ||||
| // 
 | ||||
| // The above copyright notice and this permission notice shall be included in
 | ||||
| // all copies or substantial portions of the Software.
 | ||||
| // 
 | ||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | ||||
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | ||||
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | ||||
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | ||||
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | ||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | ||||
| // THE SOFTWARE.
 | ||||
| 
 | ||||
| #pragma once | ||||
| #include <kiwano/macros.h> | ||||
| 
 | ||||
| // #define KGE_DEBUG_ENABLE_LIST_CHECK
 | ||||
| 
 | ||||
| #ifdef KGE_DEBUG_ENABLE_LIST_CHECK | ||||
| #	define KGE_DEBUG_CHECK_LIST(list_ptr) list_ptr->check_list() | ||||
| #else | ||||
| #	define KGE_DEBUG_CHECK_LIST __noop | ||||
| #endif | ||||
| 
 | ||||
| namespace kiwano | ||||
| { | ||||
| 
 | ||||
| namespace common | ||||
| { | ||||
| 
 | ||||
| template <typename _Ty> | ||||
| class intrusive_list; | ||||
| 
 | ||||
| template <typename _Ty> | ||||
| class intrusive_list_item | ||||
| { | ||||
| public: | ||||
| 	using value_type		= _Ty; | ||||
| 	using reference			= _Ty&; | ||||
| 	using const_reference	= const _Ty&; | ||||
| 
 | ||||
| 	intrusive_list_item()				: prev_(), next_() {} | ||||
| 	intrusive_list_item(_Ty const& rhs)	: prev_(rhs->prev_), next_(rhs->next_) {} | ||||
| 
 | ||||
| 	const_reference	prev_item() const	{ return prev_; } | ||||
| 	reference		prev_item()			{ return prev_; } | ||||
| 	const_reference	next_item() const	{ return next_; } | ||||
| 	reference		next_item()			{ return next_; } | ||||
| 
 | ||||
| private: | ||||
| 	_Ty prev_; | ||||
| 	_Ty next_; | ||||
| 
 | ||||
| 	template <typename U> | ||||
| 	friend class intrusive_list; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| template <typename _Ty> | ||||
| class intrusive_list | ||||
| { | ||||
| public: | ||||
| 	using value_type		= _Ty; | ||||
| 	using reference			= value_type&; | ||||
| 	using const_reference	= const value_type&; | ||||
| 
 | ||||
| 	intrusive_list()						: first_(), last_() {} | ||||
| 	~intrusive_list()						{ clear(); } | ||||
| 
 | ||||
| 	const_reference	first_item() const		{ return first_; } | ||||
| 	reference		first_item()			{ return first_; } | ||||
| 	const_reference	last_item() const		{ return last_; } | ||||
| 	reference		last_item()				{ return last_; } | ||||
| 	bool			empty() const			{ return !first_; } | ||||
| 
 | ||||
| 	void push_back(value_type 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; | ||||
| 
 | ||||
| 		KGE_DEBUG_CHECK_LIST(this); | ||||
| 	} | ||||
| 
 | ||||
| 	void push_front(value_type 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; | ||||
| 
 | ||||
| 		KGE_DEBUG_CHECK_LIST(this); | ||||
| 	} | ||||
| 
 | ||||
| 	void insert_before(value_type child, value_type 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; | ||||
| 
 | ||||
| 		KGE_DEBUG_CHECK_LIST(this); | ||||
| 	} | ||||
| 
 | ||||
| 	void insert_after(value_type child, value_type 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; | ||||
| 
 | ||||
| 		KGE_DEBUG_CHECK_LIST(this); | ||||
| 	} | ||||
| 
 | ||||
| 	void remove(value_type child) | ||||
| 	{ | ||||
| #ifdef KGE_DEBUG_ENABLE_LIST_CHECK | ||||
| 		_Ty tmp = first_; | ||||
| 		while (tmp != child) | ||||
| 		{ | ||||
| 			KGE_ASSERT((tmp != last_) && "The actor to be removed is not in this list"); | ||||
| 			tmp = tmp->next_; | ||||
| 		} | ||||
| #endif | ||||
| 
 | ||||
| 		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; | ||||
| 
 | ||||
| 		KGE_DEBUG_CHECK_LIST(this); | ||||
| 	} | ||||
| 
 | ||||
| 	void clear() | ||||
| 	{ | ||||
| 		_Ty p = first_; | ||||
| 		while (p) | ||||
| 		{ | ||||
| 			_Ty tmp = p; | ||||
| 			p = p->next_; | ||||
| 			if (tmp) | ||||
| 			{ | ||||
| 				tmp->next_ = nullptr; | ||||
| 				tmp->prev_ = nullptr; | ||||
| 			} | ||||
| 		} | ||||
| 		first_ = nullptr; | ||||
| 		last_ = nullptr; | ||||
| 	} | ||||
| 
 | ||||
| #ifdef KGE_DEBUG_ENABLE_LIST_CHECK | ||||
| 
 | ||||
| private: | ||||
| 	void check_list() | ||||
| 	{ | ||||
| 		if (!first_) | ||||
| 			return; | ||||
| 
 | ||||
| 		int pos = 0; | ||||
| 		_Ty p = first_; | ||||
| 		_Ty tmp = p; | ||||
| 		do | ||||
| 		{ | ||||
| 			tmp = p; | ||||
| 			p = p->next_; | ||||
| 			++pos; | ||||
| 
 | ||||
| 			if (p) | ||||
| 			{ | ||||
| 				KGE_ASSERT(p->prev_ == tmp && "Check list failed"); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				KGE_ASSERT(tmp == last_ && "Check list failed"); | ||||
| 			} | ||||
| 		} while (p); | ||||
| 	} | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| private: | ||||
| 	// Iterator
 | ||||
| 	template <typename _Ty> | ||||
| 	struct iterator_impl | ||||
| 	{ | ||||
| 		using iterator_category	= std::bidirectional_iterator_tag; | ||||
| 		using value_type		= _Ty; | ||||
| 		using reference			= _Ty&; | ||||
| 		using difference_type	= ptrdiff_t; | ||||
| 
 | ||||
| 		// disable warning 4996
 | ||||
| 		using _Unchecked_type = _Ty; | ||||
| 
 | ||||
| 		inline iterator_impl(value_type core = nullptr, bool is_end = false)	: base_(core), is_end_(is_end) {} | ||||
| 
 | ||||
| 		inline _Ty				operator*() const								{ KGE_ASSERT(base_); return static_cast<_Ty>(const_cast<reference>(base_)); } | ||||
| 		inline iterator_impl&	operator++()									{ KGE_ASSERT(base_ && !is_end_); value_type 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--()									{ KGE_ASSERT(base_); if (is_end_) is_end_ = false; else base_ = value_type(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_; | ||||
| 		value_type base_; | ||||
| 	}; | ||||
| 
 | ||||
| public: | ||||
| 	using reference					= value_type&; | ||||
| 	using const_reference			= const value_type&; | ||||
| 	using iterator					= iterator_impl<value_type>; | ||||
| 	using const_iterator			= iterator_impl<const value_type>; | ||||
| 	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 reference				front()			{ if (empty()) throw std::out_of_range("front() called on empty intrusive_list"); return first_item(); } | ||||
| 	inline const_reference			front() const	{ if (empty()) throw std::out_of_range("front() called on empty intrusive_list"); return first_item(); } | ||||
| 	inline reference				back()			{ if (empty()) throw std::out_of_range("back() called on empty intrusive_list"); return last_item(); } | ||||
| 	inline const_reference			back() const	{ if (empty()) throw std::out_of_range("back() called on empty intrusive_list"); return last_item(); } | ||||
| 
 | ||||
| private: | ||||
| 	value_type first_; | ||||
| 	value_type last_; | ||||
| }; | ||||
| 
 | ||||
| }  // namespace common
 | ||||
| 
 | ||||
| }  // namespace kiwano
 | ||||
| 
 | ||||
| #undef KGE_DEBUG_CHECK_LIST | ||||
| #undef KGE_DEBUG_ENABLE_LIST_CHECK | ||||
|  | @ -1,151 +0,0 @@ | |||
| // Copyright (c) 2016-2018 Kiwano - 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 <kiwano/macros.h> | ||||
| #include <utility> | ||||
| #include <type_traits> | ||||
| 
 | ||||
| namespace kiwano | ||||
| { | ||||
| 
 | ||||
| namespace common | ||||
| { | ||||
| 
 | ||||
| template <typename _Ty, typename _ManagerTy> | ||||
| 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 manager_type			= _ManagerTy; | ||||
| 
 | ||||
| 	intrusive_ptr() noexcept												: ptr_(nullptr)		{} | ||||
| 	intrusive_ptr(std::nullptr_t) noexcept									: ptr_(nullptr)		{} | ||||
| 	intrusive_ptr(pointer_type p)											: ptr_(p)			{ typename manager_type::AddRef(ptr_); } | ||||
| 	intrusive_ptr(const intrusive_ptr& other)								: ptr_(other.ptr_)	{ typename manager_type::AddRef(ptr_); } | ||||
| 	intrusive_ptr(intrusive_ptr&& other) noexcept							: ptr_(nullptr)		{ swap(other); } | ||||
| 	~intrusive_ptr()														{ reset(); } | ||||
| 
 | ||||
| 	template <typename _UTy> | ||||
| 	intrusive_ptr(const intrusive_ptr<_UTy, manager_type>& other)			{ ptr_ = const_cast<pointer_type>(dynamic_cast<const_pointer_type>(other.get())); typename manager_type::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)			{ typename manager_type::Release(ptr_); ptr_ = nullptr; } | ||||
| 	inline void					swap(intrusive_ptr& 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 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)					{ reset(); return *this; } | ||||
| 
 | ||||
| private: | ||||
| 	pointer_type ptr_; | ||||
| }; | ||||
| 
 | ||||
| template <class _Ty, class _UTy, class manager_type> | ||||
| inline bool operator==(intrusive_ptr<_Ty, manager_type> const& lhs, intrusive_ptr<_UTy, manager_type> const& rhs) noexcept | ||||
| { | ||||
| 	return lhs.get() == rhs.get(); | ||||
| } | ||||
| 
 | ||||
| template <class _Ty, class manager_type> | ||||
| inline bool operator==(intrusive_ptr<_Ty, manager_type> const& lhs, _Ty* rhs) noexcept | ||||
| { | ||||
| 	return lhs.get() == rhs; | ||||
| } | ||||
| 
 | ||||
| template <class _Ty, class manager_type> | ||||
| inline bool operator==(_Ty* lhs, intrusive_ptr<_Ty, manager_type> const& rhs) noexcept | ||||
| { | ||||
| 	return lhs == rhs.get(); | ||||
| } | ||||
| 
 | ||||
| template <class _Ty, class manager_type> | ||||
| inline bool operator==(intrusive_ptr<_Ty, manager_type> const& lhs, std::nullptr_t) noexcept | ||||
| { | ||||
| 	return !static_cast<bool>(lhs); | ||||
| } | ||||
| 
 | ||||
| template <class _Ty, class manager_type> | ||||
| inline bool operator==(std::nullptr_t, intrusive_ptr<_Ty, manager_type> const& rhs) noexcept | ||||
| { | ||||
| 	return !static_cast<bool>(rhs); | ||||
| } | ||||
| 
 | ||||
| template <class _Ty, class _UTy, class manager_type> | ||||
| inline bool operator!=(intrusive_ptr<_Ty, manager_type> const& lhs, intrusive_ptr<_UTy, manager_type> const& rhs) noexcept | ||||
| { | ||||
| 	return !(lhs == rhs); | ||||
| } | ||||
| 
 | ||||
| template <class _Ty, class manager_type> | ||||
| inline bool operator!=(intrusive_ptr<_Ty, manager_type> const& lhs, _Ty* rhs) noexcept | ||||
| { | ||||
| 	return lhs.get() != rhs; | ||||
| } | ||||
| 
 | ||||
| template <class _Ty, class manager_type> | ||||
| inline bool operator!=(_Ty* lhs, intrusive_ptr<_Ty, manager_type> const& rhs) noexcept | ||||
| { | ||||
| 	return lhs != rhs.get(); | ||||
| } | ||||
| 
 | ||||
| template <class _Ty, class manager_type> | ||||
| inline bool operator!=(intrusive_ptr<_Ty, manager_type> const& lhs, std::nullptr_t) noexcept | ||||
| { | ||||
| 	return static_cast<bool>(lhs); | ||||
| } | ||||
| 
 | ||||
| template <class _Ty, class manager_type> | ||||
| inline bool operator!=(std::nullptr_t, intrusive_ptr<_Ty, manager_type> const& rhs) noexcept | ||||
| { | ||||
| 	return static_cast<bool>(rhs); | ||||
| } | ||||
| 
 | ||||
| template <class _Ty, class _UTy, class manager_type> | ||||
| inline bool operator<(intrusive_ptr<_Ty, manager_type> const& lhs, intrusive_ptr<_UTy, manager_type> 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 manager_type> | ||||
| inline void swap(intrusive_ptr<_Ty, manager_type>& lhs, intrusive_ptr<_Ty, manager_type>& rhs) noexcept | ||||
| { | ||||
| 	lhs.swap(rhs); | ||||
| } | ||||
| 
 | ||||
| }  // namespace common
 | ||||
| 
 | ||||
| }  // namespace kiwano
 | ||||
|  | @ -1,40 +0,0 @@ | |||
| // Copyright (c) 2016-2018 Kiwano - Nomango
 | ||||
| // 
 | ||||
| // Permission is hereby granted, free of charge, to any person obtaining a copy
 | ||||
| // of this software and associated documentation files (the "Software"), to deal
 | ||||
| // in the Software without restriction, including without limitation the rights
 | ||||
| // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | ||||
| // copies of the Software, and to permit persons to whom the Software is
 | ||||
| // furnished to do so, subject to the following conditions:
 | ||||
| // 
 | ||||
| // The above copyright notice and this permission notice shall be included in
 | ||||
| // all copies or substantial portions of the Software.
 | ||||
| // 
 | ||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | ||||
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | ||||
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | ||||
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | ||||
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | ||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | ||||
| // THE SOFTWARE.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| namespace kiwano | ||||
| { | ||||
| namespace common | ||||
| { | ||||
| 
 | ||||
| class noncopyable | ||||
| { | ||||
| protected: | ||||
| 	noncopyable() = default; | ||||
| 
 | ||||
| private: | ||||
| 	noncopyable(const noncopyable&) = delete; | ||||
| 
 | ||||
| 	noncopyable& operator=(const noncopyable&) = delete; | ||||
| }; | ||||
| 
 | ||||
| }  // namespace common
 | ||||
| }  // namespace kiwano
 | ||||
|  | @ -1,85 +0,0 @@ | |||
| // Copyright (c) 2016-2018 Kiwano - Nomango
 | ||||
| // 
 | ||||
| // Permission is hereby granted, free of charge, to any person obtaining a copy
 | ||||
| // of this software and associated documentation files (the "Software"), to deal
 | ||||
| // in the Software without restriction, including without limitation the rights
 | ||||
| // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | ||||
| // copies of the Software, and to permit persons to whom the Software is
 | ||||
| // furnished to do so, subject to the following conditions:
 | ||||
| // 
 | ||||
| // The above copyright notice and this permission notice shall be included in
 | ||||
| // all copies or substantial portions of the Software.
 | ||||
| // 
 | ||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | ||||
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | ||||
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | ||||
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | ||||
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | ||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | ||||
| // THE SOFTWARE.
 | ||||
| 
 | ||||
| #pragma once | ||||
| #include <memory> | ||||
| #include <mutex> | ||||
| 
 | ||||
| // Class that will implement the singleton mode,
 | ||||
| // must use the macro in its delare file
 | ||||
| 
 | ||||
| #ifndef KGE_DECLARE_SINGLETON | ||||
| #define KGE_DECLARE_SINGLETON( CLASS )			\ | ||||
| 	friend ::kiwano::common::singleton< CLASS >;  \ | ||||
| 	friend typename std::unique_ptr< CLASS >::deleter_type | ||||
| #endif | ||||
| 
 | ||||
| namespace kiwano | ||||
| { | ||||
| namespace common | ||||
| { | ||||
| 
 | ||||
| template <typename _Ty> | ||||
| struct singleton | ||||
| { | ||||
| public: | ||||
| 	static inline _Ty* GetInstance() | ||||
| 	{ | ||||
| 		if (!instance_) | ||||
| 		{ | ||||
| 			std::call_once(once_, InitInstance); | ||||
| 		} | ||||
| 		return instance_.get(); | ||||
| 	} | ||||
| 
 | ||||
| 	static inline void DestroyInstance() | ||||
| 	{ | ||||
| 		instance_.reset(); | ||||
| 	} | ||||
| 
 | ||||
| protected: | ||||
| 	singleton() = default; | ||||
| 
 | ||||
| private: | ||||
| 	singleton(const singleton&) = delete; | ||||
| 
 | ||||
| 	singleton& operator=(const singleton&) = delete; | ||||
| 
 | ||||
| 	static inline void InitInstance() | ||||
| 	{ | ||||
| 		if (!instance_) | ||||
| 		{ | ||||
| 			instance_.reset(new (std::nothrow) _Ty); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	static std::once_flag once_; | ||||
| 	static std::unique_ptr<_Ty> instance_; | ||||
| }; | ||||
| 
 | ||||
| template <typename _Ty> | ||||
| std::once_flag singleton<_Ty>::once_; | ||||
| 
 | ||||
| template <typename _Ty> | ||||
| std::unique_ptr<_Ty> singleton<_Ty>::instance_; | ||||
| 
 | ||||
| }  // namespace common
 | ||||
| }  // namespace kiwano
 | ||||
|  | @ -10,8 +10,8 @@ | |||
| 
 | ||||
| //---- Define debug-output handler. Defaults to calling kiwano::logs::Messageln()/Warningln()/Errorln()
 | ||||
| //#define KGE_LOG(FORMAT, ...)              wprintf(FORMAT L"\n", __VA_ARGS__)
 | ||||
| //#define KGE_WARNING_LOG(FORMAT, ...)      wprintf(FORMAT L"\n", __VA_ARGS__)
 | ||||
| //#define KGE_ERROR_LOG(FORMAT, ...)        wprintf(FORMAT L"\n", __VA_ARGS__)
 | ||||
| //#define KGE_WARN(FORMAT, ...)      wprintf(FORMAT L"\n", __VA_ARGS__)
 | ||||
| //#define KGE_ERROR(FORMAT, ...)        wprintf(FORMAT L"\n", __VA_ARGS__)
 | ||||
| 
 | ||||
| //---- Define attributes of all API symbols declarations for DLL
 | ||||
| //#define KGE_USE_DLL
 | ||||
|  |  | |||
|  | @ -62,7 +62,7 @@ namespace kiwano | |||
| 	FARPROC Library::GetProcess(String const& proc_name) | ||||
| 	{ | ||||
| 		KGE_ASSERT(instance_ != nullptr); | ||||
| 		return GetProcAddress(instance_, wide_to_string(proc_name).c_str()); | ||||
| 		return GetProcAddress(instance_, oc::wide_to_string(proc_name).c_str()); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -25,66 +25,52 @@ | |||
| 
 | ||||
| namespace | ||||
| { | ||||
| 	std::streambuf* cin_buffer, * cout_buffer, * cerr_buffer; | ||||
| 	std::fstream console_input, console_output, console_error; | ||||
| 	std::streambuf* cout_buffer, * cerr_buffer; | ||||
| 	std::fstream console_output, console_error; | ||||
| 
 | ||||
| 	std::wstreambuf* wcin_buffer, * wcout_buffer, * wcerr_buffer; | ||||
| 	std::wfstream wconsole_input, wconsole_output, wconsole_error; | ||||
| 	std::wstreambuf* wcout_buffer, * wcerr_buffer; | ||||
| 	std::wfstream wconsole_output, wconsole_error; | ||||
| 
 | ||||
| 	void RedirectStdIO() | ||||
| 	{ | ||||
| 		cin_buffer = std::cin.rdbuf(); | ||||
| 		cout_buffer = std::cout.rdbuf(); | ||||
| 		cerr_buffer = std::cerr.rdbuf(); | ||||
| 		wcin_buffer = std::wcin.rdbuf(); | ||||
| 		wcout_buffer = std::wcout.rdbuf(); | ||||
| 		wcerr_buffer = std::wcerr.rdbuf(); | ||||
| 
 | ||||
| 		console_input.open("CONIN$", std::ios::in); | ||||
| 		console_output.open("CONOUT$", std::ios::out); | ||||
| 		console_error.open("CONOUT$", std::ios::out); | ||||
| 		wconsole_input.open("CONIN$", std::ios::in); | ||||
| 		wconsole_output.open("CONOUT$", std::ios::out); | ||||
| 		wconsole_error.open("CONOUT$", std::ios::out); | ||||
| 
 | ||||
| 		FILE* dummy; | ||||
| 		freopen_s(&dummy, "CONOUT$", "w+t", stdout); | ||||
| 		freopen_s(&dummy, "CONIN$", "r+t", stdin); | ||||
| 		freopen_s(&dummy, "CONOUT$", "w+t", stderr); | ||||
| 		(void)dummy; | ||||
| 
 | ||||
| 		std::cin.rdbuf(console_input.rdbuf()); | ||||
| 		std::cout.rdbuf(console_output.rdbuf()); | ||||
| 		std::cerr.rdbuf(console_error.rdbuf()); | ||||
| 		std::wcin.rdbuf(wconsole_input.rdbuf()); | ||||
| 		std::wcout.rdbuf(wconsole_output.rdbuf()); | ||||
| 		std::wcerr.rdbuf(wconsole_error.rdbuf()); | ||||
| 	} | ||||
| 
 | ||||
| 	void ResetStdIO() | ||||
| 	{ | ||||
| 		console_input.close(); | ||||
| 		console_output.close(); | ||||
| 		console_error.close(); | ||||
| 		wconsole_input.close(); | ||||
| 		wconsole_output.close(); | ||||
| 		wconsole_error.close(); | ||||
| 
 | ||||
| 		std::cin.rdbuf(cin_buffer); | ||||
| 		std::cout.rdbuf(cout_buffer); | ||||
| 		std::cerr.rdbuf(cerr_buffer); | ||||
| 		std::wcin.rdbuf(wcin_buffer); | ||||
| 		std::wcout.rdbuf(wcout_buffer); | ||||
| 		std::wcerr.rdbuf(wcerr_buffer); | ||||
| 
 | ||||
| 		fclose(stdout); | ||||
| 		fclose(stdin); | ||||
| 		fclose(stderr); | ||||
| 
 | ||||
| 		cin_buffer = nullptr; | ||||
| 		cout_buffer = nullptr; | ||||
| 		cerr_buffer = nullptr; | ||||
| 		wcin_buffer = nullptr; | ||||
| 		wcout_buffer = nullptr; | ||||
| 		wcerr_buffer = nullptr; | ||||
| 	} | ||||
|  | @ -125,17 +111,17 @@ namespace kiwano | |||
| { | ||||
| 	namespace __console_colors | ||||
| 	{ | ||||
| 		const WORD _blue = FOREGROUND_BLUE | FOREGROUND_INTENSITY; | ||||
| 		const WORD _green = FOREGROUND_GREEN | FOREGROUND_INTENSITY; | ||||
| 		const WORD _red = FOREGROUND_RED | FOREGROUND_INTENSITY; | ||||
| 		const WORD _yellow = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY; | ||||
| 		const WORD _white = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY; | ||||
| 		const WORD _blue	= FOREGROUND_BLUE | FOREGROUND_INTENSITY; | ||||
| 		const WORD _green	= FOREGROUND_GREEN | FOREGROUND_INTENSITY; | ||||
| 		const WORD _red		= FOREGROUND_RED | FOREGROUND_INTENSITY; | ||||
| 		const WORD _yellow	= FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY; | ||||
| 		const WORD _white	= FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY; | ||||
| 
 | ||||
| 		const WORD _blue_bg = _white | BACKGROUND_BLUE | BACKGROUND_INTENSITY; | ||||
| 		const WORD _green_bg = _white | BACKGROUND_GREEN | BACKGROUND_INTENSITY; | ||||
| 		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 _blue_bg		= _white | BACKGROUND_BLUE | BACKGROUND_INTENSITY; | ||||
| 		const WORD _green_bg	= _white | BACKGROUND_GREEN | BACKGROUND_INTENSITY; | ||||
| 		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; | ||||
| 
 | ||||
|  | @ -202,6 +188,11 @@ namespace kiwano | |||
| 				default_stderr_color_ = stderr_info.wAttributes; | ||||
| 			} | ||||
| 
 | ||||
| 			// replace the C++ global locale with the user-preferred locale
 | ||||
| 			(void)std::locale::global(std::locale("")); | ||||
| 			(void)std::wcout.imbue(std::locale()); | ||||
| 			(void)std::wcerr.imbue(std::locale()); | ||||
| 
 | ||||
| 			RedirectOutputStreamBuffer(std::wcout.rdbuf()); | ||||
| 			RedirectErrorStreamBuffer(std::wcerr.rdbuf()); | ||||
| 		} | ||||
|  | @ -298,10 +289,12 @@ namespace kiwano | |||
| 
 | ||||
| 	std::wostream& Logger::OutPrefix(std::wostream& out) | ||||
| 	{ | ||||
| 		out << L"[KIWANO] "; | ||||
| 
 | ||||
| 		time_t unix = std::time(nullptr); | ||||
| 		std::tm tmbuf; | ||||
| 		localtime_s(&tmbuf, &unix); | ||||
| 		out << std::put_time(&tmbuf, L"[kiwano] %H:%M:%S"); | ||||
| 		out << std::put_time(&tmbuf, L"%H:%M:%S"); | ||||
| 		return out; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -319,7 +312,7 @@ namespace kiwano | |||
| 				HWND console = ::AllocateConsole(); | ||||
| 				if (!console) | ||||
| 				{ | ||||
| 					KGE_WARNING_LOG(L"AllocConsole failed"); | ||||
| 					KGE_WARN(L"AllocConsole failed"); | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
|  |  | |||
|  | @ -28,26 +28,26 @@ | |||
| 
 | ||||
| #ifndef KGE_LOG | ||||
| #	ifdef KGE_DEBUG | ||||
| #		define KGE_LOG(FORMAT, ...)		::kiwano::Logger::GetInstance()->Messagef((FORMAT ## "\n"), __VA_ARGS__) | ||||
| #		define KGE_LOG(FORMAT, ...)		::kiwano::Logger::instance().Messagef((FORMAT ## "\n"), __VA_ARGS__) | ||||
| #	else | ||||
| #		define KGE_LOG __noop | ||||
| #	endif | ||||
| #endif | ||||
| 
 | ||||
| #ifndef KGE_WARNING_LOG | ||||
| #	define KGE_WARNING_LOG(FORMAT, ...)	::kiwano::Logger::GetInstance()->Warningf((FORMAT ## "\n"), __VA_ARGS__) | ||||
| #ifndef KGE_WARN | ||||
| #	define KGE_WARN(FORMAT, ...)		::kiwano::Logger::instance().Warningf((FORMAT ## "\n"), __VA_ARGS__) | ||||
| #endif | ||||
| 
 | ||||
| #ifndef KGE_ERROR_LOG | ||||
| #	define KGE_ERROR_LOG(FORMAT, ...)	::kiwano::Logger::GetInstance()->Errorf((FORMAT ## "\n"), __VA_ARGS__) | ||||
| #ifndef KGE_ERROR | ||||
| #	define KGE_ERROR(FORMAT, ...)		::kiwano::Logger::instance().Errorf((FORMAT ## "\n"), __VA_ARGS__) | ||||
| #endif | ||||
| 
 | ||||
| #ifndef KGE_PRINT | ||||
| #	define KGE_PRINT(...)				::kiwano::Logger::GetInstance()->Println(__VA_ARGS__) | ||||
| #	define KGE_PRINT(...)				::kiwano::Logger::instance().Println(__VA_ARGS__) | ||||
| #endif | ||||
| 
 | ||||
| #ifndef KGE_PRINTF | ||||
| #	define KGE_PRINTF(FORMAT, ...)		::kiwano::Logger::GetInstance()->Printf((FORMAT), __VA_ARGS__) | ||||
| #	define KGE_PRINTF(FORMAT, ...)		::kiwano::Logger::instance().Printf((FORMAT), __VA_ARGS__) | ||||
| #endif | ||||
| 
 | ||||
| namespace kiwano | ||||
|  | @ -55,7 +55,7 @@ namespace kiwano | |||
| 	class KGE_API Logger | ||||
| 		: public Singleton<Logger> | ||||
| 	{ | ||||
| 		KGE_DECLARE_SINGLETON(Logger); | ||||
| 		OC_DECLARE_SINGLETON(Logger); | ||||
| 
 | ||||
| 	public: | ||||
| 		// ÏÔʾ»ò¹Ø±Õ¿ØÖÆÌ¨
 | ||||
|  | @ -99,6 +99,10 @@ namespace kiwano | |||
| 		template <typename ..._Args> | ||||
| 		void Errorln(_Args&& ... args); | ||||
| 
 | ||||
| 		std::wostream& GetOutputStream(); | ||||
| 
 | ||||
| 		std::wostream& GetErrorStream(); | ||||
| 
 | ||||
| 		std::wstreambuf* RedirectOutputStreamBuffer(std::wstreambuf* buf); | ||||
| 
 | ||||
| 		std::wstreambuf* RedirectErrorStreamBuffer(std::wstreambuf* buf); | ||||
|  | @ -292,7 +296,17 @@ namespace kiwano | |||
| 
 | ||||
| 	inline std::wostream& Logger::DefaultOutputColor(std::wostream& out) | ||||
| 	{ | ||||
| 		::SetConsoleTextAttribute(::GetStdHandle(STD_OUTPUT_HANDLE), Logger::GetInstance()->default_stdout_color_); | ||||
| 		::SetConsoleTextAttribute(::GetStdHandle(STD_OUTPUT_HANDLE), Logger::instance().default_stdout_color_); | ||||
| 		return out; | ||||
| 	} | ||||
| 
 | ||||
| 	inline std::wostream& Logger::GetOutputStream() | ||||
| 	{ | ||||
| 		return output_stream_; | ||||
| 	} | ||||
| 
 | ||||
| 	inline std::wostream& Logger::GetErrorStream() | ||||
| 	{ | ||||
| 		return error_stream_; | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -90,7 +90,7 @@ namespace kiwano | |||
| 
 | ||||
| 	String ObjectBase::DumpObject() | ||||
| 	{ | ||||
| 		String name = kiwano::string_to_wide(typeid(*this).name()); | ||||
| 		String name = oc::string_to_wide(typeid(*this).name()); | ||||
| 		return String::format(L"{ class=\"%s\" id=%d refcount=%d name=\"%s\" }", | ||||
| 			name.c_str(), GetObjectID(), GetRefCount(), GetName().c_str()); | ||||
| 	} | ||||
|  |  | |||
|  | @ -20,12 +20,12 @@ | |||
| 
 | ||||
| #pragma once | ||||
| #include <kiwano/macros.h> | ||||
| #include <kiwano/common/noncopyable.hpp> | ||||
| #include <kiwano/common/common.h> | ||||
| 
 | ||||
| namespace kiwano | ||||
| { | ||||
| 	class KGE_API RefCounter | ||||
| 		: protected common::noncopyable | ||||
| 		: protected Noncopyable | ||||
| 	{ | ||||
| 	public: | ||||
| 		// 增加引用计数
 | ||||
|  |  | |||
|  | @ -50,28 +50,28 @@ namespace kiwano | |||
| 			HRSRC res_info = FindResourceW(nullptr, MAKEINTRESOURCE(id_), type_); | ||||
| 			if (res_info == nullptr) | ||||
| 			{ | ||||
| 				KGE_ERROR_LOG(L"FindResource failed"); | ||||
| 				KGE_ERROR(L"FindResource failed"); | ||||
| 				break; | ||||
| 			} | ||||
| 
 | ||||
| 			HGLOBAL res_data = LoadResource(nullptr, res_info); | ||||
| 			if (res_data == nullptr) | ||||
| 			{ | ||||
| 				KGE_ERROR_LOG(L"LoadResource failed"); | ||||
| 				KGE_ERROR(L"LoadResource failed"); | ||||
| 				break; | ||||
| 			} | ||||
| 
 | ||||
| 			DWORD size = SizeofResource(nullptr, res_info); | ||||
| 			if (size == 0) | ||||
| 			{ | ||||
| 				KGE_ERROR_LOG(L"SizeofResource failed"); | ||||
| 				KGE_ERROR(L"SizeofResource failed"); | ||||
| 				break; | ||||
| 			} | ||||
| 
 | ||||
| 			LPVOID buffer = LockResource(res_data); | ||||
| 			if (buffer == nullptr) | ||||
| 			{ | ||||
| 				KGE_ERROR_LOG(L"LockResource failed"); | ||||
| 				KGE_ERROR(L"LockResource failed"); | ||||
| 				break; | ||||
| 			} | ||||
| 
 | ||||
|  |  | |||
|  | @ -20,25 +20,25 @@ | |||
| 
 | ||||
| #pragma once | ||||
| #include <kiwano/core/RefCounter.hpp> | ||||
| #include <kiwano/common/intrusive_ptr.hpp> | ||||
| #include <kiwano/common/common.h> | ||||
| 
 | ||||
| namespace kiwano | ||||
| { | ||||
| 	struct DefaultIntrusivePtrManager | ||||
| 	struct DefaultIntrusivePtrProxy | ||||
| 	{ | ||||
| 		static inline void AddRef(RefCounter* ptr) | ||||
| 		static inline void add_ref(RefCounter* ptr) | ||||
| 		{ | ||||
| 			if (ptr) ptr->Retain(); | ||||
| 		} | ||||
| 
 | ||||
| 		static inline void Release(RefCounter* ptr) | ||||
| 		static inline void release(RefCounter* ptr) | ||||
| 		{ | ||||
| 			if (ptr) ptr->Release(); | ||||
| 		} | ||||
| 	}; | ||||
| 
 | ||||
| 	template <typename _Ty> | ||||
| 	using SmartPtr = common::intrusive_ptr<_Ty, DefaultIntrusivePtrManager>; | ||||
| 	using SmartPtr = IntrusivePtr<_Ty, DefaultIntrusivePtrProxy>; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -363,7 +363,7 @@ namespace kiwano | |||
| 
 | ||||
| 		if (!std::regex_match(str.c_str(), duration_regex)) | ||||
| 		{ | ||||
| 			KGE_ERROR_LOG(L"Duration::Parse failed, invalid duration"); | ||||
| 			KGE_ERROR(L"Duration::Parse failed, invalid duration"); | ||||
| 			return ret; | ||||
| 		} | ||||
| 
 | ||||
|  |  | |||
|  | @ -20,19 +20,19 @@ | |||
| 
 | ||||
| #pragma once | ||||
| #include <type_traits> | ||||
| #include <kiwano/common/intrusive_ptr.hpp> | ||||
| #include <kiwano/common/common.h> | ||||
| #include <Unknwnbase.h> | ||||
| 
 | ||||
| namespace kiwano | ||||
| { | ||||
| 	struct ComPtrManager | ||||
| 	struct ComPtrProxy | ||||
| 	{ | ||||
| 		static inline void AddRef(IUnknown* ptr) | ||||
| 		static inline void add_ref(IUnknown* ptr) | ||||
| 		{ | ||||
| 			if (ptr) ptr->AddRef(); | ||||
| 		} | ||||
| 
 | ||||
| 		static inline void Release(IUnknown* ptr) | ||||
| 		static inline void release(IUnknown* ptr) | ||||
| 		{ | ||||
| 			if (ptr) ptr->Release(); | ||||
| 		} | ||||
|  | @ -42,6 +42,6 @@ namespace kiwano | |||
| 	template< | ||||
| 		typename _Ty, | ||||
| 		typename = typename std::enable_if<std::is_base_of<IUnknown, _Ty>::value, int>::type> | ||||
| 	using ComPtr = common::intrusive_ptr<_Ty, ComPtrManager>; | ||||
| 	using ComPtr = IntrusivePtr<_Ty, ComPtrProxy>; | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -28,7 +28,7 @@ namespace kiwano | |||
| 	{ | ||||
| 		if (FAILED(hr)) | ||||
| 		{ | ||||
| 			KGE_ERROR_LOG(L"Fatal error with HRESULT of %08X", hr); | ||||
| 			KGE_ERROR(L"Fatal error with HRESULT of %08X", hr); | ||||
| 
 | ||||
| 			StackWalker{}.ShowCallstack(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -32,15 +32,6 @@ | |||
| // common
 | ||||
| //
 | ||||
| 
 | ||||
| #include <kiwano/common/vector.hpp> | ||||
| #include <kiwano/common/string.hpp> | ||||
| #include <kiwano/common/any.hpp> | ||||
| #include <kiwano/common/function.hpp> | ||||
| #include <kiwano/common/intrusive_list.hpp> | ||||
| #include <kiwano/common/intrusive_ptr.hpp> | ||||
| #include <kiwano/common/noncopyable.hpp> | ||||
| #include <kiwano/common/singleton.hpp> | ||||
| #include <kiwano/common/basic_json.hpp> | ||||
| #include <kiwano/common/common.h> | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -69,9 +69,9 @@ namespace kiwano | |||
| 	{ | ||||
| 		ThrowIfFailed(::CoInitialize(nullptr)); | ||||
| 
 | ||||
| 		Use(Renderer::GetInstance()); | ||||
| 		Use(Input::GetInstance()); | ||||
| 		Use(Director::GetInstance()); | ||||
| 		Use(&Renderer::instance()); | ||||
| 		Use(&Input::instance()); | ||||
| 		Use(&Director::instance()); | ||||
| 	} | ||||
| 
 | ||||
| 	Application::~Application() | ||||
|  | @ -83,8 +83,8 @@ namespace kiwano | |||
| 
 | ||||
| 	void Application::Init(const Config& config) | ||||
| 	{ | ||||
| 		Window::GetInstance()->Init(config.window, Application::WndProc); | ||||
| 		Renderer::GetInstance()->Init(config.render); | ||||
| 		Window::instance().Init(config.window, Application::WndProc); | ||||
| 		Renderer::instance().Init(config.render); | ||||
| 
 | ||||
| 		// Setup all components
 | ||||
| 		for (auto c : comps_) | ||||
|  | @ -94,14 +94,14 @@ namespace kiwano | |||
| 
 | ||||
| 		if (config.debug) | ||||
| 		{ | ||||
| 			Director::GetInstance()->ShowDebugInfo(true); | ||||
| 			Renderer::GetInstance()->SetCollectingStatus(true); | ||||
| 			Director::instance().ShowDebugInfo(true); | ||||
| 			Renderer::instance().SetCollectingStatus(true); | ||||
| 		} | ||||
| 
 | ||||
| 		// Everything is ready
 | ||||
| 		OnReady(); | ||||
| 
 | ||||
| 		HWND hwnd = Window::GetInstance()->GetHandle(); | ||||
| 		HWND hwnd = Window::instance().GetHandle(); | ||||
| 
 | ||||
| 		// disable imm
 | ||||
| 		::ImmAssociateContext(hwnd, nullptr); | ||||
|  | @ -118,10 +118,10 @@ namespace kiwano | |||
| 
 | ||||
| 		end_ = false; | ||||
| 
 | ||||
| 		Window::GetInstance()->Prepare(); | ||||
| 		Window::instance().Prepare(); | ||||
| 		while (!end_) | ||||
| 		{ | ||||
| 			Window::GetInstance()->PollEvents(); | ||||
| 			Window::instance().PollEvents(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -133,9 +133,9 @@ namespace kiwano | |||
| 	void Application::Destroy() | ||||
| 	{ | ||||
| 		// Clear all resources
 | ||||
| 		Director::GetInstance()->ClearStages(); | ||||
| 		ResourceCache::GetInstance()->Clear(); | ||||
| 		TextureCache::GetInstance()->Clear(); | ||||
| 		Director::instance().ClearStages(); | ||||
| 		ResourceCache::instance().Clear(); | ||||
| 		TextureCache::instance().Clear(); | ||||
| 
 | ||||
| 		if (inited_) | ||||
| 		{ | ||||
|  | @ -148,16 +148,9 @@ namespace kiwano | |||
| 			comps_.clear(); | ||||
| 		} | ||||
| 
 | ||||
| 		// Destroy all instances
 | ||||
| 		Director::DestroyInstance(); | ||||
| 		ResourceCache::DestroyInstance(); | ||||
| 		TextureCache::DestroyInstance(); | ||||
| 		Input::DestroyInstance(); | ||||
| 		Renderer::DestroyInstance(); | ||||
| 		Window::DestroyInstance(); | ||||
| 
 | ||||
| 		// DO NOT destroy Logger instance manually
 | ||||
| 		// Logger::DestroyInstance();
 | ||||
| 		Input::instance().Destroy(); | ||||
| 		Renderer::instance().Destroy(); | ||||
| 		Window::instance().Destroy(); | ||||
| 	} | ||||
| 
 | ||||
| 	void Application::Use(ComponentBase* component) | ||||
|  | @ -248,7 +241,7 @@ namespace kiwano | |||
| 		} | ||||
| 
 | ||||
| 		// Rendering
 | ||||
| 		Renderer* renderer = Renderer::GetInstance(); | ||||
| 		Renderer* renderer = &Renderer::instance(); | ||||
| 		for (auto c : render_comps_) | ||||
| 		{ | ||||
| 			c->OnRender(renderer); | ||||
|  | @ -396,7 +389,7 @@ namespace kiwano | |||
| 			{ | ||||
| 				// KGE_LOG(L"Window resized");
 | ||||
| 
 | ||||
| 				Window::GetInstance()->UpdateWindowRect(); | ||||
| 				Window::instance().UpdateWindowRect(); | ||||
| 
 | ||||
| 				WindowResizedEvent evt; | ||||
| 				evt.width = LOWORD(lparam); | ||||
|  | @ -422,7 +415,7 @@ namespace kiwano | |||
| 		{ | ||||
| 			bool active = (LOWORD(wparam) != WA_INACTIVE); | ||||
| 
 | ||||
| 			Window::GetInstance()->SetActive(active); | ||||
| 			Window::instance().SetActive(active); | ||||
| 
 | ||||
| 			WindowFocusChangedEvent evt; | ||||
| 			evt.focus = active; | ||||
|  | @ -456,7 +449,7 @@ namespace kiwano | |||
| 
 | ||||
| 		case WM_SETCURSOR: | ||||
| 		{ | ||||
| 			Window::GetInstance()->UpdateCursor(); | ||||
| 			Window::instance().UpdateCursor(); | ||||
| 		} | ||||
| 		break; | ||||
| 
 | ||||
|  |  | |||
|  | @ -50,7 +50,7 @@ namespace kiwano | |||
| 
 | ||||
| 	// 应用
 | ||||
| 	class KGE_API Application | ||||
| 		: protected common::noncopyable | ||||
| 		: protected Noncopyable | ||||
| 	{ | ||||
| 	public: | ||||
| 		Application(); | ||||
|  |  | |||
|  | @ -31,7 +31,7 @@ namespace kiwano | |||
| 		, public RenderComponent | ||||
| 		, public EventComponent | ||||
| 	{ | ||||
| 		KGE_DECLARE_SINGLETON(Director); | ||||
| 		OC_DECLARE_SINGLETON(Director); | ||||
| 
 | ||||
| 	public: | ||||
| 		// Çл»Îę̀
 | ||||
|  |  | |||
|  | @ -27,7 +27,7 @@ namespace kiwano | |||
| 	class KGE_API FileSystem | ||||
| 		: public Singleton<FileSystem> | ||||
| 	{ | ||||
| 		KGE_DECLARE_SINGLETON(FileSystem); | ||||
| 		OC_DECLARE_SINGLETON(FileSystem); | ||||
| 
 | ||||
| 	public: | ||||
| 		// 添加文件搜索路径
 | ||||
|  |  | |||
|  | @ -140,4 +140,8 @@ namespace kiwano | |||
| 	{ | ||||
| 		return Point{ mouse_pos_x_, mouse_pos_y_ }; | ||||
| 	} | ||||
| 
 | ||||
| 	void Input::Destroy() | ||||
| 	{ | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -32,7 +32,7 @@ namespace kiwano | |||
| 		, public UpdateComponent | ||||
| 		, public EventComponent | ||||
| 	{ | ||||
| 		KGE_DECLARE_SINGLETON(Input); | ||||
| 		OC_DECLARE_SINGLETON(Input); | ||||
| 
 | ||||
| 	public: | ||||
| 		// 检测键盘或鼠标按键是否正被按下
 | ||||
|  | @ -72,6 +72,8 @@ namespace kiwano | |||
| 
 | ||||
| 		void UpdateMousePos(float, float); | ||||
| 
 | ||||
| 		void Destroy(); | ||||
| 
 | ||||
| 	protected: | ||||
| 		Input(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -63,20 +63,6 @@ namespace kiwano | |||
| 
 | ||||
| 	Window::~Window() | ||||
| 	{ | ||||
| 		if (is_fullscreen_) | ||||
| 			RestoreResolution(device_name_); | ||||
| 
 | ||||
| 		if (device_name_) | ||||
| 		{ | ||||
| 			delete[] device_name_; | ||||
| 			device_name_ = nullptr; | ||||
| 		} | ||||
| 
 | ||||
| 		if (handle_) | ||||
| 		{ | ||||
| 			::DestroyWindow(handle_); | ||||
| 			handle_ = nullptr; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	void Window::Init(WindowConfig const& config, WNDPROC proc) | ||||
|  | @ -388,6 +374,24 @@ namespace kiwano | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	void Window::Destroy() | ||||
| 	{ | ||||
| 		if (is_fullscreen_) | ||||
| 			RestoreResolution(device_name_); | ||||
| 
 | ||||
| 		if (device_name_) | ||||
| 		{ | ||||
| 			delete[] device_name_; | ||||
| 			device_name_ = nullptr; | ||||
| 		} | ||||
| 
 | ||||
| 		if (handle_) | ||||
| 		{ | ||||
| 			::DestroyWindow(handle_); | ||||
| 			handle_ = nullptr; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	namespace | ||||
| 	{ | ||||
| 		MONITORINFOEX GetMoniterInfoEx(HWND hwnd) | ||||
|  | @ -434,7 +438,7 @@ namespace kiwano | |||
| 			mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; | ||||
| 
 | ||||
| 			if (::ChangeDisplaySettingsExW(device_name, &mode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL) | ||||
| 				KGE_ERROR_LOG(L"ChangeDisplaySettings failed"); | ||||
| 				KGE_ERROR(L"ChangeDisplaySettings failed"); | ||||
| 		} | ||||
| 
 | ||||
| 		void RestoreResolution(WCHAR* device_name) | ||||
|  |  | |||
|  | @ -63,7 +63,7 @@ namespace kiwano | |||
| 	class KGE_API Window | ||||
| 		: public Singleton<Window> | ||||
| 	{ | ||||
| 		KGE_DECLARE_SINGLETON(Window); | ||||
| 		OC_DECLARE_SINGLETON(Window); | ||||
| 
 | ||||
| 	public: | ||||
| 		// »ñÈ¡±êÌâ
 | ||||
|  | @ -110,6 +110,8 @@ namespace kiwano | |||
| 		 | ||||
| 		void SetActive(bool actived); | ||||
| 
 | ||||
| 		void Destroy(); | ||||
| 
 | ||||
| 	protected: | ||||
| 		Window(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -37,7 +37,7 @@ namespace kiwano | |||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				KGE_ERROR_LOG(L"Load shlapi.dll failed"); | ||||
| 				KGE_ERROR(L"Load shlapi.dll failed"); | ||||
| 				throw std::runtime_error("Load shlapi.dll failed"); | ||||
| 			} | ||||
| 		} | ||||
|  |  | |||
|  | @ -111,20 +111,20 @@ namespace kiwano | |||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			Renderer::GetInstance()->CreateSolidBrush(*this, style.color); | ||||
| 			Renderer::instance().CreateSolidBrush(*this, style.color); | ||||
| 			type_ = Type::SolidColor; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	void Brush::SetStyle(LinearGradientStyle const& style) | ||||
| 	{ | ||||
| 		Renderer::GetInstance()->CreateLinearGradientBrush(*this, style.begin, style.end, style.stops, style.extend_mode); | ||||
| 		Renderer::instance().CreateLinearGradientBrush(*this, style.begin, style.end, style.stops, style.extend_mode); | ||||
| 		type_ = Type::LinearGradient; | ||||
| 	} | ||||
| 
 | ||||
| 	void Brush::SetStyle(RadialGradientStyle const& style) | ||||
| 	{ | ||||
| 		Renderer::GetInstance()->CreateRadialGradientBrush(*this, style.center, style.offset, style.radius, style.stops, style.extend_mode); | ||||
| 		Renderer::instance().CreateRadialGradientBrush(*this, style.center, style.offset, style.radius, style.stops, style.extend_mode); | ||||
| 		type_ = Type::RadialGradient; | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -49,25 +49,25 @@ namespace kiwano | |||
| 
 | ||||
| 	bool FontCollection::Load(String const& file) | ||||
| 	{ | ||||
| 		Renderer::GetInstance()->CreateFontCollection(*this, { file }); | ||||
| 		Renderer::instance().CreateFontCollection(*this, { file }); | ||||
| 		return IsValid(); | ||||
| 	} | ||||
| 
 | ||||
| 	bool FontCollection::Load(Vector<String> const& files) | ||||
| 	{ | ||||
| 		Renderer::GetInstance()->CreateFontCollection(*this, files); | ||||
| 		Renderer::instance().CreateFontCollection(*this, files); | ||||
| 		return IsValid(); | ||||
| 	} | ||||
| 
 | ||||
| 	bool FontCollection::Load(Resource const& res) | ||||
| 	{ | ||||
| 		Renderer::GetInstance()->CreateFontCollection(*this, { res }); | ||||
| 		Renderer::instance().CreateFontCollection(*this, { res }); | ||||
| 		return IsValid(); | ||||
| 	} | ||||
| 
 | ||||
| 	bool FontCollection::Load(Vector<Resource> const& res_arr) | ||||
| 	{ | ||||
| 		Renderer::GetInstance()->CreateFontCollection(*this, res_arr); | ||||
| 		Renderer::instance().CreateFontCollection(*this, res_arr); | ||||
| 		return IsValid(); | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -147,35 +147,35 @@ namespace kiwano | |||
| 	Geometry Geometry::CreateLine(Point const& begin, Point const& end) | ||||
| 	{ | ||||
| 		Geometry output; | ||||
| 		Renderer::GetInstance()->CreateLineGeometry(output, begin, end); | ||||
| 		Renderer::instance().CreateLineGeometry(output, begin, end); | ||||
| 		return output; | ||||
| 	} | ||||
| 
 | ||||
| 	Geometry Geometry::CreateRect(Rect const& rect) | ||||
| 	{ | ||||
| 		Geometry output; | ||||
| 		Renderer::GetInstance()->CreateRectGeometry(output, rect); | ||||
| 		Renderer::instance().CreateRectGeometry(output, rect); | ||||
| 		return output; | ||||
| 	} | ||||
| 
 | ||||
| 	Geometry Geometry::CreateRoundedRect(Rect const& rect, Vec2 const& radius) | ||||
| 	{ | ||||
| 		Geometry output; | ||||
| 		Renderer::GetInstance()->CreateRoundedRectGeometry(output, rect, radius); | ||||
| 		Renderer::instance().CreateRoundedRectGeometry(output, rect, radius); | ||||
| 		return output; | ||||
| 	} | ||||
| 
 | ||||
| 	Geometry Geometry::CreateCircle(Point const& center, float radius) | ||||
| 	{ | ||||
| 		Geometry output; | ||||
| 		Renderer::GetInstance()->CreateEllipseGeometry(output, center, Vec2{ radius, radius }); | ||||
| 		Renderer::instance().CreateEllipseGeometry(output, center, Vec2{ radius, radius }); | ||||
| 		return output; | ||||
| 	} | ||||
| 
 | ||||
| 	Geometry Geometry::CreateEllipse(Point const& center, Vec2 const& radius) | ||||
| 	{ | ||||
| 		Geometry output; | ||||
| 		Renderer::GetInstance()->CreateEllipseGeometry(output, center, radius); | ||||
| 		Renderer::instance().CreateEllipseGeometry(output, center, radius); | ||||
| 		return output; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -284,7 +284,7 @@ namespace kiwano | |||
| 	{ | ||||
| 		if (!path_geo_) | ||||
| 		{ | ||||
| 			Renderer::GetInstance()->CreatePathGeometrySink(*this); | ||||
| 			Renderer::instance().CreatePathGeometrySink(*this); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -130,7 +130,7 @@ namespace kiwano | |||
| 
 | ||||
| 	// 几何体生成器
 | ||||
| 	class KGE_API GeometrySink | ||||
| 		: protected common::noncopyable | ||||
| 		: protected Noncopyable | ||||
| 	{ | ||||
| 	public: | ||||
| 		GeometrySink(); | ||||
|  |  | |||
|  | @ -44,7 +44,7 @@ namespace kiwano | |||
| 
 | ||||
| 	bool GifImage::Load(String const& file_path) | ||||
| 	{ | ||||
| 		Renderer::GetInstance()->CreateGifImage(*this, file_path); | ||||
| 		Renderer::instance().CreateGifImage(*this, file_path); | ||||
| 
 | ||||
| 		if (IsValid()) | ||||
| 		{ | ||||
|  | @ -60,7 +60,7 @@ namespace kiwano | |||
| 
 | ||||
| 	bool GifImage::Load(Resource const& res) | ||||
| 	{ | ||||
| 		Renderer::GetInstance()->CreateGifImage(*this, res); | ||||
| 		Renderer::instance().CreateGifImage(*this, res); | ||||
| 
 | ||||
| 		if (IsValid()) | ||||
| 		{ | ||||
|  |  | |||
|  | @ -41,7 +41,7 @@ namespace kiwano | |||
| 
 | ||||
| 	// äÖȾĿ±ê
 | ||||
| 	class KGE_API RenderTarget | ||||
| 		: public common::noncopyable | ||||
| 		: public Noncopyable | ||||
| 	{ | ||||
| 	public: | ||||
| 		bool IsValid() const; | ||||
|  |  | |||
|  | @ -52,8 +52,8 @@ namespace kiwano | |||
| 	{ | ||||
| 		KGE_LOG(L"Creating device resources"); | ||||
| 
 | ||||
| 		hwnd_ = Window::GetInstance()->GetHandle(); | ||||
| 		output_size_ = Window::GetInstance()->GetSize(); | ||||
| 		hwnd_ = Window::instance().GetHandle(); | ||||
| 		output_size_ = Window::instance().GetSize(); | ||||
| 
 | ||||
| 		d2d_res_ = nullptr; | ||||
| 		d3d_res_ = nullptr; | ||||
|  | @ -247,15 +247,15 @@ namespace kiwano | |||
| 			hr = E_UNEXPECTED; | ||||
| 		} | ||||
| 
 | ||||
| 		if (!FileSystem::GetInstance()->IsFileExists(file_path)) | ||||
| 		if (!FileSystem::instance().IsFileExists(file_path)) | ||||
| 		{ | ||||
| 			KGE_WARNING_LOG(L"Texture file '%s' not found!", file_path.c_str()); | ||||
| 			KGE_WARN(L"Texture file '%s' not found!", file_path.c_str()); | ||||
| 			hr = E_FAIL; | ||||
| 		} | ||||
| 
 | ||||
| 		if (SUCCEEDED(hr)) | ||||
| 		{ | ||||
| 			String full_path = FileSystem::GetInstance()->GetFullPathForFile(file_path); | ||||
| 			String full_path = FileSystem::instance().GetFullPathForFile(file_path); | ||||
| 
 | ||||
| 			ComPtr<IWICBitmapDecoder> decoder; | ||||
| 			hr = d2d_res_->CreateBitmapDecoderFromFile(decoder, full_path); | ||||
|  | @ -298,7 +298,7 @@ namespace kiwano | |||
| 
 | ||||
| 		if (FAILED(hr)) | ||||
| 		{ | ||||
| 			KGE_WARNING_LOG(L"Load texture failed with HRESULT of %08X!", hr); | ||||
| 			KGE_WARN(L"Load texture failed with HRESULT of %08X!", hr); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -353,7 +353,7 @@ namespace kiwano | |||
| 
 | ||||
| 		if (FAILED(hr)) | ||||
| 		{ | ||||
| 			KGE_WARNING_LOG(L"Load texture failed with HRESULT of %08X!", hr); | ||||
| 			KGE_WARN(L"Load texture failed with HRESULT of %08X!", hr); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -365,15 +365,15 @@ namespace kiwano | |||
| 			hr = E_UNEXPECTED; | ||||
| 		} | ||||
| 
 | ||||
| 		if (!FileSystem::GetInstance()->IsFileExists(file_path)) | ||||
| 		if (!FileSystem::instance().IsFileExists(file_path)) | ||||
| 		{ | ||||
| 			KGE_WARNING_LOG(L"Gif texture file '%s' not found!", file_path.c_str()); | ||||
| 			KGE_WARN(L"Gif texture file '%s' not found!", file_path.c_str()); | ||||
| 			hr = E_FAIL; | ||||
| 		} | ||||
| 
 | ||||
| 		if (SUCCEEDED(hr)) | ||||
| 		{ | ||||
| 			String full_path = FileSystem::GetInstance()->GetFullPathForFile(file_path); | ||||
| 			String full_path = FileSystem::instance().GetFullPathForFile(file_path); | ||||
| 
 | ||||
| 			ComPtr<IWICBitmapDecoder> decoder; | ||||
| 			hr = d2d_res_->CreateBitmapDecoderFromFile(decoder, full_path); | ||||
|  | @ -386,7 +386,7 @@ namespace kiwano | |||
| 
 | ||||
| 		if (FAILED(hr)) | ||||
| 		{ | ||||
| 			KGE_WARNING_LOG(L"Load GIF texture failed with HRESULT of %08X!", hr); | ||||
| 			KGE_WARN(L"Load GIF texture failed with HRESULT of %08X!", hr); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -411,7 +411,7 @@ namespace kiwano | |||
| 
 | ||||
| 		if (FAILED(hr)) | ||||
| 		{ | ||||
| 			KGE_WARNING_LOG(L"Load GIF texture failed with HRESULT of %08X!", hr); | ||||
| 			KGE_WARN(L"Load GIF texture failed with HRESULT of %08X!", hr); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -578,7 +578,7 @@ namespace kiwano | |||
| 
 | ||||
| 		if (FAILED(hr)) | ||||
| 		{ | ||||
| 			KGE_WARNING_LOG(L"Load GIF frame failed with HRESULT of %08X!", hr); | ||||
| 			KGE_WARN(L"Load GIF frame failed with HRESULT of %08X!", hr); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -596,13 +596,13 @@ namespace kiwano | |||
| 		{ | ||||
| 			for (auto& file_path : full_paths) | ||||
| 			{ | ||||
| 				if (!FileSystem::GetInstance()->IsFileExists(file_path)) | ||||
| 				if (!FileSystem::instance().IsFileExists(file_path)) | ||||
| 				{ | ||||
| 					KGE_WARNING_LOG(L"Font file '%s' not found!", file_path.c_str()); | ||||
| 					KGE_WARN(L"Font file '%s' not found!", file_path.c_str()); | ||||
| 					hr = E_FAIL; | ||||
| 				} | ||||
| 
 | ||||
| 				file_path = FileSystem::GetInstance()->GetFullPathForFile(file_path); | ||||
| 				file_path = FileSystem::instance().GetFullPathForFile(file_path); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
|  | @ -632,7 +632,7 @@ namespace kiwano | |||
| 
 | ||||
| 		if (FAILED(hr)) | ||||
| 		{ | ||||
| 			KGE_WARNING_LOG(L"Load font failed with HRESULT of %08X!", hr); | ||||
| 			KGE_WARN(L"Load font failed with HRESULT of %08X!", hr); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -670,7 +670,7 @@ namespace kiwano | |||
| 
 | ||||
| 		if (FAILED(hr)) | ||||
| 		{ | ||||
| 			KGE_WARNING_LOG(L"Load font failed with HRESULT of %08X!", hr); | ||||
| 			KGE_WARN(L"Load font failed with HRESULT of %08X!", hr); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -1015,4 +1015,16 @@ namespace kiwano | |||
| 		ThrowIfFailed(hr); | ||||
| 	} | ||||
| 
 | ||||
| 	void Renderer::Destroy() | ||||
| 	{ | ||||
| 		DiscardDeviceResources(); | ||||
| 
 | ||||
| 		d2d_res_.reset(); | ||||
| 		d3d_res_.reset(); | ||||
| 		drawing_state_block_.reset(); | ||||
| 		font_collection_loader_.reset(); | ||||
| 		res_font_file_loader_.reset(); | ||||
| 		res_font_collection_loader_.reset(); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -59,7 +59,7 @@ namespace kiwano | |||
| 		, public EventComponent | ||||
| 		, public RenderTarget | ||||
| 	{ | ||||
| 		KGE_DECLARE_SINGLETON(Renderer); | ||||
| 		OC_DECLARE_SINGLETON(Renderer); | ||||
| 
 | ||||
| 	public: | ||||
| 		// <20>零헌팁奈<ED8C81>
 | ||||
|  | @ -185,6 +185,8 @@ namespace kiwano | |||
| 
 | ||||
| 		void HandleMessage(HWND hwnd, UINT32 msg, WPARAM wparam, LPARAM lparam) override; | ||||
| 
 | ||||
| 		void Destroy(); | ||||
| 
 | ||||
| 	public: | ||||
| 		inline HWND						GetTargetWindow() const			{ return hwnd_; } | ||||
| 
 | ||||
|  |  | |||
|  | @ -39,7 +39,7 @@ namespace kiwano | |||
| 
 | ||||
| 	void TextFormat::Update(Font const& font) | ||||
| 	{ | ||||
| 		Renderer::GetInstance()->CreateTextFormat(*this, font); | ||||
| 		Renderer::instance().CreateTextFormat(*this, font); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
|  | @ -72,7 +72,7 @@ namespace kiwano | |||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		Renderer::GetInstance()->CreateTextLayout( | ||||
| 		Renderer::instance().CreateTextLayout( | ||||
| 			*this, | ||||
| 			text, | ||||
| 			text_format_ | ||||
|  |  | |||
|  | @ -55,13 +55,13 @@ namespace kiwano | |||
| 
 | ||||
| 	bool Texture::Load(String const& file_path) | ||||
| 	{ | ||||
| 		Renderer::GetInstance()->CreateTexture(*this, file_path); | ||||
| 		Renderer::instance().CreateTexture(*this, file_path); | ||||
| 		return IsValid(); | ||||
| 	} | ||||
| 
 | ||||
| 	bool Texture::Load(Resource const& res) | ||||
| 	{ | ||||
| 		Renderer::GetInstance()->CreateTexture(*this, res); | ||||
| 		Renderer::instance().CreateTexture(*this, res); | ||||
| 		return IsValid(); | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -27,7 +27,7 @@ namespace kiwano | |||
| 	class KGE_API TextureCache | ||||
| 		: public Singleton<TextureCache> | ||||
| 	{ | ||||
| 		KGE_DECLARE_SINGLETON(TextureCache); | ||||
| 		OC_DECLARE_SINGLETON(TextureCache); | ||||
| 
 | ||||
| 	public: | ||||
| 		Texture AddOrGetTexture(String const& file_path); | ||||
|  |  | |||
|  | @ -113,7 +113,7 @@ namespace kiwano | |||
| 			if (evt.type == event::MouseHover) | ||||
| 			{ | ||||
| 				SetStatus(Status::Hover); | ||||
| 				Window::GetInstance()->SetCursor(CursorType::Hand); | ||||
| 				Window::instance().SetCursor(CursorType::Hand); | ||||
| 
 | ||||
| 				if (mouse_over_callback_) | ||||
| 					mouse_over_callback_(); | ||||
|  | @ -121,7 +121,7 @@ namespace kiwano | |||
| 			else if (evt.type == event::MouseOut) | ||||
| 			{ | ||||
| 				SetStatus(Status::Normal); | ||||
| 				Window::GetInstance()->SetCursor(CursorType::Arrow); | ||||
| 				Window::instance().SetCursor(CursorType::Arrow); | ||||
| 
 | ||||
| 				if (mouse_out_callback_) | ||||
| 					mouse_out_callback_(); | ||||
|  |  | |||
|  | @ -61,9 +61,9 @@ namespace kiwano | |||
| 
 | ||||
| 	bool ResourceCache::LoadFromJsonFile(String const& file_path) | ||||
| 	{ | ||||
| 		if (!FileSystem::GetInstance()->IsFileExists(file_path)) | ||||
| 		if (!FileSystem::instance().IsFileExists(file_path)) | ||||
| 		{ | ||||
| 			KGE_WARNING_LOG(L"ResourceCache::LoadFromJsonFile failed: File not found."); | ||||
| 			KGE_WARN(L"ResourceCache::LoadFromJsonFile failed: File not found."); | ||||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
|  | @ -73,19 +73,19 @@ namespace kiwano | |||
| 
 | ||||
| 		try | ||||
| 		{ | ||||
| 			String full_path = FileSystem::GetInstance()->GetFullPathForFile(file_path); | ||||
| 			String full_path = FileSystem::instance().GetFullPathForFile(file_path); | ||||
| 			ifs.open(full_path.c_str()); | ||||
| 			ifs >> json_data; | ||||
| 			ifs.close(); | ||||
| 		} | ||||
| 		catch (std::wifstream::failure& e) | ||||
| 		{ | ||||
| 			KGE_WARNING_LOG(L"ResourceCache::LoadFromJsonFile failed: Cannot open file. (%s)", string_to_wide(e.what()).c_str()); | ||||
| 			KGE_WARN(L"ResourceCache::LoadFromJsonFile failed: Cannot open file. (%s)", oc::string_to_wide(e.what()).c_str()); | ||||
| 			return false; | ||||
| 		} | ||||
| 		catch (common::json_exception& e) | ||||
| 		catch (oc::json_exception& e) | ||||
| 		{ | ||||
| 			KGE_WARNING_LOG(L"ResourceCache::LoadFromJsonFile failed: Cannot parse to JSON. (%s)", string_to_wide(e.what()).c_str()); | ||||
| 			KGE_WARN(L"ResourceCache::LoadFromJsonFile failed: Cannot parse to JSON. (%s)", oc::string_to_wide(e.what()).c_str()); | ||||
| 			return false; | ||||
| 		} | ||||
| 		return LoadFromJson(json_data); | ||||
|  | @ -113,7 +113,7 @@ namespace kiwano | |||
| 		} | ||||
| 		catch (std::exception& e) | ||||
| 		{ | ||||
| 			KGE_WARNING_LOG(L"ResourceCache::LoadFromJson failed: JSON data is invalid. (%s)", string_to_wide(e.what()).c_str()); | ||||
| 			KGE_WARN(L"ResourceCache::LoadFromJson failed: JSON data is invalid. (%s)", oc::string_to_wide(e.what()).c_str()); | ||||
| 			return false; | ||||
| 		} | ||||
| 		return false; | ||||
|  | @ -121,9 +121,9 @@ namespace kiwano | |||
| 
 | ||||
| 	bool ResourceCache::LoadFromXmlFile(String const& file_path) | ||||
| 	{ | ||||
| 		if (!FileSystem::GetInstance()->IsFileExists(file_path)) | ||||
| 		if (!FileSystem::instance().IsFileExists(file_path)) | ||||
| 		{ | ||||
| 			KGE_WARNING_LOG(L"ResourceCache::LoadFromXmlFile failed: File not found."); | ||||
| 			KGE_WARN(L"ResourceCache::LoadFromXmlFile failed: File not found."); | ||||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
|  | @ -133,7 +133,7 @@ namespace kiwano | |||
| 
 | ||||
| 		try | ||||
| 		{ | ||||
| 			String full_path = FileSystem::GetInstance()->GetFullPathForFile(file_path); | ||||
| 			String full_path = FileSystem::instance().GetFullPathForFile(file_path); | ||||
| 			ifs.open(full_path.c_str()); | ||||
| 
 | ||||
| 			StringStream ss; | ||||
|  | @ -141,14 +141,14 @@ namespace kiwano | |||
| 
 | ||||
| 			if (tinyxml2::XML_SUCCESS != doc.Parse(ss.str().c_str())) | ||||
| 			{ | ||||
| 				KGE_WARNING_LOG(L"ResourceCache::LoadFromXmlFile failed: %s (%s)", | ||||
| 				KGE_WARN(L"ResourceCache::LoadFromXmlFile failed: %s (%s)", | ||||
| 					tinyxml2::XMLDocument::ErrorIDToName(doc.ErrorID()), doc.ErrorStr()); | ||||
| 				return false; | ||||
| 			} | ||||
| 		} | ||||
| 		catch (std::wifstream::failure& e) | ||||
| 		{ | ||||
| 			KGE_WARNING_LOG(L"ResourceCache::LoadFromXmlFile failed: Cannot open file. (%s)", string_to_wide(e.what()).c_str()); | ||||
| 			KGE_WARN(L"ResourceCache::LoadFromXmlFile failed: Cannot open file. (%s)", oc::string_to_wide(e.what()).c_str()); | ||||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
|  | @ -183,7 +183,7 @@ namespace kiwano | |||
| 			} | ||||
| 			catch (std::exception& e) | ||||
| 			{ | ||||
| 				KGE_WARNING_LOG(L"ResourceCache::LoadFromXml failed: %s", string_to_wide(e.what()).c_str()); | ||||
| 				KGE_WARN(L"ResourceCache::LoadFromXml failed: %s", oc::string_to_wide(e.what()).c_str()); | ||||
| 				return false; | ||||
| 			} | ||||
| 		} | ||||
|  | @ -363,6 +363,8 @@ namespace kiwano | |||
| 	void ResourceCache::Clear() | ||||
| 	{ | ||||
| 		object_cache_.clear(); | ||||
| 		gif_cache_.clear(); | ||||
| 		font_collection_cache_.clear(); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -30,7 +30,7 @@ namespace kiwano | |||
| 	class KGE_API ResourceCache | ||||
| 		: public Singleton<ResourceCache> | ||||
| 	{ | ||||
| 		KGE_DECLARE_SINGLETON(ResourceCache); | ||||
| 		OC_DECLARE_SINGLETON(ResourceCache); | ||||
| 
 | ||||
| 	public: | ||||
| 		// 从 JSON 文件加载资源信息
 | ||||
|  |  | |||
|  | @ -27,7 +27,7 @@ namespace kiwano | |||
| 	class KGE_API UserData | ||||
| 		: public Singleton<UserData> | ||||
| 	{ | ||||
| 		KGE_DECLARE_SINGLETON(UserData); | ||||
| 		OC_DECLARE_SINGLETON(UserData); | ||||
| 
 | ||||
| 	public: | ||||
| 		using DataMap = UnorderedMap<String, Any>; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue