From 9e80ce694e842f4a7f9c0778ca7679a11011ffea Mon Sep 17 00:00:00 2001 From: RealTheSunCat Date: Thu, 30 Dec 2021 18:23:55 +0100 Subject: [PATCH] Switch to SDL1 --- CMakeLists.txt | 20 +- Constants.h | 3 +- Minecraft4k.cpp | 88 +++---- Shader.cpp | 2 - Shader.h | 2 +- TextureGenerator.h | 2 +- Util.cpp | 166 ++++++++++-- Util.h | 33 ++- Vector.cpp | 3 +- glad.c | 32 ++- include/{glad => }/glad.h | 0 include/malloc-2.8.3.h | 534 ++++++++++++++++++++++++++++++++++++++ 12 files changed, 773 insertions(+), 112 deletions(-) rename include/{glad => }/glad.h (100%) create mode 100644 include/malloc-2.8.3.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d2a22c..38b78be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.15.0 FATAL_ERROR) project(Minecraft4k C CXX) -include_directories(include build) +include_directories(include) set(PROJECT_NAME Minecraft4k) @@ -24,13 +24,13 @@ set(Resource_Files source_group("Resource Files" FILES ${Resource_Files}) set(Source_Files - "glad.c" "Minecraft4k.cpp" "Shader.cpp" "TextureGenerator.cpp" "Util.cpp" "World.cpp" "Vector.cpp" + "glad.c" ) source_group("Source Files" FILES ${Source_Files}) @@ -40,7 +40,11 @@ set(ALL_FILES ${Source_Files} ) -find_package(SDL2 REQUIRED) +# Don't link stdlib +set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "") +set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "") + +find_package(SDL REQUIRED) add_executable(${PROJECT_NAME} ${ALL_FILES}) set(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME}) @@ -58,16 +62,16 @@ if(UNIX) # target_compile_options(${PROJECT_NAME} PRIVATE -g -DDEBUG) # TODO -m32, use C libs - target_compile_options(${PROJECT_NAME} PRIVATE - -Os -s -fno-rtti -fno-stack-protector -ffunction-sections -fdata-sections -Wl,--gc-sections - -fno-math-errno -fno-unroll-loops -fmerge-all-constants -fno-ident -mfpmath=387 -mfancy-math-387 + target_compile_options(${PROJECT_NAME} PRIVATE -DSDL_stdinc_h_ + -Os -s -fno-rtti -fno-stack-protector -ffunction-sections -fdata-sections -fno-math-errno + -fno-unroll-loops -fmerge-all-constants -fno-ident -mfpmath=387 -mfancy-math-387 #-e _start -fsingle-precision-constant -ffast-math -fno-exceptions -nostartfiles -nostdlib -nodefaultlibs -fcf-protection=none -N -fno-align-functions -fomit-frame-pointer -fno-threadsafe-statics -finline-limit=10 -fno-asynchronous-unwind-tables ) target_link_options(${PROJECT_NAME} PRIVATE - -Wl,--hash-style=gnu,--build-id=none,-z,max-page-size=2048 + -Wl,--hash-style=gnu,--build-id=none,--gc-sections#,-z,max-page-size=2048#,-e,_start ) add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD @@ -118,7 +122,7 @@ set(ADDITIONAL_LIBRARY_DEPENDENCIES ) endif() -target_link_libraries(${PROJECT_NAME} PRIVATE "${ADDITIONAL_LIBRARY_DEPENDENCIES}" ${SDL2_LIBRARIES}) +target_link_libraries(${PROJECT_NAME} PRIVATE "${ADDITIONAL_LIBRARY_DEPENDENCIES} ${SDL_LIBRARY}") link_directories(${PROJECT_NAME} PRIVATE "lib" diff --git a/Constants.h b/Constants.h index 61973c0..994b07f 100644 --- a/Constants.h +++ b/Constants.h @@ -1,6 +1,7 @@ #pragma once -#include +typedef unsigned char uint8_t; +typedef unsigned long uint64_t; #include "Vector.h" diff --git a/Minecraft4k.cpp b/Minecraft4k.cpp index eb388ed..63ecb60 100644 --- a/Minecraft4k.cpp +++ b/Minecraft4k.cpp @@ -1,7 +1,5 @@ -#include - -#include -#include +#include +#include #include "Constants.h" #include "Shader.h" @@ -11,8 +9,6 @@ #include "shader_code.h" -SDL_GLContext mainContext; - struct Controller { float forward; @@ -88,11 +84,11 @@ static vec3 lerp(const vec3& start, const vec3& end, const float t) } void initTexture(GLuint* texture, const int width, const int height); -void updateMouse(SDL_Window* window); -void updateController(SDL_Window* window); +void updateMouse(); +void updateController(); void onWindowResized(int width, int height); -void updateScreenResolution(SDL_Window* window) +void updateScreenResolution() { if (SCR_DETAIL < -4) SCR_DETAIL = -4; @@ -139,7 +135,7 @@ void updateScreenResolution(SDL_Window* window) break; } - SDL_SetWindowTitle(window, title); + SDL_WM_SetCaption(title, nullptr); glDeleteTextures(1, &screenTexture); initTexture(&screenTexture, int(SCR_RES.x), int(SCR_RES.y)); @@ -242,11 +238,11 @@ void collidePlayer() //prints(playerPos); prints('\n'); } -void run(SDL_Window* window) { +void run() { auto lastUpdateTime = currentTime(); float lastFrameTime = lastUpdateTime - 16; - SDL_WarpMouseInWindow(window, WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2); + SDL_WarpMouse(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2); SDL_Event evt; @@ -256,11 +252,11 @@ void run(SDL_Window* window) { deltaTime = frameTime - lastFrameTime; lastFrameTime = frameTime; - updateMouse(window); - updateController(window); + updateMouse(); + updateController(); if (needsResUpdate) { - updateScreenResolution(window); + updateScreenResolution(); } sinYaw = sin(cameraYaw); @@ -377,7 +373,7 @@ void run(SDL_Window* window) { prints("frame\n"); - SDL_GL_SwapWindow(window); + SDL_GL_SwapBuffers(); while(SDL_PollEvent(&evt)) { @@ -392,16 +388,16 @@ void run(SDL_Window* window) { //glfwTerminate(); } -void updateMouse(SDL_Window* window) +void updateMouse() { int x, y; SDL_GetMouseState(&x, &y); - SDL_WarpMouseInWindow(window, WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2); + SDL_WarpMouse(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2); cameraYaw += (x - (WINDOW_WIDTH / 2)) / 500.0f; cameraPitch -= (y - (WINDOW_HEIGHT / 2)) / 500.0f; - if(fabs(cameraYaw) > PI) + if(abs(cameraYaw) > PI) { if (cameraYaw > 0) cameraYaw = -PI - (cameraYaw - PI); @@ -458,28 +454,28 @@ bool keyPress(SDL_Window* window, int key) return false; }*/ -void updateController(SDL_Window* window) +void updateController() { controller.reset(); - const uint8_t *keyboard = SDL_GetKeyboardState(nullptr); + const uint8_t *keyboard = SDL_GetKeyState(nullptr); - if(keyboard[SDL_SCANCODE_W]) + if(keyboard[SDLK_w]) controller.forward += 1.0f; - if (keyboard[SDL_SCANCODE_S]) + if (keyboard[SDLK_s]) controller.forward -= 1.0f; - if (keyboard[SDL_SCANCODE_D]) + if (keyboard[SDLK_d]) controller.right += 1.0f; - if (keyboard[SDL_SCANCODE_A]) + if (keyboard[SDLK_a]) controller.right -= 1.0f; - if (keyboard[SDL_SCANCODE_SPACE]) + if (keyboard[SDLK_SPACE]) controller.jump = true; - if (keyboard[SDL_SCANCODE_COMMA]) { + if (keyboard[SDLK_COMMA]) { SCR_DETAIL--; needsResUpdate = true; } - if (keyboard[SDL_SCANCODE_PERIOD]) { + if (keyboard[SDLK_PERIOD]) { SCR_DETAIL++; needsResUpdate = true; } @@ -525,7 +521,7 @@ void initTexture(GLuint* texture, const int width, const int height) { } // TODO maybe use _start: https://int21.de/linux4k/ -int main(const int argc, const char** argv) +int main() { prints("Initializing SDL... "); // uhh I guess we don't need to SDL_Init?? @@ -533,36 +529,22 @@ int main(const int argc, const char** argv) prints("Creating window... "); + SDL_SetVideoMode(WINDOW_WIDTH, WINDOW_HEIGHT, 0, SDL_OPENGL); // TODO SDL_FULLSCREEN? + SDL_ShowCursor(SDL_DISABLE); + // Request an OpenGL 4.3 context (should be core) SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); // TODO what is this? - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); + /*SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);*/ #ifdef __APPLE__ - SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE ); // add on Mac bc Apple is big dumb :( + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); // add on Mac bc Apple is big dumb :( #endif - - SDL_Window* window = SDL_CreateWindow("Minecraft4k", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL); - - SDL_SetWindowResizable(window, SDL_TRUE); - - if(!window) - { - prints("Failed to create window!\n"); - return -1; - } prints("Done!\n"); - SDL_ShowCursor(SDL_FALSE); prints("Setting OpenGL context... "); - mainContext = SDL_GL_CreateContext(window); - if(!mainContext) - { - prints("Failed to create OpenGL context!\n"); - return -1; - } + prints("Done!\n"); @@ -570,8 +552,8 @@ int main(const int argc, const char** argv) gladLoadGLLoader(SDL_GL_GetProcAddress); prints("Done!\n"); - // enable vsync so we don't run at about a kjghpillion fps - SDL_GL_SetSwapInterval(1); + // TODO enable vsync so we don't run at about a kjghpillion fps + //SDL_GL_SetSwapState(1); prints("Configuring OpenGL... "); @@ -613,7 +595,7 @@ int main(const int argc, const char** argv) init(); prints("Finished initializing engine! Running the game...\n"); - run(window); + run(); SDL_ShowCursor(SDL_TRUE); } \ No newline at end of file diff --git a/Shader.cpp b/Shader.cpp index 65c431a..da15a6a 100644 --- a/Shader.cpp +++ b/Shader.cpp @@ -1,7 +1,5 @@ #include "Shader.h" -#include - #include "Util.h" Shader::Shader(const char* vertexCode, const char* fragmentCode) diff --git a/Shader.h b/Shader.h index 1feeea0..21f8578 100644 --- a/Shader.h +++ b/Shader.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include "Vector.h" diff --git a/TextureGenerator.h b/TextureGenerator.h index 6dd97d0..f800f7a 100644 --- a/TextureGenerator.h +++ b/TextureGenerator.h @@ -1,4 +1,4 @@ #pragma once -#include +#include GLuint generateTextures(long long seed); diff --git a/Util.cpp b/Util.cpp index d87d5ec..11469a4 100644 --- a/Util.cpp +++ b/Util.cpp @@ -1,14 +1,13 @@ #include "Util.h" -#include -#include +#include float currentTime() { static bool firstCall = true; static long long startTime; - long long curTime = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + long long curTime = SDL_GetTicks(); if(firstCall) { @@ -20,7 +19,7 @@ float currentTime() } uint64_t Random::seedUniquifier = 8682522807148012; -Random::Random() : seed(uniqueSeed() ^ uint64_t(currentTime())) {} +Random::Random() : seed(uniqueSeed() ^ uint64_t(currentTime)) {} Random::Random(const uint64_t seed) : seed(initialScramble(seed)) {} uint64_t Random::initialScramble(const uint64_t seed) @@ -222,15 +221,6 @@ void GLAPIENTRY error_callback(GLenum source, //__debugbreak(); } -vec3 rotToVec3(const float yaw, const float pitch) -{ - vec3 ret; - ret.x = cos(radians(yaw)) * (pitch == 0 ? 1 : cos(radians(pitch))); - ret.y = pitch == 0 ? 0 : sin(radians(pitch)); - ret.z = sin(radians(yaw)) * (pitch == 0 ? 1 : cos(radians(pitch))); - return ret.normalized(); -} - float radians(float deg) { return deg * (PI / 180.f); @@ -241,6 +231,11 @@ float degrees(float rad) return rad / (PI / 180.f); } +/*float abs(float v) +{ + return v < 0 ? -v : v; +}*/ + bool sign(float v) { return (0 < v) - (v < 0); @@ -248,26 +243,116 @@ bool sign(float v) float fract(float v) { - return abs(v - int(v)); + return v - floor(v); +} + +float floor(float x) +{ + float xcopy=x<0?x*-1:x; + unsigned int zeros=0; + float n=1; + for(n=1;xcopy>n*10;n*=10,++zeros); + for(xcopy-=n;zeros!=-1;xcopy-=n) + { + if(xcopy<0) + { + xcopy+=n; + n/=10; + --zeros; + } + } + + xcopy+=n; + + return x<0?(xcopy==0?x:x-(1-xcopy)):(x-xcopy); +} + +// from Quake FISR +float sqrt(float v) +{ + long i; + float x2, y; + const float threehalfs = 1.5F; + + x2 = v * 0.5F; + y = v; + i = * ( long * ) &y; // evil floating point bit level hacking + i = 0x5f3759df - ( i >> 1 ); // what the fuck? + y = * ( float * ) &i; + y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration +// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed + + return 1/y; +} + +float pow(float v, int p) +{ + for(int i = 0; i < p; i++) + v *= v; + + return v; +} + +float cos(float x) +{ + constexpr float tp = 1./(2.*PI); + x *= tp; + x -= .25f + floor(x + .25f); + x *= 16.f * (abs(x) - .5f); + #if EXTRA_PRECISION + x += T(.225f) * x * (abs(x) - 1.f); + #endif + return x; +} + +float sin(float x) +{ + return cos(PI/2 - x); } -float maxf(float a, float b) +float max(float a, float b) { return a > b ? a : b; } +float mod(float x, float y) { + return x - trunc(x / y) * y; +} + +float trunc(float v) +{ + return v < 0 ? floor(-v) : floor(v); +} + +#include "costable_0_01.h" + +#define lerp(w, v1, v2) ((1.0 - (w)) * (v1) + (w) * (v2)) +double cos(double x) +{ + x = abs(x); + x = mod(x, 2*PI); + double i = x * 100.0; + int index = (int)i; + return lerp(i - index, /* weight */ + costable_0_01[index], /* lower value */ + costable_0_01[index + 1] /* upper value */ + ); +} + vec3 max(const vec3& a, const vec3& b) { return vec3( - maxf(a.x, b.x), - maxf(a.y, b.y), - maxf(a.z, b.z) + max(a.x, b.x), + max(a.y, b.y), + max(a.z, b.z) ); } -float roundFloat(float v) + +// NOTE: broken for negatives (doesn't matter for terrain height) +int roundFloat(float v) { - return floor(v + 0.5f); + return int(v + 0.5f); } unsigned int murmurHash2(const char* str, int len) @@ -318,6 +403,45 @@ unsigned int murmurHash2(const char* str, int len) return h; } +/* +unsigned long strlen(const char *str) +{ + const char *s; + for (s = str; *s; ++s); + + return (s - str); +} + +char *strcpy(char *strDest, const char *strSrc) +{ + char *temp = strDest; + while(*strDest++ = *strSrc++); + + return temp; +} + +char *strcat(char *dest, const char *src) +{ + char *rdest = dest; + + while (*dest) + dest++; + + while (*dest++ = *src++); + + return rdest; +}*/ + +void memcpy(void *dest, void *src, long unsigned int n) +{ + // Typecast src and dest addresses to (char *) + char *csrc = (char *)src; + char *cdest = (char *)dest; + + // Copy contents of src[] to dest[] + for (int i=0; i -#include -#include +#include +#include "Constants.h" #include "Vector.h" -constexpr float PI = 3.14159265359f; - float currentTime(); +constexpr float PI = 3.14159265359f; + // It's just the Java Random class class Random { @@ -68,23 +67,33 @@ void GLAPIENTRY error_callback(GLenum source, const GLchar* message, const void* userParam); -vec3 rotToVec3(float yaw, float pitch); - float radians(float deg); float degrees(float rad); -// why do I have to define these?? -/* -float absf(float v); -float maxf(float a, float b);*/ -float roundFloat(float v); +int roundFloat(float v); +//float abs(float v); bool sign(float v); float fract(float v); +float floor(float x); +float sqrt(float v); +float pow(float v, int p); +float mod(float v, float d); +float trunc(float v); + +float cos(float x); +float sin(float x); vec3 max(const vec3& a, const vec3& b); unsigned int murmurHash2(const char* str, int len); +/* +unsigned long strlen(const char *str); +char *strcpy(char *strDest, const char *strSrc); +char *strcat(char *dest, const char *src); +*/ +void memcpy(void *dest, void *src, long unsigned int n); + /* reverse: reverse string s in place */ void reverse(char s[]); diff --git a/Vector.cpp b/Vector.cpp index 72e87b6..3bc4a58 100644 --- a/Vector.cpp +++ b/Vector.cpp @@ -1,6 +1,5 @@ #include "Vector.h" - -#include +#include // for abs #include "Util.h" diff --git a/glad.c b/glad.c index 338e515..9d87cc3 100644 --- a/glad.c +++ b/glad.c @@ -19,12 +19,19 @@ https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D4.3 */ -#include -#include -#include +// use Util.h functions in C +unsigned long strlen(const char *str); +void memcpy(void *dest, void *src, long unsigned int n); + +// use SDL's malloc +#include "malloc-2.8.3.h" + +#include +//#define NULL 0 static void* get_proc(const char *namez); + #if defined(_WIN32) || defined(__CYGWIN__) #ifndef _WINDOWS_ #undef APIENTRY @@ -75,7 +82,7 @@ void close_gl(void) { } } #else -#include +// TODO what is this #include static void* libGL; #if !defined(__APPLE__) && !defined(__HAIKU__) @@ -83,6 +90,7 @@ typedef void* (APIENTRYP PFNGLXGETPROCADDRESSPROC_PRIVATE)(const char*); static PFNGLXGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr; #endif +/* static int open_gl(void) { #ifdef __APPLE__ @@ -122,9 +130,10 @@ void close_gl(void) { dlclose(libGL); libGL = NULL; } -} +}*/ #endif +/* static void* get_proc(const char *namez) { void* result = NULL; @@ -155,7 +164,7 @@ int gladLoadGL(void) { } return status; -} +}*/ struct gladGLversionStruct GLVersion = { 0, 0 }; @@ -182,7 +191,7 @@ static int get_exts(void) { num_exts_i = 0; glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts_i); if (num_exts_i > 0) { - exts_i = (char **)malloc((size_t)num_exts_i * (sizeof *exts_i)); + exts_i = (char **)malloc((unsigned long)num_exts_i * (sizeof *exts_i)); } if (exts_i == NULL) { @@ -191,7 +200,7 @@ static int get_exts(void) { for(index = 0; index < (unsigned)num_exts_i; index++) { const char *gl_str_tmp = (const char*)glGetStringi(GL_EXTENSIONS, index); - size_t len = strlen(gl_str_tmp); + unsigned long len = strlen(gl_str_tmp); char *local_str = (char*)malloc((len+1) * sizeof(char)); if(local_str != NULL) { @@ -215,7 +224,7 @@ static void free_exts(void) { } } -static int has_ext(const char *ext) { +/*static int has_ext(const char *ext) { #ifdef _GLAD_IS_SOME_NEW_VERSION if(max_loaded_major < 3) { #endif @@ -255,7 +264,8 @@ static int has_ext(const char *ext) { #endif return 0; -} +}*/ + int GLAD_GL_VERSION_1_0 = 1; int GLAD_GL_VERSION_1_1 = 1; int GLAD_GL_VERSION_1_2 = 1; @@ -1302,7 +1312,7 @@ static void load_GL_VERSION_4_3(GLADloadproc load) { } static int find_extensionsGL(void) { if (!get_exts()) return 0; - (void)&has_ext; + //(void)&has_ext; free_exts(); return 1; } diff --git a/include/glad/glad.h b/include/glad.h similarity index 100% rename from include/glad/glad.h rename to include/glad.h diff --git a/include/malloc-2.8.3.h b/include/malloc-2.8.3.h new file mode 100644 index 0000000..62f597e --- /dev/null +++ b/include/malloc-2.8.3.h @@ -0,0 +1,534 @@ +/* + Default header file for malloc-2.8.x, written by Doug Lea + and released to the public domain, as explained at + http://creativecommons.org/licenses/publicdomain. + + last update: Mon Aug 15 08:55:52 2005 Doug Lea (dl at gee) + + This header is for ANSI C/C++ only. You can set any of + the following #defines before including: + + * If USE_DL_PREFIX is defined, it is assumed that malloc.c + was also compiled with this option, so all routines + have names starting with "dl". + + * If HAVE_USR_INCLUDE_MALLOC_H is defined, it is assumed that this + file will be #included AFTER . This is needed only if + your system defines a struct mallinfo that is incompatible with the + standard one declared here. Otherwise, you can include this file + INSTEAD of your system system . At least on ANSI, all + declarations should be compatible with system versions + + * If MSPACES is defined, declarations for mspace versions are included. +*/ + +#ifndef MALLOC_280_H +#define MALLOC_280_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include /* for size_t */ + +#if !ONLY_MSPACES + +#ifndef USE_DL_PREFIX +#define dlcalloc calloc +#define dlfree free +#define dlmalloc malloc +#define dlmemalign memalign +#define dlrealloc realloc +#define dlvalloc valloc +#define dlpvalloc pvalloc +#define dlmallinfo mallinfo +#define dlmallopt mallopt +#define dlmalloc_trim malloc_trim +#define dlmalloc_stats malloc_stats +#define dlmalloc_usable_size malloc_usable_size +#define dlmalloc_footprint malloc_footprint +#define dlindependent_calloc independent_calloc +#define dlindependent_comalloc independent_comalloc +#endif /* USE_DL_PREFIX */ + + +/* + malloc(size_t n) + Returns a pointer to a newly allocated chunk of at least n bytes, or + null if no space is available, in which case errno is set to ENOMEM + on ANSI C systems. + + If n is zero, malloc returns a minimum-sized chunk. (The minimum + size is 16 bytes on most 32bit systems, and 32 bytes on 64bit + systems.) Note that size_t is an unsigned type, so calls with + arguments that would be negative if signed are interpreted as + requests for huge amounts of space, which will often fail. The + maximum supported value of n differs across systems, but is in all + cases less than the maximum representable value of a size_t. +*/ +void* dlmalloc(size_t); + +/* + free(void* p) + Releases the chunk of memory pointed to by p, that had been previously + allocated using malloc or a related routine such as realloc. + It has no effect if p is null. If p was not malloced or already + freed, free(p) will by default cuase the current program to abort. +*/ +void dlfree(void*); + +/* + calloc(size_t n_elements, size_t element_size); + Returns a pointer to n_elements * element_size bytes, with all locations + set to zero. +*/ +void* dlcalloc(size_t, size_t); + +/* + realloc(void* p, size_t n) + Returns a pointer to a chunk of size n that contains the same data + as does chunk p up to the minimum of (n, p's size) bytes, or null + if no space is available. + + The returned pointer may or may not be the same as p. The algorithm + prefers extending p in most cases when possible, otherwise it + employs the equivalent of a malloc-copy-free sequence. + + If p is null, realloc is equivalent to malloc. + + If space is not available, realloc returns null, errno is set (if on + ANSI) and p is NOT freed. + + if n is for fewer bytes than already held by p, the newly unused + space is lopped off and freed if possible. realloc with a size + argument of zero (re)allocates a minimum-sized chunk. + + The old unix realloc convention of allowing the last-free'd chunk + to be used as an argument to realloc is not supported. +*/ + +void* dlrealloc(void*, size_t); + +/* + memalign(size_t alignment, size_t n); + Returns a pointer to a newly allocated chunk of n bytes, aligned + in accord with the alignment argument. + + The alignment argument should be a power of two. If the argument is + not a power of two, the nearest greater power is used. + 8-byte alignment is guaranteed by normal malloc calls, so don't + bother calling memalign with an argument of 8 or less. + + Overreliance on memalign is a sure way to fragment space. +*/ +void* dlmemalign(size_t, size_t); + +/* + valloc(size_t n); + Equivalent to memalign(pagesize, n), where pagesize is the page + size of the system. If the pagesize is unknown, 4096 is used. +*/ +void* dlvalloc(size_t); + +/* + mallopt(int parameter_number, int parameter_value) + Sets tunable parameters The format is to provide a + (parameter-number, parameter-value) pair. mallopt then sets the + corresponding parameter to the argument value if it can (i.e., so + long as the value is meaningful), and returns 1 if successful else + 0. SVID/XPG/ANSI defines four standard param numbers for mallopt, + normally defined in malloc.h. None of these are use in this malloc, + so setting them has no effect. But this malloc also supports other + options in mallopt: + + Symbol param # default allowed param values + M_TRIM_THRESHOLD -1 2*1024*1024 any (-1U disables trimming) + M_GRANULARITY -2 page size any power of 2 >= page size + M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support) +*/ +int dlmallopt(int, int); + +#define M_TRIM_THRESHOLD (-1) +#define M_GRANULARITY (-2) +#define M_MMAP_THRESHOLD (-3) + + +/* + malloc_footprint(); + Returns the number of bytes obtained from the system. The total + number of bytes allocated by malloc, realloc etc., is less than this + value. Unlike mallinfo, this function returns only a precomputed + result, so can be called frequently to monitor memory consumption. + Even if locks are otherwise defined, this function does not use them, + so results might not be up to date. +*/ +size_t dlmalloc_footprint(void); + +#if !NO_MALLINFO +/* + mallinfo() + Returns (by copy) a struct containing various summary statistics: + + arena: current total non-mmapped bytes allocated from system + ordblks: the number of free chunks + smblks: always zero. + hblks: current number of mmapped regions + hblkhd: total bytes held in mmapped regions + usmblks: the maximum total allocated space. This will be greater + than current total if trimming has occurred. + fsmblks: always zero + uordblks: current total allocated space (normal or mmapped) + fordblks: total free space + keepcost: the maximum number of bytes that could ideally be released + back to system via malloc_trim. ("ideally" means that + it ignores page restrictions etc.) + + Because these fields are ints, but internal bookkeeping may + be kept as longs, the reported values may wrap around zero and + thus be inaccurate. +*/ +#ifndef HAVE_USR_INCLUDE_MALLOC_H +#ifndef _MALLOC_H +#ifndef MALLINFO_FIELD_TYPE +#define MALLINFO_FIELD_TYPE size_t +#endif /* MALLINFO_FIELD_TYPE */ +struct mallinfo { + MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */ + MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */ + MALLINFO_FIELD_TYPE smblks; /* always 0 */ + MALLINFO_FIELD_TYPE hblks; /* always 0 */ + MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */ + MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */ + MALLINFO_FIELD_TYPE fsmblks; /* always 0 */ + MALLINFO_FIELD_TYPE uordblks; /* total allocated space */ + MALLINFO_FIELD_TYPE fordblks; /* total free space */ + MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */ +}; +#endif /* _MALLOC_H */ +#endif /* HAVE_USR_INCLUDE_MALLOC_H */ + +struct mallinfo dlmallinfo(void); +#endif /* NO_MALLINFO */ + +/* + independent_calloc(size_t n_elements, size_t element_size, void* chunks[]); + + independent_calloc is similar to calloc, but instead of returning a + single cleared space, it returns an array of pointers to n_elements + independent elements that can hold contents of size elem_size, each + of which starts out cleared, and can be independently freed, + realloc'ed etc. The elements are guaranteed to be adjacently + allocated (this is not guaranteed to occur with multiple callocs or + mallocs), which may also improve cache locality in some + applications. + + The "chunks" argument is optional (i.e., may be null, which is + probably the most typical usage). If it is null, the returned array + is itself dynamically allocated and should also be freed when it is + no longer needed. Otherwise, the chunks array must be of at least + n_elements in length. It is filled in with the pointers to the + chunks. + + In either case, independent_calloc returns this pointer array, or + null if the allocation failed. If n_elements is zero and "chunks" + is null, it returns a chunk representing an array with zero elements + (which should be freed if not wanted). + + Each element must be individually freed when it is no longer + needed. If you'd like to instead be able to free all at once, you + should instead use regular calloc and assign pointers into this + space to represent elements. (In this case though, you cannot + independently free elements.) + + independent_calloc simplifies and speeds up implementations of many + kinds of pools. It may also be useful when constructing large data + structures that initially have a fixed number of fixed-sized nodes, + but the number is not known at compile time, and some of the nodes + may later need to be freed. For example: + + struct Node { int item; struct Node* next; }; + + struct Node* build_list() { + struct Node** pool; + int n = read_number_of_nodes_needed(); + if (n <= 0) return 0; + pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0); + if (pool == 0) die(); + // organize into a linked list... + struct Node* first = pool[0]; + for (i = 0; i < n-1; ++i) + pool[i]->next = pool[i+1]; + free(pool); // Can now free the array (or not, if it is needed later) + return first; + } +*/ +void** dlindependent_calloc(size_t, size_t, void**); + +/* + independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]); + + independent_comalloc allocates, all at once, a set of n_elements + chunks with sizes indicated in the "sizes" array. It returns + an array of pointers to these elements, each of which can be + independently freed, realloc'ed etc. The elements are guaranteed to + be adjacently allocated (this is not guaranteed to occur with + multiple callocs or mallocs), which may also improve cache locality + in some applications. + + The "chunks" argument is optional (i.e., may be null). If it is null + the returned array is itself dynamically allocated and should also + be freed when it is no longer needed. Otherwise, the chunks array + must be of at least n_elements in length. It is filled in with the + pointers to the chunks. + + In either case, independent_comalloc returns this pointer array, or + null if the allocation failed. If n_elements is zero and chunks is + null, it returns a chunk representing an array with zero elements + (which should be freed if not wanted). + + Each element must be individually freed when it is no longer + needed. If you'd like to instead be able to free all at once, you + should instead use a single regular malloc, and assign pointers at + particular offsets in the aggregate space. (In this case though, you + cannot independently free elements.) + + independent_comallac differs from independent_calloc in that each + element may have a different size, and also that it does not + automatically clear elements. + + independent_comalloc can be used to speed up allocation in cases + where several structs or objects must always be allocated at the + same time. For example: + + struct Head { ... } + struct Foot { ... } + + void send_message(char* msg) { + int msglen = strlen(msg); + size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) }; + void* chunks[3]; + if (independent_comalloc(3, sizes, chunks) == 0) + die(); + struct Head* head = (struct Head*)(chunks[0]); + char* body = (char*)(chunks[1]); + struct Foot* foot = (struct Foot*)(chunks[2]); + // ... + } + + In general though, independent_comalloc is worth using only for + larger values of n_elements. For small values, you probably won't + detect enough difference from series of malloc calls to bother. + + Overuse of independent_comalloc can increase overall memory usage, + since it cannot reuse existing noncontiguous small chunks that + might be available for some of the elements. +*/ +void** dlindependent_comalloc(size_t, size_t*, void**); + + +/* + pvalloc(size_t n); + Equivalent to valloc(minimum-page-that-holds(n)), that is, + round up n to nearest pagesize. + */ +void* dlpvalloc(size_t); + +/* + malloc_trim(size_t pad); + + If possible, gives memory back to the system (via negative arguments + to sbrk) if there is unused memory at the `high' end of the malloc + pool or in unused MMAP segments. You can call this after freeing + large blocks of memory to potentially reduce the system-level memory + requirements of a program. However, it cannot guarantee to reduce + memory. Under some allocation patterns, some large free blocks of + memory will be locked between two used chunks, so they cannot be + given back to the system. + + The `pad' argument to malloc_trim represents the amount of free + trailing space to leave untrimmed. If this argument is zero, only + the minimum amount of memory to maintain internal data structures + will be left. Non-zero arguments can be supplied to maintain enough + trailing space to service future expected allocations without having + to re-obtain memory from the system. + + Malloc_trim returns 1 if it actually released any memory, else 0. +*/ +int dlmalloc_trim(size_t); + +/* + malloc_usable_size(void* p); + + Returns the number of bytes you can actually use in + an allocated chunk, which may be more than you requested (although + often not) due to alignment and minimum size constraints. + You can use this many bytes without worrying about + overwriting other allocated objects. This is not a particularly great + programming practice. malloc_usable_size can be more useful in + debugging and assertions, for example: + + p = malloc(n); + assert(malloc_usable_size(p) >= 256); +*/ +size_t dlmalloc_usable_size(void*); + +/* + malloc_stats(); + Prints on stderr the amount of space obtained from the system (both + via sbrk and mmap), the maximum amount (which may be more than + current if malloc_trim and/or munmap got called), and the current + number of bytes allocated via malloc (or realloc, etc) but not yet + freed. Note that this is the number of bytes allocated, not the + number requested. It will be larger than the number requested + because of alignment and bookkeeping overhead. Because it includes + alignment wastage as being in use, this figure may be greater than + zero even when no user-level chunks are allocated. + + The reported current and maximum system memory can be inaccurate if + a program makes other calls to system memory allocation functions + (normally sbrk) outside of malloc. + + malloc_stats prints only the most commonly interesting statistics. + More information can be obtained by calling mallinfo. +*/ +void dlmalloc_stats(void); + +#endif /* !ONLY_MSPACES */ + +#if MSPACES + +/* + mspace is an opaque type representing an independent + region of space that supports mspace_malloc, etc. +*/ +typedef void* mspace; + +/* + create_mspace creates and returns a new independent space with the + given initial capacity, or, if 0, the default granularity size. It + returns null if there is no system memory available to create the + space. If argument locked is non-zero, the space uses a separate + lock to control access. The capacity of the space will grow + dynamically as needed to service mspace_malloc requests. You can + control the sizes of incremental increases of this space by + compiling with a different DEFAULT_GRANULARITY or dynamically + setting with mallopt(M_GRANULARITY, value). +*/ +mspace create_mspace(size_t capacity, int locked); + +/* + destroy_mspace destroys the given space, and attempts to return all + of its memory back to the system, returning the total number of + bytes freed. After destruction, the results of access to all memory + used by the space become undefined. +*/ +size_t destroy_mspace(mspace msp); + +/* + create_mspace_with_base uses the memory supplied as the initial base + of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this + space is used for bookkeeping, so the capacity must be at least this + large. (Otherwise 0 is returned.) When this initial space is + exhausted, additional memory will be obtained from the system. + Destroying this space will deallocate all additionally allocated + space (if possible) but not the initial base. +*/ +mspace create_mspace_with_base(void* base, size_t capacity, int locked); + +/* + mspace_malloc behaves as malloc, but operates within + the given space. +*/ +void* mspace_malloc(mspace msp, size_t bytes); + +/* + mspace_free behaves as free, but operates within + the given space. + + If compiled with FOOTERS==1, mspace_free is not actually needed. + free may be called instead of mspace_free because freed chunks from + any space are handled by their originating spaces. +*/ +void mspace_free(mspace msp, void* mem); + +/* + mspace_realloc behaves as realloc, but operates within + the given space. + + If compiled with FOOTERS==1, mspace_realloc is not actually + needed. realloc may be called instead of mspace_realloc because + realloced chunks from any space are handled by their originating + spaces. +*/ +void* mspace_realloc(mspace msp, void* mem, size_t newsize); + +/* + mspace_calloc behaves as calloc, but operates within + the given space. +*/ +void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size); + +/* + mspace_memalign behaves as memalign, but operates within + the given space. +*/ +void* mspace_memalign(mspace msp, size_t alignment, size_t bytes); + +/* + mspace_independent_calloc behaves as independent_calloc, but + operates within the given space. +*/ +void** mspace_independent_calloc(mspace msp, size_t n_elements, + size_t elem_size, void* chunks[]); + +/* + mspace_independent_comalloc behaves as independent_comalloc, but + operates within the given space. +*/ +void** mspace_independent_comalloc(mspace msp, size_t n_elements, + size_t sizes[], void* chunks[]); + +/* + mspace_footprint() returns the number of bytes obtained from the + system for this space. +*/ +size_t mspace_footprint(mspace msp); + + +#if !NO_MALLINFO +/* + mspace_mallinfo behaves as mallinfo, but reports properties of + the given space. +*/ +struct mallinfo mspace_mallinfo(mspace msp); +#endif /* NO_MALLINFO */ + +/* + mspace_malloc_stats behaves as malloc_stats, but reports + properties of the given space. +*/ +void mspace_malloc_stats(mspace msp); + +/* + mspace_trim behaves as malloc_trim, but + operates within the given space. +*/ +int mspace_trim(mspace msp, size_t pad); + +/* + An alias for malloc_usable_size. +*/ +size_t mspace_usable_size(void *mem); + +/* + An alias for mallopt. +*/ +int mspace_mallopt(int, int); + +#endif /* MSPACES */ + +#ifdef __cplusplus +}; /* end of extern "C" */ +#endif + +#endif /* MALLOC_280_H */