tb_value.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. // ================================================================================
  2. // == This file is a part of Turbo Badger. (C) 2011-2014, Emil Segerås ==
  3. // == See tb_core.h for more information. ==
  4. // ================================================================================
  5. #include "tb_value.h"
  6. #include "tb_object.h"
  7. #include "tb_str.h"
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <assert.h>
  12. namespace tb {
  13. // FIX: ## Floating point string conversions might be locale dependant. Force "." as decimal!
  14. // == Helper functions ============================
  15. char *next_token(char *&str, const char *delim) {
  16. str += strspn(str, delim);
  17. if (!*str)
  18. return nullptr;
  19. char *token = str;
  20. str += strcspn(str, delim);
  21. if (*str)
  22. *str++ = '\0';
  23. return token;
  24. }
  25. bool is_start_of_number(const char *str)
  26. {
  27. if (*str == '-')
  28. str++;
  29. if (*str == '.')
  30. str++;
  31. return *str >= '0' && *str <= '9';
  32. }
  33. bool contains_non_trailing_space(const char *str)
  34. {
  35. if (const char *p = strstr(str, " "))
  36. {
  37. while (*p == ' ')
  38. p++;
  39. return *p != '\0';
  40. }
  41. return false;
  42. }
  43. bool is_number_only(const char *s)
  44. {
  45. if (!s || *s == 0 || *s == ' ')
  46. return 0;
  47. char *p;
  48. strtod(s, &p);
  49. while (*p == ' ')
  50. p++;
  51. return *p == '\0';
  52. }
  53. bool is_number_float(const char *str)
  54. {
  55. while (*str) if (*str++ == '.') return true;
  56. return false;
  57. }
  58. // == TBValueArray ==================================
  59. TBValueArray::TBValueArray()
  60. {
  61. }
  62. TBValueArray::~TBValueArray()
  63. {
  64. }
  65. TBValue *TBValueArray::AddValue()
  66. {
  67. TBValue *v;
  68. if ((v = new TBValue()) && m_list.Add(v))
  69. return v;
  70. delete v;
  71. return nullptr;
  72. }
  73. TBValue *TBValueArray::GetValue(int index)
  74. {
  75. if (index >= 0 && index < m_list.GetNumItems())
  76. return m_list[index];
  77. return nullptr;
  78. }
  79. TBValueArray *TBValueArray::Clone(TBValueArray *source)
  80. {
  81. TBValueArray *new_arr = new TBValueArray;
  82. if (!new_arr)
  83. return nullptr;
  84. for (int i = 0; i < source->m_list.GetNumItems(); i++)
  85. {
  86. TBValue *new_val = new_arr->AddValue();
  87. if (!new_val)
  88. {
  89. delete new_arr;
  90. return nullptr;
  91. }
  92. new_val->Copy(*source->GetValue(i));
  93. }
  94. return new_arr;
  95. }
  96. // == TBValue =======================================
  97. TBValue::TBValue()
  98. : m_packed_init(0)
  99. {
  100. }
  101. TBValue::TBValue(const TBValue &value)
  102. : m_packed_init(0)
  103. {
  104. Copy(value);
  105. }
  106. TBValue::TBValue(TYPE type)
  107. : m_packed_init(0)
  108. {
  109. switch (type)
  110. {
  111. case TYPE_NULL:
  112. SetNull();
  113. break;
  114. case TYPE_STRING:
  115. SetString("", SET_AS_STATIC);
  116. break;
  117. case TYPE_FLOAT:
  118. SetFloat(0);
  119. break;
  120. case TYPE_INT:
  121. SetInt(0);
  122. break;
  123. case TYPE_OBJECT:
  124. SetObject(nullptr);
  125. break;
  126. case TYPE_ARRAY:
  127. if (TBValueArray *arr = new TBValueArray())
  128. SetArray(arr, SET_TAKE_OWNERSHIP);
  129. break;
  130. default:
  131. assert(!"Not implemented!");
  132. };
  133. }
  134. TBValue::TBValue(int value)
  135. : m_packed_init(0)
  136. {
  137. SetInt(value);
  138. }
  139. TBValue::TBValue(float value)
  140. : m_packed_init(0)
  141. {
  142. SetFloat(value);
  143. }
  144. TBValue::TBValue(const char *value, SET set)
  145. : m_packed_init(0)
  146. {
  147. SetString(value, set);
  148. }
  149. TBValue::TBValue(TBTypedObject *object)
  150. : m_packed_init(0)
  151. {
  152. SetObject(object);
  153. }
  154. TBValue::~TBValue()
  155. {
  156. SetNull();
  157. }
  158. void TBValue::TakeOver(TBValue &source_value)
  159. {
  160. if (source_value.m_packed.type == TYPE_STRING)
  161. SetString(source_value.val_str, source_value.m_packed.allocated ? SET_TAKE_OWNERSHIP : SET_NEW_COPY);
  162. else if (source_value.m_packed.type == TYPE_ARRAY)
  163. SetArray(source_value.val_arr, source_value.m_packed.allocated ? SET_TAKE_OWNERSHIP : SET_NEW_COPY);
  164. else
  165. *this = source_value;
  166. source_value.m_packed.type = TYPE_NULL;
  167. }
  168. void TBValue::Copy(const TBValue &source_value)
  169. {
  170. if (source_value.m_packed.type == TYPE_STRING)
  171. SetString(source_value.val_str, SET_NEW_COPY);
  172. else if (source_value.m_packed.type == TYPE_ARRAY)
  173. SetArray(source_value.val_arr, SET_NEW_COPY);
  174. else if (source_value.m_packed.type == TYPE_OBJECT)
  175. {
  176. assert(!"We can't copy objects! The value will be nulled!");
  177. SetObject(nullptr);
  178. }
  179. else
  180. {
  181. SetNull();
  182. memcpy(this, &source_value, sizeof(TBValue));
  183. }
  184. }
  185. void TBValue::SetNull()
  186. {
  187. if (m_packed.allocated)
  188. {
  189. if (m_packed.type == TYPE_STRING)
  190. free(val_str);
  191. else if (m_packed.type == TYPE_OBJECT)
  192. delete val_obj;
  193. else if (m_packed.type == TYPE_ARRAY)
  194. delete val_arr;
  195. }
  196. m_packed.type = TYPE_NULL;
  197. }
  198. void TBValue::SetInt(int val)
  199. {
  200. SetNull();
  201. m_packed.type = TYPE_INT;
  202. val_int = val;
  203. }
  204. void TBValue::SetFloat(float val)
  205. {
  206. SetNull();
  207. m_packed.type = TYPE_FLOAT;
  208. val_float = val;
  209. }
  210. void TBValue::SetString(const char *val, SET set)
  211. {
  212. SetNull();
  213. m_packed.allocated = (set == SET_NEW_COPY || set == SET_TAKE_OWNERSHIP);
  214. if (set != SET_NEW_COPY)
  215. {
  216. val_str = const_cast<char *>(val);
  217. m_packed.type = TYPE_STRING;
  218. }
  219. else if ((val_str = strdup(val)))
  220. m_packed.type = TYPE_STRING;
  221. }
  222. void TBValue::SetObject(TBTypedObject *object)
  223. {
  224. SetNull();
  225. m_packed.type = TYPE_OBJECT;
  226. m_packed.allocated = true;
  227. val_obj = object;
  228. }
  229. void TBValue::SetArray(TBValueArray *arr, SET set)
  230. {
  231. SetNull();
  232. m_packed.allocated = (set == SET_NEW_COPY || set == SET_TAKE_OWNERSHIP);
  233. if (set != SET_NEW_COPY)
  234. {
  235. val_arr = arr;
  236. m_packed.type = TYPE_ARRAY;
  237. }
  238. else if ((val_arr = TBValueArray::Clone(arr)))
  239. m_packed.type = TYPE_ARRAY;
  240. }
  241. void TBValue::SetFromStringAuto(const char *str, SET set)
  242. {
  243. if (!str)
  244. SetNull();
  245. else if (is_number_only(str))
  246. {
  247. if (is_number_float(str))
  248. SetFloat((float)atof(str));
  249. else
  250. SetInt(atoi(str));
  251. }
  252. else if (is_start_of_number(str) && contains_non_trailing_space(str))
  253. {
  254. // If the number has nontrailing space, we'll assume a list of numbers (example: "10 -4 3.5")
  255. SetNull();
  256. if (TBValueArray *arr = new TBValueArray)
  257. {
  258. TBStr tmpstr;
  259. if (tmpstr.Set(str))
  260. {
  261. char *str_next = tmpstr.CStr();
  262. while (char *token = next_token(str_next, ", "))
  263. {
  264. if (TBValue *new_val = arr->AddValue())
  265. new_val->SetFromStringAuto(token, SET_NEW_COPY);
  266. }
  267. }
  268. SetArray(arr, SET_TAKE_OWNERSHIP);
  269. }
  270. }
  271. else if (*str == '[')
  272. {
  273. SetNull();
  274. if (TBValueArray *arr = new TBValueArray)
  275. {
  276. assert(!"not implemented! Split out the tokenizer code above!");
  277. SetArray(arr, SET_TAKE_OWNERSHIP);
  278. }
  279. }
  280. else
  281. {
  282. SetString(str, set);
  283. return;
  284. }
  285. // We didn't set as string, so we might need to deal with the passed in string data.
  286. if (set == SET_TAKE_OWNERSHIP)
  287. {
  288. // Delete the passed in data
  289. TBValue tmp;
  290. tmp.SetString(str, SET_TAKE_OWNERSHIP);
  291. }
  292. }
  293. int TBValue::GetInt() const
  294. {
  295. if (m_packed.type == TYPE_STRING)
  296. return atoi(val_str);
  297. else if (m_packed.type == TYPE_FLOAT)
  298. return (int) val_float;
  299. return m_packed.type == TYPE_INT ? val_int : 0;
  300. }
  301. float TBValue::GetFloat() const
  302. {
  303. if (m_packed.type == TYPE_STRING)
  304. return (float) atof(val_str);
  305. else if (m_packed.type == TYPE_INT)
  306. return (float) val_int;
  307. return m_packed.type == TYPE_FLOAT ? val_float : 0;
  308. }
  309. const char *TBValue::GetString()
  310. {
  311. if (m_packed.type == TYPE_INT)
  312. {
  313. char tmp[32];
  314. sprintf(tmp, "%d", val_int);
  315. SetString(tmp, SET_NEW_COPY);
  316. }
  317. else if (m_packed.type == TYPE_FLOAT)
  318. {
  319. char tmp[32];
  320. sprintf(tmp, "%f", val_float);
  321. SetString(tmp, SET_NEW_COPY);
  322. }
  323. else if (m_packed.type == TYPE_OBJECT)
  324. return val_obj ? val_obj->GetClassName() : "";
  325. return m_packed.type == TYPE_STRING ? val_str : "";
  326. }
  327. }; // namespace tb