database.vala 24 KB

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