TrinityCore
Loading...
Searching...
No Matches
Containers.h
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef TRINITY_CONTAINERS_H
19#define TRINITY_CONTAINERS_H
20
21#include "Define.h"
22#include "MapUtils.h"
23#include "Random.h"
24#include <algorithm>
25#include <iterator>
26#include <stdexcept>
27#include <type_traits>
28#include <utility>
29#include <vector>
30
31namespace Trinity
32{
33 template <class T>
35 {
36 public:
37 using iterator_category = std::output_iterator_tag;
38 using value_type = void;
39 using pointer = T*;
40 using reference = T&;
41 using difference_type = std::ptrdiff_t;
42
43 CheckedBufferOutputIterator(T* buf, size_t n) : _buf(buf), _end(buf+n) {}
44
45 T& operator*() const { check(); return *_buf; }
48
49 size_t remaining() const { return (_end - _buf); }
50
51 private:
52 T* _buf;
53 T* _end;
54 void check() const
55 {
56 if (!(_buf < _end))
57 throw std::out_of_range("index");
58 }
59 };
60
61 namespace Containers
62 {
63 // resizes <container> to have at most <requestedSize> elements
64 // if it has more than <requestedSize> elements, the elements to keep are selected randomly
65 template<class C>
66 void RandomResize(C& container, std::size_t requestedSize)
67 {
68 static_assert(std::is_base_of<std::forward_iterator_tag, typename std::iterator_traits<typename C::iterator>::iterator_category>::value, "Invalid container passed to Trinity::Containers::RandomResize");
69 if (std::size(container) <= requestedSize)
70 return;
71 auto keepIt = std::begin(container), curIt = std::begin(container);
72 uint32 elementsToKeep = requestedSize, elementsToProcess = std::size(container);
73 while (elementsToProcess)
74 {
75 // this element has chance (elementsToKeep / elementsToProcess) of being kept
76 if (urand(1, elementsToProcess) <= elementsToKeep)
77 {
78 if (keepIt != curIt)
79 *keepIt = std::move(*curIt);
80 ++keepIt;
81 --elementsToKeep;
82 }
83 ++curIt;
84 --elementsToProcess;
85 }
86 container.erase(keepIt, std::end(container));
87 }
88
89 template<class C, class Predicate>
90 void RandomResize(C& container, Predicate&& predicate, std::size_t requestedSize)
91 {
93 C containerCopy;
94 std::copy_if(std::begin(container), std::end(container), std::inserter(containerCopy, std::end(containerCopy)), predicate);
95
96 if (requestedSize)
97 RandomResize(containerCopy, requestedSize);
98
99 container = std::move(containerCopy);
100 }
101
102 /*
103 * Select a random element from a container.
104 *
105 * Note: container cannot be empty
106 */
107 template<class C>
108 inline auto SelectRandomContainerElement(C const& container) -> typename std::add_const<decltype(*std::begin(container))>::type&
109 {
110 auto it = std::begin(container);
111 std::advance(it, urand(0, uint32(std::size(container)) - 1));
112 return *it;
113 }
114
115 /*
116 * Select a random element from a container where each element has a different chance to be selected.
117 *
118 * @param container Container to select an element from
119 * @param weights Chances of each element to be selected, must be in the same order as elements in container.
120 * Caller is responsible for checking that sum of all weights is greater than 0.
121 *
122 * Note: container cannot be empty
123 */
124 template<class C>
125 inline auto SelectRandomWeightedContainerElement(C const& container, std::vector<double> const& weights) -> decltype(std::begin(container))
126 {
127 auto it = std::begin(container);
128 std::advance(it, urandweighted(weights.size(), weights.data()));
129 return it;
130 }
131
132 /*
133 * Select a random element from a container where each element has a different chance to be selected.
134 *
135 * @param container Container to select an element from
136 * @param weightExtractor Function retrieving chance of each element in container, expected to take an element of the container and returning a double
137 *
138 * Note: container cannot be empty
139 */
140 template<class C, class Fn>
141 inline auto SelectRandomWeightedContainerElement(C const& container, Fn weightExtractor) -> decltype(std::begin(container))
142 {
143 std::vector<double> weights;
144 weights.reserve(std::size(container));
145 double weightSum = 0.0;
146 for (auto& val : container)
147 {
148 double weight = weightExtractor(val);
149 weights.push_back(weight);
150 weightSum += weight;
151 }
152 if (weightSum <= 0.0)
153 weights.assign(std::size(container), 1.0);
154
155 return SelectRandomWeightedContainerElement(container, weights);
156 }
157
166 template<class Iterator>
167 inline void RandomShuffle(Iterator begin, Iterator end)
168 {
169 std::shuffle(begin, end, RandomEngine::Instance());
170 }
171
179 template<class C>
180 inline void RandomShuffle(C& container)
181 {
182 RandomShuffle(std::begin(container), std::end(container));
183 }
184
197 template<class Iterator1, class Iterator2>
198 inline bool Intersects(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2)
199 {
200 while (first1 != last1 && first2 != last2)
201 {
202 if (*first1 < *first2)
203 ++first1;
204 else if (*first2 < *first1)
205 ++first2;
206 else
207 return true;
208 }
209
210 return false;
211 }
212
226 template<class Iterator1, class Iterator2, class Predicate>
227 inline bool Intersects(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2, Predicate&& equalPred)
228 {
229 while (first1 != last1 && first2 != last2)
230 {
231 if (*first1 < *first2)
232 ++first1;
233 else if (*first2 < *first1)
234 ++first2;
235 else if (!equalPred(*first1, *first2))
236 ++first1, ++first2;
237 else
238 return true;
239 }
240
241 return false;
242 }
243
244 namespace Impl
245 {
246 template <typename Container, typename Predicate>
247 void EraseIfMoveAssignable(Container& c, Predicate p)
248 {
249 auto wpos = c.begin();
250 for (auto rpos = c.begin(), end = c.end(); rpos != end; ++rpos)
251 {
252 if (!p(*rpos))
253 {
254 if (rpos != wpos)
255 std::swap(*rpos, *wpos);
256 ++wpos;
257 }
258 }
259 c.erase(wpos, c.end());
260 }
261
262 template <typename Container, typename Predicate>
263 void EraseIfNotMoveAssignable(Container& c, Predicate p)
264 {
265 for (auto it = c.begin(); it != c.end();)
266 {
267 if (p(*it))
268 it = c.erase(it);
269 else
270 ++it;
271 }
272 }
273 }
274
275 template <typename Container, typename Predicate>
276 void EraseIf(Container& c, Predicate p)
277 {
278 if constexpr (std::is_move_assignable_v<decltype(*c.begin())>)
279 Impl::EraseIfMoveAssignable(c, std::ref(p));
280 else
281 Impl::EraseIfNotMoveAssignable(c, std::ref(p));
282 }
283
291 template<typename T>
292 inline decltype(auto) EnsureWritableVectorIndex(std::vector<T>& vec, typename std::vector<T>::size_type i)
293 {
294 if (i >= vec.size())
295 vec.resize(i + 1);
296
297 return vec[i];
298 }
299
306 template<typename T>
307 inline decltype(auto) EnsureWritableVectorIndex(std::vector<T>& vec, typename std::vector<T>::size_type i, T const& resizeDefault)
308 {
309 if (i >= vec.size())
310 vec.resize(i + 1, resizeDefault);
311
312 return vec[i];
313 }
314 }
316}
318
319#endif
uint32_t uint32
Definition: Define.h:143
uint32 urandweighted(size_t count, double const *chances)
Definition: Random.cpp:87
uint32 urand(uint32 min, uint32 max)
Definition: Random.cpp:42
static RandomEngine & Instance()
Definition: Random.cpp:93
Definition: Containers.h:35
CheckedBufferOutputIterator operator++(int)
Definition: Containers.h:47
T & operator*() const
Definition: Containers.h:45
CheckedBufferOutputIterator & operator++()
Definition: Containers.h:46
void check() const
Definition: Containers.h:54
T & reference
Definition: Containers.h:40
std::ptrdiff_t difference_type
Definition: Containers.h:41
size_t remaining() const
Definition: Containers.h:49
std::output_iterator_tag iterator_category
Definition: Containers.h:37
T * _end
Definition: Containers.h:53
CheckedBufferOutputIterator(T *buf, size_t n)
Definition: Containers.h:43
void value_type
Definition: Containers.h:38
T * _buf
Definition: Containers.h:52
T * pointer
Definition: Containers.h:39
void EraseIfMoveAssignable(Container &c, Predicate p)
Definition: Containers.h:247
void EraseIfNotMoveAssignable(Container &c, Predicate p)
Definition: Containers.h:263
auto SelectRandomWeightedContainerElement(C const &container, std::vector< double > const &weights) -> decltype(std::begin(container))
Definition: Containers.h:125
decltype(auto) EnsureWritableVectorIndex(std::vector< T > &vec, typename std::vector< T >::size_type i)
Definition: Containers.h:292
void RandomShuffle(Iterator begin, Iterator end)
Reorder the elements of the iterator range randomly.
Definition: Containers.h:167
auto SelectRandomContainerElement(C const &container) -> typename std::add_const< decltype(*std::begin(container))>::type &
Definition: Containers.h:108
bool Intersects(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2)
Definition: Containers.h:198
void EraseIf(Container &c, Predicate p)
Definition: Containers.h:276
void RandomResize(C &container, std::size_t requestedSize)
Definition: Containers.h:66
Definition: AsioHacksFwd.h:53