WIP: Handling the keyboard #1

Draft
arek wants to merge 2 commits from handle-keyboard into main
4 changed files with 398 additions and 3 deletions

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0 )
cmake_minimum_required(VERSION 3.10 )
set(CMAKE_C_STANDARD 11)
project(wlgol
VERSION 0.0.1
@ -22,9 +22,9 @@ add_custom_command(
)
set(SOURCES
wlgol.c
tkeyboard.c
tpointer.c
hashtable.c
${CMAKE_CURRENT_BINARY_DIR}/xdg-shell.c
)
@ -32,7 +32,7 @@ set(GENHEADERS
${CMAKE_CURRENT_BINARY_DIR}/include/xdg-shell.h
)
add_executable(wlgol ${SOURCES} ${GENHEADERS})
add_executable(wlgol wlgol.c ${SOURCES} ${GENHEADERS})
target_include_directories(wlgol
PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/include
@ -43,3 +43,20 @@ target_link_libraries(wlgol
wayland-client
wayland-cursor
)
add_executable(test_hashtable tests/test_hashtable.c
${SOURCES}
)
target_link_libraries(test_hashtable
wayland-client
wayland-cursor
)
target_include_directories(test_hashtable
PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/include
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
)
enable_testing()
add_test(NAME Hashtable COMMAND test_hashtable)

199
hashtable.c Normal file
View File

@ -0,0 +1,199 @@
// implementation of a hashtable
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hashtable.h"
// entry in the hashtable
struct entry
{
const char *key;
void *value;
struct entry *next;
};
struct htobj
{
int size;
struct entry **table;
};
struct item {
struct entry *prev, *found;
int index;
};
static unsigned int hash(const char *key)
{
unsigned int hash = 0;
while (*key)
{
hash = (hash << 5) - hash + *key++;
}
return hash;
}
hashtable hashtable_new(int size)
{
// Allocate memory for the hashtable
hashtable h = malloc(sizeof(struct htobj));
// Set the size of the hashtable
h->size = size;
// Allocate memory for the entry pointers
h->table = calloc(size, sizeof(struct entry *));
// Return the newly created hashtable
return h;
}
struct item hashtable_lookup_item(hashtable h, const char *key)
{
struct item result = {
.found = NULL,
.index = -1,
};
int index = hash(key) % h->size;
struct entry *e = h->table[index];
struct entry *prev = NULL;
while (e != NULL) {
if (strcmp(e->key, key) == 0) {
result.index = index;
result.found = e;
result.prev = prev;
return result;
}
prev = e;
e = e->next;
}
return result; // empty in this case
}
void *hashtable_set(hashtable h, const char *key, void *value)
{
struct item item = hashtable_lookup_item(h, key);
// not found - insert new
if (item.found == NULL) {
int index = hash(key) % h->size;
// Create a new entry
struct entry *e = malloc(sizeof(struct entry));
e->key = strdup(key); // key is the copy
e->value = value;
e->next = NULL;
// Insert the entry at the beginning of the linked list
e->next = h->table[index];
h->table[index] = e;
return NULL;
}
// found replace the value
void *old_value = item.found->value;
item.found-> value = value;
return old_value;
}
void *hashtable_lookup(hashtable h, const char *key)
{
struct item item = hashtable_lookup_item(h, key);
if (item.found != NULL) {
return item.found->value;
}
return NULL;
}
void *hashtable_remove(hashtable h, const char *key)
{
struct item item = hashtable_lookup_item(h, key);
if (item.found == NULL) {
return NULL;
}
// found, so detete it
if (item.prev != NULL) {
item.prev->next = item.found->next;
} else {
h->table[item.index] = item.found->next;
}
// free unused memory
void *value = item.found->value; // remember value
free((void*) item.found->key); // free key
free((void*) item.found); // free entry
return value;
}
void hashtable_destroy_bucket(hashtable h, int i)
{
struct entry *e = h->table[i];
while (e != NULL) {
free((void*)e->key);
e = e->next;
free(e);
}
}
void hashtable_destroy(hashtable h)
{
if (h==NULL) return;
for (int i = 0; i < h->size; i++) {
hashtable_destroy_bucket(h, i);
}
free (h->table);
free(h);
}
ht_iterator hashtable_iter(hashtable h)
{
ht_iterator iter = {
.h = h,
.index = -1,
.entry = NULL,
};
return iter;
}
bool ht_iter_next(ht_iterator *iter)
{
if (iter == NULL) {
return false;
}
hashtable h = iter->h;
while(true) {
if (iter->index >= h->size) {
return false;
}
if (iter->entry == NULL) {
iter->index++;
iter->entry = h->table[iter->index];
} else {
iter->entry = iter->entry->next;
}
if (iter->entry != NULL) return true;
}
}
const char *ht_iter_key(ht_iterator *iter)
{
if (iter == NULL || iter->entry == NULL) return NULL;
return iter->entry->key;
}
void *ht_iter_value(ht_iterator *iter)
{
if (iter == NULL || iter->entry == NULL) return NULL;
return iter->entry->value;
}

116
include/hashtable.h Normal file
View File

@ -0,0 +1,116 @@
#ifndef HASHTABLE_H
#define HASHTABLE_H
#include <stdbool.h>
struct htobj;
typedef struct htobj *hashtable;
typedef struct {
struct htobj *h;
struct entry *entry;
int index;
} ht_iterator;
/**
* @brief Create a new hashtable
*
* This function creates a new hashtable with the specified size.
* It initializes the table with NULL entries.
*
* @param size The size of the hashtable
* @return A pointer to the newly created hashtable
*/
hashtable hashtable_new(int size);
/**
* @brief Insert a new key-value pair into the hashtable
*
* This function inserts a new key-value pair into the hashtable.
* It calculates the index using the hash function and inserts the
* key-value pair at the beginning of the linked list at that index.
*
* @param h Pointer to the hashtable
* @param key Pointer to the key
* @param value Pointer to the value
* @return null or pointer to the previous value of the key
*/
void *hashtable_set(hashtable h, const char *key, void *value);
/**
* @brief Get the value associated with a key from the hashtable
*
* This function takes a hashtable and a key as input and returns the
* value associated with the key. If the key is not found in the
* hashtable, it returns NULL.
*
* @param h Pointer to the hashtable
* @param key Pointer to the key
* @return Pointer to the value associated with the key, or NULL if not found
*/
void *hashtable_lookup(hashtable h, const char *key);
/**
* @brief Remove a key-value pair from the hashtable
*
* This function removes a key-value pair from the hashtable.
* It calculates the index using the hash function and traverses
* the linked list at that index. If the key is found, it removes
* the corresponding entry from the linked list and frees the memory.
*
* @param h Pointer to the hashtable
* @param key Pointer to the key to remove
* @return null or value associated with the removed key.
*/
void *hashtable_remove(hashtable h, const char *key);
/**
* @brief Destroy hashtable.
*
* Values must be destroyed by the caller earlier.
*
* @param h Reference to the hastable.
*/
void hashtable_destroy(hashtable h);
/**
* @brief Get the iterator of key-value pairs in the hashtable
*
* This function returns the iterator of key-value pairs in the hashtable.
*
* @param h Pointer to the hashtable
* @return The iterator of key-value pairs in the hashtable
*/
ht_iterator hashtable_iter(hashtable h);
/**
* @brief Get the next key-value pair from the iterator
*
* This function returns the next key-value pair from the iterator.
*
* @param iter Pointer to the iterator
* @return true if there is a next key-value pair, false otherwise
*/
bool ht_iter_next(ht_iterator *iter);
/**
* @brief Get the key from the iterator
*
* This function returns the key from the iterator.
*
* @param iter Pointer to the iterator
* @return The key from the iterator
*/
const char *ht_iter_key(ht_iterator *iter);
/**
* @brief Get the value from the iterator
*
* This function returns the value from the iterator.
*
* @param iter Pointer to the iterator
* @return The value from the iterator
*/
void *ht_iter_value(ht_iterator *iter);
#endif

63
tests/test_hashtable.c Normal file
View File

@ -0,0 +1,63 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <hashtable.h>
void test_hashtable(int size) {
hashtable h = hashtable_new(size);
void *value1 = "to jest jakaś tam wartość";
void *value2 = "I inna";
void *value3 = "trzecia";
void *value4 = "Czwarta";
void *value5 = "Piąta";
void *retval = hashtable_set(h, "jeden", value1);
assert(retval == NULL);
void *found = hashtable_lookup(h, "jeden");
assert(found != NULL && !strcmp(value1, found));
retval = hashtable_set(h, "dwa", value2);
assert(retval == NULL);
retval = hashtable_set(h, "trzy", value3);
assert(retval == NULL);
retval = hashtable_set(h, "cztery", value4);
assert(retval == NULL);
retval = hashtable_set(h, "jeden", value5);
assert(retval != NULL);
assert (retval == value1);
retval = hashtable_lookup(h, "niema");
assert(retval == NULL);
retval = hashtable_lookup(h, "jeden");
assert(retval == value5);
ht_iterator iter = hashtable_iter(h);
while (ht_iter_next(&iter)) {
printf("Key %s, value: %s\n", ht_iter_key(&iter), (const char*) ht_iter_value(&iter));
}
retval = hashtable_remove(h, "cztery");
assert (retval == value4);
retval = hashtable_remove(h, "trzy");
assert(retval == value3);
retval = hashtable_remove(h, "dwa");
assert(retval == value2);
retval = hashtable_remove(h, "jeden");
assert(retval == value5);
hashtable_destroy(h);
}
int main() {
test_hashtable(2);
test_hashtable(10);
}