+/** hazptr_obj_batch */
+/* Only for default domain. Supports only hazptr_obj_base_refcounted
+ * and a thread-safe access only, for now. */
+
+class hazptr_obj_batch {
+ static constexpr size_t DefaultThreshold = 20;
+ hazptr_obj* head_{nullptr};
+ hazptr_obj* tail_{nullptr};
+ size_t rcount_{0};
+ size_t threshold_{DefaultThreshold};
+
+ public:
+ hazptr_obj_batch() {}
+ hazptr_obj_batch(hazptr_obj* head, hazptr_obj* tail, size_t rcount)
+ : head_(head), tail_(tail), rcount_(rcount) {}
+
+ ~hazptr_obj_batch() {
+ retire_all();
+ }
+
+ /* Prepare a hazptr_obj_base_refcounted for retirement but don't
+ push it the domain yet. Return true if the batch is ready. */
+ template <typename T, typename D = std::default_delete<T>>
+ hazptr_obj_batch prep_retire_refcounted(
+ hazptr_obj_base_refcounted<T, D>* obj,
+ D deleter = {}) {
+ obj->preRetire(deleter);
+ obj->next_ = head_;
+ head_ = obj;
+ if (tail_ == nullptr) {
+ tail_ = obj;
+ }
+ if (++rcount_ < threshold_) {
+ return hazptr_obj_batch();
+ } else {
+ auto head = head_;
+ auto tail = tail_;
+ auto rcount = rcount_;
+ clear();
+ return hazptr_obj_batch(head, tail, rcount);
+ }
+ }
+
+ bool empty() {
+ return rcount_ == 0;
+ }
+
+ void retire_all() {
+ if (!empty()) {
+ auto& domain = default_hazptr_domain();
+ domain.pushRetired(head_, tail_, rcount_);
+ domain.tryBulkReclaim();
+ clear();
+ }
+ }
+
+ void set_threshold(size_t thresh) {
+ threshold_ = thresh;
+ }
+
+ private:
+ void clear() {
+ head_ = nullptr;
+ tail_ = nullptr;
+ rcount_ = 0;
+ }
+};
+