1 #ifndef PROTON_REF_HEADER
2 #define PROTON_REF_HEADER
11 #include <type_traits>
12 #include <proton/pool.hpp>
13 #include <initializer_list>
15 #ifndef PROTON_REF_DEBUG
16 #define PROTON_REF_LOG(lvl, out)
18 #define PROTON_REF_LOG PROTON_LOG
32 refc_t(
const refc_t& r):__r(0)
35 refc_t& operator=(
const refc_t& r)
40 bool operator<(
long i)
const
45 bool operator==(
long i)
const
75 extern init_alloc
alloc;
77 class init_alloc_inner{};
78 extern init_alloc_inner alloc_inner;
84 template<
typename refT>
bool is_null(
const refT& x)
86 return &x.__o()==NULL;
93 template<
typename refT>
bool is_valid(
const refT& x)
95 return &x.__o()!=NULL;
101 #define PROTON_COPY_DECL(type)\
102 virtual void copy_to(void* p)const\
104 new (p) type(*this);\
110 #define PROTON_COPY_DECL_NV(type)\
111 void copy_to(void* p)const\
113 new (p) type(*this);\
123 template<
typename refT> refT
copy(
const refT& x)
127 typedef typename refT::alloc_t alloc_t;
128 detail::refc_t* p=(detail::refc_t*)alloc_t::duplicate(x._rp);
129 new (p) detail::refc_t();
130 typename refT::obj_t* q=(
typename refT::obj_t *)(p+1);
131 x->copy_to((
void*)q);
132 return refT(alloc_inner,p,q);
138 template<
typename refT>
void reset(refT& x)
150 return x._rp->count();
160 template<
typename T,
typename refT> T
cast(
const refT& x)
162 static_assert(std::is_class<typename T::proton_ref_self_t>(),
"The target type is not a ref_ type");
165 typedef typename T::obj_t target_t;
166 target_t* p=
dynamic_cast<target_t*
>(x._p);
168 return T(alloc_inner, x._rp, p);
169 throw std::bad_cast();
176 template<
typename objT,
typename allocator=smart_allocator<objT> >
struct ref_ {
177 friend void reset<ref_>(
ref_& x);
178 friend ref_ copy<ref_>(
const ref_& x);
179 friend long ref_count<ref_>(
const ref_& x);
180 template<
typename T,
typename ref_>
friend T cast(
const ref_& x);
184 typedef std::ostream proton_ostream_t;
186 typedef allocator alloc_t;
189 detail::refc_t * _rp;
193 void enter(detail::refc_t* rp)
203 long r=_rp->release();
206 alloc_t::confiscate(_rp);
219 PROTON_REF_LOG(9,
"default ctor");
223 ref_(init_alloc_inner, detail::refc_t* rp, objT* p):_rp(rp), _p(p)
225 PROTON_REF_LOG(9,
"alloc_inner ctor");
233 template<
typename ...argT>
explicit ref_(init_alloc, argT&& ...a)
235 PROTON_REF_LOG(9,
"alloc fwd ctor");
240 typedef typename alloc_t::template rebind<ref_obj_t>::other real_alloc;
241 ref_obj_t* p=real_alloc::allocate(1);
243 new (&(p->r)) detail::refc_t();
244 new (&p->o) obj_t(a...);
260 template<
typename T>
explicit ref_(init_alloc, std::initializer_list<T> a)
262 PROTON_REF_LOG(9,
"alloc initializer_list fwd ctor");
267 typedef typename alloc_t::template rebind<ref_obj_t>::other real_alloc;
268 ref_obj_t* p=real_alloc::allocate(1);
270 new (&(p->r)) detail::refc_t();
271 new (&p->o) obj_t(a);
280 template<
typename T>
explicit ref_(std::initializer_list<T> a):
ref_(
alloc,a)
287 PROTON_REF_LOG(9,
"const copy ctor");
293 PROTON_REF_LOG(9,
"copy ctor");
299 PROTON_REF_LOG(9,
"copy rvalue ctor");
307 PROTON_REF_LOG(9,
"move ctor");
316 PROTON_REF_LOG(9,
"assign lvalue");
318 detail::refc_t* rp_old=_rp;
325 long r=rp_old->release();
328 alloc_t::confiscate(rp_old);
339 PROTON_REF_LOG(9,
"assign rvalue");
341 detail::refc_t* rp_old=_rp;
350 long r=rp_old->release();
353 alloc_t::confiscate(rp_old);
362 ~ref_()noexcept(noexcept(_p->~objT()))
375 template<
typename baseT>
operator const baseT& ()
const
377 PROTON_REF_LOG(9,
"const baseT&()");
378 static_assert(std::is_class<typename baseT::proton_ref_self_t>(),
"The target type is not a ref_ type");
379 static_assert(std::is_base_of<typename baseT::obj_t, obj_t>(),
"The target type is not a base type of obj_t");
380 static_assert(static_cast<typename baseT::obj_t*>((obj_t*)4096)==(
typename baseT::obj_t*)4096,
"can not convert to a non-first-base ref_");
381 return reinterpret_cast<const baseT&
>(*this);
386 template<
typename derivedT,
387 typename=
typename std::enable_if<
388 std::is_base_of<obj_t, derivedT>::value
391 ref_(
const ref_<derivedT>& x)noexcept:_rp(x._rp), _p(static_cast<obj_t*>(x._p))
399 template<
typename baseT,
400 typename=
typename std::enable_if<
401 std::is_base_of<baseT, obj_t>::value
402 &&
static_cast<baseT*
>((obj_t*)4096)==(baseT*)4096
405 operator const ref_<baseT>& ()
const noexcept
407 PROTON_REF_LOG(9,
"const baseT&()");
408 return reinterpret_cast<const ref_<baseT>&
>(*this);
415 template<
typename baseT,
416 typename=
typename std::enable_if<
417 std::is_base_of<baseT, obj_t>::value
423 PROTON_REF_LOG(9,
"baseT()");
424 return ref_<baseT>(alloc_inner, _rp,
static_cast<baseT*
>(_p));
429 const objT& __o()
const
445 const objT& operator *()
const
469 static_assert(std::is_class<typename T::proton_ref_self_t>(),
470 "The target type is not a ref_ type");
471 if((
void*)&(__o())==(
void*)&(x.__o()))
475 return __o() == x.__o();
478 template<
typename T>
bool operator!=(
const T& x)
const
488 static_assert(std::is_class<typename T::proton_ref_self_t>(),
489 "The target type is not a ref_ type");
490 if((
void*)&(x.__o())==(
void*)&(__o()))
496 return __o() < x.__o();
499 template<
typename T>
bool operator>=(
const T& x)
const
504 template<
typename T>
bool operator>(
const T& x)
const
509 template<
typename T>
bool operator<=(
const T& x)
const
517 template<
typename ...T>
auto operator()(T&& ...x)const -> decltype((*_p)(x...))
526 template<
typename ...T>
auto operator()(T&& ...x) -> decltype((*_p)(x...))
535 template<
typename T>
auto operator[](T&& x)const -> decltype((*_p)[x])
544 template<
typename T>
auto operator[](T&& x) -> decltype((*_p)[x])
555 template<
typename T>std::ostream& operator<<(
typename T::proton_ostream_t& s,
571 #define PROTON_KEY_DECL(type)\
572 bool operator<(const type& y)const\
574 return key()<y.key();\
577 bool operator==(const type& y)const\
579 return key()==y.key();\
589 size_t operator()(
const T& x)
const
594 typedef decltype(x->key()) ref_t;
595 typedef typename std::remove_reference<ref_t>::type const_key_t;
596 typedef typename std::remove_cv<const_key_t>::type key_t;
597 return std::hash<key_t>()(x->key());
610 size_t operator()(
const T& x)
const
612 typedef decltype(std::get<key_seq>(x->key())) ref_t;
613 typedef typename std::remove_reference<ref_t>::type const_key_t;
614 typedef typename std::remove_cv<const_key_t>::type key_t;
618 return std::hash<key_t>()(std::get<key_seq>(x->key()));
628 #endif // PROTON_REF_HEADER