1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <editeng/Trie.hxx>
21 static const int LATIN_ARRAY_SIZE
= 26;
23 sal_Unicode mCharacter
;
25 std::vector
<std::unique_ptr
<TrieNode
>> mChildren
;
26 std::unique_ptr
<TrieNode
> mLatinArray
[LATIN_ARRAY_SIZE
];
28 explicit TrieNode(sal_Unicode aCharacter
= '\0');
31 TrieNode
* findChild(sal_Unicode aCharacter
);
32 TrieNode
* traversePath(const OUString
& sPath
);
33 void addNewChild(TrieNode
* pChild
);
34 void collectSuggestions(const OUString
& sPath
, std::vector
<OUString
>& rSuggestionList
);
35 static void collectSuggestionsForCurrentNode(TrieNode
* pCurrent
, const OUString
& sPath
, vector
<OUString
>& rSuggestionList
);
38 TrieNode::TrieNode(sal_Unicode aCharacter
) :
39 mCharacter(aCharacter
),
42 for (auto & i
: mLatinArray
)
48 void TrieNode::markWord()
53 void TrieNode::addNewChild(TrieNode
* pChild
)
55 if (pChild
->mCharacter
>= 'a' &&
56 pChild
->mCharacter
<= 'z')
58 mLatinArray
[pChild
->mCharacter
- u
'a'].reset(pChild
);
62 mChildren
.push_back(std::unique_ptr
<TrieNode
>(pChild
));
66 TrieNode
* TrieNode::findChild(sal_Unicode aInputCharacter
)
68 if (aInputCharacter
>= 'a' &&
69 aInputCharacter
<= 'z')
71 return mLatinArray
[aInputCharacter
- u
'a'].get();
74 for(auto const & pCurrent
: mChildren
)
76 if ( pCurrent
->mCharacter
== aInputCharacter
)
77 return pCurrent
.get();
83 void TrieNode::collectSuggestions(const OUString
& sPath
, vector
<OUString
>& rSuggestionList
)
85 // first traverse nodes for alphabet characters
86 for (auto const & pCurrent
: mLatinArray
)
88 if (pCurrent
!= nullptr)
89 collectSuggestionsForCurrentNode(pCurrent
.get(), sPath
, rSuggestionList
);
92 // traverse nodes for other characters
93 for(auto const & pCurrent
: mChildren
)
95 if (pCurrent
!= nullptr)
96 collectSuggestionsForCurrentNode(pCurrent
.get(), sPath
, rSuggestionList
);
100 void TrieNode::collectSuggestionsForCurrentNode(TrieNode
* pCurrent
, const OUString
& sPath
, vector
<OUString
>& rSuggestionList
)
102 OUString aStringPath
= sPath
+ OUStringChar(pCurrent
->mCharacter
);
103 if(pCurrent
->mMarker
)
105 rSuggestionList
.push_back(aStringPath
);
107 // recursively descend tree
108 pCurrent
->collectSuggestions(aStringPath
, rSuggestionList
);
111 TrieNode
* TrieNode::traversePath(const OUString
& sPath
)
113 TrieNode
* pCurrent
= this;
115 for ( sal_Int32 i
= 0; i
< sPath
.getLength(); i
++ )
117 sal_Unicode aCurrentChar
= sPath
[i
];
118 pCurrent
= pCurrent
->findChild(aCurrentChar
);
119 if ( pCurrent
== nullptr )
129 mRoot(new TrieNode())
135 void Trie::insert(const OUString
& sInputString
) const
137 // adding an empty word is not allowed
138 if ( sInputString
.isEmpty() )
143 // traverse the input string and modify the tree with new nodes / characters
145 TrieNode
* pCurrent
= mRoot
.get();
146 sal_Unicode aCurrentChar
;
148 for ( sal_Int32 i
= 0; i
< sInputString
.getLength(); i
++ )
150 aCurrentChar
= sInputString
[i
];
151 TrieNode
* pChild
= pCurrent
->findChild(aCurrentChar
);
152 if ( pChild
== nullptr )
154 TrieNode
* pNewNode
= new TrieNode(aCurrentChar
);
155 pCurrent
->addNewChild(pNewNode
);
164 pCurrent
->markWord();
167 void Trie::findSuggestions(const OUString
& sWordPart
, vector
<OUString
>& rSuggestionList
) const
169 TrieNode
* pNode
= mRoot
->traversePath(sWordPart
);
171 if (pNode
!= nullptr)
173 pNode
->collectSuggestions(sWordPart
, rSuggestionList
);
177 size_t Trie::size() const
181 std::vector
<OUString
> entries
;
182 mRoot
->collectSuggestions(OUString(), entries
);
183 return entries
.size();
187 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */