+/**
+ * hazptr_array
+ */
+
+template <size_t M>
+FOLLY_ALWAYS_INLINE hazptr_array<M>::hazptr_array() {
+ auto h = reinterpret_cast<hazptr_holder*>(&raw_);
+ if (HAZPTR_TC) {
+ auto ptc = hazptr_tc_tls();
+ if (LIKELY(ptc != nullptr)) {
+ auto& tc = *ptc;
+ auto count = tc.count();
+ if (M <= count) {
+ size_t offset = count - M;
+ for (size_t i = 0; i < M; ++i) {
+ auto hprec = tc[offset + i].hprec_;
+ DCHECK(hprec != nullptr);
+ DEBUG_PRINT(i << " " << &h[i]);
+ new (&h[i]) hazptr_holder(nullptr);
+ h[i].hazptr_ = hprec;
+ DEBUG_PRINT(
+ i << " " << &h[i] << " " << h[i].domain_ << " " << h[i].hazptr_);
+ }
+ tc.count_ = offset;
+ return;
+ }
+ }
+ }
+ // slow path
+ for (size_t i = 0; i < M; ++i) {
+ new (&h[i]) hazptr_holder;
+ DEBUG_PRINT(
+ i << " " << &h[i] << " " << h[i].domain_ << " " << h[i].hazptr_);
+ }
+}
+
+template <size_t M>
+FOLLY_ALWAYS_INLINE hazptr_array<M>::hazptr_array(
+ hazptr_array&& other) noexcept {
+ DEBUG_PRINT(this << " " << M << " " << &other);
+ auto h = reinterpret_cast<hazptr_holder*>(&raw_);
+ for (size_t i = 0; i < M; ++i) {
+ new (&h[i]) hazptr_holder(std::move(other.h_[i]));
+ DEBUG_PRINT(i << " " << &h[i] << " " << &other.h_[i]);
+ }
+ empty_ = other.empty_;
+ other.empty_ = true;
+}
+
+template <size_t M>
+FOLLY_ALWAYS_INLINE hazptr_array<M>::hazptr_array(std::nullptr_t) noexcept {
+ DEBUG_PRINT(this << " " << M);
+ auto h = reinterpret_cast<hazptr_holder*>(&raw_);
+ for (size_t i = 0; i < M; ++i) {
+ new (&h[i]) hazptr_holder(nullptr);
+ DEBUG_PRINT(i << " " << &h[i]);
+ }
+ empty_ = true;
+}
+
+template <size_t M>
+FOLLY_ALWAYS_INLINE hazptr_array<M>::~hazptr_array() {
+ if (empty_) {
+ return;
+ }
+ auto h = reinterpret_cast<hazptr_holder*>(&raw_);
+ if (HAZPTR_TC) {
+ auto ptc = hazptr_tc_tls();
+ if (LIKELY(ptc != nullptr)) {
+ auto& tc = *ptc;
+ auto count = tc.count();
+ if ((M <= HAZPTR_TC_SIZE) && (count + M <= HAZPTR_TC_SIZE)) {
+ for (size_t i = 0; i < M; ++i) {
+ tc[count + i].hprec_ = h[i].hazptr_;
+ DEBUG_PRINT(i << " " << &h[i]);
+ new (&h[i]) hazptr_holder(nullptr);
+ DEBUG_PRINT(
+ i << " " << &h[i] << " " << h[i].domain_ << " " << h[i].hazptr_);
+ }
+ tc.count_ = count + M;
+ return;
+ }
+ }
+ }
+ // slow path
+ for (size_t i = 0; i < M; ++i) {
+ h[i].~hazptr_holder();
+ }
+}
+
+template <size_t M>
+FOLLY_ALWAYS_INLINE hazptr_array<M>& hazptr_array<M>::operator=(
+ hazptr_array&& other) noexcept {
+ DEBUG_PRINT(this << " " << M << " " << &other);
+ auto h = reinterpret_cast<hazptr_holder*>(&raw_);
+ for (size_t i = 0; i < M; ++i) {
+ h[i] = std::move(other[i]);
+ DEBUG_PRINT(i << " " << &h[i] << " " << &other[i]);
+ }
+ empty_ = other.empty_;
+ other.empty_ = true;
+ return *this;
+}
+
+template <size_t M>
+FOLLY_ALWAYS_INLINE hazptr_holder& hazptr_array<M>::operator[](
+ size_t i) noexcept {
+ auto h = reinterpret_cast<hazptr_holder*>(&raw_);
+ DCHECK(i < M);
+ return h[i];
+}
+
+/**
+ * hazptr_local
+ */
+
+template <size_t M>
+FOLLY_ALWAYS_INLINE hazptr_local<M>::hazptr_local() {
+ auto h = reinterpret_cast<hazptr_holder*>(&raw_);
+ if (HAZPTR_TC) {
+ auto ptc = hazptr_tc_tls();
+ if (LIKELY(ptc != nullptr)) {
+ auto& tc = *ptc;
+ auto count = tc.count();
+ if (M <= count) {
+ if (kIsDebug) {
+ DCHECK(!tc.local_);
+ tc.local_ = true;
+ }
+ // Fast path
+ for (size_t i = 0; i < M; ++i) {
+ auto hprec = tc[i].hprec_;
+ DCHECK(hprec != nullptr);
+ DEBUG_PRINT(i << " " << &h[i]);
+ new (&h[i]) hazptr_holder(nullptr);
+ h[i].hazptr_ = hprec;
+ DEBUG_PRINT(
+ i << " " << &h[i] << " " << h[i].domain_ << " " << h[i].hazptr_);
+ }
+ return;
+ }
+ }
+ }
+ // Slow path
+ need_destruct_ = true;
+ for (size_t i = 0; i < M; ++i) {
+ new (&h[i]) hazptr_holder;
+ DEBUG_PRINT(
+ i << " " << &h[i] << " " << h[i].domain_ << " " << h[i].hazptr_);
+ }
+}
+
+template <size_t M>
+FOLLY_ALWAYS_INLINE hazptr_local<M>::~hazptr_local() {
+ if (LIKELY(!need_destruct_)) {
+ if (kIsDebug) {
+ auto ptc = hazptr_tc_tls();
+ DCHECK(ptc != nullptr);
+ auto& tc = *ptc;
+ DCHECK(tc.local_);
+ tc.local_ = false;
+ }
+ return;
+ }
+ // Slow path
+ auto h = reinterpret_cast<hazptr_holder*>(&raw_);
+ for (size_t i = 0; i < M; ++i) {
+ h[i].~hazptr_holder();
+ }
+}
+
+template <size_t M>
+FOLLY_ALWAYS_INLINE hazptr_holder& hazptr_local<M>::operator[](
+ size_t i) noexcept {
+ auto h = reinterpret_cast<hazptr_holder*>(&raw_);
+ DCHECK(i < M);
+ return h[i];
+}
+