knihovna glib

41
Knihovna GLib Multiplatformní nástavba standardní C knihovny (běží na Windows, Linux, Mac, ...) Naleznete zde nástroje pro komfortní práci s řetězci a poli proměnné velikosti, práci se seznamy, stromy, hashovacími tabulkami či poměrně komplikovanými metodami jako je použití vláken (threads), run-time zavádění modulů (plug-inů) a tak dále... Nahrazuje některé funkce C knihovny a garantuje jejich existenci Každý zdrojový soubor využívající funkce knihovny GLib - musí mít na začátku hlavičkový soubor: #include <glib.h> - musí být nalinkován ke GLib knihovně, zjednodušeně (linux – spustitelný soubor): gcc `glib-config –cflags` `glib-config –libs` test.c -o test

Upload: fagan

Post on 16-Jan-2016

54 views

Category:

Documents


0 download

DESCRIPTION

Multiplatformní nástavba standardní C knihovny (běží na Windows, Linux, Mac, ...) - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Knihovna GLib

Knihovna GLib● Multiplatformní nástavba standardní C knihovny (běží na Windows, Linux, Mac, ...)

● Naleznete zde nástroje pro komfortní práci s řetězci a poli proměnné velikosti, práci se seznamy, stromy, hashovacími tabulkami či poměrně komplikovanými metodami jako je použití vláken (threads), run-time zavádění modulů (plug-inů) a tak dále...

● Nahrazuje některé funkce C knihovny a garantuje jejich existenci

● Každý zdrojový soubor využívající funkce knihovny GLib- musí mít na začátku hlavičkový soubor:

#include <glib.h>

- musí být nalinkován ke GLib knihovně, zjednodušeně (linux – spustitelný soubor):

gcc `glib-config –cflags` `glib-config –libs` test.c -o test

Page 2: Knihovna GLib

GLib – Základní datové typy● GLib definuje svoje datové typy odpovídající standardním C typům + některé vlastní.

● GLib definuje Boolean:gboolean – může nabývat hodnot TRUE nebo FALSE

● Vše co pochází z GLib knihovny začíná písmenem G, tento zvyk se dodržuje a u jiných knihoven se většinou setkáme s podobnou vlastností.

Page 3: Knihovna GLib

GLib – práce s pamětí● Pro práci s dynamickou pamětí najdeme v Glib ekvivalenty funkcí malloc() a free() +

jejich rozšířené verze v podobě maker:● g_new(type, count);

Toto makro alokuje paměť pro count prvků typu type. Vrácený pointer je přetypován na pointer na daný typ. Jestliže je count rovno 0, vrátí NULL.Př: int *a = g_new(int, 10); /* alokuje 10 * sizeof(int) */

● g_new0(type, count);Jako předchozí, navíc nastavý alokovanou paměť na samé nuly.

● gpointer g_malloc(gulong size);je obdobou předchozích maker. g_malloc() alokuje size bajtů paměti a vrátí pointer na ni. Je-li size rovno 0, vrátí NULL.

● gpointer g_malloc0(gulong size);alokuje size bajtů paměti, které následně všechny nastaví na hodnotu 0. Vrátí pointer na alokovanou paměť. V případě, že size je 0, vrátí NULL.

● Alokovanou paměť je občas třeba realokovat, a ktomu nám slouží tyto dvě makra:g_renew(type, mem, count);realokuje paměť, na kterou ukazuje pointer mem tak, že nyní je v ní místo pro count prvků typu type. Makro vrátí novou adresu, na které se teď proměnná nachází.gpointer g_realloc(gpointer mem, gulong size);tato funkce realokuje paměť reprezentovanou pointerem mem na velikost size bajtů. Vrátí novou adresu paměti, protože je pravděpodobné, že se při této operaci změní.

Page 4: Knihovna GLib

GLib – práce s pamětí● Každá alokovaná paměť musí být uvolněna a k tomu máme jen jednu funkci:void g_free(gpointer mem);která uvolní místo, na které ukazuje pointer mem.

● Takže GLib definuje svoje funkce pro alokaci paměti a pokud náš program úplně stavíme na GLib, tak bysme měli použít tyto funkce, ale nezapomeňme, že to jsou pouze makra, které volají nám již známé funkce malloc(),free() a realloc().

● Glib navíc garantuje funkci, kterou ve standardní C knihovně nenajdeme:gpointer g_memdup(gconstpointer mem, guint byte_size);alokuje byte_size bajtů a zkopíruje do nich byte_size bajtů z mem. Je-li mem rovno NULL, jednoduše vrátí NULL. Jinak vrátí pointer na nově alokovanou oblast paměti.

● Všechny funkce knihovny GLib při alokaci paměti testují úspěšnost operace. V případě neúspěchu aplikace okamžitě končí. Znamená to tedy, že není třeba testovat, zda-li bylo volání funkce úspěšné a paměť se správně alokovala.

příklad:unsigned char *a = g_new(unsigned char, (1024*768) << 2);if (!a) { !!!TADY SE APLIKACE NIKDY NEDOSTANE!!! }

Page 5: Knihovna GLib

GLib – práce s cestami k souborům● gchar* g_basename(const gchar *file_name)

vrátí jméno souboru bez předcházející adresářové složky. Vrácený řetězcový pointer ukazuje přímo doprostřed argumentu file_name

● gchar* g_dirname(const gchar *file_name);vrátí adresářovou složku jména souboru file_name. Pokud file_name neobsahuje cestu i s adresáři, použije se jako návratová hodnota řetězec ".". Vrácená hodnota by měla být po použití dealokována

● gboolean g_path_is_absolute(const gchar *file_name);vrátí TRUE, jestliže je jméno souboru file_name absolutní, tj. rozhodne, jestli obsahuje plnou cestu z kořenového adresáře. (Např. "/usr/local" v Unixech nebo "C:\WINDOWS\SYSTEM" ve Windows.)

● gchar* g_path_skip_root(gchar *file_name);vrátí pointer na jméno souboru file_name těsně za označením kořenového adresáře, tj. za lomítkem (/) v Unixech a za C:\ ve Windows. Jestliže file_name není absolutní jméno souboru, funkce předá NULL.

● gchar* g_get_home_dir(void);● gchar* g_get_tmp_dir(void);● gchar* g_get_current_dir(void);

Funkce hledají zmíněné informace v proměnných prostředí HOME (ve Windows NT i HOMEDRIVE a HOMEPATH), TMPDIR, TMP, TEMP..

Page 6: Knihovna GLib

GLib – práce s cestami k souborům● Pro ještě větší přenositelnost kódu GLib definuje oddělovače adresářů a cest, jsou to

konstantní makra:

● #define G_DIR_SEPARATOR● #define G_DIR_SEPARATOR_S

G_DIR_SEPARATOR je na Unixech roven '/' a ve Windows '\'. V makru G_DIR_SEPARATOR_S je definováno totéž, ale jako řetězec (tedy "/" a "\").

● #define G_SEARCHPATH_SEPARATOR● #define G_SEARCHPATH_SEPARATOR_S

G_SEARCHPATH_SEPARATOR uchovává oddělovač cest v proměnné prostředí PATH. V Unixu je to dvojtečka (':') a ve Windows středník (';'). Potřebujete-li oddělovač cest zapsaný jako řetězec, sáhněte po G_SEARCHPATH_SEPARATOR_S.

Page 7: Knihovna GLib

GLib – pole (arrays)● Pole (arrays) knihovny GLib jsou podobné polím ze standardního jazyka C. Jejich

předností však je, že se automaticky zvětšují s tím, jak do nich přidáváte nové prvky. Přístup k těmto polím je velice podobný přístupu k automaticky rostoucím řetězcům GString - vždyť také mají mnoho společného. "Nafukovací" pole knihovny GLib jsou definovány strukturou GArray:struct GArray { gchar *data; guint len;}Prvek data je pointer na informace uložené v poli a můžete k němu přistupovat jako ke standardnímu céčkovskému poli. Jak se však bude pole zvětšovat, bude se měnit.

● GArray* g_array_new(gboolean zero_terminated, gboolean clear, guint element_size);Argument zero_terminated nastavte na TRUE, chcete-li, aby pole mělo vždy na svém konci vynulovaný prvek (aby bylo ukončeno nulovým ('0') prvkem). Jinak použijte hodnotu FALSE.Chcete-li, aby byly všechny nově alokované položky vynulovány zvolte jako argument clear hodnotu TRUEFunkce vrátí pointer na nově alokovaný GArray, který musí být zrušen voláním g_array_free().

Page 8: Knihovna GLib

GLib – pole (arrays)● void g_array_free(GArray *array, gboolean free_segment);

Je-li free_segment nastaven na TRUE, uvolní se také data udržované polem array. Je-li naopak free_segment roven FALSE, můžete data i nadále používat jako obyčejné céčkovské pole (Nesmíte však zapomenout je nakonec uvolnit voláním g_free()!).

● #define g_array_append_val(array, v)vytvoří na konci pole array nový prvek a zkopíruje do něj hodnotu v. GArray svou velikost podle potřeby zvětší. Makro vrátí hodnotu argumentu array.g_array_append_val() je ve skutečnosti makro, kterým voláte funkci g_array_append_vals(). Používá se v něm reference na v, což znamená, že v MUSÍ být proměnná (a ne konstanta, jako např. "96").

● GArray* g_array_append_vals(GArray *array, gconstpointer data, guint len);Tato funkce vloží len prvků pole data na konec dynamického pole array. data je tedy pointer na první položku, která se má do pole přidat a len je počet těchto položek. GArray array se podle potřeby automaticky zvětší.

● #define g_array_prepend_val(array, v)● GArray* g_array_prepend_vals(GArray *array, gconstpointer data, guint len);makro a funkce, které dělají totéž co makro g_array_append_val() a funkce g_array_append_vals() s tím rozdílem, že položky nepřidávají na konec, ale na začátek pole array.

Page 9: Knihovna GLib

GLib – pole (arrays)● #define g_array_insert_val(array, index, data)● GArray* g_array_insert_vals(GArray *array, guint index, gconstpointer data, guint len);Makro a funkce, které se postarají o vložení len prvků z adresy data na index-tou pozici v dynamickém poli array. data je tedy pointer na první vkládaný prvek, len je počet prvků (v případě použití makra g_array_insert_val() je len=1) a index je místo v poli array, kam se položky umístí. Prvky pole array za tímto indexem se pochopitelně automaticky posunou, aby udělaly pro nově vkládané položky místo a GArray podle potřeby zvětší svou velikost tak, aby mohl pojmout všechny údaje.

● GArray* g_array_remove_index(GArray *array, guint index);Odstraní z dynamického pole array položku s indexem index. Vzniklá mezera se vyplní posunutím zbývajících prvků pole na její místo. Funkce zachovává pořadí prvků. Vrácenou hodnotou je pointer na GArray.

● Array* g_array_remove_index_fast(GArray *array, guint index);Jak již název napovídá, půjde o rychlejší variantu funkce na odstranění položky z pole array. Čas na vykonání operace se ušetří tak, že po odstranění položky s indexem index se místo posouvání zbývajících prvků do vzniklé mezery přesune poslední prvek pole. Funkce g_array_remove_index_fast() proběhne o něco rychleji než funkce g_array_remove_index(), její nevýhodou však je, že nezachovává pořadí prvků v poli. To ji tedy předurčuje k použití pouze tam, kde tato vlastnost nevadí (kde nezáleží na pořadí položek v poli a je jedno, jaký index prvky mají).

Page 10: Knihovna GLib

GLib – pole (arrays)● K přístupu k položkám dynamických polí můžete použít makro#define g_array_index(a,t,i) (((t*) (a)->data) [(i)])Toto makro v podstatě zastřešuje a zpřehledňuje práci s položkou data struktury GArray.

Malí příklad:/* prirazeni hodnoty 5. polozce pole */g_array_index(array, gint, 5) = 0;

/* prace s polozkou number struktury MyStruct,ktera je 7. prvkem pole

typedef struct { int number } MyStruct;*/g_array_index(array, MyStruct, 7).number = 12;

/* ziskani pointeru na 3. polozku pole typu gfloat */gfloat *p = &(g_array_index(array, gfloat, 3));

Page 11: Knihovna GLib

GLib – pole (závěr)● Pomocí GArray můžeme vytvožit libovolně rostoucí pole jakéhokoliv typu, ale Glib nabízí

pro speciální účely ještě např:GPtrArray – pole pro práci s pointery - gpointerGByteArray – pole pro práci s typem unsigned char (nebo guint8)

● Funkce těchto dvou polí se nijak neliší, jsou optimalizované a přizpůsobené pro daný typ (gpointer nebo guint8).

● GByteArray* g_byte_array_new(void);● GByteArray* g_byte_array_append(GByteArray *array, const guint8 *data, guint len);● GByteArray* g_byte_array_prepend(GByteArray *array, const guint8 *data, guint len);● GByteArray* g_byte_array_set_size(GByteArray *array, guint length);● GByteArray* g_byte_array_remove_index(GByteArray *array, guint index);● GByteArray* g_byte_array_remove_index_fast(GByteArray *array, guint index);● #define g_byte_array_index(a,i) (((guint8*) (a)->data) [(i)])● void g_byte_array_free(GByteArray *array, gboolean free_segment);

● GPtrArray* g_ptr_array_new(void);● void g_ptr_array_add(GPtrArray *array, gpointer data);● void g_ptr_array_set_size(GPtrArray *array, gint length);● gboolean g_ptr_array_remove(GPtrArray *array, gpointer data);● gpointer g_ptr_array_remove_index(GPtrArray *array, guint index);● gboolean g_ptr_array_remove_fast(GPtrArray *array, gpointer data);● gpointer g_ptr_array_remove_index_fast(GPtrArray *array, guint index);● #define g_ptr_array_index(array,index)● void g_ptr_array_free(GPtrArray *array, gboolean free_seg);

Page 12: Knihovna GLib

GLib – řetězce● Glib nám nabízí funkce pro práci se standardními C řetězci. Definuje některé funkce

ekvivalentní knihovně C + některé své. Funkce byly vytvořeny z důvodů bezpečnosti a přenositelnosti. Do všech typů funkce (g_)printf() můžeme vložit formát ve formě pozičních argumentů, malý příklad: char *text = g_strdup_printf(“%2$d, %1$d\n“, 1, 2); printf(text); g_free(text); /* vystup bude: 2, 1 */

● Funkce, které vytvoří nový řetězec:gchar* g_strdup(const gchar *str);gchar* g_strndup(const gchar *str, guint n);gchar* g_strnfill(guint length, gchar fill_char); gchar* g_strdup_printf(const gchar *format, ...);gchar* g_strdup_vprintf(const gchar *format, va_list args);gint g_snprintf(gchar *string, gulong n, const gchar *format, ...);gint g_vsnprintf(gchar *string, gulong n, const gchar *format, va_list args);guint g_printf_string_upper_bound(const gchar *format, va_list args); (vypočítá a vrátí maximální velikost paměti, které je třeba k uložení výstupu)

● Funkce, které porovnávají řetězce (bez rozlišení velkých a malých písmen):gint g_strcasecmp(const gchar *s1, const gchar *s2);gint g_strncasecmp(const gchar *s1, const gchar *s2, guint n);

● Různé:void g_strup(gchar *string); převede řetězec na velké písmenavoid g_strdown(gchar *string); převede řetězec na malé písmenavoid g_strreverse(gchar *string); převrátí řetězec (znaky)gdouble g_strtod(const gchar *nptr, gchar **endptr); převede na double

Page 13: Knihovna GLib

GLib – řetězce● Odstraňování bílých znaků:● gchar* g_strchug(gchar *string);

Odstraní všechny bílé znaky (white spaces) ze začátku řetězce string. Zbývající znaky posune na začátek tak, aby vyplnily vzniklou mezeru. Vrátí string.

● gchar* g_strchomp(gchar *string);Odstraní všechny bílé znaky (white spaces) z konce řetězce string. Vrátí string.

● #define g_strstrip(string)Makro, které odstraní všechny bílé znaky (white spaces) ze začátku i konce řetězce.

● Spojování řetězců dohromady:● gchar* g_strconcat(const gchar *string1, ...);

Spojí všechny řetězce, zapsané jako argumenty funkce, dohromady. Řetězce zapisujte jako argumenty postupně za sebou v takovém pořadí, v jakém je chcete spojit. Posledním prvkem musí být vždy NULL. Výsledný, nově alokovaný řetězec funkce použije jako návratovou hodnotu. Vrácený řetězec je třeba po použití dealokovat. Vstupní řetězce zůstanou nedotčeny.

● gchar* g_strjoin(const gchar *separator, ...);Tato funkce spojí všechny řetězce, zadané jako argumenty ..., dohromady. Mezi každé dva vloží volitelný řetězec separator. Je-li separator roven NULL, mezi řetězce se nebude vkládat nic (analogie s funkcí g_strconcat()). Posledním prvkem v seznamu argumentů (řetězců) musí být NULL. Vrácený řetězec je výsledek operace sloučení. Je nově alokovaný v paměti a proto by měl být po použití dealokován.

Page 14: Knihovna GLib

GLib – řetězce● Nahrazení znaků v řetězci:● gchar* g_strdelimit(gchar *string, const gchar *delimiters, gchar new_delimiter);funkce, která nahradí rozdělovací znaky v řetězci string znakem new_delimiter. Každý znak řetězce string, který bude nalezen v řetězci delimiters, bude nahrazen znakem new_delimiter. Je-li delimiters rovno NULL, použijí se rozdělovací znaky def. jako: #define G_STR_DELIMITERS "_-|> <."Změny se provedou přímo v řetězci string. Funkce g_strdelimit() jako návratovou hodnotu použije vstupní argument string.

● Rozdělování řetězců na pole řetězců:● gchar** g_strsplit(const gchar *string, const gchar *delimiter, gint max_tokens);Tato rutina se postará o alokování pole řetězců, které předá jako návratovou hodnotu. Pole řetězců vytvoří z řetězce string tak, že jej rozdělí na maximálně max_tokens částí v místech specifikovaných řetězcem delimiter.Každý znak řetězce delimiter bude v řetězci string chápán jako místo, kde má dojít k rozdělení. Je-li max_tokens menší než 1, rozdělí se celý řetězec. Je-li však max_tokens kladná nenulová hodnota a počet rozdělení dosáhne tohoto čísla, poslední řetězec ve vráceném poli řetězců bude obsahovat zbytek řetězce string (nezáleží na tom, že třeba ještě obsahuje nějaké rozdělovací znaky z delimiter). K uvolnění pole řetězců vytvořeného funkcí g_strsplit() používejte: void g_strfreev(gchar **str_array);

Page 15: Knihovna GLib

GLib – řetězce GString● Každý, kdo už někdy pracoval s řetězci v C zjistí, že práce s nimi je někdy dost pracná,

hlídat si velikost alokované paměti pro řetězec, realokovat paměť pro vložení, atd...GLib to samozdřejmě řeší strukturou GString. Je to něco jako GArray přispůsobené na řetězec.

struct GString { gchar *str; gint len;}

Řetězec str je v tomto případě obyčejný céčkovský řetězec ukončený nulovým znakem ('\0') a takto k němu můžete i přistupovat. Pokud si nejste opravdu jisti tím, co děláte, používejte jej přímým voláním jen ke čtení. K zápisu využijte výhradně funkcí popsaných níže.

Položka len vždy obsahuje délku řetězce str bez ukončovacího znaku '\0'.

Jelikož se řetězec automaticky realokuje, jak do něj přidáváte text, je velice pravděpodobné, že se bude v paměti stěhovat. Nelze tedy spoléhat na to, že pointer str bude ukazovat vždy na stejné místo v paměti.

Page 16: Knihovna GLib

GLib – řetězce GString● Funkce pro vytvoření a uvolnění struktury GString:

● GString* g_string_new(const gchar *init);Tato funkce vytvoří nový GString, tedy alokuje místo pro strukturu GString a přiřadí do ní řetězec init. Vrátí pointer na nově vzniklý GString

● GString* g_string_sized_new(guint dfl_size);Funkce, která vytvoří nový GString s dostatkem místa pro dfl_size znaků. To je užitečné, když do řetězce hodláte mnohokrát přidávat text a nechcete, aby se realokoval příliš často.

● void g_string_free(GString* string, gint free_segment);Tato funkce uvolní z paměti GString. Je-li navíc free_segment nastaven na TRUE, dealokují se také textová data udržovaná GStringem (položka str struktury GString - viz. výše). Je-li free_segment FALSE, text zůstane v paměti, takže jej můžete dále používat jako obyčejný řetězec ukončený nulovým znakem.

● Funkci g_string_sized_new() můžete využít, když chcete například manuálně nastavit řetězec ve struktuře GString.

Page 17: Knihovna GLib

GLib – řetězce GString● Práce s textem:● GString* g_string_append(GString *string, const gchar *val);

Tato funkce přidá do textového bufferu string řetězec val.● GString* g_string_append_c(GString *string, gchar c);

Tato funkce přidá jeden znak c do textového bufferu string.● GString* g_string_prepend(GString *string, const gchar *val);

Funkce, která přidá na začátek textového bufferu string řetězec val.● GString* g_string_prepend_c(GString *string, gchar c);

Funkce, která přidá jeden znak c na začátek textového bufferu string.● GString* g_string_insert(GString *string, gint pos, const gchar *val);Funkce, která vloží do textového bufferu string na pozici pos řetězec val.

● GString* g_string_insert_c(GString *string, gint pos, gchar c);Funkce, která vloží do textového bufferu string na pozici pos znak c.

● GString* g_string_assign(GString *lval, const gchar *rval);Funkce, která zkopíruje obsah řetězce rval do textového bufferu lval. Původní obsah GStringu lval se zruší.

Page 18: Knihovna GLib

GLib – řetězce GString● Práce s formátovaným textem:● void g_string_sprintf(GString* string, const gchar *format, ...);

● tato funkce je podobná funkci sprintf() ze standardního céčka, uloží do GStringu formátovaný řetězec daný formátem format a volitelnými parametry funkce. Předcházející obsah je odstraněn.

● void g_string_sprintfa(GString* string, const gchar *format, ...);Je podobná předchozí funkci. Liší se tím, že formátovaný řetězec daný formátem format přidá na konec textového bufferu string. Znak 'a' na konci jména funkce znamená append.

● Odstraňování textu:● GString* g_string_erase(GString *string, gint pos, gint len);Tato funkce odstraní len znaků z GStringu string počínaje znakem na pozici pos (první znak má index 0). Zbytek řetězce je posunut dolů tak, aby vyplnil mezeru.

● GString* g_string_truncate(GString *string, gint len);Odstraní konec řetězce, uloženého v GStringu string tak, že ponechá jen prvních len znaků.

Page 19: Knihovna GLib

GLib – řetězce GString● Ostatní funkce:● GString* g_string_up(GString *string);

zkonvertuje veškerý text uložený v GStringu string na velká písmena abecedy.● GString* g_string_down(GString *string);

zkonvertuje veškerý text uložený v GStringu string na malá písmena abecedy.(nevím jestli tyto funkce používají lokalizaci ze systémové proměnné LOCALE)

● Malý příklad:int main(void) { GString *s, *t; gchar *u; /* pomocny pointer (retezec) */ /* inicializace novych retezcu */ s = g_string_new("ahoj"); /* vytvoreni s prirazenim */ t = g_string_sized_new(10); /* retezec v t zabira 10 bajtu */ g_string_assign(t, "nazdar"); /* prirazeni */ g_string_up(s); /* konverze na velka pismena */ /* kontrolni vypis */ printf("obsah s: %s; delka s: %d\n", s->str, s->len); printf("obsah t: %s; delka t: %d\n", t->str, t->len); u = s->str; /* u nyni ukazuje na retezec ulozeny v s */ /* dealokace */ g_string_free(s, FALSE); /* data z s zustavaji v pameti */ g_string_free(t, TRUE); /* dealokuj veskery obsah t */ /* kontrolni vypis - data pochazejici z GStringu s existuji! */ printf("obsah u: %s\n", u); g_free(u); /* dealokuj retezec, ktery pochazi z s */ return(0); }

Page 20: Knihovna GLib

GLib – Hash tabulky (GHashTable)● Hash tabulky (asociativní pole), představují výkonný programátorský nástroj, který

realizuje spojení dat s jejich jednoznačným klíčem, takže pokud zadáte klíč, data mohou být v hash tabulce díky výkonným algoritmům velice rychle nalezena.Hash tabulka je v knihovně GLib reprezentována strukturou GHashTable. Všechny položky této struktury jsou neveřejné a doporučuje se k nim přistupovat výhradně použitím speciálních funkcí.Hash tabulka je implementována universálně, takže lze zadat funkci pro porovnávání a funkci pro výpočet hashové hodnoty:guint(*GHashFunc)(gconstpointer key);gint(*GCompareFunc)(gconstpointer a, gconstpointer b);

● GLib sama o sobě definuje 3 typy hashovacích a porovnávacích funkcí, pomocí těchto funkcí můžeme vytvořit různé hash tabulky na různé účely.

● Vytvoření hash tabulky:● GHashTable* g_hash_table_new(GHashFunc hash_func, GCompareFunc key_compare_func);Funkce vrací pointer na nově alokovanou strukturu GHashTable a jako parametry si žádá dvě funkce. První musí odpovídat typu GHashFunc a druhá GcompareFunc. Př:

● g_hash_table_new(g_str_hash, g_str_equal); Vytvoří HT pro řetězce● g_hash_table_new(g_int_hash, g_int_equal); Vytvoří HT pro typ gint

Page 21: Knihovna GLib

GLib – Hash tabulky (GHashTable)● Zničení hash tabulky:● void g_hash_table_destroy(GHashTable *hash_table);

dealokuje paměť vyhrazenou pro hash tabulku hash_table. Pokud jste do tabulky ukládali dynamická data a klíče, musíte je dealokovat ještě předtím, než provedete tuto funkci.

● Vkládání dat:● void g_hash_table_insert(GHashTable *hash_table, gpointer key, gpointer value);Vloží do hash tabulky hash_table klíč key a data value. Jestliže už klíč v tabulce existuje, jeho stávající hodnota je nahrazena novou.

Je třeba upozornit, že hodnoty key a value jsou v hash tabulce uchovány tak, jak je funkce g_hash_table_insert() dostane. Neprovádí se žádná kopie apod. Používáte-li pouze statická data, je vše v pořádku, ale s dynamickými daty nastávají potíže. Musíte ručně zajistit, že se dealokují při odstraňování z hash tabulky. Z tohoto důvodu se nedoporučuje do jedné GHashTable ukládat statické a dynamické hodnoty zároveň (ty statické realokujte na dynamické použitím funkce g_strdup()).Vyplývá z toho následující: pokud do GHashTable ukládáte dynamicky alokovaná data, musíte se před operací vkládání přesvědčit, že tam žádná data s klíčem key ještě nejsou. Pokud by byly, musíte ta stará nejprve dealokovat.

● Doporučuju kouknout se do zdrojáků a zjistit jak je funkce udělaná: soubor glib/ghash.c

Page 22: Knihovna GLib

GLib – Hash tabulky (GHashTable)● Získání dat:● gpointer g_hash_table_lookup(GHashTable *hash_table, gconstpointer key);v hash tabulce hash_table vyhledá záznam s klíčem key a vrátí pointer na jeho data nebo NULL, nebyl-li takový klíč nalezen.

● gboolean g_hash_table_lookup_extended(GHashTable *hash_table, gconstpointer lookup_key, gpointer *orig_key, gpointer *value);tato funkce vyhledá v tabulce hash_table záznam odpovídající klíči lookup_key a do proměnných orig_key a value uloží původní klíč a jemu přiřazená data. Funkce vrátí TRUE, byl-li klíč v tabulce nalezen nebo FALSE v opačném případě. Tato funkce je užitečná, když potřebujete dealokovat originální klíč, třeba před voláním g_hash_table_remove() (viz později).

● Odstranění dat:● void g_hash_table_remove(GHashTable *hash_table, gconstpointer key);odstraní klíč key a jemu asociovaná data. Pokud hash tabulka uchovává dynamicky alokovaná data, musíte se postarat o jejich uvolnění z paměti ručně.

Page 23: Knihovna GLib

GLib – Hash tabulky (GHashTable)● Odstranění dat (pokr.)● guint g_hash_table_foreach_remove(GHashTable *hash_table, GHRFunc func, gpointer user_data);

gboolean(*GHRFunc)(gpointer key, gpointer value, gpointer user_data);

Funkce g_hash_table_foreach_remove() slouží k odstranění i několika položek najednou. Na každou dvojici klíč--data tabulky hash_table zavolá uživatelskou funkci func, která musí odpovídat předpisu GHRFunc, a když ona vrátí TRUE, daný záznam bude z hash_table odstraněn.Parametr user_data bude v nezměněné podobě předán volané funkci func.Funkce g_hash_table_foreach_remove() vrací počet odstraněných položek.

● Další funkce:● guint g_hash_table_size(GHashTable *hash_table);

Funkce vrátí počet dvojic klíč--data uložených v tabulce hash_table.

Page 24: Knihovna GLib

GLib – Hash tabulky (GHashTable)● Odstranění dat (pokr.)● void g_hash_table_foreach(GHashTable *hash_table, GHFunc func, gpointer user_data);

void(*GHFunc) (gpointer key, gpointer value, gpointer user_data);

Funkce g_hash_table_foreach() zavolá na každý záznam (dvojici klíč--data) tabulky hash_table funkci func, které předá klíč (key), jeho data (value) a uživatelská data (user_data).

● void g_hash_table_freeze(GHashTable *hash_table);● void g_hash_table_thaw(GHashTable *hash_table);

Standardně, po každém vložení nebo odebrání prvku z tabulky se provádí vnitřní přeuspořádání položek. Tato operace ukrádá kousek strojového času, takže když hodláte v hash tabulce provést najednou větší množství změn, je vhodné nejprve zavolat funkci g_hash_table_freeze(), která tabulku hash_table zmrazí, takže se po každém přidání či odebrání prvku nebude přebudovávat vnitřní struktura položek. Po dokončení úprav zavolejte g_hash_table_thaw(), přebudovávání obnovíte.Hash tabulky si pamatují, kolikrát byly "zmrazeny" a proto kolikrát zavoláte funkci g_hash_table_freeze(), tolikrát musíte zavolat i g_hash_table_thaw().

Page 25: Knihovna GLib

GLib – Binární stromy● Strom● je takové uspořádání prvků (uzlů, nodes), ve kterém lze rozeznat předchůdce (rodiče -

parent) a následovníky (děti - children). Každý prvek může mít nejvýše jednoho předchůdce a několik následovníků (binární stromy nejvíce dva).

● Kořenem (root) nazýváme takový prvek, který nemá předchůdce. V každém stromu se nachází jen jeden kořen.

● Naopak listy (leafs) jsou takové prvky, které nemají žádného následovníka. Má-li strom jen jeden prvek, je kořenem i listem zároveň - hybrid.

● Binární stromy knihovny GLib jsou reprezentovány strukturou GTree. Všechny položky této struktury jsou skryté, což znamená, že by se se stromem mělo pracovat jen pomocí vymezené sady funkcí, kterou si v této a následující části popíšeme.

● Do stromu GTree se ukládají dvojice klíč--data. GTree je neustále vyvažován, takže cesta od kořene k listům je vždy nejmenší možná. To je předpokladem dobré efektivity vyhledávacího algoritmu.

● Vytvoření a zničení binárního stromu:● GTree* g_tree_new(GCompareFunc key_compare_func);

Jako jediný parametr se jí předává funkce key_compare_func, která musí odpovídat předpisu: gint (*GCompareFunc) (gconstpointer a, gconstpointer b);

● void g_tree_destroy(GTree *tree);Uvolní binární strom tree z paměti. Pokud jste ale používali dynamicky alokované klíče nebo data, musíte je ještě před voláním g_tree_destroy() dealokovat sami.

Page 26: Knihovna GLib

GLib – Binární stromy● Přidávání prvků:● void g_tree_insert(GTree *tree, gpointer key, gpointer value);Tato funkce vloží do binárního stromu tree pod klíčem key data value. Jestliže prvek s klíčem key ve stromu již existuje, budou jeho stará data nahrazena novými.Strom je automaticky "vyvážen", takže vzdálenost listů od kořene zůstává co nejmenší.

● Získávání dat:● gpointer g_tree_lookup(GTree *tree, gpointer key);

vyhledá v binárním stromu tree uzel s klíčem key a vrátí jemu přiřazená data. Vyhledání dat podle klíče je velmi rychlé, protože strom je v každém okamžiku "vyvážen" (balanced).

● Odstraňování prvků:● void g_tree_remove(GTree *tree, gpointer key);

ze stromu tree odstraní podle hodnoty klíče key dvojici klíč--data. Pokud jste klíč nebo data alokovali dynamicky, musíte se sami postarat o to, abyste je také dealokovali.

● Vyhledávání:● gpointer g_tree_search(GTree *tree, GSearchFunc search_func, gpointer data);Funkce, která má za úkol vyhledat ve stromu tree danou položku. Vyhledávání se realizuje pomocí funkce search_func.

Page 27: Knihovna GLib

GLib – Binární stromy● Procházení stromem:● void g_tree_traverse(GTree *tree, GTraverseFunc traverse_func, GTraverseType traverse_type, gpointer data);

gint (*GTraverseFunc)(gpointer key, gpointer value, gpointer data);

typedef enum { G_IN_ORDER, G_PRE_ORDER, G_POST_ORDER, G_LEVEL_ORDER /* není pro binární stromy. */} GTraverseType;

Procházení stromem tree, funkce traverse_func je zavolána pro každý pár, pořadí určuje traverse_type. Parametr data bude předán nezměněn funkci func.

Page 28: Knihovna GLib

GLib – Binární stromy - příklad● #include <glib.h>

gint my_compare(gconstpointer a, gconstpointer b){ return (strcmp((gchar *) a, (gchar *) b));}

gint main(void){ GTree *tree;

/* inicializace stromu */ tree = g_tree_new(my_compare); g_tree_insert(tree, "Karel", GINT_TO_POINTER(100)); g_tree_insert(tree, "Petr", GINT_TO_POINTER(200)); g_tree_insert(tree, "Josef", GINT_TO_POINTER(150)); g_tree_insert(tree, "Adam", GINT_TO_POINTER(620)); g_tree_insert(tree, "Pavel", GINT_TO_POINTER(490));

/* ziskani hodnot */ printf("Josef ma %d Kc\n", g_tree_lookup(tree, "Josef")); /* dealokace */ g_tree_destroy(tree);}

Page 29: Knihovna GLib

GLib – Obousměrné seznamy (GList)● Seznam (angl. list) jako abstraktní datová struktura je velmi často používaný v oblasti

nenumerického zpracování dat. Je tvořen dynamickou posloupností prvků, které jsou navzájem svázány pointery tak, že tvoří pomyslný řetěz položek. V programu pak stačí uchovávat pouze pointer na první prvek seznamu a díky němu se postupně přes jednotlivé pointery můžeme dostat ke každé položce seznamu.

● struct GList{ gpointer data; GList *next; GList *prev;};

Pointer data slouží k uložení ukazatele na data, které chceme v seznamu uchovávat.Položky next a prev jsou pointery na následující popř. předcházející prvek seznamu, můžou se používat při procházení seznamem v obou směrech.

U obousměrných seznamů - v kontrastu s tím, na co jsme byli dosud zvyklí - neexistuje funkce pro vytvoření GListu. Prázdný seznam je jednoduše GList* nastavený na NULL. Funkcím, které se seznamy pracují, se obvykle předává pointer na první položku seznamu.

Page 30: Knihovna GLib

GLib – Obousměrné seznamy (GList)● Přidávání položek do obousměrného seznamu:● GList* g_list_append(GList *list, gpointer data);● GList* g_list_prepend(GList *list, gpointer data);● GList* g_list_insert(GList *list, gpointer data, gint position);GList* g_list_insert_sorted(GList *list, gpointer data, GCompareFunc func);

Pro všechny tři platí, že argument list je pointer na první položku seznamu, nebo NULL, vytváříme-li nový seznam. Argument data jsou ukládaná data (buď pointer na datovou položku nebo přetypovaný gint/guint).

Funkce g_list_append() přidá prvek data na konec seznamu, g_list_prepend() na začátek seznamu a funkce g_list_insert() vloží položku data na pozici danou argumentem position. Je-li position, argument funkce g_list_insert(), záporná hodnota nebo hodnota větší než počet prvků v seznamu, uloží se nový prvek na konec.

Volání g_list_insert() s position rovno 0 je ekvivalentem volání g_list_prepend(), position rovno 1 vytvoří novou položku hned za prvkem list a podobně. první položku seznamu.

Page 31: Knihovna GLib

GLib – Obousměrné seznamy (GList)● Odstrnění položek do obousměrného seznamu:● GList* g_list_remove(GList *list, gpointer data);Tato funkce odstraní z obousměrného seznamu list položku s daty data. Argument list je tedy pointer na první položku seznamu a data pointer na uložená data. Navrácená hodnota je nový počátek seznamu. Jestliže se v seznamu vyskytují dvě položky se stejnými daty, je odstraněna pouze první z nich. Jestliže v seznamu neexistuje položka, která by data obsahovala, zůstane seznam nezměněn.Funkcí g_list_remove() se prvek GList dealokuje. data však zůstanou nedotčena - v případě, že už nejsou potřeba, je nutno je dealokovat zvlášť.

● GList* g_list_remove_link(GList *list, GList *llink);Ze seznamu, na jehož počátek ukazuje parametr list, odstraní prvek llink, ale nedealokuje ho. Položky prev a next (viz struktura GList) odstraněného prvku llist se nastaví na NULL, takže se z listu vlastně stane samostatný seznam o jednom prvku. Není-li již takto odstraněné položky potřeba, je nutno ji dealokovat voláním funkce g_list_free_1().

● Dealokace obousměrných seznamů:● void g_list_free(GList *list);

dealokuje seznam, kde list je pointer na počátek seznamu.● void g_list_free_1(GList *list);

Pozor! Není možné libovolnou položku seznamu pouze takto jednoduše dealokovat. Musíme ji nejprve ze seznamu odstranit voláním funkce g_list_remove_link().

Page 32: Knihovna GLib

GLib – Obousměrné seznamy (GList)● Procházení obousměrným seznamem:

● GList* g_list_first(GList *list);Vrátí první položku seznamu. list je jeho libovolný prvek.

● GList* g_list_last(GList *list);Vrátí poslední položku seznamu. list je libovolný prvek.

K získání následujícího nebo předcházejícího prvku můžete využívat přímý přístup k položkám next popř. prev struktury GList nebo použít následující makra, která navíc provádějí kontrolu na (nechtěné) předání NULL:

● GList* g_list_nth(GList *list, guint n);Vrátí n-tý prvek v pořadí od prvku list (list je chápán jako nultý) nebo NULL, není-li v seznamu tolik prvků. Záporné hodnoty n nejsou povoleny.

● gpointer g_list_nth_data(GList *list, guint n);Vrátí pointer na data n-tého prvku v pořadí od prvku list (list je chápán jako nultý) nebo NULL, není-li v seznamu tolik prvků. Záporné hodnoty n nejsou povoleny.

Page 33: Knihovna GLib

GLib – Obousměrné seznamy (GList)● Prohledávání obousměrného seznamu:

● gint g_list_position(GList *list, GList *llink);● gint g_list_index(GList *list, gpointer data);

Tyto dvě funkce vrací index (pořadí) listu llink od začátku list. První funkce potřebuje k nalezení ukazatel na list, druhé funkce stačí data.

● GList* g_list_find(GList *list, gpointer data);● GList* g_list_find_custom(GList *list, gpointer data, GCompareFunc func);Obě vracejí pointer na nalezenou položku seznamu, obě požadují jako parametr list počátek tohoto seznamu stejně tak jako pointer na data hledaného prvku. Odlišný však je způsob, jakým položku GList vyhledají.

Použitím funkce g_list_find_custom() máte nad vyhledáváním úplnou kontrolu. Jako poslední argument této funkce se předává nám již známá funkce typu GCompareFunc a právě ona rozhoduje o relaci mezi dvěma položkami seznamu a tak potažmo i o tom, který prvek seznamu bude prohlášen za ten pravý.

Page 34: Knihovna GLib

GLib – Obousměrné seznamy (GList)● Další funkce:● void g_list_foreach(GList *list, GFunc func, gpointer user_data);

Funkce která na každý prvek seznamu list zavolá funkci func a mimo jiné jí předá i data user_data.void (*GFunc)(gpointer data, gpointer user_data);

● guint g_list_length(GList *list);Vrátí počet prvků v obousměrném seznamu.

● GList* g_list_copy(GList *list);Vytvoří nově alokovanou kopii seznamu list. Pointery na data se do nového seznamu pouze jednoduše kopírují, takže ukazují-li na nějaké dynamické datové položky, budou mít oba seznamy všechny ukazatele na stejná data (jinými slovy, kopie dynamických dat se neprovádí).

● GList* g_list_reverse(GList *list);Obrátí pořadí prvků v seznamu list a vrátí pointer na nový počátek. (Tzn. první položka bude poslední, druhá bude předposlední atd.)

● GList* g_list_sort(GList *list, GCompareFunc compare_func);Seřadí seznam list podle kritéria definovaného funkcí compare_func.

● GList* g_list_concat(GList *list1, GList *list2);Seznam list2 připojí na konec seznamu list1. Pozor: Položky druhého seznamu nejsou duplikovány.

Page 35: Knihovna GLib

GLib – Jednosměrné seznamy (GSList)● Jednosměrné seznamy jsou těžkou analogií k obousměrným. Základní rozdíl, v čem se tyto

dva typy liší, je skutečnost, že jednosměrné seznamy lze procházet jen v jednom směru, tj. nedisponují pointery na "předcházející" prvky (prev).

● Uzly jednosměrných seznamů jsou definovány strukturou GSList:struct GSList{ gpointer data; GSList *next;};

● Funkce pro jednosměrné seznami jsou velmi podobné těm obousměrným, jediné co chybý jsou funkce, které potřebují předcházející prvky.

Page 36: Knihovna GLib

GLib – Unikód● Otázka kódování různých jazyků je velmi složitá, a proto vzniklo univerzální kódování –

Unikód (UNICODE). Unikód můžou být 8 16 a 32 bitové řetězce. Protože 16 a 32 bytové řetězce ruší kompatibility se standardními ansi-8 bitovými, vzniklo kódování utf8, toto kódování zachováná prvních 127 znaků z kódování ISO-8859-1 a zbylý bit určuje zda znak nebude zakódován do více bytů. Více na www.unicode.org.

● Obdoba standardních funkcí definovaných v ctype.h:● gboolean g_unichar_isalnum (gunichar c);● gboolean g_unichar_isalpha (gunichar c);● gboolean g_unichar_iscntrl (gunichar c);● gboolean g_unichar_isdigit (gunichar c);● gboolean g_unichar_isgraph (gunichar c);● gboolean g_unichar_islower (gunichar c);● gboolean g_unichar_isprint (gunichar c);● gboolean g_unichar_ispunct (gunichar c);● gboolean g_unichar_isspace (gunichar c);● gboolean g_unichar_isupper (gunichar c);● gboolean g_unichar_isxdigit (gunichar c);● gboolean g_unichar_istitle (gunichar c);● gboolean g_unichar_isdefined (gunichar c);● gboolean g_unichar_iswide (gunichar c);● gunichar g_unichar_toupper (gunichar c);● gunichar g_unichar_tolower (gunichar c);● gunichar g_unichar_totitle (gunichar c);

Page 37: Knihovna GLib

GLib – Unikód● Pro zjištění zda je použita utf8 locale je funkce:gboolean g_get_charset(char **charset);Vrací TRUE jestli ano.

● Převod unicode znaku na číslo:● gint g_unichar_digit_value(gunichar c);● gint g_unichar_xdigit_value(gunichar c);

● Nízkoúrovňové funkce pro průchod v řetězcích.● #define g_utf8_next_char(p) (char *)((p) + g_utf8_skip[*(guchar *)(p)])Skok na další unicode znak v řetězci.

● gchar* g_utf8_prev_char(const gchar *p);Skok na předchozí unicode znak.

● gunichar g_utf8_get_char(const gchar *p);Dekóduje a vrátí unicode znak v řetězci.

● gunichar g_utf8_get_char_validated(const gchar *p, gssize max_len);

● Dekóduje a vrátí unicode znak v řetězci, maximální délka znaku je max_len.

Page 38: Knihovna GLib

GLib – Unikód● glong g_utf8_strlen(const gchar *p, gssize max);

Zpočítá počet znaků v utf8 řetězci (Pozor, počet znaků se nemusí rovnat počtu bytů, to znamená, že funkce strnlen(p, n) může vrátit jinou hodnotu než funkce g_utf8_strlen(p, n)

● gchar* g_utf8_strncpy(gchar *dest, const gchar *src,gsize n);Zkopíruje n znaků z src do dest, jako strccpy().

● gchar* g_utf8_strchr(const gchar *p, gssize len, gunichar c);Utf8 ekvivalent funkce strchr().

● gchar* g_utf8_strrchr(const gchar *p, gssize len,gunichar c);Utf8 ekvivalent funkce strrchr().

● gchar* g_utf8_strreverse(const gchar *str, gssize len);Utf8 ekvivalent funkce g_strreverse().

Page 39: Knihovna GLib

GLib – Unikód● Následující funkce slouží pro převod mezi jednotlivým kódováním:● gunichar2 *g_utf8_to_utf16(const gchar *str, glong len, glong *items_read, glong *items_written, GError **error);

● gunichar *g_utf8_to_ucs4(const gchar *str, glong len, glong *items_read, glong *items_written, GError **error);

● gunichar *g_utf8_to_ucs4_fast(const gchar *str, glong len, glong *items_written);

● gunichar *g_utf16_to_ucs4(const gunichar2 *str, glong len, glong *items_read, glong *items_written, GError **error);

Page 40: Knihovna GLib

GLib – Unikód● Následující funkce slouží pro převod mezi jednotlivým kódováním:● gchar *g_utf16_to_utf8(const gunichar2 *str, glong len, glong *items_read, glong *items_written, GError **error);

● gunichar2 *g_ucs4_to_utf16(const gunichar *str, glong len, glong *items_read, glong *items_written, GError **error);

● gchar *g_ucs4_to_utf8(const gunichar *str, glong len, glong *items_read, glong *items_written, GError **error);

● utf16 – 16 bitové kódování● ucs4 – 32 bitové kódování.● utf8 – 8 bitové kódování, kde znak může mít více bajtů.

Page 41: Knihovna GLib

GLib – Další funkce● GLib umožňuje i spoustu dalších funkcí na plně univerzální využití, některé funkce jsou

perfektně popsány na www.root.cz (z tadyma jsem čerpal já) v sekci vývoj->knihovny->GLib. Ovšem některé funkce a možnosti byly dodělány až po skončení seriálu na www.root.cz a nenalezneme je tam:

● GLib umožňuje kompletní vytvoření objektů v čistém jazyce C (GObject).● GLib má multiplatformní kód pro práci s vlákny.● Pomocí GLib můžeme zjistit kde náš program zkrachoval (GBacktrace)● Implementace lokalizace● Náhodné čísla (GRand)● Práce s OI (g_io)

● To co na www.root.cz najdeme:● Lexikální scanner (GScanner)● Doplňování řetězců (GCompletion)● Fronty (synchronní a asynchronní)● Práce s datem a časem● Cache● Práce s mnohonásobnými stromy.● Kvarky (GQuark)

● Vypracoval:Petr Kobalíček ([email protected])14.3.2005 Zlín