Kea  2.3.1-git
data.h
Go to the documentation of this file.
1 // Copyright (C) 2010-2022 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #ifndef ISC_DATA_H
8 #define ISC_DATA_H 1
9 
10 #include <iostream>
11 #include <map>
12 #include <stdexcept>
13 #include <string>
14 #include <vector>
15 
16 #include <boost/shared_ptr.hpp>
17 
18 #include <stdint.h>
19 
20 #include <exceptions/exceptions.h>
21 
22 namespace isc { namespace data {
23 
24 class Element;
25 // todo: describe the rationale behind ElementPtr?
26 typedef boost::shared_ptr<Element> ElementPtr;
27 typedef boost::shared_ptr<const Element> ConstElementPtr;
28 
34 class TypeError : public isc::Exception {
35 public:
36  TypeError(const char* file, size_t line, const char* what) :
37  isc::Exception(file, line, what) {}
38 };
39 
44 // i'd like to use Exception here but we need one that is derived from
45 // runtime_error (as this one is directly based on external data, and
46 // i want to add some values to any static data string that is provided)
47 class JSONError : public isc::Exception {
48 public:
49  JSONError(const char* file, size_t line, const char* what) :
50  isc::Exception(file, line, what) {}
51 };
52 
70 class Element {
71 
72 public:
92  struct Position {
93  std::string file_;
94  uint32_t line_;
95  uint32_t pos_;
96 
98  Position() : file_(""), line_(0), pos_(0) {
99  }
100 
106  Position(const std::string& file, const uint32_t line,
107  const uint32_t pos)
108  : file_(file), line_(line), pos_(pos) {
109  }
110 
114  std::string str() const;
115  };
116 
124  static const Position& ZERO_POSITION() {
125  static Position position("", 0, 0);
126  return (position);
127  }
128 
129 private:
130  // technically the type could be omitted; is it useful?
131  // should we remove it or replace it with a pure virtual
132  // function getType?
133  int type_;
134 
136  Position position_;
137 
138 protected:
139 
146  Element(int t, const Position& pos = ZERO_POSITION())
147  : type_(t), position_(pos) {
148  }
149 
150 
151 public:
152 
153  // any is a special type used in list specifications, specifying
154  // that the elements can be of any type
155  enum types { integer, real, boolean, null, string, list, map, any };
156  // base class; make dtor virtual
157  virtual ~Element() {};
158 
160  int getType() const { return (type_); }
161 
167  const Position& getPosition() const { return (position_); }
168 
176  std::string str() const;
177 
182  std::string toWire() const;
183  void toWire(std::ostream& out) const;
184 
187 #define throwTypeError(error) \
188  { \
189  std::string msg_ = error; \
190  if ((position_.file_ != "") || \
191  (position_.line_ != 0) || \
192  (position_.pos_ != 0)) { \
193  msg_ += " in (" + position_.str() + ")"; \
194  } \
195  isc_throw(TypeError, msg_); \
196  }
197 
199 
201  virtual bool equals(const Element& other) const = 0;
202 
205  virtual void toJSON(std::ostream& ss) const = 0;
206 
214 
215  virtual int64_t intValue() const
216  { throwTypeError("intValue() called on non-integer Element"); };
217  virtual double doubleValue() const
218  { throwTypeError("doubleValue() called on non-double Element"); };
219  virtual bool boolValue() const
220  { throwTypeError("boolValue() called on non-Bool Element"); };
221  virtual std::string stringValue() const
222  { throwTypeError("stringValue() called on non-string Element"); };
223  virtual const std::vector<ElementPtr>& listValue() const {
224  // replace with real exception or empty vector?
225  throwTypeError("listValue() called on non-list Element");
226  };
227  virtual const std::map<std::string, ConstElementPtr>& mapValue() const {
228  // replace with real exception or empty map?
229  throwTypeError("mapValue() called on non-map Element");
230  };
232 
241 
242  virtual bool getValue(int64_t& t) const;
243  virtual bool getValue(double& t) const;
244  virtual bool getValue(bool& t) const;
245  virtual bool getValue(std::string& t) const;
246  virtual bool getValue(std::vector<ElementPtr>& t) const;
247  virtual bool getValue(std::map<std::string, ConstElementPtr>& t) const;
249 
259 
260  virtual bool setValue(const long long int v);
261  bool setValue(const long int i) { return (setValue(static_cast<long long int>(i))); };
262  bool setValue(const int i) { return (setValue(static_cast<long long int>(i))); };
263  virtual bool setValue(const double v);
264  virtual bool setValue(const bool t);
265  virtual bool setValue(const std::string& v);
266  virtual bool setValue(const std::vector<ElementPtr>& v);
267  virtual bool setValue(const std::map<std::string, ConstElementPtr>& v);
269 
270  // Other functions for specific subtypes
271 
276 
277  virtual ConstElementPtr get(const int i) const;
281 
286  virtual ElementPtr getNonConst(const int i) const;
287 
292  virtual void set(const size_t i, ElementPtr element);
293 
296  virtual void add(ElementPtr element);
297 
301  virtual void remove(const int i);
302 
304  virtual size_t size() const;
305 
307  virtual bool empty() const;
309 
310 
315 
316  virtual ConstElementPtr get(const std::string& name) const;
320 
324  virtual void set(const std::string& name, ConstElementPtr element);
325 
328  virtual void remove(const std::string& name);
329 
333  virtual bool contains(const std::string& name) const;
334 
348  virtual ConstElementPtr find(const std::string& identifier) const;
349 
354  virtual bool find(const std::string& identifier, ConstElementPtr& t) const;
356 
358 
359  // TODO: should we move all factory functions to a different class
360  // so as not to burden the Element base with too many functions?
361  // and/or perhaps even to a separate header?
362 
375 
376  static ElementPtr create(const Position& pos = ZERO_POSITION());
377  static ElementPtr create(const long long int i,
378  const Position& pos = ZERO_POSITION());
379  static ElementPtr create(const int i,
380  const Position& pos = ZERO_POSITION());
381  static ElementPtr create(const long int i,
382  const Position& pos = ZERO_POSITION());
383  static ElementPtr create(const uint32_t i,
384  const Position& pos = ZERO_POSITION());
385  static ElementPtr create(const double d,
386  const Position& pos = ZERO_POSITION());
387  static ElementPtr create(const bool b,
388  const Position& pos = ZERO_POSITION());
389  static ElementPtr create(const std::string& s,
390  const Position& pos = ZERO_POSITION());
391  // need both std:string and char *, since c++ will match
392  // bool before std::string when you pass it a char *
393  static ElementPtr create(const char *s,
394  const Position& pos = ZERO_POSITION());
395 
400  static ElementPtr createList(const Position& pos = ZERO_POSITION());
401 
406  static ElementPtr createMap(const Position& pos = ZERO_POSITION());
408 
410 
414 
416  static ElementPtr fromJSON(const std::string& in, bool preproc = false);
423 
433  static ElementPtr fromJSON(std::istream& in, bool preproc = false);
434 
446  static ElementPtr fromJSON(std::istream& in, const std::string& file_name,
447  bool preproc = false);
448 
461  // make this one private?
463  static ElementPtr fromJSON(std::istream& in, const std::string& file,
464  int& line, int &pos);
465 
473  static ElementPtr fromJSONFile(const std::string& file_name,
474  bool preproc = false);
476 
478 
484  static std::string typeToName(Element::types type);
485 
491  static Element::types nameToType(const std::string& type_name);
492 
507  static void preprocess(std::istream& in, std::stringstream& out);
508 
510 
514 
516  static ElementPtr fromWire(std::stringstream& in, int length);
525 
532  static ElementPtr fromWire(const std::string& s);
534 
538  if (type_ == list || type_ == map) {
539  size_t s(size());
540  for (size_t i = 0; i < s; ++i) {
541  // Get child.
542  ElementPtr child;
543  if (type_ == list) {
544  child = getNonConst(i);
545  } else if (type_ == map) {
546  std::string const key(get(i)->stringValue());
547  // The ElementPtr - ConstElementPtr disparity between
548  // ListElement and MapElement is forcing a const cast here.
549  // It's undefined behavior to modify it after const casting.
550  // The options are limited. I've tried templating, moving
551  // this function from a member function to free-standing and
552  // taking the Element template as argument. I've tried
553  // making it a virtual function with overridden
554  // implementations in ListElement and MapElement. Nothing
555  // works.
556  child = boost::const_pointer_cast<Element>(get(key));
557  }
558 
559  // Makes no sense to continue for non-container children.
560  if (child->getType() != list && child->getType() != map) {
561  continue;
562  }
563 
564  // Recurse if not empty.
565  if (!child->empty()){
566  child->removeEmptyContainersRecursively();
567  }
568 
569  // When returning from recursion, remove if empty.
570  if (child->empty()) {
571  remove(i);
572  --i;
573  --s;
574  }
575  }
576  }
577  }
578 };
579 
590 class IntElement : public Element {
591  int64_t i;
592 public:
593  IntElement(int64_t v, const Position& pos = ZERO_POSITION())
594  : Element(integer, pos), i(v) { }
595  int64_t intValue() const { return (i); }
596  using Element::getValue;
597  bool getValue(int64_t& t) const { t = i; return (true); }
598  using Element::setValue;
599  bool setValue(long long int v) { i = v; return (true); }
600  void toJSON(std::ostream& ss) const;
601  bool equals(const Element& other) const;
602 };
603 
604 class DoubleElement : public Element {
605  double d;
606 
607 public:
608  DoubleElement(double v, const Position& pos = ZERO_POSITION())
609  : Element(real, pos), d(v) {};
610  double doubleValue() const { return (d); }
611  using Element::getValue;
612  bool getValue(double& t) const { t = d; return (true); }
613  using Element::setValue;
614  bool setValue(const double v) { d = v; return (true); }
615  void toJSON(std::ostream& ss) const;
616  bool equals(const Element& other) const;
617 };
618 
619 class BoolElement : public Element {
620  bool b;
621 
622 public:
623  BoolElement(const bool v, const Position& pos = ZERO_POSITION())
624  : Element(boolean, pos), b(v) {};
625  bool boolValue() const { return (b); }
626  using Element::getValue;
627  bool getValue(bool& t) const { t = b; return (true); }
628  using Element::setValue;
629  bool setValue(const bool v) { b = v; return (true); }
630  void toJSON(std::ostream& ss) const;
631  bool equals(const Element& other) const;
632 };
633 
634 class NullElement : public Element {
635 public:
636  NullElement(const Position& pos = ZERO_POSITION())
637  : Element(null, pos) {};
638  void toJSON(std::ostream& ss) const;
639  bool equals(const Element& other) const;
640 };
641 
642 class StringElement : public Element {
643  std::string s;
644 
645 public:
646  StringElement(std::string v, const Position& pos = ZERO_POSITION())
647  : Element(string, pos), s(v) {};
648  std::string stringValue() const { return (s); }
649  using Element::getValue;
650  bool getValue(std::string& t) const { t = s; return (true); }
651  using Element::setValue;
652  bool setValue(const std::string& v) { s = v; return (true); }
653  void toJSON(std::ostream& ss) const;
654  bool equals(const Element& other) const;
655 };
656 
657 class ListElement : public Element {
658  std::vector<ElementPtr> l;
659 
660 public:
661  ListElement(const Position& pos = ZERO_POSITION())
662  : Element(list, pos) {}
663  const std::vector<ElementPtr>& listValue() const { return (l); }
664  using Element::getValue;
665  bool getValue(std::vector<ElementPtr>& t) const {
666  t = l;
667  return (true);
668  }
669  using Element::setValue;
670  bool setValue(const std::vector<ElementPtr>& v) {
671  l = v;
672  return (true);
673  }
674  using Element::get;
675  ConstElementPtr get(int i) const { return (l.at(i)); }
676  ElementPtr getNonConst(int i) const { return (l.at(i)); }
677  using Element::set;
678  void set(size_t i, ElementPtr e) {
679  l.at(i) = e;
680  }
681  void add(ElementPtr e) { l.push_back(e); };
682  using Element::remove;
683  void remove(int i) { l.erase(l.begin() + i); };
684  void toJSON(std::ostream& ss) const;
685  size_t size() const { return (l.size()); }
686  bool empty() const { return (l.empty()); }
687  bool equals(const Element& other) const;
688 
698  void sort(std::string const& index = std::string());
699 };
700 
701 class MapElement : public Element {
702  std::map<std::string, ConstElementPtr> m;
703 
704 public:
705  MapElement(const Position& pos = ZERO_POSITION()) : Element(map, pos) {}
706  // @todo should we have direct iterators instead of exposing the std::map
707  // here?
708  const std::map<std::string, ConstElementPtr>& mapValue() const override {
709  return (m);
710  }
711  using Element::getValue;
712  bool getValue(std::map<std::string, ConstElementPtr>& t) const override {
713  t = m;
714  return (true);
715  }
716  using Element::setValue;
717  bool setValue(const std::map<std::string, ConstElementPtr>& v) override {
718  m = v;
719  return (true);
720  }
721  using Element::get;
722  ConstElementPtr get(const std::string& s) const override {
723  auto found = m.find(s);
724  return (found != m.end() ? found->second : ConstElementPtr());
725  }
726 
733  ConstElementPtr get(int const i) const override {
734  auto it(m.begin());
735  std::advance(it, i);
736  return create(it->first);
737  }
738 
739  using Element::set;
740  void set(const std::string& key, ConstElementPtr value) override;
741  using Element::remove;
742  void remove(const std::string& s) override { m.erase(s); }
743 
747  void remove(int const i) override {
748  auto it(m.begin());
749  std::advance(it, i);
750  m.erase(it);
751  }
752 
753  bool contains(const std::string& s) const override {
754  return (m.find(s) != m.end());
755  }
756  void toJSON(std::ostream& ss) const override;
757 
758  // we should name the two finds better...
759  // find the element at id; raises TypeError if one of the
760  // elements at path except the one we're looking for is not a
761  // mapelement.
762  // returns an empty element if the item could not be found
763  ConstElementPtr find(const std::string& id) const override;
764 
765  // find the Element at 'id', and store the element pointer in t
766  // returns true if found, or false if not found (either because
767  // it doesn't exist or one of the elements in the path is not
768  // a MapElement)
769  bool find(const std::string& id, ConstElementPtr& t) const override;
770 
774  size_t size() const override {
775  return (m.size());
776  }
777 
778  bool equals(const Element& other) const override;
779 
780  bool empty() const override { return (m.empty()); }
781 };
782 
786 bool isNull(ConstElementPtr p);
787 
795 void removeIdentical(ElementPtr a, ConstElementPtr b);
796 
802 ConstElementPtr removeIdentical(ConstElementPtr a, ConstElementPtr b);
803 
812 void merge(ElementPtr element, ConstElementPtr other);
813 
823 typedef std::function<bool (ElementPtr&, ElementPtr&)> MatchTestFunc;
824 
827 typedef std::function<bool (ElementPtr&)> NoDataTestFunc;
828 
830 typedef std::function<bool (const std::string&)> IsKeyTestFunc;
831 
835  MatchTestFunc match_;
836  NoDataTestFunc no_data_;
837  IsKeyTestFunc is_key_;
838 };
839 
842 typedef std::map<std::string, HierarchyTraversalTest> FunctionMap;
843 
857 typedef std::vector<FunctionMap> HierarchyDescriptor;
858 
877 void mergeDiffAdd(ElementPtr& element, ElementPtr& other,
878  HierarchyDescriptor& hierarchy, std::string key,
879  size_t idx = 0);
880 
898 void mergeDiffDel(ElementPtr& element, ElementPtr& other,
899  HierarchyDescriptor& hierarchy, std::string key,
900  size_t idx = 0);
901 
918 void extend(const std::string& container, const std::string& extension,
919  ElementPtr& element, ElementPtr& other,
920  HierarchyDescriptor& hierarchy, std::string key, size_t idx = 0,
921  bool alter = false);
922 
933 ElementPtr copy(ConstElementPtr from, int level = 100);
934 
940 bool isEquivalent(ConstElementPtr a, ConstElementPtr b);
941 
953 void prettyPrint(ConstElementPtr element, std::ostream& out,
954  unsigned indent = 0, unsigned step = 2);
955 
966 std::string prettyPrint(ConstElementPtr element,
967  unsigned indent = 0, unsigned step = 2);
968 
979 std::ostream& operator<<(std::ostream& out, const Element::Position& pos);
980 
995 std::ostream& operator<<(std::ostream& out, const Element& e);
996 
997 bool operator==(const Element& a, const Element& b);
998 bool operator!=(const Element& a, const Element& b);
999 bool operator<(const Element& a, const Element& b);
1000 
1001 } // namespace data
1002 } // namespace isc
1003 
1004 #endif // ISC_DATA_H
1005 
1006 // Local Variables:
1007 // mode: c++
1008 // End:
virtual std::string stringValue() const
Definition: data.h:221
int64_t intValue() const
Definition: data.h:595
virtual ~Element()
Definition: data.h:157
bool getValue(double &t) const
Definition: data.h:612
bool operator<(Element const &a, Element const &b)
Definition: data.cc:219
bool setValue(const int i)
Definition: data.h:262
uint32_t line_
Line number.
Definition: data.h:94
virtual void set(const size_t i, ElementPtr element)
Sets the ElementPtr at the given index.
Definition: data.cc:140
bool empty() const
Return true if there are no elements in the list.
Definition: data.h:686
static const Position & ZERO_POSITION()
Returns Position object with line_ and pos_ set to 0, and with an empty file name.
Definition: data.h:124
void extend(const std::string &container, const std::string &extension, ElementPtr &element, ElementPtr &other, HierarchyDescriptor &hierarchy, std::string key, size_t idx, bool alter)
Extends data by adding the specified &#39;extension&#39; elements from &#39;other&#39; inside the &#39;container&#39; element...
Definition: data.cc:1308
const Position & getPosition() const
Returns position where the data element&#39;s value starts in a configuration string. ...
Definition: data.h:167
bool setValue(const std::vector< ElementPtr > &v)
Definition: data.h:670
A standard Data module exception that is thrown if a parse error is encountered when constructing an ...
Definition: data.h:47
void prettyPrint(ConstElementPtr element, std::ostream &out, unsigned indent, unsigned step)
Pretty prints the data into stream.
Definition: data.cc:1487
const std::map< std::string, ConstElementPtr > & mapValue() const override
Definition: data.h:708
bool operator!=(const Element &a, const Element &b)
Definition: data.cc:214
virtual int64_t intValue() const
Definition: data.h:215
bool isEquivalent(ConstElementPtr a, ConstElementPtr b)
Compares the data with other using unordered lists.
Definition: data.cc:1482
bool setValue(long long int v)
Definition: data.h:599
virtual bool getValue(int64_t &t) const
Definition: data.cc:70
boost::shared_ptr< Element > ElementPtr
Definition: data.h:24
ListElement(const Position &pos=ZERO_POSITION())
Definition: data.h:661
#define throwTypeError(error)
Add the position to a TypeError message should be used in place of isc_throw(TypeError, error)
Definition: data.h:187
void removeIdentical(ElementPtr a, ConstElementPtr b)
Remove all values from the first ElementPtr that are equal in the second.
Definition: data.cc:1093
StringElement(std::string v, const Position &pos=ZERO_POSITION())
Definition: data.h:646
bool isNull(ConstElementPtr p)
Checks whether the given ElementPtr is a NULL pointer.
Definition: data.cc:1088
double doubleValue() const
Definition: data.h:610
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
bool getValue(std::map< std::string, ConstElementPtr > &t) const override
Definition: data.h:712
void mergeDiffDel(ElementPtr &element, ElementPtr &other, HierarchyDescriptor &hierarchy, std::string key, size_t idx)
Merges the diff data by removing the data present in &#39;other&#39; from &#39;element&#39; (recursively).
Definition: data.cc:1218
Position()
Default constructor.
Definition: data.h:98
Position(const std::string &file, const uint32_t line, const uint32_t pos)
Constructor.
Definition: data.h:106
std::vector< FunctionMap > HierarchyDescriptor
Hierarchy descriptor of the containers in a specific Element hierarchy tree.
Definition: data.h:857
bool operator==(const Element &a, const Element &b)
Definition: data.cc:210
bool getValue(bool &t) const
Definition: data.h:627
bool setValue(const std::map< std::string, ConstElementPtr > &v) override
Definition: data.h:717
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
Definition: data.cc:1360
std::ostream & operator<<(std::ostream &out, const Element::Position &pos)
Insert Element::Position as a string into stream.
Definition: data.cc:45
std::function< bool(ElementPtr &)> NoDataTestFunc
Function used to check if the data provided for the element contains only information used for identi...
Definition: data.h:827
size_t size() const override
Returns number of stored elements.
Definition: data.h:774
bool setValue(const bool v)
Definition: data.h:629
virtual const std::map< std::string, ConstElementPtr > & mapValue() const
Definition: data.h:227
Notes: IntElement type is changed to int64_t.
Definition: data.h:590
TypeError(const char *file, size_t line, const char *what)
Definition: data.h:36
IntElement(int64_t v, const Position &pos=ZERO_POSITION())
Definition: data.h:593
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:27
virtual const std::vector< ElementPtr > & listValue() const
Definition: data.h:223
bool getValue(int64_t &t) const
Definition: data.h:597
void removeEmptyContainersRecursively()
Remove all empty maps and lists from this Element and its descendants.
Definition: data.h:537
NullElement(const Position &pos=ZERO_POSITION())
Definition: data.h:636
A standard Data module exception that is thrown if a function is called for an Element that has a wro...
Definition: data.h:34
DoubleElement(double v, const Position &pos=ZERO_POSITION())
Definition: data.h:608
MapElement(const Position &pos=ZERO_POSITION())
Definition: data.h:705
Represents the position of the data element within a configuration string.
Definition: data.h:92
This is a base class for exceptions thrown from the DNS library module.
Defines the logger used by the top-level component of kea-lfc.
bool boolValue() const
Definition: data.h:625
std::function< bool(const std::string &)> IsKeyTestFunc
Function used to check if the key is used for identification.
Definition: data.h:830
uint32_t pos_
Position within the line.
Definition: data.h:95
bool contains(const std::string &s) const override
Checks if there is data at the given key.
Definition: data.h:753
void merge(ElementPtr element, ConstElementPtr other)
Merges the data from other into element.
Definition: data.cc:1139
bool setValue(const long int i)
Definition: data.h:261
Structure holding the test functions used to traverse the element hierarchy.
Definition: data.h:834
virtual double doubleValue() const
Definition: data.h:217
bool getValue(std::string &t) const
Definition: data.h:650
std::map< std::string, HierarchyTraversalTest > FunctionMap
Mapping between a container name and functions used to match elements inside the container.
Definition: data.h:842
int getType() const
Definition: data.h:160
std::function< bool(ElementPtr &, ElementPtr &)> MatchTestFunc
Function used to check if two MapElements refer to the same configuration data.
Definition: data.h:823
virtual ConstElementPtr get(const int i) const
Returns the ElementPtr at the given index.
Definition: data.cc:130
The Element class represents a piece of data, used by the command channel and configuration parts...
Definition: data.h:70
bool empty() const override
Return true if there are no elements in the list.
Definition: data.h:780
bool setValue(const std::string &v)
Definition: data.h:652
ElementPtr getNonConst(int i) const
returns element as non-const pointer
Definition: data.h:676
bool getValue(std::vector< ElementPtr > &t) const
Definition: data.h:665
virtual bool setValue(const long long int v)
Definition: data.cc:100
bool setValue(const double v)
Definition: data.h:614
BoolElement(const bool v, const Position &pos=ZERO_POSITION())
Definition: data.h:623
size_t size() const
Returns the number of elements in the list.
Definition: data.h:685
virtual void remove(const int i)
Removes the element at the given position.
Definition: data.cc:150
void mergeDiffAdd(ElementPtr &element, ElementPtr &other, HierarchyDescriptor &hierarchy, std::string key, size_t idx)
Merges the diff data by adding the missing elements from &#39;other&#39; to &#39;element&#39; (recursively).
Definition: data.cc:1157
std::string file_
File name.
Definition: data.h:93
void add(ElementPtr e)
Adds an ElementPtr to the list.
Definition: data.h:681
virtual bool boolValue() const
Definition: data.h:219
JSONError(const char *file, size_t line, const char *what)
Definition: data.h:49
Element(int t, const Position &pos=ZERO_POSITION())
Constructor.
Definition: data.h:146
const std::vector< ElementPtr > & listValue() const
Definition: data.h:663
std::string stringValue() const
Definition: data.h:648