1 // This file's extension implies that it's C, but it's really -*- C++ -*-.
4 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
9 * @author scott snyder <snyder@bnl.gov>
11 * @brief Simple multidimensional arrays (inline and template implementations).
15 #include "CxxUtils/unused.h"
20 // cppcheck doesn't properly handle recursive templates like this.
26 * @brief Construct an @c Array<N>::const_iterator.
27 * @param rep @c Arrayrep from which to initialize the iterator.
28 * @param offs Offset of the first element referenced by the iterator
30 * @return The new iterator.
32 template <unsigned int N>
34 typename ArrayIteratorChooser<N>::const_iterator
35 ArrayIteratorChooser<N>::make_iterator (const Arrayrep* rep,
38 return const_iterator (rep, offs);
43 * @brief Construct an @c Array<1>::const_iterator.
44 * @param rep @c Arrayrep from which to initialize the iterator.
45 * @param offs Offset of the first element referenced by the iterator
47 * @return The new iterator.
50 ArrayIteratorChooser<1>::const_iterator
51 ArrayIteratorChooser<1>::make_iterator (const Arrayrep* rep,
54 return rep ? &rep->m_data[offs] : 0;
58 //**********************************************************************
62 * @brief Default constructor.
64 * This produces an invalid @c Array that is not associated with
65 * an @c Arrayrep. @c valid() will return @c false for such an array.
66 * The only other thing that it is legal to do with an invalid array
67 * is to assign to it (which may make it valid).
69 template <unsigned int N>
79 * @param rep @c Arrayrep from which to initialize the array.
81 * Initialize an array from an @c Arrayrep. The new array will
82 * represent the entire @c Arrayrep. The dimension @c N must
83 * match the length of the @c Arrayrep's shape.
85 template <unsigned int N>
86 Array<N>::Array (const Arrayrep& rep)
90 assert (m_rep->m_shape.size() == N);
91 assert (m_rep->m_sizes.size() == m_rep->m_shape.size());
96 * @brief Test for validity.
97 * @return True if the @c Array is associated with an @c Arrayrep,
100 template <unsigned int N>
101 bool Array<N>::valid() const
108 * @brief Return the array shape.
109 * @return The array shape.
111 * The array shape is vector with one element for each array dimension,
112 * giving the size of the array along that dimension.
114 template <unsigned int N>
115 std::vector<unsigned int> Array<N>::shape() const
117 return std::vector<unsigned int>
118 (m_rep->m_shape.begin() + m_rep->m_shape.size() - N,
119 m_rep->m_shape.end());
124 * @brief Return the size of the array along one dimension.
125 * @param dim The dimension of the size to retrieve.
126 * Must be less than the number of dimensions.
128 * As a special case, the size of an invalid array will always be 0.
129 * @return The array size along dimension @dim.
131 template <unsigned int N>
132 unsigned int Array<N>::size (unsigned int dim /*=0*/) const
135 if (!m_rep) return 0;
136 return m_rep->m_shape[m_rep->m_shape.size() - N + dim];
141 * @brief Array indexing.
142 * @param i The desired index. Must be less than the array size
143 * along this dimension.
144 * @return The @a i'th @c N-1 dimensional subarray in the array.
146 * Note that this operation is not available if @c N is 0.
148 template <unsigned int N>
150 Array<N-1> Array<N>::operator[] (unsigned int i) const
152 assert (i < m_rep->m_shape[m_rep->m_shape.size() - N]);
153 return Array<N-1> (*m_rep, m_offs + i * m_rep->m_sizes[N-1]);
158 * @brief Return a direct pointer to array elements.
159 * @return A pointer to the first array elements.
161 * Subsequent elements follow in standard C indexing order.
163 template <unsigned int N>
165 const Arrayelt* Array<N>::ptr () const
167 return &m_rep->m_data[m_offs];
172 * @brief Return an iterator pointing at the beginning of the container.
173 * @return An iterator pointing at the beginning of the container.
175 template <unsigned int N>
177 typename Array<N>::const_iterator Array<N>::begin () const
179 return ArrayIteratorChooser<N>::make_iterator (m_rep, m_offs);
184 * @brief Return an iterator pointing past the end of the container.
185 * @return An iterator pointing past the end of the container.
187 template <unsigned int N>
189 typename Array<N>::const_iterator Array<N>::end () const
191 unsigned int offs = m_rep ? m_offs + size() * m_rep->m_sizes[N-1] : 0;
192 return ArrayIteratorChooser<N>::make_iterator (m_rep, offs);
197 * @brief Creates a text representation of the array content.
198 * @param std::ostream where the text should be written
200 * Writes the content of the array to a ostream. The sub-arrays are
201 * enclosed by square brackets and separated by commas.
203 template <unsigned int N>
205 void Array<N>::write_array (std::ostream& stream) const
211 m_rep->write_array (stream);
217 * @brief Private constructor for array indexing.
218 * @param rep @c Arrayrep from which to initialize the array.
219 * @param offs Offset of the first element of the new array
222 * This is a private constructor used to make the @c Array
223 * instances returned from an indexing operation.
225 template <unsigned int N>
227 Array<N>::Array (const Arrayrep& rep, unsigned int offs)
235 * @brief Default constructor.
237 * This produces an invalid @c Array that is not associated with
238 * an @c Arrayrep. @c valid() will return @c false for such an array.
239 * The only other thing that it is legal to do with an invalid array
240 * is to assign to it (which may make it valid).
250 * @brief Constructor.
251 * @param rep @c Arrayrep from which to initialize the array.
253 * Initialize an array from an @c Arrayrep. The new array will
254 * represent the entire @c Arrayrep. The dimension @c N must
255 * match the length of the @c Arrayrep's shape.
258 Array<0>::Array (const Arrayrep& rep)
259 : m_elt (&rep.m_data[0])
261 assert (rep.m_shape.size() == 0);
262 assert (rep.m_sizes.size() == rep.m_shape.size());
267 * @brief Test for validity.
268 * @return True if the @c Array is associated with an @c Arrayrep,
272 bool Array<0>::valid() const
279 * @brief Return the array shape.
280 * @return The array shape.
282 * The array shape is vector with one element for each array dimension,
283 * giving the size of the array along that dimension.
284 * For @c Array<0>, this will always be an empty array.
287 std::vector<unsigned int> Array<0>::shape() const
289 return std::vector<unsigned int> ();
294 * @brief Return the size of the array along one dimension.
295 * @param dim The dimension of the size to retrieve.
296 * Must be less than the number of dimensions.
297 * @return The array size along dimension @dim.
299 * For @c Array<0>, @a dim must be 0, and the function
300 * will always return 1.
303 unsigned int Array<0>::size ([[maybe_unused]] unsigned int dim /*=0*/) const
311 * @brief Convert to a number.
312 * @return The @c Array<0> contents as a number.
315 Array<0>::operator Arrayelt() const
322 * @brief Convert to an integer.
323 * @return The @c Array<0> contents as an integer.
326 int Array<0>::asint() const
328 return static_cast<int> (*m_elt);
333 * @brief Creates a text representation of the array content.
334 * @param std::ostream where the text should be written
336 * Writes the content of the array to a ostream. The sub-arrays are
337 * enclosed by square brackets and separated by commas.
340 void Array<0>::write_array (std::ostream& stream) const
347 * @brief Private constructor for array indexing.
348 * @param rep @c Arrayrep from which to initialize the array.
349 * @param offs Offset of the first element of the new array
352 * This is a private constructor used to make the @c Array
353 * instances returned from an indexing operation.
356 Array<0>::Array (const Arrayrep& rep, unsigned int offs)
357 : m_elt (&rep.m_data[offs])
362 template <unsigned int N>
363 std::ostream& operator<< (std::ostream& s, const Array<N>& a)
370 //**********************************************************************
374 * @brief Proxy constructor.
375 * @param i The iterator that is being dereferenced.
377 template <unsigned int N>
378 ArrayIterator<N>::pointer::pointer (const ArrayIterator& i)
385 * @brief Dereference the proxy.
386 * @return A copy of the @c Array proxy.
388 template <unsigned int N>
389 typename ArrayIterator<N>::value_type
390 ArrayIterator<N>::pointer::operator* () const
397 * @brief Dereference the proxy.
398 * @return A pointer to the @c Array proxy.
399 * This proxy is only until the @c pointer instance
402 template <unsigned int N>
403 const typename ArrayIterator<N>::value_type*
404 ArrayIterator<N>::pointer::operator-> () const
411 * @brief Default constructor.
412 * Makes an invalid iterator.
414 template <unsigned int N>
415 ArrayIterator<N>::ArrayIterator ()
423 * @brief Constructor from @c Arrayrep and offset.
424 * @param rep The underlying array representation.
425 * @param offs The offset in the representation of the
426 * first element referenced by this iterator.
428 template <unsigned int N>
429 ArrayIterator<N>::ArrayIterator (const Arrayrep* rep, unsigned int offs)
437 * @brief Equality comparison.
438 * @param other The other object with which to compare.
439 * @return True if the iterators are equal.
441 template <unsigned int N>
442 bool ArrayIterator<N>::operator== (const ArrayIterator<N>& other) const
444 return m_rep == other.m_rep && m_offs == other.m_offs;
449 * @brief Inequality comparison.
450 * @param other The other object with which to compare.
451 * @return True if the iterators are not equal.
453 template <unsigned int N>
454 bool ArrayIterator<N>::operator!= (const ArrayIterator<N>& other) const
456 return !(*this == other);
461 * @brief Less-than comparison.
462 * @param other The other object with which to compare.
463 * @return True if this iterator is less than @a other.
464 * This will always return false for iterators
465 * over different arrays.
467 template <unsigned int N>
468 bool ArrayIterator<N>::operator< (const ArrayIterator<N>& other) const
470 return m_rep == other.m_rep && m_offs < other.m_offs;
475 * @brief Greater-than comparison.
476 * @param other The other object with which to compare.
477 * @return True if this iterator is greater than @a other.
478 * This will always return false for iterators
479 * over different arrays.
481 template <unsigned int N>
482 bool ArrayIterator<N>::operator> (const ArrayIterator<N>& other) const
484 return other < *this;
489 * @brief Less-than-or-equal comparison.
490 * @param other The other object with which to compare.
491 * @return True if this iterator is less than or equal to @a other.
492 * This will always return false for iterators
493 * over different arrays.
495 template <unsigned int N>
496 bool ArrayIterator<N>::operator<= (const ArrayIterator<N>& other) const
498 return m_rep == other.m_rep && m_offs <= other.m_offs;
503 * @brief Greater-than-or-equal comparison.
504 * @param other The other object with which to compare.
505 * @return True if this iterator is less than or equal to @a other.
506 * This will always return false for iterators
507 * over different arrays.
509 template <unsigned int N>
510 bool ArrayIterator<N>::operator>= (const ArrayIterator<N>& other) const
512 return other <= *this;
517 * @brief Dereference the iterator.
518 * @return The value that the iterator points to.
519 * Note that this method returns a @c value_type, not
520 * a @c reference. (Thus, this class does not quite
521 * conform to the iterator requirements.)
523 template <unsigned int N>
524 typename ArrayIterator<N>::value_type ArrayIterator<N>::operator* () const
526 assert (m_offs < m_rep->m_data.size());
527 return Array<N-1> (*m_rep, m_offs);
532 * @brief Dereference the iterator.
533 * @return A proxy for the iterator element.
535 * This method will return a proxy for the array, which you
536 * can then dereference. Note that if you get a C++ pointer
537 * from this, then it will be valid only until the proxy
538 * object gets destroyed.
540 template <unsigned int N>
541 typename ArrayIterator<N>::pointer ArrayIterator<N>::operator-> () const
543 return pointer (*this);
548 * @brief Advance the iterator.
549 * @returns This iterator.
551 template <unsigned int N>
552 ArrayIterator<N>& ArrayIterator<N>::operator++ ()
554 m_offs += m_rep->m_sizes[N-1];
560 * @brief Advance the iterator.
561 * @returns The iterator before being advanced.
563 template <unsigned int N>
564 ArrayIterator<N> ArrayIterator<N>::operator++ (int)
566 ArrayIterator tmp (*this);
567 m_offs += m_rep->m_sizes[N-1];
573 * @brief Back up the iterator.
574 * @returns This iterator.
576 template <unsigned int N>
577 ArrayIterator<N>& ArrayIterator<N>::operator-- ()
579 m_offs -= m_rep->m_sizes[N-1];
585 * @brief Back up the iterator.
586 * @returns The iterator before being backed up.
588 template <unsigned int N>
589 ArrayIterator<N> ArrayIterator<N>::operator-- (int)
591 ArrayIterator tmp (*this);
592 m_offs -= m_rep->m_sizes[N-1];
598 * @brief Array indexing relative to the iterator.
599 * @param n The array index.
600 * @return The array item at an offset of @a n from the
601 * current iterator position.
602 * Note that this method returns a @c value_type, not
603 * a @c reference. (Thus, this class does not quite
604 * conform to the iterator requirements.)
606 template <unsigned int N>
607 typename ArrayIterator<N>::value_type
608 ArrayIterator<N>::operator[] (difference_type n) const
610 unsigned int offs = m_offs + n * m_rep->m_sizes[N-1];
611 assert (offs < m_rep->m_data.size());
612 return Array<N-1> (*m_rep, offs);
617 * @brief Advance the iterator.
618 * @param n Number of steps by which to advance the iterator.
619 * @return This iterator.
621 template <unsigned int N>
622 ArrayIterator<N>& ArrayIterator<N>::operator+= (difference_type n)
624 m_offs += n * m_rep->m_sizes[N-1];
630 * @brief Return a new iterator pointing @a n steps ahead.
631 * @param n Number of steps by which to advance.
632 * @return The new iterator.
634 template <unsigned int N>
635 ArrayIterator<N> ArrayIterator<N>::operator+ (difference_type n) const
637 return ArrayIterator (m_rep, m_offs + n * m_rep->m_sizes[N-1]);
642 * @brief Back up the iterator.
643 * @param n Number of steps by which to advance the iterator.
644 * @return This iterator.
646 template <unsigned int N>
647 ArrayIterator<N>& ArrayIterator<N>::operator-= (difference_type n)
649 m_offs -= n * m_rep->m_sizes[N-1];
655 * @brief Return a new iterator pointing @a n steps behind.
656 * @param n Number of steps by which to back up.
657 * @return The new iterator.
659 template <unsigned int N>
660 ArrayIterator<N> ArrayIterator<N>::operator- (difference_type n) const
662 return ArrayIterator (m_rep, m_offs - n * m_rep->m_sizes[N-1]);
667 * @brief Return the difference between two iterators.
668 * @param other The other iterator for the comparison.
669 * @return The number of elements difference between
670 * this iterator and @a other.
671 * Undefined if the two iterators do not point
672 * into the same array.
674 template <unsigned int N>
675 typename ArrayIterator<N>::difference_type
676 ArrayIterator<N>::operator- (const ArrayIterator& other) const
678 return (m_offs - other.m_offs) / m_rep->m_sizes[N-1];
682 //**********************************************************************
686 * @brief Constructor.
687 * @param rep @c Arrayrep from which to initialize the array.
689 * Initialize an array from an @c Arrayrep. The new array will
690 * represent the entire @c Arrayrep. The dimension @c N must
691 * match the length of the @c Arrayrep's shape.
693 template <unsigned int N>
695 WritableArray<N>::WritableArray (Arrayrep& rep)
703 * @brief Array indexing.
704 * @param i The desired index. Must be less than the array size
705 * along this dimension.
706 * @return The @a i'th @c N-1 dimensional subarray in the array.
708 * Note that this operation is not available if @c N is 0.
710 template <unsigned int N>
712 WritableArray<N-1> WritableArray<N>::operator[] (unsigned int i)
714 assert (i < this->m_rep_nc->m_shape[this->m_rep_nc->m_shape.size() - N]);
715 return WritableArray<N-1> (*this->m_rep_nc,
716 this->m_offs + i * this->m_rep_nc->m_sizes[N-1]);
721 * @brief Array indexing.
722 * @param i The desired index. Must be less than the array size
723 * along this dimension.
724 * @return The @a i'th @c N-1 dimensional subarray in the array.
726 * Note that this operation is not available if @c N is 0.
728 template <unsigned int N>
730 Array<N-1> WritableArray<N>::operator[] (unsigned int i) const
732 assert (i < this->m_rep_nc->m_shape[this->m_rep_nc->m_shape.size() - N]);
733 return Array<N-1> (*this->m_rep_nc,
734 this->m_offs + i * this->m_rep_nc->m_sizes[N-1]);
739 * @brief Return a direct pointer to array elements.
740 * @return A pointer to the first array elements.
742 * Subsequent elements follow in standard C indexing order.
744 template <unsigned int N>
746 Arrayelt* WritableArray<N>::ptr ()
748 return &this->m_rep_nc->m_data[this->m_offs];
753 * @brief Private constructor for array indexing.
754 * @param rep @c Arrayrep from which to initialize the array.
755 * @param offs Offset of the first element of the new array
758 * This is a private constructor used to make the @c Array
759 * instances returned from an indexing operation.
761 template <unsigned int N>
763 WritableArray<N>::WritableArray (Arrayrep& rep, unsigned int offs)
764 : Array<N> (rep, offs),
771 * @brief Constructor.
772 * @param rep @c Arrayrep from which to initialize the array.
774 * Initialize an array from an @c Arrayrep. The new array will
775 * represent the entire @c Arrayrep. The dimension @c N must
776 * match the length of the @c Arrayrep's shape.
779 WritableArray<0>::WritableArray (Arrayrep& rep)
781 m_elt_nc (&rep.m_data[0])
788 * @param elt The RHS of the assignment.
789 * @return This object.
791 * Assign into the array.
794 WritableArray<0>& WritableArray<0>::operator= (Arrayelt elt)
802 * @brief Private constructor for array indexing.
803 * @param rep @c Arrayrep from which to initialize the array.
804 * @param offs Offset of the first element of the new array
807 * This is a private constructor used to make the @c Array
808 * instances returned from an indexing operation.
811 WritableArray<0>::WritableArray (Arrayrep& rep, unsigned int offs)
812 : Array<0> (rep, offs),
813 m_elt_nc (&rep.m_data[offs])
818 //**********************************************************************
822 * @brief Constructor.
823 * @param shape The shape of the array, as a C array.
824 * Should be @c N elements long. \
826 * The shape is the size of the array along each dimension.
828 template <unsigned int N>
829 WritableArrayData<N>::WritableArrayData(const unsigned int shape[])
830 : Arrayrep (shape, N),
831 WritableArray<N> (*static_cast<Arrayrep*>(this))
837 * @brief Constructor.
838 * @param shape The shape of the array, as a std::vector.
839 * Should be @c N elements long.
841 * The shape is the size of the array along each dimension.
843 template <unsigned int N>
844 WritableArrayData<N>::WritableArrayData(const std::vector<unsigned int>& shape)
846 WritableArray<N> (*static_cast<Arrayrep*>(this))
848 assert (shape.size() == N);
853 * @brief Helper to convert from an @x Arrayrep to a scalar type.
854 * @param rep Representation object to convert.
855 * @param x[out] Result of the conversion.
858 ATH_REQUIRES(std::assignable_from<T&, float>)
859 void fromArrayrep (const CaloRec::Arrayrep& rep, T& x)
866 * @brief Helper to convert from an @x Arrayrep to an @c Array.
867 * @param rep Representation object to convert.
868 * @param x[out] Result of the conversion.
870 template <unsigned int N>
871 void fromArrayrep (const CaloRec::Arrayrep& rep, CxxUtils::Array<N>& x)
873 x = CxxUtils::Array<N> (rep);
877 } // namespace CxxUtils
878 #endif // not __CPPCHECK__