database.vala 24 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102
  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. /// Saves database to path without marking it as not changed.
  372. public void dump(string path)
  373. {
  374. Hashtable json = encode();
  375. SJSON.save(json, path);
  376. }
  377. /// Saves database to path.
  378. public void save(string path)
  379. {
  380. dump(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. _redo_points.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)))
  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. _redo_points.clear();
  724. destroy_internal(id);
  725. }
  726. public void set_property(Guid id, string key, Value? value)
  727. {
  728. assert(has_object(id));
  729. assert(is_valid_key(key));
  730. assert(is_valid_value(value));
  731. HashMap<string, Value?> ob = get_data(id);
  732. _undo.write_set_property_action(id, key, ob.has_key(key) ? ob[key] : null);
  733. _redo.clear();
  734. _redo_points.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. _redo_points.clear();
  746. add_to_set_internal(id, key, item_id);
  747. }
  748. public void remove_from_set(Guid id, string key, Guid item_id)
  749. {
  750. assert(has_object(id));
  751. assert(is_valid_key(key));
  752. assert(item_id != GUID_ZERO);
  753. _undo.write_add_to_set_action(id, key, item_id);
  754. _redo.clear();
  755. _redo_points.clear();
  756. remove_from_set_internal(id, key, item_id);
  757. }
  758. public bool has_object(Guid id)
  759. {
  760. bool contains = (_data["_objects"] as HashMap<string, Value?>).has_key(id.to_string());
  761. return id == GUID_ZERO || contains;
  762. }
  763. public bool has_property(Guid id, string key)
  764. {
  765. assert(has_object(id));
  766. assert(is_valid_key(key));
  767. return get_data(id).has_key(key);
  768. }
  769. public Value? get_property(Guid id, string key)
  770. {
  771. assert(has_object(id));
  772. assert(is_valid_key(key));
  773. HashMap<string, Value?> ob = get_data(id);
  774. Value? value = (ob.has_key(key) ? ob[key] : null);
  775. #if 0
  776. stdout.printf("get_property %s %s %s\n"
  777. , id.to_string()
  778. , key
  779. , (value == null) ? "null" : value_to_string(value)
  780. );
  781. #endif // CROWN_DEBUG
  782. return value;
  783. }
  784. public HashMap<string, Value?> get_object(Guid id)
  785. {
  786. return (HashMap<string, Value?>)get_data(GUID_ZERO)[id.to_string()];
  787. }
  788. public string[] get_keys(Guid id)
  789. {
  790. HashMap<string, Value?> data = get_data(id);
  791. return data.keys.to_array();
  792. }
  793. public void add_restore_point(int id, Guid[] data)
  794. {
  795. #if 0
  796. stdout.printf("add_restore_point %d, undo size = %u\n", id, _undo.size());
  797. #endif // CROWN_DEBUG
  798. _undo_points.write_restore_point(id, _undo.size(), data);
  799. _redo.clear();
  800. _redo_points.clear();
  801. }
  802. /// Duplicates the object specified by id and assign new_id to the duplicated object.
  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. /// Copies the database to db under the given new_key.
  832. public void copy_to(Database db, string new_key)
  833. {
  834. assert(db != null);
  835. assert(is_valid_key(new_key));
  836. copy_deep(db, GUID_ZERO, new_key);
  837. }
  838. public void copy_deep(Database db, Guid id, string new_key)
  839. {
  840. HashMap<string, Value?> o = get_data(id);
  841. string[] keys = o.keys.to_array();
  842. foreach (string key in keys)
  843. {
  844. if (key == "_objects")
  845. continue;
  846. Value? value = o[key];
  847. if (value.holds(typeof(HashSet)))
  848. {
  849. HashSet<Guid?> hs = (HashSet<Guid?>)value;
  850. foreach (Guid j in hs)
  851. {
  852. db.create(j);
  853. copy_deep(db, j, "");
  854. db.add_to_set(id, new_key + (new_key == "" ? "" : ".") + key, j);
  855. }
  856. }
  857. else
  858. {
  859. db.set_property(id, new_key + (new_key == "" ? "" : ".") + key, o[key]);
  860. }
  861. }
  862. }
  863. public void undo()
  864. {
  865. if (_undo_points.size() == 0)
  866. return;
  867. RestorePoint rp = _undo_points.read_restore_point();
  868. _redo_points.write_restore_point(rp.id, _redo.size(), rp.data);
  869. undo_until(rp.size);
  870. undo_redo(true, rp.id, rp.data);
  871. }
  872. public void redo()
  873. {
  874. if (_redo_points.size() == 0)
  875. return;
  876. RestorePoint rp = _redo_points.read_restore_point();
  877. _undo_points.write_restore_point(rp.id, _undo.size(), rp.data);
  878. redo_until(rp.size);
  879. undo_redo(false, rp.id, rp.data);
  880. }
  881. private void undo_until(uint32 size)
  882. {
  883. while (_undo.size() != size)
  884. {
  885. uint32 type = _undo.peek_type();
  886. if (type == ActionType.CREATE)
  887. {
  888. CreateAction a = _undo.read_create_action();
  889. _redo.write_destroy_action(a.id);
  890. create_internal(a.id);
  891. }
  892. else if (type == ActionType.DESTROY)
  893. {
  894. DestroyAction a = _undo.read_destroy_action();
  895. _redo.write_create_action(a.id);
  896. destroy_internal(a.id);
  897. }
  898. else if (type == ActionType.SET_PROPERTY)
  899. {
  900. SetPropertyAction a = _undo.read_set_property_action();
  901. _redo.write_set_property_action(a.id, a.key, get_data(a.id).has_key(a.key) ? get_data(a.id)[a.key] : null);
  902. set_property_internal(a.id, a.key, a.val);
  903. }
  904. else if (type == ActionType.ADD_TO_SET)
  905. {
  906. AddToSetAction a = _undo.read_add_to_set_action();
  907. _redo.write_remove_from_set_action(a.id, a.key, a.item_id);
  908. add_to_set_internal(a.id, a.key, a.item_id);
  909. }
  910. else if (type == ActionType.REMOVE_FROM_SET)
  911. {
  912. RemoveFromSetAction a = _undo.read_remove_from_set_action();
  913. _redo.write_add_to_set_action(a.id, a.key, a.item_id);
  914. remove_from_set_internal(a.id, a.key, a.item_id);
  915. }
  916. }
  917. }
  918. private void redo_until(uint32 size)
  919. {
  920. while (_redo.size() != size)
  921. {
  922. uint32 type = _redo.peek_type();
  923. if (type == ActionType.CREATE)
  924. {
  925. CreateAction a = _redo.read_create_action();
  926. _undo.write_destroy_action(a.id);
  927. create_internal(a.id);
  928. }
  929. else if (type == ActionType.DESTROY)
  930. {
  931. DestroyAction a = _redo.read_destroy_action();
  932. _undo.write_create_action(a.id);
  933. destroy_internal(a.id);
  934. }
  935. else if (type == ActionType.SET_PROPERTY)
  936. {
  937. SetPropertyAction a = _redo.read_set_property_action();
  938. _undo.write_set_property_action(a.id, a.key, get_data(a.id).has_key(a.key) ? get_data(a.id)[a.key] : null);
  939. set_property_internal(a.id, a.key, a.val);
  940. }
  941. else if (type == ActionType.ADD_TO_SET)
  942. {
  943. AddToSetAction a = _redo.read_add_to_set_action();
  944. _undo.write_remove_from_set_action(a.id, a.key, a.item_id);
  945. add_to_set_internal(a.id, a.key, a.item_id);
  946. }
  947. else if (type == ActionType.REMOVE_FROM_SET)
  948. {
  949. RemoveFromSetAction a = _redo.read_remove_from_set_action();
  950. _undo.write_add_to_set_action(a.id, a.key, a.item_id);
  951. remove_from_set_internal(a.id, a.key, a.item_id);
  952. }
  953. }
  954. }
  955. }
  956. }