diff --git a/WsNovelParser/novelparser.cpp b/WsNovelParser/novelparser.cpp index 4a04fbf..3ed8eae 100644 --- a/WsNovelParser/novelparser.cpp +++ b/WsNovelParser/novelparser.cpp @@ -12,7 +12,7 @@ NovelParser::NovelParser() { this->syntax_defines = example_novel::NovalSyntax::getParseTree(); checker_list << std::make_shared(); - checker_list << std::make_shared(); + checker_list << std::make_shared(); analyzer_ref = std::make_shared(checker_list); } diff --git a/libParse/parse_novel.cpp b/libParse/parse_novel.cpp index b7d843f..8c3817b 100644 --- a/libParse/parse_novel.cpp +++ b/libParse/parse_novel.cpp @@ -12,10 +12,10 @@ using namespace example_novel; void FragmentExistsCheck::exists_check(std::shared_ptr root, std::shared_ptr target) const { - if (target->element()->typeMark() == (int)example_novel::NovelNode::FragmentRefer) { - auto refer = std::dynamic_pointer_cast(target->element()); + if (target->element()->typeMark() == (int)NovelNode::FragmentRefer) { + auto refer = std::dynamic_pointer_cast(target->element()); auto signature = refer->storyRefer() + u8"&" + refer->fragmentRefer(); - root->getNamedNodeBy((int)example_novel::NovelNode::FragmentDefine, signature); + root->getNamedNodeBy((int)NovelNode::FragmentDefine, signature); } for (auto& xit : target->children()) { @@ -27,268 +27,169 @@ void FragmentExistsCheck::validCheck(std::shared_ptrexists_check(std::dynamic_pointer_cast(root->element()), root); } -FragmentSortHelper::FragmentSortHelper(std::shared_ptr node_bind, int story_sort) { - if (node_bind->element()->typeMark() == (int)example_novel::NovelNode::FragmentDefine) { - type_marks = Type::ELEMENT; - } - else { - type_marks = Type::REFER; +QString FragmentExistsCheck::name() const { + return u8"FragmentExistsCheck"; +} + +void FragmentGraphCheck::setElement(std::shared_ptr inst) +{ + elements_store[inst->nodePeer()->signature()] = inst; +} + +std::shared_ptr FragmentGraphCheck::getElement(const QString& signature) const +{ + return elements_store[signature]; +} + +QList> example_novel::FragmentGraphCheck::getHangoutNodes() { + QList> values; + + for (auto node_item : elements_store) { + if (!node_item->inDegree()) + values.append(node_item); } - element_bind = node_bind; - next_attachment = nullptr; - this->story_sort = story_sort; -} - -FragmentSortHelper::Type FragmentSortHelper::nodeType() const { return type_marks; } - -std::shared_ptr FragmentSortHelper::nodeBind() const { return element_bind; } - -int FragmentSortHelper::storySort() const -{ - return story_sort; -} - -std::shared_ptr FragmentSortHelper::next() const { - return next_attachment; -} - -void FragmentSortHelper::attachNext(std::shared_ptr fragment) { - this->next_attachment = fragment; -} - -void FragmentSortHelper::assignSibling(std::shared_ptr other) -{ - auto temp_list = this->siblings_store; - temp_list.append(other->siblings_store); - temp_list.append(other); - temp_list.append(shared_from_this()); - - QHash> helpers; - for (auto& it : temp_list) { - helpers[it->element_bind->element()->signature()] = it; + for (auto inst : values) { + auto name = inst->nodePeer()->signature(); + elements_store.remove(name); } - temp_list = helpers.values(); - for (auto& it : temp_list) { - auto vlist = temp_list; - vlist.removeAll(it); + return values; +} - it->siblings_store = vlist; +bool example_novel::FragmentGraphCheck::nodeDismantle(std::shared_ptr inst) { + bool flag = false; + + for (auto item : inst->nextList()) { + item->inDegree()--; + flag = true; } + + return flag; } -QList > FragmentSortHelper::siblings() const +void FragmentGraphCheck::validCheck(std::shared_ptr root) const { - return siblings_store; -} + std::function>(std::shared_ptr)> story_peak + = [&](std::shared_ptr root)->QList> { + QList> return_temp; + auto type_mark = (NovelNode)root->element()->typeMark(); + if (type_mark == NovelNode::StoryDefine) { + return_temp << root; + } -void FragmentOrdersCheck::elements_link_build(const QList >& stories) -{ - QHash> helper; - for (auto& i : stories) - helper[i->storyName()] = i; + for (auto child : root->children()) { + return_temp.append(story_peak(child)); + } - auto auto_refer = [&](std::shared_ptr story) { - auto fragment_head = story->fragmentSort(); - while (fragment_head) { - switch (fragment_head->nodeType()) { - case FragmentSortHelper::Type::REFER: - { - auto access = fragment_head->nodeBind(); - auto elm = std::dynamic_pointer_cast(access->element()); - if (!helper.contains(elm->storyRefer())) { - throw new lib_parse::CheckException(QString(u8"Parse[0x0001]故事线“%1”不存在!").arg(elm->storyRefer())); - } - auto story_target = helper[elm->storyRefer()]; - auto fragm_target = story_target->fragment(elm->fragmentRefer()); - if (!fragm_target) { - throw new lib_parse::CheckException( - QString(u8"Parse[0x0002]故事线“%1”的情节“%2”不存在!").arg(elm->storyRefer()).arg(elm->fragmentRefer())); - } + return return_temp; + }; - fragment_head->assignSibling(fragm_target); + auto self = std::const_pointer_cast(this->shared_from_this()); + + // 获取所有故事线 + auto all_story = story_peak(root); + // 注册图节点 + for (auto story : all_story) { + auto fragment_items = story->children(); + + // 构建情节节点列表 + for (auto frag_primitive : fragment_items) { + switch (frag_primitive->element()->typeMark()) { + case (int)NovelNode::FragmentDefine: { + auto target_node = std::dynamic_pointer_cast(frag_primitive->element()); + auto finst = std::make_shared(target_node); + + self->setElement(finst); }break; - default: - break; - } - - fragment_head = fragment_head->next(); - } - }; - - for (auto& vit : stories) { - auto_refer(vit); - } -} - -template -void cast(InputIt Begin, InputIt End, OutputIt Dst, Operate fn) { - while (Begin != End) { - *Dst++ = fn(*Begin++); - } -} - - -void FragmentOrdersCheck::sort_cycle_check(const QList>& tracks, std::shared_ptr _current, int story_sort_source) -{ - if (!_current || !_current->next()) - return; - - auto target = _current->next(); - - if (tracks.contains(peaks_appoint_element(target))) { - QString error_cycle; - for (auto& it : tracks) - error_cycle += u8"->" + it->nodeBind()->element()->signature() + u8"\n"; - error_cycle += u8"->" + target->nodeBind()->element()->signature() + u8"。"; - - throw new lib_parse::CheckException(u8"Parse[0x0003]排序异常:\n" + error_cycle); - } - - auto nlist = tracks; - nlist.append(peaks_appoint_element(target)); - - if (target->nodeType() == example_novel::FragmentSortHelper::Type::REFER) { - decltype (target->siblings()) sibling_forks; - - auto siblings = target->siblings(); - for (auto& vit : siblings) { - if (vit->storySort() <= story_sort_source) - sibling_forks << vit; - } - - for (auto& fork : sibling_forks) { - sort_cycle_check(nlist, fork, story_sort_source); - } - } - - sort_cycle_check(nlist, target, story_sort_source); -} - -std::shared_ptr example_novel::FragmentOrdersCheck::peaks_appoint_element(std::shared_ptr refer_n) const -{ - if (refer_n->nodeType() == example_novel::FragmentSortHelper::Type::ELEMENT) - return refer_n; - - auto sibs = refer_n->siblings(); - for (auto ptr : sibs) { - if (ptr->nodeType() == example_novel::FragmentSortHelper::Type::ELEMENT) - return ptr; - } - - return nullptr; -} - - -void FragmentOrdersCheck::validCheck(std::shared_ptr root) const { - std::function>(std::shared_ptr)> peak_story = - [&](std::shared_ptr pnode) -> QList> { - QList> listret; - - if (pnode->element()->typeMark() == (int)example_novel::NovelNode::StoryDefine) - listret << pnode; - - for (auto& vit : pnode->children()) - listret.append(peak_story(vit)); - - return listret; - }; - - auto stories = peak_story(root); - std::sort(std::begin(stories), std::end(stories), - [](std::shared_ptr itema, std::shared_ptr itemb) -> bool { - auto storya = std::dynamic_pointer_cast(itema->element()); - auto storyb = std::dynamic_pointer_cast(itemb->element()); - return storya->sort() < storyb->sort(); - }); - - for (auto& sit : stories) { - auto story_sort = std::make_shared(sit); - const_cast(this)->stories_list << story_sort; - - auto children = sit->children(); - std::shared_ptr temp_ptr = nullptr; - for (auto& nf : children) { - switch ((example_novel::NovelNode)nf->element()->typeMark()) { - case example_novel::NovelNode::FragmentDefine: - case example_novel::NovelNode::FragmentRefer: { - auto frag_sort = std::make_shared(nf, story_sort->sortValue()); - if (!temp_ptr) { - story_sort->attachFragmentSort(frag_sort); - } - else { - temp_ptr->attachNext(frag_sort); - } - temp_ptr = frag_sort; - } break; - default: - break; + default: break; } } } - // 重复排序检查 - int prev_sort = 0; - for (auto& s : stories_list) { - if (s->sortValue() < 1) - throw new lib_parse::CheckException(u8"Parse[0x0006]故事“%1”的排序<1。"); - if (prev_sort >= s->sortValue()) { - auto idx = stories_list.indexOf(s); - auto prev = stories_list[idx - 1]; - throw new lib_parse::CheckException(QString(u8"Parse[0x0007]故事“%1”与故事“%2”排序重复。").arg(s->storyName()).arg(prev->storyName())); + // 构建图连接 + for (auto story : all_story) { + auto fragment_items = story->children(); + + // 过滤获取情节节点 + for (auto idx = 0; idx < fragment_items.size(); idx++) { + auto fragment_inst = fragment_items[idx]; + switch (fragment_inst->element()->typeMark()) + { + case (int)NovelNode::FragmentDefine: + case (int)NovelNode::FragmentRefer: + break; + default: + fragment_items.removeAt(idx); + idx--; + break; + } + } + + auto get_name = [](std::shared_ptr node)->QString { + switch (node->element()->typeMark()) { + case (int)NovelNode::FragmentDefine: { + auto def_node = std::dynamic_pointer_cast(node->element()); + return def_node->signature(); + }break; + case (int)NovelNode::FragmentRefer: { + auto ref_node = std::dynamic_pointer_cast(node->element()); + return ref_node->referSignature(); + }break; + } + return QString(); + }; + + // 构建完整图结构 + for (auto fidx = 1; fidx < fragment_items.size(); fidx++) { + auto tail_name = get_name(fragment_items[fidx - 1]); + auto head_name = get_name(fragment_items[fidx]); + + auto tail_helper = getElement(tail_name); + auto head_helper = getElement(head_name); + + tail_helper->appendNext(head_helper); + head_helper->inDegree()++; } } - const_cast(this)->elements_link_build(this->stories_list); + // 获取拓扑排序序列 + auto values = self->getHangoutNodes(); + for (auto idx = 0; idx < values.size(); ++idx) { + auto target = values[idx]; - for (auto& s : this->stories_list) { - if(!s->fragmentSort()) - continue; - - QList> tracks; - tracks << peaks_appoint_element(s->fragmentSort()); - const_cast(this)->sort_cycle_check(tracks, s->fragmentSort(), s->sortValue()); + self->nodeDismantle(target); + auto x_values = self->getHangoutNodes(); + values.append(x_values); } + + // 理论上不应该有残余 + if (elements_store.size()) + throw new lib_parse::CheckException(u8"情节图存在环形结构"); } -StorySortHelper::StorySortHelper(std::shared_ptr story_bind) { - this->story_bind = story_bind; - this->fragments_bind = nullptr; +QString example_novel::FragmentGraphCheck::name() const { + return u8"FragmentGraphCheck"; } -std::shared_ptr StorySortHelper::storyElement() const { - return std::dynamic_pointer_cast(story_bind->element()); -} +FragmentGraphHelper::FragmentGraphHelper(std::shared_ptr node) : node_peer(node) {} -QString StorySortHelper::storyName() const { return storyElement()->name(); } - -int StorySortHelper::sortValue() const +std::shared_ptr FragmentGraphHelper::nodePeer() const { - return storyElement()->sort(); + return this->node_peer; } -std::shared_ptr StorySortHelper::fragmentSort() const { - return this->fragments_bind; +void FragmentGraphHelper::appendNext(std::shared_ptr node) { + this->next_nodes.append(node); } -void StorySortHelper::attachFragmentSort(std::shared_ptr refer) { - this->fragments_bind = refer; +QList> FragmentGraphHelper::nextList() const +{ + return next_nodes; } -std::shared_ptr StorySortHelper::fragment(const QString& name) const { - auto temp_ptr = fragments_bind; - - do { - if (temp_ptr->nodeType() == FragmentSortHelper::Type::ELEMENT) { - auto node = std::dynamic_pointer_cast(temp_ptr->nodeBind()->element()); - if (node->name() == name) - return temp_ptr; - } - temp_ptr = temp_ptr->next(); - } while (temp_ptr); - - return nullptr; +uint& FragmentGraphHelper::inDegree() +{ + return this->indegree; } - diff --git a/libParse/parse_novel.h b/libParse/parse_novel.h index f2dab6e..c81c331 100644 --- a/libParse/parse_novel.h +++ b/libParse/parse_novel.h @@ -12,81 +12,42 @@ namespace example_novel { public: // 通过 CheckProvider 继承 virtual void validCheck(std::shared_ptr root) const override; - virtual QString name() const override { - return u8"FragmentExistsCheck"; - } + virtual QString name() const override; }; + class FragmentGraphHelper; + class LIBPARSE_EXPORT FragmentGraphCheck : public std::enable_shared_from_this, public lib_parse::CheckProvider { + private: + QHash> elements_store; - class StorySortHelper; - class FragmentSortHelper; - class LIBPARSE_EXPORT FragmentOrdersCheck : public lib_parse::CheckProvider { - protected: - QList> stories_list; + public: + void setElement(std::shared_ptr inst); + std::shared_ptr getElement(const QString &signature) const; - void elements_link_build(const QList>& stories); - void sort_cycle_check(const QList>& tracks, std::shared_ptr current, - int story_sort_source); - - std::shared_ptr peaks_appoint_element(std::shared_ptr refer_n) const; + QList> getHangoutNodes(); + bool nodeDismantle(std::shared_ptr inst); // CheckProvider interface public: virtual void validCheck(std::shared_ptr root) const override; - virtual QString name() const override { - return u8"FragmentOrdersCheck"; - } + virtual QString name() const override; }; - /** - * @brief 情节排序辅助类 - */ - class LIBPARSE_EXPORT FragmentSortHelper : public std::enable_shared_from_this { - public: - enum class Type { - REFER, ELEMENT - }; - - FragmentSortHelper(std::shared_ptr node_bind, int story_sort); - - Type nodeType() const; - std::shared_ptr nodeBind() const; - int storySort() const; - - std::shared_ptr next() const; - void attachNext(std::shared_ptr fragment); - - void assignSibling(std::shared_ptr other); - QList> siblings() const; - - + class FragmentGraphHelper : public std::enable_shared_from_this { private: - Type type_marks; - int story_sort; - std::shared_ptr element_bind; - std::shared_ptr next_attachment; - QList> siblings_store; - }; - - /** - * @brief 故事排序辅助类 - */ - class LIBPARSE_EXPORT StorySortHelper { - private: - std::shared_ptr story_bind; - std::shared_ptr fragments_bind; + std::shared_ptr node_peer; + QList> next_nodes; + uint indegree = 0; public: - StorySortHelper(std::shared_ptr story_bind); + FragmentGraphHelper(std::shared_ptr node); + + std::shared_ptr nodePeer() const; - std::shared_ptr storyElement() const; - QString storyName() const; - int sortValue() const; + void appendNext(std::shared_ptr node); + QList> nextList() const; - std::shared_ptr fragmentSort() const; - void attachFragmentSort(std::shared_ptr refer); - - std::shared_ptr fragment(const QString& name) const; + uint& inDegree(); };