diff options
Diffstat (limited to '')
-rw-r--r-- | src/libmdsserver/client-list.c | 241 | ||||
-rw-r--r-- | src/libmdsserver/client-list.h | 125 |
2 files changed, 366 insertions, 0 deletions
diff --git a/src/libmdsserver/client-list.c b/src/libmdsserver/client-list.c new file mode 100644 index 0000000..0e1a2ab --- /dev/null +++ b/src/libmdsserver/client-list.c @@ -0,0 +1,241 @@ +/** + * mds — A micro-display server + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include "client-list.h" + +#include "macros.h" + +#include <string.h> +#include <errno.h> + + +/** + * The default initial capacity + */ +#ifndef CLIENT_LIST_DEFAULT_INITIAL_CAPACITY +#define CLIENT_LIST_DEFAULT_INITIAL_CAPACITY 8 +#endif + + +/** + * Computes the nearest, but higher, power of two, + * but only if the current value is not a power of two + * + * @param value The value to be rounded up to a power of two + * @return The nearest, but not smaller, power of two + */ +static size_t to_power_of_two(size_t value) +{ + value -= 1; + value |= value >> 1; + value |= value >> 2; + value |= value >> 4; + value |= value >> 8; + value |= value >> 16; +#if __WORDSIZE == 64 + value |= value >> 32; +#endif + return value + 1; +} + + +/** + * Create a client list + * + * @param this Memory slot in which to store the new client list + * @param capacity The minimum initial capacity of the client list, 0 for default + * @return Non-zero on error, `errno` will have been set accordingly + */ +int client_list_create(client_list_t* restrict this, size_t capacity) +{ + /* Use default capacity of zero is specified. */ + if (capacity == 0) + capacity = CLIENT_LIST_DEFAULT_INITIAL_CAPACITY; + + /* Initialise the client list. */ + this->capacity = capacity = to_power_of_two(capacity); + this->size = 0; + this->clients = NULL; + if (xmalloc(this->clients, capacity, uint64_t)) + return -1; + + return 0; +} + + +/** + * Release all resources in a client list, should + * be done even if `client_list_create` fails + * + * @param this The client list + */ +void client_list_destroy(client_list_t* restrict this) +{ + free(this->clients); + this->clients = NULL; +} + + +/** + * Clone a client list + * + * @param this The client list to clone + * @param out Memory slot in which to store the new client list + * @return Non-zero on error, `errno` will have been set accordingly + */ +int client_list_clone(const client_list_t* restrict this, client_list_t* restrict out) +{ + size_t n = this->capacity * sizeof(uint64_t); + uint64_t* restrict new_clients = NULL; + + out->clients = NULL; + + if ((new_clients = malloc(n)) == NULL) + goto fail; + + out->clients = new_clients; + + out->capacity = this->capacity; + out->size = this->size; + + memcpy(out->clients, this->clients, n); + + return 0; + + fail: + free(new_clients); + return -1; +} + + +/** + * Add a client to the list + * + * @param this The list + * @param client The client to add + * @return Non-zero on error, errno will be set accordingly + */ +int client_list_add(client_list_t* restrict this, uint64_t client) +{ + if (this->size == this->capacity) + { + uint64_t* old = this->clients; + if (xrealloc(old, this->capacity <<= 1, uint64_t)) + { + this->capacity >>= 1; + this->clients = old; + return -1; + } + } + + this->clients[this->size++] = client; + return 0; +} + + +/** + * Remove a client from the list, once + * + * @param this The list + * @param client The client to remove + */ +void client_list_remove(client_list_t* restrict this, uint64_t client) +{ + size_t i; + for (i = 0; i < this->size; i++) + { + if (this->clients[i] == client) + { + size_t n = (--(this->size) - i) * sizeof(uint64_t); + memmove(this->clients + i, this->clients + i + 1, n); + + if (this->size << 1 <= this->capacity) + { + uint64_t* old = this->clients; + if (xrealloc(old, this->capacity >>= 1, uint64_t)) + { + this->capacity <<= 1; + this->clients = old; + } + } + + return; + } + } +} + + +/** + * Calculate the buffer size need to marshal a client list + * + * @param this The list + * @return The number of bytes to allocate to the output buffer + */ +size_t client_list_marshal_size(const client_list_t* restrict this) +{ + return 2 * sizeof(size_t) + this->size * sizeof(uint64_t) + sizeof(int); +} + + +/** + * Marshals a client list + * + * @param this The list + * @param data Output buffer for the marshalled data + */ +void client_list_marshal(const client_list_t* restrict this, char* restrict data) +{ + buf_set_next(data, int, CLIENT_LIST_T_VERSION); + buf_set_next(data, size_t, this->capacity); + buf_set_next(data, size_t, this->size); + + memcpy(data, this->clients, this->size * sizeof(uint64_t)); +} + + +/** + * Unmarshals a client list + * + * @param this Memory slot in which to store the new client list + * @param data In buffer with the marshalled data + * @return Non-zero on error, errno will be set accordingly. + * Destroy the list on error. + */ +int client_list_unmarshal(client_list_t* restrict this, char* restrict data) +{ + size_t n; + + /* buf_get(data, int, 0, CLIENT_LIST_T_VERSION); */ + buf_next(data, int, 1); + + this->clients = NULL; + + buf_get_next(data, size_t, this->capacity); + buf_get_next(data, size_t, this->size); + + n = this->capacity * sizeof(uint64_t); + + if ((this->clients = malloc(n)) == NULL) + return -1; + + n = this->size * sizeof(uint64_t); + + memcpy(this->clients, data, n); + + return 0; +} + diff --git a/src/libmdsserver/client-list.h b/src/libmdsserver/client-list.h new file mode 100644 index 0000000..1894b63 --- /dev/null +++ b/src/libmdsserver/client-list.h @@ -0,0 +1,125 @@ +/** + * mds — A micro-display server + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef MDS_LIBMDSSERVER_CLIENT_LIST_H +#define MDS_LIBMDSSERVER_CLIENT_LIST_H + + +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> + + + +#define CLIENT_LIST_T_VERSION 0 + +/** + * Dynamic array of client ID:s + */ +typedef struct client_list +{ + /** + * The size of the array + */ + size_t capacity; + + /** + * The index after the last used index + */ + size_t size; + + /** + * Stored client ID:s + */ + uint64_t* clients; + +} client_list_t; + + + +/** + * Create a client list + * + * @param this Memory slot in which to store the new client list + * @param capacity The minimum initial capacity of the client list, 0 for default + * @return Non-zero on error, `errno` will have been set accordingly + */ +int client_list_create(client_list_t* restrict this, size_t capacity); + +/** + * Release all resources in a client list, should + * be done even if `client_list_create` fails + * + * @param this The client list + */ +void client_list_destroy(client_list_t* restrict this); + +/** + * Clone a client list + * + * @param this The client list to clone + * @param out Memory slot in which to store the new client list + * @return Non-zero on error, `errno` will have been set accordingly + */ +int client_list_clone(const client_list_t* restrict this, client_list_t* restrict out); + +/** + * Add a client to the list + * + * @param this The list + * @param client The client to add + * @return Non-zero on error, errno will be set accordingly + */ +int client_list_add(client_list_t* restrict this, uint64_t client); + +/** + * Remove a client from the list, once + * + * @param this The list + * @param client The client to remove + */ +void client_list_remove(client_list_t* restrict this, uint64_t client); + +/** + * Calculate the buffer size need to marshal a client list + * + * @param this The list + * @return The number of bytes to allocate to the output buffer + */ +size_t client_list_marshal_size(const client_list_t* restrict this) __attribute__((pure)); + +/** + * Marshals a client list + * + * @param this The list + * @param data Output buffer for the marshalled data + */ +void client_list_marshal(const client_list_t* restrict this, char* restrict data); + +/** + * Unmarshals a client list + * + * @param this Memory slot in which to store the new client list + * @param data In buffer with the marshalled data + * @return Non-zero on error, errno will be set accordingly. + * Destroy the list on error. + */ +int client_list_unmarshal(client_list_t* restrict this, char* restrict data); + + +#endif + |