1//
2// Array.h
3//
4// Library: Redis
5// Package: Redis
6// Module: Array
7//
8// Definition of the Array class.
9//
10// Copyright (c) 2015, Applied Informatics Software Engineering GmbH.
11// and Contributors.
12//
13// SPDX-License-Identifier: BSL-1.0
14//
15
16
17#ifndef Redis_Array_INCLUDED
18#define Redis_Array_INCLUDED
19
20
21#include "Poco/Redis/Redis.h"
22#include "Poco/Redis/Type.h"
23#include "Poco/Redis/Exception.h"
24#include <vector>
25#include <sstream>
26
27
28namespace Poco {
29namespace Redis {
30
31
32class Redis_API Array
33 /// Represents a Redis Array. An Array can contain Integers, Strings,
34 /// Bulk Strings, Errors and other Arrays. It can also contain a Null
35 /// value.
36{
37public:
38 typedef std::vector<RedisType::Ptr>::const_iterator const_iterator;
39
40 Array();
41 /// Creates an Array. As long as there are no elements added,
42 /// the array will contain a Null value.
43
44 Array(const Array& copy);
45 /// Creates an Array by copying another one.
46
47 virtual ~Array();
48 /// Destroys the Array.
49
50 template<typename T>
51 Array& operator<<(const T& arg)
52 /// Adds the argument to the array.
53 ///
54 /// Note: a std::string will be added as a BulkString because this
55 /// is commonly used for representing strings in Redis. If you
56 /// really need a simple string, use addSimpleString().
57 {
58 return add(arg);
59 }
60
61 Array& operator<<(const char* s);
62 /// Special implementation for const char*.
63 ///
64 /// Note: the specialization creates a BulkString. If you need
65 /// a simple string, call addSimpleString().
66
67 Array& operator<<(const std::vector<std::string>& strings);
68 /// Special implementation for a vector with strings.
69 /// All strings will be added as a BulkString.
70
71 Array& add();
72 /// Adds an Null BulkString.
73
74 template<typename T>
75 Array& add(const T& arg)
76 /// Adds an element to the array.
77 ///
78 /// Note: the specialization for std::string will add a BulkString!
79 /// If you really need a simple string, call addSimpleString.
80 {
81 addRedisType(new Type<T>(arg));
82 return *this;
83 }
84
85 Array& add(const char* s);
86 /// Special implementation for const char*.
87 ///
88 /// Note: the specialization creates a BulkString. If you need
89 /// a simple string, call addSimpleString.
90
91 Array& add(const std::vector<std::string>& strings);
92 /// Special implementation for a vector with strings.
93 /// All strings will be added as a BulkString.
94
95 Array& addRedisType(RedisType::Ptr value);
96 /// Adds a Redis element.
97
98 Array& addSimpleString(const std::string& value);
99 /// Adds a simple string (can't contain newline characters!).
100
101 const_iterator begin() const;
102 /// Returns an iterator to the start of the array.
103 ///
104 /// Note: this can throw a NullValueException when this is a Null array.
105
106 void clear();
107 /// Removes all elements from the array.
108
109 const_iterator end() const;
110 /// Returns an iterator to the end of the array.
111 ///
112 /// Note: this can throw a NullValueException when this is a Null array.
113
114 template<typename T>
115 T get(size_t pos) const
116 /// Returns the element on the given position and tries to convert
117 /// to the template type. A Poco::BadCastException will be thrown when the
118 /// the conversion fails. An Poco::InvalidArgumentException will be thrown
119 /// when the index is out of range. When the array is a Null array
120 /// a Poco::NullValueException is thrown.
121 {
122 if ( _elements.isNull() ) throw NullValueException();
123
124 if ( pos >= _elements.value().size() ) throw InvalidArgumentException();
125
126 RedisType::Ptr element = _elements.value().at(pos);
127 if ( RedisTypeTraits<T>::TypeId == element->type() )
128 {
129 Type<T>* concrete = dynamic_cast<Type<T>* >(element.get());
130 if ( concrete != NULL ) return concrete->value();
131 }
132 throw BadCastException();
133 }
134
135 int getType(size_t pos) const;
136 /// Returns the type of the element. This can throw a Poco::NullValueException
137 /// when this array is a Null array. An Poco::InvalidArgumentException will
138 /// be thrown when the index is out of range.
139
140 bool isNull() const;
141 /// Returns true when this is a Null array.
142
143 void makeNull();
144 /// Turns the array into a Null array. When the array already has some
145 /// elements, the array will be cleared.
146
147 std::string toString() const;
148 /// Returns the String representation as specified in the
149 /// Redis Protocol specification.
150
151 size_t size() const;
152 /// Returns the size of the array.
153 ///
154 /// Note: this can throw a NullValueException when this is a Null array.
155
156private:
157 void checkNull();
158 /// Checks for null array and sets a new vector if true.
159
160 Nullable<std::vector<RedisType::Ptr> > _elements;
161};
162
163
164//
165// inlines
166//
167
168
169inline Array& Array::operator<<(const char* s)
170{
171 BulkString value(s);
172 return add(value);
173}
174
175
176inline Array& Array::operator<<(const std::vector<std::string>& strings)
177{
178 return add(strings);
179}
180
181
182inline Array& Array::add()
183{
184 BulkString value;
185 return add(value);
186}
187
188
189template<>
190inline Array& Array::add(const std::string& arg)
191{
192 BulkString value(arg);
193 return add(value);
194}
195
196
197inline Array& Array::add(const char* s)
198{
199 BulkString value(s);
200 return add(value);
201}
202
203
204inline Array& Array::add(const std::vector<std::string>& strings)
205{
206 for(std::vector<std::string>::const_iterator it = strings.begin(); it != strings.end(); ++it)
207 {
208 add(*it);
209 }
210 return *this;
211}
212
213
214inline Array& Array::addSimpleString(const std::string& value)
215{
216 return addRedisType(new Type<std::string>(value));
217}
218
219
220inline Array::const_iterator Array::begin() const
221{
222 return _elements.value().begin();
223}
224
225
226inline void Array::checkNull()
227{
228 std::vector<RedisType::Ptr> v;
229 if ( _elements.isNull() ) _elements.assign(v);
230}
231
232
233inline void Array::clear()
234{
235 if ( !_elements.isNull() )
236 {
237 _elements.value().clear();
238 }
239}
240
241
242inline Array::const_iterator Array::end() const
243{
244 return _elements.value().end();
245}
246
247
248inline bool Array::isNull() const
249{
250 return _elements.isNull();
251}
252
253
254inline void Array::makeNull()
255{
256 if ( !_elements.isNull() ) _elements.value().clear();
257
258 _elements.clear();
259}
260
261
262inline size_t Array::size() const
263{
264 return _elements.value().size();
265}
266
267
268template<>
269struct RedisTypeTraits<Array>
270{
271 enum { TypeId = RedisType::REDIS_ARRAY };
272
273 static const char marker = '*';
274
275 static std::string toString(const Array& value)
276 {
277 std::stringstream result;
278 result << marker;
279 if ( value.isNull() )
280 {
281 result << "-1" << LineEnding::NEWLINE_CRLF;
282 }
283 else
284 {
285 result << value.size() << LineEnding::NEWLINE_CRLF;
286 for(std::vector<RedisType::Ptr>::const_iterator it = value.begin();
287 it != value.end(); ++it)
288 {
289 result << (*it)->toString();
290 }
291 }
292 return result.str();
293 }
294
295 static void read(RedisInputStream& input, Array& value)
296 {
297 value.clear();
298
299 Int64 length = NumberParser::parse64(input.getline());
300
301 if ( length != -1 )
302 {
303 for(int i = 0; i < length; ++i)
304 {
305 char mark = static_cast<char>(input.get());
306 RedisType::Ptr element = RedisType::createRedisType(mark);
307
308 if ( element.isNull() )
309 throw RedisException("Wrong answer received from Redis server");
310
311 element->read(input);
312 value.addRedisType(element);
313 }
314 }
315 }
316};
317
318
319} } // namespace Poco::Redis
320
321
322#endif // Redis_Array_INCLUDED
323