13 #ifndef __UT_ArraySet__
14 #define __UT_ArraySet__
23 #include <hboost/functional/hash.hpp>
32 struct DefaultClearer;
41 static const bool clearNeedsDestruction =
false;
49 if (std::numeric_limits<T>::has_quiet_NaN) {
53 v = std::numeric_limits<T>::quiet_NaN();
66 if (std::numeric_limits<T>::has_quiet_NaN) {
107 static const bool clearNeedsDestruction =
false;
110 template<
typename S0,
typename S1>
161 std::size_t MAX_LOAD_FACTOR_256=128,
163 class Hash=hboost::hash<Key>,
164 class KeyEqual=std::equal_to<Key>
192 if (init_bucket_count != 0)
201 that.myBuckets =
nullptr;
202 that.myNumBuckets = 0;
215 template<
typename INPUT_ITERATOR>
226 for (; start_input != end_input; ++start_input)
231 *pdest = *start_input;
245 if (init_bucket_count == 0 || init_bucket_count < init.size()) {
249 bucket_count = init_bucket_count;
252 for (
auto &&p = init.begin(); p != init.end(); ++p) {
287 insert(init.begin(), init.end());
296 that.myBuckets =
nullptr;
297 that.myNumBuckets = 0;
313 if (Clearer::isClear(*p))
316 const_iterator it = that.
find(*p);
326 return !(*
this == that);
395 if (Clearer::clearNeedsDestruction || !Clearer::isClear(*p))
438 return float(MAX_LOAD_FACTOR_256)/256;
453 if (new_num_buckets < min_buckets) {
454 new_num_buckets = min_buckets;
478 if (new_num_buckets == 0)
486 if (new_num_buckets < old_size)
488 UT_ASSERT_MSG(0,
"What does the caller expect to happen when setting the number of buckets lower than the size, but not to zero?\nThis class doesn't support multiple items per bucket.");
489 new_num_buckets = old_size;
497 pointer new_end = new_buckets + new_num_buckets;
498 for (
pointer p = new_buckets; p < new_end; ++p)
500 Clearer::clearConstruct(p);
509 if (!Clearer::isClear(*srcp))
518 insertHelper<false,false>(new_buckets, new_num_buckets,
v, destp);
519 *destp = std::move(v);
550 template<
bool constant_type>
565 UT_ASSERT_MSG_P(scan || current == end || !Clearer::isClear(*current),
"An iterator can't point to a clear item!");
568 while (myCurrent != myEnd && Clearer::isClear(*myCurrent))
580 UT_ASSERT_MSG_P(myEnd == that.myEnd,
"Probably unintentional: Comparing against iterator from different set or iterator invalidated by reallocation!");
581 return (myCurrent == that.myCurrent);
585 UT_ASSERT_MSG_P(myEnd == that.myEnd,
"Probably unintentional: Comparing against iterator from different set or iterator invalidated by reallocation!");
586 return (myCurrent != that.myCurrent);
590 return myCurrent == myEnd;
595 if (myCurrent == myEnd) {
600 }
while (myCurrent != myEnd && Clearer::isClear(*myCurrent));
621 UT_ASSERT_MSG_P(myCurrent <= myEnd,
"Dereferencing iterator past end!");
626 UT_ASSERT_MSG_P(myCurrent <= myEnd,
"Dereferencing iterator past end!");
682 return const_iterator(pend,pend,
false);
685 const_iterator
end()
const
688 return const_iterator(pend,pend,
false);
700 return iterator(
nullptr,
nullptr,
false);
705 for (
pointer p = search_start; p != pend; ++p)
709 if (Clearer::isClear(*p))
713 for (
pointer p = search_start-1; p >= pstart; --p)
717 if (Clearer::isClear(*p))
722 const_iterator
find(
const Key &key)
const
728 return const_iterator(
nullptr,
nullptr,
false);
736 return const_iterator(p,pend,
false);
737 if (Clearer::isClear(*p))
738 return const_iterator(pend,pend,
false);
744 return const_iterator(p,pend,
false);
745 if (Clearer::isClear(*p))
746 return const_iterator(pend,pend,
false);
748 return const_iterator(pend,pend,
false);
773 else if (Clearer::isClear(*p))
774 return MULTI ? count : 0;
785 else if (Clearer::isClear(*p))
786 return MULTI ? count : 0;
788 return MULTI ? count : 0;
807 if (Clearer::isClear(*p))
815 if (Clearer::isClear(*p))
824 std::pair<const_iterator,const_iterator>
equal_range(
const Key &key)
const
831 return std::make_pair(const_iterator(
nullptr,
nullptr,
false), const_iterator(
nullptr,
nullptr,
false));
839 return std::make_pair(const_iterator(p,pend,
false), const_iterator(p+1,pend,
true));
840 if (Clearer::isClear(*p))
841 return std::make_pair(const_iterator(pend,pend,
false), const_iterator(pend,pend,
false));
847 return std::make_pair(const_iterator(p,pend,
false), const_iterator(p+1,pend,
true));
848 if (Clearer::isClear(*p))
849 return std::make_pair(const_iterator(pend,pend,
false), const_iterator(pend,pend,
false));
851 return std::make_pair(const_iterator(pend,pend,
false), const_iterator(pend,pend,
false));
864 else if (first_found)
866 if (first_found != search_start)
867 return std::make_pair(const_iterator(first_found,pend,
false), const_iterator(p,pend,
true));
872 else if (Clearer::isClear(*p))
875 return std::make_pair(const_iterator(pend,pend,
false), const_iterator(pend,pend,
false));
884 return std::make_pair(const_iterator(p+1,pend,
false), const_iterator(end_found,pend,
true));
887 return std::make_pair(const_iterator(pstart,pend,
false), const_iterator(end_found,pend,
true));
896 return std::make_pair(
iterator(
nullptr,
nullptr,
false),
iterator(
nullptr,
nullptr,
false));
901 for (
pointer p = search_start; p != pend; ++p)
905 if (Clearer::isClear(*p))
906 return std::make_pair(
iterator(pend,pend,
false),
iterator(pend,pend,
false));
909 for (
pointer p = search_start-1; p >= pstart; --p)
913 if (Clearer::isClear(*p))
914 return std::make_pair(
iterator(pend,pend,
false),
iterator(pend,pend,
false));
916 return std::make_pair(
iterator(pend,pend,
false),
iterator(pend,pend,
false));
922 for (
pointer p = search_start; p != pend; ++p)
929 else if (first_found)
931 if (first_found != search_start)
932 return std::make_pair(
iterator(first_found,pend,
false),
iterator(p,pend,
true));
937 else if (Clearer::isClear(*p))
940 return std::make_pair(
iterator(pend,pend,
false),
iterator(pend,pend,
false));
945 for (
pointer p = search_start-1; p >= pstart; --p)
949 return std::make_pair(
iterator(p+1,pend,
false),
iterator(end_found,pend,
true));
952 return std::make_pair(
iterator(pstart,pend,
false),
iterator(end_found,pend,
true));
979 *p = std::move(
value);
987 template<
typename INPUT_ITERATOR>
988 void insert(INPUT_ITERATOR start_input, INPUT_ITERATOR end_input)
1001 for (; start_input != end_input; ++start_input)
1006 *pdest = *start_input;
1014 void insert(std::initializer_list<value_type> list)
1017 insert(list.begin(),list.end());
1024 template <
typename... Args>
1046 UT_ASSERT_MSG_P(p >= pstart && p < pend && !Clearer::isClear(*p),
"An iterator to erase can't point to a clear item!");
1058 bool end_case = (pnext == pend);
1061 if (Clearer::isClear(*pnext))
1072 end_case = (pnext == pend);
1073 }
while (!end_case && !Clearer::isClear(*pnext));
1076 if (end_case && (p != pstart) && !Clearer::isClear(*(p-1)))
1084 while (pprev != pstart && !Clearer::isClear(*(pprev-1)))
1096 if (ideal_bucket_num > (pprev-pstart))
1099 for (
pointer pdest = p; pdest != pprev; --pdest)
1101 *pdest = std::move(*(pdest-1));
1103 Clearer::clear(*pprev);
1108 }
while (pprev != p);
1121 for (
pointer pdest = p; pdest+1 != pnext; ++pdest)
1126 if (ideal_bucket_num > empty_bucket_num)
1128 Clearer::clear(*pdest);
1129 return iterator(p+(pdest==p),pend,
false);
1132 *pdest = std::move(*(pdest+1));
1135 Clearer::clear(*(pnext-1));
1145 #if 0 // This isn't fully implemented, so it's excluded to avoid anyone accidentally using it.
1156 if (start_iter == end_iter)
1165 UT_ASSERT_MSG_P(prange_start >= pstart && prange_start < prange_end && prange_end <= pend && !Clearer::isClear(*prange_start),
"An iterator to erase can't point to a clear item!");
1170 Clearer::clear(*prange_start);
1171 for (
pointer p = prange_start+1; p != prange_end; ++p)
1173 if (!Clearer::isClear(*p))
1176 ++nitems_in_last_block;
1181 nitems_in_last_block = 0;
1193 pointer block_end = prange_end;
1195 if (prange_end != pend)
1201 if (nitems_in_last_block == 0)
1208 }
while (block_end != pend && !Clearer::isClear(*block_end));
1214 if (nitems_in_last_block != prange_end-prange_start)
1227 if (block_end == pend && nitems_in_last_block == prange_end-prange_start && prange_start != pstart && !Clearer::isClear(*(prange_start-1)))
1230 pointer block_start = prange_start;
1234 }
while (block_start != pstart && !Clearer::isClear(*(block_start-1)));
1292 int64 mem = inclusive ?
sizeof(*this) : 0;
1297 template<
typename FUNCTOR>
1303 for (; p != pend; ++p)
1305 if (!Clearer::isClear(*p))
1319 if ((256%MAX_LOAD_FACTOR_256) == 0)
1321 return size * (256/MAX_LOAD_FACTOR_256) + 1;
1323 return (size*256 + MAX_LOAD_FACTOR_256-1)/MAX_LOAD_FACTOR_256;
1336 template<
bool fail_on_equal=!MULTI,
bool check_realloc=true>
1341 if (check_realloc && nbuckets == 0)
1348 const pointer pend = pstart + nbuckets;
1350 const size_type ideal_bucket = (hash%nbuckets);
1351 pointer init_searchp = pstart + ideal_bucket;
1352 pointer searchp = init_searchp;
1354 if (Clearer::isClear(*searchp))
1370 if (!fail_on_equal && check_realloc)
1385 if ((
hasher()(*searchp)%nbuckets) <= ideal_bucket)
1390 if (searchp == pend || Clearer::isClear(*searchp))
1394 if (fail_on_equal && other_hash==hash &&
key_equal()(*searchp,value))
1399 if (ideal_bucket < (other_hash%nbuckets))
1414 while (searchp != pend && !Clearer::isClear(*searchp))
1419 if (searchp != pend)
1430 if (fail_on_equal && check_realloc)
1445 while (searchp != insertp)
1447 *searchp = std::move(*(searchp-1));
1459 if (insertp == init_searchp)
1463 UT_ASSERT_P(insertp-1 >= pstart || (fail_on_equal && insertp == pstart));
1464 while ((!fail_on_equal || insertp != pstart) && !Clearer::isClear(*(insertp-1)))
1467 if (fail_on_equal && other_hash == hash &&
key_equal()(*(insertp-1),value))
1475 if ((other_hash%nbuckets) <= ideal_bucket)
1478 UT_ASSERT_P(insertp-1 >= pstart || (fail_on_equal && insertp == pstart));
1496 pointer blockstart = (init_searchp < insertp) ? init_searchp : insertp;
1497 if (fail_on_equal && check_realloc)
1503 if (blockstart == pstart)
1514 bool in_ideal_bucket_span =
true;
1515 bool checked_realloc =
false;
1516 while (!Clearer::isClear(*(blockstart-1)))
1521 if (fail_on_equal && in_ideal_bucket_span)
1524 if ((other_hash == hash) &&
key_equal()(*blockstart,value))
1529 in_ideal_bucket_span = ((other_hash%nbuckets) == ideal_bucket);
1531 if (fail_on_equal && check_realloc && !checked_realloc)
1533 if (!in_ideal_bucket_span)
1547 checked_realloc =
true;
1552 else if (blockstart == pstart)
1563 if (fail_on_equal && check_realloc && !checked_realloc)
1577 while (blockstart != insertp)
1579 *(blockstart-1) = std::move(*blockstart);
1594 std::size_t MAX_LOAD_FACTOR_256,
1609 static const bool clearNeedsDestruction =
false;
1614 template<
typename Key,
1616 int MAX_LOAD_FACTOR_256 = 128,
1618 class Hash = hboost::hash<Key>,
1619 class KeyEqual = std::equal_to<Key> >
1623 template<
typename Key,
1625 int MAX_LOAD_FACTOR_256,
float load_factor() const
Returns the current portion of buckets that are occupied.
const_iterator find(const Key &key) const
const_pointer searchStart(const Key &key) const
static void clearConstruct(bool *p)
ArraySet(const set_type &that)
ArraySet(size_type init_bucket_count)
UT_ASSERT_COMPILETIME(BRAY_EVENT_MAXFLAGS<=32)
std::ptrdiff_t difference_type
std::pair< iterator, bool > insert(const value_type &value)
size_type size() const
Returns the number of items in the set.
UT_API exint UTbumpAllocToPrime(exint current_size)
void setNumBuckets(size_type new_num_buckets)
static const bool clearNeedsDestruction
STATIC_INLINE size_t Hash(const char *s, size_t len)
void swap(UT::ArraySet< Key, MULTI, MAX_LOAD_FACTOR_256, Clearer, Hash, KeyEqual > &a, UT::ArraySet< Key, MULTI, MAX_LOAD_FACTOR_256, Clearer, Hash, KeyEqual > &b)
pointer getCurrent() const
GLsizei const GLfloat * value
static void clearConstruct(T *p)
static size_type max_bucket_count()
std::pair< iterator, bool > insert(value_type &&value)
static void clear(bool &v)
constexpr bool SYSisNan(const F f)
set_type & operator=(set_type &&that)
GLboolean GLboolean GLboolean GLboolean a
bool empty() const
Returns true iff there are no items in the set.
ImageBuf OIIO_API min(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
iterator end()
Returns a non-const end iterator for the set.
iterator_t & operator=(const iterator_t &)=default
#define UT_ASSERT_MSG_P(ZZ,...)
static bool isClear(bool v)
std::ptrdiff_t difference_type
bool insertHelper(pointer pstart, size_type nbuckets, const value_type &value, pointer &destp)
static bool isClear(const std::pair< S0, S1 > &v)
ArraySet< Key, MULTI, MAX_LOAD_FACTOR_256, Clearer, Hash, KeyEqual > set_type
#define UT_ASSERT_MSG(ZZ,...)
iterator erase(iterator iter)
void insert(INPUT_ITERATOR start_input, INPUT_ITERATOR end_input)
Inserts all of the items in the range [start_input,end_input).
iterator_t(pointer current, const_pointer end, bool scan=true)
static SYS_FORCE_INLINE bool isClear(TheType &v)
static size_type minBuckets(size_type size)
reference operator*() const
static void clearConstruct(std::pair< S0, S1 > *p)
void destroy()
Removes all items from the set and frees all the memory.
static bool isClear(S *v)
ArraySet(std::initializer_list< value_type > init, size_type init_bucket_count=0)
iterator begin()
Returns a non-const iterator for the beginning of the set.
set_type & operator=(const set_type &that)
set_type & operator=(std::initializer_list< value_type > init)
static key_equal key_eq()
static void clearConstruct(S **p)
void bumpNumBuckets(size_type new_num_items)
const_iterator cbegin() const
Returns a const iterator for the beginning of the set.
static SYS_FORCE_INLINE void clear(TheType &v)
GLboolean GLboolean GLboolean b
const_iterator cend() const
Returns a const end iterator for the set.
iterator find(const Key &key)
std::conditional< constant_type, const value_type, value_type >::type & reference
std::forward_iterator_tag iterator_category
int64 getMemoryUsage(bool inclusive) const
ArraySet(set_type &&that)
Move constructor, destroying the source.
size_type count(const Key &key) const
bool operator!=(const set_type &that) const
size_type bucket_size(size_type i) const
std::pair< iterator, bool > emplace(Args &&...args)
std::conditional< constant_type, const typename ArraySet::value_type, typename ArraySet::value_type >::type value_type
SYS_FORCE_INLINE void forEach(FUNCTOR &&functor) const
void insert(std::initializer_list< value_type > list)
Inserts all of the items from the initializer_list.
const value_type * const_pointer
const_pointer getEnd() const
std::pair< const_iterator, const_iterator > equal_range(const Key &key) const
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
iterator_t< constant_type > & operator++()
void swap(set_type &that)
Swaps another set with this one.
const value_type & const_reference
pointer operator->() const
**If you just want to fire and args
static void clear(std::pair< S0, S1 > &v)
static size_type max_size()
void rehash(size_type new_num_buckets)
std::pair< iterator, iterator > equal_range(const Key &key)
static float max_load_factor()
std::conditional< constant_type, typename set_type::const_pointer, typename set_type::pointer >::type pointer
static hasher hash_function()
const_iterator begin() const
Returns a const iterator for the beginning of the set.
iterator_t< false > iterator
Iterator type for iterating over non-constant elements.
SIM_API const UT_StringHolder distance
bool operator!=(const iterator_t &that) const
bool contains(const Key &key) const
static SYS_FORCE_INLINE void clearConstruct(TheType *p)
size_type bucket_count() const
Returns the current number of buckets.
pointer searchStart(const Key &key)
const_iterator(const iterator &non_const_it)
bool operator==(const iterator_t &that) const
size_type erase(const Key &key)
ArraySet(INPUT_ITERATOR start_input, INPUT_ITERATOR end_input, size_type init_bucket_count=0)
Inserts all of the items in the range [start_input,end_input).
const_iterator end() const
Returns a const end iterator for the set.
bool operator==(const set_type &that) const
void reserve(size_type num_items)