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
|
||||
|
||||
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
|
||||
|
|
@ -1,22 +1,4 @@
|
|||
// 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 <string>
|
||||
|
|
@ -27,9 +9,7 @@
|
|||
#include <cstring>
|
||||
#include <cstdio>
|
||||
|
||||
namespace kiwano
|
||||
{
|
||||
namespace common
|
||||
namespace oc
|
||||
{
|
||||
|
||||
//
|
||||
|
|
@ -425,8 +405,8 @@ basic_string<wchar_t> format_string(const wchar_t* const fmt, _Args&& ... args);
|
|||
//
|
||||
// string && wstring
|
||||
//
|
||||
using string = ::kiwano::common::basic_string<char>;
|
||||
using wstring = ::kiwano::common::basic_string<wchar_t>;
|
||||
using string = ::oc::basic_string<char>;
|
||||
using wstring = ::oc::basic_string<wchar_t>;
|
||||
|
||||
|
||||
inline string to_string(int val) { return to_basic_string<char>(val); }
|
||||
|
|
@ -450,10 +430,9 @@ inline wstring to_wstring(double val) { return to_basic_string<wchar_t>(val);
|
|||
inline wstring to_wstring(long double val) { return to_basic_string<wchar_t>(val); }
|
||||
|
||||
|
||||
} // namespace common
|
||||
} // namespace kiwano
|
||||
} // namespace oc
|
||||
|
||||
namespace kiwano
|
||||
namespace oc
|
||||
{
|
||||
|
||||
//
|
||||
|
|
@ -515,8 +494,6 @@ namespace __string_details
|
|||
}
|
||||
}
|
||||
|
||||
namespace common
|
||||
{
|
||||
|
||||
template <typename _CharTy>
|
||||
inline basic_string<_CharTy>::basic_string()
|
||||
|
|
@ -1159,31 +1136,31 @@ namespace common
|
|||
//
|
||||
|
||||
template <typename _CharTy>
|
||||
inline basic_string<_CharTy> basic_string<_CharTy>::parse(int val) { return ::kiwano::common::to_basic_string<char_type>(val); }
|
||||
inline basic_string<_CharTy> basic_string<_CharTy>::parse(int val) { return ::oc::to_basic_string<char_type>(val); }
|
||||
|
||||
template <typename _CharTy>
|
||||
inline basic_string<_CharTy> basic_string<_CharTy>::parse(unsigned int val) { return ::kiwano::common::to_basic_string<char_type>(val); }
|
||||
inline basic_string<_CharTy> basic_string<_CharTy>::parse(unsigned int val) { return ::oc::to_basic_string<char_type>(val); }
|
||||
|
||||
template <typename _CharTy>
|
||||
inline basic_string<_CharTy> basic_string<_CharTy>::parse(long val) { return ::kiwano::common::to_basic_string<char_type>(val); }
|
||||
inline basic_string<_CharTy> basic_string<_CharTy>::parse(long val) { return ::oc::to_basic_string<char_type>(val); }
|
||||
|
||||
template <typename _CharTy>
|
||||
inline basic_string<_CharTy> basic_string<_CharTy>::parse(unsigned long val) { return ::kiwano::common::to_basic_string<char_type>(val); }
|
||||
inline basic_string<_CharTy> basic_string<_CharTy>::parse(unsigned long val) { return ::oc::to_basic_string<char_type>(val); }
|
||||
|
||||
template <typename _CharTy>
|
||||
inline basic_string<_CharTy> basic_string<_CharTy>::parse(long long val) { return ::kiwano::common::to_basic_string<char_type>(val); }
|
||||
inline basic_string<_CharTy> basic_string<_CharTy>::parse(long long val) { return ::oc::to_basic_string<char_type>(val); }
|
||||
|
||||
template <typename _CharTy>
|
||||
inline basic_string<_CharTy> basic_string<_CharTy>::parse(unsigned long long val) { return ::kiwano::common::to_basic_string<char_type>(val); }
|
||||
inline basic_string<_CharTy> basic_string<_CharTy>::parse(unsigned long long val) { return ::oc::to_basic_string<char_type>(val); }
|
||||
|
||||
template <typename _CharTy>
|
||||
inline basic_string<_CharTy> basic_string<_CharTy>::parse(float val) { return ::kiwano::common::to_basic_string<char_type>(val); }
|
||||
inline basic_string<_CharTy> basic_string<_CharTy>::parse(float val) { return ::oc::to_basic_string<char_type>(val); }
|
||||
|
||||
template <typename _CharTy>
|
||||
inline basic_string<_CharTy> basic_string<_CharTy>::parse(double val) { return ::kiwano::common::to_basic_string<char_type>(val); }
|
||||
inline basic_string<_CharTy> basic_string<_CharTy>::parse(double val) { return ::oc::to_basic_string<char_type>(val); }
|
||||
|
||||
template <typename _CharTy>
|
||||
inline basic_string<_CharTy> basic_string<_CharTy>::parse(long double val) { return ::kiwano::common::to_basic_string<char_type>(val); }
|
||||
inline basic_string<_CharTy> basic_string<_CharTy>::parse(long double val) { return ::oc::to_basic_string<char_type>(val); }
|
||||
|
||||
//
|
||||
// details of basic_string::format
|
||||
|
|
@ -1193,7 +1170,7 @@ namespace common
|
|||
template <typename ..._Args>
|
||||
inline basic_string<_CharTy> basic_string<_CharTy>::format(const char_type* fmt, _Args&& ... args)
|
||||
{
|
||||
return ::kiwano::common::format_string(fmt, std::forward<_Args>(args)...);
|
||||
return ::oc::format_string(fmt, std::forward<_Args>(args)...);
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -1515,10 +1492,10 @@ namespace common
|
|||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace kiwano
|
||||
namespace oc
|
||||
{
|
||||
|
||||
template <typename _Codecvt, typename _Elem = wchar_t>
|
||||
|
|
@ -1527,8 +1504,8 @@ class string_convert
|
|||
enum : size_t { BUFFER_INCREASE = 8, BUFFER_MAX = 16 };
|
||||
|
||||
public:
|
||||
using byte_string = ::kiwano::common::basic_string<char>;
|
||||
using wide_string = ::kiwano::common::basic_string<_Elem>;
|
||||
using byte_string = ::oc::basic_string<char>;
|
||||
using wide_string = ::oc::basic_string<_Elem>;
|
||||
using codecvt_type = _Codecvt;
|
||||
using state_type = typename codecvt_type::state_type;
|
||||
using int_type = typename wide_string::traits_type::int_type;
|
||||
|
|
@ -1605,7 +1582,8 @@ public:
|
|||
case codecvt_type::noconv:
|
||||
{
|
||||
// no conversion, just copy code values
|
||||
for (; first != last; ++first) {
|
||||
for (; first != last; ++first)
|
||||
{
|
||||
wstr.push_back(static_cast<_Elem>(*first));
|
||||
}
|
||||
break;
|
||||
|
|
@ -1702,63 +1680,62 @@ class chs_codecvt
|
|||
public:
|
||||
chs_codecvt() : codecvt_byname("chs") {}
|
||||
|
||||
static inline ::kiwano::common::wstring string_to_wide(::kiwano::common::string const& str)
|
||||
static inline ::oc::wstring string_to_wide(::oc::string const& str)
|
||||
{
|
||||
string_convert<chs_codecvt> conv;
|
||||
return conv.from_bytes(str);
|
||||
}
|
||||
|
||||
static inline ::kiwano::common::string wide_to_string(::kiwano::common::wstring const& str)
|
||||
static inline ::oc::string wide_to_string(::oc::wstring const& str)
|
||||
{
|
||||
string_convert<chs_codecvt> conv;
|
||||
return conv.to_bytes(str);
|
||||
}
|
||||
};
|
||||
|
||||
inline ::kiwano::common::wstring string_to_wide(::kiwano::common::string const& str)
|
||||
inline ::oc::wstring string_to_wide(::oc::string const& str)
|
||||
{
|
||||
return kiwano::chs_codecvt::string_to_wide(str);
|
||||
return oc::chs_codecvt::string_to_wide(str);
|
||||
}
|
||||
|
||||
inline ::kiwano::common::string wide_to_string(::kiwano::common::wstring const& str)
|
||||
inline ::oc::string wide_to_string(::oc::wstring const& str)
|
||||
{
|
||||
return kiwano::chs_codecvt::wide_to_string(str);
|
||||
return oc::chs_codecvt::wide_to_string(str);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace oc
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template<>
|
||||
struct hash<::kiwano::common::string>
|
||||
struct hash<::oc::string>
|
||||
{
|
||||
inline size_t operator()(const ::kiwano::common::string& key) const
|
||||
inline size_t operator()(const ::oc::string& key) const
|
||||
{
|
||||
return key.hash();
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct hash<::kiwano::common::wstring>
|
||||
struct hash<::oc::wstring>
|
||||
{
|
||||
inline size_t operator()(const ::kiwano::common::wstring& key) const
|
||||
inline size_t operator()(const ::oc::wstring& key) const
|
||||
{
|
||||
return key.hash();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<>
|
||||
inline void swap<::kiwano::common::string>(::kiwano::common::string& lhs, ::kiwano::common::string& rhs) noexcept
|
||||
inline void swap<::oc::string>(::oc::string& lhs, ::oc::string& rhs) noexcept
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void swap<::kiwano::common::wstring>(::kiwano::common::wstring& lhs, ::kiwano::common::wstring& rhs) noexcept
|
||||
inline void swap<::oc::wstring>(::oc::wstring& lhs, ::oc::wstring& rhs) noexcept
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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>;
|
||||
|
||||
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...))
|
||||
{
|
||||
return oc::closure(ptr, func);
|
||||
}
|
||||
|
||||
namespace std
|
||||
template<typename _Ty, typename _Uty, typename _Ret, typename... _Args>
|
||||
inline Function<_Ret(_Args...)> Closure(_Uty* ptr, _Ret(_Ty::* func)(_Args...) const)
|
||||
{
|
||||
template<>
|
||||
struct hash<::kiwano::Json>
|
||||
{
|
||||
size_t operator()(const ::kiwano::Json& json) const
|
||||
{
|
||||
return hash<::kiwano::Json::string_type>{}(json.dump());
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
inline void swap<::kiwano::Json>(::kiwano::Json& lhs, ::kiwano::Json& rhs) noexcept
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
|
@ -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