PageRenderTime 39ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llcommon/llsd.h

https://bitbucket.org/lindenlab/viewer-beta/
C++ Header | 485 lines | 201 code | 50 blank | 234 comment | 12 complexity | 92279f6ec298b14aac39086f9a15418b MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llsd.h
  3. * @brief LLSD flexible data system.
  4. *
  5. * $LicenseInfo:firstyear=2005&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #ifndef LL_LLSD_NEW_H
  27. #define LL_LLSD_NEW_H
  28. #include <map>
  29. #include <string>
  30. #include <vector>
  31. #include "stdtypes.h"
  32. #include "lldate.h"
  33. #include "lluri.h"
  34. #include "lluuid.h"
  35. /**
  36. LLSD provides a flexible data system similar to the data facilities of
  37. dynamic languages like Perl and Python. It is created to support exchange
  38. of structured data between loosely coupled systems. (Here, "loosely coupled"
  39. means not compiled together into the same module.)
  40. Data in such exchanges must be highly tolerant of changes on either side
  41. such as:
  42. - recompilation
  43. - implementation in a different langauge
  44. - addition of extra parameters
  45. - execution of older versions (with fewer parameters)
  46. To this aim, the C++ API of LLSD strives to be very easy to use, and to
  47. default to "the right thing" wherever possible. It is extremely tolerant
  48. of errors and unexpected situations.
  49. The fundamental class is LLSD. LLSD is a value holding object. It holds
  50. one value that is either undefined, one of the scalar types, or a map or an
  51. array. LLSD objects have value semantics (copying them copies the value,
  52. though it can be considered efficient, due to sharing), and mutable.
  53. Undefined is the singular value given to LLSD objects that are not
  54. initialized with any data. It is also used as the return value for
  55. operations that return an LLSD.
  56. The scalar data types are:
  57. - Boolean - true or false
  58. - Integer - a 32 bit signed integer
  59. - Real - a 64 IEEE 754 floating point value
  60. - UUID - a 128 unique value
  61. - String - a sequence of zero or more Unicode chracters
  62. - Date - an absolute point in time, UTC,
  63. with resolution to the second
  64. - URI - a String that is a URI
  65. - Binary - a sequence of zero or more octets (unsigned bytes)
  66. A map is a dictionary mapping String keys to LLSD values. The keys are
  67. unique within a map, and have only one value (though that value could be
  68. an LLSD array).
  69. An array is a sequence of zero or more LLSD values.
  70. Thread Safety
  71. In general, these LLSD classes offer *less* safety than STL container
  72. classes. Implementations prior to this one were unsafe even when
  73. completely unrelated LLSD trees were in two threads due to reference
  74. sharing of special 'undefined' values that participated in the reference
  75. counting mechanism.
  76. The dereference-before-refcount and aggressive tree sharing also make
  77. it impractical to share an LLSD across threads. A strategy of passing
  78. ownership or a copy to another thread is still difficult due to a lack
  79. of a cloning interface but it can be done with some care.
  80. One way of transferring ownership is as follows:
  81. void method(const LLSD input) {
  82. ...
  83. LLSD * xfer_tree = new LLSD();
  84. {
  85. // Top-level values
  86. (* xfer_tree)['label'] = "Some text";
  87. (* xfer_tree)['mode'] = APP_MODE_CONSTANT;
  88. // There will be a second-level
  89. LLSD subtree(LLSD::emptyMap());
  90. (* xfer_tree)['subtree'] = subtree;
  91. // Do *not* copy from LLSD objects via LLSD
  92. // intermediaries. Only use plain-old-data
  93. // types as intermediaries to prevent reference
  94. // sharing.
  95. subtree['value1'] = input['value1'].asInteger();
  96. subtree['value2'] = input['value2'].asString();
  97. // Close scope and drop 'subtree's reference.
  98. // Only xfer_tree has a reference to the second
  99. // level data.
  100. }
  101. ...
  102. // Transfer the LLSD pointer to another thread. Ownership
  103. // transfers, this thread no longer has a reference to any
  104. // part of the xfer_tree and there's nothing to free or
  105. // release here. Receiving thread does need to delete the
  106. // pointer when it is done with the LLSD. Transfer
  107. // mechanism must perform correct data ordering operations
  108. // as dictated by architecture.
  109. other_thread.sendMessageAndPointer("Take This", xfer_tree);
  110. xfer_tree = NULL;
  111. Avoid this pattern which provides half of a race condition:
  112. void method(const LLSD input) {
  113. ...
  114. LLSD xfer_tree(LLSD::emptyMap());
  115. xfer_tree['label'] = "Some text";
  116. xfer_tree['mode'] = APP_MODE_CONSTANT;
  117. ...
  118. other_thread.sendMessageAndPointer("Take This", xfer_tree);
  119. @nosubgrouping
  120. */
  121. // Normally undefined, used for diagnostics
  122. //#define LLSD_DEBUG_INFO 1
  123. class LL_COMMON_API LLSD
  124. {
  125. public:
  126. LLSD(); ///< initially Undefined
  127. ~LLSD(); ///< this class may NOT be subclassed
  128. /** @name Copyable and Assignable */
  129. //@{
  130. LLSD(const LLSD&);
  131. void assign(const LLSD& other);
  132. LLSD& operator=(const LLSD& other) { assign(other); return *this; }
  133. //@}
  134. void clear(); ///< resets to Undefined
  135. /** @name Scalar Types
  136. The scalar types, and how they map onto C++
  137. */
  138. //@{
  139. typedef bool Boolean;
  140. typedef S32 Integer;
  141. typedef F64 Real;
  142. typedef std::string String;
  143. typedef LLUUID UUID;
  144. typedef LLDate Date;
  145. typedef LLURI URI;
  146. typedef std::vector<U8> Binary;
  147. //@}
  148. /** @name Scalar Constructors */
  149. //@{
  150. LLSD(Boolean);
  151. LLSD(Integer);
  152. LLSD(Real);
  153. LLSD(const String&);
  154. LLSD(const UUID&);
  155. LLSD(const Date&);
  156. LLSD(const URI&);
  157. LLSD(const Binary&);
  158. //@}
  159. /** @name Convenience Constructors */
  160. //@{
  161. LLSD(F32); // F32 -> Real
  162. //@}
  163. /** @name Scalar Assignment */
  164. //@{
  165. void assign(Boolean);
  166. void assign(Integer);
  167. void assign(Real);
  168. void assign(const String&);
  169. void assign(const UUID&);
  170. void assign(const Date&);
  171. void assign(const URI&);
  172. void assign(const Binary&);
  173. LLSD& operator=(Boolean v) { assign(v); return *this; }
  174. LLSD& operator=(Integer v) { assign(v); return *this; }
  175. LLSD& operator=(Real v) { assign(v); return *this; }
  176. LLSD& operator=(const String& v) { assign(v); return *this; }
  177. LLSD& operator=(const UUID& v) { assign(v); return *this; }
  178. LLSD& operator=(const Date& v) { assign(v); return *this; }
  179. LLSD& operator=(const URI& v) { assign(v); return *this; }
  180. LLSD& operator=(const Binary& v) { assign(v); return *this; }
  181. //@}
  182. /**
  183. @name Scalar Accessors
  184. @brief Fetch a scalar value, converting if needed and possible
  185. Conversion among the basic types, Boolean, Integer, Real and String, is
  186. fully defined. Each type can be converted to another with a reasonable
  187. interpretation. These conversions can be used as a convenience even
  188. when you know the data is in one format, but you want it in another. Of
  189. course, many of these conversions lose information.
  190. Note: These conversions are not the same as Perl's. In particular, when
  191. converting a String to a Boolean, only the empty string converts to
  192. false. Converting the String "0" to Boolean results in true.
  193. Conversion to and from UUID, Date, and URI is only defined to and from
  194. String. Conversion is defined to be information preserving for valid
  195. values of those types. These conversions can be used when one needs to
  196. convert data to or from another system that cannot handle these types
  197. natively, but can handle strings.
  198. Conversion to and from Binary isn't defined.
  199. Conversion of the Undefined value to any scalar type results in a
  200. reasonable null or zero value for the type.
  201. */
  202. //@{
  203. Boolean asBoolean() const;
  204. Integer asInteger() const;
  205. Real asReal() const;
  206. String asString() const;
  207. UUID asUUID() const;
  208. Date asDate() const;
  209. URI asURI() const;
  210. Binary asBinary() const;
  211. operator Boolean() const { return asBoolean(); }
  212. operator Integer() const { return asInteger(); }
  213. operator Real() const { return asReal(); }
  214. operator String() const { return asString(); }
  215. operator UUID() const { return asUUID(); }
  216. operator Date() const { return asDate(); }
  217. operator URI() const { return asURI(); }
  218. operator Binary() const { return asBinary(); }
  219. // This is needed because most platforms do not automatically
  220. // convert the boolean negation as a bool in an if statement.
  221. bool operator!() const {return !asBoolean();}
  222. //@}
  223. /** @name Character Pointer Helpers
  224. These are helper routines to make working with char* as easy as
  225. working with strings.
  226. */
  227. //@{
  228. LLSD(const char*);
  229. void assign(const char*);
  230. LLSD& operator=(const char* v) { assign(v); return *this; }
  231. //@}
  232. /** @name Map Values */
  233. //@{
  234. static LLSD emptyMap();
  235. bool has(const String&) const;
  236. LLSD get(const String&) const;
  237. void insert(const String&, const LLSD&);
  238. void erase(const String&);
  239. LLSD& with(const String&, const LLSD&);
  240. LLSD& operator[](const String&);
  241. LLSD& operator[](const char* c) { return (*this)[String(c)]; }
  242. const LLSD& operator[](const String&) const;
  243. const LLSD& operator[](const char* c) const { return (*this)[String(c)]; }
  244. //@}
  245. /** @name Array Values */
  246. //@{
  247. static LLSD emptyArray();
  248. LLSD get(Integer) const;
  249. void set(Integer, const LLSD&);
  250. void insert(Integer, const LLSD&);
  251. void append(const LLSD&);
  252. void erase(Integer);
  253. LLSD& with(Integer, const LLSD&);
  254. const LLSD& operator[](Integer) const;
  255. LLSD& operator[](Integer);
  256. //@}
  257. /** @name Iterators */
  258. //@{
  259. int size() const;
  260. typedef std::map<String, LLSD>::iterator map_iterator;
  261. typedef std::map<String, LLSD>::const_iterator map_const_iterator;
  262. map_iterator beginMap();
  263. map_iterator endMap();
  264. map_const_iterator beginMap() const;
  265. map_const_iterator endMap() const;
  266. typedef std::vector<LLSD>::iterator array_iterator;
  267. typedef std::vector<LLSD>::const_iterator array_const_iterator;
  268. array_iterator beginArray();
  269. array_iterator endArray();
  270. array_const_iterator beginArray() const;
  271. array_const_iterator endArray() const;
  272. //@}
  273. /** @name Type Testing */
  274. //@{
  275. enum Type {
  276. TypeUndefined = 0,
  277. TypeBoolean,
  278. TypeInteger,
  279. TypeReal,
  280. TypeString,
  281. TypeUUID,
  282. TypeDate,
  283. TypeURI,
  284. TypeBinary,
  285. TypeMap,
  286. TypeArray,
  287. TypeLLSDTypeEnd,
  288. TypeLLSDTypeBegin = TypeUndefined,
  289. TypeLLSDNumTypes = (TypeLLSDTypeEnd - TypeLLSDTypeBegin)
  290. };
  291. Type type() const;
  292. bool isUndefined() const { return type() == TypeUndefined; }
  293. bool isDefined() const { return type() != TypeUndefined; }
  294. bool isBoolean() const { return type() == TypeBoolean; }
  295. bool isInteger() const { return type() == TypeInteger; }
  296. bool isReal() const { return type() == TypeReal; }
  297. bool isString() const { return type() == TypeString; }
  298. bool isUUID() const { return type() == TypeUUID; }
  299. bool isDate() const { return type() == TypeDate; }
  300. bool isURI() const { return type() == TypeURI; }
  301. bool isBinary() const { return type() == TypeBinary; }
  302. bool isMap() const { return type() == TypeMap; }
  303. bool isArray() const { return type() == TypeArray; }
  304. //@}
  305. /** @name Automatic Cast Protection
  306. These are not implemented on purpose. Without them, C++ can perform
  307. some conversions that are clearly not what the programmer intended.
  308. If you get a linker error about these being missing, you have made
  309. mistake in your code. DO NOT IMPLEMENT THESE FUNCTIONS as a fix.
  310. All of these problems stem from trying to support char* in LLSD or in
  311. std::string. There are too many automatic casts that will lead to
  312. using an arbitrary pointer or scalar type to std::string.
  313. */
  314. //@{
  315. LLSD(const void*); ///< construct from aribrary pointers
  316. void assign(const void*); ///< assign from arbitrary pointers
  317. LLSD& operator=(const void*); ///< assign from arbitrary pointers
  318. bool has(Integer) const; ///< has() only works for Maps
  319. //@}
  320. /** @name Implementation */
  321. //@{
  322. public:
  323. class Impl;
  324. private:
  325. Impl* impl;
  326. friend class LLSD::Impl;
  327. //@}
  328. private:
  329. /** @name Debugging Interface */
  330. //@{
  331. /// Returns XML version of llsd -- only to be called from debugger
  332. static const char *dumpXML(const LLSD &llsd);
  333. /// Returns Notation version of llsd -- only to be called from debugger
  334. static const char *dump(const LLSD &llsd);
  335. //@}
  336. public:
  337. static std::string typeString(Type type); // Return human-readable type as a string
  338. };
  339. struct llsd_select_bool : public std::unary_function<LLSD, LLSD::Boolean>
  340. {
  341. LLSD::Boolean operator()(const LLSD& sd) const
  342. {
  343. return sd.asBoolean();
  344. }
  345. };
  346. struct llsd_select_integer : public std::unary_function<LLSD, LLSD::Integer>
  347. {
  348. LLSD::Integer operator()(const LLSD& sd) const
  349. {
  350. return sd.asInteger();
  351. }
  352. };
  353. struct llsd_select_real : public std::unary_function<LLSD, LLSD::Real>
  354. {
  355. LLSD::Real operator()(const LLSD& sd) const
  356. {
  357. return sd.asReal();
  358. }
  359. };
  360. struct llsd_select_float : public std::unary_function<LLSD, F32>
  361. {
  362. F32 operator()(const LLSD& sd) const
  363. {
  364. return (F32)sd.asReal();
  365. }
  366. };
  367. struct llsd_select_uuid : public std::unary_function<LLSD, LLSD::UUID>
  368. {
  369. LLSD::UUID operator()(const LLSD& sd) const
  370. {
  371. return sd.asUUID();
  372. }
  373. };
  374. struct llsd_select_string : public std::unary_function<LLSD, LLSD::String>
  375. {
  376. LLSD::String operator()(const LLSD& sd) const
  377. {
  378. return sd.asString();
  379. }
  380. };
  381. LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLSD& llsd);
  382. namespace llsd
  383. {
  384. #ifdef LLSD_DEBUG_INFO
  385. /** @name Unit Testing Interface */
  386. //@{
  387. LL_COMMON_API void dumpStats(const LLSD&); ///< Output information on object and usage
  388. /// @warn THE FOLLOWING COUNTS WILL NOT BE ACCURATE IN A MULTI-THREADED
  389. /// ENVIRONMENT.
  390. ///
  391. /// These counts track LLSD::Impl (hidden) objects.
  392. LL_COMMON_API U32 allocationCount(); ///< how many Impls have been made
  393. LL_COMMON_API U32 outstandingCount(); ///< how many Impls are still alive
  394. /// These counts track LLSD (public) objects.
  395. LL_COMMON_API extern S32 sLLSDAllocationCount; ///< Number of LLSD objects ever created
  396. LL_COMMON_API extern S32 sLLSDNetObjects; ///< Number of LLSD objects that exist
  397. #endif
  398. //@}
  399. } // namespace llsd
  400. /** QUESTIONS & TO DOS
  401. - Would Binary be more convenient as unsigned char* buffer semantics?
  402. - Should Binary be convertible to/from String, and if so how?
  403. - as UTF8 encoded strings (making not like UUID<->String)
  404. - as Base64 or Base96 encoded (making like UUID<->String)
  405. - Conversions to std::string and LLUUID do not result in easy assignment
  406. to std::string, std::string or LLUUID due to non-unique conversion paths
  407. */
  408. #endif // LL_LLSD_NEW_H