13 #ifndef __UT_ArraySet__
14 #define __UT_ArraySet__
23 #include <hboost/functional/hash.hpp>
33 struct DefaultClearer;
42 static const bool clearNeedsDestruction =
false;
50 if (std::numeric_limits<T>::has_quiet_NaN) {
54 v = std::numeric_limits<T>::quiet_NaN();
67 if (std::numeric_limits<T>::has_quiet_NaN) {
108 static const bool clearNeedsDestruction =
false;
111 template<
typename S0,
typename S1>
162 std::size_t MAX_LOAD_FACTOR_256=128,
164 class Hash=hboost::hash<Key>,
165 class KeyEqual=std::equal_to<Key>
193 if (init_bucket_count != 0)
202 that.myBuckets =
nullptr;
203 that.myNumBuckets = 0;
216 template<
typename INPUT_ITERATOR>
224 if (ninput_items == 0)
229 for (; start_input != end_input; ++start_input)
234 *pdest = *start_input;
248 if (init_bucket_count == 0 || init_bucket_count < init.size()) {
252 bucket_count = init_bucket_count;
255 for (
auto &&p = init.begin(); p != init.end(); ++p) {
290 insert(init.begin(), init.end());
299 that.myBuckets =
nullptr;
300 that.myNumBuckets = 0;
316 if (Clearer::isClear(*p))
319 const_iterator it = that.
find(*p);
329 return !(*
this == that);
398 if (Clearer::clearNeedsDestruction || !Clearer::isClear(*p))
441 return float(MAX_LOAD_FACTOR_256)/256;
456 if (new_num_buckets < min_buckets) {
457 new_num_buckets = min_buckets;
481 if (new_num_buckets == 0)
489 if (new_num_buckets < old_size)
491 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.");
492 new_num_buckets = old_size;
500 pointer new_end = new_buckets + new_num_buckets;
501 for (
pointer p = new_buckets; p < new_end; ++p)
503 Clearer::clearConstruct(p);
512 if (!Clearer::isClear(*srcp))
521 insertHelper<false,false>(new_buckets, new_num_buckets,
v, destp);
522 *destp = std::move(v);
553 template<
bool constant_type>
568 UT_ASSERT_MSG_P(scan || current == end || !Clearer::isClear(*current),
"An iterator can't point to a clear item!");
571 while (myCurrent != myEnd && Clearer::isClear(*myCurrent))
583 UT_ASSERT_MSG_P(myEnd == that.myEnd,
"Probably unintentional: Comparing against iterator from different set or iterator invalidated by reallocation!");
584 return (myCurrent == that.myCurrent);
588 UT_ASSERT_MSG_P(myEnd == that.myEnd,
"Probably unintentional: Comparing against iterator from different set or iterator invalidated by reallocation!");
589 return (myCurrent != that.myCurrent);
593 return myCurrent == myEnd;
598 if (myCurrent == myEnd) {
603 }
while (myCurrent != myEnd && Clearer::isClear(*myCurrent));
624 UT_ASSERT_MSG_P(myCurrent <= myEnd,
"Dereferencing iterator past end!");
629 UT_ASSERT_MSG_P(myCurrent <= myEnd,
"Dereferencing iterator past end!");
685 return const_iterator(pend,pend,
false);
688 const_iterator
end()
const
691 return const_iterator(pend,pend,
false);
703 return iterator(
nullptr,
nullptr,
false);
708 for (
pointer p = search_start; p != pend; ++p)
712 if (Clearer::isClear(*p))
716 for (
pointer p = search_start-1; p >= pstart; --p)
720 if (Clearer::isClear(*p))
725 const_iterator
find(
const Key &key)
const
731 return const_iterator(
nullptr,
nullptr,
false);
739 return const_iterator(p,pend,
false);
740 if (Clearer::isClear(*p))
741 return const_iterator(pend,pend,
false);
747 return const_iterator(p,pend,
false);
748 if (Clearer::isClear(*p))
749 return const_iterator(pend,pend,
false);
751 return const_iterator(pend,pend,
false);
776 else if (Clearer::isClear(*p))
777 return MULTI ? count : 0;
788 else if (Clearer::isClear(*p))
789 return MULTI ? count : 0;
791 return MULTI ? count : 0;
810 if (Clearer::isClear(*p))
818 if (Clearer::isClear(*p))
824 template <
typename S>
828 [
this](
const auto v) {
return contains(
v); });
834 std::pair<const_iterator,const_iterator>
equal_range(
const Key &key)
const
841 return std::make_pair(const_iterator(
nullptr,
nullptr,
false), const_iterator(
nullptr,
nullptr,
false));
849 return std::make_pair(const_iterator(p,pend,
false), const_iterator(p+1,pend,
true));
850 if (Clearer::isClear(*p))
851 return std::make_pair(const_iterator(pend,pend,
false), const_iterator(pend,pend,
false));
857 return std::make_pair(const_iterator(p,pend,
false), const_iterator(p+1,pend,
true));
858 if (Clearer::isClear(*p))
859 return std::make_pair(const_iterator(pend,pend,
false), const_iterator(pend,pend,
false));
861 return std::make_pair(const_iterator(pend,pend,
false), const_iterator(pend,pend,
false));
874 else if (first_found)
876 if (first_found != search_start)
877 return std::make_pair(const_iterator(first_found,pend,
false), const_iterator(p,pend,
true));
882 else if (Clearer::isClear(*p))
885 return std::make_pair(const_iterator(pend,pend,
false), const_iterator(pend,pend,
false));
894 return std::make_pair(const_iterator(p+1,pend,
false), const_iterator(end_found,pend,
true));
897 return std::make_pair(const_iterator(pstart,pend,
false), const_iterator(end_found,pend,
true));
906 return std::make_pair(
iterator(
nullptr,
nullptr,
false),
iterator(
nullptr,
nullptr,
false));
911 for (
pointer p = search_start; p != pend; ++p)
915 if (Clearer::isClear(*p))
916 return std::make_pair(
iterator(pend,pend,
false),
iterator(pend,pend,
false));
919 for (
pointer p = search_start-1; p >= pstart; --p)
923 if (Clearer::isClear(*p))
924 return std::make_pair(
iterator(pend,pend,
false),
iterator(pend,pend,
false));
926 return std::make_pair(
iterator(pend,pend,
false),
iterator(pend,pend,
false));
932 for (
pointer p = search_start; p != pend; ++p)
939 else if (first_found)
941 if (first_found != search_start)
942 return std::make_pair(
iterator(first_found,pend,
false),
iterator(p,pend,
true));
947 else if (Clearer::isClear(*p))
950 return std::make_pair(
iterator(pend,pend,
false),
iterator(pend,pend,
false));
955 for (
pointer p = search_start-1; p >= pstart; --p)
959 return std::make_pair(
iterator(p+1,pend,
false),
iterator(end_found,pend,
true));
962 return std::make_pair(
iterator(pstart,pend,
false),
iterator(end_found,pend,
true));
989 *p = std::move(
value);
997 template<
typename INPUT_ITERATOR>
998 void insert(INPUT_ITERATOR start_input, INPUT_ITERATOR end_input)
1011 for (; start_input != end_input; ++start_input)
1016 *pdest = *start_input;
1024 void insert(std::initializer_list<value_type> list)
1027 insert(list.begin(),list.end());
1034 template <
typename... Args>
1056 UT_ASSERT_MSG_P(p >= pstart && p < pend && !Clearer::isClear(*p),
"An iterator to erase can't point to a clear item!");
1068 bool end_case = (pnext == pend);
1071 if (Clearer::isClear(*pnext))
1082 end_case = (pnext == pend);
1083 }
while (!end_case && !Clearer::isClear(*pnext));
1086 if (end_case && (p != pstart) && !Clearer::isClear(*(p-1)))
1094 while (pprev != pstart && !Clearer::isClear(*(pprev-1)))
1106 if (ideal_bucket_num > (pprev-pstart))
1109 for (
pointer pdest = p; pdest != pprev; --pdest)
1111 *pdest = std::move(*(pdest-1));
1113 Clearer::clear(*pprev);
1118 }
while (pprev != p);
1131 for (
pointer pdest = p; pdest+1 != pnext; ++pdest)
1136 if (ideal_bucket_num > empty_bucket_num)
1138 Clearer::clear(*pdest);
1139 return iterator(p+(pdest==p),pend,
false);
1142 *pdest = std::move(*(pdest+1));
1145 Clearer::clear(*(pnext-1));
1155 #if 0 // This isn't fully implemented, so it's excluded to avoid anyone accidentally using it.
1166 if (start_iter == end_iter)
1175 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!");
1180 Clearer::clear(*prange_start);
1181 for (
pointer p = prange_start+1; p != prange_end; ++p)
1183 if (!Clearer::isClear(*p))
1186 ++nitems_in_last_block;
1191 nitems_in_last_block = 0;
1203 pointer block_end = prange_end;
1205 if (prange_end != pend)
1211 if (nitems_in_last_block == 0)
1218 }
while (block_end != pend && !Clearer::isClear(*block_end));
1224 if (nitems_in_last_block != prange_end-prange_start)
1237 if (block_end == pend && nitems_in_last_block == prange_end-prange_start && prange_start != pstart && !Clearer::isClear(*(prange_start-1)))
1240 pointer block_start = prange_start;
1244 }
while (block_start != pstart && !Clearer::isClear(*(block_start-1)));
1302 int64 mem = inclusive ?
sizeof(*this) : 0;
1307 template<
typename FUNCTOR>
1313 for (; p != pend; ++p)
1315 if (!Clearer::isClear(*p))
1329 if ((256%MAX_LOAD_FACTOR_256) == 0)
1331 return size * (256/MAX_LOAD_FACTOR_256) + 1;
1333 return (size*256 + MAX_LOAD_FACTOR_256-1)/MAX_LOAD_FACTOR_256;
1346 template<
bool fail_on_equal=!MULTI,
bool check_realloc=true>
1351 if (check_realloc && nbuckets == 0)
1358 const pointer pend = pstart + nbuckets;
1360 const size_type ideal_bucket = (hash%nbuckets);
1361 pointer init_searchp = pstart + ideal_bucket;
1362 pointer searchp = init_searchp;
1364 if (Clearer::isClear(*searchp))
1380 if (!fail_on_equal && check_realloc)
1395 if ((
hasher()(*searchp)%nbuckets) <= ideal_bucket)
1400 if (searchp == pend || Clearer::isClear(*searchp))
1404 if (fail_on_equal && other_hash==hash &&
key_equal()(*searchp,value))
1409 if (ideal_bucket < (other_hash%nbuckets))
1424 while (searchp != pend && !Clearer::isClear(*searchp))
1429 if (searchp != pend)
1440 if (fail_on_equal && check_realloc)
1455 while (searchp != insertp)
1457 *searchp = std::move(*(searchp-1));
1469 if (insertp == init_searchp)
1473 UT_ASSERT_P(insertp-1 >= pstart || (fail_on_equal && insertp == pstart));
1474 while ((!fail_on_equal || insertp != pstart) && !Clearer::isClear(*(insertp-1)))
1477 if (fail_on_equal && other_hash == hash &&
key_equal()(*(insertp-1),value))
1485 if ((other_hash%nbuckets) <= ideal_bucket)
1488 UT_ASSERT_P(insertp-1 >= pstart || (fail_on_equal && insertp == pstart));
1506 pointer blockstart = (init_searchp < insertp) ? init_searchp : insertp;
1507 if (fail_on_equal && check_realloc)
1513 if (blockstart == pstart)
1524 bool in_ideal_bucket_span =
true;
1525 bool checked_realloc =
false;
1526 while (!Clearer::isClear(*(blockstart-1)))
1531 if (fail_on_equal && in_ideal_bucket_span)
1534 if ((other_hash == hash) &&
key_equal()(*blockstart,value))
1539 in_ideal_bucket_span = ((other_hash%nbuckets) == ideal_bucket);
1541 if (fail_on_equal && check_realloc && !checked_realloc)
1543 if (!in_ideal_bucket_span)
1557 checked_realloc =
true;
1562 else if (blockstart == pstart)
1573 if (fail_on_equal && check_realloc && !checked_realloc)
1587 while (blockstart != insertp)
1589 *(blockstart-1) = std::move(*blockstart);
1604 std::size_t MAX_LOAD_FACTOR_256,
1619 static const bool clearNeedsDestruction =
false;
1624 template<
typename Key,
1626 int MAX_LOAD_FACTOR_256 = 128,
1628 class Hash = hboost::hash<Key>,
1629 class KeyEqual = std::equal_to<Key> >
1633 template<
typename Key,
1635 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
IMATH_NAMESPACE::V2f float
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)
bool containsAll(const S &src) const
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)
PcpNodeRef_ChildrenIterator begin(const PcpNodeRef::child_const_range &r)
Support for range-based for loops for PcpNodeRef children ranges.