Starting

    I want to create a framework - collection of libraries.

    Why static libraries? Compiler build them very fast. Easy to use.

    Something about code:

  • All functions, struct and other types must have names with letters 'sl' in the beginning.
  • Do not use `namespace` in API. Can use it for internal things.
  • Do not use STL in API. Can use it for internal things.
  • I will prefer C-style programming (c arrays, c strings)
  • Use char* strings, not wchar* or other.
  • Names must looks like this slLongName

    Why no namespaces and not_like_this_names? Because this is huge wasting of time. Names_like_this can be used in classes like containers, or in math classes. But not in Interface classes.

    I will use Visual Studio. About folders:

  • `build` - contain project files
  • `inc` - include files
  • `libs` - static library files
  • `src` - source code, including all 3rd party libraries.
  • I don't want to use things like ref count, or scene manager. I need to write first layer that will be above base things. Only after this, I will write second layer, then third layer and others. Do not write complicated classes for basic things, like for texture. Write simple class for texture, then write more complex class using this class.

    I will put include files and source code in folders, for example, everything for math will be in forlder with name `math`.

    All basic functionality will be in base library. Other things will be in other libraries.

    There is must be a file, that will include all basic things. It will located in `inc` folder, and will have name - `slowlib.h`

    Macros

    Preprocessor. In other file, I will put macros, that will help to make code more platform independent. And just useful macros.

    // I think this is unnecessary, maybe this is old style thing, but I saw it in many
    // professional projects.
    // Just...`inline` will not guarantee that function will be inline
    #ifdef _MSC_VER
    #define SL_FORCEINLINE __forceinline
    #else
    #define SL_FORCEINLINE inline
    #endif
    					

    Detect platform

    #if defined(WIN32) | defined(_WIN64) | defined(_WIN32)
    #define SL_PLATFORM_WINDOWS
    #else
    #error Please, write code for other platform
    #endif

    When you use C functions from C library in C++ you need to add this in function definition\declaration. It for Visual Studio.

    #ifdef SL_PLATFORM_WINDOWS
    #define SL_CDECL _cdecl
    #else
    #error Please, write code for other platform
    #endif

    Debug

    #ifdef _DEBUG
    #define SL_DEBUG
    #endif

    MAKEFOURCC

    // `pack` 4 bytes into 1 uint32_t
    // I don't know about speed.
    // uint32_i magic = SL_MAKEFOURCC('‰', 'P', 'N', 'G');
    //    //magic must be `1196314761`
    #define SL_MAKEFOURCC( ch0, ch1, ch2, ch3 )\
    	((uint32_t)(uint8_t)(ch0)|((uint32_t)(uint8_t)(ch1)<<8)|\
    	((uint32_t)(uint8_t)(ch2)<<16)|((uint32_t)(uint8_t)(ch3)<<24))

    Need to know if this is 64 bit configuration

    #ifdef SL_PLATFORM_WINDOWS
    #if defined _WIN64 || defined __x86_64__
    #define SL_BIT_64
    #endif
    #else
    #error Please, write code for other platform
    #endif

    Show file name, line and function

    // printf("%s %i %s\n", SL_FILE, SL_LINE, SL_FUNCTION);
    #ifdef SL_PLATFORM_WINDOWS
    #define SL_FILE __FILE__
    #define SL_LINE __LINE__
    #define SL_FUNCTION __FUNCTION__
    #else
    #error Please, write code for other platform
    #endif

    For easy linking

    #ifdef _MSC_VER
    
    #if _MSC_VER >= 1920 && _MSC_VER < 1930
    #define SL_LINK_LIBRARY_CMP "_v142"
    #elif _MSC_VER >= 1930 && _MSC_VER < 1933
    #error Please, do something!
    #define SL_LINK_LIBRARY_CMP "_v142"
    #endif
    
    #ifdef SL_BIT_64
    #define SL_LINK_LIBRARY_ARCH "_x64"
    #else
    #define SL_LINK_LIBRARY_ARCH "_x86"
    #endif
    
    #ifdef SL_DEBUG
    #define SL_LINK_LIBRARY_CONF "_Debug"
    #else
    #define SL_LINK_LIBRARY_CONF "_Release"
    #endif
    
    // Use like this: SL_LINK_LIBRARY("libname")
    #define SL_LINK_LIBRARY(n) \
    	__pragma(comment(lib, n SL_LINK_LIBRARY_CMP SL_LINK_LIBRARY_ARCH SL_LINK_LIBRARY_CONF ".lib"))
    

    And last

    // For example if you have 0xAABBCCDD
    // You can get 0xAABB and 0xCCDD using this macros
    #define SL_LO32(l) ((uint16_t)(((uint32_t)(l)) & 0xffff))
    #define SL_HI32(l) ((uint16_t)((((uint32_t)(l)) >> 16) & 0xffff))

    Memory

    Add functions that will allocate and free memory. Memory allocated in one module(exe, dll), can not be deallocated in other. For example, if you create .dll with function that will get some text `void libGetInfo(std::string* s){//fill s here}` you will get error, because library will allocate memory for string data, probably, free old memory, and then in application, app will free this memory. .exe and .dll can use different system libraries for working with memory. Better to make your own functions for this.

    For memory I use other .h file

    Use this functions instead malloc\free new\delete

    class slMemory
    {
    public:
    	static void* malloc(size_t size);
    	static void* calloc(size_t size);
    	static void  free(void*);
    	static void* realloc(void*, size_t size);
    };

    Add functions for faster object creation. Use like this: MyClass* o = slCreate<MyClass>(arg1, arg2, arg3);

    template<typename _type>
    class slObjectCreator
    {
    public:
    
    	template<typename... Args>
    	static _type* create(Args&&... args)
    	{
    		_type* ptr = (_type*)slMemory::malloc(sizeof(_type));
    		if (ptr)
    			new(ptr) _type(std::forward<Args>(args)...);
    		return ptr;
    	}
    
    	static void destroy(_type* ptr)
    	{
    		assert(ptr);
    		ptr->~_type();
    		slMemory::free(ptr);
    	}
    };
    
    // Create object
    template<typename _type, typename... Args>
    _type* slCreate(Args&&... args)
    {
    	return slObjectCreator<_type>::create(std::forward<Args>(args)...);
    }
    
    template<typename _type>
    void slDestroy(_type* ptr)
    {
    	assert(ptr);
    	slObjectCreator<_type>::destroy(ptr);
    }

    Class implementation

    #include "slowlib.h"
    
    #ifdef SL_PLATFORM_WINDOWS
    #define WIN32_LEAN_AND_MEAN
    #include <Windows.h>
    static HANDLE g_processHeap = GetProcessHeap();
    #endif
    
    void* slMemory::malloc(size_t size)
    {
    #ifdef SL_PLATFORM_WINDOWS
    	return HeapAlloc(g_processHeap, 0, size);
    #else
    	return ::malloc(size);
    #endif
    }
    
    void* slMemory::calloc(size_t size)
    {
    #ifdef SL_PLATFORM_WINDOWS
    	return HeapAlloc(g_processHeap, HEAP_ZERO_MEMORY, size);
    #else
    	return ::calloc(1, size);
    #endif
    }
    
    void slMemory::free(void* ptr)
    {
    #ifdef SL_PLATFORM_WINDOWS
    	HeapFree(g_processHeap, 0, ptr);
    #else
    	::free(ptr);
    #endif
    }
    
    void* slMemory::realloc(void* ptr, size_t size)
    {
    #ifdef SL_PLATFORM_WINDOWS
    	return HeapReAlloc(g_processHeap, HEAP_ZERO_MEMORY, ptr, size);
    #else
    	return ::realloc(ptr, size);
    #endif
    }
    

    DLL

    It easiest thing.

    In other .h file

    typedef void* slDLLHandle;   // HMODULE in Windows
    typedef void* slDLLFunction;
    
    class slDLL
    {
    public:
    	
    	// Load dynamic lybrary.
    	// Return pointer if library is loaded.
    	// Call free when you no need it.
    	static slDLLHandle load(const char* libraryName);
    
    	// Unload dynamic lybrary.
    	static void free(slDLLHandle* library);
    
    	// Get function from .dll
    	// Return NULL if there is some error.
    	static slDLLFunction get_proc(slDLLHandle* library, const char* functionName);
    };

    Implementation

    #include "slowlib.h"
    
    #ifdef SL_PLATFORM_WINDOWS
    #define WIN32_LEAN_AND_MEAN
    #include <Windows.h>
    #endif
    
    slDLLHandle slDLL::load(const char* libraryName)
    {
    	SL_ASSERT(libraryName);
    #ifdef SL_PLATFORM_WINDOWS
    	return (slDLLHandle)LoadLibraryA(libraryName);
    #else
    #error Please, write code for other platform
    #endif
    }
    
    void slDLL::free(slDLLHandle* library)
    {
    	SL_ASSERT_ST(library);
    #ifdef SL_PLATFORM_WINDOWS
    	FreeLibrary((HMODULE)library);
    #else
    #error Please, write code for other platform
    #endif
    }
    
    slDLLFunction slDLL::get_proc(slDLLHandle* library, const char* functionName)
    {
    	SL_ASSERT_ST(library);
    	SL_ASSERT_ST(functionName);
    #ifdef SL_PLATFORM_WINDOWS
    	return (slDLLFunction)GetProcAddress((HMODULE)library, functionName);
    #else
    #error Please, write code for other platform
    #endif
    }

    Assert

    In other .h file

    In my assert I will use stacktracer. SL_ASSERT will call sl_internal::onAssert(). onAssert() will call default function for assert, you can change it using function slSetOnAssert.

    namespace sl_internal
    {
        enum flag_onAssert
        {
            flag_onAssert_useDefaultSystemWindow = 0x1,
            flag_onAssert_useStackTrace = 0x2,
        };
        void SL_CDECL onAssert(const char* message, const char* file, uint32_t line, uint32_t flags = 0);
    }
    
    #ifdef SL_DEBUG
    #define SL_ASSERT(expression) if((expression) == 0){sl_internal::onAssert(#expression, SL_FILE, SL_LINE, 0);}
    #define SL_ASSERT_ST(expression) if((expression) == 0){sl_internal::onAssert(#expression, SL_FILE, SL_LINE,\
     sl_internal::flag_onAssert_useDefaultSystemWindow | sl_internal::flag_onAssert_useStackTrace);}
    #else
    #define SL_ASSERT(expression) ((void)0)
    #define SL_ASSERT_ST(expression) ((void)0)
    #endif
    
    extern "C"
    {
        void SL_CDECL slSetOnAssert(void(*)(const char* message, const char* file, uint32_t line, uint32_t flags));
    }

    Implementation

    #include "slowlib.h"
    
    #include <stdio.h>
    
    #ifdef SL_PLATFORM_WINDOWS
    #define WIN32_LEAN_AND_MEAN
    #include <Windows.h>
    #endif
    
    void onAssert_default(const char* message, const char* file, uint32_t line, uint32_t flags)
    {
    #ifdef SL_DEBUG
        if ((flags & sl_internal::flag_onAssert_useStackTrace) == sl_internal::flag_onAssert_useStackTrace)
        {
            slStackTracer::Print();
        }
    
        if ((flags & sl_internal::flag_onAssert_useDefaultSystemWindow) == sl_internal::flag_onAssert_useDefaultSystemWindow)
        {
            slString str_msg(message);
            slString str_file(file);
    
            slStringW str1;
            str_msg.to_utf16(str1);
    
            slStringW str2;
            str_file.to_utf16(str2);
    
    #ifdef SL_PLATFORM_WINDOWS
            _wassert((const wchar_t*)str1.m_data, (const wchar_t*)str2.m_data, line);
    #endif
        }
        else
        {
            printf("%s %s %i\n", message, file, line);
    #ifdef SL_PLATFORM_WINDOWS
            DebugBreak();
    #endif
        }
    #endif
    }
    
    static void(*g_onAssert)(const char* message, const char* file, uint32_t line, uint32_t flags) = onAssert_default;
    
    namespace sl_internal
    {
        void SL_CDECL onAssert(const char* message, const char* file, uint32_t line, uint32_t flags)
        {
            g_onAssert(message, file, line, flags);
        }
    }
    
    extern "C"
    {
        void SL_CDECL slSetOnAssert(void(* f)(const char* message, const char* file, uint32_t line, uint32_t flags))
        {
            g_onAssert = f ? f : onAssert_default;
        }
    }
    

    String

    In this project I decided to write unicode string. Not template class.

    Unicode string have method for conversion into UTF8 and UTF16. I need to store this text. Create simple classes.

    // just data and size
    // it will use in slString
    class slStringA
    {
    	void reallocate(size_t new_allocated);
    public:
    	slStringA();
    	~slStringA();
    	void push_back(char8_t);
    	size_t m_allocated = 0;
    	size_t m_size = 0;
    	char8_t* m_data = nullptr;
    };
    class slStringW
    {
    	void reallocate(size_t new_allocated);
    public:
    	slStringW();
    	~slStringW();
    	void push_back(char16_t);
    	size_t m_allocated = 0;
    	size_t m_size = 0;
    	char16_t* m_data = nullptr;
    };

    Unicode string. Why I need this? Because C++ method (std::wcsrtombs) is not working. And I don't wanted to find other solutions. Better to make your own.

    class slString
    {
    	size_t m_size = 0;
    	size_t m_allocated = 0;
    	char32_t* m_data = nullptr;
    
    	void reallocate(size_t new_allocated);
    public:
    	slString();
    	slString(const char*);
    	slString(const wchar_t*);
    	slString(const char8_t*);
    	slString(const char16_t*);
    	slString(const char32_t*);
    	slString(const slString&);
    	slString(slString&&);
    	~slString();
    	
    	const char32_t* c_str();
    	size_t size() const;
    	void reserve(size_t size);
    	void clear();
    
    	void assign(const char*);
    	void assign(const wchar_t*);
    	void assign(const char8_t*);
    	void assign(const char16_t*);
    	void assign(const char32_t*);
    	void assign(const slString&);
    
    	void append(const char*);
    	void append(const wchar_t*);
    	void append(const char8_t*);
    	void append(const char16_t*);
    	void append(const char32_t*);
    	void append(const slString&);
    	void append(int8_t);
    	void append(int16_t);
    	void append(int32_t);
    	void append(int64_t);
    	void append(uint8_t);
    	void append(uint16_t);
    	void append(uint32_t);
    	void append(uint64_t);
    	void append(float);
    	void append(double);
    
    	void push_back(char);
    	void push_back(wchar_t);
    	void push_back(char8_t);
    	void push_back(char16_t);
    	void push_back(char32_t);
    
    	void pop_back();
    	char32_t pop_back_return();
    	void pop_back_before(char32_t before_this);
    	void pop_front();
    	void replace(char32_t a, char32_t b);
    	void shrink_to_fit();
    
    	void erase(size_t begin, size_t end);
    	void insert(const char32_t* str, size_t where);
    	void trim_spaces();
    
    	// Only for ASCII
    	void to_lower();
    	void to_upper();
    	void flip();
    	void flip_slash();
    	void flip_backslash();
    	int32_t to_int();
    	int64_t to_intll();
    	uint32_t to_uint();
    	uint64_t to_uintll();
    	float to_float();
    	double to_double();
    
    	slString& operator=(const char*);
    	slString& operator=(const wchar_t*);
    	slString& operator=(const char8_t*);
    	slString& operator=(const char16_t*);
    	slString& operator=(const char32_t*);
    	slString& operator=(const slString&);
    	slString& operator=(slString&&);
    
    	const char32_t& operator[](size_t i) const;
    	char32_t& operator[](size_t i);
    	const char32_t& at(size_t i) const;
    	char32_t& at(size_t i);
    
    	void operator+=(const char*);
    	void operator+=(const wchar_t*);
    	void operator+=(const char8_t*);
    	void operator+=(const char16_t*);
    	void operator+=(const char32_t*);
    	void operator+=(int8_t);
    	void operator+=(int16_t);
    	void operator+=(int32_t);
    	void operator+=(int64_t);
    	void operator+=(uint8_t);
    	void operator+=(uint16_t);
    	void operator+=(uint32_t);
    	void operator+=(uint64_t);
    	void operator+=(float);
    	void operator+=(double);
    
    	bool operator==(const slString& other) const;
    	bool operator!=(const slString& other) const;
    
    	void to_utf8(slStringA&);
    	void to_utf16(slStringW&);
    };

    Implementation is too long. For more speed I generated utf8 and utf16 codes. It in UnicodeChars.inl

    Stacktracer

    Stacktracer will tell you programm execution position. Only when you call function. It usually use in assert. So, you will get more usefull information when you make some mistake.

    Last time I tried (some years ago), and it not worked.

    class slStackTracer
    {
    public:
    	static void Print();
    };

    Implemented like this

    static slStackTracerImpl g_stackTracer;
    
    void slStackTracer::Print()
    {
    	size_t t[100];
    	g_stackTracer.dumpStackTrace(t, g_stackTracer.getStackTrace(t, 100, 0));
    }
    

    See source code for slStackTracerImpl \src\slowlib.base\system\slowlib.base.stacktracer.cpp.

    Code was taken from other library. I need to rewrite it. Maybe.

    Download code