database.vala 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097
  1. /*
  2. * Copyright (c) 2012-2017 Daniele Bartolini and individual contributors.
  3. * License: https://github.com/dbartolini/crown/blob/master/LICENSE
  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. /// Resets database to clean state.
  355. public void reset()
  356. {
  357. _data.clear();
  358. _undo.clear();
  359. _redo.clear();
  360. _undo_points.clear();
  361. _redo_points.clear();
  362. _changed = false;
  363. // This is a special field which stores all objects
  364. _data.set("_objects", new HashMap<string, Value?>());
  365. }
  366. /// Returns whether the database has been changed since last call to Save().
  367. public bool changed()
  368. {
  369. return _changed;
  370. }
  371. /// Marks the database as changed without modifiying any data.
  372. public void touch()
  373. {
  374. _changed = true;
  375. }
  376. /// Saves database to path.
  377. public void save(string path)
  378. {
  379. Hashtable json = encode();
  380. SJSON.save(json, path);
  381. _changed = false;
  382. }
  383. /// Loads database from path.
  384. public void load(string path)
  385. {
  386. Hashtable json = SJSON.load(path);
  387. decode(json);
  388. _changed = false;
  389. }
  390. private Hashtable encode()
  391. {
  392. return encode_object(_data);
  393. }
  394. private static bool is_valid_value(Value? value)
  395. {
  396. return value == null
  397. || value.holds(typeof(bool))
  398. || value.holds(typeof(double))
  399. || value.holds(typeof(string))
  400. || value.holds(typeof(Guid))
  401. || value.holds(typeof(Vector3))
  402. || value.holds(typeof(Quaternion))
  403. ;
  404. }
  405. private static bool is_valid_key(string key)
  406. {
  407. return key.length > 0
  408. && key != "_objects"
  409. && !key.has_prefix(".")
  410. && !key.has_suffix(".")
  411. ;
  412. }
  413. #if 0
  414. private static string value_to_string(Value? value)
  415. {
  416. if (value == null)
  417. return "null";
  418. if (value.holds(typeof(bool)))
  419. return ((bool)value).to_string();
  420. if (value.holds(typeof(double)))
  421. return ((double)value).to_string();
  422. if (value.holds(typeof(string)))
  423. return ((string)value).to_string();
  424. if (value.holds(typeof(Guid)))
  425. return ((Guid)value).to_string();
  426. if (value.holds(typeof(Vector3)))
  427. return ((Vector3)value).to_string();
  428. if (value.holds(typeof(Quaternion)))
  429. return ((Quaternion)value).to_string();
  430. if (value.holds(typeof(HashSet)))
  431. return "Set<Guid>";
  432. return "<invalid>";
  433. }
  434. #endif // CROWN_DEBUG
  435. private void decode(Hashtable json)
  436. {
  437. reset();
  438. decode_root_object(json);
  439. }
  440. private void decode_root_object(Hashtable json)
  441. {
  442. decode_object(GUID_ZERO, "", json);
  443. }
  444. private void decode_object(Guid id, string db_key, Hashtable json)
  445. {
  446. string old_db = db_key;
  447. string k = db_key;
  448. string[] keys = json.keys.to_array();
  449. foreach (string key in keys)
  450. {
  451. assert(key != "_objects");
  452. Value? val = json[key];
  453. k += k == "" ? key : ("." + key);
  454. if (val.holds(typeof(Hashtable)))
  455. {
  456. Hashtable ht = (Hashtable)val;
  457. if (is_set(ht))
  458. decode_set(id, key, ht);
  459. else
  460. decode_object(id, k, ht);
  461. }
  462. else
  463. {
  464. set_property_internal(id, k, decode_value(val));
  465. }
  466. k = old_db;
  467. }
  468. }
  469. private bool is_set(Hashtable json)
  470. {
  471. string[] keys = json.keys.to_array();
  472. foreach (string k in keys)
  473. {
  474. Guid guid;
  475. if (!Guid.try_parse(k, out guid))
  476. return false;
  477. }
  478. return true;
  479. }
  480. private void decode_set(Guid id, string key, Hashtable json)
  481. {
  482. create_empty_set(id, key);
  483. string[] keys = json.keys.to_array();
  484. foreach (string k in keys)
  485. {
  486. Guid item_id = Guid.parse(k);
  487. create_internal(item_id);
  488. decode_object(item_id, "", (Hashtable)json[k]);
  489. add_to_set_internal(id, key, item_id);
  490. }
  491. }
  492. private Value? decode_value(Value? value)
  493. {
  494. if (value.holds(typeof(ArrayList)))
  495. {
  496. ArrayList<Value?> al = (ArrayList<Value?>)value;
  497. if (al.size == 3)
  498. return Vector3((double)al[0], (double)al[1], (double)al[2]);
  499. else if (al.size == 4)
  500. return Quaternion((double)al[0], (double)al[1], (double)al[2], (double)al[3]);
  501. else
  502. assert(false);
  503. }
  504. else if (value.holds(typeof(string)))
  505. {
  506. Guid id;
  507. if (Guid.try_parse((string)value, out id))
  508. return id;
  509. return value;
  510. }
  511. else if (value == null || value.holds(typeof(bool)) || value.holds(typeof(double)))
  512. {
  513. return value;
  514. }
  515. else
  516. {
  517. assert(false);
  518. }
  519. return null;
  520. }
  521. private Hashtable encode_object(HashMap<string, Value?> db)
  522. {
  523. Hashtable obj = new Hashtable();
  524. string[] keys = db.keys.to_array();
  525. foreach (string key in keys)
  526. {
  527. if (key == "_objects")
  528. continue;
  529. string[] foo = key.split(".");
  530. Hashtable x = obj;
  531. if (foo.length > 1)
  532. {
  533. for (int i = 0; i < foo.length - 1; ++i)
  534. {
  535. string f = foo[i];
  536. if (x.has_key(f))
  537. {
  538. x = (Hashtable)x[f];
  539. continue;
  540. }
  541. Hashtable y = new Hashtable();
  542. x.set(f, y);
  543. x = y;
  544. }
  545. }
  546. x.set(foo[foo.length-1], encode_value(db[key]));
  547. }
  548. return obj;
  549. }
  550. private Value? encode_value(Value? value)
  551. {
  552. assert(is_valid_value(value) || value.holds(typeof(HashSet)));
  553. if (value.holds(typeof(Vector3)))
  554. {
  555. Vector3 v = (Vector3)value;
  556. ArrayList<Value?> arr = new Gee.ArrayList<Value?>();
  557. arr.add(v.x);
  558. arr.add(v.y);
  559. arr.add(v.z);
  560. return arr;
  561. }
  562. else if (value.holds(typeof(Quaternion)))
  563. {
  564. Quaternion q = (Quaternion)value;
  565. ArrayList<Value?> arr = new Gee.ArrayList<Value?>();
  566. arr.add(q.x);
  567. arr.add(q.y);
  568. arr.add(q.z);
  569. arr.add(q.w);
  570. return arr;
  571. }
  572. else if (value.holds(typeof(Guid)))
  573. {
  574. Guid id = (Guid)value;
  575. return "\"%s\"".printf(id.to_string());
  576. }
  577. else if (value.holds(typeof(HashSet)))
  578. {
  579. HashSet<Guid?> hs = (HashSet<Guid?>)value;
  580. Hashtable ht = new Hashtable();
  581. foreach (Guid id in hs)
  582. {
  583. HashMap<string, Value?> objs = (HashMap<string, Value?>)_data["_objects"];
  584. ht.set(id.to_string(), encode_object((HashMap<string, Value?>)objs[id.to_string()]));
  585. }
  586. return ht;
  587. }
  588. else
  589. {
  590. return value;
  591. }
  592. }
  593. private HashMap<string, Value?> get_data(Guid id)
  594. {
  595. assert(has_object(id));
  596. return (HashMap<string, Value?>)(id == GUID_ZERO ? _data : (_data["_objects"] as HashMap<string, Value?>)[id.to_string()]);
  597. }
  598. private void create_internal(Guid id)
  599. {
  600. assert(id != GUID_ZERO);
  601. #if 0
  602. stdout.printf("create %s\n", id.to_string());
  603. #endif // CROWN_DEBUG
  604. (_data["_objects"] as HashMap<string, Value?>).set(id.to_string(), new HashMap<string, Value?>());
  605. _changed = true;
  606. key_changed(id, "_objects");
  607. }
  608. private void destroy_internal(Guid id)
  609. {
  610. assert(id != GUID_ZERO);
  611. assert(has_object(id));
  612. #if 0
  613. stdout.printf("destroy %s\n", id.to_string());
  614. #endif // CROWN_DEBUG
  615. (_data["_objects"] as HashMap<string, Value?>).unset(id.to_string());
  616. _changed = true;
  617. key_changed(id, "_objects");
  618. }
  619. private void set_property_internal(Guid id, string key, Value? value)
  620. {
  621. assert(has_object(id));
  622. assert(is_valid_key(key));
  623. assert(is_valid_value(value));
  624. #if 0
  625. stdout.printf("set_property %s %s %s\n"
  626. , id.to_string()
  627. , key
  628. , (value == null) ? "null" : value_to_string(value)
  629. );
  630. #endif // CROWN_DEBUG
  631. HashMap<string, Value?> ob = get_data(id);
  632. ob[key] = value;
  633. _changed = true;
  634. key_changed(id, key);
  635. }
  636. private void create_empty_set(Guid id, string key)
  637. {
  638. assert(has_object(id));
  639. assert(is_valid_key(key));
  640. HashMap<string, Value?> ob = get_data(id);
  641. assert(!ob.has_key(key));
  642. ob[key] = new HashSet<Guid?>(Guid.hash_func, Guid.equal_func);
  643. }
  644. private void add_to_set_internal(Guid id, string key, Guid item_id)
  645. {
  646. assert(has_object(id));
  647. assert(is_valid_key(key));
  648. assert(item_id != GUID_ZERO);
  649. assert(has_object(item_id));
  650. #if 0
  651. stdout.printf("add_to_set %s %s %s\n"
  652. , id.to_string()
  653. , key
  654. , item_id.to_string()
  655. );
  656. #endif // CROWN_DEBUG
  657. HashMap<string, Value?> ob = get_data(id);
  658. if (!ob.has_key(key))
  659. {
  660. HashSet<Guid?> hs = new HashSet<Guid?>(Guid.hash_func, Guid.equal_func);
  661. hs.add(item_id);
  662. ob[key] = hs;
  663. }
  664. else
  665. {
  666. (ob[key] as HashSet<Guid?>).add(item_id);
  667. }
  668. _changed = true;
  669. key_changed(id, key);
  670. }
  671. private void remove_from_set_internal(Guid id, string key, Guid item_id)
  672. {
  673. assert(has_object(id));
  674. assert(is_valid_key(key));
  675. assert(item_id != GUID_ZERO);
  676. #if 0
  677. stdout.printf("remove_from_set %s %s %s\n"
  678. , id.to_string()
  679. , key
  680. , item_id.to_string()
  681. );
  682. #endif // CROWN_DEBUG
  683. HashMap<string, Value?> ob = get_data(id);
  684. (ob[key] as HashSet<Guid?>).remove(item_id);
  685. _changed = true;
  686. key_changed(id, key);
  687. }
  688. public void create(Guid id)
  689. {
  690. assert(id != GUID_ZERO);
  691. assert(!has_object(id));
  692. _undo.write_destroy_action(id);
  693. _redo.clear();
  694. create_internal(id);
  695. }
  696. public void destroy(Guid id)
  697. {
  698. assert(id != GUID_ZERO);
  699. assert(has_object(id));
  700. HashMap<string, Value?> o = get_data(id);
  701. string[] keys = o.keys.to_array();
  702. foreach (string key in keys)
  703. {
  704. Value? value = o[key];
  705. if (value.holds(typeof(HashSet)))
  706. {
  707. HashSet<Guid?> hs = (HashSet<Guid?>)value;
  708. Guid?[] ids = hs.to_array();
  709. foreach (Guid item_id in ids)
  710. {
  711. remove_from_set(id, key, item_id);
  712. destroy(item_id);
  713. }
  714. }
  715. else
  716. {
  717. set_property(id, key, null);
  718. }
  719. }
  720. _undo.write_create_action(id);
  721. _redo.clear();
  722. destroy_internal(id);
  723. }
  724. public void set_property(Guid id, string key, Value? value)
  725. {
  726. assert(has_object(id));
  727. assert(is_valid_key(key));
  728. assert(is_valid_value(value));
  729. HashMap<string, Value?> ob = get_data(id);
  730. _undo.write_set_property_action(id, key, ob.has_key(key) ? ob[key] : null);
  731. _redo.clear();
  732. set_property_internal(id, key, value);
  733. }
  734. public void add_to_set(Guid id, string key, Guid item_id)
  735. {
  736. assert(has_object(id));
  737. assert(is_valid_key(key));
  738. assert(item_id != GUID_ZERO);
  739. assert(has_object(item_id));
  740. _undo.write_remove_from_set_action(id, key, item_id);
  741. _redo.clear();
  742. add_to_set_internal(id, key, item_id);
  743. }
  744. public void remove_from_set(Guid id, string key, Guid item_id)
  745. {
  746. assert(has_object(id));
  747. assert(is_valid_key(key));
  748. assert(item_id != GUID_ZERO);
  749. _undo.write_add_to_set_action(id, key, item_id);
  750. _redo.clear();
  751. remove_from_set_internal(id, key, item_id);
  752. }
  753. public bool has_object(Guid id)
  754. {
  755. bool contains = (_data["_objects"] as HashMap<string, Value?>).has_key(id.to_string());
  756. return id == GUID_ZERO || contains;
  757. }
  758. public bool has_property(Guid id, string key)
  759. {
  760. assert(has_object(id));
  761. assert(is_valid_key(key));
  762. return get_data(id).has_key(key);
  763. }
  764. public Value? get_property(Guid id, string key)
  765. {
  766. assert(has_object(id));
  767. assert(is_valid_key(key));
  768. HashMap<string, Value?> ob = get_data(id);
  769. Value? value = (ob.has_key(key) ? ob[key] : null);
  770. #if 0
  771. stdout.printf("get_property %s %s %s\n"
  772. , id.to_string()
  773. , key
  774. , (value == null) ? "null" : value_to_string(value)
  775. );
  776. #endif // CROWN_DEBUG
  777. return value;
  778. }
  779. public HashMap<string, Value?> get_object(Guid id)
  780. {
  781. return (HashMap<string, Value?>)get_data(GUID_ZERO)[id.to_string()];
  782. }
  783. public string[] get_keys(Guid id)
  784. {
  785. HashMap<string, Value?> data = get_data(id);
  786. return data.keys.to_array();
  787. }
  788. public void add_restore_point(int id, Guid[] data)
  789. {
  790. #if 0
  791. stdout.printf("add_restore_point %d, undo size = %u\n", id, _undo.size());
  792. #endif // CROWN_DEBUG
  793. _undo_points.write_restore_point(id, _undo.size(), data);
  794. _redo.clear();
  795. _redo_points.clear();
  796. }
  797. /// Duplicates the object specified by id and assign new_id to the duplicated object.
  798. public void duplicate(Guid id, Guid new_id)
  799. {
  800. assert(id != GUID_ZERO);
  801. assert(new_id != GUID_ZERO);
  802. assert(id != new_id);
  803. assert(has_object(id));
  804. create(new_id);
  805. HashMap<string, Value?> o = get_data(id);
  806. string[] keys = o.keys.to_array();
  807. foreach (string key in keys)
  808. {
  809. Value? val = o[key];
  810. if (val.holds(typeof(HashSet)))
  811. {
  812. HashSet<Guid?> hs = (HashSet<Guid?>)val;
  813. foreach (Guid j in hs)
  814. {
  815. Guid x = Guid.new_guid();
  816. duplicate(j, x);
  817. add_to_set(new_id, key, x);
  818. }
  819. }
  820. else
  821. {
  822. set_property(new_id, key, o[key]);
  823. }
  824. }
  825. }
  826. /// Copies the database to db under the given new_key.
  827. public void copy_to(Database db, string new_key)
  828. {
  829. assert(db != null);
  830. assert(is_valid_key(new_key));
  831. copy_deep(db, GUID_ZERO, new_key);
  832. }
  833. public void copy_deep(Database db, Guid id, string new_key)
  834. {
  835. HashMap<string, Value?> o = get_data(id);
  836. string[] keys = o.keys.to_array();
  837. foreach (string key in keys)
  838. {
  839. if (key == "_objects")
  840. continue;
  841. Value? value = o[key];
  842. if (value.holds(typeof(HashSet)))
  843. {
  844. HashSet<Guid?> hs = (HashSet<Guid?>)value;
  845. foreach (Guid j in hs)
  846. {
  847. db.create(j);
  848. copy_deep(db, j, "");
  849. db.add_to_set(id, new_key + (new_key == "" ? "" : ".") + key, j);
  850. }
  851. }
  852. else
  853. {
  854. db.set_property(id, new_key + (new_key == "" ? "" : ".") + key, o[key]);
  855. }
  856. }
  857. }
  858. public void undo()
  859. {
  860. if (_undo_points.size() == 0)
  861. return;
  862. RestorePoint rp = _undo_points.read_restore_point();
  863. _redo_points.write_restore_point(rp.id, _redo.size(), rp.data);
  864. undo_until(rp.size);
  865. undo_redo(true, rp.id, rp.data);
  866. }
  867. public void redo()
  868. {
  869. if (_redo_points.size() == 0)
  870. return;
  871. RestorePoint rp = _redo_points.read_restore_point();
  872. _undo_points.write_restore_point(rp.id, _undo.size(), rp.data);
  873. redo_until(rp.size);
  874. undo_redo(false, rp.id, rp.data);
  875. }
  876. private void undo_until(uint32 size)
  877. {
  878. while (_undo.size() != size)
  879. {
  880. uint32 type = _undo.peek_type();
  881. if (type == ActionType.CREATE)
  882. {
  883. CreateAction a = _undo.read_create_action();
  884. _redo.write_destroy_action(a.id);
  885. create_internal(a.id);
  886. }
  887. else if (type == ActionType.DESTROY)
  888. {
  889. DestroyAction a = _undo.read_destroy_action();
  890. _redo.write_create_action(a.id);
  891. destroy_internal(a.id);
  892. }
  893. else if (type == ActionType.SET_PROPERTY)
  894. {
  895. SetPropertyAction a = _undo.read_set_property_action();
  896. _redo.write_set_property_action(a.id, a.key, get_data(a.id).has_key(a.key) ? get_data(a.id)[a.key] : null);
  897. set_property_internal(a.id, a.key, a.val);
  898. }
  899. else if (type == ActionType.ADD_TO_SET)
  900. {
  901. AddToSetAction a = _undo.read_add_to_set_action();
  902. _redo.write_remove_from_set_action(a.id, a.key, a.item_id);
  903. add_to_set_internal(a.id, a.key, a.item_id);
  904. }
  905. else if (type == ActionType.REMOVE_FROM_SET)
  906. {
  907. RemoveFromSetAction a = _undo.read_remove_from_set_action();
  908. _redo.write_add_to_set_action(a.id, a.key, a.item_id);
  909. remove_from_set_internal(a.id, a.key, a.item_id);
  910. }
  911. }
  912. }
  913. private void redo_until(uint32 size)
  914. {
  915. while (_redo.size() != size)
  916. {
  917. uint32 type = _redo.peek_type();
  918. if (type == ActionType.CREATE)
  919. {
  920. CreateAction a = _redo.read_create_action();
  921. _undo.write_destroy_action(a.id);
  922. create_internal(a.id);
  923. }
  924. else if (type == ActionType.DESTROY)
  925. {
  926. DestroyAction a = _redo.read_destroy_action();
  927. _undo.write_create_action(a.id);
  928. destroy_internal(a.id);
  929. }
  930. else if (type == ActionType.SET_PROPERTY)
  931. {
  932. SetPropertyAction a = _redo.read_set_property_action();
  933. _undo.write_set_property_action(a.id, a.key, get_data(a.id).has_key(a.key) ? get_data(a.id)[a.key] : null);
  934. set_property_internal(a.id, a.key, a.val);
  935. }
  936. else if (type == ActionType.ADD_TO_SET)
  937. {
  938. AddToSetAction a = _redo.read_add_to_set_action();
  939. _undo.write_remove_from_set_action(a.id, a.key, a.item_id);
  940. add_to_set_internal(a.id, a.key, a.item_id);
  941. }
  942. else if (type == ActionType.REMOVE_FROM_SET)
  943. {
  944. RemoveFromSetAction a = _redo.read_remove_from_set_action();
  945. _undo.write_add_to_set_action(a.id, a.key, a.item_id);
  946. remove_from_set_internal(a.id, a.key, a.item_id);
  947. }
  948. }
  949. }
  950. }
  951. }