database.vala 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098
  1. /*
  2. * Copyright (c) 2012-2016 Daniele Bartolini and individual contributors.
  3. * License: https://github.com/taylor001/crown/blob/master/LICENSE-GPLv2
  4. */
  5. using Gee;
  6. namespace Crown
  7. {
  8. public class Database
  9. {
  10. private enum ActionType
  11. {
  12. CREATE,
  13. DESTROY,
  14. SET_PROPERTY,
  15. ADD_TO_SET,
  16. REMOVE_FROM_SET,
  17. RESTORE_POINT
  18. }
  19. private enum ValueType
  20. {
  21. NULL,
  22. BOOL,
  23. DOUBLE,
  24. STRING,
  25. GUID,
  26. VECTOR3,
  27. QUATERNION
  28. }
  29. private struct CreateAction
  30. {
  31. public Guid id;
  32. }
  33. private struct DestroyAction
  34. {
  35. public Guid id;
  36. }
  37. private struct SetPropertyAction
  38. {
  39. public Guid id;
  40. public string key;
  41. public Value? val;
  42. }
  43. private struct AddToSetAction
  44. {
  45. public Guid id;
  46. public string key;
  47. public Guid item_id;
  48. }
  49. private struct RemoveFromSetAction
  50. {
  51. public Guid id;
  52. public string key;
  53. public Guid item_id;
  54. }
  55. private struct RestorePoint
  56. {
  57. public int id;
  58. public uint32 size;
  59. public Guid[] data;
  60. }
  61. private class Stack
  62. {
  63. private uint8[] _data;
  64. private uint32 _read;
  65. public Stack()
  66. {
  67. _data = new uint8[1024*1024];
  68. _read = 0;
  69. }
  70. public void clear()
  71. {
  72. _read = 0;
  73. }
  74. public uint32 size()
  75. {
  76. return _read;
  77. }
  78. public void write_data(void* data, ulong len)
  79. {
  80. uint8* buf = (uint8*)data;
  81. for (ulong i = 0; i < len; ++i, ++_read)
  82. _data[_read] = buf[i];
  83. }
  84. public void write_bool(bool a)
  85. {
  86. write_data(&a, sizeof(bool));
  87. }
  88. public void write_int(int a)
  89. {
  90. write_data(&a, sizeof(int));
  91. }
  92. public void write_uint32(uint32 a)
  93. {
  94. write_data(&a, sizeof(uint32));
  95. }
  96. public void write_double(double a)
  97. {
  98. write_data(&a, sizeof(double));
  99. }
  100. public void write_string(string str)
  101. {
  102. uint32 len = str.length;
  103. write_data(&str.data[0], len);
  104. write_data(&len, sizeof(uint32));
  105. }
  106. public void write_guid(Guid a)
  107. {
  108. write_data(&a, sizeof(Guid));
  109. }
  110. public void write_vector3(Vector3 a)
  111. {
  112. write_data(&a, sizeof(Vector3));
  113. }
  114. public void write_quaternion(Quaternion a)
  115. {
  116. write_data(&a, sizeof(Quaternion));
  117. }
  118. public void write_action_type(ActionType t)
  119. {
  120. write_uint32((uint32)t);
  121. }
  122. public void write_value_type(ValueType t)
  123. {
  124. write_uint32((uint32)t);
  125. }
  126. public ActionType read_action_type()
  127. {
  128. _read -= (uint32)sizeof(uint32);
  129. uint32 a = *(uint32*)(&_data[_read]);
  130. return (ActionType)a;
  131. }
  132. public bool read_bool()
  133. {
  134. _read -= (uint32)sizeof(bool);
  135. bool a = *(bool*)(&_data[_read]);
  136. return a;
  137. }
  138. public int read_int()
  139. {
  140. _read -= (uint32)sizeof(int);
  141. int a = *(int*)(&_data[_read]);
  142. return a;
  143. }
  144. public uint32 read_uint32()
  145. {
  146. _read -= (uint32)sizeof(uint32);
  147. uint32 a = *(uint32*)(&_data[_read]);
  148. return a;
  149. }
  150. public double read_double()
  151. {
  152. _read -= (uint32)sizeof(double);
  153. double a = *(double*)(&_data[_read]);
  154. return a;
  155. }
  156. public Guid read_guid()
  157. {
  158. _read -= (uint32)sizeof(Guid);
  159. Guid a = *(Guid*)(&_data[_read]);
  160. return a;
  161. }
  162. public Vector3 read_vector3()
  163. {
  164. _read -= (uint32)sizeof(Vector3);
  165. Vector3 a = *(Vector3*)(&_data[_read]);
  166. return a;
  167. }
  168. public Quaternion read_quaternion()
  169. {
  170. _read -= (uint32)sizeof(Quaternion);
  171. Quaternion a = *(Quaternion*)(&_data[_read]);
  172. return a;
  173. }
  174. public string read_string()
  175. {
  176. _read -= (uint32)sizeof(uint32);
  177. uint32 len = *(uint32*)(&_data[_read]);
  178. _read -= len;
  179. uint8[] str = new uint8[len + 1];
  180. for (uint32 i = 0; i < len; ++i)
  181. str[i] = *(uint8*)(&_data[_read + i]);
  182. str[len] = '\0';
  183. return (string)str;
  184. }
  185. public ValueType read_value_type()
  186. {
  187. _read -= (uint32)sizeof(uint32);
  188. uint32 a = *(uint32*)(&_data[_read]);
  189. return (ValueType)a;
  190. }
  191. public void write_create_action(Guid id)
  192. {
  193. write_guid(id);
  194. write_action_type(ActionType.CREATE);
  195. }
  196. public void write_destroy_action(Guid id)
  197. {
  198. write_guid(id);
  199. write_action_type(ActionType.DESTROY);
  200. }
  201. public void write_set_property_action(Guid id, string key, Value? val)
  202. {
  203. if (val == null)
  204. {
  205. // Push nothing
  206. write_value_type(ValueType.NULL);
  207. }
  208. else if (val.holds(typeof(bool)))
  209. {
  210. write_bool((bool)val);
  211. write_value_type(ValueType.BOOL);
  212. }
  213. else if (val.holds(typeof(double)))
  214. {
  215. write_double((double)val);
  216. write_value_type(ValueType.DOUBLE);
  217. }
  218. else if (val.holds(typeof(string)))
  219. {
  220. write_string((string)val);
  221. write_value_type(ValueType.STRING);
  222. }
  223. else if (val.holds(typeof(Guid)))
  224. {
  225. write_guid((Guid)val);
  226. write_value_type(ValueType.GUID);
  227. }
  228. else if (val.holds(typeof(Vector3)))
  229. {
  230. write_vector3((Vector3)val);
  231. write_value_type(ValueType.VECTOR3);
  232. }
  233. else if (val.holds(typeof(Quaternion)))
  234. {
  235. write_quaternion((Quaternion)val);
  236. write_value_type(ValueType.QUATERNION);
  237. }
  238. write_string(key);
  239. write_guid(id);
  240. write_action_type(ActionType.SET_PROPERTY);
  241. }
  242. public void write_add_to_set_action(Guid id, string key, Guid item_id)
  243. {
  244. write_guid(item_id);
  245. write_string(key);
  246. write_guid(id);
  247. write_action_type(ActionType.ADD_TO_SET);
  248. }
  249. public void write_remove_from_set_action(Guid id, string key, Guid item_id)
  250. {
  251. write_guid(item_id);
  252. write_string(key);
  253. write_guid(id);
  254. write_action_type(ActionType.REMOVE_FROM_SET);
  255. }
  256. public void write_restore_point(int id, uint32 size, Guid[] data)
  257. {
  258. uint32 num_guids = data.length;
  259. for (uint32 i = 0; i < num_guids; ++i)
  260. write_guid(data[i]);
  261. write_uint32(num_guids);
  262. write_uint32(size);
  263. write_int(id);
  264. write_action_type(ActionType.RESTORE_POINT);
  265. }
  266. public uint32 peek_type()
  267. {
  268. return *(uint32*)(&_data[_read - (uint32)sizeof(uint32)]);
  269. }
  270. public CreateAction read_create_action()
  271. {
  272. ActionType t = read_action_type();
  273. assert(t == ActionType.CREATE);
  274. return { read_guid() };
  275. }
  276. public DestroyAction read_destroy_action()
  277. {
  278. ActionType t = read_action_type();
  279. assert(t == ActionType.DESTROY);
  280. return { read_guid() };
  281. }
  282. public SetPropertyAction read_set_property_action()
  283. {
  284. ActionType t = read_action_type();
  285. assert(t == ActionType.SET_PROPERTY);
  286. Guid id = read_guid();
  287. string key = read_string();
  288. ValueType type = read_value_type();
  289. Value? val = null;
  290. if (type == ValueType.NULL)
  291. {
  292. // Pop nothing
  293. }
  294. else if (type == ValueType.BOOL)
  295. val = read_bool();
  296. else if (type == ValueType.DOUBLE)
  297. val = read_double();
  298. else if (type == ValueType.STRING)
  299. val = read_string();
  300. else if (type == ValueType.GUID)
  301. val = read_guid();
  302. else if (type == ValueType.VECTOR3)
  303. val = read_vector3();
  304. else if (type == ValueType.QUATERNION)
  305. val = read_quaternion();
  306. else
  307. assert(false);
  308. return { id, key, val };
  309. }
  310. public AddToSetAction read_add_to_set_action()
  311. {
  312. ActionType t = read_action_type();
  313. assert(t == ActionType.ADD_TO_SET);
  314. return { read_guid(), read_string(), read_guid() };
  315. }
  316. public RemoveFromSetAction read_remove_from_set_action()
  317. {
  318. ActionType t = read_action_type();
  319. assert(t == ActionType.REMOVE_FROM_SET);
  320. return { read_guid(), read_string(), read_guid() };
  321. }
  322. public RestorePoint read_restore_point()
  323. {
  324. ActionType t = read_action_type();
  325. assert(t == ActionType.RESTORE_POINT);
  326. int id = read_int();
  327. uint32 size = read_uint32();
  328. uint32 num_guids = read_uint32();
  329. Guid[] ids = new Guid[num_guids];
  330. for (uint32 i = 0; i < num_guids; ++i)
  331. ids[i] = read_guid();
  332. return { id, size, ids };
  333. }
  334. }
  335. // Data
  336. private HashMap<string, Value?> _data;
  337. private Stack _undo;
  338. private Stack _redo;
  339. private Stack _undo_points;
  340. private Stack _redo_points;
  341. private bool _changed;
  342. // Signals
  343. public signal void key_changed(Guid id, string key);
  344. public signal void undo_redo(bool undo, int id, Guid[] data);
  345. public Database()
  346. {
  347. _data = new HashMap<string, Value?>();
  348. _undo = new Stack();
  349. _redo = new Stack();
  350. _undo_points = new Stack();
  351. _redo_points = new Stack();
  352. reset();
  353. }
  354. /// <summary>
  355. /// Resets database to clean state.
  356. /// </summary>
  357. public void reset()
  358. {
  359. _data.clear();
  360. _undo.clear();
  361. _redo.clear();
  362. _undo_points.clear();
  363. _redo_points.clear();
  364. _changed = false;
  365. // This is a special field which stores all objects
  366. _data.set("_objects", new HashMap<string, Value?>());
  367. }
  368. /// <summary>
  369. /// Returns whether the database has been changed since last call to Save().
  370. /// </summary>
  371. public bool changed()
  372. {
  373. return _changed;
  374. }
  375. /// <summary>
  376. /// Saves database to path.
  377. /// </summary>
  378. public void save(string path)
  379. {
  380. Hashtable json = encode();
  381. SJSON.save(json, path);
  382. _changed = false;
  383. }
  384. /// <summary>
  385. /// Loads database from path.
  386. /// </summary>
  387. public void load(string path)
  388. {
  389. Hashtable json = SJSON.load(path);
  390. decode(json);
  391. _changed = false;
  392. }
  393. private Hashtable encode()
  394. {
  395. return encode_object(_data);
  396. }
  397. private static bool is_valid_value(Value? value)
  398. {
  399. return value == null
  400. || value.holds(typeof(bool))
  401. || value.holds(typeof(double))
  402. || value.holds(typeof(string))
  403. || value.holds(typeof(Guid))
  404. || value.holds(typeof(Vector3))
  405. || value.holds(typeof(Quaternion))
  406. ;
  407. }
  408. private static bool is_valid_key(string key)
  409. {
  410. return key.length > 0
  411. && key != "_objects"
  412. && !key.has_prefix(".")
  413. && !key.has_suffix(".")
  414. ;
  415. }
  416. private static string value_to_string(Value? value)
  417. {
  418. if (value == null)
  419. return "null";
  420. if (value.holds(typeof(bool)))
  421. return ((bool)value).to_string();
  422. if (value.holds(typeof(double)))
  423. return ((double)value).to_string();
  424. if (value.holds(typeof(string)))
  425. return ((string)value).to_string();
  426. if (value.holds(typeof(Guid)))
  427. return ((Guid)value).to_string();
  428. if (value.holds(typeof(Vector3)))
  429. return ((Vector3)value).to_string();
  430. if (value.holds(typeof(Quaternion)))
  431. return ((Quaternion)value).to_string();
  432. if (value.holds(typeof(HashSet<Guid?>)))
  433. return "Set<Guid>";
  434. return "<invalid>";
  435. }
  436. private void decode(Hashtable json)
  437. {
  438. reset();
  439. decode_root_object(json);
  440. }
  441. private void decode_root_object(Hashtable json)
  442. {
  443. decode_object(GUID_ZERO, "", json);
  444. }
  445. private void decode_object(Guid id, string db_key, Hashtable json)
  446. {
  447. string old_db = db_key;
  448. string k = db_key;
  449. string[] keys = json.keys.to_array();
  450. foreach (string key in keys)
  451. {
  452. assert(key != "_objects");
  453. Value? val = json[key];
  454. k += k == "" ? key : ("." + key);
  455. if (val.holds(typeof(Hashtable)))
  456. {
  457. Hashtable ht = (Hashtable)val;
  458. if (is_set(ht))
  459. decode_set(id, key, ht);
  460. else
  461. decode_object(id, k, ht);
  462. }
  463. else
  464. {
  465. set_property_internal(id, k, decode_value(val));
  466. }
  467. k = old_db;
  468. }
  469. }
  470. private bool is_set(Hashtable json)
  471. {
  472. string[] keys = json.keys.to_array();
  473. foreach (string k in keys)
  474. {
  475. Guid guid;
  476. if (!Guid.try_parse(k, out guid))
  477. return false;
  478. }
  479. return true;
  480. }
  481. private void decode_set(Guid id, string key, Hashtable json)
  482. {
  483. create_empty_set(id, key);
  484. string[] keys = json.keys.to_array();
  485. foreach (string k in keys)
  486. {
  487. Guid item_id = Guid.parse(k);
  488. create_internal(item_id);
  489. decode_object(item_id, "", (Hashtable)json[k]);
  490. add_to_set_internal(id, key, item_id);
  491. }
  492. }
  493. private Value? decode_value(Value? value)
  494. {
  495. if (value.holds(typeof(ArrayList<Value?>)))
  496. {
  497. ArrayList<Value?> al = (ArrayList<Value?>)value;
  498. if (al.size == 3)
  499. return Vector3((double)al[0], (double)al[1], (double)al[2]);
  500. else if (al.size == 4)
  501. return Quaternion((double)al[0], (double)al[1], (double)al[2], (double)al[3]);
  502. else
  503. assert(false);
  504. }
  505. else if (value.holds(typeof(string)))
  506. {
  507. Guid id;
  508. if (Guid.try_parse((string)value, out id))
  509. return id;
  510. return value;
  511. }
  512. else if (value == null || value.holds(typeof(bool)) || value.holds(typeof(double)))
  513. {
  514. return value;
  515. }
  516. else
  517. {
  518. assert(false);
  519. }
  520. return null;
  521. }
  522. private Hashtable encode_object(HashMap<string, Value?> db)
  523. {
  524. Hashtable obj = new Hashtable();
  525. string[] keys = db.keys.to_array();
  526. foreach (string key in keys)
  527. {
  528. if (key == "_objects")
  529. continue;
  530. string[] foo = key.split(".");
  531. Hashtable x = obj;
  532. if (foo.length > 1)
  533. {
  534. for (int i = 0; i < foo.length - 1; ++i)
  535. {
  536. string f = foo[i];
  537. if (x.has_key(f))
  538. {
  539. x = (Hashtable)x[f];
  540. continue;
  541. }
  542. Hashtable y = new Hashtable();
  543. x.set(f, y);
  544. x = y;
  545. }
  546. }
  547. x.set(foo[foo.length-1], encode_value(db[key]));
  548. }
  549. return obj;
  550. }
  551. private Value? encode_value(Value? value)
  552. {
  553. assert(is_valid_value(value) || value.holds(typeof(HashSet<Guid?>)));
  554. if (value.holds(typeof(Vector3)))
  555. {
  556. Vector3 v = (Vector3)value;
  557. ArrayList<Value?> arr = new Gee.ArrayList<Value?>();
  558. arr.add(v.x);
  559. arr.add(v.y);
  560. arr.add(v.z);
  561. return arr;
  562. }
  563. else if (value.holds(typeof(Quaternion)))
  564. {
  565. Quaternion q = (Quaternion)value;
  566. ArrayList<Value?> arr = new Gee.ArrayList<Value?>();
  567. arr.add(q.x);
  568. arr.add(q.y);
  569. arr.add(q.z);
  570. arr.add(q.w);
  571. return arr;
  572. }
  573. else if (value.holds(typeof(Guid)))
  574. {
  575. Guid id = (Guid)value;
  576. return "\"%s\"".printf(id.to_string());
  577. }
  578. else if (value.holds(typeof(HashSet<Guid?>)))
  579. {
  580. HashSet<Guid?> hs = (HashSet<Guid?>)value;
  581. Hashtable ht = new Hashtable();
  582. foreach (Guid id in hs)
  583. {
  584. HashMap<string, Value?> objs = (HashMap<string, Value?>)_data["_objects"];
  585. ht.set(id.to_string(), encode_object((HashMap<string, Value?>)objs[id.to_string()]));
  586. }
  587. return ht;
  588. }
  589. else
  590. {
  591. return value;
  592. }
  593. }
  594. private HashMap<string, Value?> get_data(Guid id)
  595. {
  596. assert(has_object(id));
  597. return (HashMap<string, Value?>)(id == GUID_ZERO ? _data : (_data["_objects"] as HashMap<string, Value?>)[id.to_string()]);
  598. }
  599. private void create_internal(Guid id)
  600. {
  601. assert(id != GUID_ZERO);
  602. #if CROWN_DEBUG
  603. stdout.printf("create %s\n", id.to_string());
  604. #endif // CROWN_DEBUG
  605. (_data["_objects"] as HashMap<string, Value?>).set(id.to_string(), new HashMap<string, Value?>());
  606. _changed = true;
  607. key_changed(id, "_objects");
  608. }
  609. private void destroy_internal(Guid id)
  610. {
  611. assert(id != GUID_ZERO);
  612. assert(has_object(id));
  613. #if CROWN_DEBUG
  614. stdout.printf("destroy %s\n", id.to_string());
  615. #endif // CROWN_DEBUG
  616. (_data["_objects"] as HashMap<string, Value?>).unset(id.to_string());
  617. _changed = true;
  618. key_changed(id, "_objects");
  619. }
  620. private void set_property_internal(Guid id, string key, Value? value)
  621. {
  622. assert(has_object(id));
  623. assert(is_valid_key(key));
  624. assert(is_valid_value(value));
  625. #if CROWN_DEBUG
  626. stdout.printf("set_property %s %s %s\n"
  627. , id.to_string()
  628. , key
  629. , (value == null) ? "null" : value_to_string(value)
  630. );
  631. #endif // CROWN_DEBUG
  632. HashMap<string, Value?> ob = get_data(id);
  633. ob[key] = value;
  634. _changed = true;
  635. key_changed(id, key);
  636. }
  637. private void create_empty_set(Guid id, string key)
  638. {
  639. assert(has_object(id));
  640. assert(is_valid_key(key));
  641. HashMap<string, Value?> ob = get_data(id);
  642. assert(!ob.has_key(key));
  643. ob[key] = new HashSet<Guid?>(Guid.hash_func, Guid.equal_func);
  644. }
  645. private void add_to_set_internal(Guid id, string key, Guid item_id)
  646. {
  647. assert(has_object(id));
  648. assert(is_valid_key(key));
  649. assert(item_id != GUID_ZERO);
  650. assert(has_object(item_id));
  651. #if CROWN_DEBUG
  652. stdout.printf("add_to_set %s %s %s\n"
  653. , id.to_string()
  654. , key
  655. , item_id.to_string()
  656. );
  657. #endif // CROWN_DEBUG
  658. HashMap<string, Value?> ob = get_data(id);
  659. if (!ob.has_key(key))
  660. {
  661. HashSet<Guid?> hs = new HashSet<Guid?>(Guid.hash_func, Guid.equal_func);
  662. hs.add(item_id);
  663. ob[key] = hs;
  664. }
  665. else
  666. {
  667. (ob[key] as HashSet<Guid?>).add(item_id);
  668. }
  669. _changed = true;
  670. key_changed(id, key);
  671. }
  672. private void remove_from_set_internal(Guid id, string key, Guid item_id)
  673. {
  674. assert(has_object(id));
  675. assert(is_valid_key(key));
  676. assert(item_id != GUID_ZERO);
  677. #if CROWN_DEBUG
  678. stdout.printf("remove_from_set %s %s %s\n"
  679. , id.to_string()
  680. , key
  681. , item_id.to_string()
  682. );
  683. #endif // CROWN_DEBUG
  684. HashMap<string, Value?> ob = get_data(id);
  685. (ob[key] as HashSet<Guid?>).remove(item_id);
  686. _changed = true;
  687. key_changed(id, key);
  688. }
  689. public void create(Guid id)
  690. {
  691. assert(id != GUID_ZERO);
  692. assert(!has_object(id));
  693. _undo.write_destroy_action(id);
  694. _redo.clear();
  695. create_internal(id);
  696. }
  697. public void destroy(Guid id)
  698. {
  699. assert(id != GUID_ZERO);
  700. assert(has_object(id));
  701. HashMap<string, Value?> o = get_data(id);
  702. string[] keys = o.keys.to_array();
  703. foreach (string key in keys)
  704. {
  705. Value? value = o[key];
  706. if (value.holds(typeof(HashSet<Guid?>)))
  707. {
  708. HashSet<Guid?> hs = (HashSet<Guid?>)value;
  709. Guid?[] ids = hs.to_array();
  710. foreach (Guid item_id in ids)
  711. {
  712. remove_from_set(id, key, item_id);
  713. destroy(item_id);
  714. }
  715. }
  716. else
  717. {
  718. set_property(id, key, null);
  719. }
  720. }
  721. _undo.write_create_action(id);
  722. _redo.clear();
  723. destroy_internal(id);
  724. }
  725. public void set_property(Guid id, string key, Value? value)
  726. {
  727. assert(has_object(id));
  728. assert(is_valid_key(key));
  729. assert(is_valid_value(value));
  730. HashMap<string, Value?> ob = get_data(id);
  731. _undo.write_set_property_action(id, key, ob.has_key(key) ? ob[key] : null);
  732. _redo.clear();
  733. set_property_internal(id, key, value);
  734. }
  735. public void add_to_set(Guid id, string key, Guid item_id)
  736. {
  737. assert(has_object(id));
  738. assert(is_valid_key(key));
  739. assert(item_id != GUID_ZERO);
  740. assert(has_object(item_id));
  741. _undo.write_remove_from_set_action(id, key, item_id);
  742. _redo.clear();
  743. add_to_set_internal(id, key, item_id);
  744. }
  745. public void remove_from_set(Guid id, string key, Guid item_id)
  746. {
  747. assert(has_object(id));
  748. assert(is_valid_key(key));
  749. assert(item_id != GUID_ZERO);
  750. _undo.write_add_to_set_action(id, key, item_id);
  751. _redo.clear();
  752. remove_from_set_internal(id, key, item_id);
  753. }
  754. public bool has_object(Guid id)
  755. {
  756. bool contains = (_data["_objects"] as HashMap<string, Value?>).has_key(id.to_string());
  757. return id == GUID_ZERO || contains;
  758. }
  759. public bool has_property(Guid id, string key)
  760. {
  761. assert(has_object(id));
  762. assert(is_valid_key(key));
  763. return get_data(id).has_key(key);
  764. }
  765. public Value? get_property(Guid id, string key)
  766. {
  767. assert(has_object(id));
  768. assert(is_valid_key(key));
  769. HashMap<string, Value?> ob = get_data(id);
  770. Value? value = (ob.has_key(key) ? ob[key] : null);
  771. #if CROWN_DEBUG
  772. stdout.printf("get_property %s %s %s\n"
  773. , id.to_string()
  774. , key
  775. , (value == null) ? "null" : value_to_string(value)
  776. );
  777. #endif // CROWN_DEBUG
  778. return value;
  779. }
  780. public HashMap<string, Value?> get_object(Guid id)
  781. {
  782. return (HashMap<string, Value?>)get_data(GUID_ZERO)[id.to_string()];
  783. }
  784. public string[] get_keys(Guid id)
  785. {
  786. HashMap<string, Value?> data = get_data(id);
  787. return data.keys.to_array();
  788. }
  789. public void add_restore_point(int id, Guid[] data)
  790. {
  791. #if CROWN_DEBUG
  792. stdout.printf("add_restore_point %d\n", id);
  793. #endif // CROWN_DEBUG
  794. _undo_points.write_restore_point(id, _undo.size(), data);
  795. }
  796. /// <summary>
  797. /// Duplicates the object specified by id and assign new_id to the duplicated object.
  798. /// </summary>
  799. public void duplicate(Guid id, Guid new_id)
  800. {
  801. assert(id != GUID_ZERO);
  802. assert(new_id != GUID_ZERO);
  803. assert(id != new_id);
  804. assert(has_object(id));
  805. create(new_id);
  806. HashMap<string, Value?> o = get_data(id);
  807. string[] keys = o.keys.to_array();
  808. foreach (string key in keys)
  809. {
  810. Value? val = o[key];
  811. if (val.holds(typeof(HashSet<Guid?>)))
  812. {
  813. HashSet<Guid?> hs = (HashSet<Guid?>)val;
  814. foreach (Guid j in hs)
  815. {
  816. Guid x = Guid.new_guid();
  817. duplicate(j, x);
  818. add_to_set(new_id, key, x);
  819. }
  820. }
  821. else
  822. {
  823. set_property(new_id, key, o[key]);
  824. }
  825. }
  826. }
  827. /// <summary>
  828. /// Copies the database to db under the given new_key.
  829. /// </summary>
  830. public void copy_to(Database db, string new_key)
  831. {
  832. assert(db != null);
  833. assert(is_valid_key(new_key));
  834. copy_deep(db, GUID_ZERO, new_key);
  835. }
  836. public void copy_deep(Database db, Guid id, string new_key)
  837. {
  838. HashMap<string, Value?> o = get_data(id);
  839. string[] keys = o.keys.to_array();
  840. foreach (string key in keys)
  841. {
  842. if (key == "_objects")
  843. continue;
  844. Value? value = o[key];
  845. if (value.holds(typeof(HashSet<Guid?>)))
  846. {
  847. HashSet<Guid?> hs = (HashSet<Guid?>)value;
  848. foreach (Guid j in hs)
  849. {
  850. db.create(j);
  851. copy_deep(db, j, "");
  852. db.add_to_set(id, new_key + (new_key == "" ? "" : ".") + key, j);
  853. }
  854. }
  855. else
  856. {
  857. db.set_property(id, new_key + (new_key == "" ? "" : ".") + key, o[key]);
  858. }
  859. }
  860. }
  861. public void undo()
  862. {
  863. if (_undo_points.size() == 0)
  864. return;
  865. RestorePoint rp = _undo_points.read_restore_point();
  866. _redo_points.write_restore_point(rp.id, _redo.size(), rp.data);
  867. undo_until(rp.size);
  868. undo_redo(true, rp.id, rp.data);
  869. }
  870. public void redo()
  871. {
  872. if (_redo_points.size() == 0)
  873. return;
  874. RestorePoint rp = _redo_points.read_restore_point();
  875. _undo_points.write_restore_point(rp.id, _undo.size(), rp.data);
  876. redo_until(rp.size);
  877. undo_redo(false, rp.id, rp.data);
  878. }
  879. private void undo_until(uint32 size)
  880. {
  881. while (_undo.size() != size)
  882. {
  883. uint32 type = _undo.peek_type();
  884. if (type == ActionType.CREATE)
  885. {
  886. CreateAction a = _undo.read_create_action();
  887. _redo.write_destroy_action(a.id);
  888. create_internal(a.id);
  889. }
  890. else if (type == ActionType.DESTROY)
  891. {
  892. DestroyAction a = _undo.read_destroy_action();
  893. _redo.write_create_action(a.id);
  894. destroy_internal(a.id);
  895. }
  896. else if (type == ActionType.SET_PROPERTY)
  897. {
  898. SetPropertyAction a = _undo.read_set_property_action();
  899. _redo.write_set_property_action(a.id, a.key, get_data(a.id).has_key(a.key) ? get_data(a.id)[a.key] : null);
  900. set_property_internal(a.id, a.key, a.val);
  901. }
  902. else if (type == ActionType.ADD_TO_SET)
  903. {
  904. AddToSetAction a = _undo.read_add_to_set_action();
  905. _redo.write_remove_from_set_action(a.id, a.key, a.item_id);
  906. add_to_set_internal(a.id, a.key, a.item_id);
  907. }
  908. else if (type == ActionType.REMOVE_FROM_SET)
  909. {
  910. RemoveFromSetAction a = _undo.read_remove_from_set_action();
  911. _redo.write_add_to_set_action(a.id, a.key, a.item_id);
  912. remove_from_set_internal(a.id, a.key, a.item_id);
  913. }
  914. }
  915. }
  916. private void redo_until(uint32 size)
  917. {
  918. while (_redo.size() != size)
  919. {
  920. uint32 type = _redo.peek_type();
  921. if (type == ActionType.CREATE)
  922. {
  923. CreateAction a = _redo.read_create_action();
  924. _undo.write_destroy_action(a.id);
  925. create_internal(a.id);
  926. }
  927. else if (type == ActionType.DESTROY)
  928. {
  929. DestroyAction a = _redo.read_destroy_action();
  930. _undo.write_create_action(a.id);
  931. destroy_internal(a.id);
  932. }
  933. else if (type == ActionType.SET_PROPERTY)
  934. {
  935. SetPropertyAction a = _redo.read_set_property_action();
  936. _undo.write_set_property_action(a.id, a.key, get_data(a.id).has_key(a.key) ? get_data(a.id)[a.key] : null);
  937. set_property_internal(a.id, a.key, a.val);
  938. }
  939. else if (type == ActionType.ADD_TO_SET)
  940. {
  941. AddToSetAction a = _redo.read_add_to_set_action();
  942. _undo.write_remove_from_set_action(a.id, a.key, a.item_id);
  943. add_to_set_internal(a.id, a.key, a.item_id);
  944. }
  945. else if (type == ActionType.REMOVE_FROM_SET)
  946. {
  947. RemoveFromSetAction a = _redo.read_remove_from_set_action();
  948. _undo.write_add_to_set_action(a.id, a.key, a.item_id);
  949. remove_from_set_internal(a.id, a.key, a.item_id);
  950. }
  951. }
  952. }
  953. }
  954. }