1 // Copyright (C) 2007  Davis E. King (davis@dlib.net)
2 // License: Boost Software License   See LICENSE.txt for the full license.
3 #ifndef DLIB_WEAK_PTr_
4 #define DLIB_WEAK_PTr_
5 
6 #include <algorithm>
7 #include <memory>
8 #include "shared_ptr.h"
9 #include "../algs.h"
10 #include "weak_ptr_abstract.h"
11 
12 namespace dlib {
13 
14     template <
15         typename T
16         >
17     class weak_ptr
18     {
19 
20         /*!
21             CONVENTION
22                 - if (weak_node != 0) then
23                     - data == valid pointer to shared data
24                     - weak_node->ref_count == the number of weak_ptrs that reference this->data
25                 - else
26                     - data == 0
27 
28                 - expired() == ((weak_node == 0) || (weak_node->shared_node == 0))
29                 - if (expired() == false) then
30                     - use_count() == weak_node->shared_node->ref_count
31                 - else
32                     - use_count() == 0
33         !*/
34 
35     public:
36         typedef T element_type;
37 
weak_ptr()38         weak_ptr(
39         ) : data(0), weak_node(0)
40         {
41         }
42 
43         template<typename Y>
weak_ptr(const shared_ptr<Y> & r)44         weak_ptr(
45             const shared_ptr<Y>& r
46         )
47         {
48             data = r.data;
49             if (r.shared_node)
50             {
51                 if (r.shared_node->weak_node)
52                 {
53                     weak_node = r.shared_node->weak_node;
54                     weak_node->ref_count += 1;
55                 }
56                 else
57                 {
58                     weak_node = new weak_ptr_node(r.shared_node);
59                     r.shared_node->weak_node = weak_node;
60                 }
61             }
62             else
63             {
64                 weak_node = 0;
65             }
66         }
67 
weak_ptr(const weak_ptr & r)68         weak_ptr(
69             const weak_ptr& r
70         )
71         {
72             data = r.data;
73             weak_node = r.weak_node;
74             if (weak_node)
75                 weak_node->ref_count += 1;
76         }
77 
78         template<typename Y>
weak_ptr(const weak_ptr<Y> & r)79         weak_ptr(
80             const weak_ptr<Y>& r
81         )
82         {
83             data = r.data;
84             weak_node = r.weak_node;
85             if (weak_node)
86                 weak_node->ref_count += 1;
87         }
88 
~weak_ptr()89         ~weak_ptr(
90         )
91         {
92             if (weak_node)
93             {
94                 // make note that this weak_ptr is being destroyed
95                 weak_node->ref_count -= 1;
96 
97                 // if this is the last weak_ptr then we should clean up our stuff
98                 if (weak_node->ref_count == 0)
99                 {
100                     if (expired() == false)
101                         weak_node->shared_node->weak_node = 0;
102                     delete weak_node;
103                 }
104             }
105         }
106 
107         weak_ptr& operator= (
108             const weak_ptr& r
109         )
110         {
111             weak_ptr(r).swap(*this);
112             return *this;
113         }
114 
115         template<typename Y>
116         weak_ptr& operator= (
117             const weak_ptr<Y>& r
118         )
119         {
120             weak_ptr(r).swap(*this);
121             return *this;
122         }
123 
124         template<typename Y>
125         weak_ptr& operator=(
126             const shared_ptr<Y>& r
127         )
128         {
129             weak_ptr(r).swap(*this);
130             return *this;
131         }
132 
use_count()133         long use_count(
134         ) const
135         {
136             if (expired())
137                 return 0;
138             else
139                 return weak_node->shared_node->ref_count;
140         }
141 
expired()142         bool expired() const { return weak_node == 0 || weak_node->shared_node == 0; }
143 
lock()144         shared_ptr<T> lock(
145         ) const
146         {
147             if (expired())
148                 return shared_ptr<T>();
149             else
150                 return shared_ptr<T>(*this);
151         }
152 
reset()153         void reset(
154         )
155         {
156             weak_ptr().swap(*this);
157         }
158 
swap(weak_ptr<T> & b)159         void swap(
160             weak_ptr<T>& b
161         )
162         {
163             std::swap(data, b.data);
164             std::swap(weak_node, b.weak_node);
165         }
166 
167         template <typename Y>
_private_less(const weak_ptr<Y> & rhs)168         bool _private_less (
169             const weak_ptr<Y>& rhs
170         ) const
171         {
172             if (expired())
173             {
174                 if (rhs.expired())
175                 {
176                     return false;
177                 }
178                 else
179                 {
180                     return true;
181                 }
182             }
183             else
184             {
185                 if (rhs.expired())
186                 {
187                     return false;
188                 }
189                 else
190                 {
191                     // in this case they have both not expired so lets
192                     // compare the shared_node pointers
193                     return (weak_node->shared_node) < (rhs.weak_node->shared_node);
194                 }
195             }
196         }
197 
198     private:
199 
200         template <typename Y> friend class shared_ptr;
201         template <typename Y> friend class weak_ptr;
202 
203         T* data;
204         weak_ptr_node* weak_node;
205     };
206 
207     template<typename T, typename U>
208     bool operator< (
209         const weak_ptr<T>& a,
210         const weak_ptr<U>& b
211     )
212     {
213         return a._private_less(b);
214     }
215 
216     template<typename T>
swap(weak_ptr<T> & a,weak_ptr<T> & b)217     void swap(
218         weak_ptr<T>& a,
219         weak_ptr<T> & b
220     ) { a.swap(b); }
221 }
222 
223 #endif // DLIB_WEAK_PTr_
224 
225 
226