link_storage.h 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /* link_storage.h - link storage
  2. * Copyright (C) 2017 caryoscelus
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #ifndef CORE_NODE_LINK_STORAGE_H_56A4E74C_E276_5ADA_A9E9_06154E870892
  18. #define CORE_NODE_LINK_STORAGE_H_56A4E74C_E276_5ADA_A9E9_06154E870892
  19. #include <core/std/array.h>
  20. #include <core/class_init.h>
  21. #include <core/node_info.h>
  22. #include <core/exceptions.h>
  23. #include "abstract_list.h"
  24. #include "abstract_value.h"
  25. #include "make.h"
  26. namespace rainynite::core {
  27. /**
  28. * Typed storage of value node links.
  29. */
  30. template <class Self, typename... Ts>
  31. class LinkStorage : public AbstractListLinked
  32. {
  33. public:
  34. LinkStorage() {
  35. size_t i = 0;
  36. for (auto const& v : Self::default_values()) {
  37. set_link_without_checks(i, shallow_copy(*v));
  38. ++i;
  39. }
  40. }
  41. virtual ~LinkStorage() {
  42. }
  43. size_t link_count() const override {
  44. return sizeof...(Ts);
  45. }
  46. vector<AbstractReference> get_links() const override {
  47. return { storage.begin(), storage.end() };
  48. }
  49. AbstractReference get_link(size_t i) const override {
  50. check_range(i);
  51. if (auto link = storage[i])
  52. return link;
  53. throw NullPointerException("Null link");
  54. }
  55. TypeConstraint get_link_type(size_t i) const override {
  56. check_range(i);
  57. return types()[i];
  58. }
  59. void set_link(size_t i, AbstractReference value) override {
  60. check_range(i);
  61. auto const& t = types()[i];
  62. if (!(t.accept(value->get_type())))
  63. throw NodeAccessError("Node property type mis-match");
  64. set_link_without_checks(i, value);
  65. links_changed();
  66. }
  67. private:
  68. void set_link_without_checks(size_t i, AbstractReference value) {
  69. signal_connections[i].disconnect();
  70. storage[i] = value;
  71. signal_connections[i] = value->subscribe([this](){
  72. links_changed();
  73. });
  74. }
  75. public:
  76. template <typename... Is>
  77. void init_values(Is&&... values) {
  78. static_assert(sizeof...(Is) == sizeof...(Ts));
  79. storage = {make_value<Is>(std::forward<Is>(values))...};
  80. size_t i = 0;
  81. for (auto t : {std::type_index(typeid(Is))...}) {
  82. if (!types()[i].accept(t))
  83. throw NodeAccessError("Invalid type in init");
  84. ++i;
  85. }
  86. }
  87. protected:
  88. /**
  89. * Called when links are changed.
  90. *
  91. * Mostly a hack to notify nodes of changes without inheriting it from here.
  92. * Used solely to call changed
  93. */
  94. virtual void links_changed() {
  95. }
  96. private:
  97. void check_range(size_t id) const {
  98. if (id >= sizeof...(Ts))
  99. throw std::out_of_range("set_link out of range");
  100. }
  101. protected:
  102. using TypeArray = array<TypeConstraint, sizeof...(Ts)>;
  103. static TypeArray const& types() {
  104. static TypeArray instance { TypeConstraint(Ts())... };
  105. return instance;
  106. }
  107. private:
  108. array<shared_ptr<AbstractValue>, sizeof...(Ts)> storage;
  109. array<boost::signals2::connection, sizeof...(Ts)> signal_connections;
  110. };
  111. template <typename... Ts>
  112. vector<AbstractReference> generate_value_vector(Ts&&... values) {
  113. return {
  114. make_value<Ts>(std::forward<Ts>(values))...
  115. };
  116. }
  117. #define DEFAULT_VALUES(...) \
  118. public: \
  119. static vector<AbstractReference> const& default_values() { \
  120. static vector<AbstractReference> instance { \
  121. generate_value_vector(__VA_ARGS__) \
  122. }; \
  123. return instance; \
  124. }
  125. } // namespace rainynite::core
  126. #endif