SynchronizedPtr.h 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /*
  2. * Copyright 2017-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #pragma once
  17. #include <folly/Synchronized.h>
  18. /* `SynchronizedPtr` is a variation on the `Synchronized` idea that's useful for
  19. * some cases where you want to protect a pointed-to object (or an object within
  20. * some pointer-like wrapper). If you would otherwise need to use
  21. * `Synchronized<smart_ptr<Synchronized<T>>>` consider using
  22. * `SynchronizedPtr<smart_ptr<T>>`as it is a bit easier to use and it works when
  23. * you want the `T` object at runtime to actually a subclass of `T`.
  24. *
  25. * You can access the contained `T` with `.rlock()`, and `.wlock()`, and the
  26. * pointer or pointer-like wrapper with `.wlockPointer()`. The corresponding
  27. * `with...` methods take a callback, invoke it with a `T const&`, `T&` or
  28. * `smart_ptr<T>&` respectively, and return the callback's result.
  29. */
  30. namespace folly {
  31. template <typename LockHolder, typename Element>
  32. struct SynchronizedPtrLockedElement {
  33. explicit SynchronizedPtrLockedElement(LockHolder&& holder)
  34. : holder_(std::move(holder)) {}
  35. Element& operator*() const {
  36. return **holder_;
  37. }
  38. Element* operator->() const {
  39. return &**holder_;
  40. }
  41. explicit operator bool() const {
  42. return static_cast<bool>(*holder_);
  43. }
  44. private:
  45. LockHolder holder_;
  46. };
  47. template <typename PointerType, typename MutexType = SharedMutex>
  48. class SynchronizedPtr {
  49. using inner_type = Synchronized<PointerType, MutexType>;
  50. inner_type inner_;
  51. public:
  52. using pointer_type = PointerType;
  53. using element_type = typename std::pointer_traits<pointer_type>::element_type;
  54. using const_element_type = typename std::add_const<element_type>::type;
  55. using read_locked_element = SynchronizedPtrLockedElement<
  56. typename inner_type::ConstLockedPtr,
  57. const_element_type>;
  58. using write_locked_element = SynchronizedPtrLockedElement<
  59. typename inner_type::LockedPtr,
  60. element_type>;
  61. using write_locked_pointer = typename inner_type::LockedPtr;
  62. template <typename... Args>
  63. explicit SynchronizedPtr(Args... args)
  64. : inner_(std::forward<Args>(args)...) {}
  65. SynchronizedPtr() = default;
  66. SynchronizedPtr(SynchronizedPtr const&) = default;
  67. SynchronizedPtr(SynchronizedPtr&&) = default;
  68. SynchronizedPtr& operator=(SynchronizedPtr const&) = default;
  69. SynchronizedPtr& operator=(SynchronizedPtr&&) = default;
  70. // Methods to provide appropriately locked and const-qualified access to the
  71. // element.
  72. read_locked_element rlock() const {
  73. return read_locked_element(inner_.rlock());
  74. }
  75. template <class Function>
  76. auto withRLock(Function&& function) const {
  77. return function(*rlock());
  78. }
  79. write_locked_element wlock() {
  80. return write_locked_element(inner_.wlock());
  81. }
  82. template <class Function>
  83. auto withWLock(Function&& function) {
  84. return function(*wlock());
  85. }
  86. // Methods to provide write-locked access to the pointer. We deliberately make
  87. // it difficult to get a read-locked pointer because that provides read-locked
  88. // non-const access to the element, and the purpose of this class is to
  89. // discourage that.
  90. write_locked_pointer wlockPointer() {
  91. return inner_.wlock();
  92. }
  93. template <class Function>
  94. auto withWLockPointer(Function&& function) {
  95. return function(*wlockPointer());
  96. }
  97. };
  98. } // namespace folly