Lukhnos: Taiyan // Refactor for better thread safety

- See UPR269.
- A vChewing-Specific change, allowing the HYPY input mode to support the intonation key "1", is unavailable in this update. It will be brought back later if possible.
This commit is contained in:
ShikiSuen 2022-02-02 11:58:19 +08:00
parent 40e28d8657
commit d3032053ab
2 changed files with 1423 additions and 1258 deletions

View File

@ -5,149 +5,108 @@
* All rights reserved. See "LICENSE.TXT" for details. * All rights reserved. See "LICENSE.TXT" for details.
*/ */
#ifndef Mandarin_h #ifndef MANDARIN_H_
#define Mandarin_h #define MANDARIN_H_
#include <iostream> #include <iostream>
#include <map>
#include <string> #include <string>
#include <vector> #include <vector>
#include <map>
namespace Taiyan { namespace Taiyan {
namespace Mandarin { namespace Mandarin {
using namespace std;
class BopomofoSyllable { class BopomofoSyllable {
public: public:
typedef unsigned int Component; typedef uint16_t Component;
BopomofoSyllable(Component syllable = 0)
: m_syllable(syllable)
{
}
BopomofoSyllable(const BopomofoSyllable& another) explicit BopomofoSyllable(Component syllable = 0) : syllable_(syllable) {}
: m_syllable(another.m_syllable)
{
}
~BopomofoSyllable() BopomofoSyllable(const BopomofoSyllable&) = default;
{ BopomofoSyllable(BopomofoSyllable&& another) = default;
} BopomofoSyllable& operator=(const BopomofoSyllable&) = default;
BopomofoSyllable& operator=(BopomofoSyllable&&) = default;
BopomofoSyllable& operator=(const BopomofoSyllable& another) // takes the ASCII-form, "v"-tolerant, Non-Continental-style Hanyu Pinyin (fong, pong, bong
{ // acceptable)
m_syllable = another.m_syllable; static const BopomofoSyllable FromHanyuPinyin(const std::string& str);
return *this;
}
// takes the ASCII-form, "v"-tolerant, TW-style Hanyu Pinyin (fong, pong, bong acceptable)
static const BopomofoSyllable FromHanyuPinyin(const string& str);
// TO DO: Support accented vowels // TO DO: Support accented vowels
const string HanyuPinyinString(bool includesTone, bool useVForUUmlaut) const; const std::string HanyuPinyinString(bool includesTone,
// const string HanyuPinyinString(bool includesTone, bool useVForUUmlaut, bool composeAccentedVowel) const; bool useVForUUmlaut) const;
// const std::string HanyuPinyinString(bool includesTone, bool useVForUUmlaut,
// bool composeAccentedVowel) const;
// PHT = Pai-hua-tsi // PHT = Pai-hua-tsi
static const BopomofoSyllable FromPHT(const string& str); static const BopomofoSyllable FromPHT(const std::string& str);
const string PHTString(bool includesTone) const; const std::string PHTString(bool includesTone) const;
static const BopomofoSyllable FromComposedString(const string& str); static const BopomofoSyllable FromComposedString(const std::string& str);
const string composedString() const; const std::string composedString() const;
void clear() void clear() { syllable_ = 0; }
{
m_syllable = 0; bool isEmpty() const { return !syllable_; }
bool hasConsonant() const { return !!(syllable_ & ConsonantMask); }
bool hasMiddleVowel() const { return !!(syllable_ & MiddleVowelMask); }
bool hasVowel() const { return !!(syllable_ & VowelMask); }
bool hasToneMarker() const { return !!(syllable_ & ToneMarkerMask); }
Component consonantComponent() const { return syllable_ & ConsonantMask; }
Component middleVowelComponent() const {
return syllable_ & MiddleVowelMask;
} }
bool isEmpty() const Component vowelComponent() const { return syllable_ & VowelMask; }
{
return !m_syllable; Component toneMarkerComponent() const { return syllable_ & ToneMarkerMask; }
bool operator==(const BopomofoSyllable& another) const {
return syllable_ == another.syllable_;
} }
bool hasConsonant() const bool operator!=(const BopomofoSyllable& another) const {
{ return syllable_ != another.syllable_;
return !!(m_syllable & ConsonantMask);
} }
bool hasMiddleVowel() const bool isOverlappingWith(const BopomofoSyllable& another) const {
{ #define IOW_SAND(mask) ((syllable_ & mask) && (another.syllable_ & mask))
return !!(m_syllable & MiddleVowelMask); return IOW_SAND(ConsonantMask) || IOW_SAND(MiddleVowelMask) ||
} IOW_SAND(VowelMask) || IOW_SAND(ToneMarkerMask);
bool hasVowel() const
{
return !!(m_syllable & VowelMask);
}
bool hasToneMarker() const
{
return !!(m_syllable & ToneMarkerMask);
}
Component consonantComponent() const
{
return m_syllable & ConsonantMask;
}
Component middleVowelComponent() const
{
return m_syllable & MiddleVowelMask;
}
Component vowelComponent() const
{
return m_syllable & VowelMask;
}
Component toneMarkerComponent() const
{
return m_syllable & ToneMarkerMask;
}
bool operator==(const BopomofoSyllable& another) const
{
return m_syllable == another.m_syllable;
}
bool operator!=(const BopomofoSyllable& another) const
{
return m_syllable != another.m_syllable;
}
bool isOverlappingWith(const BopomofoSyllable& another) const
{
#define IOW_SAND(mask) ((m_syllable & mask) && (another.m_syllable & mask))
return IOW_SAND(ConsonantMask) || IOW_SAND(MiddleVowelMask) || IOW_SAND(VowelMask) || IOW_SAND(ToneMarkerMask);
#undef IOW_SAND #undef IOW_SAND
} }
// consonants J, Q, X all require the existence of vowel I or UE // consonants J, Q, X all require the existence of vowel I or UE
bool belongsToJQXClass() const bool belongsToJQXClass() const {
{ Component consonant = syllable_ & ConsonantMask;
Component consonant = m_syllable & ConsonantMask;
return (consonant == J || consonant == Q || consonant == X); return (consonant == J || consonant == Q || consonant == X);
} }
// zi, ci, si, chi, chi, shi, ri // zi, ci, si, chi, chi, shi, ri
bool belongsToZCSRClass() const bool belongsToZCSRClass() const {
{ Component consonant = syllable_ & ConsonantMask;
Component consonant = m_syllable & ConsonantMask;
return (consonant >= ZH && consonant <= S); return (consonant >= ZH && consonant <= S);
} }
Component maskType() const Component maskType() const {
{
Component mask = 0; Component mask = 0;
mask |= (m_syllable & ConsonantMask) ? ConsonantMask : 0; mask |= (syllable_ & ConsonantMask) ? ConsonantMask : 0;
mask |= (m_syllable & MiddleVowelMask) ? MiddleVowelMask : 0; mask |= (syllable_ & MiddleVowelMask) ? MiddleVowelMask : 0;
mask |= (m_syllable & VowelMask) ? VowelMask : 0; mask |= (syllable_ & VowelMask) ? VowelMask : 0;
mask |= (m_syllable & ToneMarkerMask) ? ToneMarkerMask : 0; mask |= (syllable_ & ToneMarkerMask) ? ToneMarkerMask : 0;
return mask; return mask;
} }
const BopomofoSyllable operator+(const BopomofoSyllable& another) const const BopomofoSyllable operator+(const BopomofoSyllable& another) const {
{ Component newSyllable = syllable_;
Component newSyllable = m_syllable; #define OP_SOVER(mask) \
#define OP_SOVER(mask) if (another.m_syllable & mask) newSyllable = (newSyllable & ~mask) | (another.m_syllable & mask) if (another.syllable_ & mask) { \
newSyllable = (newSyllable & ~mask) | (another.syllable_ & mask); \
}
OP_SOVER(ConsonantMask); OP_SOVER(ConsonantMask);
OP_SOVER(MiddleVowelMask); OP_SOVER(MiddleVowelMask);
OP_SOVER(VowelMask); OP_SOVER(VowelMask);
@ -156,9 +115,11 @@ namespace Taiyan {
return BopomofoSyllable(newSyllable); return BopomofoSyllable(newSyllable);
} }
BopomofoSyllable& operator+=(const BopomofoSyllable& another) BopomofoSyllable& operator+=(const BopomofoSyllable& another) {
{ #define OPE_SOVER(mask) \
#define OPE_SOVER(mask) if (another.m_syllable & mask) m_syllable = (m_syllable & ~mask) | (another.m_syllable & mask) if (another.syllable_ & mask) { \
syllable_ = (syllable_ & ~mask) | (another.syllable_ & mask); \
}
OPE_SOVER(ConsonantMask); OPE_SOVER(ConsonantMask);
OPE_SOVER(MiddleVowelMask); OPE_SOVER(MiddleVowelMask);
OPE_SOVER(VowelMask); OPE_SOVER(VowelMask);
@ -167,83 +128,74 @@ namespace Taiyan {
return *this; return *this;
} }
short absoluteOrder() const uint16_t absoluteOrder() const {
{
// turn BPMF syllable into a 4*14*4*22 number // turn BPMF syllable into a 4*14*4*22 number
return (short)(m_syllable & ConsonantMask) + return (uint16_t)(syllable_ & ConsonantMask) +
(short)((m_syllable & MiddleVowelMask) >> 5) * 22 + (uint16_t)((syllable_ & MiddleVowelMask) >> 5) * 22 +
(short)((m_syllable & VowelMask) >> 7) * 22 * 4 + (uint16_t)((syllable_ & VowelMask) >> 7) * 22 * 4 +
(short)((m_syllable & ToneMarkerMask) >> 11) * 22 * 4 * 14; (uint16_t)((syllable_ & ToneMarkerMask) >> 11) * 22 * 4 * 14;
} }
const string absoluteOrderString() const const std::string absoluteOrderString() const {
{
// 5*14*4*22 = 6160, we use a 79*79 encoding to represent that // 5*14*4*22 = 6160, we use a 79*79 encoding to represent that
short order = absoluteOrder(); uint16_t order = absoluteOrder();
char low = 48 + (char)(order % 79); char low = 48 + static_cast<char>(order % 79);
char high = 48 + (char)(order / 79); char high = 48 + static_cast<char>(order / 79);
string result(2, ' '); std::string result(2, ' ');
result[0] = low; result[0] = low;
result[1] = high; result[1] = high;
return result; return result;
} }
static BopomofoSyllable FromAbsoluteOrder(short order) static BopomofoSyllable FromAbsoluteOrder(uint16_t order) {
{ return BopomofoSyllable((order % 22) | ((order / 22) % 4) << 5 |
return BopomofoSyllable(
(order % 22) |
((order / 22) % 4) << 5 |
((order / (22 * 4)) % 14) << 7 | ((order / (22 * 4)) % 14) << 7 |
((order / (22 * 4 * 14)) % 5) << 11 ((order / (22 * 4 * 14)) % 5) << 11);
);
} }
static BopomofoSyllable FromAbsoluteOrderString(const string& str) static BopomofoSyllable FromAbsoluteOrderString(const std::string& str) {
{ if (str.length() != 2) return BopomofoSyllable();
if (str.length() != 2)
return BopomofoSyllable();
return FromAbsoluteOrder((short)(str[1] - 48) * 79 + (short)(str[0] - 48)); return FromAbsoluteOrder((uint16_t)(str[1] - 48) * 79 +
(uint16_t)(str[0] - 48));
} }
friend ostream& operator<<(ostream& stream, const BopomofoSyllable& syllable); friend std::ostream& operator<<(std::ostream& stream,
const BopomofoSyllable& syllable);
static const Component static constexpr Component
ConsonantMask = 0x001f, // 0000 0000 0001 1111, 21 consonants ConsonantMask = 0x001f, // 0000 0000 0001 1111, 21 consonants
MiddleVowelMask = 0x0060, // 0000 0000 0110 0000, 3 middle vowels MiddleVowelMask = 0x0060, // 0000 0000 0110 0000, 3 middle vowels
VowelMask = 0x0780, // 0000 0111 1000 0000, 13 vowels VowelMask = 0x0780, // 0000 0111 1000 0000, 13 vowels
ToneMarkerMask = 0x3800, // 0011 1000 0000 0000, 5 tones (tone1 = 0x00) ToneMarkerMask = 0x3800, // 0011 1000 0000 0000, 5 tones (tone1 = 0x00)
B = 0x0001, P = 0x0002, M = 0x0003, F = 0x0004, B = 0x0001, P = 0x0002, M = 0x0003, F = 0x0004, D = 0x0005, T = 0x0006,
D = 0x0005, T = 0x0006, N = 0x0007, L = 0x0008, N = 0x0007, L = 0x0008, G = 0x0009, K = 0x000a, H = 0x000b, J = 0x000c,
G = 0x0009, K = 0x000a, H = 0x000b, Q = 0x000d, X = 0x000e, ZH = 0x000f, CH = 0x0010, SH = 0x0011, R = 0x0012,
J = 0x000c, Q = 0x000d, X = 0x000e, Z = 0x0013, C = 0x0014, S = 0x0015, I = 0x0020, U = 0x0040,
ZH = 0x000f, CH = 0x0010, SH = 0x0011, R = 0x0012, UE = 0x0060, // ue = u umlaut (we use the German convention here as an
Z = 0x0013, C = 0x0014, S = 0x0015, // ersatz to the /ju:/ sound)
I = 0x0020, U = 0x0040, UE = 0x0060, // ue = u umlaut (we use the German convention here as an ersatz to the /ju:/ sound) A = 0x0080, O = 0x0100, ER = 0x0180, E = 0x0200, AI = 0x0280, EI = 0x0300,
A = 0x0080, O = 0x0100, ER = 0x0180, E = 0x0200, AO = 0x0380, OU = 0x0400, AN = 0x0480, EN = 0x0500, ANG = 0x0580,
AI = 0x0280, EI = 0x0300, AO = 0x0380, OU = 0x0400, ENG = 0x0600, ERR = 0x0680, Tone1 = 0x0000, Tone2 = 0x0800,
AN = 0x0480, EN = 0x0500, ANG = 0x0580, ENG = 0x0600, Tone3 = 0x1000, Tone4 = 0x1800, Tone5 = 0x2000;
ERR = 0x0680,
Tone1 = 0x0000, Tone2 = 0x0800, Tone3 = 0x1000, Tone4 = 0x1800, Tone5 = 0x2000;
protected: protected:
Component m_syllable; Component syllable_;
}; };
inline ostream& operator<<(ostream& stream, const BopomofoSyllable& syllable) inline std::ostream& operator<<(std::ostream& stream,
{ const BopomofoSyllable& syllable) {
stream << syllable.composedString(); stream << syllable.composedString();
return stream; return stream;
} }
typedef BopomofoSyllable BPMF; typedef BopomofoSyllable BPMF;
typedef map<char, vector<BPMF::Component> > BopomofoKeyToComponentMap; typedef std::map<char, std::vector<BPMF::Component> > BopomofoKeyToComponentMap;
typedef map<BPMF::Component, char> BopomofoComponentToKeyMap; typedef std::map<BPMF::Component, char> BopomofoComponentToKeyMap;
class BopomofoKeyboardLayout { class BopomofoKeyboardLayout {
public: public:
static void FinalizeLayouts();
static const BopomofoKeyboardLayout* StandardLayout(); static const BopomofoKeyboardLayout* StandardLayout();
static const BopomofoKeyboardLayout* ETenLayout(); static const BopomofoKeyboardLayout* ETenLayout();
static const BopomofoKeyboardLayout* HsuLayout(); static const BopomofoKeyboardLayout* HsuLayout();
@ -251,42 +203,41 @@ namespace Taiyan {
static const BopomofoKeyboardLayout* IBMLayout(); static const BopomofoKeyboardLayout* IBMLayout();
static const BopomofoKeyboardLayout* HanyuPinyinLayout(); static const BopomofoKeyboardLayout* HanyuPinyinLayout();
// recognizes (case-insensitive): standard, eten, hsu, eten26, ibm BopomofoKeyboardLayout(const BopomofoKeyToComponentMap& ktcm,
static const BopomofoKeyboardLayout* LayoutForName(const string& name); const std::string& name)
: m_keyToComponent(ktcm), m_name(name) {
BopomofoKeyboardLayout(const BopomofoKeyToComponentMap& ktcm, const string& name) for (BopomofoKeyToComponentMap::const_iterator miter =
: m_keyToComponent(ktcm) m_keyToComponent.begin();
, m_name(name) miter != m_keyToComponent.end(); ++miter)
{ for (std::vector<BPMF::Component>::const_iterator viter =
for (BopomofoKeyToComponentMap::const_iterator miter = m_keyToComponent.begin() ; miter != m_keyToComponent.end() ; ++miter) (*miter).second.begin();
for (vector<BPMF::Component>::const_iterator viter = (*miter).second.begin() ; viter != (*miter).second.end() ; ++viter) viter != (*miter).second.end(); ++viter)
m_componentToKey[*viter] = (*miter).first; m_componentToKey[*viter] = (*miter).first;
} }
const string name() const const std::string name() const { return m_name; }
{
return m_name;
}
char componentToKey(BPMF::Component component) const char componentToKey(BPMF::Component component) const {
{ BopomofoComponentToKeyMap::const_iterator iter =
BopomofoComponentToKeyMap::const_iterator iter = m_componentToKey.find(component); m_componentToKey.find(component);
return (iter == m_componentToKey.end()) ? 0 : (*iter).second; return (iter == m_componentToKey.end()) ? 0 : (*iter).second;
} }
const vector<BPMF::Component> keyToComponents(char key) const const std::vector<BPMF::Component> keyToComponents(char key) const {
{
BopomofoKeyToComponentMap::const_iterator iter = m_keyToComponent.find(key); BopomofoKeyToComponentMap::const_iterator iter = m_keyToComponent.find(key);
return (iter == m_keyToComponent.end()) ? vector<BPMF::Component>() : (*iter).second; return (iter == m_keyToComponent.end()) ? std::vector<BPMF::Component>()
: (*iter).second;
} }
const string keySequenceFromSyllable(BPMF syllable) const const std::string keySequenceFromSyllable(BPMF syllable) const {
{ std::string sequence;
string sequence;
BPMF::Component c; BPMF::Component c;
char k; char k;
#define STKS_COMBINE(component) if ((c = component)) { if ((k = componentToKey(c))) sequence += string(1, k); } #define STKS_COMBINE(component) \
if ((c = component)) { \
if ((k = componentToKey(c))) sequence += std::string(1, k); \
}
STKS_COMBINE(syllable.consonantComponent()); STKS_COMBINE(syllable.consonantComponent());
STKS_COMBINE(syllable.middleVowelComponent()); STKS_COMBINE(syllable.middleVowelComponent());
STKS_COMBINE(syllable.vowelComponent()); STKS_COMBINE(syllable.vowelComponent());
@ -295,19 +246,17 @@ namespace Taiyan {
return sequence; return sequence;
} }
const BPMF syllableFromKeySequence(const string& sequence) const const BPMF syllableFromKeySequence(const std::string& sequence) const {
{
BPMF syllable; BPMF syllable;
for (string::const_iterator iter = sequence.begin() ; iter != sequence.end() ; ++iter) for (std::string::const_iterator iter = sequence.begin();
{ iter != sequence.end(); ++iter) {
bool beforeSeqHasIorUE = sequenceContainsIorUE(sequence.begin(), iter); bool beforeSeqHasIorUE = sequenceContainsIorUE(sequence.begin(), iter);
bool aheadSeqHasIorUE = sequenceContainsIorUE(iter + 1, sequence.end()); bool aheadSeqHasIorUE = sequenceContainsIorUE(iter + 1, sequence.end());
vector<BPMF::Component> components = keyToComponents(*iter); std::vector<BPMF::Component> components = keyToComponents(*iter);
if (!components.size()) if (!components.size()) continue;
continue;
if (components.size() == 1) { if (components.size() == 1) {
syllable += BPMF(components[0]); syllable += BPMF(components[0]);
@ -319,25 +268,24 @@ namespace Taiyan {
BPMF ending = components.size() > 2 ? BPMF(components[2]) : follow; BPMF ending = components.size() > 2 ? BPMF(components[2]) : follow;
// apply the I/UE + E rule // apply the I/UE + E rule
if (head.vowelComponent() == BPMF::E && follow.vowelComponent() != BPMF::E) if (head.vowelComponent() == BPMF::E &&
{ follow.vowelComponent() != BPMF::E) {
syllable += beforeSeqHasIorUE ? head : follow; syllable += beforeSeqHasIorUE ? head : follow;
continue; continue;
} }
if (head.vowelComponent() != BPMF::E && follow.vowelComponent() == BPMF::E) if (head.vowelComponent() != BPMF::E &&
{ follow.vowelComponent() == BPMF::E) {
syllable += beforeSeqHasIorUE ? follow : head; syllable += beforeSeqHasIorUE ? follow : head;
continue; continue;
} }
// apply the J/Q/X + I/UE rule, only two components are allowed in the components vector here // apply the J/Q/X + I/UE rule, only two components are allowed in the
// components vector here
if (head.belongsToJQXClass() && !follow.belongsToJQXClass()) { if (head.belongsToJQXClass() && !follow.belongsToJQXClass()) {
if (!syllable.isEmpty()) { if (!syllable.isEmpty()) {
if (ending != follow) if (ending != follow) syllable += ending;
syllable += ending; } else {
}
else {
syllable += aheadSeqHasIorUE ? head : follow; syllable += aheadSeqHasIorUE ? head : follow;
} }
@ -346,10 +294,8 @@ namespace Taiyan {
if (!head.belongsToJQXClass() && follow.belongsToJQXClass()) { if (!head.belongsToJQXClass() && follow.belongsToJQXClass()) {
if (!syllable.isEmpty()) { if (!syllable.isEmpty()) {
if (ending != follow) if (ending != follow) syllable += ending;
syllable += ending; } else {
}
else {
syllable += aheadSeqHasIorUE ? follow : head; syllable += aheadSeqHasIorUE ? follow : head;
} }
@ -358,30 +304,30 @@ namespace Taiyan {
// the nasty issue of only one char in the buffer // the nasty issue of only one char in the buffer
if (iter == sequence.begin() && iter + 1 == sequence.end()) { if (iter == sequence.begin() && iter + 1 == sequence.end()) {
if (head.hasVowel() || follow.hasToneMarker() || head.belongsToZCSRClass()) if (head.hasVowel() || follow.hasToneMarker() ||
head.belongsToZCSRClass()) {
syllable += head; syllable += head;
else { } else {
if (follow.hasVowel() || ending.hasToneMarker()) if (follow.hasVowel() || ending.hasToneMarker()) {
syllable += follow; syllable += follow;
else } else {
syllable += ending; syllable += ending;
} }
}
continue; continue;
} }
if (!(syllable.maskType() & head.maskType()) && !endAheadOrAheadHasToneMarkKey(iter + 1, sequence.end())) { if (!(syllable.maskType() & head.maskType()) &&
!endAheadOrAheadHasToneMarkKey(iter + 1, sequence.end())) {
syllable += head; syllable += head;
} } else {
else { if (endAheadOrAheadHasToneMarkKey(iter + 1, sequence.end()) &&
if (endAheadOrAheadHasToneMarkKey(iter + 1, sequence.end()) && head.belongsToZCSRClass() && syllable.isEmpty()) { head.belongsToZCSRClass() && syllable.isEmpty()) {
syllable += head; syllable += head;
} } else if (syllable.maskType() < follow.maskType()) {
else if (syllable.maskType() < follow.maskType()) {
syllable += follow; syllable += follow;
} } else {
else {
syllable += ending; syllable += ending;
} }
} }
@ -390,24 +336,23 @@ namespace Taiyan {
// heuristics for Hsu keyboard layout // heuristics for Hsu keyboard layout
if (this == HsuLayout()) { if (this == HsuLayout()) {
// fix the left out L to ERR when it has sound, and GI, GUE -> JI, JUE // fix the left out L to ERR when it has sound, and GI, GUE -> JI, JUE
if (syllable.vowelComponent() == BPMF::ENG && !syllable.hasConsonant() && !syllable.hasMiddleVowel()) { if (syllable.vowelComponent() == BPMF::ENG && !syllable.hasConsonant() &&
!syllable.hasMiddleVowel()) {
syllable += BPMF(BPMF::ERR); syllable += BPMF(BPMF::ERR);
} } else if (syllable.consonantComponent() == BPMF::G &&
else if (syllable.consonantComponent() == BPMF::G && (syllable.middleVowelComponent() == BPMF::I || syllable.middleVowelComponent() == BPMF::UE)) { (syllable.middleVowelComponent() == BPMF::I ||
syllable.middleVowelComponent() == BPMF::UE)) {
syllable += BPMF(BPMF::J); syllable += BPMF(BPMF::J);
} }
} }
return syllable; return syllable;
} }
protected: protected:
bool endAheadOrAheadHasToneMarkKey(string::const_iterator ahead, string::const_iterator end) const bool endAheadOrAheadHasToneMarkKey(std::string::const_iterator ahead,
{ std::string::const_iterator end) const {
if (ahead == end) if (ahead == end) return true;
return true;
char tone1 = componentToKey(BPMF::Tone1); char tone1 = componentToKey(BPMF::Tone1);
char tone2 = componentToKey(BPMF::Tone2); char tone2 = componentToKey(BPMF::Tone2);
@ -418,70 +363,57 @@ namespace Taiyan {
if (tone1) if (tone1)
if (*ahead == tone1) return true; if (*ahead == tone1) return true;
if (*ahead == tone2 || *ahead == tone3 || *ahead == tone4 || *ahead == tone5) if (*ahead == tone2 || *ahead == tone3 || *ahead == tone4 ||
*ahead == tone5)
return true; return true;
return false; return false;
} }
bool sequenceContainsIorUE(string::const_iterator start, string::const_iterator end) const bool sequenceContainsIorUE(std::string::const_iterator start,
{ std::string::const_iterator end) const {
char iChar = componentToKey(BPMF::I); char iChar = componentToKey(BPMF::I);
char ueChar = componentToKey(BPMF::UE); char ueChar = componentToKey(BPMF::UE);
for (; start != end; ++start) for (; start != end; ++start)
if (*start == iChar || *start == ueChar) if (*start == iChar || *start == ueChar) return true;
return true;
return false; return false;
} }
string m_name; std::string m_name;
BopomofoKeyToComponentMap m_keyToComponent; BopomofoKeyToComponentMap m_keyToComponent;
BopomofoComponentToKeyMap m_componentToKey; BopomofoComponentToKeyMap m_componentToKey;
static const BopomofoKeyboardLayout* c_StandardLayout;
static const BopomofoKeyboardLayout* c_ETenLayout;
static const BopomofoKeyboardLayout* c_HsuLayout;
static const BopomofoKeyboardLayout* c_ETen26Layout;
static const BopomofoKeyboardLayout* c_IBMLayout;
// this is essentially an empty layout, but we use pointer semantic to tell the differences--and pass on the responsibility to BopomofoReadingBuffer
static const BopomofoKeyboardLayout* c_HanyuPinyinLayout;
}; };
class BopomofoReadingBuffer { class BopomofoReadingBuffer {
public: public:
BopomofoReadingBuffer(const BopomofoKeyboardLayout* layout) explicit BopomofoReadingBuffer(const BopomofoKeyboardLayout* layout)
: m_layout(layout) : layout_(layout), pinyin_mode_(false) {
, m_pinyinMode(false)
{
if (layout == BopomofoKeyboardLayout::HanyuPinyinLayout()) { if (layout == BopomofoKeyboardLayout::HanyuPinyinLayout()) {
m_pinyinMode = true; pinyin_mode_ = true;
m_pinyinSequence = ""; pinyin_sequence_ = "";
} }
} }
void setKeyboardLayout(const BopomofoKeyboardLayout* layout) void setKeyboardLayout(const BopomofoKeyboardLayout* layout) {
{ layout_ = layout;
m_layout = layout;
if (layout == BopomofoKeyboardLayout::HanyuPinyinLayout()) { if (layout == BopomofoKeyboardLayout::HanyuPinyinLayout()) {
m_pinyinMode = true; pinyin_mode_ = true;
m_pinyinSequence = ""; pinyin_sequence_ = "";
} }
} }
bool isValidKey(char k) const bool isValidKey(char k) const {
{ if (!pinyin_mode_) {
if (!m_pinyinMode) { return layout_ ? (layout_->keyToComponents(k)).size() > 0 : false;
return m_layout ? (m_layout->keyToComponents(k)).size() > 0 : false;
} }
char lk = tolower(k); char lk = tolower(k);
if (lk >= 'a' && lk <= 'z') { if (lk >= 'a' && lk <= 'z') {
// if a tone marker is already in place // if a tone marker is already in place
if (m_pinyinSequence.length()) { if (pinyin_sequence_.length()) {
char lastc = m_pinyinSequence[m_pinyinSequence.length() - 1]; char lastc = pinyin_sequence_[pinyin_sequence_.length() - 1];
if (lastc >= '2' && lastc <= '5') { if (lastc >= '2' && lastc <= '5') {
return false; return false;
} }
@ -490,98 +422,83 @@ namespace Taiyan {
return true; return true;
} }
if (m_pinyinSequence.length() && (lk >= '2' && lk <= '5')) { if (pinyin_sequence_.length() && (lk >= '2' && lk <= '5')) {
return true; return true;
} }
return false; return false;
} }
bool combineKey(char k) bool combineKey(char k) {
{ if (!isValidKey(k)) return false;
if (!isValidKey(k))
return false;
if (m_pinyinMode) { if (pinyin_mode_) {
m_pinyinSequence += string(1, tolower(k)); pinyin_sequence_ += std::string(1, tolower(k));
m_syllable = BPMF::FromHanyuPinyin(m_pinyinSequence); syllable_ = BPMF::FromHanyuPinyin(pinyin_sequence_);
return true; return true;
} }
string sequence = m_layout->keySequenceFromSyllable(m_syllable) + string(1, k); std::string sequence =
m_syllable = m_layout->syllableFromKeySequence(sequence); layout_->keySequenceFromSyllable(syllable_) + std::string(1, k);
syllable_ = layout_->syllableFromKeySequence(sequence);
return true; return true;
} }
void clear() void clear() {
{ pinyin_sequence_.clear();
m_pinyinSequence.clear(); syllable_.clear();
m_syllable.clear();
} }
void backspace() void backspace() {
{ if (!layout_) return;
if (!m_layout)
return;
if (m_pinyinMode) { if (pinyin_mode_) {
if (m_pinyinSequence.length()) { if (pinyin_sequence_.length()) {
m_pinyinSequence = m_pinyinSequence.substr(0, m_pinyinSequence.length() - 1); pinyin_sequence_ =
pinyin_sequence_.substr(0, pinyin_sequence_.length() - 1);
} }
m_syllable = BPMF::FromHanyuPinyin(m_pinyinSequence); syllable_ = BPMF::FromHanyuPinyin(pinyin_sequence_);
return; return;
} }
string sequence = m_layout->keySequenceFromSyllable(m_syllable); std::string sequence = layout_->keySequenceFromSyllable(syllable_);
if (sequence.length()) { if (sequence.length()) {
sequence = sequence.substr(0, sequence.length() - 1); sequence = sequence.substr(0, sequence.length() - 1);
m_syllable = m_layout->syllableFromKeySequence(sequence); syllable_ = layout_->syllableFromKeySequence(sequence);
} }
} }
bool isEmpty() const bool isEmpty() const { return syllable_.isEmpty(); }
{
return m_syllable.isEmpty(); const std::string composedString() const {
if (pinyin_mode_) {
return pinyin_sequence_;
} }
const string composedString() const return syllable_.composedString();
{
if (m_pinyinMode) {
return m_pinyinSequence;
} }
return m_syllable.composedString(); const BPMF syllable() const { return syllable_; }
const std::string standardLayoutQueryString() const {
return BopomofoKeyboardLayout::StandardLayout()->keySequenceFromSyllable(syllable_);
} }
const BPMF syllable() const const std::string absoluteOrderQueryString() const {
{ return syllable_.absoluteOrderString();
return m_syllable;
} }
const string standardLayoutQueryString() const bool hasToneMarker() const { return syllable_.hasToneMarker(); }
{
return BopomofoKeyboardLayout::StandardLayout()->keySequenceFromSyllable(m_syllable);
}
const string absoluteOrderQueryString() const
{
return m_syllable.absoluteOrderString();
}
bool hasToneMarker() const
{
return m_syllable.hasToneMarker();
}
protected: protected:
const BopomofoKeyboardLayout* m_layout; const BopomofoKeyboardLayout* layout_;
BPMF m_syllable; BPMF syllable_;
bool m_pinyinMode; bool pinyin_mode_;
string m_pinyinSequence; std::string pinyin_sequence_;
}; };
} } // namespace Mandarin
} } // namespace Taiyan
#endif #endif // MANDARIN_H_

File diff suppressed because it is too large Load Diff