/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2012,2013, by the GROMACS development team, led by
- * David van der Spoel, Berk Hess, Erik Lindahl, and including many
- * others, as listed in the AUTHORS file in the top-level source
- * directory and at http://www.gromacs.org.
+ * Copyright (c) 2012,2013,2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
*
* GROMACS is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
*/
/*! \file
* \brief
- * Declares gmx::ConstArrayRef.
+ * Declares gmx::ArrayRef and gmx::ConstArrayRef.
*
* \author Teemu Murtola <teemu.murtola@gmail.com>
* \inpublicapi
#include <utility>
#include <vector>
-#include "gmxassert.h"
+#include "gromacs/utility/gmxassert.h"
namespace gmx
{
/*! \brief
- * STL container non-mutable interface for a C array (or part of a std::vector).
+ * Tag type to initialize empty array references.
+ *
+ * This type (together with appropriate constructors in ArrayRef and
+ * ConstArrayRef) allows initializing any array reference to an empty value
+ * without explicitly specifying its type. This is convenient when calling
+ * a function that takes an array reference, where constructing an empty
+ * reference explicitly would otherwise require specifying the full array
+ * reference type, including the template parameter.
+ */
+struct EmptyArrayRef {};
+
+/*! \brief
+ * STL-like container for an interface to a C array (or part of a std::vector).
+ *
+ * \tparam T Value type of elements.
+ *
+ * This class provides an interface similar to \c std::vector<T>, with the
+ * following main differences:
+ * - This class does not have its own storage. Instead, it references an
+ * existing array of values (either a C-style array or part of an existing
+ * std::vector<T>).
+ * - It is only possible to modify the values themselves through ArrayRef;
+ * it is not possible to add or remove values.
+ * - Copying objects of this type is cheap, and the copies behave identically
+ * to the original object: the copy references the same set of values.
+ *
+ * This class is useful for writing wrappers that expose a different view of
+ * the internal data stored as a single vector/array.
+ *
+ * Methods in this class do not throw, except where indicated.
+ *
+ * Note that due to a Doxygen limitation, the constructor that takes a C array
+ * whose size is known at compile time does not appear in the documentation.
+ *
+ * \todo
+ * This class is not complete. At least, it should be possible to convert an
+ * ArrayRef to a ConstArrayRef. There are likely also methods missing (not
+ * required for current usage).
+ *
+ * \inpublicapi
+ * \ingroup module_utility
+ */
+template <typename T>
+class ArrayRef
+{
+ public:
+ //! Type of values stored in the container.
+ typedef T value_type;
+ //! Type for representing size of the container.
+ typedef size_t size_type;
+ //! Type for representing difference between two container indices.
+ typedef ptrdiff_t difference_type;
+ //! Const reference to a container element.
+ typedef const T &const_reference;
+ //! Const pointer to a container element.
+ typedef const T *const_pointer;
+ //! Const iterator type for the container.
+ typedef const T *const_iterator;
+ //! Reference to a container element.
+ typedef T &reference;
+ //! Pointer to a container element.
+ typedef T *pointer;
+ //! Iterator type for the container.
+ typedef T *iterator;
+ //! Standard reverse iterator.
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ //! Standard reverse iterator.
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+ /*! \brief
+ * Constructs an empty reference.
+ */
+ ArrayRef() : begin_(NULL), end_(NULL) {}
+ /*! \brief
+ * Constructs an empty reference.
+ *
+ * This is provided for convenience, such that EmptyArrayRef can be
+ * used to initialize any ArrayRef, without specifying the template
+ * type. It is not explicit to enable that usage.
+ */
+ ArrayRef(const EmptyArrayRef &) : begin_(NULL), end_(NULL) {}
+ /*! \brief
+ * Constructs a reference to a particular range.
+ *
+ * \param[in] begin Pointer to the beginning of a range.
+ * \param[in] end Pointer to the end of a range.
+ *
+ * Passed pointers must remain valid for the lifetime of this object.
+ *
+ * \note For clarity, use the non-member function arrayRefFromPointers
+ * instead.
+ */
+ ArrayRef(pointer begin, pointer end)
+ : begin_(begin), end_(end)
+ {
+ GMX_ASSERT(end >= begin, "Invalid range");
+ }
+ //! \cond
+ // Doxygen 1.8.5 doesn't parse the declaration correctly...
+ /*! \brief
+ * Constructs a reference to a C array.
+ *
+ * \param[in] array C array to reference.
+ * \tparam count Deduced number of elements in \p array.
+ *
+ * This constructor can only be used with a real array (not with a
+ * pointer). It constructs a reference to the whole array, without
+ * a need to pass the number of elements explicitly. The compiler
+ * must be able to deduce the array size.
+ *
+ * Passed array must remain valid for the lifetime of this object.
+ *
+ * This constructor is not explicit to allow directly passing
+ * a C array to a function that takes an ArrayRef parameter.
+ */
+ template <size_t count>
+ ArrayRef(value_type (&array)[count])
+ : begin_(array), end_(array + count)
+ {
+ }
+ //! \endcond
+
+ //! Returns an iterator to the beginning of the container.
+ iterator begin() { return begin_; }
+ //! Returns an iterator to the beginning of the container.
+ const_iterator begin() const { return begin_; }
+ //! Returns an iterator to the end of the container.
+ iterator end() { return end_; }
+ //! Returns an iterator to the end of the container.
+ const_iterator end() const { return end_; }
+ //! Returns an iterator to the reverse beginning of the container.
+ iterator rbegin() { return reverse_iterator(end()); }
+ //! Returns an iterator to the reverse beginning of the container.
+ const_iterator rbegin() const { return reverse_iterator(end()); }
+ //! Returns an iterator to the reverse end of the container.
+ iterator rend() { return reverse_iterator(begin()); }
+ //! Returns an iterator to the reverse end of the container.
+ const_iterator rend() const { return reverse_iterator(begin()); }
+
+ //! Returns the size of the container.
+ size_type size() const { return end_ - begin_; }
+ //! Identical to size().
+ size_type capacity() const { return end_ - begin_; }
+ //! Whether the container is empty.
+ bool empty() const { return begin_ == end_; }
+
+ //! Access container element.
+ reference operator[](size_type n) { return begin_[n]; }
+ //! Access container element.
+ const_reference operator[](size_type n) const { return begin_[n]; }
+ //! Access container element (throws on out-of-range error).
+ reference at(size_type n)
+ {
+ if (n >= size())
+ {
+ throw std::out_of_range("Vector index out of range");
+ }
+ return begin_[n];
+ }
+ //! Access container element (throws on out-of-range error).
+ const_reference at(size_type n) const
+ {
+ if (n >= size())
+ {
+ throw std::out_of_range("Vector index out of range");
+ }
+ return begin_[n];
+ }
+ //! Returns the first element in the container.
+ reference front() { return *begin_; }
+ //! Returns the first element in the container.
+ const_reference front() const { return *begin_; }
+ //! Returns the last element in the container.
+ reference back() { return *(end_ - 1); }
+ //! Returns the last element in the container.
+ const_reference back() const { return *(end_ - 1); }
+
+ //! Returns a raw pointer to the contents of the array.
+ pointer data() { return begin_; }
+ //! Returns a raw pointer to the contents of the array.
+ const_pointer data() const { return begin_; }
+
+ /*! \brief
+ * Swaps referenced memory with the other object.
+ *
+ * The actual memory areas are not modified, only the references are
+ * swapped.
+ */
+ void swap(ArrayRef<T> &other)
+ {
+ std::swap(begin_, other.begin_);
+ std::swap(end_, other.end_);
+ }
+
+ private:
+ pointer begin_;
+ pointer end_;
+};
+
+
+/*! \brief
+ * Constructs a reference to a particular range from two pointers.
+ *
+ * \param[in] begin Pointer to the beginning of a range.
+ * \param[in] end Pointer to the end of a range.
+ *
+ * Passed pointers must remain valid for the lifetime of this object.
+ *
+ * \related ArrayRef
+ */
+template <typename T>
+ArrayRef<T> arrayRefFromPointers(T * begin, T * end)
+{
+ return ArrayRef<T>(begin, end);
+}
+
+/*! \brief
+ * Constructs a reference to an array
+ *
+ * \param[in] begin Pointer to the beginning of the array.
+ * May be NULL if \p size is zero.
+ * \param[in] size Number of elements in the array.
+ *
+ * Passed pointer must remain valid for the lifetime of this object.
+ *
+ * \related ArrayRef
+ */
+template <typename T>
+ArrayRef<T> arrayRefFromArray(T * begin, size_t size)
+{
+ return arrayRefFromPointers<T>(begin, begin+size);
+}
+
+/*! \brief
+ * Constructs a reference to a particular range in a std::vector.
+ *
+ * \param[in] begin Iterator to the beginning of a range.
+ * \param[in] end Iterator to the end of a range.
+ *
+ * The referenced vector must remain valid and not be reallocated for
+ * the lifetime of this object.
+ *
+ * \related ArrayRef
+ */
+template <typename T>
+ArrayRef<T> arrayRefFromVector(typename std::vector<T>::iterator begin,
+ typename std::vector<T>::iterator end)
+{
+ T * p_begin = (begin != end) ? &*begin : NULL;
+ T * p_end = p_begin + (end-begin);
+ return arrayRefFromPointers<T>(p_begin, p_end);
+}
+
+
+
+/*! \brief
+ * STL-like container for non-mutable interface to a C array (or part of a
+ * std::vector).
*
* \tparam T Value type of elements.
*
* - Copying objects of this type is cheap, and the copies behave identically
* to the original object: the copy references the same set of values.
*
+ * This class is useful for writing wrappers that expose a different view of
+ * the internal data stored as a single vector/array.
+ *
+ * Methods in this class do not throw, except where indicated.
+ *
+ * Note that due to a Doxygen limitation, the constructor that takes a C array
+ * whose size is known at compile time does not appear in the documentation.
+ *
* \inpublicapi
* \ingroup module_utility
*/
* Constructs an empty reference.
*/
ConstArrayRef() : begin_(NULL), end_(NULL) {}
+ /*! \brief
+ * Constructs an empty reference.
+ *
+ * This is provided for convenience, such that EmptyArrayRef can be
+ * used to initialize any Const ArrayRef, without specifying the
+ * template type. It is not explicit to enable that usage.
+ */
+ ConstArrayRef(const EmptyArrayRef &) : begin_(NULL), end_(NULL) {}
/*! \brief
* Constructs a reference to a particular range.
*
* \param[in] end Pointer to the end of a range.
*
* Passed pointers must remain valid for the lifetime of this object.
+ *
+ * \note For clarity, use the non-member function constArrayRefFromPointers
+ * instead.
*/
ConstArrayRef(const_pointer begin, const_pointer end)
: begin_(begin), end_(end)
{
GMX_ASSERT(end >= begin, "Invalid range");
}
+ //! \cond
+ // Doxygen 1.8.5 doesn't parse the declaration correctly...
/*! \brief
- * Constructs a reference to a particular rangein a std::vector.
- *
- * \param[in] begin Pointer to the beginning of a range.
- * \param[in] end Pointer to the end of a range.
+ * Constructs a reference to a C array.
*
- * The referenced vector must remain valid and not be reallocated for
- * the lifetime of this object.
- */
- ConstArrayRef(typename std::vector<T>::const_iterator begin,
- typename std::vector<T>::const_iterator end)
- : begin_((begin != end) ? &*begin : NULL),
- end_(begin_+(end-begin))
- {
- GMX_ASSERT(end >= begin, "Invalid range");
- }
- /*! \brief
- * Constructs a reference to an array.
+ * \param[in] array C array to reference.
+ * \tparam count Deduced number of elements in \p array.
*
- * \param[in] begin Pointer to the beginning of the array.
- * May be NULL if \p size is zero.
- * \param[in] size Number of elements in the array.
+ * This constructor can only be used with a real array (not with a
+ * pointer). It constructs a reference to the whole array, without
+ * a need to pass the number of elements explicitly. The compiler
+ * must be able to deduce the array size.
+ * Passed array must remain valid for the lifetime of this object.
*
- * Passed pointer must remain valid for the lifetime of this object.
+ * This constructor is not explicit to allow directly passing
+ * a C array to a function that takes a ConstArrayRef parameter.
*/
- ConstArrayRef(const_pointer begin, size_type size)
- : begin_(begin), end_(begin + size)
+ template <size_t count>
+ ConstArrayRef(const value_type (&array)[count])
+ : begin_(array), end_(array + count)
{
}
+ //! \endcond
- //! Returns an interator to the beginning of the container.
+ //! Returns an iterator to the beginning of the container.
const_iterator begin() const { return begin_; }
- //! Returns an interator to the end of the container.
+ //! Returns an iterator to the end of the container.
const_iterator end() const { return end_; }
- //! Returns an interator to the reverse beginning of the container.
+ //! Returns an iterator to the reverse beginning of the container.
const_iterator rbegin() const { return reverse_iterator(end()); }
- //! Returns an interator to the reverse end of the container.
+ //! Returns an iterator to the reverse end of the container.
const_iterator rend() const { return reverse_iterator(begin()); }
//! Returns the size of the container.
const_pointer end_;
};
+
+/*! \brief
+ * Constructs a reference to a particular range from two pointers.
+ *
+ * \param[in] begin Pointer to the beginning of a range.
+ * \param[in] end Pointer to the end of a range.
+ *
+ * Passed pointers must remain valid for the lifetime of this object.
+ *
+ * \related ConstArrayRef
+ */
+template <typename T>
+ConstArrayRef<T> constArrayRefFromPointers(const T * begin, const T * end)
+{
+ return ConstArrayRef<T>(begin, end);
+}
+
+/*! \brief
+ * Constructs a reference to an array.
+ *
+ * \param[in] begin Pointer to the beginning of the array.
+ * May be NULL if \p size is zero.
+ * \param[in] size Number of elements in the array.
+ *
+ * Passed pointer must remain valid for the lifetime of this object.
+ *
+ * \related ConstArrayRef
+ */
+template <typename T>
+ConstArrayRef<T> constArrayRefFromArray(const T * begin, size_t size)
+{
+ return constArrayRefFromPointers<T>(begin, begin+size);
+}
+
+/*! \brief
+ * Constructs a reference to a particular range in a std::vector.
+ *
+ * \param[in] begin Iterator to the beginning of a range.
+ * \param[in] end Iterator to the end of a range.
+ *
+ * The referenced vector must remain valid and not be reallocated for
+ * the lifetime of this object.
+ *
+ * \related ConstArrayRef
+ */
+template <typename T>
+ConstArrayRef<T> constArrayRefFromVector(typename std::vector<T>::const_iterator begin,
+ typename std::vector<T>::const_iterator end)
+{
+ const T * p_begin = (begin != end) ? &*begin : NULL;
+ const T * p_end = p_begin + (end-begin);
+ return constArrayRefFromPointers<T>(p_begin, p_end);
+}
+
+/*! \brief
+ * Simple swap method for ArrayRef objects.
+ *
+ * \see ArrayRef::swap()
+ *
+ * \ingroup module_utility
+ */
+template <typename T>
+void swap(ArrayRef<T> &a, ArrayRef<T> &b)
+{
+ a.swap(b);
+}
+
/*! \brief
* Simple swap method for ConstArrayRef objects.
*
* \see ConstArrayRef::swap()
+ *
+ * \ingroup module_utility
*/
template <typename T>
void swap(ConstArrayRef<T> &a, ConstArrayRef<T> &b)