1 | #ifndef CODEC_H |
---|
2 | #define CODEC_H |
---|
3 | |
---|
4 | #include <QString> |
---|
5 | #include <QList> |
---|
6 | |
---|
7 | namespace QPunchCard { |
---|
8 | class Codec; |
---|
9 | } |
---|
10 | |
---|
11 | // der define ist fuer cardcodes.h |
---|
12 | #define ERROR -5 |
---|
13 | |
---|
14 | #include "qpunchcard/card.h" |
---|
15 | #include "qpunchcard/deck.h" |
---|
16 | |
---|
17 | namespace QPunchCard { |
---|
18 | |
---|
19 | /** |
---|
20 | * Abstracte Codec-Klasse. Implementierungen muessen toAscii/fromAscii |
---|
21 | * implementieren und sollten canEncode() implementieren. Fuer Namenszuordnung |
---|
22 | * und fortgeschrittene Erstellung ist CodecFactory zustaendig. |
---|
23 | **/ |
---|
24 | class Codec { |
---|
25 | public: |
---|
26 | // soll const sein, weil Codec unveraenderbar *immer* das gleiche |
---|
27 | // Ergebnis liefern soll, nach Erzeugung. Das ist auch noetig fuer |
---|
28 | // CharArrayCodec. |
---|
29 | const char illegal; |
---|
30 | /// @param illegal_character Zeichen fuer nicht existente Zahlen |
---|
31 | Codec(char illegal_character = '~') : illegal(illegal_character) {} |
---|
32 | Codec(const Codec& other) : illegal(other.illegal) {} |
---|
33 | virtual ~Codec() {} |
---|
34 | virtual char toAscii(const Column* col) const = 0; |
---|
35 | virtual QString toAscii(const Card* target_card) const; |
---|
36 | virtual Column fromAscii(char ch) const = 0; |
---|
37 | void fromAscii(const QString& string, Card* target_card) const; |
---|
38 | |
---|
39 | virtual bool canEncode(const Column* col) const { return toAscii(col) != illegal; } |
---|
40 | virtual bool canEncode(char /*char*/ ) const = 0; |
---|
41 | bool canEncode(const QString& string) const; |
---|
42 | |
---|
43 | int countIllegalColumns(const Card* card) const; |
---|
44 | int countIllegalColumns(const Deck* deck) const; |
---|
45 | }; |
---|
46 | |
---|
47 | /** |
---|
48 | * Codec-Implementierung, der mithilfe von hardgecodeten Codetabellen |
---|
49 | * (von Douglas Jones uebernommen) eine Umwandlung char->Column und andersrum |
---|
50 | * durchfuehren kann. Letzteres geht genauso perfomant dank 4kb grosser |
---|
51 | * inverser Tabelle, die bei Objektkonstruktion angelegt wird. |
---|
52 | **/ |
---|
53 | class CharArrayCodec : public Codec { |
---|
54 | class Data { |
---|
55 | public: |
---|
56 | const int* table; |
---|
57 | char inverse_table[4096]; |
---|
58 | int ref; |
---|
59 | }; |
---|
60 | |
---|
61 | Data* d; |
---|
62 | |
---|
63 | public: |
---|
64 | CharArrayCodec(const int* table, char illegal = '~');// : Codec(illegal), table(table) {} |
---|
65 | CharArrayCodec(const CharArrayCodec& other) : Codec(other) { |
---|
66 | d = other.d; |
---|
67 | d->ref++; |
---|
68 | } |
---|
69 | ~CharArrayCodec() { if(--d->ref == 0) delete d; } |
---|
70 | char toAscii(const Column* col) const { return d->inverse_table[*col]; } |
---|
71 | Column fromAscii(char ch) const { return Column(canEncode(ch) ? d->table[ch]: 0); } |
---|
72 | |
---|
73 | bool canEncode(const Column* col) const { return d->inverse_table[*col] != illegal; } |
---|
74 | bool canEncode(char ch) const { |
---|
75 | bool r = (d->table[ch] != ERROR); |
---|
76 | if(ch < ' ' || ch > 'z') r = false; |
---|
77 | //qDebug("CharArrayCodec: %c is a %s character", ch, r ? "valid" : "invalid"); |
---|
78 | return r; } |
---|
79 | }; |
---|
80 | |
---|
81 | /** |
---|
82 | * Factory-Klasse, die alle bekannten Codecs zurueckgeben kann. Wesentliches |
---|
83 | * Merkmal ist die Faehigkeit, mit Namen (QStrings) von Codecs umgehen zu |
---|
84 | * koennen und Codecs aus Namen erstellen zu koennen. Ausserdem gibt es |
---|
85 | * Algorithmen zum Finden des bestmoeglichen Codecs zu einer Card/einem Deck, |
---|
86 | * die mit Codec:countIllegalColumns() arbeitet. |
---|
87 | **/ |
---|
88 | class CodecFactory { |
---|
89 | static QHash<QString, Codec*> codec_cache; |
---|
90 | public: |
---|
91 | // TODO: Codec-Caching (Codec-Constructor privatisieren, dafuer hier caching |
---|
92 | // betreiben) weil einige codecs recht teuer zu erstellen sind (CharArrayCodec) |
---|
93 | static QList<QString> availableCodecs(); |
---|
94 | static const Codec* createCodec(const QString& name, char illegal_character = '~'); |
---|
95 | static const QString autoDetectCodec(const Card* card); |
---|
96 | static const QString autoDetectCodec(const Deck* deck); |
---|
97 | }; |
---|
98 | |
---|
99 | }; // Namespace |
---|
100 | #endif // CODEC_H |
---|