remove common & use OuterC instead

This commit is contained in:
Nomango 2019-12-17 20:47:55 +08:00
parent 03edd40ecd
commit b53f77af05
87 changed files with 5167 additions and 5154 deletions

View File

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

View File

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

21
src/3rd-party/OuterC/LICENSE vendored Normal file
View File

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

View File

@ -1,32 +1,11 @@
// Copyright (c) 2018-2019 Kiwano - Nomango
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// Copyright (c) 2019-2020 OuterC - Nomango
#pragma once
#include <typeinfo>
#include <type_traits>
#include <exception>
namespace kiwano
{
namespace common
namespace oc
{
class bad_any_cast : public std::exception
@ -133,7 +112,7 @@ public:
template <typename _Ty>
const _Ty* cast_pointer() const noexcept
{
static_assert(!std::is_void<_Ty>::value, "kiwano::any cannot contain void");
static_assert(!std::is_void<_Ty>::value, "oc::any cannot contain void");
const type_info* const info = typeinfo();
if (info && (*info == typeid(std::decay<_Ty>::type)))
@ -519,14 +498,14 @@ _Ty any_cast(any&& a)
return static_cast<_Ty>(std::move(*ptr));
}
} // namespace common
} // namespace kiwano
} // namespace oc
namespace std
{
inline void swap(kiwano::common::any& lhs, kiwano::common::any& rhs) noexcept
{
lhs.swap(rhs);
}
inline void swap(oc::any& lhs, oc::any& rhs) noexcept
{
lhs.swap(rhs);
}
}

169
src/3rd-party/OuterC/oc/function.h vendored Normal file
View File

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

View File

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

254
src/3rd-party/OuterC/oc/intrusive_list.h vendored Normal file
View File

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

201
src/3rd-party/OuterC/oc/intrusive_ptr.h vendored Normal file
View File

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

50
src/3rd-party/OuterC/oc/json.h vendored Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

8
src/3rd-party/OuterC/oc/macros.h vendored Normal file
View File

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

19
src/3rd-party/OuterC/oc/noncopyable.h vendored Normal file
View File

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

13
src/3rd-party/OuterC/oc/oc.h vendored Normal file
View File

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

50
src/3rd-party/OuterC/oc/singleton.h vendored Normal file
View File

@ -0,0 +1,50 @@
// Copyright (c) 2019-2020 OuterC - Nomango
#pragma once
// Class that will implement the singleton mode must use the macro in its delare file
#ifndef OC_DECLARE_SINGLETON
#define OC_DECLARE_SINGLETON( CLASS ) \
friend ::oc::singleton< CLASS >;
#endif
namespace oc
{
template <typename _Ty>
struct singleton
{
protected:
singleton() = default;
singleton(const singleton&) = delete;
singleton& operator=(const singleton&) = delete;
private:
struct object_creator
{
object_creator()
{
(void)singleton<_Ty>::instance();
}
inline void dummy() const {}
};
static object_creator creator_;
public:
using object_type = _Ty;
static inline object_type& instance()
{
static object_type instance;
creator_.dummy();
return instance;
}
};
template <typename _Ty>
typename singleton<_Ty>::object_creator singleton<_Ty>::creator_;
} // namespace oc

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -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:
// 开启设备

View File

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

View File

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

View File

@ -19,7 +19,6 @@
// THE SOFTWARE.
#pragma once
#include <kiwano/common/intrusive_ptr.hpp>
#include <kiwano/core/ObjectBase.h>
#include <kiwano-audio/Sound.h>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -31,7 +31,7 @@ namespace kiwano
, stroke_color_(Color::White)
, stroke_style_(StrokeStyle::Miter)
{
Renderer::GetInstance()->CreateTextureRenderTarget(rt_);
Renderer::instance().CreateTextureRenderTarget(rt_);
}
Canvas::~Canvas()

View File

@ -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: ";
{

View File

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

View File

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

View File

@ -29,7 +29,7 @@ namespace kiwano
SetStage(this);
SetAnchor(Vec2{ 0, 0 });
SetSize(Renderer::GetInstance()->GetOutputSize());
SetSize(Renderer::instance().GetOutputSize());
}
Stage::~Stage()

View File

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

View File

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

View File

@ -28,24 +28,17 @@
#include <unordered_map>
#include <sstream>
#include <kiwano/common/vector.hpp>
#include <kiwano/common/string.hpp>
#include <kiwano/common/any.hpp>
#include <kiwano/common/intrusive_list.hpp>
#include <kiwano/common/intrusive_ptr.hpp>
#include <kiwano/common/noncopyable.hpp>
#include <kiwano/common/singleton.hpp>
#include <kiwano/common/function.hpp>
#include <kiwano/common/basic_json.hpp>
#include <3rd-party/OuterC/oc/oc.h>
#include <kiwano/macros.h>
namespace kiwano
{
using String = kiwano::common::wstring;
using String = oc::wstring;
using StringStream = std::wstringstream;
template <typename _Ty, typename... _Args>
using Vector = kiwano::common::vector<_Ty, _Args...>;
using Vector = oc::vector<_Ty, _Args...>;
template <typename _Ty, typename... _Args>
using List = std::list<_Ty, _Args...>;
@ -72,37 +65,38 @@ namespace kiwano
using UnorderedMap = std::unordered_map<_Kty, _Ty, _Args...>;
template <typename _FuncTy>
using Function = kiwano::common::function<_FuncTy>;
using Function = oc::function<_FuncTy>;
using Any = kiwano::common::any;
using Any = oc::any;
using Json = kiwano::common::basic_json<kiwano::Map, kiwano::Vector, kiwano::String,
int, double, bool, std::allocator>;
using Json = oc::basic_json<Map, Vector, String, int, double, bool, std::allocator>;
template <typename _Ty>
using Singleton = common::singleton<_Ty>;
using Singleton = oc::singleton<_Ty>;
template <typename _Ty>
using IntrusiveList = common::intrusive_list<_Ty>;
using IntrusiveList = oc::intrusive_list<_Ty>;
template <typename _Ty>
using IntrusiveListItem = common::intrusive_list_item<_Ty>;
}
using IntrusiveListItem = oc::intrusive_list_item<_Ty>;
namespace std
{
template<>
struct hash<::kiwano::Json>
template <typename _Ty, typename _RefProxyTy>
using IntrusivePtr = oc::intrusive_ptr<_Ty, _RefProxyTy>;
using Noncopyable = oc::noncopyable;
// Closure
template<typename _Ty, typename _Uty, typename _Ret, typename... _Args>
inline Function<_Ret(_Args...)> Closure(_Uty* ptr, _Ret(_Ty::* func)(_Args...))
{
size_t operator()(const ::kiwano::Json& json) const
{
return hash<::kiwano::Json::string_type>{}(json.dump());
}
};
return oc::closure(ptr, func);
}
template<>
inline void swap<::kiwano::Json>(::kiwano::Json& lhs, ::kiwano::Json& rhs) noexcept
template<typename _Ty, typename _Uty, typename _Ret, typename... _Args>
inline Function<_Ret(_Args...)> Closure(_Uty* ptr, _Ret(_Ty::* func)(_Args...) const)
{
lhs.swap(rhs);
return oc::closure(ptr, func);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -25,66 +25,52 @@
namespace
{
std::streambuf* cin_buffer, * cout_buffer, * cerr_buffer;
std::fstream console_input, console_output, console_error;
std::streambuf* cout_buffer, * cerr_buffer;
std::fstream console_output, console_error;
std::wstreambuf* wcin_buffer, * wcout_buffer, * wcerr_buffer;
std::wfstream wconsole_input, wconsole_output, wconsole_error;
std::wstreambuf* wcout_buffer, * wcerr_buffer;
std::wfstream wconsole_output, wconsole_error;
void RedirectStdIO()
{
cin_buffer = std::cin.rdbuf();
cout_buffer = std::cout.rdbuf();
cerr_buffer = std::cerr.rdbuf();
wcin_buffer = std::wcin.rdbuf();
wcout_buffer = std::wcout.rdbuf();
wcerr_buffer = std::wcerr.rdbuf();
console_input.open("CONIN$", std::ios::in);
console_output.open("CONOUT$", std::ios::out);
console_error.open("CONOUT$", std::ios::out);
wconsole_input.open("CONIN$", std::ios::in);
wconsole_output.open("CONOUT$", std::ios::out);
wconsole_error.open("CONOUT$", std::ios::out);
FILE* dummy;
freopen_s(&dummy, "CONOUT$", "w+t", stdout);
freopen_s(&dummy, "CONIN$", "r+t", stdin);
freopen_s(&dummy, "CONOUT$", "w+t", stderr);
(void)dummy;
std::cin.rdbuf(console_input.rdbuf());
std::cout.rdbuf(console_output.rdbuf());
std::cerr.rdbuf(console_error.rdbuf());
std::wcin.rdbuf(wconsole_input.rdbuf());
std::wcout.rdbuf(wconsole_output.rdbuf());
std::wcerr.rdbuf(wconsole_error.rdbuf());
}
void ResetStdIO()
{
console_input.close();
console_output.close();
console_error.close();
wconsole_input.close();
wconsole_output.close();
wconsole_error.close();
std::cin.rdbuf(cin_buffer);
std::cout.rdbuf(cout_buffer);
std::cerr.rdbuf(cerr_buffer);
std::wcin.rdbuf(wcin_buffer);
std::wcout.rdbuf(wcout_buffer);
std::wcerr.rdbuf(wcerr_buffer);
fclose(stdout);
fclose(stdin);
fclose(stderr);
cin_buffer = nullptr;
cout_buffer = nullptr;
cerr_buffer = nullptr;
wcin_buffer = nullptr;
wcout_buffer = nullptr;
wcerr_buffer = nullptr;
}
@ -125,17 +111,17 @@ namespace kiwano
{
namespace __console_colors
{
const WORD _blue = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
const WORD _green = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
const WORD _red = FOREGROUND_RED | FOREGROUND_INTENSITY;
const WORD _yellow = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
const WORD _white = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
const WORD _blue = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
const WORD _green = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
const WORD _red = FOREGROUND_RED | FOREGROUND_INTENSITY;
const WORD _yellow = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
const WORD _white = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
const WORD _blue_bg = _white | BACKGROUND_BLUE | BACKGROUND_INTENSITY;
const WORD _green_bg = _white | BACKGROUND_GREEN | BACKGROUND_INTENSITY;
const WORD _red_bg = _white | BACKGROUND_RED | BACKGROUND_INTENSITY;
const WORD _yellow_bg = BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY;
const WORD _white_bg = BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY;
const WORD _blue_bg = _white | BACKGROUND_BLUE | BACKGROUND_INTENSITY;
const WORD _green_bg = _white | BACKGROUND_GREEN | BACKGROUND_INTENSITY;
const WORD _red_bg = _white | BACKGROUND_RED | BACKGROUND_INTENSITY;
const WORD _yellow_bg = BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY;
const WORD _white_bg = BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY;
const WORD _reset = _white;
@ -202,6 +188,11 @@ namespace kiwano
default_stderr_color_ = stderr_info.wAttributes;
}
// replace the C++ global locale with the user-preferred locale
(void)std::locale::global(std::locale(""));
(void)std::wcout.imbue(std::locale());
(void)std::wcerr.imbue(std::locale());
RedirectOutputStreamBuffer(std::wcout.rdbuf());
RedirectErrorStreamBuffer(std::wcerr.rdbuf());
}
@ -298,10 +289,12 @@ namespace kiwano
std::wostream& Logger::OutPrefix(std::wostream& out)
{
out << L"[KIWANO] ";
time_t unix = std::time(nullptr);
std::tm tmbuf;
localtime_s(&tmbuf, &unix);
out << std::put_time(&tmbuf, L"[kiwano] %H:%M:%S");
out << std::put_time(&tmbuf, L"%H:%M:%S");
return out;
}
@ -319,7 +312,7 @@ namespace kiwano
HWND console = ::AllocateConsole();
if (!console)
{
KGE_WARNING_LOG(L"AllocConsole failed");
KGE_WARN(L"AllocConsole failed");
}
else
{

View File

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

View File

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

View File

@ -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:
// 增加引用计数

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -50,7 +50,7 @@ namespace kiwano
// 应用
class KGE_API Application
: protected common::noncopyable
: protected Noncopyable
{
public:
Application();

View File

@ -31,7 +31,7 @@ namespace kiwano
, public RenderComponent
, public EventComponent
{
KGE_DECLARE_SINGLETON(Director);
OC_DECLARE_SINGLETON(Director);
public:
// Çл»Îę̀

View File

@ -27,7 +27,7 @@ namespace kiwano
class KGE_API FileSystem
: public Singleton<FileSystem>
{
KGE_DECLARE_SINGLETON(FileSystem);
OC_DECLARE_SINGLETON(FileSystem);
public:
// 添加文件搜索路径

View File

@ -140,4 +140,8 @@ namespace kiwano
{
return Point{ mouse_pos_x_, mouse_pos_y_ };
}
void Input::Destroy()
{
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -130,7 +130,7 @@ namespace kiwano
// 几何体生成器
class KGE_API GeometrySink
: protected common::noncopyable
: protected Noncopyable
{
public:
GeometrySink();

View File

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

View File

@ -41,7 +41,7 @@ namespace kiwano
// äÖȾĿ±ê
class KGE_API RenderTarget
: public common::noncopyable
: public Noncopyable
{
public:
bool IsValid() const;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -30,7 +30,7 @@ namespace kiwano
class KGE_API ResourceCache
: public Singleton<ResourceCache>
{
KGE_DECLARE_SINGLETON(ResourceCache);
OC_DECLARE_SINGLETON(ResourceCache);
public:
// 从 JSON 文件加载资源信息

View File

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