Various changes to preferences object, file loading, and error logging.
[jben.git] / kanjilist.cpp
bloba85f0c4826d9811cd0b69782bf59914bca825ab3
1 /*
2 Project: J-Ben
3 Author: Paul Goins
4 Website: http://www.vultaire.net/software/jben/
5 License: GNU General Public License (GPL) version 2
6 (http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt)
8 File: kanjilist.cpp
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>
24 #include "kanjilist.h"
25 #include "kdict.h"
26 #include "errorlog.h"
27 #include <sstream>
28 #include <algorithm>
29 using namespace std;
31 KanjiList::KanjiList(const BoostHM<wchar_t, KInfo>* kDictHash) {
32 kanjiHash = kDictHash;
35 int KanjiList::AddFromString(const wstring& s) {
36 int kanjiAdded = 0, len = s.length();
37 wchar_t c;
38 BoostHM<wchar_t,KInfo>::const_iterator it;
40 for(int i=0;i<len;i++) {
41 c = s[i];
42 it = kanjiHash->find(c);
43 if(it!=kanjiHash->end()) {
44 if(find(kanjiList.begin(), kanjiList.end(), c)==kanjiList.end()) {
45 kanjiList.push_back(c);
46 kanjiAdded++;
51 return kanjiAdded;
54 /* Convert the kanjilist into a wide char string,
55 with lineWidth kanji per line (0 == no line breaks). */
56 wstring KanjiList::ToString(int lineWidth) {
57 wstring result;
58 int lineWidthCounter=0;
59 int len = kanjiList.size();
60 for(int i=0;i<len;i++) {
61 result.append(1, kanjiList[i]);
62 if(lineWidth>0) {
63 lineWidthCounter++;
64 if(lineWidthCounter>=lineWidth) {
65 result.append(1, L'\n');
66 lineWidthCounter=0;
70 return result;
73 void KanjiList::Clear() {
74 kanjiList.clear();
77 int KanjiList::AddByGrade(int lowGrade, int highGrade) {
78 wstring kanjiStr;
79 int grade;
81 for(BoostHM<wchar_t,KInfo>::const_iterator
82 ki=kanjiHash->begin(); ki!=kanjiHash->end(); ki++) {
83 grade = ki->second.grade;
84 if(grade>=lowGrade &&
85 (grade<=highGrade || highGrade==0))
86 kanjiStr.append(1, ki->first);
89 return AddFromString(kanjiStr);
92 int KanjiList::AddByFrequency(int lowFreq, int highFreq) {
93 wstring kanjiStr;
94 int freq;
96 for(BoostHM<wchar_t,KInfo>::const_iterator ki=kanjiHash->begin(); ki!=kanjiHash->end(); ki++) {
97 freq = ki->second.freq;
98 if(freq>=lowFreq && freq<=highFreq)
99 kanjiStr.append(1, ki->first);
102 return AddFromString(kanjiStr);
105 int KanjiList::Size() {return kanjiList.size();}
107 void KanjiList::InplaceMerge(vector<wchar_t>& v, BoostHM<wchar_t,int>& indexer, int start, int middle, int end) {
108 /* Merge is implemented as a bubble sort started at halfway
109 (since we know the first whole half is already sorted) */
110 int i, highIndex;
111 wchar_t temp;
112 i = highIndex = middle;
113 while(i<end) {
114 if(i>0 && (indexer[v[i]] < indexer[v[i-1]])) {
115 temp = v[i-1];
116 v[i-1] = v[i];
117 v[i] = temp;
118 i--;
119 } else {
120 highIndex++;
121 i=highIndex;
127 SortKanjiList sorts the currently loaded kanji list based upon a specified
128 KANJIDIC field, like F (frequency) or G (jouyou grade). Sorting is done
129 via a merged sort. This might be overkill, but I wanted to try doing
130 it, so I did.
132 void KanjiList::Sort(int sortType, bool reverseOrder) {
133 int totalSize = kanjiList.size();
134 if(totalSize<=1) return; /* Size 0 or 1 list is already sorted */
136 myCharIndexer = new BoostHM<wchar_t,int>;
137 myCharIndexer->clear();
138 vector<wchar_t>::iterator vi;
140 /* Create index based on the sort type */
141 int value;
142 const KDict* kd = KDict::Get();
143 const KInfo* ki;
144 for(vi=kanjiList.begin();vi!=kanjiList.end();vi++) {
145 ki = kd->GetEntry(*vi);
146 if(sortType==ST_GRADE)
147 value = ki->grade;
148 else if(sortType==ST_FREQUENCY)
149 value = ki->grade;
150 else {
151 ostringstream oss;
152 oss << "Unknown sort type: " << sortType << endl;
153 el.Push(EL_Error, oss.str());
154 break;
156 if(value==-1) value=INT_MAX;
157 myCharIndexer->assign(*vi, value);
160 /* Sort our data based upon the stored key in the hash table */
161 /* This code, a merge sort, was created based upon code at:
162 http://en.wikipedia.org/wiki/Merge_sort#C.2B.2B_implementation
163 These pages were referred to:
164 http://www.cppreference.com/cppalgorithm/merge.html
165 http://www.cppreference.com/cppalgorithm/inplace_merge.html */
166 int rangeSize, rangeStart;
167 for(rangeSize=1; rangeSize<totalSize; rangeSize *= 2) {
168 for(rangeStart=0;
169 rangeStart<totalSize-rangeSize;
170 rangeStart += rangeSize*2) {
171 /* Our range sort function is HERE */
172 InplaceMerge(
173 kanjiList,
174 *myCharIndexer,
175 rangeStart,
176 rangeStart + rangeSize,
177 min(rangeStart + rangeSize*2, totalSize));
181 delete myCharIndexer;
184 wchar_t KanjiList::operator[](unsigned int index) {
185 if(index<kanjiList.size()) return kanjiList[index];
186 return L'\0';
189 int KanjiList::GetIndexByChar(wchar_t c) {
190 int i, len = kanjiList.size();
191 for(i=0;i<len;i++)
192 if(kanjiList[i]==c) return i;
193 return -1;
196 vector<wchar_t>& KanjiList::GetVector() {return kanjiList;}