fix pixmap leak
git-svn-id: http://svn2.nishi.boats/svn/milsko/trunk@82 b9cfdab3-6d41-4d17-bbe4-086880011989
This commit is contained in:
parent
e74b80da50
commit
8ea2d4a50a
15 changed files with 9440 additions and 1337 deletions
12
GNUmakefile
12
GNUmakefile
|
|
@ -7,7 +7,7 @@ CFLAGS = -Wall -Wextra -Iinclude
|
||||||
LDFLAGS =
|
LDFLAGS =
|
||||||
LIBS =
|
LIBS =
|
||||||
|
|
||||||
L_CFLAGS = $(CFLAGS) -fPIC -D_MILSKO
|
L_CFLAGS = $(CFLAGS) -fPIC -D_MILSKO -DHAVE_CONFIG_H
|
||||||
L_LDFLAGS = $(LDFLAGS)
|
L_LDFLAGS = $(LDFLAGS)
|
||||||
L_LIBS = $(LIBS)
|
L_LIBS = $(LIBS)
|
||||||
|
|
||||||
|
|
@ -15,7 +15,7 @@ E_CFLAGS = $(CFLAGS)
|
||||||
E_LDFLAGS = $(LDFLAGS) -Lsrc
|
E_LDFLAGS = $(LDFLAGS) -Lsrc
|
||||||
E_LIBS = $(LIBS) -lMw
|
E_LIBS = $(LIBS) -lMw
|
||||||
|
|
||||||
L_OBJS = src/ds.o src/core.o src/default.o src/draw.o src/lowlevel.o src/font.o
|
L_OBJS = src/ds.o src/core.o src/default.o src/draw.o src/lowlevel.o src/font.o src/image.o
|
||||||
L_OBJS += src/window.o src/button.o src/opengl.o src/frame.o
|
L_OBJS += src/window.o src/button.o src/opengl.o src/frame.o
|
||||||
|
|
||||||
ifeq ($(TARGET),NetBSD)
|
ifeq ($(TARGET),NetBSD)
|
||||||
|
|
@ -53,7 +53,7 @@ SO = .dll
|
||||||
EXEC = .exe
|
EXEC = .exe
|
||||||
endif
|
endif
|
||||||
|
|
||||||
EXAMPLES = examples/example$(EXEC) examples/rotate$(EXEC) examples/opengl$(EXEC)
|
EXAMPLES = examples/example$(EXEC) examples/rotate$(EXEC) examples/opengl$(EXEC) examples/image$(EXEC)
|
||||||
|
|
||||||
.PHONY: all format clean lib examples
|
.PHONY: all format clean lib examples
|
||||||
|
|
||||||
|
|
@ -62,8 +62,8 @@ lib: src/libMw$(SO)
|
||||||
examples: $(EXAMPLES)
|
examples: $(EXAMPLES)
|
||||||
|
|
||||||
format:
|
format:
|
||||||
clang-format --verbose -i $(shell find src include examples tools -name "*.c" -or -name "*.h")
|
clang-format --verbose -i `find src include examples tools "(" -name "*.c" -or -name "*.h" ")" -and -not -name "stb_*.h"`
|
||||||
perltidy -b -bext='/' --paren-tightness=2 $(shell find tools -name "*.pl")
|
perltidy -b -bext='/' --paren-tightness=2 `find tools -name "*.pl"`
|
||||||
|
|
||||||
src/libMw$(SO): $(L_OBJS)
|
src/libMw$(SO): $(L_OBJS)
|
||||||
$(CC) $(L_LDFLAGS) -shared -o $@ $^ $(L_LIBS)
|
$(CC) $(L_LDFLAGS) -shared -o $@ $^ $(L_LIBS)
|
||||||
|
|
@ -81,4 +81,4 @@ examples/%.o: examples/%.c
|
||||||
$(CC) $(E_CFLAGS) -c -o $@ $<
|
$(CC) $(E_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f src/*.dll src/*.so src/*.a src/*.lib */*.o examples/*.exe $(EXAMPLES)
|
rm -f src/*.dll src/*.so src/*.a src/*.lib */*.o */*/*.o examples/*.exe $(EXAMPLES)
|
||||||
|
|
|
||||||
16
examples/image.c
Normal file
16
examples/image.c
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
/* $Id$ */
|
||||||
|
#include <Mw/Milsko.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
MwWidget window = MwVaCreateWidget(MwWindowClass, "window", NULL, 0, 0, 500, 500,
|
||||||
|
MwNtitle, "image button",
|
||||||
|
NULL);
|
||||||
|
MwWidget button = MwCreateWidget(MwButtonClass, "button", window, 50, 50, 400, 400);
|
||||||
|
MwLLPixmap px = MwLoadImage(button, "examples/picture.png");
|
||||||
|
|
||||||
|
MwVaApply(button,
|
||||||
|
MwNpixmap, px,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
MwLoop(window);
|
||||||
|
}
|
||||||
BIN
examples/picture.png
Normal file
BIN
examples/picture.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
|
|
@ -106,6 +106,14 @@ MWDECL void MwSetInteger(MwWidget handle, const char* key, int n);
|
||||||
*/
|
*/
|
||||||
MWDECL void MwSetText(MwWidget handle, const char* key, const char* value);
|
MWDECL void MwSetText(MwWidget handle, const char* key, const char* value);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* %brief Sets a void pointer property
|
||||||
|
* %param handle Widget
|
||||||
|
* %param key Key
|
||||||
|
* %param value Value
|
||||||
|
*/
|
||||||
|
MWDECL void MwSetVoid(MwWidget handle, const char* key, void* value);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* %brief Gets the integer property
|
* %brief Gets the integer property
|
||||||
* %param handle Widget
|
* %param handle Widget
|
||||||
|
|
@ -122,6 +130,14 @@ MWDECL int MwGetInteger(MwWidget handle, const char* key);
|
||||||
*/
|
*/
|
||||||
MWDECL const char* MwGetText(MwWidget handle, const char* key);
|
MWDECL const char* MwGetText(MwWidget handle, const char* key);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* %brief Gets the void pointer property
|
||||||
|
* %param handle Widget
|
||||||
|
* %param key Key
|
||||||
|
* %return Value
|
||||||
|
*/
|
||||||
|
MWDECL void* MwGetVoid(MwWidget handle, const char* key);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* %brief Sets the default property
|
* %brief Sets the default property
|
||||||
* %param handle Widget
|
* %param handle Widget
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,14 @@ MWDECL void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int in
|
||||||
*/
|
*/
|
||||||
MWDECL void MwDrawText(MwWidget handle, MwPoint* point, const char* text, MwLLColor color);
|
MWDECL void MwDrawText(MwWidget handle, MwPoint* point, const char* text, MwLLColor color);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* %brief Creates a pixmap from image
|
||||||
|
* %param handle Widget
|
||||||
|
* %param path Path
|
||||||
|
* %return Pixmap
|
||||||
|
*/
|
||||||
|
MWDECL MwLLPixmap MwLoadImage(MwWidget handle, const char* path);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@
|
||||||
#define MwNbackground "Sbackground"
|
#define MwNbackground "Sbackground"
|
||||||
#define MwNforeground "Sforeground"
|
#define MwNforeground "Sforeground"
|
||||||
|
|
||||||
|
#define MwNpixmap "Vpixmap"
|
||||||
|
|
||||||
#define MwNactivateHandler "Cactivate"
|
#define MwNactivateHandler "Cactivate"
|
||||||
#define MwNresizeHandler "Cresize"
|
#define MwNresizeHandler "Cresize"
|
||||||
#define MwNtickHandler "Ctick"
|
#define MwNtickHandler "Ctick"
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ typedef struct _MwRect MwRect;
|
||||||
typedef struct _MwIntegerKeyValue MwIntegerKeyValue;
|
typedef struct _MwIntegerKeyValue MwIntegerKeyValue;
|
||||||
typedef struct _MwTextKeyValue MwTextKeyValue;
|
typedef struct _MwTextKeyValue MwTextKeyValue;
|
||||||
typedef struct _MwUserHandlerKeyValue MwUserHandlerKeyValue;
|
typedef struct _MwUserHandlerKeyValue MwUserHandlerKeyValue;
|
||||||
|
typedef struct _MwVoidKeyValue MwVoidKeyValue;
|
||||||
typedef struct _MwFont MwFont;
|
typedef struct _MwFont MwFont;
|
||||||
#ifdef _MILSKO
|
#ifdef _MILSKO
|
||||||
typedef struct _MwWidget *MwWidget, MwWidgetRec;
|
typedef struct _MwWidget *MwWidget, MwWidgetRec;
|
||||||
|
|
@ -56,6 +57,11 @@ struct _MwUserHandlerKeyValue {
|
||||||
MwUserHandler value;
|
MwUserHandler value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct _MwVoidKeyValue {
|
||||||
|
char* key;
|
||||||
|
void* value;
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef _MILSKO
|
#ifdef _MILSKO
|
||||||
struct _MwWidget {
|
struct _MwWidget {
|
||||||
char* name;
|
char* name;
|
||||||
|
|
@ -74,6 +80,7 @@ struct _MwWidget {
|
||||||
MwIntegerKeyValue* integer;
|
MwIntegerKeyValue* integer;
|
||||||
MwTextKeyValue* text;
|
MwTextKeyValue* text;
|
||||||
MwUserHandlerKeyValue* handler;
|
MwUserHandlerKeyValue* handler;
|
||||||
|
MwVoidKeyValue* data;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,15 @@
|
||||||
struct _MwLL {
|
struct _MwLL {
|
||||||
Display* display;
|
Display* display;
|
||||||
Window window;
|
Window window;
|
||||||
|
Pixmap pixmap;
|
||||||
GC gc;
|
GC gc;
|
||||||
Colormap colormap;
|
Colormap colormap;
|
||||||
void* user;
|
void* user;
|
||||||
Atom wm_delete;
|
Atom wm_delete;
|
||||||
|
|
||||||
|
unsigned int width;
|
||||||
|
unsigned int height;
|
||||||
|
|
||||||
MwLLHandler handler;
|
MwLLHandler handler;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
24
src/button.c
24
src/button.c
|
|
@ -11,6 +11,7 @@ static void draw(MwWidget handle) {
|
||||||
MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground));
|
MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground));
|
||||||
MwLLColor text = MwParseColor(handle, MwGetText(handle, MwNforeground));
|
MwLLColor text = MwParseColor(handle, MwGetText(handle, MwNforeground));
|
||||||
const char* str = MwGetText(handle, MwNtext);
|
const char* str = MwGetText(handle, MwNtext);
|
||||||
|
MwLLPixmap px = MwGetVoid(handle, MwNpixmap);
|
||||||
|
|
||||||
if(str == NULL) str = "";
|
if(str == NULL) str = "";
|
||||||
|
|
||||||
|
|
@ -22,10 +23,33 @@ static void draw(MwWidget handle) {
|
||||||
MwDrawFrame(handle, &r, base, handle->pressed);
|
MwDrawFrame(handle, &r, base, handle->pressed);
|
||||||
MwDrawRect(handle, &r, base);
|
MwDrawRect(handle, &r, base);
|
||||||
|
|
||||||
|
if(px != NULL) {
|
||||||
|
int ow = r.width;
|
||||||
|
int oh = r.height;
|
||||||
|
|
||||||
|
double sw = (double)ow / px->width;
|
||||||
|
double sh = (double)oh / px->height;
|
||||||
|
|
||||||
|
if(sw < sh) {
|
||||||
|
r.width = px->width * sw;
|
||||||
|
r.height = px->height * sw;
|
||||||
|
} else {
|
||||||
|
r.width = px->width * sh;
|
||||||
|
r.height = px->height * sh;
|
||||||
|
}
|
||||||
|
r.width -= 10;
|
||||||
|
r.height -= 10;
|
||||||
|
|
||||||
|
r.x += (double)(ow - r.width) / 2;
|
||||||
|
r.y += (double)(oh - r.height) / 2;
|
||||||
|
|
||||||
|
MwLLDrawPixmap(handle->lowlevel, &r, px);
|
||||||
|
} else {
|
||||||
point.x = r.x + r.width / 2;
|
point.x = r.x + r.width / 2;
|
||||||
point.y = r.x + r.height / 2;
|
point.y = r.x + r.height / 2;
|
||||||
|
|
||||||
MwDrawText(handle, &point, str, text);
|
MwDrawText(handle, &point, str, text);
|
||||||
|
}
|
||||||
|
|
||||||
MwLLFreeColor(text);
|
MwLLFreeColor(text);
|
||||||
MwLLFreeColor(base);
|
MwLLFreeColor(base);
|
||||||
|
|
|
||||||
14
src/core.c
14
src/core.c
|
|
@ -57,10 +57,12 @@ MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent,
|
||||||
sh_new_strdup(h->text);
|
sh_new_strdup(h->text);
|
||||||
sh_new_strdup(h->integer);
|
sh_new_strdup(h->integer);
|
||||||
sh_new_strdup(h->handler);
|
sh_new_strdup(h->handler);
|
||||||
|
sh_new_strdup(h->data);
|
||||||
|
|
||||||
shdefault(h->integer, -1);
|
shdefault(h->integer, -1);
|
||||||
shdefault(h->text, NULL);
|
shdefault(h->text, NULL);
|
||||||
shdefault(h->handler, NULL);
|
shdefault(h->handler, NULL);
|
||||||
|
shdefault(h->data, NULL);
|
||||||
|
|
||||||
MwDispatch(h, create);
|
MwDispatch(h, create);
|
||||||
|
|
||||||
|
|
@ -122,6 +124,7 @@ void MwDestroyWidget(MwWidget handle) {
|
||||||
}
|
}
|
||||||
shfree(handle->text);
|
shfree(handle->text);
|
||||||
shfree(handle->handler);
|
shfree(handle->handler);
|
||||||
|
shfree(handle->data);
|
||||||
|
|
||||||
free(handle);
|
free(handle);
|
||||||
}
|
}
|
||||||
|
|
@ -182,6 +185,10 @@ void MwSetText(MwWidget handle, const char* key, const char* value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MwSetVoid(MwWidget handle, const char* key, void* value) {
|
||||||
|
shput(handle->data, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
int MwGetInteger(MwWidget handle, const char* key) {
|
int MwGetInteger(MwWidget handle, const char* key) {
|
||||||
if(strcmp(key, MwNx) == 0 || strcmp(key, MwNy) == 0 || strcmp(key, MwNwidth) == 0 || strcmp(key, MwNheight) == 0) {
|
if(strcmp(key, MwNx) == 0 || strcmp(key, MwNy) == 0 || strcmp(key, MwNwidth) == 0 || strcmp(key, MwNheight) == 0) {
|
||||||
int x, y;
|
int x, y;
|
||||||
|
|
@ -203,6 +210,10 @@ const char* MwGetText(MwWidget handle, const char* key) {
|
||||||
return shget(handle->text, key);
|
return shget(handle->text, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* MwGetVoid(MwWidget handle, const char* key) {
|
||||||
|
return shget(handle->data, key);
|
||||||
|
}
|
||||||
|
|
||||||
void MwVaApply(MwWidget handle, ...) {
|
void MwVaApply(MwWidget handle, ...) {
|
||||||
va_list va;
|
va_list va;
|
||||||
|
|
||||||
|
|
@ -228,6 +239,9 @@ void MwVaListApply(MwWidget handle, va_list va) {
|
||||||
shput(handle->handler, key, h);
|
shput(handle->handler, key, h);
|
||||||
ind = shgeti(handle->handler, key);
|
ind = shgeti(handle->handler, key);
|
||||||
handle->handler[ind].user_data = NULL;
|
handle->handler[ind].user_data = NULL;
|
||||||
|
} else if(key[0] == 'V') {
|
||||||
|
void* v = va_arg(va, void*);
|
||||||
|
MwSetVoid(handle, key, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
16
src/draw.c
16
src/draw.c
|
|
@ -1,6 +1,8 @@
|
||||||
/* $Id$ */
|
/* $Id$ */
|
||||||
#include <Mw/Milsko.h>
|
#include <Mw/Milsko.h>
|
||||||
|
|
||||||
|
#include <stb_image.h>
|
||||||
|
|
||||||
static int hex(const char* txt, int len) {
|
static int hex(const char* txt, int len) {
|
||||||
int i;
|
int i;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
|
@ -145,3 +147,17 @@ void MwDrawText(MwWidget handle, MwPoint* point, const char* text, MwLLColor col
|
||||||
sx += fw * sc;
|
sx += fw * sc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MwLLPixmap MwLoadImage(MwWidget handle, const char* path) {
|
||||||
|
int width, height, ch;
|
||||||
|
unsigned char* rgb = stbi_load(path, &width, &height, &ch, 3);
|
||||||
|
MwLLPixmap px;
|
||||||
|
|
||||||
|
if(rgb == NULL) return NULL;
|
||||||
|
|
||||||
|
px = MwLLCreatePixmap(handle->lowlevel, rgb, width, height);
|
||||||
|
|
||||||
|
free(rgb);
|
||||||
|
|
||||||
|
return px;
|
||||||
|
}
|
||||||
|
|
|
||||||
3
src/image.c
Normal file
3
src/image.c
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
/* $Id$ */
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "stb_image.h"
|
||||||
239
src/stb_ds.h
generated
239
src/stb_ds.h
generated
|
|
@ -556,8 +556,7 @@ extern void* stbds_shmode_func(size_t elemsize, int mode);
|
||||||
#define stbds_arrins(a,i,v) (stbds_arrinsn((a),(i),1), (a)[i]=(v))
|
#define stbds_arrins(a,i,v) (stbds_arrinsn((a),(i),1), (a)[i]=(v))
|
||||||
|
|
||||||
#define stbds_arrmaybegrow(a,n) ((!(a) || stbds_header(a)->length + (n) > stbds_header(a)->capacity) \
|
#define stbds_arrmaybegrow(a,n) ((!(a) || stbds_header(a)->length + (n) > stbds_header(a)->capacity) \
|
||||||
? (stbds_arrgrow(a, n, 0), 0) \
|
? (stbds_arrgrow(a,n,0),0) : 0)
|
||||||
: 0)
|
|
||||||
|
|
||||||
#define stbds_arrgrow(a,b,c) ((a) = stbds_arrgrowf_wrapper((a), sizeof *(a), (b), (c)))
|
#define stbds_arrgrow(a,b,c) ((a) = stbds_arrgrowf_wrapper((a), sizeof *(a), (b), (c)))
|
||||||
|
|
||||||
|
|
@ -663,12 +662,14 @@ typedef struct
|
||||||
ptrdiff_t temp;
|
ptrdiff_t temp;
|
||||||
} stbds_array_header;
|
} stbds_array_header;
|
||||||
|
|
||||||
typedef struct stbds_string_block {
|
typedef struct stbds_string_block
|
||||||
|
{
|
||||||
struct stbds_string_block *next;
|
struct stbds_string_block *next;
|
||||||
char storage[8];
|
char storage[8];
|
||||||
} stbds_string_block;
|
} stbds_string_block;
|
||||||
|
|
||||||
struct stbds_string_arena {
|
struct stbds_string_arena
|
||||||
|
{
|
||||||
stbds_string_block *storage;
|
stbds_string_block *storage;
|
||||||
size_t remaining;
|
size_t remaining;
|
||||||
unsigned char block;
|
unsigned char block;
|
||||||
|
|
@ -678,7 +679,8 @@ struct stbds_string_arena {
|
||||||
#define STBDS_HM_BINARY 0
|
#define STBDS_HM_BINARY 0
|
||||||
#define STBDS_HM_STRING 1
|
#define STBDS_HM_STRING 1
|
||||||
|
|
||||||
enum {
|
enum
|
||||||
|
{
|
||||||
STBDS_SH_NONE,
|
STBDS_SH_NONE,
|
||||||
STBDS_SH_DEFAULT,
|
STBDS_SH_DEFAULT,
|
||||||
STBDS_SH_STRDUP,
|
STBDS_SH_STRDUP,
|
||||||
|
|
@ -688,32 +690,25 @@ enum {
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
// in C we use implicit assignment from these void*-returning functions to T*.
|
// in C we use implicit assignment from these void*-returning functions to T*.
|
||||||
// in C++ these templates make the same code work
|
// in C++ these templates make the same code work
|
||||||
template <class T>
|
template<class T> static T * stbds_arrgrowf_wrapper(T *a, size_t elemsize, size_t addlen, size_t min_cap) {
|
||||||
static T* stbds_arrgrowf_wrapper(T* a, size_t elemsize, size_t addlen, size_t min_cap) {
|
|
||||||
return (T*)stbds_arrgrowf((void *)a, elemsize, addlen, min_cap);
|
return (T*)stbds_arrgrowf((void *)a, elemsize, addlen, min_cap);
|
||||||
}
|
}
|
||||||
template <class T>
|
template<class T> static T * stbds_hmget_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, int mode) {
|
||||||
static T* stbds_hmget_key_wrapper(T* a, size_t elemsize, void* key, size_t keysize, int mode) {
|
|
||||||
return (T*)stbds_hmget_key((void*)a, elemsize, key, keysize, mode);
|
return (T*)stbds_hmget_key((void*)a, elemsize, key, keysize, mode);
|
||||||
}
|
}
|
||||||
template <class T>
|
template<class T> static T * stbds_hmget_key_ts_wrapper(T *a, size_t elemsize, void *key, size_t keysize, ptrdiff_t *temp, int mode) {
|
||||||
static T* stbds_hmget_key_ts_wrapper(T* a, size_t elemsize, void* key, size_t keysize, ptrdiff_t* temp, int mode) {
|
|
||||||
return (T*)stbds_hmget_key_ts((void*)a, elemsize, key, keysize, temp, mode);
|
return (T*)stbds_hmget_key_ts((void*)a, elemsize, key, keysize, temp, mode);
|
||||||
}
|
}
|
||||||
template <class T>
|
template<class T> static T * stbds_hmput_default_wrapper(T *a, size_t elemsize) {
|
||||||
static T* stbds_hmput_default_wrapper(T* a, size_t elemsize) {
|
|
||||||
return (T*)stbds_hmput_default((void *)a, elemsize);
|
return (T*)stbds_hmput_default((void *)a, elemsize);
|
||||||
}
|
}
|
||||||
template <class T>
|
template<class T> static T * stbds_hmput_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, int mode) {
|
||||||
static T* stbds_hmput_key_wrapper(T* a, size_t elemsize, void* key, size_t keysize, int mode) {
|
|
||||||
return (T*)stbds_hmput_key((void*)a, elemsize, key, keysize, mode);
|
return (T*)stbds_hmput_key((void*)a, elemsize, key, keysize, mode);
|
||||||
}
|
}
|
||||||
template <class T>
|
template<class T> static T * stbds_hmdel_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode){
|
||||||
static T* stbds_hmdel_key_wrapper(T* a, size_t elemsize, void* key, size_t keysize, size_t keyoffset, int mode) {
|
|
||||||
return (T*)stbds_hmdel_key((void*)a, elemsize, key, keysize, keyoffset, mode);
|
return (T*)stbds_hmdel_key((void*)a, elemsize, key, keysize, keyoffset, mode);
|
||||||
}
|
}
|
||||||
template <class T>
|
template<class T> static T * stbds_shmode_func_wrapper(T *, size_t elemsize, int mode) {
|
||||||
static T* stbds_shmode_func_wrapper(T*, size_t elemsize, int mode) {
|
|
||||||
return (T*)stbds_shmode_func(elemsize, mode);
|
return (T*)stbds_shmode_func(elemsize, mode);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
@ -728,6 +723,7 @@ static T* stbds_shmode_func_wrapper(T*, size_t elemsize, int mode) {
|
||||||
|
|
||||||
#endif // INCLUDE_STB_DS_H
|
#endif // INCLUDE_STB_DS_H
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// IMPLEMENTATION
|
// IMPLEMENTATION
|
||||||
|
|
@ -763,7 +759,8 @@ size_t stbds_rehash_items;
|
||||||
//int *prev_allocs[65536];
|
//int *prev_allocs[65536];
|
||||||
//int num_prev;
|
//int num_prev;
|
||||||
|
|
||||||
void* stbds_arrgrowf(void* a, size_t elemsize, size_t addlen, size_t min_cap) {
|
void *stbds_arrgrowf(void *a, size_t elemsize, size_t addlen, size_t min_cap)
|
||||||
|
{
|
||||||
stbds_array_header temp={0}; // force debugging
|
stbds_array_header temp={0}; // force debugging
|
||||||
void *b;
|
void *b;
|
||||||
size_t min_len = stbds_arrlen(a) + addlen;
|
size_t min_len = stbds_arrlen(a) + addlen;
|
||||||
|
|
@ -800,7 +797,8 @@ void* stbds_arrgrowf(void* a, size_t elemsize, size_t addlen, size_t min_cap) {
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
void stbds_arrfreef(void* a) {
|
void stbds_arrfreef(void *a)
|
||||||
|
{
|
||||||
STBDS_FREE(NULL, stbds_header(a));
|
STBDS_FREE(NULL, stbds_header(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -850,7 +848,8 @@ typedef struct
|
||||||
|
|
||||||
static size_t stbds_hash_seed=0x31415926;
|
static size_t stbds_hash_seed=0x31415926;
|
||||||
|
|
||||||
void stbds_rand_seed(size_t seed) {
|
void stbds_rand_seed(size_t seed)
|
||||||
|
{
|
||||||
stbds_hash_seed = seed;
|
stbds_hash_seed = seed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -861,7 +860,8 @@ void stbds_rand_seed(size_t seed) {
|
||||||
|
|
||||||
#define STBDS_SIZE_T_BITS ((sizeof (size_t)) * 8)
|
#define STBDS_SIZE_T_BITS ((sizeof (size_t)) * 8)
|
||||||
|
|
||||||
static size_t stbds_probe_position(size_t hash, size_t slot_count, size_t slot_log2) {
|
static size_t stbds_probe_position(size_t hash, size_t slot_count, size_t slot_log2)
|
||||||
|
{
|
||||||
size_t pos;
|
size_t pos;
|
||||||
STBDS_NOTUSED(slot_log2);
|
STBDS_NOTUSED(slot_log2);
|
||||||
pos = hash & (slot_count-1);
|
pos = hash & (slot_count-1);
|
||||||
|
|
@ -871,7 +871,8 @@ static size_t stbds_probe_position(size_t hash, size_t slot_count, size_t slot_l
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t stbds_log2(size_t slot_count) {
|
static size_t stbds_log2(size_t slot_count)
|
||||||
|
{
|
||||||
size_t n=0;
|
size_t n=0;
|
||||||
while (slot_count > 1) {
|
while (slot_count > 1) {
|
||||||
slot_count >>= 1;
|
slot_count >>= 1;
|
||||||
|
|
@ -880,7 +881,8 @@ static size_t stbds_log2(size_t slot_count) {
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static stbds_hash_index* stbds_make_hash_index(size_t slot_count, stbds_hash_index* ot) {
|
static stbds_hash_index *stbds_make_hash_index(size_t slot_count, stbds_hash_index *ot)
|
||||||
|
{
|
||||||
stbds_hash_index *t;
|
stbds_hash_index *t;
|
||||||
t = (stbds_hash_index *) STBDS_REALLOC(NULL,0,(slot_count >> STBDS_BUCKET_SHIFT) * sizeof(stbds_hash_bucket) + sizeof(stbds_hash_index) + STBDS_CACHE_LINE_SIZE-1);
|
t = (stbds_hash_index *) STBDS_REALLOC(NULL,0,(slot_count >> STBDS_BUCKET_SHIFT) * sizeof(stbds_hash_bucket) + sizeof(stbds_hash_index) + STBDS_CACHE_LINE_SIZE-1);
|
||||||
t->storage = (stbds_hash_bucket *) STBDS_ALIGN_FWD((size_t) (t+1), STBDS_CACHE_LINE_SIZE);
|
t->storage = (stbds_hash_bucket *) STBDS_ALIGN_FWD((size_t) (t+1), STBDS_CACHE_LINE_SIZE);
|
||||||
|
|
@ -999,7 +1001,8 @@ static stbds_hash_index* stbds_make_hash_index(size_t slot_count, stbds_hash_ind
|
||||||
pos &= (t->slot_count-1);
|
pos &= (t->slot_count-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
done:;
|
done:
|
||||||
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1010,7 +1013,8 @@ static stbds_hash_index* stbds_make_hash_index(size_t slot_count, stbds_hash_ind
|
||||||
#define STBDS_ROTATE_LEFT(val, n) (((val) << (n)) | ((val) >> (STBDS_SIZE_T_BITS - (n))))
|
#define STBDS_ROTATE_LEFT(val, n) (((val) << (n)) | ((val) >> (STBDS_SIZE_T_BITS - (n))))
|
||||||
#define STBDS_ROTATE_RIGHT(val, n) (((val) >> (n)) | ((val) << (STBDS_SIZE_T_BITS - (n))))
|
#define STBDS_ROTATE_RIGHT(val, n) (((val) >> (n)) | ((val) << (STBDS_SIZE_T_BITS - (n))))
|
||||||
|
|
||||||
size_t stbds_hash_string(char* str, size_t seed) {
|
size_t stbds_hash_string(char *str, size_t seed)
|
||||||
|
{
|
||||||
size_t hash = seed;
|
size_t hash = seed;
|
||||||
while (*str)
|
while (*str)
|
||||||
hash = STBDS_ROTATE_LEFT(hash, 9) + (unsigned char) *str++;
|
hash = STBDS_ROTATE_LEFT(hash, 9) + (unsigned char) *str++;
|
||||||
|
|
@ -1044,7 +1048,8 @@ typedef int STBDS_SIPHASH_2_4_can_only_be_used_in_64_bit_builds[sizeof(size_t) =
|
||||||
#pragma warning(disable:4127) // conditional expression is constant, for do..while(0) and sizeof()==
|
#pragma warning(disable:4127) // conditional expression is constant, for do..while(0) and sizeof()==
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static size_t stbds_siphash_bytes(void* p, size_t len, size_t seed) {
|
static size_t stbds_siphash_bytes(void *p, size_t len, size_t seed)
|
||||||
|
{
|
||||||
unsigned char *d = (unsigned char *) p;
|
unsigned char *d = (unsigned char *) p;
|
||||||
size_t i,j;
|
size_t i,j;
|
||||||
size_t v0,v1,v2,v3, data;
|
size_t v0,v1,v2,v3, data;
|
||||||
|
|
@ -1067,20 +1072,10 @@ static size_t stbds_siphash_bytes(void* p, size_t len, size_t seed) {
|
||||||
|
|
||||||
#define STBDS_SIPROUND() \
|
#define STBDS_SIPROUND() \
|
||||||
do { \
|
do { \
|
||||||
v0 += v1; \
|
v0 += v1; v1 = STBDS_ROTATE_LEFT(v1, 13); v1 ^= v0; v0 = STBDS_ROTATE_LEFT(v0,STBDS_SIZE_T_BITS/2); \
|
||||||
v1 = STBDS_ROTATE_LEFT(v1, 13); \
|
v2 += v3; v3 = STBDS_ROTATE_LEFT(v3, 16); v3 ^= v2; \
|
||||||
v1 ^= v0; \
|
v2 += v1; v1 = STBDS_ROTATE_LEFT(v1, 17); v1 ^= v2; v2 = STBDS_ROTATE_LEFT(v2,STBDS_SIZE_T_BITS/2); \
|
||||||
v0 = STBDS_ROTATE_LEFT(v0, STBDS_SIZE_T_BITS / 2); \
|
v0 += v3; v3 = STBDS_ROTATE_LEFT(v3, 21); v3 ^= v0; \
|
||||||
v2 += v3; \
|
|
||||||
v3 = STBDS_ROTATE_LEFT(v3, 16); \
|
|
||||||
v3 ^= v2; \
|
|
||||||
v2 += v1; \
|
|
||||||
v1 = STBDS_ROTATE_LEFT(v1, 17); \
|
|
||||||
v1 ^= v2; \
|
|
||||||
v2 = STBDS_ROTATE_LEFT(v2, STBDS_SIZE_T_BITS / 2); \
|
|
||||||
v0 += v3; \
|
|
||||||
v3 = STBDS_ROTATE_LEFT(v3, 21); \
|
|
||||||
v3 ^= v0; \
|
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
for (i=0; i+sizeof(size_t) <= len; i += sizeof(size_t), d += sizeof(size_t)) {
|
for (i=0; i+sizeof(size_t) <= len; i += sizeof(size_t), d += sizeof(size_t)) {
|
||||||
|
|
@ -1094,22 +1089,14 @@ static size_t stbds_siphash_bytes(void* p, size_t len, size_t seed) {
|
||||||
}
|
}
|
||||||
data = len << (STBDS_SIZE_T_BITS-8);
|
data = len << (STBDS_SIZE_T_BITS-8);
|
||||||
switch (len - i) {
|
switch (len - i) {
|
||||||
case 7:
|
case 7: data |= ((size_t) d[6] << 24) << 24; // fall through
|
||||||
data |= ((size_t)d[6] << 24) << 24; // fall through
|
case 6: data |= ((size_t) d[5] << 20) << 20; // fall through
|
||||||
case 6:
|
case 5: data |= ((size_t) d[4] << 16) << 16; // fall through
|
||||||
data |= ((size_t)d[5] << 20) << 20; // fall through
|
case 4: data |= (d[3] << 24); // fall through
|
||||||
case 5:
|
case 3: data |= (d[2] << 16); // fall through
|
||||||
data |= ((size_t)d[4] << 16) << 16; // fall through
|
case 2: data |= (d[1] << 8); // fall through
|
||||||
case 4:
|
case 1: data |= d[0]; // fall through
|
||||||
data |= (d[3] << 24); // fall through
|
case 0: break;
|
||||||
case 3:
|
|
||||||
data |= (d[2] << 16); // fall through
|
|
||||||
case 2:
|
|
||||||
data |= (d[1] << 8); // fall through
|
|
||||||
case 1:
|
|
||||||
data |= d[0]; // fall through
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
v3 ^= data;
|
v3 ^= data;
|
||||||
for (j=0; j < STBDS_SIPHASH_C_ROUNDS; ++j)
|
for (j=0; j < STBDS_SIPHASH_C_ROUNDS; ++j)
|
||||||
|
|
@ -1126,7 +1113,8 @@ static size_t stbds_siphash_bytes(void* p, size_t len, size_t seed) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t stbds_hash_bytes(void* p, size_t len, size_t seed) {
|
size_t stbds_hash_bytes(void *p, size_t len, size_t seed)
|
||||||
|
{
|
||||||
#ifdef STBDS_SIPHASH_2_4
|
#ifdef STBDS_SIPHASH_2_4
|
||||||
return stbds_siphash_bytes(p,len,seed);
|
return stbds_siphash_bytes(p,len,seed);
|
||||||
#else
|
#else
|
||||||
|
|
@ -1211,7 +1199,9 @@ size_t stbds_hash_bytes(void* p, size_t len, size_t seed) {
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int stbds_is_key_equal(void* a, size_t elemsize, void* key, size_t keysize, size_t keyoffset, int mode, size_t i) {
|
|
||||||
|
static int stbds_is_key_equal(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode, size_t i)
|
||||||
|
{
|
||||||
if (mode >= STBDS_HM_STRING)
|
if (mode >= STBDS_HM_STRING)
|
||||||
return 0==strcmp((char *) key, * (char **) ((char *) a + elemsize*i + keyoffset));
|
return 0==strcmp((char *) key, * (char **) ((char *) a + elemsize*i + keyoffset));
|
||||||
else
|
else
|
||||||
|
|
@ -1223,7 +1213,8 @@ static int stbds_is_key_equal(void* a, size_t elemsize, void* key, size_t keysiz
|
||||||
|
|
||||||
#define stbds_hash_table(a) ((stbds_hash_index *) stbds_header(a)->hash_table)
|
#define stbds_hash_table(a) ((stbds_hash_index *) stbds_header(a)->hash_table)
|
||||||
|
|
||||||
void stbds_hmfree_func(void* a, size_t elemsize) {
|
void stbds_hmfree_func(void *a, size_t elemsize)
|
||||||
|
{
|
||||||
if (a == NULL) return;
|
if (a == NULL) return;
|
||||||
if (stbds_hash_table(a) != NULL) {
|
if (stbds_hash_table(a) != NULL) {
|
||||||
if (stbds_hash_table(a)->string.mode == STBDS_SH_STRDUP) {
|
if (stbds_hash_table(a)->string.mode == STBDS_SH_STRDUP) {
|
||||||
|
|
@ -1238,7 +1229,8 @@ void stbds_hmfree_func(void* a, size_t elemsize) {
|
||||||
STBDS_FREE(NULL, stbds_header(a));
|
STBDS_FREE(NULL, stbds_header(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
static ptrdiff_t stbds_hm_find_slot(void* a, size_t elemsize, void* key, size_t keysize, size_t keyoffset, int mode) {
|
static ptrdiff_t stbds_hm_find_slot(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode)
|
||||||
|
{
|
||||||
void *raw_a = STBDS_HASH_TO_ARR(a,elemsize);
|
void *raw_a = STBDS_HASH_TO_ARR(a,elemsize);
|
||||||
stbds_hash_index *table = stbds_hash_table(raw_a);
|
stbds_hash_index *table = stbds_hash_table(raw_a);
|
||||||
size_t hash = mode >= STBDS_HM_STRING ? stbds_hash_string((char*)key,table->seed) : stbds_hash_bytes(key, keysize,table->seed);
|
size_t hash = mode >= STBDS_HM_STRING ? stbds_hash_string((char*)key,table->seed) : stbds_hash_bytes(key, keysize,table->seed);
|
||||||
|
|
@ -1286,7 +1278,8 @@ static ptrdiff_t stbds_hm_find_slot(void* a, size_t elemsize, void* key, size_t
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
}
|
}
|
||||||
|
|
||||||
void* stbds_hmget_key_ts(void* a, size_t elemsize, void* key, size_t keysize, ptrdiff_t* temp, int mode) {
|
void * stbds_hmget_key_ts(void *a, size_t elemsize, void *key, size_t keysize, ptrdiff_t *temp, int mode)
|
||||||
|
{
|
||||||
size_t keyoffset = 0;
|
size_t keyoffset = 0;
|
||||||
if (a == NULL) {
|
if (a == NULL) {
|
||||||
// make it non-empty so we can return a temp
|
// make it non-empty so we can return a temp
|
||||||
|
|
@ -1316,14 +1309,16 @@ void* stbds_hmget_key_ts(void* a, size_t elemsize, void* key, size_t keysize, pt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void* stbds_hmget_key(void* a, size_t elemsize, void* key, size_t keysize, int mode) {
|
void * stbds_hmget_key(void *a, size_t elemsize, void *key, size_t keysize, int mode)
|
||||||
|
{
|
||||||
ptrdiff_t temp;
|
ptrdiff_t temp;
|
||||||
void *p = stbds_hmget_key_ts(a, elemsize, key, keysize, &temp, mode);
|
void *p = stbds_hmget_key_ts(a, elemsize, key, keysize, &temp, mode);
|
||||||
stbds_temp(STBDS_HASH_TO_ARR(p,elemsize)) = temp;
|
stbds_temp(STBDS_HASH_TO_ARR(p,elemsize)) = temp;
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* stbds_hmput_default(void* a, size_t elemsize) {
|
void * stbds_hmput_default(void *a, size_t elemsize)
|
||||||
|
{
|
||||||
// three cases:
|
// three cases:
|
||||||
// a is NULL <- allocate
|
// a is NULL <- allocate
|
||||||
// a has a hash table but no entries, because of shmode <- grow
|
// a has a hash table but no entries, because of shmode <- grow
|
||||||
|
|
@ -1339,7 +1334,8 @@ void* stbds_hmput_default(void* a, size_t elemsize) {
|
||||||
|
|
||||||
static char *stbds_strdup(char *str);
|
static char *stbds_strdup(char *str);
|
||||||
|
|
||||||
void* stbds_hmput_key(void* a, size_t elemsize, void* key, size_t keysize, int mode) {
|
void *stbds_hmput_key(void *a, size_t elemsize, void *key, size_t keysize, int mode)
|
||||||
|
{
|
||||||
size_t keyoffset=0;
|
size_t keyoffset=0;
|
||||||
void *raw_a;
|
void *raw_a;
|
||||||
stbds_hash_index *table;
|
stbds_hash_index *table;
|
||||||
|
|
@ -1452,25 +1448,18 @@ void* stbds_hmput_key(void* a, size_t elemsize, void* key, size_t keysize, int m
|
||||||
stbds_temp(a) = i-1;
|
stbds_temp(a) = i-1;
|
||||||
|
|
||||||
switch (table->string.mode) {
|
switch (table->string.mode) {
|
||||||
case STBDS_SH_STRDUP:
|
case STBDS_SH_STRDUP: stbds_temp_key(a) = *(char **) ((char *) a + elemsize*i) = stbds_strdup((char*) key); break;
|
||||||
stbds_temp_key(a) = *(char**)((char*)a + elemsize * i) = stbds_strdup((char*)key);
|
case STBDS_SH_ARENA: stbds_temp_key(a) = *(char **) ((char *) a + elemsize*i) = stbds_stralloc(&table->string, (char*)key); break;
|
||||||
break;
|
case STBDS_SH_DEFAULT: stbds_temp_key(a) = *(char **) ((char *) a + elemsize*i) = (char *) key; break;
|
||||||
case STBDS_SH_ARENA:
|
default: memcpy((char *) a + elemsize*i, key, keysize); break;
|
||||||
stbds_temp_key(a) = *(char**)((char*)a + elemsize * i) = stbds_stralloc(&table->string, (char*)key);
|
|
||||||
break;
|
|
||||||
case STBDS_SH_DEFAULT:
|
|
||||||
stbds_temp_key(a) = *(char**)((char*)a + elemsize * i) = (char*)key;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
memcpy((char*)a + elemsize * i, key, keysize);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return STBDS_ARR_TO_HASH(a,elemsize);
|
return STBDS_ARR_TO_HASH(a,elemsize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void* stbds_shmode_func(size_t elemsize, int mode) {
|
void * stbds_shmode_func(size_t elemsize, int mode)
|
||||||
|
{
|
||||||
void *a = stbds_arrgrowf(0, elemsize, 0, 1);
|
void *a = stbds_arrgrowf(0, elemsize, 0, 1);
|
||||||
stbds_hash_index *h;
|
stbds_hash_index *h;
|
||||||
memset(a, 0, elemsize);
|
memset(a, 0, elemsize);
|
||||||
|
|
@ -1480,7 +1469,8 @@ void* stbds_shmode_func(size_t elemsize, int mode) {
|
||||||
return STBDS_ARR_TO_HASH(a,elemsize);
|
return STBDS_ARR_TO_HASH(a,elemsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* stbds_hmdel_key(void* a, size_t elemsize, void* key, size_t keysize, size_t keyoffset, int mode) {
|
void * stbds_hmdel_key(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode)
|
||||||
|
{
|
||||||
if (a == NULL) {
|
if (a == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1547,7 +1537,8 @@ void* stbds_hmdel_key(void* a, size_t elemsize, void* key, size_t keysize, size_
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
}
|
}
|
||||||
|
|
||||||
static char* stbds_strdup(char* str) {
|
static char *stbds_strdup(char *str)
|
||||||
|
{
|
||||||
// to keep replaceable allocator simple, we don't want to use strdup.
|
// to keep replaceable allocator simple, we don't want to use strdup.
|
||||||
// rolling our own also avoids problem of strdup vs _strdup
|
// rolling our own also avoids problem of strdup vs _strdup
|
||||||
size_t len = strlen(str)+1;
|
size_t len = strlen(str)+1;
|
||||||
|
|
@ -1563,7 +1554,8 @@ static char* stbds_strdup(char* str) {
|
||||||
#define STBDS_STRING_ARENA_BLOCKSIZE_MAX (1u<<20)
|
#define STBDS_STRING_ARENA_BLOCKSIZE_MAX (1u<<20)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char* stbds_stralloc(stbds_string_arena* a, char* str) {
|
char *stbds_stralloc(stbds_string_arena *a, char *str)
|
||||||
|
{
|
||||||
char *p;
|
char *p;
|
||||||
size_t len = strlen(str)+1;
|
size_t len = strlen(str)+1;
|
||||||
if (len > a->remaining) {
|
if (len > a->remaining) {
|
||||||
|
|
@ -1610,7 +1602,8 @@ char* stbds_stralloc(stbds_string_arena* a, char* str) {
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void stbds_strreset(stbds_string_arena* a) {
|
void stbds_strreset(stbds_string_arena *a)
|
||||||
|
{
|
||||||
stbds_string_block *x,*y;
|
stbds_string_block *x,*y;
|
||||||
x = a->storage;
|
x = a->storage;
|
||||||
while (x) {
|
while (x) {
|
||||||
|
|
@ -1638,15 +1631,12 @@ void stbds_strreset(stbds_string_arena* a) {
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct { int key,b,c,d; } stbds_struct;
|
||||||
int key, b, c, d;
|
typedef struct { int key[2],b,c,d; } stbds_struct2;
|
||||||
} stbds_struct;
|
|
||||||
typedef struct {
|
|
||||||
int key[2], b, c, d;
|
|
||||||
} stbds_struct2;
|
|
||||||
|
|
||||||
static char buffer[256];
|
static char buffer[256];
|
||||||
char* strkey(int n) {
|
char *strkey(int n)
|
||||||
|
{
|
||||||
#if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__)
|
#if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__)
|
||||||
sprintf_s(buffer, sizeof(buffer), "test_%d", n);
|
sprintf_s(buffer, sizeof(buffer), "test_%d", n);
|
||||||
#else
|
#else
|
||||||
|
|
@ -1655,7 +1645,8 @@ char* strkey(int n) {
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void stbds_unit_tests(void) {
|
void stbds_unit_tests(void)
|
||||||
|
{
|
||||||
#if defined(_MSC_VER) && _MSC_VER <= 1200 && defined(__cplusplus)
|
#if defined(_MSC_VER) && _MSC_VER <= 1200 && defined(__cplusplus)
|
||||||
// VC6 C++ doesn't like the template<> trick on unnamed structures, so do nothing!
|
// VC6 C++ doesn't like the template<> trick on unnamed structures, so do nothing!
|
||||||
STBDS_ASSERT(0);
|
STBDS_ASSERT(0);
|
||||||
|
|
@ -1663,18 +1654,9 @@ void stbds_unit_tests(void) {
|
||||||
const int testsize = 100000;
|
const int testsize = 100000;
|
||||||
const int testsize2 = testsize/20;
|
const int testsize2 = testsize/20;
|
||||||
int *arr=NULL;
|
int *arr=NULL;
|
||||||
struct {
|
struct { int key; int value; } *intmap = NULL;
|
||||||
int key;
|
struct { char *key; int value; } *strmap = NULL, s;
|
||||||
int value;
|
struct { stbds_struct key; int value; } *map = NULL;
|
||||||
}* intmap = NULL;
|
|
||||||
struct {
|
|
||||||
char* key;
|
|
||||||
int value;
|
|
||||||
} *strmap = NULL, s;
|
|
||||||
struct {
|
|
||||||
stbds_struct key;
|
|
||||||
int value;
|
|
||||||
}* map = NULL;
|
|
||||||
stbds_struct *map2 = NULL;
|
stbds_struct *map2 = NULL;
|
||||||
stbds_struct2 *map3 = NULL;
|
stbds_struct2 *map3 = NULL;
|
||||||
stbds_string_arena sa = { 0 };
|
stbds_string_arena sa = { 0 };
|
||||||
|
|
@ -1691,25 +1673,16 @@ void stbds_unit_tests(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=0; i < 4; ++i) {
|
for (i=0; i < 4; ++i) {
|
||||||
arrpush(arr, 1);
|
arrpush(arr,1); arrpush(arr,2); arrpush(arr,3); arrpush(arr,4);
|
||||||
arrpush(arr, 2);
|
|
||||||
arrpush(arr, 3);
|
|
||||||
arrpush(arr, 4);
|
|
||||||
arrdel(arr,i);
|
arrdel(arr,i);
|
||||||
arrfree(arr);
|
arrfree(arr);
|
||||||
arrpush(arr, 1);
|
arrpush(arr,1); arrpush(arr,2); arrpush(arr,3); arrpush(arr,4);
|
||||||
arrpush(arr, 2);
|
|
||||||
arrpush(arr, 3);
|
|
||||||
arrpush(arr, 4);
|
|
||||||
arrdelswap(arr,i);
|
arrdelswap(arr,i);
|
||||||
arrfree(arr);
|
arrfree(arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=0; i < 5; ++i) {
|
for (i=0; i < 5; ++i) {
|
||||||
arrpush(arr, 1);
|
arrpush(arr,1); arrpush(arr,2); arrpush(arr,3); arrpush(arr,4);
|
||||||
arrpush(arr, 2);
|
|
||||||
arrpush(arr, 3);
|
|
||||||
arrpush(arr, 4);
|
|
||||||
stbds_arrins(arr,i,5);
|
stbds_arrins(arr,i,5);
|
||||||
STBDS_ASSERT(arr[i] == 5);
|
STBDS_ASSERT(arr[i] == 5);
|
||||||
if (i < 4)
|
if (i < 4)
|
||||||
|
|
@ -1726,24 +1699,20 @@ void stbds_unit_tests(void) {
|
||||||
hmput(intmap, i, i*5);
|
hmput(intmap, i, i*5);
|
||||||
for (i=0; i < testsize; i+=1) {
|
for (i=0; i < testsize; i+=1) {
|
||||||
if (i & 1) STBDS_ASSERT(hmget(intmap, i) == -2 );
|
if (i & 1) STBDS_ASSERT(hmget(intmap, i) == -2 );
|
||||||
else
|
else STBDS_ASSERT(hmget(intmap, i) == i*5);
|
||||||
STBDS_ASSERT(hmget(intmap, i) == i * 5);
|
|
||||||
if (i & 1) STBDS_ASSERT(hmget_ts(intmap, i, temp) == -2 );
|
if (i & 1) STBDS_ASSERT(hmget_ts(intmap, i, temp) == -2 );
|
||||||
else
|
else STBDS_ASSERT(hmget_ts(intmap, i, temp) == i*5);
|
||||||
STBDS_ASSERT(hmget_ts(intmap, i, temp) == i * 5);
|
|
||||||
}
|
}
|
||||||
for (i=0; i < testsize; i+=2)
|
for (i=0; i < testsize; i+=2)
|
||||||
hmput(intmap, i, i*3);
|
hmput(intmap, i, i*3);
|
||||||
for (i=0; i < testsize; i+=1)
|
for (i=0; i < testsize; i+=1)
|
||||||
if (i & 1) STBDS_ASSERT(hmget(intmap, i) == -2 );
|
if (i & 1) STBDS_ASSERT(hmget(intmap, i) == -2 );
|
||||||
else
|
else STBDS_ASSERT(hmget(intmap, i) == i*3);
|
||||||
STBDS_ASSERT(hmget(intmap, i) == i * 3);
|
|
||||||
for (i=2; i < testsize; i+=4)
|
for (i=2; i < testsize; i+=4)
|
||||||
hmdel(intmap, i); // delete half the entries
|
hmdel(intmap, i); // delete half the entries
|
||||||
for (i=0; i < testsize; i+=1)
|
for (i=0; i < testsize; i+=1)
|
||||||
if (i & 3) STBDS_ASSERT(hmget(intmap, i) == -2 );
|
if (i & 3) STBDS_ASSERT(hmget(intmap, i) == -2 );
|
||||||
else
|
else STBDS_ASSERT(hmget(intmap, i) == i*3);
|
||||||
STBDS_ASSERT(hmget(intmap, i) == i * 3);
|
|
||||||
for (i=0; i < testsize; i+=1)
|
for (i=0; i < testsize; i+=1)
|
||||||
hmdel(intmap, i); // delete the rest of the entries
|
hmdel(intmap, i); // delete the rest of the entries
|
||||||
for (i=0; i < testsize; i+=1)
|
for (i=0; i < testsize; i+=1)
|
||||||
|
|
@ -1811,14 +1780,12 @@ void stbds_unit_tests(void) {
|
||||||
shput(strmap, strkey(i), i*3);
|
shput(strmap, strkey(i), i*3);
|
||||||
for (i=0; i < testsize; i+=1)
|
for (i=0; i < testsize; i+=1)
|
||||||
if (i & 1) STBDS_ASSERT(shget(strmap, strkey(i)) == -2 );
|
if (i & 1) STBDS_ASSERT(shget(strmap, strkey(i)) == -2 );
|
||||||
else
|
else STBDS_ASSERT(shget(strmap, strkey(i)) == i*3);
|
||||||
STBDS_ASSERT(shget(strmap, strkey(i)) == i * 3);
|
|
||||||
for (i=2; i < testsize; i+=4)
|
for (i=2; i < testsize; i+=4)
|
||||||
shdel(strmap, strkey(i)); // delete half the entries
|
shdel(strmap, strkey(i)); // delete half the entries
|
||||||
for (i=0; i < testsize; i+=1)
|
for (i=0; i < testsize; i+=1)
|
||||||
if (i & 3) STBDS_ASSERT(shget(strmap, strkey(i)) == -2 );
|
if (i & 3) STBDS_ASSERT(shget(strmap, strkey(i)) == -2 );
|
||||||
else
|
else STBDS_ASSERT(shget(strmap, strkey(i)) == i*3);
|
||||||
STBDS_ASSERT(shget(strmap, strkey(i)) == i * 3);
|
|
||||||
for (i=0; i < testsize; i+=1)
|
for (i=0; i < testsize; i+=1)
|
||||||
shdel(strmap, strkey(i)); // delete the rest of the entries
|
shdel(strmap, strkey(i)); // delete the rest of the entries
|
||||||
for (i=0; i < testsize; i+=1)
|
for (i=0; i < testsize; i+=1)
|
||||||
|
|
@ -1827,10 +1794,7 @@ void stbds_unit_tests(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
struct {
|
struct { char *key; char value; } *hash = NULL;
|
||||||
char* key;
|
|
||||||
char value;
|
|
||||||
}* hash = NULL;
|
|
||||||
char name[4] = "jen";
|
char name[4] = "jen";
|
||||||
shput(hash, "bob" , 'h');
|
shput(hash, "bob" , 'h');
|
||||||
shput(hash, "sally" , 'e');
|
shput(hash, "sally" , 'e');
|
||||||
|
|
@ -1851,11 +1815,9 @@ void stbds_unit_tests(void) {
|
||||||
stbds_struct s = { i,i*2,i*3 ,i*4 };
|
stbds_struct s = { i,i*2,i*3 ,i*4 };
|
||||||
stbds_struct t = { i,i*2,i*3+1,i*4 };
|
stbds_struct t = { i,i*2,i*3+1,i*4 };
|
||||||
if (i & 1) STBDS_ASSERT(hmget(map, s) == 0);
|
if (i & 1) STBDS_ASSERT(hmget(map, s) == 0);
|
||||||
else
|
else STBDS_ASSERT(hmget(map, s) == i*5);
|
||||||
STBDS_ASSERT(hmget(map, s) == i * 5);
|
|
||||||
if (i & 1) STBDS_ASSERT(hmget_ts(map, s, temp) == 0);
|
if (i & 1) STBDS_ASSERT(hmget_ts(map, s, temp) == 0);
|
||||||
else
|
else STBDS_ASSERT(hmget_ts(map, s, temp) == i*5);
|
||||||
STBDS_ASSERT(hmget_ts(map, s, temp) == i * 5);
|
|
||||||
//STBDS_ASSERT(hmget(map, t.key) == 0);
|
//STBDS_ASSERT(hmget(map, t.key) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1869,8 +1831,7 @@ void stbds_unit_tests(void) {
|
||||||
stbds_struct s = { i,i*2,i*3,i*4 };
|
stbds_struct s = { i,i*2,i*3,i*4 };
|
||||||
stbds_struct t = { i,i*2,i*3+1,i*4 };
|
stbds_struct t = { i,i*2,i*3+1,i*4 };
|
||||||
if (i & 1) STBDS_ASSERT(hmgets(map2, s.key).d == 0);
|
if (i & 1) STBDS_ASSERT(hmgets(map2, s.key).d == 0);
|
||||||
else
|
else STBDS_ASSERT(hmgets(map2, s.key).d == i*4);
|
||||||
STBDS_ASSERT(hmgets(map2, s.key).d == i * 4);
|
|
||||||
//STBDS_ASSERT(hmgetp(map2, t.key) == 0);
|
//STBDS_ASSERT(hmgetp(map2, t.key) == 0);
|
||||||
}
|
}
|
||||||
hmfree(map2);
|
hmfree(map2);
|
||||||
|
|
@ -1883,14 +1844,14 @@ void stbds_unit_tests(void) {
|
||||||
stbds_struct2 s = { { i,i*2}, i*3, i*4, i*5 };
|
stbds_struct2 s = { { i,i*2}, i*3, i*4, i*5 };
|
||||||
stbds_struct2 t = { { i,i*2}, i*3+1, i*4, i*5 };
|
stbds_struct2 t = { { i,i*2}, i*3+1, i*4, i*5 };
|
||||||
if (i & 1) STBDS_ASSERT(hmgets(map3, s.key).d == 0);
|
if (i & 1) STBDS_ASSERT(hmgets(map3, s.key).d == 0);
|
||||||
else
|
else STBDS_ASSERT(hmgets(map3, s.key).d == i*5);
|
||||||
STBDS_ASSERT(hmgets(map3, s.key).d == i * 5);
|
|
||||||
//STBDS_ASSERT(hmgetp(map3, t.key) == 0);
|
//STBDS_ASSERT(hmgetp(map3, t.key) == 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
This software is available under 2 licenses -- choose whichever you prefer.
|
This software is available under 2 licenses -- choose whichever you prefer.
|
||||||
|
|
|
||||||
7988
src/stb_image.h
Normal file
7988
src/stb_image.h
Normal file
File diff suppressed because it is too large
Load diff
54
src/x11.c
54
src/x11.c
|
|
@ -3,6 +3,22 @@
|
||||||
|
|
||||||
static unsigned long mask = ExposureMask | StructureNotifyMask | ButtonPressMask | ButtonReleaseMask;
|
static unsigned long mask = ExposureMask | StructureNotifyMask | ButtonPressMask | ButtonReleaseMask;
|
||||||
|
|
||||||
|
static void create_pixmap(MwLL handle) {
|
||||||
|
XWindowAttributes attr;
|
||||||
|
int x, y;
|
||||||
|
unsigned int w, h;
|
||||||
|
|
||||||
|
MwLLGetXYWH(handle, &x, &y, &w, &h);
|
||||||
|
|
||||||
|
XGetWindowAttributes(handle->display, handle->window, &attr);
|
||||||
|
|
||||||
|
handle->pixmap = XCreatePixmap(handle->display, handle->window, w, h, attr.depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy_pixmap(MwLL handle) {
|
||||||
|
XFreePixmap(handle->display, handle->pixmap);
|
||||||
|
}
|
||||||
|
|
||||||
MwLL MwLLCreate(MwLL parent, int x, int y, int width, int height) {
|
MwLL MwLLCreate(MwLL parent, int x, int y, int width, int height) {
|
||||||
MwLL r;
|
MwLL r;
|
||||||
Window p;
|
Window p;
|
||||||
|
|
@ -19,12 +35,18 @@ MwLL MwLLCreate(MwLL parent, int x, int y, int width, int height) {
|
||||||
p = parent->window;
|
p = parent->window;
|
||||||
}
|
}
|
||||||
r->window = XCreateSimpleWindow(r->display, p, x, y, width, height, 0, 0, WhitePixel(r->display, XDefaultScreen(r->display)));
|
r->window = XCreateSimpleWindow(r->display, p, x, y, width, height, 0, 0, WhitePixel(r->display, XDefaultScreen(r->display)));
|
||||||
|
|
||||||
|
r->width = width;
|
||||||
|
r->height = height;
|
||||||
|
|
||||||
r->colormap = DefaultColormap(r->display, XDefaultScreen(r->display));
|
r->colormap = DefaultColormap(r->display, XDefaultScreen(r->display));
|
||||||
r->wm_delete = XInternAtom(r->display, "WM_DELETE_WINDOW", False);
|
r->wm_delete = XInternAtom(r->display, "WM_DELETE_WINDOW", False);
|
||||||
XSetWMProtocols(r->display, r->window, &r->wm_delete, 1);
|
XSetWMProtocols(r->display, r->window, &r->wm_delete, 1);
|
||||||
|
|
||||||
r->gc = XCreateGC(r->display, r->window, 0, 0);
|
r->gc = XCreateGC(r->display, r->window, 0, 0);
|
||||||
|
|
||||||
|
create_pixmap(r);
|
||||||
|
|
||||||
XSetGraphicsExposures(r->display, r->gc, False);
|
XSetGraphicsExposures(r->display, r->gc, False);
|
||||||
|
|
||||||
XSelectInput(r->display, r->window, mask);
|
XSelectInput(r->display, r->window, mask);
|
||||||
|
|
@ -36,6 +58,7 @@ MwLL MwLLCreate(MwLL parent, int x, int y, int width, int height) {
|
||||||
void MwLLDestroy(MwLL handle) {
|
void MwLLDestroy(MwLL handle) {
|
||||||
MwLLDestroyCommon(handle);
|
MwLLDestroyCommon(handle);
|
||||||
|
|
||||||
|
destroy_pixmap(handle);
|
||||||
XFreeGC(handle->display, handle->gc);
|
XFreeGC(handle->display, handle->gc);
|
||||||
XDestroyWindow(handle->display, handle->window);
|
XDestroyWindow(handle->display, handle->window);
|
||||||
free(handle);
|
free(handle);
|
||||||
|
|
@ -51,7 +74,7 @@ void MwLLPolygon(MwLL handle, MwPoint* points, int points_count, MwLLColor color
|
||||||
p[i].x = points[i].x;
|
p[i].x = points[i].x;
|
||||||
p[i].y = points[i].y;
|
p[i].y = points[i].y;
|
||||||
}
|
}
|
||||||
XFillPolygon(handle->display, handle->window, handle->gc, p, points_count, Convex, CoordModeOrigin);
|
XFillPolygon(handle->display, handle->pixmap, handle->gc, p, points_count, Convex, CoordModeOrigin);
|
||||||
|
|
||||||
free(p);
|
free(p);
|
||||||
}
|
}
|
||||||
|
|
@ -110,25 +133,43 @@ int MwLLPending(MwLL handle) {
|
||||||
void MwLLNextEvent(MwLL handle) {
|
void MwLLNextEvent(MwLL handle) {
|
||||||
XEvent ev;
|
XEvent ev;
|
||||||
while(XCheckTypedWindowEvent(handle->display, handle->window, ClientMessage, &ev) || XCheckWindowEvent(handle->display, handle->window, mask, &ev)) {
|
while(XCheckTypedWindowEvent(handle->display, handle->window, ClientMessage, &ev) || XCheckWindowEvent(handle->display, handle->window, mask, &ev)) {
|
||||||
|
int render = 0;
|
||||||
if(ev.type == Expose) {
|
if(ev.type == Expose) {
|
||||||
MwLLDispatch(handle, draw);
|
render = 1;
|
||||||
} else if(ev.type == ButtonPress) {
|
} else if(ev.type == ButtonPress) {
|
||||||
if(ev.xbutton.button == Button1) {
|
if(ev.xbutton.button == Button1) {
|
||||||
MwLLDispatch(handle, down);
|
MwLLDispatch(handle, down);
|
||||||
MwLLDispatch(handle, draw);
|
render = 1;
|
||||||
}
|
}
|
||||||
} else if(ev.type == ButtonRelease) {
|
} else if(ev.type == ButtonRelease) {
|
||||||
if(ev.xbutton.button == Button1) {
|
if(ev.xbutton.button == Button1) {
|
||||||
MwLLDispatch(handle, up);
|
MwLLDispatch(handle, up);
|
||||||
MwLLDispatch(handle, draw);
|
render = 1;
|
||||||
}
|
}
|
||||||
} else if(ev.type == ConfigureNotify) {
|
} else if(ev.type == ConfigureNotify) {
|
||||||
MwLLDispatch(handle, resize);
|
MwLLDispatch(handle, resize);
|
||||||
|
|
||||||
|
if(handle->width != (unsigned int)ev.xconfigure.width || handle->height != (unsigned int)ev.xconfigure.height) {
|
||||||
|
destroy_pixmap(handle);
|
||||||
|
create_pixmap(handle);
|
||||||
|
render = 1;
|
||||||
|
}
|
||||||
|
handle->width = ev.xconfigure.width;
|
||||||
|
handle->height = ev.xconfigure.height;
|
||||||
} else if(ev.type == ClientMessage) {
|
} else if(ev.type == ClientMessage) {
|
||||||
if(ev.xclient.data.l[0] == (long)handle->wm_delete) {
|
if(ev.xclient.data.l[0] == (long)handle->wm_delete) {
|
||||||
MwLLDispatch(handle, close);
|
MwLLDispatch(handle, close);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(render) {
|
||||||
|
int x, y;
|
||||||
|
unsigned int w, h;
|
||||||
|
|
||||||
|
MwLLGetXYWH(handle, &x, &y, &w, &h);
|
||||||
|
|
||||||
|
MwLLDispatch(handle, draw);
|
||||||
|
XCopyArea(handle->display, handle->pixmap, handle->window, handle->gc, 0, 0, w, h, 0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -232,11 +273,14 @@ void MwLLDrawPixmap(MwLL handle, MwRect* rect, MwLLPixmap pixmap) {
|
||||||
}
|
}
|
||||||
|
|
||||||
src = XRenderCreatePicture(handle->display, px, format, 0, &attr);
|
src = XRenderCreatePicture(handle->display, px, format, 0, &attr);
|
||||||
dest = XRenderCreatePicture(handle->display, handle->window, format, 0, &attr);
|
dest = XRenderCreatePicture(handle->display, handle->pixmap, format, 0, &attr);
|
||||||
|
|
||||||
XRenderSetPictureTransform(handle->display, src, &m);
|
XRenderSetPictureTransform(handle->display, src, &m);
|
||||||
XRenderComposite(handle->display, PictOpSrc, src, 0, dest, 0, 0, 0, 0, rect->x, rect->y, rect->width, rect->height);
|
XRenderComposite(handle->display, PictOpSrc, src, 0, dest, 0, 0, 0, 0, rect->x, rect->y, rect->width, rect->height);
|
||||||
|
|
||||||
|
XRenderFreePicture(handle->display, src);
|
||||||
|
XRenderFreePicture(handle->display, dest);
|
||||||
|
|
||||||
XFreePixmap(handle->display, px);
|
XFreePixmap(handle->display, px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue