1 //===-- jitcs_adt_ref.h -----------------------------------------*- C++ -*-===//
2 // An attributed pointer class.
4 // Copyright (C) 2013-2014 Dirk Steinke.
5 // See copyright and license notice in COPYRIGHT or include/jitcs.h
7 // A Ref or RefOrNull pointer object NEVER owns the object pointed to.
8 // A Ref pointer can never contain a null pointer. A RefOrNull object cannot
9 // directly use the -> operator. You can check for isNull(), and
10 // removeNullType() if it is not.
11 // (The principle of this is taken from the language Ceylon which, according
12 // to my understanding, handles null pointers quite nicely.)
13 //===----------------------------------------------------------------------===//
15 #ifndef _JITCS_ADT_REF_H_
16 #define _JITCS_ADT_REF_H_
19 #include <type_traits>
28 template <bool b
, typename
= typename
std::enable_if
<b
,int>::type
>
29 void guarantee(const char *) {}
31 // _Ref is an attributed pointer type.
32 // Currently it supports the const-attribute of its data, and
33 // the nonnull-attribute of the pointer.
35 template <typename T
, unsigned FLAGS
>
37 typedef typename
std::add_const
<T
>::type CType
;
39 static const bool IsConstRef
= (FLAGS
& REF_Const
) != 0;
40 typedef typename
std::conditional
<IsConstRef
, CType
, NCType
>::type Type
;
41 typedef Type
* PtrType
;
42 typedef Type
& RefType
;
45 guarantee
<(FLAGS
& REF_Nullable
) != 0>
46 ("Default constructor only for nullable refs");
50 _Ref(const _Ref
&) = default;
51 _Ref
& operator = (const _Ref
&) = default;
56 PtrType
operator ->() {
57 guarantee
<(FLAGS
& REF_Nullable
) == 0>
58 ("dereferencing only for non-nullable refs, remove nullable first");
61 RefType
operator *() {
62 guarantee
<(FLAGS
& REF_Nullable
) == 0>
63 ("dereferencing only for non-nullable refs, remove nullable first");
67 template <typename T2
, unsigned FLAGS2
>
68 _Ref(_Ref
<T2
, FLAGS2
> o
) {
69 static_assert((~FLAGS
& FLAGS2
) == 0, "incompatible _Ref flags");
70 //static_assert(std::is_base_of<T, T2>::value, "incompatible _Ref types");
74 template <typename T2
>
76 typedef typename
std::remove_const
<T2
>::type T2B
;
77 //static_assert(std::is_base_of<T, T2B>::value, "incompatible _Ref types");
78 if ((FLAGS
& REF_Nullable
) == 0)
83 _Ref(std::nullptr_t
) {
84 guarantee
<(FLAGS
& REF_Nullable
) != 0>("nullptr not allowed here");
89 template <typename T2
, unsigned FLAGS2
>
90 _Ref
& operator =(_Ref
<T2
, FLAGS2
> o
) {
91 static_assert((~FLAGS
& FLAGS2
) == 0, "incompatible _Ref flags");
92 //static_assert(std::is_base_of<T, T2>::value, "incompatible _Ref types");
94 _isValid
= o
._isValid
;
96 template <typename T2
>
97 _Ref
& operator =(T2
* o
) {
98 typedef typename
std::remove_const
<T2
>::type T2B
;
99 //static_assert(std::is_base_of<T, T2B>::value, "incompatible _Ref types");
100 if ((FLAGS
& REF_Nullable
) == 0)
101 assert(o
!= nullptr);
105 _Ref
& operator =(std::nullptr_t
) {
106 guarantee
<(FLAGS
& REF_Nullable
) != 0>("nullptr not allowed here");
112 bool isNull() const {
113 if ((FLAGS
& REF_Nullable
) == 0)
115 return _ptr
== nullptr;
117 _Ref
<T
,FLAGS
& ~REF_Nullable
> removeNullType() const {
118 if ((FLAGS
& REF_Nullable
) == 0)
120 assert(_ptr
!= nullptr);
128 // Ref represents a nonnull pointer to some object.
130 template <typename T
>
131 using Ref
= _Ref
<typename
std::remove_const
<T
>::type
,
132 (std::is_const
<T
>::value
? REF_Const
: REF_Any
)>;
134 // RefOrNull represents a normal pointer to some object. Accessing the
135 // data is achieved thru removeNullType, after which the "->" operator
136 // is accessible. Calling removeNullType without checking isNull first
137 // is considered a bug.
138 // The concept is taken from the Ceylon language which handles null
139 // pointers very nicely thru a clever type system.
141 template <typename T
>
142 using RefOrNull
= _Ref
<typename
std::remove_const
<T
>::type
,
143 (std::is_const
<T
>::value
? REF_Const
: REF_Any
)
145 } // end of namespace jitcs