Code Monkey home page Code Monkey logo

libs's Introduction

build

libs

Single-file public domain libraries for C/C++ (dual licensed under MIT).

  • app.h - Small cross-platform base framework for graphical apps, for C/C++.
  • assetsys.h - File system abstraction to read from zip-files, for C/C++.
  • hashtable.h - Cache efficient hash table implementation for C/C++.
  • http.h - Basic HTTP protocol implementation over sockets (no https).
  • ini.h - Simple ini-file reader for C/C++.
  • rnd.h - Pseudo-random number generators for C/C++.
  • strpool.h - Highly efficient string pool for C/C++.
  • thread.h - Cross platform threading functions for C/C++.

wip libs

More libs, work-in-progress, some are unfinished, some are complete but lacking documentation.

  • array.h - Dynamic array library for C/C++.
  • audiosys.h - Sound mixer library for C/C++.
  • buffer.h - Memory buffer with read/write operations, for C/C++.
  • crtemu.h - Cathode ray tube emulation shader for C/C++.
  • cstr.h - String interning and manipulation library for C/C++.
  • dialog.h - Loading and management of dialogs for a custom game dialog system.
  • dir.h - Directory listing functions for C/C++.
  • frametimer.h - Framerate timer functionality, for C/C++.
  • id3tag.h - Read/write ID3 tags from/to mp3 files in C/C++.
  • img.h - Image processing functions for C/C++.
  • mus.h - Parsing library for MUS music files (as used in DOS games).
  • paldither.h - Convert true-color image to custom palette, with dither.
  • palettize.h - Median-cut palette generation and remapping for C/C++.
  • palrle.h - Run-length encoding of palettized bitmaps, for C/C++.
  • pixelfont.h - Custom pixel font format builder and renderer.
  • sysfont.h - Simple debug text renderer for C/C++.
  • testfw.h - Basic test framework for C/C++.

repackaged libs

Single-file header-only versions of libs written by other people, released under the same license as the original lib. I recommend using the latest version of these libs - I only repackage them like this to fit my single-file-libs centered dev paradigm, and if you don't absolutely need that, you are better off using the original multi-file versions.

  • ftplib.h - FTP client lib for C/C++. By Thomas Pfau.
  • hoedown.h - Markdown to HTML renderer for C/C++. By Porte/Marti/Mendez/Torres.
  • libxdiff.h - File Differential Library. By Davide Libenzi.
  • lzma.h - LZMA data compression/decompression library. By Igor Pavlov.
  • opl.h - OPL3/SB16 emulation with MIDI interface. Based on code by Aaron Giles and Mateusz Viste
  • samplerate.h - Sample-rate converter (libsamplerate) for C/C++. By Erik de Castro Lopo
  • speech.h - Basic text-to-speech synthesizer for C/C++. By Jari Komppa / Nick Ing-Simmons (et al)

libs's People

Contributors

czarnota avatar elijahcirioli avatar liamkarlmitchell avatar lutzenh avatar mattiasgustavsson avatar randygaul avatar robloach avatar sokolmish avatar theia-ajax avatar thp avatar zanea avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

libs's Issues

ini.h: Bad bounds checking in ini_find_property()

Currently, ini_find_property() loops through properties with this line:

libs/ini.h

Line 755 in 022370a

for( i = 0; i < ini->property_capacity; ++i )

This runs fine when the property you expect is there, but when it is not the code will run through all uninitialized and unused sections because the loop is bounded by ini->property_capacity, not ini->property_count. If the section happens to be 1 and the property name string is ill-formed, then the program will crash.

Setting calloc() as a custom memory allocator (by defining the INI_MALLOC macro) will also get rid of the bad behavior, but in case of a property that doesn't exist in the file there will still be unnecessary iterations (from ini->property_count to ini->property_capacity).

No thread_detach() function?

I noticed a lack of a detach function, I was wondering if it was on purpose. Anyway if anyone needs here's my version:

int thread_detach( thread_ptr_t thread )
    {
    #if defined( _WIN32 )

        return CloseHandle((HANDLE) thread) != 0;

    #elif defined( __linux__ ) || defined( __APPLE__ ) || defined( __ANDROID__ )

        return pthread_detach((pthread_t) thread) == 0;

    #else 
        #error Unknown platform.
    #endif
    }

app.h + VS2019 + Win10 PRO

Has anyone ever attempted this?
app.h uses Direct Sound 8 ... my build fails on various locations in dsound.h

TODO: Fix signal so that this can be an "if" instead of "while"

I'm trying to port the spsc queue to use C11 thread and atomic and I encounter this comment:

https://github.com/mattiasgustavsson/libs/blob/main/thread.h#L1401

As far as I can tell, the current signal is already guarding against spurious wake up with a while loop:

https://github.com/mattiasgustavsson/libs/blob/main/thread.h#L970-L974

https://github.com/mattiasgustavsson/libs/blob/main/thread.h#L998-L1008

What else needs to be fixed?
Can this just be switched to if instead?
It saves one atomic load which doesn't seem to be much in the grand scheme of things but still it's something.

In thread.h: thread_create() name conflict on macOS

thread.h fails to compile for me on macOS 10.14 with Xcode because thread.h's thread_create() declaration conflicts with the thread_create found in the macOS SDK's mach/task.h. Maybe calling it something that's already taken wasn't a good idea?

Issue with ini_find_section and ini_find_property (+fix)

When no name_length argument is provided, you ask for string length by calling INI_STRLEN(name).
This is actually wrong, it should be INI_STRLEN(name) + 1, as you should compare it with '\0' too.

In current state, if eg. two sections are present in INI, [A] and [AB], where section [AB] comes before section [A], when you call ini_find_section(ini, "A"), it returns index of section [AB] instead of [A].

This is quite huge bug... Cost me some time, searching through my code what I did wrong and after stepping into everything, I saw this... It should be fixed ASAP.

It affects ini_find_section and ini_find_property functions.

assetsys.h Win32_WINNT version

Just a recommendation to not muck with the value someone else may have defined use a less than check don't just blindly set it to XP minimum.

#if _WIN32_WINNT < 0x0501
    #undef _WIN32_WINNT
    #define _WIN32_WINNT 0x0501 // requires Windows XP minimum
    // 0x0400=Windows NT 4.0, 0x0500=Windows 2000, 0x0501=Windows XP, 0x0502=Windows Server 2003, 0x0600=Windows Vista, 
    // 0x0601=Windows 7, 0x0602=Windows 8, 0x0603=Windows 8.1, 0x0A00=Windows 10
#endif

http.h: line 312: if (sock == -1)

This needs to replaced with:
if (sock == HTTP_INVALID_SOCKET)

I hope that no one has written this yet and that I have overlooked it ;)

ini.h: handling property and comment on same line, and handling empty values.

I ran into two issues:

property = 5 ; test comment returned 5 ; test comment as value.

property = \n removed spaces before the value, upto the end of the line, and spaces after the value upto '='.

This resulted in a negative or zero value length. In case of a zero length ini_property_add() would do strlen() to search for the end of the value, which it would find at the end of the file. So for an empty value ALL data upto the end of the file would be returned.
As a workaround I added ini_property_add_empty() which stores 1 byte empty string (just the '\0').

            /* property */
            else
                {
                start = ptr;
                while( *ptr && *ptr !='=' && *ptr != '\n' ) ++ptr; // find "="
                if( *ptr == '=' )
                    {
                    len = (int)( ptr - start);
                    ++ptr;
                    while( *ptr && *ptr <= ' ' && *ptr != '\n' ) ptr++;  // this will properly detect start of comment. only the '\n' check is needed since '\n' < ' ')
                    start2 = ptr;
                    while( *ptr                && *ptr != ';' && *ptr != '\n') ++ptr;  // find end of value, upto start of comment or end of line
                    while( *(--ptr) <= ' ' ) (void)ptr;  // ignore traling spaces, tabs, etc. (if there is no value, this will stop back at the "=", causing (ptr - start2) to be negative!
                    ptr++;
					int len2 = (int) ptr - start2; // can be negative beause we skip spaces in both directions!
					if(len2 > 0)
						{
						ini_property_add( ini, s, start, len, start2, len2 ); // (can't handle empty or negative values!)
						}else{
						ini_property_add_empty( ini, s, start, len); // store an empty value.
						}
					// Note: if we removed trailing spaces, they will be skipped in the next pass, and we will detect (and skip) the ";" comment (if any)
                    }
                }

I did not do a lot of testing but it works in my case so far, so others may find this helpful.

thread.h mutex recursive on Windows but not pthread

In thread.h thread_mutex_lock() doesn't behave the same on Windows as on Linux/macOS. On Windows it is recursive, meaning you can double-lock a mutex on the same thread, but on Linux as it is it will deadlock. My personal solution is making the pthread one also recursive by replacing pthread_mutex_init( (pthread_mutex_t*) mutex, NULL ); with:

	pthread_mutexattr_t ma;
	pthread_mutexattr_init(&ma);
	pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE);
	pthread_mutex_init((pthread_mutex_t *) mutex, &ma);
	pthread_mutexattr_destroy(&ma);

AssetSys: Mount from Memory

Would be awesome to have a assetsys_mount_memory() or similar to mount from an already loaded file data.

assetsys_mount_memory(assetsys_t* sys, void* file_data, uint file_size, char const* mount_as);

Would this be out of scope for assetsys?

hashtable as priority queue

Like we discussed over twitter, since hashtable uses an additional layer of indirection under the hood to expose arrays of items and keys, it is completely possible to sort the user items without disturbing the internal probing chains.

I'm posting an implementation of a swap function, which can trivially plugged into a sorting algorithm. This allows the hash table to also double up as a sorted array, useful for priority queues or LRU caches.

void hashtable_internal_byteswap( void* a, void* b, int len )
    {
    char* str_a = (char*)a;
    char* str_b = (char*)b;

    for ( int i = 0; i < len; ++i )
        {
        char t = *str_a;
        *str_a = *str_b;
        *str_b = t;
        ++str_a;
        ++str_b;
        }
    }


int hashtable_swap( hashtable_t const* table, int item_index_a, int item_index_b )
    {
    if( (item_index_a < 0) | (item_index_b < 0) ) return 0;

    int slot_a = table->items_slot[ item_index_a ];
    int slot_b = table->items_slot[ item_index_b ];

    table->items_slot[ item_index_a ] = slot_b;
    table->items_slot[ item_index_b ] = slot_a;

    HASHTABLE_U64 temp_key = table->items_key[ item_index_a ];
    table->items_key[ item_index_a ] = table->items_key[ item_index_b ];
    table->items_key[ item_index_b ] = temp_key;

    void* item_a = (void*)( ( (uintptr_t) table->items_data ) + item_index_a * table->item_size );
    void* item_b = (void*)( ( (uintptr_t) table->items_data ) + item_index_b * table->item_size );
    hashtable_internal_byteswap( item_a, item_b, table->item_size );

    table->slots[ slot_a ].item_index = item_index_b;
    table->slots[ slot_b ].item_index = item_index_a;

    return 1;
    }

What't the point of the way union/struct types are defined in thread.h?

I am fairly new to C coding (several months, though I have coded in C++) and I do not understand many C conventions so bear with me. What is the point of writing the types in thread.h in two passes. You have a union like

union thread_mutex_t 
    { 
    void* align; 
    char data[ 64 ];
    };

and then you have a compile time check like this

#pragma warning( push )
#pragma warning( disable: 4214 ) // nonstandard extension used: bit field types other than int
struct x { char thread_mutex_type_too_small : ( sizeof( thread_mutex_t ) < sizeof( CRITICAL_SECTION ) ? 0 : 1 ); }; 
#pragma warning( pop )

In the case of the thread_signal_t implementation t is even worse since you also define an internal struct besides the compile time check. So, what is the point in doing that instead of just defining it once? You would not need the compilation check and it would be much clearer.

I had this question since I am currently modifying the thread_signal code so that it can return arbitrary value and not just 1 or 0 so it would act kind of like a listener object that returns an event. It would return a "null" (or equivalent for your type) value if timeout and the value if it did not timeout (which could be another suggestion to add to the code since it would actually be pretty useful and is not that hard to implement with some macro magic.

app.h sample not building with tcc on Win10

The sample is not building with tcc unless I:

  1. I use the app.h from the template_project repo
  2. Comment out msvc specific last line extern "C"
  3. Move #include "app.h" below #include <stdlib.h>

When I try to build without the above steps it gives error:
app.h:837: error: ')' expected (got "*")

Compiles just fine with msvc but decided to file an issue for tcc after I saw your tweet about how you liked the workflow.

Is the SDL backend of app.h in working state?

In the docs of app.h you can read "even though only windows is supported right now", but however, the source code seems to have a SDL platform backend. I'm wondering if that backend can be used (in which case all the platforms supported by SDL would work), or if it's still WIP or with some features not working.

Also, I see that you put a set of OpenGL functions pointers inside a struct, which is something I like to do (because I wish to write apps which can be setup to either use the host GPU OpenGL implementation, or alternatively a software implementation based in Mesa through osmesa -even switching between both implementations at runtime would be possible, provided that the app sets all the OpenGL state during each redraw). Just for not reinventing the wheel, have you done something like this in any of your apps/demos?

Well, if I use app.h, I believe I'll need to customize it because my apps need to access OpenGL, and I think that you are hiding OpenGL from the client apps, so I'd add an API call that behaves as a redraw callback or something like that (as well as an API call for switching between the host GPU and the osmesa implementations).

assetsys_mount should accept absolute path

Is there any certain motivation behind that statement?

assetsys_error_t assetsys_mount( assetsys_t* sys, char const* path, char const* mount_as )
...
... `path` must be a relative path ...

In my project i actually have to load assets from different places, eg. installation folder and folder in Documents(win) or home(linux). And calculating relative path to these is not the pleasing work to do.

This line however does permit absolute paths in windows! I can still mount any directory or archive i want having path starting with something like this C:/Users/user/Documents/Game.

libs/assetsys.h

Line 5866 in 022370a

if( len > 0 && path[ 0 ] == '/' ) return ASSETSYS_ERROR_INVALID_PATH;

But this won't work on linux, so it makes me wonder why even bother adding that line over there? I had to remove it for my project. I have to support multiple paths to the assets and relative paths are not reasonable restriction over here.

App.h using deprecated Windows APIs to find known folders

From MSDN docs on the API and enum values used:

Note As of Windows Vista, this function is merely a wrapper for SHGetKnownFolderPath. The CSIDL value is translated to its associated KNOWNFOLDERID and then SHGetKnownFolderPath is called. New applications should use the known folder system rather than the older CSIDL system, which is supported only for backward compatibility.


[!Note]As of Windows Vista, these values have been replaced by KNOWNFOLDERID values. See that topic for a list of the new constants and their corresponding CSIDL values. For convenience, corresponding KNOWNFOLDERID values are also noted here for each CSIDL value.

The CSIDL system is supported under Windows Vista for compatibility reasons. However, new development should use KNOWNFOLDERID values rather than CSIDL values.

It might be sense to include this API flag, but hide it behind something like a APP_XP_COMPAT compiler define, so people can use these deprecated functions only if XP compatibility is desired.

Here's the new API that should supposedly be used instead:

Infinite loop in hash table

I found an infinite loop in the hash table implementation. The infinite loop shows up when removing an entry. I'm guessing this was caused by the refactor to use item_index < 0 instead of a zero-hash (or I'm just doing something stupid). Here's a minimal program to reproduce the bug. I'm going to take a whack at figuring this out myself shortly, but am posting it here just in case.

#define HASHTABLE_IMPLEMENTATION
#include "hashtable.h"

#include <stdint.h>

uint64_t constexpr fnv1a(const void* data, int size)
{
	const char* s = (const char*)data;
	uint64_t h = 14695981039346656037ULL;
	char c = 0;
	while (size--) {
		h = h ^ (uint64_t)(*s++);
		h = h * 1099511628211ULL;
	}
	return h;
}

struct v2
{
	float x;
	float y;
};

v2 V2(float x, float y) { v2 v; v.x = x; v.y = y; return v; }

void hset(hashtable_t* h, uint64_t key, v2 v)
{
	hashtable_insert(h, (uint32_t)fnv1a(&key, sizeof(key)), &key, &v);
}

v2 hget(hashtable_t* h, uint64_t key)
{
	void* ptr = hashtable_find(h, (uint32_t)fnv1a(&key, sizeof(key)), &key);
	if (ptr) return *(v2*)ptr;
	else return V2(0, 0);
}

void hdel(hashtable_t* h, uint64_t key)
{
	hashtable_remove(h, (uint32_t)fnv1a(&key, sizeof(key)), &key);
}

int main()
{
	hashtable_t hashtable;
	hashtable_t* h = &hashtable;
	hashtable_init(h, sizeof(int), sizeof(v2), 16, NULL);
	hset(h, 0, V2(1, 2));
	hset(h, 1, V2(4, 10));
	hset(h, 2, V2(-12, 13));
	v2 a = hget(h, 0);
	v2 b = hget(h, 1);
	v2 c = hget(h, 2);
	assert(a.x == 1 && a.y == 2);
	assert(b.x == 4 && b.y == 10);
	assert(c.x == -12 && c.y == 13);
	hdel(h, 0);
	hdel(h, 1);
	hdel(h, 2); // <-- Infinite loop shows up here.
	a = hget(h, 0);
	b = hget(h, 1);
	c = hget(h, 2);
	assert(a.x == 0 && a.y == 0);
	assert(b.x == 0 && b.y == 0);
	assert(c.x == 0 && c.y == 0);
	hashtable_term(h);
	return 0;
}

strpool_length() documentation question

The documentation for strpool_length() says this:

Returns the length, in characters, of the specified string. The resulting value is only valid as long as no call is made
to strpool_init, strpool_term, strpool_defrag or strpool_discard. It is therefor recommended to never store the
value, and always grab it fresh by another call to strpool_length when it is needed. strpool_length is a very fast
function to call - it does little more than an array lookup. If handle is invalid, strpool_length returns 0.

Why would the length not stay valid even after a call to strpool_defrag()? The string still exists, it's just that its location in memory may have changed. So is the documentation accurate?

Another nitpick, wouldn't it be better to say that this returns the length in bytes, not characters? I don't think strpool is doing any kind of UTF8 decoding.

In thread.h, MinGW doesn't like VC's __try/__except

In thread.h in thread_create() the _WIN32 code assumes that we're using Visual Studio and uses the Microsoft-specific __try() and __except() to name the thread. Since MinGW's GCC doesn't like it and it's only vaguely needed if you're using Visual Studio I added a #ifdef _MSC_VER around it at line 684 to disable thread naming.

Multithreading

Is strpool.h thread-safe?
E.g. can we access & modify the pool concurrently?

hashtable_init description doesn't match function.

The function declaration is

void hashtable_init( hashtable_t* table, int key_size, int item_size, int initial_capacity, void* memctx );

but the description says:

hashtable_init
--------------

    void hashtable_init( hashtable_t* table, int item_size, int initial_capacity, void* memctx )

Initialize a hashtable instance. `item_size` specifies the size, in bytes, of the data type holding a single item stored
in the table. `initial_capacity` is the number of items to allocate storage for initially - capacity will automatically
grow as needed, by reallocating memory.

So, I'm unsure what to do here.

bug in rnd_xorshift_range()

The function rnd_xorshift_range() returns out of range values, because it uses the next value like if it was a normalized float in range [0,1]. I think the best solution would be to create a nextf() normalized float for xorshift, and call it from rnd_xorshift_range()

INI_STRICMP should have length as 3rd argument

Current API that accept name_length won't work correctly if string is not nul terminated. Name length implies that it's OK to not be nul terminated, but because INI_STRICMP doesn't have length:

int ini_find_section( ini_t const* ini, char const* name, int name_length );
int ini_find_property( ini_t const* ini, int section, char const* name, int name_length );

My fix was to add length to INI_STRICMP usage:

if( (int) INI_STRLEN( other ) == name_length && INI_STRICMP( name, other, name_length ) == 0 )

WASM assetsys example

I dunno if it's useful for anyone, but I wanted to see if I could load files with the same code on native/wasm (via emscripten) and it worked great! Here is the deployed example. I had some issues with physfs in emscripten, and didn't need all the containers it supported (so I disabled all but zip) and assetsys was just a way better fit. Would you like a PR for the example, or a link in README?

Unrelated: I love this collection of headers! assetsys is very simple to use, and works great, and everything else is mega-useful. Keep up the good work!

Can't mount as root

Hi,

In the documentation it says that in order to mount as root path you can pass an empty string to mount_as. But in the code it checks if the mount_as string is empty and returns an error. Passing "/" causes other problems regarding finding files. Are there any plans to fix these issues?

Cast from thread_tls_t to pthread_key_t loses precision

I'm using g++, and I'm getting errors like this when using thread.h:

error: cast from ‘thread_tls_t {aka void*}’ to ‘pthread_key_t {aka unsigned int}’ loses precision [-fpermissive]
  pthread_key_delete((pthread_key_t)tls);

The Windows code is casting tls to uintptr_t before casting to DWORD in order to (I assume) fix a similar issue on Windows. The same fix seems to work for the Posix version in g++.

[`thread.h`] : Linux `pthread_setname_np()` not defined

Got this issue on Linux Mint 20 ( based upon Ubuntu whatever).

GCC will complain pthread_setname_np() is missing.

Actually, it is just hidden by default, because it is "not portable" ( suffix _np ).

To make it visible again, one has to add : #define __USE_GNU

strpool.h - discards all

Hi,

In strpool.h, is it possible to implement a function to discard all strings in pool?
That is, recycle memory without freeing it, and also without iterating with strpool_discard over each handle.

Thank's.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.