xpcom/base/nsAutoRef.h

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:73f9b5917418
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #ifndef nsAutoRef_h_
8 #define nsAutoRef_h_
9
10 #include "mozilla/Attributes.h"
11
12 #include "nscore.h" // for nullptr, bool
13
14 template <class T> class nsSimpleRef;
15 template <class T> class nsAutoRefBase;
16 template <class T> class nsReturnRef;
17 template <class T> class nsReturningRef;
18
19 /**
20 * template <class T> class nsAutoRef
21 *
22 * A class that holds a handle to a resource that must be released.
23 * No reference is added on construction.
24 *
25 * No copy constructor nor copy assignment operators are available, so the
26 * resource will be held until released on destruction or explicitly
27 * |reset()| or transferred through provided methods.
28 *
29 * The publicly available methods are the public methods on this class and its
30 * public base classes |nsAutoRefBase<T>| and |nsSimpleRef<T>|.
31 *
32 * For ref-counted resources see also |nsCountedRef<T>|.
33 * For function return values see |nsReturnRef<T>|.
34 *
35 * For each class |T|, |nsAutoRefTraits<T>| or |nsSimpleRef<T>| must be
36 * specialized to use |nsAutoRef<T>| and |nsCountedRef<T>|.
37 *
38 * @param T A class identifying the type of reference held by the
39 * |nsAutoRef<T>| and the unique set methods for managing references
40 * to the resource (defined by |nsAutoRefTraits<T>| or
41 * |nsSimpleRef<T>|).
42 *
43 * Often this is the class representing the resource. Sometimes a
44 * new possibly-incomplete class may need to be declared.
45 *
46 *
47 * Example: An Automatically closing file descriptor
48 *
49 * // References that are simple integral types (as file-descriptors are)
50 * // usually need a new class to represent the resource and how to handle its
51 * // references.
52 * class nsRawFD;
53 *
54 * // Specializing nsAutoRefTraits<nsRawFD> describes how to manage file
55 * // descriptors, so that nsAutoRef<nsRawFD> provides automatic closing of
56 * // its file descriptor on destruction.
57 * template <>
58 * class nsAutoRefTraits<nsRawFD> {
59 * public:
60 * // The file descriptor is held in an int.
61 * typedef int RawRef;
62 * // -1 means that there is no file associated with the handle.
63 * static int Void() { return -1; }
64 * // The file associated with a file descriptor is released with close().
65 * static void Release(RawRef aFD) { close(aFD); }
66 * };
67 *
68 * // A function returning a file descriptor that must be closed.
69 * nsReturnRef<nsRawFD> get_file(const char *filename) {
70 * // Constructing from a raw file descriptor assumes ownership.
71 * nsAutoRef<nsRawFD> fd(open(filename, O_RDONLY));
72 * fcntl(fd, F_SETFD, FD_CLOEXEC);
73 * return fd.out();
74 * }
75 *
76 * void f() {
77 * unsigned char buf[1024];
78 *
79 * // Hold a file descriptor for /etc/hosts in fd1.
80 * nsAutoRef<nsRawFD> fd1(get_file("/etc/hosts"));
81 *
82 * nsAutoRef<nsRawFD> fd2;
83 * fd2.steal(fd1); // fd2 takes the file descriptor from fd1
84 * ssize_t count = read(fd1, buf, 1024); // error fd1 has no file
85 * count = read(fd2, buf, 1024); // reads from /etc/hosts
86 *
87 * // If the file descriptor is not stored then it is closed.
88 * get_file("/etc/login.defs"); // login.defs is closed
89 *
90 * // Now use fd1 to hold a file descriptor for /etc/passwd.
91 * fd1 = get_file("/etc/passwd");
92 *
93 * // The nsAutoRef<nsRawFD> can give up the file descriptor if explicitly
94 * // instructed, but the caller must then ensure that the file is closed.
95 * int rawfd = fd1.disown();
96 *
97 * // Assume ownership of another file descriptor.
98 * fd1.own(open("/proc/1/maps");
99 *
100 * // On destruction, fd1 closes /proc/1/maps and fd2 closes /etc/hosts,
101 * // but /etc/passwd is not closed.
102 * }
103 *
104 */
105
106
107 template <class T>
108 class nsAutoRef : public nsAutoRefBase<T>
109 {
110 protected:
111 typedef nsAutoRef<T> ThisClass;
112 typedef nsAutoRefBase<T> BaseClass;
113 typedef nsSimpleRef<T> SimpleRef;
114 typedef typename BaseClass::RawRefOnly RawRefOnly;
115 typedef typename BaseClass::LocalSimpleRef LocalSimpleRef;
116
117 public:
118 nsAutoRef()
119 {
120 }
121
122 // Explicit construction is required so as not to risk unintentionally
123 // releasing the resource associated with a raw ref.
124 explicit nsAutoRef(RawRefOnly aRefToRelease)
125 : BaseClass(aRefToRelease)
126 {
127 }
128
129 // Construction from a nsReturnRef<T> function return value, which expects
130 // to give up ownership, transfers ownership.
131 // (nsReturnRef<T> is converted to const nsReturningRef<T>.)
132 explicit nsAutoRef(const nsReturningRef<T>& aReturning)
133 : BaseClass(aReturning)
134 {
135 }
136
137 // The only assignment operator provided is for transferring from an
138 // nsReturnRef smart reference, which expects to pass its ownership to
139 // another object.
140 //
141 // With raw references and other smart references, the type of the lhs and
142 // its taking and releasing nature is often not obvious from an assignment
143 // statement. Assignment from a raw ptr especially is not normally
144 // expected to release the reference.
145 //
146 // Use |steal| for taking ownership from other smart refs.
147 //
148 // For raw references, use |own| to indicate intention to have the
149 // resource released.
150 //
151 // Or, to create another owner of the same reference, use an nsCountedRef.
152
153 ThisClass& operator=(const nsReturningRef<T>& aReturning)
154 {
155 BaseClass::steal(aReturning.mReturnRef);
156 return *this;
157 }
158
159 // Conversion to a raw reference allow the nsAutoRef<T> to often be used
160 // like a raw reference.
161 operator typename SimpleRef::RawRef() const
162 {
163 return this->get();
164 }
165
166 // Transfer ownership from another smart reference.
167 void steal(ThisClass& aOtherRef)
168 {
169 BaseClass::steal(aOtherRef);
170 }
171
172 // Assume ownership of a raw ref.
173 //
174 // |own| has similar function to |steal|, and is useful for receiving
175 // ownership from a return value of a function. It is named differently
176 // because |own| requires more care to ensure that the function intends to
177 // give away ownership, and so that |steal| can be safely used, knowing
178 // that it won't steal ownership from any methods returning raw ptrs to
179 // data owned by a foreign object.
180 void own(RawRefOnly aRefToRelease)
181 {
182 BaseClass::own(aRefToRelease);
183 }
184
185 // Exchange ownership with |aOther|
186 void swap(ThisClass& aOther)
187 {
188 LocalSimpleRef temp;
189 temp.SimpleRef::operator=(*this);
190 SimpleRef::operator=(aOther);
191 aOther.SimpleRef::operator=(temp);
192 }
193
194 // Release the reference now.
195 void reset()
196 {
197 this->SafeRelease();
198 LocalSimpleRef empty;
199 SimpleRef::operator=(empty);
200 }
201
202 // Pass out the reference for a function return values.
203 nsReturnRef<T> out()
204 {
205 return nsReturnRef<T>(this->disown());
206 }
207
208 // operator->() and disown() are provided by nsAutoRefBase<T>.
209 // The default nsSimpleRef<T> provides get().
210
211 private:
212 // No copy constructor
213 explicit nsAutoRef(ThisClass& aRefToSteal);
214 };
215
216 /**
217 * template <class T> class nsCountedRef
218 *
219 * A class that creates (adds) a new reference to a resource on construction
220 * or assignment and releases on destruction.
221 *
222 * This class is similar to nsAutoRef<T> and inherits its methods, but also
223 * provides copy construction and assignment operators that enable more than
224 * one concurrent reference to the same resource.
225 *
226 * Specialize |nsAutoRefTraits<T>| or |nsSimpleRef<T>| to use this. This
227 * class assumes that the resource itself counts references and so can only be
228 * used when |T| represents a reference-counting resource.
229 */
230
231 template <class T>
232 class nsCountedRef : public nsAutoRef<T>
233 {
234 protected:
235 typedef nsCountedRef<T> ThisClass;
236 typedef nsAutoRef<T> BaseClass;
237 typedef nsSimpleRef<T> SimpleRef;
238 typedef typename BaseClass::RawRef RawRef;
239
240 public:
241 nsCountedRef()
242 {
243 }
244
245 // Construction and assignment from a another nsCountedRef
246 // or a raw ref copies and increments the ref count.
247 nsCountedRef(const ThisClass& aRefToCopy)
248 {
249 SimpleRef::operator=(aRefToCopy);
250 SafeAddRef();
251 }
252 ThisClass& operator=(const ThisClass& aRefToCopy)
253 {
254 if (this == &aRefToCopy)
255 return *this;
256
257 this->SafeRelease();
258 SimpleRef::operator=(aRefToCopy);
259 SafeAddRef();
260 return *this;
261 }
262
263 // Implicit conversion from another smart ref argument (to a raw ref) is
264 // accepted here because construction and assignment safely creates a new
265 // reference without interfering with the reference to copy.
266 explicit nsCountedRef(RawRef aRefToCopy)
267 : BaseClass(aRefToCopy)
268 {
269 SafeAddRef();
270 }
271 ThisClass& operator=(RawRef aRefToCopy)
272 {
273 this->own(aRefToCopy);
274 SafeAddRef();
275 return *this;
276 }
277
278 // Construction and assignment from an nsReturnRef function return value,
279 // which expects to give up ownership, transfers ownership.
280 explicit nsCountedRef(const nsReturningRef<T>& aReturning)
281 : BaseClass(aReturning)
282 {
283 }
284 ThisClass& operator=(const nsReturningRef<T>& aReturning)
285 {
286 BaseClass::operator=(aReturning);
287 return *this;
288 }
289
290 protected:
291 // Increase the reference count if there is a resource.
292 void SafeAddRef()
293 {
294 if (this->HaveResource())
295 this->AddRef(this->get());
296 }
297 };
298
299 /**
300 * template <class T> class nsReturnRef
301 *
302 * A type for function return values that hold a reference to a resource that
303 * must be released. See also |nsAutoRef<T>::out()|.
304 */
305
306 template <class T>
307 class nsReturnRef : public nsAutoRefBase<T>
308 {
309 protected:
310 typedef nsAutoRefBase<T> BaseClass;
311 typedef typename BaseClass::RawRefOnly RawRefOnly;
312
313 public:
314 // For constructing a return value with no resource
315 nsReturnRef()
316 {
317 }
318
319 // For returning a smart reference from a raw reference that must be
320 // released. Explicit construction is required so as not to risk
321 // unintentionally releasing the resource associated with a raw ref.
322 explicit nsReturnRef(RawRefOnly aRefToRelease)
323 : BaseClass(aRefToRelease)
324 {
325 }
326
327 // Copy construction transfers ownership
328 nsReturnRef(nsReturnRef<T>& aRefToSteal)
329 : BaseClass(aRefToSteal)
330 {
331 }
332
333 nsReturnRef(const nsReturningRef<T>& aReturning)
334 : BaseClass(aReturning)
335 {
336 }
337
338 // Conversion to a temporary (const) object referring to this object so
339 // that the reference may be passed from a function return value
340 // (temporary) to another smart reference. There is no need to use this
341 // explicitly. Simply assign a nsReturnRef<T> function return value to a
342 // smart reference.
343 operator nsReturningRef<T>()
344 {
345 return nsReturningRef<T>(*this);
346 }
347
348 // No conversion to RawRef operator is provided on nsReturnRef, to ensure
349 // that the return value is not carelessly assigned to a raw ptr (and the
350 // resource then released). If passing to a function that takes a raw
351 // ptr, use get or disown as appropriate.
352 };
353
354 /**
355 * template <class T> class nsReturningRef
356 *
357 * A class to allow ownership to be transferred from nsReturnRef function
358 * return values.
359 *
360 * It should not be necessary for clients to reference this
361 * class directly. Simply pass an nsReturnRef<T> to a parameter taking an
362 * |nsReturningRef<T>|.
363 *
364 * The conversion operator on nsReturnRef constructs a temporary wrapper of
365 * class nsReturningRef<T> around a non-const reference to the nsReturnRef.
366 * The wrapper can then be passed as an rvalue parameter.
367 */
368
369 template <class T>
370 class nsReturningRef
371 {
372 private:
373 friend class nsReturnRef<T>;
374
375 explicit nsReturningRef(nsReturnRef<T>& aReturnRef)
376 : mReturnRef(aReturnRef)
377 {
378 }
379 public:
380 nsReturnRef<T>& mReturnRef;
381 };
382
383 /**
384 * template <class T> class nsAutoRefTraits
385 *
386 * A class describing traits of references managed by the default
387 * |nsSimpleRef<T>| implementation and thus |nsAutoRef<T>| and |nsCountedRef|.
388 * The default |nsSimpleRef<T> is suitable for resources with handles that
389 * have a void value. (If there is no such void value for a handle,
390 * specialize |nsSimpleRef<T>|.)
391 *
392 * Specializations must be provided for each class |T| according to the
393 * following pattern:
394 *
395 * // The template parameter |T| should be a class such that the set of fields
396 * // in class nsAutoRefTraits<T> is unique for class |T|. Usually the
397 * // resource object class is sufficient. For handles that are simple
398 * // integral typedefs, a new unique possibly-incomplete class may need to be
399 * // declared.
400 *
401 * template <>
402 * class nsAutoRefTraits<T>
403 * {
404 * // Specializations must provide a typedef for RawRef, describing the
405 * // type of the handle to the resource.
406 * typedef <handle-type> RawRef;
407 *
408 * // Specializations should define Void(), a function returning a value
409 * // suitable for a handle that does not have an associated resource.
410 * //
411 * // The return type must be a suitable as the parameter to a RawRef
412 * // constructor and operator==.
413 * //
414 * // If this method is not accessible then some limited nsAutoRef
415 * // functionality will still be available, but the default constructor,
416 * // |reset|, and most transfer of ownership methods will not be available.
417 * static <return-type> Void();
418 *
419 * // Specializations must define Release() to properly finalize the
420 * // handle to a non-void custom-deleted or reference-counted resource.
421 * static void Release(RawRef aRawRef);
422 *
423 * // For reference-counted resources, if |nsCountedRef<T>| is to be used,
424 * // specializations must define AddRef to increment the reference count
425 * // held by a non-void handle.
426 * // (AddRef() is not necessary for |nsAutoRef<T>|.)
427 * static void AddRef(RawRef aRawRef);
428 * };
429 *
430 * See nsPointerRefTraits for example specializations for simple pointer
431 * references. See nsAutoRef for an example specialization for a non-pointer
432 * reference.
433 */
434
435 template <class T> class nsAutoRefTraits;
436
437 /**
438 * template <class T> class nsPointerRefTraits
439 *
440 * A convenience class useful as a base class for specializations of
441 * |nsAutoRefTraits<T>| where the handle to the resource is a pointer to |T|.
442 * By inheriting from this class, definitions of only Release(RawRef) and
443 * possibly AddRef(RawRef) need to be added.
444 *
445 * Examples of use:
446 *
447 * template <>
448 * class nsAutoRefTraits<PRFileDesc> : public nsPointerRefTraits<PRFileDesc>
449 * {
450 * public:
451 * static void Release(PRFileDesc *ptr) { PR_Close(ptr); }
452 * };
453 *
454 * template <>
455 * class nsAutoRefTraits<FcPattern> : public nsPointerRefTraits<FcPattern>
456 * {
457 * public:
458 * static void Release(FcPattern *ptr) { FcPatternDestroy(ptr); }
459 * static void AddRef(FcPattern *ptr) { FcPatternReference(ptr); }
460 * };
461 */
462
463 template <class T>
464 class nsPointerRefTraits
465 {
466 public:
467 // The handle is a pointer to T.
468 typedef T* RawRef;
469 // A nullptr does not have a resource.
470 static RawRef Void() { return nullptr; }
471 };
472
473 /**
474 * template <class T> class nsSimpleRef
475 *
476 * Constructs a non-smart reference, and provides methods to test whether
477 * there is an associated resource and (if so) get its raw handle.
478 *
479 * A default implementation is suitable for resources with handles that have a
480 * void value. This is not intended for direct use but used by |nsAutoRef<T>|
481 * and thus |nsCountedRef<T>|.
482 *
483 * Specialize this class if there is no particular void value for the resource
484 * handle. A specialized implementation must also provide Release(RawRef),
485 * and, if |nsCountedRef<T>| is required, AddRef(RawRef), as described in
486 * nsAutoRefTraits<T>.
487 */
488
489 template <class T>
490 class nsSimpleRef : protected nsAutoRefTraits<T>
491 {
492 protected:
493 // The default implementation uses nsAutoRefTrait<T>.
494 // Specializations need not define this typedef.
495 typedef nsAutoRefTraits<T> Traits;
496 // The type of the handle to the resource.
497 // A specialization must provide a typedef for RawRef.
498 typedef typename Traits::RawRef RawRef;
499
500 // Construct with no resource.
501 //
502 // If this constructor is not accessible then some limited nsAutoRef
503 // functionality will still be available, but the default constructor,
504 // |reset|, and most transfer of ownership methods will not be available.
505 nsSimpleRef()
506 : mRawRef(Traits::Void())
507 {
508 }
509 // Construct with a handle to a resource.
510 // A specialization must provide this.
511 nsSimpleRef(RawRef aRawRef)
512 : mRawRef(aRawRef)
513 {
514 }
515
516 // Test whether there is an associated resource. A specialization must
517 // provide this. The function is permitted to always return true if the
518 // default constructor is not accessible, or if Release (and AddRef) can
519 // deal with void handles.
520 bool HaveResource() const
521 {
522 return mRawRef != Traits::Void();
523 }
524
525 public:
526 // A specialization must provide get() or loose some functionality. This
527 // is inherited by derived classes and the specialization may choose
528 // whether it is public or protected.
529 RawRef get() const
530 {
531 return mRawRef;
532 }
533
534 private:
535 RawRef mRawRef;
536 };
537
538
539 /**
540 * template <class T> class nsAutoRefBase
541 *
542 * Internal base class for |nsAutoRef<T>| and |nsReturnRef<T>|.
543 * Adds release on destruction to a |nsSimpleRef<T>|.
544 */
545
546 template <class T>
547 class nsAutoRefBase : public nsSimpleRef<T>
548 {
549 protected:
550 typedef nsAutoRefBase<T> ThisClass;
551 typedef nsSimpleRef<T> SimpleRef;
552 typedef typename SimpleRef::RawRef RawRef;
553
554 nsAutoRefBase()
555 {
556 }
557
558 // A type for parameters that should be passed a raw ref but should not
559 // accept implicit conversions (from another smart ref). (The only
560 // conversion to this type is from a raw ref so only raw refs will be
561 // accepted.)
562 class RawRefOnly
563 {
564 public:
565 RawRefOnly(RawRef aRawRef)
566 : mRawRef(aRawRef)
567 {
568 }
569 operator RawRef() const
570 {
571 return mRawRef;
572 }
573 private:
574 RawRef mRawRef;
575 };
576
577 // Construction from a raw ref assumes ownership
578 explicit nsAutoRefBase(RawRefOnly aRefToRelease)
579 : SimpleRef(aRefToRelease)
580 {
581 }
582
583 // Constructors that steal ownership
584 explicit nsAutoRefBase(ThisClass& aRefToSteal)
585 : SimpleRef(aRefToSteal.disown())
586 {
587 }
588 explicit nsAutoRefBase(const nsReturningRef<T>& aReturning)
589 : SimpleRef(aReturning.mReturnRef.disown())
590 {
591 }
592
593 ~nsAutoRefBase()
594 {
595 SafeRelease();
596 }
597
598 // An internal class providing access to protected nsSimpleRef<T>
599 // constructors for construction of temporary simple references (that are
600 // not ThisClass).
601 class LocalSimpleRef : public SimpleRef
602 {
603 public:
604 LocalSimpleRef()
605 {
606 }
607 explicit LocalSimpleRef(RawRef aRawRef)
608 : SimpleRef(aRawRef)
609 {
610 }
611 };
612
613 private:
614 ThisClass& operator=(const ThisClass& aSmartRef) MOZ_DELETE;
615
616 public:
617 RawRef operator->() const
618 {
619 return this->get();
620 }
621
622 // Transfer ownership to a raw reference.
623 //
624 // THE CALLER MUST ENSURE THAT THE REFERENCE IS EXPLICITLY RELEASED.
625 //
626 // Is this really what you want to use? Using this removes any guarantee
627 // of release. Use nsAutoRef<T>::out() for return values, or an
628 // nsAutoRef<T> modifiable lvalue for an out parameter. Use disown() when
629 // the reference must be stored in a POD type object, such as may be
630 // preferred for a namespace-scope object with static storage duration,
631 // for example.
632 RawRef disown()
633 {
634 RawRef temp = this->get();
635 LocalSimpleRef empty;
636 SimpleRef::operator=(empty);
637 return temp;
638 }
639
640 protected:
641 // steal and own are protected because they make no sense on nsReturnRef,
642 // but steal is implemented on this class for access to aOtherRef.disown()
643 // when aOtherRef is an nsReturnRef;
644
645 // Transfer ownership from another smart reference.
646 void steal(ThisClass& aOtherRef)
647 {
648 own(aOtherRef.disown());
649 }
650 // Assume ownership of a raw ref.
651 void own(RawRefOnly aRefToRelease)
652 {
653 SafeRelease();
654 LocalSimpleRef ref(aRefToRelease);
655 SimpleRef::operator=(ref);
656 }
657
658 // Release a resource if there is one.
659 void SafeRelease()
660 {
661 if (this->HaveResource())
662 this->Release(this->get());
663 }
664 };
665
666 #endif // !defined(nsAutoRef_h_)

mercurial