projects/ExcelToXMLTool/Source/ThirdParty/OpenXLSX/include/XLRowData.hpp

Symbolic link
427 lines
16 KiB
C++

//
// Created by Kenneth Balslev on 24/08/2020.
//
#ifndef OPENXLSX_XLROWDATA_HPP
#define OPENXLSX_XLROWDATA_HPP
#pragma warning(push)
#pragma warning(disable : 4251)
#pragma warning(disable : 4275)
// ===== External Includes ===== //
#include <deque>
#include <list>
#include <memory>
#include <vector>
// ===== OpenXLSX Includes ===== //
#include "OpenXLSX-Exports.hpp"
#include "XLCell.hpp"
#include "XLConstants.hpp"
#include "XLException.hpp"
#include "XLIterator.hpp"
#include "XLXmlParser.hpp"
// ========== CLASS AND ENUM TYPE DEFINITIONS ========== //
namespace OpenXLSX
{
class XLRow;
class XLRowDataRange;
/**
* @brief This class encapsulates a (non-const) iterator, for iterating over the cells in a row.
* @todo Consider implementing a const iterator also
*/
class OPENXLSX_EXPORT XLRowDataIterator
{
friend class XLRowDataRange;
public:
using iterator_category = std::forward_iterator_tag;
using value_type = XLCell;
using difference_type = int64_t;
using pointer = XLCell*;
using reference = XLCell&;
/**
* @brief Destructor.
*/
~XLRowDataIterator();
/**
* @brief Copy constructor.
* @param other Object to be copied.
*/
XLRowDataIterator(const XLRowDataIterator& other);
/**
* @brief Move constructor.
* @param other Object to be moved.
*/
XLRowDataIterator(XLRowDataIterator&& other) noexcept;
/**
* @brief Copy assignment operator.
* @param other Object to be copied.
* @return Reference to the copied-to object.
*/
XLRowDataIterator& operator=(const XLRowDataIterator& other);
/**
* @brief Move assignment operator.
* @param other Object to be moved.
* @return Reference to the moved-to object.
*/
XLRowDataIterator& operator=(XLRowDataIterator&& other) noexcept;
/**
* @brief Pre-increment of the iterator.
* @return Reference to the iterator object.
*/
XLRowDataIterator& operator++();
/**
* @brief Post-increment of the iterator.
* @return Reference to the iterator object.
*/
XLRowDataIterator operator++(int); // NOLINT
/**
* @brief Dereferencing operator.
* @return Reference to the object pointed to by the iterator.
*/
reference operator*();
/**
* @brief Arrow operator.
* @return Pointer to the object pointed to by the iterator.
*/
pointer operator->();
/**
* @brief Equality operator.
* @param rhs XLRowDataIterator to compare to.
* @return true if equal, otherwise false.
*/
bool operator==(const XLRowDataIterator& rhs) const;
/**
* @brief Non-equality operator.
* @param rhs XLRowDataIterator to compare to.
* @return false if equal, otherwise true.
*/
bool operator!=(const XLRowDataIterator& rhs) const;
private:
/**
* @brief Constructor.
* @param rowDataRange The range to iterate over.
* @param loc The location of the iterator (begin or end).
*/
XLRowDataIterator(const XLRowDataRange& rowDataRange, XLIteratorLocation loc);
std::unique_ptr<XLRowDataRange> m_dataRange; /**< A pointer to the range to iterate over. */
std::unique_ptr<XMLNode> m_cellNode; /**< The XML node representing the cell currently pointed at. */
XLCell m_currentCell; /**< The XLCell currently pointed at. */
};
/**
* @brief This class encapsulates the concept of a contiguous range of cells in a row.
*/
class OPENXLSX_EXPORT XLRowDataRange
{
friend class XLRowDataIterator;
friend class XLRowDataProxy;
friend class XLRow;
public:
/**
* @brief Copy constructor.
* @param other Object to be copied.
*/
XLRowDataRange(const XLRowDataRange& other);
/**
* @brief Move constructor.
* @param other Object to be moved.
*/
XLRowDataRange(XLRowDataRange&& other) noexcept;
/**
* @brief Destructor.
*/
~XLRowDataRange();
/**
* @brief Copy assignment operator.
* @param other Object to be copied.
* @return A reference to the copied-to object.
*/
XLRowDataRange& operator=(const XLRowDataRange& other);
/**
* @brief Move assignment operator.
* @param other Object to be moved.
* @return A reference to the moved-to object.
*/
XLRowDataRange& operator=(XLRowDataRange&& other) noexcept;
/**
* @brief Get the size (length) of the range.
* @return The size of the range.
*/
uint16_t size() const;
/**
* @brief Get an iterator to the first element.
* @return An XLRowDataIterator pointing to the first element.
*/
XLRowDataIterator begin();
/**
* @brief Get an iterator to (one-past) the last element.
* @return An XLRowDataIterator pointing to (one past) the last element.
*/
XLRowDataIterator end();
private:
/**
* @brief Constructor.
* @param rowNode XMLNode representing the row of the range.
* @param firstColumn The index of the first column.
* @param lastColumn The index of the last column.
* @param sharedStrings A pointer to the shared strings repository.
*/
explicit XLRowDataRange(const XMLNode& rowNode, uint16_t firstColumn, uint16_t lastColumn, const XLSharedStrings& sharedStrings);
std::unique_ptr<XMLNode> m_rowNode; /**< */
uint16_t m_firstCol { 1 }; /**< The cell reference of the first cell in the range */
uint16_t m_lastCol { 1 }; /**< The cell reference of the last cell in the range */
XLSharedStrings m_sharedStrings; /**< */
};
/**
* @brief The XLRowDataProxy is used as a proxy object when getting or setting row data. The class facilitates easy conversion
* to/from containers.
*/
class OPENXLSX_EXPORT XLRowDataProxy
{
friend class XLRow;
public:
/**
* @brief Destructor
*/
~XLRowDataProxy();
/**
* @brief Copy assignment operator.
* @param other Object to be copied.
* @return A reference to the copied-to object.
*/
XLRowDataProxy& operator=(const XLRowDataProxy& other);
/**
* @brief Assignment operator taking a std::vector of XLCellValues as an argument.
* @param values A std::vector of XLCellValues representing the values to be assigned.
* @return A reference to the copied-to object.
*/
XLRowDataProxy& operator=(const std::vector<XLCellValue>& values);
/**
* @brief Assignment operator taking a std::vector of bool values as an argument.
* @param values A std::vector of bool values representing the values to be assigned.
* @return A reference to the copied-to object.
*/
XLRowDataProxy& operator=(const std::vector<bool>& values);
/**
* @brief Templated assignment operator taking any container supporting bidirectional iterators.
* @tparam T The container and value type (will be auto deducted by the compiler).
* @param values The container of the values to be assigned.
* @return A reference to the copied-to object.
* @throws XLOverflowError if size of container exceeds maximum number of columns.
*/
template<typename T,
typename std::enable_if<!std::is_same_v<T, XLRowDataProxy> &&
std::is_base_of_v<typename std::bidirectional_iterator_tag,
typename std::iterator_traits<typename T::iterator>::iterator_category>,
T>::type* = nullptr>
XLRowDataProxy& operator=(const T& values)
{
if (values.size() > MAX_COLS) throw XLOverflowError("Container size exceeds maximum number of columns.");
if (values.size() == 0) return *this;
// ===== If the container value_type is XLCellValue, the values can be copied directly.
if constexpr (std::is_same_v<typename T::value_type, XLCellValue>) {
// ===== First, delete the values in the first N columns.
deleteCellValues(values.size());
// ===== Then, prepend new cell nodes to current row node
auto colNo = values.size();
for (auto value = values.rbegin(); value != values.rend(); ++value) { // NOLINT
prependCellValue(*value, colNo);
--colNo;
}
}
// ===== If the container value_type is a POD type, use the overloaded operator= on each cell.
else {
auto range = XLRowDataRange(*m_rowNode, 1, values.size(), getSharedStrings());
auto dst = range.begin();
auto src = values.begin();
while (true) {
dst->value() = *src;
++src;
if (src == values.end()) break;
++dst;
}
}
return *this;
}
/**
* @brief Implicit conversion to std::vector of XLCellValues.
* @return A std::vector of XLCellValues.
*/
operator std::vector<XLCellValue>() const; // NOLINT
/**
* @brief Implicit conversion to std::deque of XLCellValues.
* @return A std::deque of XLCellValues.
*/
operator std::deque<XLCellValue>() const; // NOLINT
/**
* @brief Implicit conversion to std::list of XLCellValues.
* @return A std::list of XLCellValues.
*/
operator std::list<XLCellValue>() const; // NOLINT
/**
* @brief Explicit conversion operator.
* @details This function calls the convertContainer template function to convert the row data to the container
* stipulated by the client. The reason that this function is marked explicit is that the implicit conversion operators
* above will be ambiguous.
* @tparam Container The container (and value) type to convert the row data to.
* @return The required container with the row data.
*/
template<
typename Container,
typename std::enable_if<!std::is_same_v<Container, XLRowDataProxy> &&
std::is_base_of_v<typename std::bidirectional_iterator_tag,
typename std::iterator_traits<typename Container::iterator>::iterator_category>,
Container>::type* = nullptr>
explicit operator Container() const
{
return convertContainer<Container>();
}
/**
* @brief Clears all values for the current row.
*/
void clear();
private:
//---------- Private Member Functions ---------- //
/**
* @brief Constructor.
* @param row Pointer to the parent XLRow object.
* @param rowNode Pointer to the underlying XML node representing the row.
*/
XLRowDataProxy(XLRow* row, XMLNode* rowNode);
/**
* @brief Copy constructor.
* @param other Object to be copied.
* @note The copy constructor is private in order to prevent use of the auto keyword in client code.
*/
XLRowDataProxy(const XLRowDataProxy& other);
/**
* @brief Move constructor.
* @param other Object to be moved.
* @note Made private, as move construction should only be allowed when the parent object is moved. Disallowed for client code.
*/
XLRowDataProxy(XLRowDataProxy&& other) noexcept;
/**
* @brief Move assignment operator.
* @param other Object to be moved.
* @return Reference to the moved-to object.
* @note Made private, as move assignment is disallowed for client code.
*/
XLRowDataProxy& operator=(XLRowDataProxy&& other) noexcept;
/**
* @brief Get the cell values for the row.
* @return A std::vector of XLCellValues.
*/
std::vector<XLCellValue> getValues() const;
/**
* @brief Helper function for getting a pointer to the shared strings repository.
* @return A pointer to an XLSharedStrings object.
*/
XLSharedStrings getSharedStrings() const;
/**
* @brief Convenience function for erasing the first 'count' numbers of values in the row.
* @param count The number of values to erase.
*/
void deleteCellValues(uint16_t count);
/**
* @brief Convenience function for prepending a row value with a given column number.
* @param value The XLCellValue object.
* @param col The column of the value.
*/
void prependCellValue(const XLCellValue& value, uint16_t col);
/**
* @brief Convenience function for converting the row data to a user-supplied container.
* @details This function can convert row data to any user-supplied container that adheres to the design
* of STL containers and supports bidirectional iterators. This could be std::vector, std::deque, or
* std::list, but any container with the same interface should work.
* @tparam Container The container (and value) type to be returned.
* @return The row data in the required format.
* @throws bad_variant_access if Container::value type is not XLCellValue and does not match the type contained.
*/
template<
typename Container,
typename std::enable_if<!std::is_same_v<Container, XLRowDataProxy> &&
std::is_base_of_v<typename std::bidirectional_iterator_tag,
typename std::iterator_traits<typename Container::iterator>::iterator_category>,
Container>::type* = nullptr>
Container convertContainer() const
{
Container c;
auto it = std::inserter(c, c.end());
for (const auto& v : getValues()) {
// ===== If the value_type of the container is XLCellValue, the value can be assigned directly.
if constexpr (std::is_same_v<typename Container::value_type, XLCellValue>) *it++ = v;
// ===== If the value_type is something else, the underlying value has to be extracted from the XLCellValue object.
// ===== Note that if the type contained in the XLCellValue object does not match the value_type, a bad_variant_access
// ===== exception will be thrown.
else
*it++ = v.get<typename Container::value_type>();
}
return c;
}
//---------- Private Member Variables ---------- //
XLRow* m_row { nullptr }; /**< Pointer to the parent XLRow object. */
XMLNode* m_rowNode { nullptr }; /**< Pointer the the XML node representing the row. */
};
} // namespace OpenXLSX
#pragma warning(pop)
#endif // OPENXLSX_XLROWDATA_HPP