2010/03/26

QT

Właśnie skończyłem się bawić mała aplikacyjna w QT, która miała za zadanie wyświetlać dane z bazy PostgreSQL. Jestem zaskoczony jak szybko i łatwo pisze się aplikacje w QT. Po przejściach z pracą dyplomowa i .Net jestem w stanie się założyć o każde pieniądze że to co do tej pory robiłeś w .Net w QT zrobisz 2 razy szybciej. Oto dowód, kompletna aplikacja do edycji danych z poprzez ODBC w formie podobnej do arkuszu kalkulacyjnego Excel. 85 linij kodu źródłowego.


class EditableSqlModel : public QSqlQueryModel
{
Q_OBJECT

public:
EditableSqlModel(QObject *parent = 0);

Qt::ItemFlags flags(const QModelIndex &index) const;
bool setData(const QModelIndex &index, const QVariant &value, int role);

private:
void refresh();
};

int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
db.setDatabaseName("PostgreSQL_ip");

if (!db.open()) {
QMessageBox::critical(0, qApp->tr("Cannot open database"),
qApp->tr("Unable to establish a database connection.\n", QMessageBox::Cancel);
return -1;

EditableSqlModel editableModel;
QTableView *view = new QTableView;
view->setModel(editableModel);
view->setWindowTitle("Okno do edytowania");
view->show();

return app.exec();
}

EditableSqlModel::EditableSqlModel(QObject *parent) : QSqlQueryModel(parent)
{
refresh();
}

Qt::ItemFlags EditableSqlModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags flags = QSqlQueryModel::flags(index);
if (index.column() >= 1 && index.column() <= 4) flags |= Qt::ItemIsEditable; return flags; } bool EditableSqlModel::setData(const QModelIndex &index, const QVariant &value, int /* role */) { if (index.column() < 1 || index.column() > 4) return false;

QModelIndex primaryKeyIndex = QSqlQueryModel::index(index.row(), 0);
int pkey = data(primaryKeyIndex).toInt();

clear();

bool ok;
QSqlQuery query;
if( 1 == index.column() )
{
query.prepare("update users set parrent = ? where id = ?");
query.addBindValue(value.toInt());
query.addBindValue(pkey);
}
else
{
switch( index.column() )
{
case 2: query.prepare("update users set login = ? where id = ?"); break;
case 3: query.prepare("update users set first = ? where id = ?"); break;
case 4: query.prepare("update users set last = ? where id = ?"); break;
}
query.addBindValue(value.toString());
query.addBindValue(pkey);
}
ok = query.exec();

refresh();
return ok;
}

void EditableSqlModel::refresh()
{
setQuery("select * from users");
}

2010/03/25

Shared Memory

Swego czasu miałem w mojej pracy pewien epizod związany z przekonaniem kolegów do używania pamięci współdzielonej. Jako że był to bardzo oporny proces postanowiłem obrócić go w mały żart :)

2010/03/24

Ligatury

Oto garść informacji o ligaturach.
http://pl.wikipedia.org/wiki/Ligatura_(pismo)

A poniżej (w języku ang.) krótkie streszczenie problemu który napotkałem w mojej pracy w związku z porównywaniem ciągów znakowych zawierających sekwencje znaków z których dana ligatura się składa. Problem polega na tym że klient chce aby litery składowe ligatury były traktowane jako ligatura, co nie jest jednoznaczne, ponieważ takie sekwencje znaków mogą równie dobrze nie tworzyć ligatury, tylko występować swobodnie.

Question: wcscoll does not see that "ß" is equal to "ss" as customer whants


[usr@serv ~]$ export LC_ALL="de_DE.UTF-8"
[usr@serv ~]$ echo "ä" | iconv -f ISO88592 -t ASCII//TRANSLIT
ae
[usr@serv ~]$ echo "ß" | iconv -f ISO88592 -t ASCII//TRANSLIT
ss


wcscoll will not tell that “ß” and “ss” are the same, because that are two different string (coded in UCS). The point is that you don’t know if "ss" means "ss" or "ß" in that place.

The matter of ä = ae ; ss = ß is that in ASCII you cannot code the ß without using special code page. And without special chatters you cannot code all ligatures that occur in specific language. So you use the “replacement” for those chars. Going from ligature into replacement is easy, but the reverse path is not!. It is the same if the “&” sign will be not in ASCII table and you will code it as “et” (that is really the source of & character anyway, combining ‘e’ and ‘t’ – creates a ligature). But no one wants to threat “et” to be equal & because that’s not make sense, they are two different strings.

Kilka przykladowych ligatur:
et & U+0026
At @ U+0040
ſs (lub ſz) ß U+00DF
AE, ae Æ, æ U+00E6, U+00C6
OE Œ, œ, ɶ U+0152, U+0153, U+276
IJ, ij IJ U+0132, U+0133
Ng, ng Ŋ, ŋ U+014A, U+14B
Hv (Hw), hv (hw) Ƕ, ƕ U+01F6, U+0195
DŽ, Dž, dž DŽ, Dž, dž U+01C4, U+01C5, U+01C6 (*)
LJ, Lj, lj LJ, Lj, lj U+01C7, U+01C8, U+01C9 (*)
NJ, Nj, nj NJ, Nj, nj U+01CA, U+01CB, U+01CC (*)
DZ, Dz, dz DZ, Dz, dz, ʣ U+01F1, U+01F2, U+01F3, U+02A3 (*)
lʒ ɮ U+026E
dʒ ʤ U+02A4
dʑ ʥ U+02A5
ts ʦ U+02A6

2010/03/22

Sortowanie leksykograficzne

Z pozoru sortowanie napisów to prosty algorytm. Ot porównujemy sobie literki a każda z nich ma jakich kod, więc można je uszeregować. Hmmm ... i tu wychodzi uwstecznienie polonistyczne. Po pierwsze w grę wchodzą polskie litery, dalej mamy przecież wiele języków, więc musimy pamiętać też o znakach Niemieckich, Czeskich, Francuskich itd (specjalnie nie wymieniłem Chińskiego :D). To nie koniec. Co ze znakami takimi jak spacja i pauza ? Co z dwuznakami i ligaturami ? (Np Niemiecki "umlaut" (SS)).

Chwilowo myślałem więc że problem ten powiązany jest z kodowaniem znaków (np Unicode lub ASCI). Dopiero gdy zauważyłem że każdy język na świecie ma własne zasady ortografii i gramatyki tak więc nie ma czegoś takiego jak jedna kolejność znaków. Innymi słowy gdyby spisać wszystkie nazwy miast na świecie w ich oryginalnej pisowni i posortować je wg zasad Niemieckich, Francuz powiedział by że ta kolejność jest nieprawidłowa. Tak więc jeśli każdemu znakowi przypiszemy unikalną liczbę (co zresztą robi Unicode) to i tak kolejność sortowania nie jest zdefiniowana bez podania konkretnego języka wg zasad którego będziemy sortować. Jak widać kodowanie znaków dla maszyny cyfrowej jest całkiem odrębnym problemem.

Generalnie po kilku godzinach spędzonych nad tematem dogrzebałem się do jednego wniosku: Sortowanie napisów to bardzo skomplikowany problem. Nawet istnieje generalny standard:
http://www.unicode.org/reports/tr10/

Oraz narzędzia do testowania implementacji:
http://demo.icu-project.org/icu-bin/locexp?_=en_US&d_=en&x=col

W szczególności zacytuje poniższy fragment opisujący najczęstsze nieporozumienia wokoło sortowania napisów:
There are a number of common misperceptions about collation.

1. Collation is not aligned with character sets or repertoires of characters. Swedish and German share most of the same characters, for example, but have very different sorting orders.
2. Collation is not code point (binary) order. The simplest case of this is capital Z versus lowercase a. As noted above, beginners may complain about Unicode that a particular character is “not in the right place in the code chart”. That is a misunderstanding of the role of the character encoding in collation. While the Unicode Standard does not gratuitously place characters such that the binary ordering is odd, the only way to get the linguistically-correct order is to use a language-sensitive collation, not a binary ordering.
3. Collation is not a property of strings. Consider a list of cities, with each city correctly tagged with its language. Despite this, a German user will expect to see the cities all sorted according to German order, and not expect to see a word with ö appear after z, simply because the city has a Swedish name. As mentioned above it is of crucial importance that if a German businessman makes a database selection, such as to sum up revenue in each of of the cities from O... to P... for planning purposes, then cities starting with Ö must not be excluded.
4. Collation order is not preserved under concatenation or substring operations, in general. For example, the fact that x is less than y does not mean that x + z is less than y + z. This is because characters may form contractions across the substring or concatenation boundaries. In summary, the following shows which implications not to expect.

x < y does not imply that x+z 
y+z x < y does not imply that z+x < z+y 
x+z < y+z does not imply that x < y 
z+x < z+y does not imply that x < y

5. Collation order is not preserved when comparing sort keys generated from different collation sequences. Remember that sort keys are a preprocessing of strings according to a given set of collation features. From different features, you will get different binary sequences. For example, suppose we have two collations, F and G, where F is a French collation (with accents compared from the end), and G is a German phonebook ordering. Then:
* A ? B according to F if and only if sortkey(F, A) ? sortkey(F, B), and
* A ? B according to G if and only if sortkey(G, A) ? sortkey(G, B)
* But the relation between sortkey(F, A) and sortkey(G, B) says nothing about whether A ? B according to F, or whether A ? B according to G.
6. Collation order is not a stable sort; that is a property of a sort algorithm, not a collation sequence. For more information, see Section 3.4, Stability.
7. Collation order is not fixed. Over time, collation order will vary: there may be fixes that are discovered as more information becomes available about languages; there may be new government or industry standards for the language that require changes; and finally, the new characters that are added to Unicode periodically will interleave with the previously-defined ones. Thus collations must be carefully versioned.

Jeszcze co nieco po Polsku w temacie: http://www.eioba.pl/a87655/sortowanie_leksykograficzne

2010/03/16

NoSQL

Właśnie natknąłem się na coś takiego jak NoSQL:
http://nosql-database.org/
http://en.wikipedia.org/wiki/NoSQL

Spodobał mi się też komentarz:
http://www.linuxjournal.com/article/3294

... almost all [database systems] are software prisons that you must get into and leave the power of UNIX behind. [...] The resulting database systems are large, complex programs which degrade total system performance, especially when they are run in a multi-user environment. [...] UNIX provides hundreds of programs that can be piped together to easily perform almost any function imaginable. Nothing comes close to providing the functions that come standard with UNIX.

The UNIX file structure is the fastest and most readily-available database engine ever built: directories may be viewed as catalogs and tables as plain ASCII files. Commands are common UNIX utilities, such as grep, sed and awk. Nothing should be reinvented.

2010/03/12

Pierwszy post

Czy zawsze aktywujesz ostrzeżenia kompilatora ? Poniższy przykład pokazuje dlaczego są one niezbędne:


int i;
...
if( i < sizeof(int) ) {
   ...
}


Powyższy kod będzie działał tak jak zamierzamy, jeśli "i" będzie przyjmować jedynie wartości dodatnie. Jeśli w "i" znajdzie się liczba ujemna, warunek nie zostanie spełniony, choć matematycznie wszystko wygląda OK. Wynika to z faktu że porównywanie typow signed i unsigned wymusza na kompilatorze rzutowanie do typu unsigned. Z tąd liczba ze znakiem int jest rzutowana do unsigned int. Jak łatwo się domyśleć z -1 robi się 4294967295, co jasno pokazuje ze -1 > 4 :)

Aby otrzymac ostrzeżenie przed tego typu pomyłkami należy w gcc dodać opcje -Wsign-compare lub najlepiej -Wextra która ostrzega nas przed kilkoma innymi błędami. -Wextra jest rozszerzeniem -Wall, samo -Wall nie zawiera -Wsign-compare.

Po dodaniu Wextra prawdopodobnie otrzymamy szereg ostrzeżeń które będziemy chcieli usunąć. Jednym z takich ostrzeżeń są nieużywane parametry funkcji. Jest to dość irytujące ponieważ często zdarza się że celowo nie chcemy wykorzystywać wszystkich parametrów, choćby ze względu na wymuszony format funkcji potrzebnej do wywołania zwrotnego (callback). W takim wypadku możemy posłużyć się poniższym makrem:


#ifdef unused
#elif defined(__GNUC__)
# define unused(x) UNUSED_ ## x __attribute__((unused))
#elif defined(__LCLINT__)
# define unused(x) /*@unused@*/ x
#else
# define unused(x) x
#endif


np:


int fkt(int unused(opt_param)) {
}


Makro można rozszerzyć o obsługę dodatkowych kompilatorów, tak jak zostało to wykonane dla parsera składni LINT.