abstract_node.cpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. /*
  2. * abstract_node.cpp - abstract Node
  3. * Copyright (C) 2017 caryoscelus
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <core/node/abstract_node.h>
  19. #include <core/node/abstract_value.h>
  20. namespace rainynite::core {
  21. AbstractNode::~AbstractNode() {
  22. for (auto const& connection : signal_connections) {
  23. connection.disconnect();
  24. }
  25. }
  26. AbstractReference AbstractNode::get_property(string const& name) const {
  27. auto result = named_storage.find(name);
  28. if (result == named_storage.end())
  29. throw NodeAccessError("Unknown property "+name);
  30. return get_by_id(result->second);
  31. }
  32. void AbstractNode::set_property(string const& name, AbstractReference ref) {
  33. if (named_storage.count(name) == 0) {
  34. if (name[0] == '_') {
  35. // accept as custom attribute
  36. init_property(name, {}, ref);
  37. } else
  38. throw NodeAccessError("No such property");
  39. }
  40. set_link(named_storage[name], ref);
  41. }
  42. bool AbstractNode::remove_property(string const& name) {
  43. if (name[0] != '_')
  44. return false; // can only remove custom props
  45. auto iter = named_storage.find(name);
  46. if (iter == std::end(named_storage))
  47. return false;
  48. auto i = iter->second;
  49. // NOTE: this might be not thread-safe
  50. named_storage.erase(iter);
  51. names_list.erase(names_list.begin()+i);
  52. numbered_storage.erase(numbered_storage.begin()+i);
  53. // reassign links
  54. for (auto& e : named_storage) {
  55. if (e.second > i)
  56. --e.second;
  57. }
  58. return true;
  59. }
  60. size_t AbstractNode::init_property(string const& name, optional<Type> type, AbstractReference value) {
  61. size_t id = link_count();
  62. numbered_storage.push_back(value);
  63. names_list.push_back(name);
  64. named_storage[name] = id;
  65. types.push_back(type);
  66. boost::signals2::connection connection;
  67. if (value)
  68. connection = value->subscribe([this]() {
  69. node_changed();
  70. });
  71. signal_connections.push_back(connection);
  72. return id;
  73. }
  74. map<string, AbstractReference> AbstractNode::get_link_map() const {
  75. map<string, AbstractReference> result;
  76. // TODO: use generic conversion function
  77. for (auto const& e : named_storage) {
  78. result.emplace(e.first, get_by_id(e.second));
  79. }
  80. return result;
  81. }
  82. void AbstractNode::set_link(size_t i, AbstractReference value) {
  83. if (auto type = get_link_type(i)) {
  84. if (value->get_type() != *type)
  85. throw NodeAccessError("Node property type mis-match");
  86. }
  87. signal_connections[i].disconnect();
  88. get_by_id(i) = value;
  89. signal_connections[i] = value->subscribe([this]() {
  90. node_changed();
  91. });
  92. node_changed();
  93. }
  94. } // namespace rainynite::core