dynamic_node.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /*
  2. * dynamic_node.cpp - create node from argument list
  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_info.h>
  19. #include <core/node/node.h>
  20. #include <core/node/property.h>
  21. #include <core/node/proxy_node.h>
  22. #include <core/all_types.h>
  23. namespace rainynite::core {
  24. namespace nodes {
  25. template <typename T>
  26. class DynamicNode : public ProxyNode<T> {
  27. public:
  28. DynamicNode() {
  29. this->template init<string>(node_type, {});
  30. auto args = make_shared<UntypedListValue>();
  31. args->new_id();
  32. this->template init_property(arguments, make_optional(Type(typeid(Nothing))), std::move(args));
  33. }
  34. public:
  35. NodeInContext get_proxy(shared_ptr<Context> ctx) const override {
  36. try {
  37. auto type = get_node_type()->get(ctx);
  38. if (cached_type != type) {
  39. node = make_node_with_name<AbstractValue>(type);
  40. cached_type = type;
  41. }
  42. size_t i = 0;
  43. auto node_list = dynamic_cast<AbstractListLinked*>(node.get());
  44. if (auto args = this->get_property("arguments")) {
  45. for (auto const& arg : args->get_list_links(ctx)) {
  46. // TODO: context
  47. node_list->set_link(i, arg.node);
  48. ++i;
  49. }
  50. return {node, ctx};
  51. } else {
  52. throw NodeAccessError("DynamicNode: arguments property is null");
  53. }
  54. } catch (...) {
  55. return { make_value<T>(), ctx };
  56. }
  57. }
  58. private:
  59. mutable AbstractReference node;
  60. mutable string cached_type;
  61. private:
  62. NODE_PROPERTY(node_type, string);
  63. NODE_LIST_PROPERTY(arguments, Nothing);
  64. };
  65. NODE_INFO_TEMPLATE(DynamicNode, DynamicNode<T>, T);
  66. TYPE_INSTANCES(DynamicNodeNodeInfo)
  67. /**
  68. * Convert list by applying node to each element.
  69. *
  70. * Returns list, each element of which is node with a few common properties
  71. * and one from input list.
  72. */
  73. template <typename T>
  74. class ApplyToList : public ProxyListNode<T> {
  75. public:
  76. ApplyToList() {
  77. this->template init<T>(source, {});
  78. this->template init<string>(property_name, {});
  79. // TODO: make a function
  80. {
  81. auto args = make_shared<UntypedListValue>();
  82. args->new_id();
  83. this->template init_property(dynamic_arguments, make_optional(Type(typeid(Nothing))), std::move(args));
  84. }
  85. }
  86. public:
  87. vector<NodeInContext> get_list_links(shared_ptr<Context> ctx) const override {
  88. vector<NodeInContext> result;
  89. try {
  90. auto property = get_property_name()->get(ctx);
  91. auto base_node = get_source();
  92. auto dy_args = this->get_property(dynamic_arguments)->get_list_links(ctx);
  93. std::transform(
  94. std::begin(dy_args),
  95. std::end(dy_args),
  96. std::back_inserter(result),
  97. [base_node, property](auto e) -> NodeInContext {
  98. auto node = shallow_copy(*base_node);
  99. // TODO: fix context
  100. dynamic_cast<AbstractNode*>(node.get())->set_property(property, e.node);
  101. return { node, e.context };
  102. }
  103. );
  104. } catch (...) {
  105. }
  106. return result;
  107. }
  108. private:
  109. NODE_PROPERTY(source, T);
  110. NODE_PROPERTY(property_name, string);
  111. NODE_LIST_PROPERTY(dynamic_arguments, Nothing);
  112. };
  113. NODE_INFO_TEMPLATE(ApplyToList, ApplyToList<T>, vector<T>);
  114. TYPE_INSTANCES(ApplyToListNodeInfo)
  115. /**
  116. * Zip lists of lists into a list of nodes with args.
  117. *
  118. * Takes few homogeneous lists and uses their elements as node properties
  119. * (each list representing one property) in new node list.
  120. *
  121. * TODO: rename to ..Zip
  122. */
  123. template <typename T>
  124. class DynamicListTie : public ProxyListNode<T> {
  125. public:
  126. DynamicListTie() {
  127. this->template init<string>(node_type, {});
  128. auto args = make_shared<UntypedListValue>();
  129. args->new_id();
  130. this->template init_property(arguments_list, make_optional(Type(typeid(Nothing))), std::move(args));
  131. }
  132. public:
  133. void step_into_list(shared_ptr<Context> ctx, std::function<void(NodeInContext)> f) const override {
  134. try {
  135. using List = vector<NodeInContext>;
  136. using Iter = List::const_iterator;
  137. auto args = this->get_property("arguments_list");
  138. if (!args)
  139. throw NodeAccessError("arguments list is null");
  140. auto list_of_lists = args->get_list_links(ctx);
  141. if (list_of_lists.size() == 0)
  142. return;
  143. vector<List> links;
  144. vector<pair<Iter, Iter>> iterators;
  145. bool fail = false;
  146. std::transform(
  147. std::begin(list_of_lists),
  148. std::end(list_of_lists),
  149. std::back_inserter(links),
  150. [&fail](auto e) {
  151. try {
  152. return e.node->get_list_links(e.context);
  153. } catch (...) {
  154. }
  155. fail = true;
  156. return List();
  157. }
  158. );
  159. if (fail) {
  160. return;
  161. // throw
  162. }
  163. std::transform(
  164. std::begin(links),
  165. std::end(links),
  166. std::back_inserter(iterators),
  167. [](auto const& list) -> pair<Iter, Iter> {
  168. return { std::begin(list), std::end(list) };
  169. }
  170. );
  171. auto type = get_node_type()->get(ctx);
  172. while (true) {
  173. auto node = make_node_with_name<AbstractValue>(type);
  174. auto list_node = dynamic_cast<AbstractListLinked*>(node.get());
  175. if (!list_node)
  176. return;
  177. size_t i = 0;
  178. for (auto& e : iterators) {
  179. if (e.first == e.second)
  180. return;
  181. // TODO: fix contexts
  182. list_node->set_link(i, e.first->node);
  183. ++e.first;
  184. ++i;
  185. }
  186. f({node, ctx});
  187. }
  188. } catch (...) {
  189. }
  190. }
  191. private:
  192. NODE_PROPERTY(node_type, string);
  193. NODE_LIST_PROPERTY(arguments_list, Nothing);
  194. };
  195. NODE_INFO_TEMPLATE(DynamicListTie, DynamicListTie<T>, vector<T>);
  196. TYPE_INSTANCES(DynamicListTieNodeInfo)
  197. } // namespace nodes
  198. } // namespace rainynite::core