libutil++  1.9.3
 All Classes Functions Variables
Vector.cpp
1 /*
2 ** libutil++
3 ** $Id: Vector.cpp 1702 2016-08-13 23:26:06Z sella $
4 ** Copyright (c) 2011-2016 Digital Genesis, LLC. All Rights Reserved.
5 ** Released under the LGPL Version 2.1 License.
6 ** http://www.digitalgenesis.com
7 */
8 
9 static const char rcsid[] __attribute__((used)) = "$Id: Vector.cpp 1702 2016-08-13 23:26:06Z sella $";
10 
11 #include "Vector.h"
12 #include "Variant.h"
13 #include "../util/String.h"
14 #include "../util/CommonMacro.h"
15 
16 #include <stack>
17 #include <algorithm>
18 
19 using namespace sella::variant;
20 
21 Vector::Vector() throw () : Nullable(std::make_shared<std::vector<Variant>>()) { }
22 
23 Vector::Vector(const std::string &value) throw (TypeCastException) : Nullable() {
24  if (value.empty()) {
25  this->value = std::make_shared<std::vector<Variant>>();
26  } else {
27  std::vector<std::string> token = this->tokenize(value, Vector::Pattern());
28 
29  parse(token);
30  }
31 
32  it = std::static_pointer_cast<std::vector<Variant>>(this->value)->begin();
33 }
34 
35 Vector::Vector(const std::vector<std::string> &token) throw (TypeCastException) : Nullable() {
36  if (token.empty()) {
37  this->value = std::make_shared<std::vector<Variant>>();
38  } else {
39  parse(token);
40  }
41 
42  it = std::static_pointer_cast<std::vector<Variant>>(this->value)->begin();
43 }
44 
45 Vector::Vector(sella::util::MessagePack &mpack, uint32_t &offset) throw (TypeCastException) {
46  unmsgpack(mpack, offset);
47  it = std::static_pointer_cast<std::vector<Variant>>(this->value)->begin();
48 }
49 
50 Vector::Vector(const std::vector<Variant> &value) throw () : Nullable() {
51  this->value = std::make_shared<std::vector<Variant>>(value);
52  it = std::static_pointer_cast<std::vector<Variant>>(this->value)->begin();
53 }
54 
55 Vector::Vector(std::vector<Variant> &&value) throw () : Nullable() {
56  this->value = std::make_shared<std::vector<Variant>>(std::move(value));
57  it = std::static_pointer_cast<std::vector<Variant>>(this->value)->begin();
58 }
59 
60 Vector::Vector(const Vector &other) throw () : Nullable() {
61  if (LIKELY(this != &other)) {
62  if (LIKELY(!other.isNull())) {
63  if (UNLIKELY(isNull())) {
64  this->value = std::make_shared<std::vector<Variant>>(other.get());
65  } else {
66  *std::static_pointer_cast<std::vector<Variant>>(this->value) = *std::static_pointer_cast<std::vector<Variant>>(other.value);
67  }
68  } else {
69  this->value.reset();
70  }
71  this->it = other.it;
72  }
73 }
74 
75 Vector::Vector(Vector &&other) throw () : Nullable() {
76  if (LIKELY(!other.isNull())) {
77  this->value = std::move(other.value);
78  this->it = std::move(other.it);
79  } else {
80  this->value.reset();
81  }
82 }
83 
84 Vector::~Vector() throw () { }
85 
86 bool Vector::operator==(const Vector &other) const throw () {
87  return (*std::static_pointer_cast<std::vector<Variant>>(this->value) == *std::static_pointer_cast<std::vector<Variant>>(other.value));
88 }
89 
90 bool Vector::operator!=(const Vector &other) const throw () {
91  return !(*this == other);
92 }
93 
94 Vector& Vector::operator=(const Vector &other) throw () {
95  if (LIKELY(this != &other)) {
96  if (LIKELY(!other.isNull())) {
97  if (UNLIKELY(isNull())) {
98  this->value = std::make_shared<std::vector<Variant>>(other.get());
99  } else {
100  *std::static_pointer_cast<std::vector<Variant>>(this->value) = *std::static_pointer_cast<std::vector<Variant>>(other.value);
101  }
102  } else {
103  this->value.reset();
104  }
105  }
106 
107  return *this;
108 }
109 
110 Vector& Vector::operator=(Vector &&other) throw () {
111  if (LIKELY(this != &other)) {
112  if (LIKELY(!other.isNull())) {
113  this->value = std::move(other.value);
114  this->it = std::move(other.it);
115  } else {
116  this->value.reset();
117  }
118  }
119 
120  return *this;
121 }
122 
123 Vector& Vector::operator+=(const Variant &other) throw () {
124  if (UNLIKELY(isNull())) {
125  this->value = std::make_shared<std::vector<Variant>>();
126  }
127 
128  if (UNLIKELY(this == &(other.get<Vector>()))) {
129  return *this;
130  }
131 
132  auto &v = *std::static_pointer_cast<std::vector<Variant>>(this->value);
133 
134  if (other.getType() == Variant::TypeVector) {
135  auto &v2 = other.get<Vector>().get();
136 
137  v.insert(v.end(), v2.begin(), v2.end());
138  } else {
139  v.push_back(other);
140  }
141 
142  return *this;
143 }
144 
145 Vector& Vector::operator+=(Variant &&other) throw () {
146  if (UNLIKELY(isNull())) {
147  this->value = std::make_shared<std::vector<Variant>>();
148  }
149 
150  if (UNLIKELY(this == &(other.get<Vector>()))) {
151  return *this;
152  }
153 
154  auto &v = *std::static_pointer_cast<std::vector<Variant>>(this->value);
155 
156  if (other.getType() == Variant::TypeVector) {
157  auto &v2 = other.get<Vector>().get();
158 
159  std::move(v2.begin(), v2.end(), std::back_inserter(v));
160  } else {
161  v.push_back(std::move(other));
162  }
163 
164  return *this;
165 }
166 
167 const Variant& Vector::operator[](size_t index) const throw (RangeException) {
168  if (UNLIKELY(isNull())) {
169  THROW(RangeException, "index out of bounds");
170  }
171 
172  std::vector<Variant> &v = *std::static_pointer_cast<std::vector<Variant>>(this->value);
173 
174  if (UNLIKELY(index >= v.size())) {
175  THROW(RangeException, "index out of bounds");
176  }
177 
178  return v[index];
179 }
180 
181 Variant& Vector::operator[](size_t index) throw () {
182  if (UNLIKELY(isNull())) {
183  this->value = std::make_shared<std::vector<Variant>>();
184  }
185 
186  std::vector<Variant> &v = *std::static_pointer_cast<std::vector<Variant>>(this->value);
187 
188  if (index >= v.size()) { /* Expand vector, if needed. */
189  v.resize(index + 1); /* Initializes empty slots with TypeNull Variant(). */
190  }
191 
192  return v[index];
193 }
194 
195 Vector::iterator Vector::begin() throw () {
196  return get().begin();
197 }
198 
199 Vector::iterator Vector::end() throw () {
200  return get().end();
201 }
202 
203 Vector::const_iterator Vector::cbegin() const throw () {
204  return get().cbegin();
205 }
206 
207 Vector::const_iterator Vector::cend() const throw () {
208  return get().cend();
209 }
210 
211 const std::vector<Variant>& Vector::get() const throw (UnsupportedOperatorException) {
212  if (UNLIKELY(isNull())) {
213  THROW(UnsupportedOperatorException, "unable to take reference of null value");
214  }
215 
216  return *std::static_pointer_cast<std::vector<Variant>>(this->value);
217 }
218 
219 std::vector<Variant>& Vector::get() throw (UnsupportedOperatorException) {
220  if (UNLIKELY(isNull())) {
221  THROW(UnsupportedOperatorException, "unable to take reference of null value");
222  }
223 
224  return *std::static_pointer_cast<std::vector<Variant>>(this->value);
225 }
226 
227 size_t Vector::size() const throw () {
228  if (UNLIKELY(isNull())) {
229  return 0;
230  }
231 
232  return get().size();
233 }
234 
235 bool Vector::empty() const throw () {
236  if (UNLIKELY(isNull())) {
237  return true;
238  }
239 
240  return get().empty();
241 }
242 
243 void Vector::clear() throw() {
244  if (UNLIKELY(isNull())) {
245  this->value = std::make_shared<std::vector<Variant>>();
246  } else {
247  this->get().clear();
248  }
249 }
250 
251 bool Vector::erase(const std::string &v, int type) throw () {
252  const Variant value(v, type);
253 
254  return erase(value);
255 }
256 
257 bool Vector::erase(const Variant &value) throw () {
258  auto &v = *std::static_pointer_cast<std::vector<Variant>>(this->value);
259  size_t s = v.size();
260 
261  v.erase(std::remove(v.begin(), v.end(), value), v.end());
262 
263  return (s != v.size());
264 }
265 
266 bool Vector::erase(size_t index) throw () {
267  auto &v = *std::static_pointer_cast<std::vector<Variant>>(this->value);
268 
269  if ((size_t) index < v.size()) {
270  v.erase(v.begin() + index) != v.end();
271 
272  it = v.begin();
273 
274  return true;
275  }
276 
277  return false;
278 }
279 
280 void Vector::shrink_to_fit() throw () {
281  auto &v = *std::static_pointer_cast<std::vector<Variant>>(this->value);
282 
283  std::vector<Variant>(v.begin(), v.end()).swap(v);
284 }
285 
286 std::string Vector::str(int type) const throw () {
287  std::string output;
288 
289  switch (type) {
290  case JSON:
291  output = json();
292  break;
293 
294  case CJSON:
295  output = cjson();
296  break;
297 
298  case XML:
299  output = xml();
300  break;
301 
302  case CSV:
303  output = csv();
304  break;
305  }
306 
307  return output;
308 }
309 
310 #if 1
311 void Vector::msgpack(sella::util::MessagePack &mpack, uint32_t &offset) const throw (TypeCastException) {
312  uint32_t c;
313 
314  if (UNLIKELY(isNull())) {
315  c = mpack.append(offset);
316 
317  offset += c;
318 
319  if (UNLIKELY(c == 0)) {
320  THROW(TypeCastException, "Failed to append vector '%s' at offset %d (buffer length: %d)", str(JSON).c_str(), offset, mpack.length());
321  }
322  } else {
323  const std::vector<Variant> &data = *std::static_pointer_cast<std::vector<Variant>>(this->value);
324  size_t size = data.size();
325 
326  if (size > 0) {
327  PREFETCH(&data[0].value, PREFETCH_RO, PREFETCH_LOCALITY_MEDIUM);
328  }
329 
330  c = mpack.append_vector(offset, size);
331 
332  offset += c;
333 
334  if (UNLIKELY(c == 0)) {
335  THROW(TypeCastException, "Failed to append vector '%s' at offset %d (buffer length: %d)", str(JSON).c_str(), offset, mpack.length());
336  }
337 
338  for (size_t i = 0; i < size; i++) {
339  if (i + 1 < size) {
340  PREFETCH(&data[i + 1].value, PREFETCH_RO, PREFETCH_LOCALITY_MEDIUM);
341  }
342 
343  data[i].value->msgpack(mpack, offset);
344  }
345  }
346 }
347 #else
348 uint32_t Vector::msgpack(sella::util::MessagePack &mpack, uint32_t &offset) const throw (TypeCastException) {
349  uint32_t c, o = offset;
350 
351  if (UNLIKELY(isNull())) {
352  c = mpack.append(offset);
353 
354  offset += c;
355 
356  return c;
357  }
358 
359  const std::vector<Variant> &data = *std::static_pointer_cast<std::vector<Variant>>(this->value);
360 
361  if (UNLIKELY((c = mpack.append_vector(offset, data.size())) == 0)) {
362  THROW(TypeCastException, "Failed to append '%s' at offset %d (buffer length: %d)", str(JSON).c_str(), offset, mpack.length());
363  }
364 
365  offset += c;
366 
367  for (auto it = data.begin(), end = data.end(); it != end; ++it) {
368  if (UNLIKELY(isNull())) {
369  c = mpack.append(offset);
370 
371  offset += c;
372  } else {
373  int type = it->getType();
374 
375  switch (type) {
376  case Boolean::Type:
377  c = mpack.append(offset, it->get<Boolean>().get());
378  break;
379 
380  case Signed::Type:
381  c = mpack.append(offset, it->get<Signed>().get());
382  break;
383 
384  case Unsigned::Type:
385  c = mpack.append(offset, it->get<Unsigned>().get());
386  break;
387 
388  case Double::Type:
389  c = mpack.append(offset, it->get<Double>().get());
390  break;
391 
392  case UUID::Type:
393  c = mpack.append(offset, it->get<UUID>().get().str());
394  break;
395 
396  case String::Type:
397  c = mpack.append(offset, it->get<String>().get());
398  break;
399 
400  case Binary::Type:
401  c = it->get<Binary>().msgpack(mpack, offset);
402  break;
403 
404  case Pointer::Type:
405  c = mpack.append(offset, (uint64_t) it->get<Pointer>().get());
406  break;
407 
408  case IPAddress::Type:
409  c = mpack.append(offset, it->get<IPAddress>().get().str());
410  break;
411 
412  case IPPrefix::Type:
413  c = mpack.append(offset, it->get<IPPrefix>().get().str());
414  break;
415 
416  case Interval::Type:
417  c = mpack.append(offset, it->get<Interval>().str(JSON));
418  break;
419 
420  case Time::Type:
421  c = mpack.append(offset, it->get<Time>().str(JSON));
422  break;
423 
424  case Date::Type:
425  c = mpack.append(offset, it->get<Date>().str(JSON));
426  break;
427 
428  case TimeStamp::Type:
429  c = mpack.append(offset, it->get<TimeStamp>().str(JSON));
430  break;
431 
432  case Vector::Type:
433  c = it->get<Vector>().msgpack(mpack, offset);
434  break;
435 
436  case Object::Type:
437  c = it->get<Object>().msgpack(mpack, offset);
438  break;
439  }
440 
441  if (type != Object::Type && type != Vector::Type && type != Binary::Type) {
442  offset += c;
443  }
444  }
445 
446  if (UNLIKELY(c == 0)) {
447  THROW(TypeCastException, "Failed to append '%s' at offset %d (buffer length: %d)", str(JSON).c_str(), offset, mpack.length());
448  }
449  }
450 
451  return (offset - o);
452 }
453 #endif
454 
455 void Vector::msgpackBufferSize(size_t &size) const throw () {
456  if (UNLIKELY(isNull())) {
457  size += 1;
458 
459  return;
460  }
461 
462  const std::vector<Variant> &data = *std::static_pointer_cast<std::vector<Variant>>(this->value);
463 
464  for (size_t i = 0; i < data.size(); i++) {
465  data[i].value->msgpackBufferSize(size);
466  }
467 
468  size += 5;
469 }
470 
471 std::string Vector::json() const throw () {
472  if (UNLIKELY(isNull())) {
473  return "null";
474  }
475 
476  std::string output;
477  const std::vector<Variant> &data = this->get();
478 
479  if (data.empty()) {
480  output = "[ ]";
481  } else {
482  output = "[ ";
483 
484  for (auto it = data.begin(), end = data.end(); it != end; ++it) {
485  if ((!it->isScalar() && !it->isNetwork()) || it->isNumeric() || it->isBoolean() || it->isNull()) {
486  output.append(it->value->str(JSON)).append(", ");
487  } else {
488  output.append("\"").append(it->value->str(JSON)).append("\", ");
489  }
490  }
491 
492  output.erase(output.size() - 2);
493  output.append(" ]");
494  }
495 
496  return output;
497 }
498 
499 std::string Vector::cjson() const throw () {
500  if (UNLIKELY(isNull())) {
501  return "null";
502  }
503 
504  std::string output;
505  const std::vector<Variant> &data = this->get();
506 
507  if (data.empty()) {
508  output = "[]";
509  } else {
510  output = "[";
511 
512  for (auto it = data.begin(), end = data.end(); it != end; ++it) {
513  if ((!it->isScalar() && !it->isNetwork()) || it->isNumeric() || it->isBoolean() || it->isNull()) {
514  output.append(it->value->str(CJSON)).push_back(',');
515  } else {
516  output.append("\"").append(it->value->str(CJSON)).append("\",");
517  }
518  }
519 
520  output.erase(output.size() - 1);
521  output.push_back(']');
522  }
523 
524  return output;
525 }
526 
527 std::string Vector::xml() const throw () {
528  if (UNLIKELY(isNull())) {
529  return "<root null=\"true\" />";
530  }
531 
532  std::string output;
533  const std::vector<Variant> &data = this->get();
534 
535  for (auto it = data.begin(), end = data.end(); it != end; ++it) {
536  if (it->isNull()) {
537  output.append("<element null=\"true\" />");
538  } else {
539  output.append("<element>").append(it->value->str(XML)).append("</element>");
540  }
541  }
542 
543  return output;
544 }
545 
546 std::string Vector::csv() const throw () {
547  if (UNLIKELY(isNull())) {
548  return "\\N";
549  }
550 
551  std::string output;
552  const std::vector<Variant> &data = this->get();
553 
554  if (!data.empty()) {
555  for (auto it = data.begin(), end = data.end(); it != end; ++it) {
556  if (it->isNull()) {
557  output.append("\\N");
558  } else if (it->isScalar()) {
559  output.append("\"").append(sella::util::String::escape(it->value->str(CSV))).append("\"");
560  } else if (it->isObject()) {
561  if (!it->empty() && it == data.begin()) { /* Add CSV header */
562  auto &o = it->get<Object>().get();
563 
564  for (auto i = o.begin(); i != o.end(); ++i) {
565  output.append("\"").append(i->first).append("\",");
566  }
567  output.erase(output.size() - 1);
568  output.append("\r\n");
569  }
570 
571  output.append(it->value->str(CSV));
572  } else if (it->isVector()) {
573  auto &v = it->get<Vector>().get();
574 
575  if (v.empty()) {
576  output.append("\\N");
577  } else {
578  for (auto i = v.begin(), end = v.end(); i != end; ++i) {
579  if (i->isNull()) {
580  output.append("\\N,");
581  } else if (i->isScalar()) {
582  output.append("\"").append(sella::util::String::escape(i->value->str(CSV))).append("\",");
583  } else {
584  output.append("\"").append(sella::util::String::escape(i->value->str(JSON))).append("\",");
585  }
586  }
587 
588  output.erase(output.size() - 1);
589  }
590  }
591 
592  output.append("\r\n");
593  }
594 
595  output.erase(output.size() - 2);
596  }
597 
598  return output;
599 }
600 
601 void Vector::parse(const std::vector<std::string> &token) throw (TypeCastException) {
602  auto t = token.begin();
603  std::stack<int> type;
604  std::shared_ptr<std::vector<Variant>> v = std::make_shared<std::vector<Variant>>();
605 
606  for (auto it = token.begin(), end = token.end(); it != end; ++it) {
607  switch (it->at(0)) {
608  case '[':
609  if (type.empty()) {
610  t = it;
611  }
612  type.push('v');
613  break;
614 
615  case '{':
616  if (type.empty()) {
617  t = it;
618  }
619  type.push('o');
620  break;
621 
622  case ']':
623  if (UNLIKELY(type.empty() || (type.top() != 'v'))) {
624  THROW(TypeCastException, "mismatched vector [ ... ] in text (%s)", t->c_str());
625  }
626  type.pop();
627 
628  if (type.empty()) {
629  v->push_back(Variant(std::vector<std::string>(t, it)));
630  }
631  break;
632 
633  case '}':
634  if (UNLIKELY(type.empty() || (type.top() != 'o'))) {
635  THROW(TypeCastException, "mismatched object { ... } in text (%s)", t->c_str());
636  }
637  type.pop();
638 
639  if (type.empty()) {
640  v->push_back(Variant(std::vector<std::string>(t, it)));
641  }
642  break;
643 
644  case ':':
645  case ',':
646  break;
647 
648  case '"':
649  if (type.empty()) {
650  std::string value(it->begin() + 1, it->end() - 1);
651  v->push_back(Variant(value, Variant::TypeQuoted));
652  }
653  break;
654 
655  default:
656  if (type.empty()) {
657  v->push_back(Variant(*it, Variant::TypeNonQuoted));
658  }
659  }
660  }
661 
662  this->value = v;
663 }
664 
665 void Vector::unmsgpack(sella::util::MessagePack &mpack, uint32_t &offset) throw (TypeCastException) {
666  std::shared_ptr<std::vector<Variant>> v = std::make_shared<std::vector<Variant>>();
667 
668  union {
669  bool b;
670  int64_t s;
671  uint64_t u;
672  double d;
673  } u;
674 
675  try {
676  v->reserve(mpack.count(offset));
677 
678  mpack.scan(offset, [this, &mpack, &v, &u](uint32_t i, uint32_t value) {
679  switch (mpack.typeof(value)) {
680  case sella::util::MessagePack::TYPE_NULL:
681  v->push_back(std::move(Variant()));
682  break;
683 
684  case sella::util::MessagePack::TYPE_BOOLEAN:
685  if (LIKELY(mpack.decode(u.b, value))) {
686  v->push_back(std::move(Variant(u.b)));
687  } else {
688  THROW(TypeCastException, "Failed to decode boolean");
689  }
690  break;
691 
692  case sella::util::MessagePack::TYPE_SIGNED:
693  if (LIKELY(mpack.decode(u.s, value))) {
694  v->push_back(std::move(Variant(u.s)));
695  } else {
696  THROW(TypeCastException, "Failed to decode signed");
697  }
698  break;
699 
700  case sella::util::MessagePack::TYPE_UNSIGNED:
701  if (LIKELY(mpack.decode(u.u, value))) {
702  v->push_back(std::move(Variant(u.u)));
703  } else {
704  THROW(TypeCastException, "Failed to decode unsigned");
705  }
706  break;
707 
708  case sella::util::MessagePack::TYPE_FLOAT:
709  if (LIKELY(mpack.decode(u.d, value))) {
710  v->push_back(std::move(Variant(u.d)));
711  } else {
712  THROW(TypeCastException, "Failed to decode double");
713  }
714  break;
715 
716  case sella::util::MessagePack::TYPE_STRING: {
717  std::string str;
718 
719  if (LIKELY(mpack.decode(str, value))) {
720  v->push_back(std::move(Variant(std::move(str))));
721  } else {
722  THROW(TypeCastException, "Failed to decode string");
723  }
724  break;
725  }
726 
727  case sella::util::MessagePack::TYPE_VECTOR:
728  v->push_back(std::move(Variant(std::move(std::make_shared<Vector>(mpack, value)))));
729  break;
730 
731  case sella::util::MessagePack::TYPE_OBJECT:
732  v->push_back(std::move(Variant(std::move(std::make_shared<Object>(mpack, value)))));
733  break;
734 
735  default:
736  THROW(TypeCastException, "Unsupported type %u in input", mpack.typeof(value));
737  }
738 
739  return true;
740  });
741  } catch (sella::util::MemoryException &e) {
742  RETHROW(TypeCastException, e);
743  } catch (TypeCastException &e) {
744  RETHROW(TypeCastException, e);
745  } catch (std::exception &e) {
746  THROW(TypeCastException, "%s", e.what());
747  }
748 
749  this->value = v;
750 }
751 
752 bool Vector::isType(const char *value, size_t size) throw () {
753  return (size > 1 && value[0] == '[' && value[size - 1] == ']');
754 }
755 
756 /*
757 ** vim: noet ts=3 sw=3
758 */