// // Array.h // // Library: Redis // Package: Redis // Module: Array // // Definition of the Array class. // // Copyright (c) 2015, Applied Informatics Software Engineering GmbH. // and Contributors. // // SPDX-License-Identifier: BSL-1.0 // #ifndef Redis_Array_INCLUDED #define Redis_Array_INCLUDED #include "Poco/Redis/Redis.h" #include "Poco/Redis/Type.h" #include "Poco/Redis/Exception.h" #include #include namespace Poco { namespace Redis { class Redis_API Array /// Represents a Redis Array. An Array can contain Integers, Strings, /// Bulk Strings, Errors and other Arrays. It can also contain a Null /// value. { public: using const_iterator = std::vector::const_iterator; Array(); /// Creates an Array. As long as there are no elements added, /// the array will contain a Null value. Array(const Array& copy); /// Creates an Array by copying another one. virtual ~Array(); /// Destroys the Array. Array& operator=(const Array&) = default; Array& operator=(Array&&) = default; template Array& operator<<(const T& arg) /// Adds the argument to the array. /// /// Note: a std::string will be added as a BulkString because this /// is commonly used for representing strings in Redis. If you /// really need a simple string, use addSimpleString(). { return add(arg); } Array& operator<<(const char* s); /// Special implementation for const char*. /// /// Note: the specialization creates a BulkString. If you need /// a simple string, call addSimpleString(). Array& operator<<(const std::vector& strings); /// Special implementation for a vector with strings. /// All strings will be added as a BulkString. Array& add(); /// Adds an Null BulkString. template Array& add(const T& arg) /// Adds an element to the array. /// /// Note: the specialization for std::string will add a BulkString! /// If you really need a simple string, call addSimpleString. { addRedisType(new Type(arg)); return *this; } Array& add(const char* s); /// Special implementation for const char*. /// /// Note: the specialization creates a BulkString. If you need /// a simple string, call addSimpleString. Array& add(const std::vector& strings); /// Special implementation for a vector with strings. /// All strings will be added as a BulkString. Array& addRedisType(RedisType::Ptr value); /// Adds a Redis element. Array& addSimpleString(const std::string& value); /// Adds a simple string (can't contain newline characters!). const_iterator begin() const; /// Returns an iterator to the start of the array. /// /// Note: this can throw a NullValueException when this is a Null array. void clear(); /// Removes all elements from the array. const_iterator end() const; /// Returns an iterator to the end of the array. /// /// Note: this can throw a NullValueException when this is a Null array. template T get(size_t pos) const /// Returns the element on the given position and tries to convert /// to the template type. A Poco::BadCastException will be thrown when the /// the conversion fails. An Poco::InvalidArgumentException will be thrown /// when the index is out of range. When the array is a Null array /// a Poco::NullValueException is thrown. { if ( _elements.isNull() ) throw NullValueException(); if ( pos >= _elements.value().size() ) throw InvalidArgumentException(); RedisType::Ptr element = _elements.value().at(pos); if ( RedisTypeTraits::TypeId == element->type() ) { auto* concrete = dynamic_cast* >(element.get()); if ( concrete != NULL ) return concrete->value(); } throw BadCastException(); } int getType(size_t pos) const; /// Returns the type of the element. This can throw a Poco::NullValueException /// when this array is a Null array. An Poco::InvalidArgumentException will /// be thrown when the index is out of range. bool isNull() const; /// Returns true when this is a Null array. void makeNull(); /// Turns the array into a Null array. When the array already has some /// elements, the array will be cleared. std::string toString() const; /// Returns the String representation as specified in the /// Redis Protocol specification. size_t size() const; /// Returns the size of the array. /// /// Note: this can throw a NullValueException when this is a Null array. private: void checkNull(); /// Checks for null array and sets a new vector if true. Nullable> _elements; }; // // inlines // inline Array& Array::operator<<(const char* s) { BulkString value(s); return add(value); } inline Array& Array::operator<<(const std::vector& strings) { return add(strings); } inline Array& Array::add() { BulkString value; return add(value); } template<> inline Array& Array::add(const std::string& arg) { BulkString value(arg); return add(value); } inline Array& Array::add(const char* s) { BulkString value(s); return add(value); } inline Array& Array::add(const std::vector& strings) { for(std::vector::const_iterator it = strings.begin(); it != strings.end(); ++it) { add(*it); } return *this; } inline Array& Array::addSimpleString(const std::string& value) { return addRedisType(new Type(value)); } inline Array::const_iterator Array::begin() const { return _elements.value().begin(); } inline void Array::checkNull() { std::vector v; if ( _elements.isNull() ) _elements.assign(v); } inline void Array::clear() { if ( !_elements.isNull() ) { _elements.value().clear(); } } inline Array::const_iterator Array::end() const { return _elements.value().end(); } inline bool Array::isNull() const { return _elements.isNull(); } inline void Array::makeNull() { if ( !_elements.isNull() ) _elements.value().clear(); _elements.clear(); } inline size_t Array::size() const { return _elements.value().size(); } template<> struct RedisTypeTraits { enum { TypeId = RedisType::REDIS_ARRAY }; static const char marker = '*'; static std::string toString(const Array& value) { std::stringstream result; result << marker; if ( value.isNull() ) { result << "-1" << LineEnding::NEWLINE_CRLF; } else { result << value.size() << LineEnding::NEWLINE_CRLF; for(std::vector::const_iterator it = value.begin(); it != value.end(); ++it) { result << (*it)->toString(); } } return result.str(); } static void read(RedisInputStream& input, Array& value) { value.clear(); const Int64 length = NumberParser::parse64(input.getline()); if ( length != -1 ) { for(int i = 0; i < length; ++i) { char marker = input.get(); RedisType::Ptr element = RedisType::createRedisType(marker); if ( element.isNull() ) throw RedisException("Wrong answer received from Redis server"); element->read(input); value.addRedisType(element); } } } }; } // namespace Redis } // namespace Poco #endif // Redis_Array_INCLUDED