fix the concurrent compact container with timestamps

This commit is contained in:
Laurent Rineau 2025-01-31 18:07:59 +01:00
parent eb0da467ed
commit 5853673267
3 changed files with 50 additions and 74 deletions

View File

@ -220,6 +220,10 @@ class Compact_container
CGAL_INCREMENT_COMPACT_CONTAINER_BLOCK_SIZE> CGAL_INCREMENT_COMPACT_CONTAINER_BLOCK_SIZE>
>::type Increment_policy; >::type Increment_policy;
typedef TimeStamper_ Ts; typedef TimeStamper_ Ts;
template <typename U> using EraseCounterStrategy =
internal::Erase_counter_strategy<internal::has_increment_erase_counter<U>::value>;
typedef Compact_container <T, Al, Ip, Ts> Self; typedef Compact_container <T, Al, Ip, Ts> Self;
typedef Compact_container_traits <T> Traits; typedef Compact_container_traits <T> Traits;
public: public:
@ -354,7 +358,7 @@ public:
return all_items[block_number].first[index_in_block]; return all_items[block_number].first[index_in_block];
} }
friend void swap(Compact_container& a, Compact_container b) { friend void swap(Compact_container& a, Compact_container b) noexcept {
a.swap(b); a.swap(b);
} }
@ -390,22 +394,16 @@ public:
// (just forward the arguments to the constructor, to optimize a copy). // (just forward the arguments to the constructor, to optimize a copy).
template < typename... Args > template < typename... Args >
iterator iterator
emplace(const Args&... args) emplace(Args&&... args)
{ {
if (free_list == nullptr) if (free_list == nullptr)
allocate_new_block(); allocate_new_block();
pointer ret = free_list; pointer ret = free_list;
free_list = clean_pointee(ret); free_list = clean_pointee(ret);
std::size_t ts; const auto ts = Time_stamper::time_stamp(ret);
CGAL_USE(ts); std::allocator_traits<allocator_type>::construct(alloc, ret, std::forward<Args>(args)...);
if constexpr (Time_stamper::has_timestamp) { Time_stamper::restore_timestamp(ret, ts);
ts = ret->time_stamp();
}
new (ret) value_type(args...);
if constexpr (Time_stamper::has_timestamp) {
ret->set_time_stamp(ts);
}
Time_stamper::set_time_stamp(ret, time_stamp); Time_stamper::set_time_stamp(ret, time_stamp);
CGAL_assertion(type(ret) == USED); CGAL_assertion(type(ret) == USED);
++size_; ++size_;
@ -414,24 +412,7 @@ public:
iterator insert(const T &t) iterator insert(const T &t)
{ {
if (free_list == nullptr) return emplace(t);
allocate_new_block();
pointer ret = free_list;
free_list = clean_pointee(ret);
std::size_t ts;
CGAL_USE(ts);
if constexpr (Time_stamper::has_timestamp) {
ts = ret->time_stamp();
}
std::allocator_traits<allocator_type>::construct(alloc, ret, t);
if constexpr (Time_stamper::has_timestamp) {
ret->set_time_stamp(ts);
}
Time_stamper::set_time_stamp(ret, time_stamp);
CGAL_assertion(type(ret) == USED);
++size_;
return iterator(ret, 0);
} }
template < class InputIterator > template < class InputIterator >
@ -450,22 +431,14 @@ public:
void erase(iterator x) void erase(iterator x)
{ {
typedef internal::Erase_counter_strategy< auto ptr = &*x;
internal::has_increment_erase_counter<T>::value> EraseCounterStrategy; CGAL_precondition(type(ptr) == USED);
EraseCounterStrategy<T>::increment_erase_counter(*x);
const auto ts = Time_stamper::time_stamp(ptr);
std::allocator_traits<allocator_type>::destroy(alloc, ptr);
Time_stamper::restore_timestamp(ptr, ts);
CGAL_precondition(type(&*x) == USED); put_on_free_list(ptr);
EraseCounterStrategy::increment_erase_counter(*x);
std::size_t ts;
CGAL_USE(ts);
if constexpr (Time_stamper::has_timestamp) {
ts = x->time_stamp();
}
std::allocator_traits<allocator_type>::destroy(alloc, &*x);
if constexpr (Time_stamper::has_timestamp) {
x->set_time_stamp(ts);
}
put_on_free_list(&*x);
--size_; --size_;
} }
@ -697,7 +670,7 @@ public:
static bool is_begin_or_end(const_pointer ptr) static bool is_begin_or_end(const_pointer ptr)
{ return type(ptr)==START_END; } { return type(ptr)==START_END; }
void swap(Self &c) void swap(Self &c) noexcept
{ {
std::swap(alloc, c.alloc); std::swap(alloc, c.alloc);
std::swap(capacity_, c.capacity_); std::swap(capacity_, c.capacity_);
@ -805,9 +778,6 @@ void Compact_container<T, Allocator, Increment_policy, TimeStamper>::clear()
template < class T, class Allocator, class Increment_policy, class TimeStamper > template < class T, class Allocator, class Increment_policy, class TimeStamper >
void Compact_container<T, Allocator, Increment_policy, TimeStamper>::allocate_new_block() void Compact_container<T, Allocator, Increment_policy, TimeStamper>::allocate_new_block()
{ {
typedef internal::Erase_counter_strategy<
internal::has_increment_erase_counter<T>::value> EraseCounterStrategy;
pointer new_block = alloc.allocate(block_size + 2); pointer new_block = alloc.allocate(block_size + 2);
all_items.push_back(std::make_pair(new_block, block_size + 2)); all_items.push_back(std::make_pair(new_block, block_size + 2));
capacity_ += block_size; capacity_ += block_size;
@ -816,7 +786,7 @@ void Compact_container<T, Allocator, Increment_policy, TimeStamper>::allocate_ne
// will correspond to the iterator order... // will correspond to the iterator order...
for (size_type i = block_size; i >= 1; --i) for (size_type i = block_size; i >= 1; --i)
{ {
EraseCounterStrategy::set_erase_counter(*(new_block + i), 0); EraseCounterStrategy<T>::set_erase_counter(*(new_block + i), 0);
Time_stamper::initialize_time_stamp(new_block + i); Time_stamper::initialize_time_stamp(new_block + i);
put_on_free_list(new_block + i); put_on_free_list(new_block + i);
} }

View File

@ -202,6 +202,9 @@ class Concurrent_compact_container
typedef Concurrent_compact_container <T, Al> Self; typedef Concurrent_compact_container <T, Al> Self;
typedef Concurrent_compact_container_traits <T> Traits; typedef Concurrent_compact_container_traits <T> Traits;
template <typename U> using EraseCounterStrategy =
internal::Erase_counter_strategy<internal::has_increment_erase_counter<U>::value>;
public: public:
typedef CGAL::Time_stamper_impl<T> Time_stamper; typedef CGAL::Time_stamper_impl<T> Time_stamper;
typedef Time_stamper Time_stamper_impl; // backward compatibility typedef Time_stamper Time_stamper_impl; // backward compatibility
@ -344,28 +347,21 @@ public:
// (just forward the arguments to the constructor, to optimize a copy). // (just forward the arguments to the constructor, to optimize a copy).
template < typename... Args > template < typename... Args >
iterator iterator
emplace(const Args&... args) emplace(Args&&... args)
{ {
typedef CCC_internal::Erase_counter_strategy<
CCC_internal::has_increment_erase_counter<T>::value> EraseCounterStrategy;
FreeList * fl = get_free_list(); FreeList * fl = get_free_list();
pointer ret = init_insert(fl); pointer ret = init_insert(fl);
auto erase_counter = EraseCounterStrategy::erase_counter(*ret);; auto erase_counter = EraseCounterStrategy<T>::erase_counter(*ret);
new (ret) value_type(args...); const auto ts = Time_stamper::time_stamp(ret);
EraseCounterStrategy::set_erase_counter(*ret, erase_counter); std::allocator_traits<allocator_type>::construct(m_alloc, ret, std::forward<Args>(args)...);
Time_stamper::restore_timestamp(ret, ts);
EraseCounterStrategy<T>::set_erase_counter(*ret, erase_counter);
return finalize_insert(ret, fl); return finalize_insert(ret, fl);
} }
iterator insert(const T &t) iterator insert(const T &t)
{ {
typedef CCC_internal::Erase_counter_strategy< return emplace(t);
CCC_internal::has_increment_erase_counter<T>::value> EraseCounterStrategy;
FreeList * fl = get_free_list();
pointer ret = init_insert(fl);
auto erase_counter = EraseCounterStrategy::erase_counter(*ret);;
std::allocator_traits<allocator_type>::construct(m_alloc, ret, t);
EraseCounterStrategy::set_erase_counter(*ret, erase_counter);
return finalize_insert(ret, fl);
} }
template < class InputIterator > template < class InputIterator >
@ -385,13 +381,13 @@ public:
private: private:
void erase(iterator x, FreeList * fl) void erase(iterator x, FreeList * fl)
{ {
typedef CCC_internal::Erase_counter_strategy<
CCC_internal::has_increment_erase_counter<T>::value> EraseCounterStrategy;
CGAL_precondition(type(x) == USED); CGAL_precondition(type(x) == USED);
EraseCounterStrategy::increment_erase_counter(*x); EraseCounterStrategy<T>::increment_erase_counter(*x);
auto ptr = &*x;
const auto ts = Time_stamper::time_stamp(ptr);
std::allocator_traits<allocator_type>::destroy(m_alloc, &*x); std::allocator_traits<allocator_type>::destroy(m_alloc, &*x);
Time_stamper::restore_timestamp(ptr, ts);
put_on_free_list(&*x, fl); put_on_free_list(&*x, fl);
} }
@ -778,9 +774,6 @@ template < class T, class Allocator >
void Concurrent_compact_container<T, Allocator>:: void Concurrent_compact_container<T, Allocator>::
allocate_new_block(FreeList * fl) allocate_new_block(FreeList * fl)
{ {
typedef CCC_internal::Erase_counter_strategy<
CCC_internal::has_increment_erase_counter<T>::value> EraseCounterStrategy;
size_type old_block_size; size_type old_block_size;
pointer new_block; pointer new_block;
@ -818,7 +811,7 @@ void Concurrent_compact_container<T, Allocator>::
// will correspond to the iterator order... // will correspond to the iterator order...
for (size_type i = old_block_size; i >= 1; --i) for (size_type i = old_block_size; i >= 1; --i)
{ {
EraseCounterStrategy::set_erase_counter(*(new_block + i), 0); EraseCounterStrategy<T>::set_erase_counter(*(new_block + i), 0);
Time_stamper::initialize_time_stamp(new_block + i); Time_stamper::initialize_time_stamp(new_block + i);
put_on_free_list(new_block + i, fl); put_on_free_list(new_block + i, fl);
} }

View File

@ -30,13 +30,17 @@ struct Time_stamper
{ {
static constexpr bool has_timestamp = true; static constexpr bool has_timestamp = true;
static bool is_valid(const T* pt) {
return pt != nullptr && pt->time_stamp() != std::size_t(-2);
}
static void initialize_time_stamp(T* pt) { static void initialize_time_stamp(T* pt) {
pt->set_time_stamp(std::size_t(-1)); pt->set_time_stamp(std::size_t(-1));
} }
template <typename time_stamp_t> template <typename time_stamp_t>
static void set_time_stamp(T* pt, time_stamp_t& time_stamp_) { static void set_time_stamp(T* pt, time_stamp_t& time_stamp_) {
CGAL_assertion(pt->time_stamp() != std::size_t(-2)); CGAL_assertion(is_valid(pt));
if(pt->time_stamp() == std::size_t(-1)) { if(pt->time_stamp() == std::size_t(-1)) {
const std::size_t new_ts = time_stamp_++; const std::size_t new_ts = time_stamp_++;
pt->set_time_stamp(new_ts); pt->set_time_stamp(new_ts);
@ -64,13 +68,18 @@ struct Time_stamper
static std::size_t time_stamp(const T* pt) static std::size_t time_stamp(const T* pt)
{ {
CGAL_assertion(pt == nullptr || pt->time_stamp() != std::size_t(-2)); CGAL_assertion(is_valid(pt));
if(pt == nullptr){ if(pt == nullptr){
return std::size_t(-1); return std::size_t(-1);
} }
return pt->time_stamp(); return pt->time_stamp();
} }
static void restore_timestamp(T* pt, std::size_t ts)
{
pt->set_time_stamp(ts);
}
static auto display_id(const T* pt, int offset = 0) static auto display_id(const T* pt, int offset = 0)
{ {
if(pt == nullptr) if(pt == nullptr)
@ -80,7 +89,7 @@ struct Time_stamper
} }
static std::size_t hash_value(const T* p) { static std::size_t hash_value(const T* p) {
CGAL_assertion(p == nullptr || p->time_stamp() != std::size_t(-2)); CGAL_assertion(is_valid(p));
if(nullptr == p) if(nullptr == p)
return std::size_t(-1); return std::size_t(-1);
else else
@ -116,6 +125,10 @@ public:
return 0; return 0;
} }
static void restore_timestamp(T*, std::size_t)
{
}
static auto display_id(const T* pt, int) static auto display_id(const T* pt, int)
{ {
return static_cast<const void*>(pt); return static_cast<const void*>(pt);