1b877906bSopenharmony_ci//========================================================================
2b877906bSopenharmony_ci// Custom heap allocator test
3b877906bSopenharmony_ci// Copyright (c) Camilla Löwy <elmindreda@glfw.org>
4b877906bSopenharmony_ci//
5b877906bSopenharmony_ci// This software is provided 'as-is', without any express or implied
6b877906bSopenharmony_ci// warranty. In no event will the authors be held liable for any damages
7b877906bSopenharmony_ci// arising from the use of this software.
8b877906bSopenharmony_ci//
9b877906bSopenharmony_ci// Permission is granted to anyone to use this software for any purpose,
10b877906bSopenharmony_ci// including commercial applications, and to alter it and redistribute it
11b877906bSopenharmony_ci// freely, subject to the following restrictions:
12b877906bSopenharmony_ci//
13b877906bSopenharmony_ci// 1. The origin of this software must not be misrepresented; you must not
14b877906bSopenharmony_ci//    claim that you wrote the original software. If you use this software
15b877906bSopenharmony_ci//    in a product, an acknowledgment in the product documentation would
16b877906bSopenharmony_ci//    be appreciated but is not required.
17b877906bSopenharmony_ci//
18b877906bSopenharmony_ci// 2. Altered source versions must be plainly marked as such, and must not
19b877906bSopenharmony_ci//    be misrepresented as being the original software.
20b877906bSopenharmony_ci//
21b877906bSopenharmony_ci// 3. This notice may not be removed or altered from any source
22b877906bSopenharmony_ci//    distribution.
23b877906bSopenharmony_ci//
24b877906bSopenharmony_ci//========================================================================
25b877906bSopenharmony_ci
26b877906bSopenharmony_ci#define GLAD_GL_IMPLEMENTATION
27b877906bSopenharmony_ci#include <glad/gl.h>
28b877906bSopenharmony_ci#define GLFW_INCLUDE_NONE
29b877906bSopenharmony_ci#include <GLFW/glfw3.h>
30b877906bSopenharmony_ci
31b877906bSopenharmony_ci#include <stdio.h>
32b877906bSopenharmony_ci#include <stdlib.h>
33b877906bSopenharmony_ci#include <assert.h>
34b877906bSopenharmony_ci
35b877906bSopenharmony_ci#define CALL(x) (function_name = #x, x)
36b877906bSopenharmony_cistatic const char* function_name = NULL;
37b877906bSopenharmony_ci
38b877906bSopenharmony_cistruct allocator_stats
39b877906bSopenharmony_ci{
40b877906bSopenharmony_ci    size_t total;
41b877906bSopenharmony_ci    size_t current;
42b877906bSopenharmony_ci    size_t maximum;
43b877906bSopenharmony_ci};
44b877906bSopenharmony_ci
45b877906bSopenharmony_cistatic void error_callback(int error, const char* description)
46b877906bSopenharmony_ci{
47b877906bSopenharmony_ci    fprintf(stderr, "Error: %s\n", description);
48b877906bSopenharmony_ci}
49b877906bSopenharmony_ci
50b877906bSopenharmony_cistatic void* allocate(size_t size, void* user)
51b877906bSopenharmony_ci{
52b877906bSopenharmony_ci    struct allocator_stats* stats = user;
53b877906bSopenharmony_ci    assert(size > 0);
54b877906bSopenharmony_ci
55b877906bSopenharmony_ci    stats->total += size;
56b877906bSopenharmony_ci    stats->current += size;
57b877906bSopenharmony_ci    if (stats->current > stats->maximum)
58b877906bSopenharmony_ci        stats->maximum = stats->current;
59b877906bSopenharmony_ci
60b877906bSopenharmony_ci    printf("%s: allocate %zu bytes (current %zu maximum %zu total %zu)\n",
61b877906bSopenharmony_ci           function_name, size, stats->current, stats->maximum, stats->total);
62b877906bSopenharmony_ci
63b877906bSopenharmony_ci    size_t* real_block = malloc(size + sizeof(size_t));
64b877906bSopenharmony_ci    assert(real_block != NULL);
65b877906bSopenharmony_ci    *real_block = size;
66b877906bSopenharmony_ci    return real_block + 1;
67b877906bSopenharmony_ci}
68b877906bSopenharmony_ci
69b877906bSopenharmony_cistatic void deallocate(void* block, void* user)
70b877906bSopenharmony_ci{
71b877906bSopenharmony_ci    struct allocator_stats* stats = user;
72b877906bSopenharmony_ci    assert(block != NULL);
73b877906bSopenharmony_ci
74b877906bSopenharmony_ci    size_t* real_block = (size_t*) block - 1;
75b877906bSopenharmony_ci    stats->current -= *real_block;
76b877906bSopenharmony_ci
77b877906bSopenharmony_ci    printf("%s: deallocate %zu bytes (current %zu maximum %zu total %zu)\n",
78b877906bSopenharmony_ci           function_name, *real_block, stats->current, stats->maximum, stats->total);
79b877906bSopenharmony_ci
80b877906bSopenharmony_ci    free(real_block);
81b877906bSopenharmony_ci}
82b877906bSopenharmony_ci
83b877906bSopenharmony_cistatic void* reallocate(void* block, size_t size, void* user)
84b877906bSopenharmony_ci{
85b877906bSopenharmony_ci    struct allocator_stats* stats = user;
86b877906bSopenharmony_ci    assert(block != NULL);
87b877906bSopenharmony_ci    assert(size > 0);
88b877906bSopenharmony_ci
89b877906bSopenharmony_ci    size_t* real_block = (size_t*) block - 1;
90b877906bSopenharmony_ci    stats->total += size;
91b877906bSopenharmony_ci    stats->current += size - *real_block;
92b877906bSopenharmony_ci    if (stats->current > stats->maximum)
93b877906bSopenharmony_ci        stats->maximum = stats->current;
94b877906bSopenharmony_ci
95b877906bSopenharmony_ci    printf("%s: reallocate %zu bytes to %zu bytes (current %zu maximum %zu total %zu)\n",
96b877906bSopenharmony_ci           function_name, *real_block, size, stats->current, stats->maximum, stats->total);
97b877906bSopenharmony_ci
98b877906bSopenharmony_ci    real_block = realloc(real_block, size + sizeof(size_t));
99b877906bSopenharmony_ci    assert(real_block != NULL);
100b877906bSopenharmony_ci    *real_block = size;
101b877906bSopenharmony_ci    return real_block + 1;
102b877906bSopenharmony_ci}
103b877906bSopenharmony_ci
104b877906bSopenharmony_ciint main(void)
105b877906bSopenharmony_ci{
106b877906bSopenharmony_ci    struct allocator_stats stats = {0};
107b877906bSopenharmony_ci    const GLFWallocator allocator =
108b877906bSopenharmony_ci    {
109b877906bSopenharmony_ci        .allocate = allocate,
110b877906bSopenharmony_ci        .deallocate = deallocate,
111b877906bSopenharmony_ci        .reallocate = reallocate,
112b877906bSopenharmony_ci        .user = &stats
113b877906bSopenharmony_ci    };
114b877906bSopenharmony_ci
115b877906bSopenharmony_ci    glfwSetErrorCallback(error_callback);
116b877906bSopenharmony_ci    glfwInitAllocator(&allocator);
117b877906bSopenharmony_ci
118b877906bSopenharmony_ci    if (!CALL(glfwInit)())
119b877906bSopenharmony_ci        exit(EXIT_FAILURE);
120b877906bSopenharmony_ci
121b877906bSopenharmony_ci    GLFWwindow* window = CALL(glfwCreateWindow)(400, 400, "Custom allocator test", NULL, NULL);
122b877906bSopenharmony_ci    if (!window)
123b877906bSopenharmony_ci    {
124b877906bSopenharmony_ci        glfwTerminate();
125b877906bSopenharmony_ci        exit(EXIT_FAILURE);
126b877906bSopenharmony_ci    }
127b877906bSopenharmony_ci
128b877906bSopenharmony_ci    CALL(glfwMakeContextCurrent)(window);
129b877906bSopenharmony_ci    gladLoadGL(glfwGetProcAddress);
130b877906bSopenharmony_ci    CALL(glfwSwapInterval)(1);
131b877906bSopenharmony_ci
132b877906bSopenharmony_ci    while (!CALL(glfwWindowShouldClose)(window))
133b877906bSopenharmony_ci    {
134b877906bSopenharmony_ci        glClear(GL_COLOR_BUFFER_BIT);
135b877906bSopenharmony_ci        CALL(glfwSwapBuffers)(window);
136b877906bSopenharmony_ci        CALL(glfwWaitEvents)();
137b877906bSopenharmony_ci    }
138b877906bSopenharmony_ci
139b877906bSopenharmony_ci    CALL(glfwTerminate)();
140b877906bSopenharmony_ci    exit(EXIT_SUCCESS);
141b877906bSopenharmony_ci}
142b877906bSopenharmony_ci
143