SmallVector.h
Go to the documentation of this file.
1 //===- llvm/ADT/SmallVector.h - 'Normally small' vectors --------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines the SmallVector class.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_VECSMALL_ADT_SMALLVECTOR_H
15 #define LLVM_VECSMALL_ADT_SMALLVECTOR_H
16 
17 #include <algorithm>
18 #include <cassert>
19 #include <cstddef>
20 #include <cstdlib>
21 #include <cstring>
22 #include <initializer_list>
23 #include <iterator>
24 #include <memory>
25 
26 // LLVM Macros
27 #define LLVM_VECSMALL_NODISCARD
28 #define LLVM_VECSMALL_ATTRIBUTE_ALWAYS_INLINE inline
29 #define LLVM_VECSMALL_UNLIKELY(x) (x)
30 
31 // LLVM External Functions
32 namespace llvm_vecsmall
33 {
34 namespace detail
35 {
38 inline uint64_t NextPowerOf2(uint64_t A)
39 {
40  A |= (A >> 1);
41  A |= (A >> 2);
42  A |= (A >> 4);
43  A |= (A >> 8);
44  A |= (A >> 16);
45  A |= (A >> 32);
46  return A + 1;
47 }
48 } // namespace detail
49 } // namespace llvm_vecsmall
50 
51 namespace llvm_vecsmall
52 {
53 
54 // std::is_pod has been deprecated in C++20.
55 template <typename T>
56 struct IsPod : std::integral_constant<bool, std::is_standard_layout<T>::value &&
57  std::is_trivial<T>::value>
58 {
59 };
60 
63 {
64 protected:
65  void *BeginX, *EndX, *CapacityX;
66 
67 protected:
68  SmallVectorBase(void* FirstEl, size_t Size)
69  : BeginX(FirstEl), EndX(FirstEl), CapacityX((char*)FirstEl + Size)
70  {
71  }
72 
75  void grow_pod(void* FirstEl, size_t MinSizeInBytes, size_t TSize);
76 
77 public:
79  size_t size_in_bytes() const
80  {
81  return size_t((char*)EndX - (char*)BeginX);
82  }
83 
85  size_t capacity_in_bytes() const
86  {
87  return size_t((char*)CapacityX - (char*)BeginX);
88  }
89 
91  {
92  return BeginX == EndX;
93  }
94 };
95 
96 template <typename T, unsigned N>
98 
102 template <typename T, typename = void>
104 {
105 private:
106  template <typename, unsigned>
107  friend struct SmallVectorStorage;
108 
109  // Allocate raw space for N elements of type T. If T has a ctor or dtor, we
110  // don't want it to be automatically run, so we need to represent the space as
111  // something else. Use an array of char of sufficient alignment.
115  // Space after 'FirstEl' is clobbered, do not add any instance vars after it.
116 
117 protected:
119  {
120  }
121 
122  void grow_pod(size_t MinSizeInBytes, size_t TSize)
123  {
124  SmallVectorBase::grow_pod(&FirstEl, MinSizeInBytes, TSize);
125  }
126 
129  bool isSmall() const
130  {
131  return BeginX == static_cast<const void*>(&FirstEl);
132  }
133 
136  {
137  BeginX = EndX = CapacityX = &FirstEl;
138  }
139 
140  void setEnd(T* P)
141  {
142  this->EndX = P;
143  }
144 
145 public:
146  typedef size_t size_type;
147  typedef ptrdiff_t difference_type;
148  typedef T value_type;
149  typedef T* iterator;
150  typedef const T* const_iterator;
151 
152  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
153  typedef std::reverse_iterator<iterator> reverse_iterator;
154 
155  typedef T& reference;
156  typedef const T& const_reference;
157  typedef T* pointer;
158  typedef const T* const_pointer;
159 
160  // forward iterator creation methods.
163  {
164  return (iterator)this->BeginX;
165  }
167  const_iterator begin() const
168  {
169  return (const_iterator)this->BeginX;
170  }
172  iterator end()
173  {
174  return (iterator)this->EndX;
175  }
177  const_iterator end() const
178  {
179  return (const_iterator)this->EndX;
180  }
181 
182 protected:
183  iterator capacity_ptr()
184  {
185  return (iterator)this->CapacityX;
186  }
187  const_iterator capacity_ptr() const
188  {
189  return (const_iterator)this->CapacityX;
190  }
191 
192 public:
193  // reverse iterator creation methods.
194  reverse_iterator rbegin()
195  {
196  return reverse_iterator(end());
197  }
199  {
200  return const_reverse_iterator(end());
201  }
203  {
204  return reverse_iterator(begin());
205  }
207  {
208  return const_reverse_iterator(begin());
209  }
210 
212  size_type size() const
213  {
214  return end() - begin();
215  }
217  {
218  return size_type(-1) / sizeof(T);
219  }
220 
222  size_t capacity() const
223  {
224  return capacity_ptr() - begin();
225  }
226 
229  {
230  return pointer(begin());
231  }
234  {
235  return const_pointer(begin());
236  }
237 
240  {
241  assert(idx < size());
242  return begin()[idx];
243  }
246  {
247  assert(idx < size());
248  return begin()[idx];
249  }
250 
252  {
253  assert(!empty());
254  return begin()[0];
255  }
257  {
258  assert(!empty());
259  return begin()[0];
260  }
261 
263  {
264  assert(!empty());
265  return end()[-1];
266  }
268  {
269  assert(!empty());
270  return end()[-1];
271  }
272 };
273 
276 template <typename T, bool isPodLike>
278 {
279 protected:
281  {
282  }
283 
284  static void destroy_range(T* S, T* E)
285  {
286  while (S != E)
287  {
288  --E;
289  E->~T();
290  }
291  }
292 
295  template <typename It1, typename It2>
296  static void uninitialized_move(It1 I, It1 E, It2 Dest)
297  {
298  std::uninitialized_copy(std::make_move_iterator(I), std::make_move_iterator(E), Dest);
299  }
300 
303  template <typename It1, typename It2>
304  static void uninitialized_copy(It1 I, It1 E, It2 Dest)
305  {
306  std::uninitialized_copy(I, E, Dest);
307  }
308 
312  void grow(size_t MinSize = 0);
313 
314 public:
315  void push_back(const T& Elt)
316  {
317  if (LLVM_VECSMALL_UNLIKELY(this->EndX >= this->CapacityX))
318  this->grow();
319  ::new ((void*)this->end()) T(Elt);
320  this->setEnd(this->end() + 1);
321  }
322 
323  void push_back(T&& Elt)
324  {
325  if (LLVM_VECSMALL_UNLIKELY(this->EndX >= this->CapacityX))
326  this->grow();
327  ::new ((void*)this->end()) T(::std::move(Elt));
328  this->setEnd(this->end() + 1);
329  }
330 
331  void pop_back()
332  {
333  this->setEnd(this->end() - 1);
334  this->end()->~T();
335  }
336 };
337 
338 // Define this out-of-line to dissuade the C++ compiler from inlining it.
339 template <typename T, bool isPodLike>
341 {
342  size_t CurCapacity = this->capacity();
343  size_t CurSize = this->size();
344  // Always grow, even from zero.
345  size_t NewCapacity = size_t(llvm_vecsmall::detail::NextPowerOf2(CurCapacity + 2));
346  if (NewCapacity < MinSize)
347  NewCapacity = MinSize;
348  T* NewElts = static_cast<T*>(malloc(NewCapacity * sizeof(T)));
349 
350  // Move the elements over.
351  this->uninitialized_move(this->begin(), this->end(), NewElts);
352 
353  // Destroy the original elements.
354  destroy_range(this->begin(), this->end());
355 
356  // If this wasn't grown from the inline copy, deallocate the old space.
357  if (!this->isSmall())
358  free(this->begin());
359 
360  this->setEnd(NewElts + CurSize);
361  this->BeginX = NewElts;
362  this->CapacityX = this->begin() + NewCapacity;
363 }
364 
367 template <typename T>
369 {
370 protected:
372  {
373  }
374 
375  // No need to do a destroy loop for POD's.
376  static void destroy_range(T*, T*)
377  {
378  }
379 
382  template <typename It1, typename It2>
383  static void uninitialized_move(It1 I, It1 E, It2 Dest)
384  {
385  // Just do a copy.
386  uninitialized_copy(I, E, Dest);
387  }
388 
391  template <typename It1, typename It2>
392  static void uninitialized_copy(It1 I, It1 E, It2 Dest)
393  {
394  // Arbitrary iterator types; just use the basic implementation.
395  std::uninitialized_copy(I, E, Dest);
396  }
397 
400  template <typename T1, typename T2>
401  static void uninitialized_copy(
402  T1* I, T1* E, T2* Dest,
403  typename std::enable_if<
404  std::is_same<typename std::remove_const<T1>::type, T2>::value>::type* = nullptr)
405  {
406  // Use memcpy for PODs iterated by pointers (which includes SmallVector
407  // iterators): std::uninitialized_copy optimizes to memmove, but we can
408  // use memcpy here. Note that I and E are iterators and thus might be
409  // invalid for memcpy if they are equal.
410  if (I != E)
411  memcpy(Dest, I, (E - I) * sizeof(T));
412  }
413 
416  void grow(size_t MinSize = 0)
417  {
418  this->grow_pod(MinSize * sizeof(T), sizeof(T));
419  }
420 
421 public:
422  void push_back(const T& Elt)
423  {
424  if (LLVM_VECSMALL_UNLIKELY(this->EndX >= this->CapacityX))
425  this->grow();
426  memcpy(this->end(), &Elt, sizeof(T));
427  this->setEnd(this->end() + 1);
428  }
429 
430  void pop_back()
431  {
432  this->setEnd(this->end() - 1);
433  }
434 };
435 
438 template <typename T>
439 class SmallVectorImpl : public SmallVectorTemplateBase<T, IsPod<T>::value>
440 {
442 
443  SmallVectorImpl(const SmallVectorImpl&) = delete;
444 
445 public:
446  typedef typename SuperClass::iterator iterator;
449 
450 protected:
451  // Default ctor - Initialize to empty.
452  explicit SmallVectorImpl(unsigned N)
453  : SmallVectorTemplateBase<T, IsPod<T>::value>(N * sizeof(T))
454  {
455  }
456 
457 public:
459  {
460  // Destroy the constructed elements in the vector.
461  this->destroy_range(this->begin(), this->end());
462 
463  // If this wasn't grown from the inline copy, deallocate the old space.
464  if (!this->isSmall())
465  free(this->begin());
466  }
467 
468  void clear()
469  {
470  this->destroy_range(this->begin(), this->end());
471  this->EndX = this->BeginX;
472  }
473 
474  void resize(size_type N)
475  {
476  if (N < this->size())
477  {
478  this->destroy_range(this->begin() + N, this->end());
479  this->setEnd(this->begin() + N);
480  }
481  else if (N > this->size())
482  {
483  if (this->capacity() < N)
484  this->grow(N);
485  for (auto I = this->end(), E = this->begin() + N; I != E; ++I)
486  new (&*I) T();
487  this->setEnd(this->begin() + N);
488  }
489  }
490 
491  void resize(size_type N, const T& NV)
492  {
493  if (N < this->size())
494  {
495  this->destroy_range(this->begin() + N, this->end());
496  this->setEnd(this->begin() + N);
497  }
498  else if (N > this->size())
499  {
500  if (this->capacity() < N)
501  this->grow(N);
502  std::uninitialized_fill(this->end(), this->begin() + N, NV);
503  this->setEnd(this->begin() + N);
504  }
505  }
506 
508  {
509  if (this->capacity() < N)
510  this->grow(N);
511  }
512 
514  {
515  T Result = ::std::move(this->back());
516  this->pop_back();
517  return Result;
518  }
519 
520  void swap(SmallVectorImpl& RHS);
521 
523  template <typename in_iter>
524  void append(in_iter in_start, in_iter in_end)
525  {
526  size_type NumInputs = std::distance(in_start, in_end);
527  // Grow allocated space if needed.
528  if (NumInputs > size_type(this->capacity_ptr() - this->end()))
529  this->grow(this->size() + NumInputs);
530 
531  // Copy the new elements over.
532  this->uninitialized_copy(in_start, in_end, this->end());
533  this->setEnd(this->end() + NumInputs);
534  }
535 
537  void append(size_type NumInputs, const T& Elt)
538  {
539  // Grow allocated space if needed.
540  if (NumInputs > size_type(this->capacity_ptr() - this->end()))
541  this->grow(this->size() + NumInputs);
542 
543  // Copy the new elements over.
544  std::uninitialized_fill_n(this->end(), NumInputs, Elt);
545  this->setEnd(this->end() + NumInputs);
546  }
547 
548  void append(std::initializer_list<T> IL)
549  {
550  append(IL.begin(), IL.end());
551  }
552 
553  void assign(size_type NumElts, const T& Elt)
554  {
555  clear();
556  if (this->capacity() < NumElts)
557  this->grow(NumElts);
558  this->setEnd(this->begin() + NumElts);
559  std::uninitialized_fill(this->begin(), this->end(), Elt);
560  }
561 
562  void assign(std::initializer_list<T> IL)
563  {
564  clear();
565  append(IL);
566  }
567 
569  {
570  // Just cast away constness because this is a non-const member function.
571  iterator I = const_cast<iterator>(CI);
572 
573  assert(I >= this->begin() && "Iterator to erase is out of bounds.");
574  assert(I < this->end() && "Erasing at past-the-end iterator.");
575 
576  iterator N = I;
577  // Shift all elts down one.
578  std::move(I + 1, this->end(), I);
579  // Drop the last elt.
580  this->pop_back();
581  return (N);
582  }
583 
585  {
586  // Just cast away constness because this is a non-const member function.
587  iterator S = const_cast<iterator>(CS);
588  iterator E = const_cast<iterator>(CE);
589 
590  assert(S >= this->begin() && "Range to erase is out of bounds.");
591  assert(S <= E && "Trying to erase invalid range.");
592  assert(E <= this->end() && "Trying to erase past the end.");
593 
594  iterator N = S;
595  // Shift all elts down.
596  iterator I = std::move(E, this->end(), S);
597  // Drop the last elts.
598  this->destroy_range(I, this->end());
599  this->setEnd(I);
600  return (N);
601  }
602 
604  {
605  if (I == this->end())
606  { // Important special case for empty vector.
607  this->push_back(::std::move(Elt));
608  return this->end() - 1;
609  }
610 
611  assert(I >= this->begin() && "Insertion iterator is out of bounds.");
612  assert(I <= this->end() && "Inserting past the end of the vector.");
613 
614  if (this->EndX >= this->CapacityX)
615  {
616  size_t EltNo = I - this->begin();
617  this->grow();
618  I = this->begin() + EltNo;
619  }
620 
621  ::new ((void*)this->end()) T(::std::move(this->back()));
622  // Push everything else over.
623  std::move_backward(I, this->end() - 1, this->end());
624  this->setEnd(this->end() + 1);
625 
626  // If we just moved the element we're inserting, be sure to update
627  // the reference.
628  T* EltPtr = &Elt;
629  if (I <= EltPtr && EltPtr < this->EndX)
630  ++EltPtr;
631 
632  *I = ::std::move(*EltPtr);
633  return I;
634  }
635 
636  iterator insert(iterator I, const T& Elt)
637  {
638  if (I == this->end())
639  { // Important special case for empty vector.
640  this->push_back(Elt);
641  return this->end() - 1;
642  }
643 
644  assert(I >= this->begin() && "Insertion iterator is out of bounds.");
645  assert(I <= this->end() && "Inserting past the end of the vector.");
646 
647  if (this->EndX >= this->CapacityX)
648  {
649  size_t EltNo = I - this->begin();
650  this->grow();
651  I = this->begin() + EltNo;
652  }
653  ::new ((void*)this->end()) T(std::move(this->back()));
654  // Push everything else over.
655  std::move_backward(I, this->end() - 1, this->end());
656  this->setEnd(this->end() + 1);
657 
658  // If we just moved the element we're inserting, be sure to update
659  // the reference.
660  const T* EltPtr = &Elt;
661  if (I <= EltPtr && EltPtr < this->EndX)
662  ++EltPtr;
663 
664  *I = *EltPtr;
665  return I;
666  }
667 
668  iterator insert(iterator I, size_type NumToInsert, const T& Elt)
669  {
670  // Convert iterator to elt# to avoid invalidating iterator when we reserve()
671  size_t InsertElt = I - this->begin();
672 
673  if (I == this->end())
674  { // Important special case for empty vector.
675  append(NumToInsert, Elt);
676  return this->begin() + InsertElt;
677  }
678 
679  assert(I >= this->begin() && "Insertion iterator is out of bounds.");
680  assert(I <= this->end() && "Inserting past the end of the vector.");
681 
682  // Ensure there is enough space.
683  reserve(this->size() + NumToInsert);
684 
685  // Uninvalidate the iterator.
686  I = this->begin() + InsertElt;
687 
688  // If there are more elements between the insertion point and the end of the
689  // range than there are being inserted, we can use a simple approach to
690  // insertion. Since we already reserved space, we know that this won't
691  // reallocate the vector.
692  if (size_t(this->end() - I) >= NumToInsert)
693  {
694  T* OldEnd = this->end();
695  append(std::move_iterator<iterator>(this->end() - NumToInsert),
696  std::move_iterator<iterator>(this->end()));
697 
698  // Copy the existing elements that get replaced.
699  std::move_backward(I, OldEnd - NumToInsert, OldEnd);
700 
701  std::fill_n(I, NumToInsert, Elt);
702  return I;
703  }
704 
705  // Otherwise, we're inserting more elements than exist already, and we're
706  // not inserting at the end.
707 
708  // Move over the elements that we're about to overwrite.
709  T* OldEnd = this->end();
710  this->setEnd(this->end() + NumToInsert);
711  size_t NumOverwritten = OldEnd - I;
712  this->uninitialized_move(I, OldEnd, this->end() - NumOverwritten);
713 
714  // Replace the overwritten part.
715  std::fill_n(I, NumOverwritten, Elt);
716 
717  // Insert the non-overwritten middle part.
718  std::uninitialized_fill_n(OldEnd, NumToInsert - NumOverwritten, Elt);
719  return I;
720  }
721 
722  template <typename ItTy>
723  iterator insert(iterator I, ItTy From, ItTy To)
724  {
725  // Convert iterator to elt# to avoid invalidating iterator when we reserve()
726  size_t InsertElt = I - this->begin();
727 
728  if (I == this->end())
729  { // Important special case for empty vector.
730  append(From, To);
731  return this->begin() + InsertElt;
732  }
733 
734  assert(I >= this->begin() && "Insertion iterator is out of bounds.");
735  assert(I <= this->end() && "Inserting past the end of the vector.");
736 
737  size_t NumToInsert = std::distance(From, To);
738 
739  // Ensure there is enough space.
740  reserve(this->size() + NumToInsert);
741 
742  // Uninvalidate the iterator.
743  I = this->begin() + InsertElt;
744 
745  // If there are more elements between the insertion point and the end of the
746  // range than there are being inserted, we can use a simple approach to
747  // insertion. Since we already reserved space, we know that this won't
748  // reallocate the vector.
749  if (size_t(this->end() - I) >= NumToInsert)
750  {
751  T* OldEnd = this->end();
752  append(std::move_iterator<iterator>(this->end() - NumToInsert),
753  std::move_iterator<iterator>(this->end()));
754 
755  // Copy the existing elements that get replaced.
756  std::move_backward(I, OldEnd - NumToInsert, OldEnd);
757 
758  std::copy(From, To, I);
759  return I;
760  }
761 
762  // Otherwise, we're inserting more elements than exist already, and we're
763  // not inserting at the end.
764 
765  // Move over the elements that we're about to overwrite.
766  T* OldEnd = this->end();
767  this->setEnd(this->end() + NumToInsert);
768  size_t NumOverwritten = OldEnd - I;
769  this->uninitialized_move(I, OldEnd, this->end() - NumOverwritten);
770 
771  // Replace the overwritten part.
772  for (T* J = I; NumOverwritten > 0; --NumOverwritten)
773  {
774  *J = *From;
775  ++J;
776  ++From;
777  }
778 
779  // Insert the non-overwritten middle part.
780  this->uninitialized_copy(From, To, OldEnd);
781  return I;
782  }
783 
784  void insert(iterator I, std::initializer_list<T> IL)
785  {
786  insert(I, IL.begin(), IL.end());
787  }
788 
789  template <typename... ArgTypes>
790  void emplace_back(ArgTypes&&... Args)
791  {
792  if (LLVM_VECSMALL_UNLIKELY(this->EndX >= this->CapacityX))
793  this->grow();
794  ::new ((void*)this->end()) T(std::forward<ArgTypes>(Args)...);
795  this->setEnd(this->end() + 1);
796  }
797 
799 
801 
802  bool operator==(const SmallVectorImpl& RHS) const
803  {
804  if (this->size() != RHS.size())
805  return false;
806  return std::equal(this->begin(), this->end(), RHS.begin());
807  }
808  bool operator!=(const SmallVectorImpl& RHS) const
809  {
810  return !(*this == RHS);
811  }
812 
813  bool operator<(const SmallVectorImpl& RHS) const
814  {
815  return std::lexicographical_compare(this->begin(), this->end(), RHS.begin(),
816  RHS.end());
817  }
818 
829  {
830  assert(N <= this->capacity());
831  this->setEnd(this->begin() + N);
832  }
833 };
834 
835 template <typename T>
837 {
838  if (this == &RHS)
839  return;
840 
841  // We can only avoid copying elements if neither vector is small.
842  if (!this->isSmall() && !RHS.isSmall())
843  {
844  std::swap(this->BeginX, RHS.BeginX);
845  std::swap(this->EndX, RHS.EndX);
846  std::swap(this->CapacityX, RHS.CapacityX);
847  return;
848  }
849  if (RHS.size() > this->capacity())
850  this->grow(RHS.size());
851  if (this->size() > RHS.capacity())
852  RHS.grow(this->size());
853 
854  // Swap the shared elements.
855  size_t NumShared = this->size();
856  if (NumShared > RHS.size())
857  NumShared = RHS.size();
858  for (size_type i = 0; i != NumShared; ++i)
859  std::swap((*this)[i], RHS[i]);
860 
861  // Copy over the extra elts.
862  if (this->size() > RHS.size())
863  {
864  size_t EltDiff = this->size() - RHS.size();
865  this->uninitialized_copy(this->begin() + NumShared, this->end(), RHS.end());
866  RHS.setEnd(RHS.end() + EltDiff);
867  this->destroy_range(this->begin() + NumShared, this->end());
868  this->setEnd(this->begin() + NumShared);
869  }
870  else if (RHS.size() > this->size())
871  {
872  size_t EltDiff = RHS.size() - this->size();
873  this->uninitialized_copy(RHS.begin() + NumShared, RHS.end(), this->end());
874  this->setEnd(this->end() + EltDiff);
875  this->destroy_range(RHS.begin() + NumShared, RHS.end());
876  RHS.setEnd(RHS.begin() + NumShared);
877  }
878 }
879 
880 template <typename T>
882 {
883  // Avoid self-assignment.
884  if (this == &RHS)
885  return *this;
886 
887  // If we already have sufficient space, assign the common elements, then
888  // destroy any excess.
889  size_t RHSSize = RHS.size();
890  size_t CurSize = this->size();
891  if (CurSize >= RHSSize)
892  {
893  // Assign common elements.
894  iterator NewEnd;
895  if (RHSSize)
896  NewEnd = std::copy(RHS.begin(), RHS.begin() + RHSSize, this->begin());
897  else
898  NewEnd = this->begin();
899 
900  // Destroy excess elements.
901  this->destroy_range(NewEnd, this->end());
902 
903  // Trim.
904  this->setEnd(NewEnd);
905  return *this;
906  }
907 
908  // If we have to grow to have enough elements, destroy the current elements.
909  // This allows us to avoid copying them during the grow.
910  // FIXME: don't do this if they're efficiently moveable.
911  if (this->capacity() < RHSSize)
912  {
913  // Destroy current elements.
914  this->destroy_range(this->begin(), this->end());
915  this->setEnd(this->begin());
916  CurSize = 0;
917  this->grow(RHSSize);
918  }
919  else if (CurSize)
920  {
921  // Otherwise, use assignment for the already-constructed elements.
922  std::copy(RHS.begin(), RHS.begin() + CurSize, this->begin());
923  }
924 
925  // Copy construct the new elements in place.
926  this->uninitialized_copy(RHS.begin() + CurSize, RHS.end(), this->begin() + CurSize);
927 
928  // Set end.
929  this->setEnd(this->begin() + RHSSize);
930  return *this;
931 }
932 
933 template <typename T>
935 {
936  // Avoid self-assignment.
937  if (this == &RHS)
938  return *this;
939 
940  // If the RHS isn't small, clear this vector and then steal its buffer.
941  if (!RHS.isSmall())
942  {
943  this->destroy_range(this->begin(), this->end());
944  if (!this->isSmall())
945  free(this->begin());
946  this->BeginX = RHS.BeginX;
947  this->EndX = RHS.EndX;
948  this->CapacityX = RHS.CapacityX;
949  RHS.resetToSmall();
950  return *this;
951  }
952 
953  // If we already have sufficient space, assign the common elements, then
954  // destroy any excess.
955  size_t RHSSize = RHS.size();
956  size_t CurSize = this->size();
957  if (CurSize >= RHSSize)
958  {
959  // Assign common elements.
960  iterator NewEnd = this->begin();
961  if (RHSSize)
962  NewEnd = std::move(RHS.begin(), RHS.end(), NewEnd);
963 
964  // Destroy excess elements and trim the bounds.
965  this->destroy_range(NewEnd, this->end());
966  this->setEnd(NewEnd);
967 
968  // Clear the RHS.
969  RHS.clear();
970 
971  return *this;
972  }
973 
974  // If we have to grow to have enough elements, destroy the current elements.
975  // This allows us to avoid copying them during the grow.
976  // FIXME: this may not actually make any sense if we can efficiently move
977  // elements.
978  if (this->capacity() < RHSSize)
979  {
980  // Destroy current elements.
981  this->destroy_range(this->begin(), this->end());
982  this->setEnd(this->begin());
983  CurSize = 0;
984  this->grow(RHSSize);
985  }
986  else if (CurSize)
987  {
988  // Otherwise, use assignment for the already-constructed elements.
989  std::move(RHS.begin(), RHS.begin() + CurSize, this->begin());
990  }
991 
992  // Move-construct the new elements in place.
993  this->uninitialized_move(RHS.begin() + CurSize, RHS.end(), this->begin() + CurSize);
994 
995  // Set end.
996  this->setEnd(this->begin() + RHSSize);
997 
998  RHS.clear();
999  return *this;
1000 }
1001 
1006 template <typename T, unsigned N>
1007 struct SmallVectorStorage
1008 {
1010 };
1011 template <typename T>
1013 {
1014 };
1015 template <typename T>
1017 {
1018 };
1019 
1028 template <typename T, unsigned N>
1029 class SmallVector : public SmallVectorImpl<T>
1030 {
1033 
1034 public:
1036  {
1037  }
1038 
1039  explicit SmallVector(size_t Size, const T& Value = T()) : SmallVectorImpl<T>(N)
1040  {
1041  this->assign(Size, Value);
1042  }
1043 
1044  template <typename ItTy>
1045  SmallVector(ItTy S, ItTy E) : SmallVectorImpl<T>(N)
1046  {
1047  this->append(S, E);
1048  }
1049 
1050  /*
1051  template <typename RangeTy>
1052  explicit SmallVector(const llvm_vecsmall::iterator_range<RangeTy> &R)
1053  : SmallVectorImpl<T>(N) {
1054  this->append(R.begin(), R.end());
1055  }
1056  */
1057 
1058  SmallVector(std::initializer_list<T> IL) : SmallVectorImpl<T>(N)
1059  {
1060  this->assign(IL);
1061  }
1062 
1064  {
1065  if (!RHS.empty())
1067  }
1068 
1069  const SmallVector& operator=(const SmallVector& RHS)
1070  {
1072  return *this;
1073  }
1074 
1076  {
1077  if (!RHS.empty())
1079  }
1080 
1082  {
1084  return *this;
1085  }
1086 
1088  {
1089  if (!RHS.empty())
1091  }
1092 
1094  {
1096  return *this;
1097  }
1098 
1099  const SmallVector& operator=(std::initializer_list<T> IL)
1100  {
1101  this->assign(IL);
1102  return *this;
1103  }
1104 };
1105 
1106 template <typename T, unsigned N>
1107 static inline size_t capacity_in_bytes(const SmallVector<T, N>& X)
1108 {
1109  return X.capacity_in_bytes();
1110 }
1111 
1112 } // namespace llvm_vecsmall
1113 
1114 namespace std
1115 {
1117 template <typename T>
1120 {
1121  LHS.swap(RHS);
1122 }
1123 
1125 template <typename T, unsigned N>
1128 {
1129  LHS.swap(RHS);
1130 }
1131 } // namespace std
1132 
1133 namespace llvm_vecsmall
1134 {
1137 inline void SmallVectorBase::grow_pod(void* FirstEl, size_t MinSizeInBytes, size_t TSize)
1138 {
1139  size_t CurSizeBytes = size_in_bytes();
1140  size_t NewCapacityInBytes = 2 * capacity_in_bytes() + TSize; // Always grow.
1141  if (NewCapacityInBytes < MinSizeInBytes)
1142  NewCapacityInBytes = MinSizeInBytes;
1143 
1144  void* NewElts;
1145  if (BeginX == FirstEl)
1146  {
1147  NewElts = malloc(NewCapacityInBytes);
1148 
1149  // Copy the elements over. No need to run dtors on PODs.
1150  memcpy(NewElts, this->BeginX, CurSizeBytes);
1151  }
1152  else
1153  {
1154  // If this wasn't grown from the inline copy, grow the allocated space.
1155  NewElts = realloc(this->BeginX, NewCapacityInBytes);
1156  }
1157  assert(NewElts && "Out of memory");
1158 
1159  this->EndX = (char*)NewElts + CurSizeBytes;
1160  this->BeginX = NewElts;
1161  this->CapacityX = (char*)this->BeginX + NewCapacityInBytes;
1162 }
1163 } // namespace llvm_vecsmall
1164 
1165 #endif
llvm_vecsmall::SmallVectorTemplateCommon::back
const_reference back() const
Definition: SmallVector.h:267
llvm_vecsmall::SmallVectorTemplateCommon::U
std::aligned_union< 1, T >::type U
Definition: SmallVector.h:113
llvm_vecsmall::SmallVectorTemplateBase::uninitialized_copy
static void uninitialized_copy(It1 I, It1 E, It2 Dest)
Definition: SmallVector.h:304
llvm_vecsmall::SmallVectorTemplateBase< T, true >::push_back
void push_back(const T &Elt)
Definition: SmallVector.h:422
llvm_vecsmall::SmallVectorTemplateCommon::begin
LLVM_VECSMALL_ATTRIBUTE_ALWAYS_INLINE iterator begin()
Definition: SmallVector.h:162
llvm_vecsmall::SmallVectorTemplateBase< T, true >::pop_back
void pop_back()
Definition: SmallVector.h:430
llvm_vecsmall::SmallVectorImpl::resize
void resize(size_type N)
Definition: SmallVector.h:474
llvm_vecsmall::SmallVectorBase::EndX
void * EndX
Definition: SmallVector.h:65
llvm_vecsmall
Definition: SmallVector.h:32
llvm_vecsmall::SmallVectorTemplateCommon::size
LLVM_VECSMALL_ATTRIBUTE_ALWAYS_INLINE size_type size() const
Definition: SmallVector.h:212
llvm_vecsmall::SmallVectorImpl::operator<
bool operator<(const SmallVectorImpl &RHS) const
Definition: SmallVector.h:813
llvm_vecsmall::SmallVectorTemplateCommon::capacity_ptr
iterator capacity_ptr()
Definition: SmallVector.h:183
detail::copy
auto copy(const Range &range, OutputIt out) -> OutputIt
Definition: ranges.h:22
llvm_vecsmall::SmallVectorTemplateCommon::operator[]
LLVM_VECSMALL_ATTRIBUTE_ALWAYS_INLINE reference operator[](size_type idx)
Definition: SmallVector.h:239
llvm_vecsmall::SmallVectorBase::CapacityX
void * CapacityX
Definition: SmallVector.h:65
llvm_vecsmall::SmallVectorTemplateCommon::max_size
size_type max_size() const
Definition: SmallVector.h:216
LLVM_VECSMALL_UNLIKELY
#define LLVM_VECSMALL_UNLIKELY(x)
Definition: SmallVector.h:29
backward::ColorMode::type
type
Definition: backward.hpp:3600
nonstd::span_lite::size_t
span_CONFIG_SIZE_TYPE size_t
Definition: span.hpp:576
LLVM_VECSMALL_ATTRIBUTE_ALWAYS_INLINE
#define LLVM_VECSMALL_ATTRIBUTE_ALWAYS_INLINE
Definition: SmallVector.h:28
llvm_vecsmall::SmallVector::operator=
const SmallVector & operator=(std::initializer_list< T > IL)
Definition: SmallVector.h:1099
llvm_vecsmall::SmallVectorTemplateCommon::rbegin
reverse_iterator rbegin()
Definition: SmallVector.h:194
llvm_vecsmall::SmallVectorTemplateCommon::begin
LLVM_VECSMALL_ATTRIBUTE_ALWAYS_INLINE const_iterator begin() const
Definition: SmallVector.h:167
llvm_vecsmall::SmallVector::SmallVector
SmallVector(SmallVectorImpl< T > &&RHS)
Definition: SmallVector.h:1087
llvm_vecsmall::SmallVectorTemplateBase::push_back
void push_back(const T &Elt)
Definition: SmallVector.h:315
llvm_vecsmall::SmallVectorImpl::~SmallVectorImpl
~SmallVectorImpl()
Definition: SmallVector.h:458
X
#define X(name, r, bit)
Definition: zstd.c:4805
llvm_vecsmall::SmallVectorBase::capacity_in_bytes
size_t capacity_in_bytes() const
capacity_in_bytes - This returns capacity()*sizeof(T).
Definition: SmallVector.h:85
llvm_vecsmall::SmallVectorImpl
Definition: SmallVector.h:439
llvm_vecsmall::SmallVectorStorage::InlineElts
SmallVectorTemplateCommon< T >::U InlineElts[N - 1]
Definition: SmallVector.h:1009
llvm_vecsmall::SmallVector::SmallVector
SmallVector(size_t Size, const T &Value=T())
Definition: SmallVector.h:1039
llvm_vecsmall::SmallVector::SmallVector
SmallVector(SmallVector &&RHS)
Definition: SmallVector.h:1075
llvm_vecsmall::SmallVectorImpl::append
void append(in_iter in_start, in_iter in_end)
Add the specified range to the end of the SmallVector.
Definition: SmallVector.h:524
llvm_vecsmall::SmallVectorImpl::append
void append(std::initializer_list< T > IL)
Definition: SmallVector.h:548
LLVM_VECSMALL_NODISCARD
#define LLVM_VECSMALL_NODISCARD
Definition: SmallVector.h:27
llvm_vecsmall::SmallVectorImpl::insert
iterator insert(iterator I, size_type NumToInsert, const T &Elt)
Definition: SmallVector.h:668
llvm_vecsmall::SmallVectorTemplateCommon::front
reference front()
Definition: SmallVector.h:251
detail
Definition: args.h:19
llvm_vecsmall::SmallVectorTemplateCommon::size_type
size_t size_type
Definition: SmallVector.h:146
llvm_vecsmall::SmallVectorTemplateCommon::const_reference
const typedef T & const_reference
Definition: SmallVector.h:156
llvm_vecsmall::SmallVector::SmallVector
SmallVector()
Definition: SmallVector.h:1035
llvm_vecsmall::SmallVectorTemplateCommon::grow_pod
void grow_pod(size_t MinSizeInBytes, size_t TSize)
Definition: SmallVector.h:122
llvm_vecsmall::SmallVectorTemplateCommon::rend
const_reverse_iterator rend() const
Definition: SmallVector.h:206
llvm_vecsmall::SmallVectorTemplateBase::grow
void grow(size_t MinSize=0)
Definition: SmallVector.h:340
llvm_vecsmall::SmallVectorTemplateCommon::reverse_iterator
std::reverse_iterator< iterator > reverse_iterator
Definition: SmallVector.h:153
llvm_vecsmall::SmallVectorImpl::emplace_back
void emplace_back(ArgTypes &&... Args)
Definition: SmallVector.h:790
llvm_vecsmall::SmallVectorTemplateCommon::FirstEl
U FirstEl
Definition: SmallVector.h:114
llvm_vecsmall::SmallVectorTemplateCommon
Definition: SmallVector.h:103
llvm_vecsmall::SmallVector::operator=
const SmallVector & operator=(SmallVectorImpl< T > &&RHS)
Definition: SmallVector.h:1093
llvm_vecsmall::SmallVectorTemplateCommon::difference_type
ptrdiff_t difference_type
Definition: SmallVector.h:147
llvm_vecsmall::SmallVectorTemplateCommon::reference
T & reference
Definition: SmallVector.h:155
llvm_vecsmall::SmallVectorTemplateCommon::data
pointer data()
Return a pointer to the vector's buffer, even if empty().
Definition: SmallVector.h:228
llvm_vecsmall::SmallVectorTemplateCommon::capacity
size_t capacity() const
Return the total number of elements in the currently allocated buffer.
Definition: SmallVector.h:222
llvm_vecsmall::SmallVectorStorage
Definition: SmallVector.h:97
llvm_vecsmall::SmallVectorImpl::swap
void swap(SmallVectorImpl &RHS)
Definition: SmallVector.h:836
llvm_vecsmall::SmallVectorBase::size_in_bytes
size_t size_in_bytes() const
This returns size()*sizeof(T).
Definition: SmallVector.h:79
nonstd::span_lite::size
span_constexpr std::size_t size(span< T, Extent > const &spn)
Definition: span.hpp:1554
llvm_vecsmall::SmallVectorImpl::const_iterator
SuperClass::const_iterator const_iterator
Definition: SmallVector.h:447
llvm_vecsmall::SmallVectorBase::empty
LLVM_VECSMALL_NODISCARD bool empty() const
Definition: SmallVector.h:90
llvm_vecsmall::SmallVectorTemplateCommon::data
const_pointer data() const
Return a pointer to the vector's buffer, even if empty().
Definition: SmallVector.h:233
llvm_vecsmall::SmallVectorTemplateCommon::end
LLVM_VECSMALL_ATTRIBUTE_ALWAYS_INLINE const_iterator end() const
Definition: SmallVector.h:177
llvm_vecsmall::SmallVectorTemplateBase::uninitialized_move
static void uninitialized_move(It1 I, It1 E, It2 Dest)
Definition: SmallVector.h:296
llvm_vecsmall::SmallVectorImpl::append
void append(size_type NumInputs, const T &Elt)
Add the specified range to the end of the SmallVector.
Definition: SmallVector.h:537
llvm_vecsmall::SmallVectorImpl::insert
void insert(iterator I, std::initializer_list< T > IL)
Definition: SmallVector.h:784
llvm_vecsmall::SmallVectorImpl::reserve
void reserve(size_type N)
Definition: SmallVector.h:507
llvm_vecsmall::SmallVectorImpl::erase
iterator erase(const_iterator CI)
Definition: SmallVector.h:568
llvm_vecsmall::SmallVector::SmallVector
SmallVector(std::initializer_list< T > IL)
Definition: SmallVector.h:1058
llvm_vecsmall::SmallVectorTemplateBase< T, true >::grow
void grow(size_t MinSize=0)
Definition: SmallVector.h:416
llvm_vecsmall::SmallVectorImpl::insert
iterator insert(iterator I, T &&Elt)
Definition: SmallVector.h:603
llvm_vecsmall::SmallVectorBase
This is all the non-templated stuff common to all SmallVectors.
Definition: SmallVector.h:62
llvm_vecsmall::SmallVector::SmallVector
SmallVector(ItTy S, ItTy E)
Definition: SmallVector.h:1045
backward::details::move
const T & move(const T &v)
Definition: backward.hpp:394
llvm_vecsmall::SmallVectorImpl::assign
void assign(size_type NumElts, const T &Elt)
Definition: SmallVector.h:553
detail::fill_n
FMT_CONSTEXPR auto fill_n(OutputIt out, Size count, const T &value) -> OutputIt
Definition: format.h:582
std::swap
NLOHMANN_BASIC_JSON_TPL_DECLARATION void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL &j1, nlohmann::NLOHMANN_BASIC_JSON_TPL &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name) is_nothrow_move_constructible< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value &&//NOLINT(misc-redundant-expression) is_nothrow_move_assignable< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value)
exchanges the values of two JSON objects
Definition: json.hpp:21884
llvm_vecsmall::SmallVectorImpl::resize
void resize(size_type N, const T &NV)
Definition: SmallVector.h:491
llvm_vecsmall::SmallVectorImpl::operator==
bool operator==(const SmallVectorImpl &RHS) const
Definition: SmallVector.h:802
llvm_vecsmall::SmallVectorTemplateCommon::value_type
T value_type
Definition: SmallVector.h:148
llvm_vecsmall::SmallVector::Storage
SmallVectorStorage< T, N > Storage
Inline space for elements which aren't stored in the base class.
Definition: SmallVector.h:1032
llvm_vecsmall::SmallVectorImpl::operator!=
bool operator!=(const SmallVectorImpl &RHS) const
Definition: SmallVector.h:808
llvm_vecsmall::SmallVectorImpl::SuperClass
SmallVectorTemplateBase< T, IsPod< T >::value > SuperClass
Definition: SmallVector.h:441
llvm_vecsmall::SmallVectorImpl::insert
iterator insert(iterator I, ItTy From, ItTy To)
Definition: SmallVector.h:723
llvm_vecsmall::SmallVectorTemplateCommon::end
LLVM_VECSMALL_ATTRIBUTE_ALWAYS_INLINE iterator end()
Definition: SmallVector.h:172
llvm_vecsmall::SmallVectorTemplateCommon::const_reverse_iterator
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition: SmallVector.h:152
llvm_vecsmall::SmallVector::operator=
const SmallVector & operator=(SmallVector &&RHS)
Definition: SmallVector.h:1081
llvm_vecsmall::SmallVectorTemplateBase::pop_back
void pop_back()
Definition: SmallVector.h:331
llvm_vecsmall::SmallVectorTemplateCommon::rbegin
const_reverse_iterator rbegin() const
Definition: SmallVector.h:198
llvm_vecsmall::SmallVector::operator=
const SmallVector & operator=(const SmallVector &RHS)
Definition: SmallVector.h:1069
llvm_vecsmall::SmallVectorTemplateCommon::front
const_reference front() const
Definition: SmallVector.h:256
llvm_vecsmall::SmallVectorImpl::clear
void clear()
Definition: SmallVector.h:468
llvm_vecsmall::SmallVectorBase::SmallVectorBase
SmallVectorBase(void *FirstEl, size_t Size)
Definition: SmallVector.h:68
llvm_vecsmall::SmallVectorTemplateCommon::const_pointer
const typedef T * const_pointer
Definition: SmallVector.h:158
llvm_vecsmall::SmallVectorImpl::iterator
SuperClass::iterator iterator
Definition: SmallVector.h:446
llvm_vecsmall::SmallVectorTemplateCommon::setEnd
void setEnd(T *P)
Definition: SmallVector.h:140
llvm_vecsmall::SmallVectorTemplateCommon::operator[]
LLVM_VECSMALL_ATTRIBUTE_ALWAYS_INLINE const_reference operator[](size_type idx) const
Definition: SmallVector.h:245
assert
#define assert(condition)
Definition: lz4.c:271
llvm_vecsmall::SmallVectorTemplateBase::destroy_range
static void destroy_range(T *S, T *E)
Definition: SmallVector.h:284
llvm_vecsmall::SmallVectorTemplateBase
Definition: SmallVector.h:277
llvm_vecsmall::SmallVectorTemplateBase< T, true >::SmallVectorTemplateBase
SmallVectorTemplateBase(size_t Size)
Definition: SmallVector.h:371
llvm_vecsmall::SmallVectorTemplateCommon::const_iterator
const typedef T * const_iterator
Definition: SmallVector.h:150
llvm_vecsmall::SmallVectorImpl::insert
iterator insert(iterator I, const T &Elt)
Definition: SmallVector.h:636
std
llvm_vecsmall::SmallVectorBase::BeginX
void * BeginX
Definition: SmallVector.h:65
llvm_vecsmall::SmallVectorImpl::assign
void assign(std::initializer_list< T > IL)
Definition: SmallVector.h:562
llvm_vecsmall::SmallVectorTemplateCommon::rend
reverse_iterator rend()
Definition: SmallVector.h:202
llvm_vecsmall::SmallVectorTemplateCommon::isSmall
bool isSmall() const
Definition: SmallVector.h:129
llvm_vecsmall::SmallVectorTemplateBase< T, true >::uninitialized_copy
static void uninitialized_copy(T1 *I, T1 *E, T2 *Dest, typename std::enable_if< std::is_same< typename std::remove_const< T1 >::type, T2 >::value >::type *=nullptr)
Definition: SmallVector.h:401
llvm_vecsmall::SmallVectorBase::grow_pod
void grow_pod(void *FirstEl, size_t MinSizeInBytes, size_t TSize)
Definition: SmallVector.h:1137
llvm_vecsmall::SmallVectorImpl::erase
iterator erase(const_iterator CS, const_iterator CE)
Definition: SmallVector.h:584
llvm_vecsmall::SmallVector
Definition: SmallVector.h:1029
llvm_vecsmall::SmallVectorImpl::SmallVectorImpl
SmallVectorImpl(const SmallVectorImpl &)=delete
llvm_vecsmall::SmallVectorTemplateCommon::back
reference back()
Definition: SmallVector.h:262
llvm_vecsmall::SmallVectorImpl::pop_back_val
LLVM_VECSMALL_NODISCARD T pop_back_val()
Definition: SmallVector.h:513
llvm_vecsmall::SmallVectorImpl::operator=
SmallVectorImpl & operator=(const SmallVectorImpl &RHS)
Definition: SmallVector.h:881
llvm_vecsmall::SmallVectorTemplateBase< T, true >::uninitialized_copy
static void uninitialized_copy(It1 I, It1 E, It2 Dest)
Definition: SmallVector.h:392
llvm_vecsmall::IsPod
Definition: SmallVector.h:56
llvm_vecsmall::SmallVectorTemplateCommon::pointer
T * pointer
Definition: SmallVector.h:157
llvm_vecsmall::SmallVectorImpl::size_type
SuperClass::size_type size_type
Definition: SmallVector.h:448
llvm_vecsmall::SmallVectorTemplateCommon::resetToSmall
void resetToSmall()
Put this vector in a state of being small.
Definition: SmallVector.h:135
llvm_vecsmall::SmallVectorTemplateBase::push_back
void push_back(T &&Elt)
Definition: SmallVector.h:323
llvm_vecsmall::SmallVectorTemplateCommon::SmallVectorTemplateCommon
SmallVectorTemplateCommon(size_t Size)
Definition: SmallVector.h:118
Value
Definition: lobject.h:49
llvm_vecsmall::SmallVector::SmallVector
SmallVector(const SmallVector &RHS)
Definition: SmallVector.h:1063
S
#define S(x)
Definition: luac.c:667
llvm_vecsmall::SmallVectorTemplateBase< T, true >::uninitialized_move
static void uninitialized_move(It1 I, It1 E, It2 Dest)
Definition: SmallVector.h:383
llvm_vecsmall::SmallVectorTemplateCommon::capacity_ptr
const_iterator capacity_ptr() const
Definition: SmallVector.h:187
llvm_vecsmall::capacity_in_bytes
static size_t capacity_in_bytes(const SmallVector< T, N > &X)
Definition: SmallVector.h:1107
llvm_vecsmall::SmallVectorImpl::SmallVectorImpl
SmallVectorImpl(unsigned N)
Definition: SmallVector.h:452
llvm_vecsmall::SmallVectorImpl::set_size
void set_size(size_type N)
Definition: SmallVector.h:828
llvm_vecsmall::SmallVectorTemplateBase::SmallVectorTemplateBase
SmallVectorTemplateBase(size_t Size)
Definition: SmallVector.h:280
llvm_vecsmall::SmallVectorTemplateBase< T, true >::destroy_range
static void destroy_range(T *, T *)
Definition: SmallVector.h:376
llvm_vecsmall::SmallVectorTemplateCommon::iterator
T * iterator
Definition: SmallVector.h:149
RosMsgParser::ROSField
A ROSMessage will contain one or more ROSField(s). Each field is little more than a name / type pair.
Definition: ros_field.hpp:46
llvm_vecsmall::detail::NextPowerOf2
uint64_t NextPowerOf2(uint64_t A)
Definition: SmallVector.h:38


plotjuggler
Author(s): Davide Faconti
autogenerated on Mon Nov 11 2024 03:23:46