nSearchTreeNode BasicSearchTree::SplitBranch(nSearchTreeNode n,size_t depth) { if (!n || !m_Nodes[n] || m_Nodes[n]->GetDepth()==depth) return n; // for !n it returns the rootnode // for !m_Nodes[n], it fails by returning n. // for m_Nodes[n]->GetDepth()==depth, it's a special case (given position is a node) // so we just return n. SearchTreeNode* child = m_Nodes[n]; nSearchTreeNode old_parent = child->GetParent(); // Create new node "middle", add it to old_parent in place of child. // Calculate the parent offset and the new labels' parameters. size_t parent_offset = depth - child->GetLabelStartDepth(); nSearchTreeLabel labelno = child->GetLabelNo(); unsigned int oldlabelstart = child->GetLabelStart(); unsigned int oldlabellen = child->GetLabelLen(); unsigned int middle_start = oldlabelstart; unsigned int middle_len = parent_offset; unsigned int child_start = middle_start + middle_len; unsigned int child_len = oldlabellen - middle_len; wxChar middle_char = m_Labels[labelno][middle_start]; wxChar child_char = m_Labels[labelno][child_start]; // Now we're ready to create the middle node and update accordingly SearchTreeNode* newnode = CreateNode(depth,old_parent,labelno,middle_start,middle_len); m_Nodes.push_back(newnode); nSearchTreeNode middle = m_Nodes.size() - 1; // Add child to middle child->SetParent(middle); child->SetLabel(labelno,child_start,child_len); child->RecalcDepth(this); newnode->m_Children[child_char]=n; child->UpdateItems(this); // Add middle to old_parent m_Nodes[old_parent]->m_Children[middle_char]=middle; return middle; }
size_t BasicSearchTree::FindMatches(const wxString& s, std::set<size_t>& result, bool caseSensitive, bool is_prefix) { // NOTE: Current algorithm is suboptimal, but certainly it's much better // than an exhaustive search. result.clear(); wxString s2,curcmp,s3; SearchTreeNode* curnode = 0; BasicSearchTreeIterator it(this); SearchTreeItemsMap::iterator it2; bool matches; if (!caseSensitive) s2 = s.Lower(); else s2 = s; while (!it.Eof()) { matches = false; curnode = m_Nodes[*it]; if (!curnode) break; // Error! Found a NULL Node if (curnode->m_Depth < s.length()) { // Node's string is shorter than S, therefore it CANNOT be a suffix // However, we can test if it does NOT match the current string. if (!curnode->m_Depth) matches = true; else { s3 = s2.substr(curnode->GetLabelStartDepth(),curnode->GetLabelLen()); curcmp = curnode->GetLabel(this); if (!caseSensitive) curcmp = curcmp.Lower(); matches = (s3 == curcmp); } } else { if (curnode->GetLabelStartDepth() >= s2.length()) matches = is_prefix; else { s3 = s2.substr(curnode->GetLabelStartDepth()); curcmp = curnode->GetLabel(this); if (!caseSensitive) curcmp = curcmp.Lower(); matches = curcmp.StartsWith(s3); } if (matches) { // Begin items addition if (!is_prefix) { // Easy part: Only one length to search it2 = curnode->m_Items.find(s2.length()); if (it2 != curnode->m_Items.end()) result.insert(it2->second); } else { for (it2 = curnode->m_Items.lower_bound(s2.length()); it2 != curnode->m_Items.end(); ++it2) { result.insert(it2->second); } } matches = is_prefix; // End items addition } } it.FindNext(matches); } return result.size(); }