]> source.dussan.org Git - rspamd.git/commitdiff
[Minor] Add a simple shared ptr with no atomics
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 22 Jul 2021 14:30:39 +0000 (15:30 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 22 Jul 2021 14:30:39 +0000 (15:30 +0100)
src/libutil/cxx/local_shared_ptr.hxx [new file with mode: 0644]

diff --git a/src/libutil/cxx/local_shared_ptr.hxx b/src/libutil/cxx/local_shared_ptr.hxx
new file mode 100644 (file)
index 0000000..8c87514
--- /dev/null
@@ -0,0 +1,165 @@
+/*-
+ * Copyright 2021 Vsevolod Stakhov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RSPAMD_LOCAL_SHARED_PTR_HXX
+#define RSPAMD_LOCAL_SHARED_PTR_HXX
+
+#pragma once
+
+#include <memory>
+#include <algorithm> // for std::swap
+#include <cstddef> // for std::size_t
+#include <functional> // for std::less
+
+/*
+ * Smart pointers with no atomic refcounts to speed up Rspamd which is
+ * apparently single threaded
+ */
+namespace rspamd {
+
+template <class T>
+class local_weak_ptr {
+       typedef T element_type;
+
+};
+
+template <class T>
+class local_shared_ptr {
+public:
+       typedef T element_type;
+       typedef local_weak_ptr<T> weak_type;
+
+       // Simplified comparing to libc++, no custom deleter and no rebind here
+       // constructors:
+       constexpr local_shared_ptr() noexcept : px(nullptr), cnt(nullptr) {}
+
+       template<class Y, typename std::enable_if<
+               std::is_convertible<Y*, element_type*>::value, bool>::type = true>
+       explicit local_shared_ptr(Y* p) : px(p), cnt(new local_shared_ptr::control) {
+               cnt->add_shared();
+       }
+
+       local_shared_ptr(const local_shared_ptr& r) noexcept : px(r.px), cnt(r.cnt) {
+               if (cnt) {
+                       cnt->add_shared();
+               }
+       }
+       local_shared_ptr(local_shared_ptr&& r) noexcept : px(r.px), cnt(r.cnt) {
+               r.px = nullptr;
+               r.cnt = nullptr;
+       }
+       template<class Y> explicit local_shared_ptr(const local_weak_ptr<Y>& r);
+       local_shared_ptr(nullptr_t) : local_shared_ptr() { }
+
+       ~local_shared_ptr() {
+               if (cnt) {
+                       if (cnt->release_shared() <= 0) {
+                               delete px;
+                               px = nullptr;
+
+                               if (cnt->release_weak() <= 0) {
+                                       delete cnt;
+                               }
+                       }
+               }
+       }
+
+       // assignment:
+       local_shared_ptr& operator=(const local_shared_ptr& r) noexcept {
+               local_shared_ptr(r).swap(*this);
+               return *this;
+       }
+       local_shared_ptr& operator=(local_shared_ptr&& r) noexcept {
+               local_shared_ptr(std::move(r)).swap(*this);
+               return *this;
+       }
+
+       // Mutators
+       void swap(local_shared_ptr& r) noexcept {
+               std::swap(this->cnt, r.cnt);
+               std::swap(this->px, r.px);
+       }
+       void reset() noexcept {
+               local_shared_ptr().swap(*this);
+       }
+
+       // Observers:
+       T* get() const noexcept {
+               return px;
+       }
+
+       T& operator*() const noexcept {
+               return *px;
+       }
+       T* operator->() const noexcept {
+               return px;
+       }
+       long use_count() const noexcept {
+               if (cnt) {
+                       return cnt->shared_count();
+               }
+
+               return 0;
+       }
+       bool unique() const noexcept {
+               return use_count() == 1;
+       }
+
+       explicit operator bool() const noexcept {
+               return px != nullptr;
+       }
+
+       template<class Y, typename std::enable_if<
+                       std::is_convertible<Y*, element_type*>::value, bool>::type = true>
+       auto operator ==(const local_shared_ptr<Y> &other) const -> bool {
+               return px == other.px;
+       }
+
+       template<class Y, typename std::enable_if<
+                       std::is_convertible<Y*, element_type*>::value, bool>::type = true>
+       auto operator <(const local_shared_ptr<Y> &other) const -> auto {
+               return *px < *other.px;
+       }
+
+private:
+       class control {
+       public:
+               using refcount_t = int;
+
+               constexpr auto add_shared() -> refcount_t {
+                       return ++ref_shared;
+               }
+               constexpr auto release_shared() -> refcount_t {
+                       return --ref_shared;
+               }
+               constexpr auto release_weak() -> refcount_t {
+                       return --ref_weak;
+               }
+               constexpr auto shared_count() const -> refcount_t {
+                       return ref_shared;
+               }
+       private:
+               refcount_t ref_weak = 0;
+               refcount_t ref_shared = 0;
+       };
+
+       T *px; // contained pointer
+       control *cnt;
+};
+
+}
+
+#endif //RSPAMD_LOCAL_SHARED_PTR_HXX