/* Ousía Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include "Node.hpp" namespace ousia { /* Class SharedResolutionState */ /** * The SharedResolutionState structure represents the state that is shared * between all resolution paths. A reference to a per-resolution-global * SharedResolutionState instance is stored in the ResolutionState class. */ class SharedResolutionState { public: /** * Actual path (name pattern) that was requested for resolution. */ const std::vector &path; /** * Type of the node that was requested for resolution. */ const RttiBase &type; /** * Tracks all nodes that have already been visited. */ std::unordered_set visited; /** * Current resolution result. */ std::vector result; static std::vector buildPrefixTable( const std::vector &path); /** * Constructor of the SharedResolutionState class. * * @param path is a const reference to the actual path that should be * resolved. * @param type is the type of the node that should be resolved. */ SharedResolutionState(const std::vector &path, const RttiBase &type) : path(path), type(type) { } }; /* Class ResolutionState */ /** * The ResolutionState class represents a single resolution path used when * resolving Node instances by name. */ class ResolutionState { private: /** * Constructor of the ResolutionState class. * * @param shared is the shared, path independent state. * @param resolutionRoot is the current resolution root node. */ ResolutionState(SharedResolutionState &shared, int idx, Node *resolutionRoot) : shared(shared), idx(idx), resolutionRoot(resolutionRoot) { } public: /** * Constructor of the ResolutionState class. * * @param shared is the shared, path independent state. * @param resolutionRoot is the current resolution root node. */ ResolutionState(SharedResolutionState &shared, Node *resolutionRoot = nullptr) : shared(shared), idx(0), resolutionRoot(resolutionRoot) { } /** * Reference at the resolution state that is shared between the various * resolution paths. */ SharedResolutionState &shared; /** * Current index within the given path. */ int idx; /** * Current resolution root node or nullptr if no resolution root node has * been set yet. */ Node *resolutionRoot; /** * Adds a node to the result. * * @param node is the node that has been found. */ void addToResult(Node *node) { shared.result.emplace_back(ResolutionResult{node, resolutionRoot}); } /** * Marks the given node as visited. Returns false if the given node has * already been visited. * * @param node is the node that should be marked as visited. */ bool markVisited(Node *node) { if (shared.visited.count(node) > 0) { return false; } shared.visited.insert(node); return true; } /** * Returns true if the current node matches the search criteria. * * @param type is the type of the current node. * @return true if the state indicates that the path has been completely * matched and that the given type matches the queried type. */ bool matches(const RttiBase &type) { return idx == static_cast(shared.path.size()) && type.isa(shared.type); } const std::string ¤tName() { return shared.path[idx]; } ResolutionState advance() { return ResolutionState{shared, idx + 1, resolutionRoot}; } ResolutionState fork(Node *newResolutionRoot) { return ResolutionState{shared, newResolutionRoot}; } }; /* Class Node */ void Node::setName(std::string name) { // Call the name change event and (afterwards!) set the new name NameChangeEvent ev{this->name, name}; triggerEvent(ev); this->name = std::move(name); } void Node::path(std::vector &p) const { if (!isRoot()) { parent->path(p); } p.push_back(name); } std::vector Node::path() const { std::vector res; path(res); return res; } bool Node::resolutionAtBeginning(ResolutionState &state) { return state.idx == 0; } bool Node::resolve(ResolutionState &state) { // Try to mark this note as visited, do nothing if already has been visited if (state.markVisited(this)) { // Add this node to the result if it matches the current description if (state.matches(type())) { state.addToResult(this); return true; } else { continueResolve(state); } } return false; } void Node::continueResolve(ResolutionState &state) { // Do nothing in the default implementation } bool Node::continueResolveIndex(const Index &index, ResolutionState &state) { Rooted h = index.resolve(state.currentName()); if (h != nullptr) { ResolutionState advancedState = state.advance(); return h->resolve(advancedState); } return false; } bool Node::continueResolveCompositum(Handle h, ResolutionState &state) { if (h->getName() == state.currentName()) { ResolutionState advancedState = state.advance(); return h->resolve(advancedState); } else if (resolutionAtBeginning(state)) { return h->resolve(state); } return false; } bool Node::continueResolveReference(Handle h, ResolutionState &state) { if (resolutionAtBeginning(state)) { ResolutionState forkedState = state.fork(this); if (h->getName() == state.currentName()) { ResolutionState advancedState = forkedState.advance(); return h->resolve(advancedState); } return h->resolve(forkedState); } return false; } std::vector Node::resolve( const std::vector &path, const RttiBase &type) { // Create the state variables SharedResolutionState sharedState(path, type); ResolutionState state(sharedState, this); // Call the internal resolve function, make sure the length of the given // path is valid if (path.size() > 0) { continueResolveCompositum(this, state); } // Return the results return sharedState.result; } std::vector Node::resolve(const std::string &name, const RttiBase &type) { // Place the name in a vector and call the corresponding resolve function return resolve(std::vector{name}, type); } /* RTTI type registrations */ const Rtti RttiTypes::Node{"Node"}; }