Add draft better string library implementation

This commit is contained in:
Doyle Thai 2016-09-07 23:33:01 +10:00
parent da07ce3f75
commit 5b682ddcf6
7 changed files with 169 additions and 2 deletions

View File

@ -129,6 +129,7 @@
<ClCompile Include="src\Platform.c" />
<ClCompile Include="src\Renderer.c" />
<ClCompile Include="src\Shader.c" />
<ClCompile Include="src\String.c" />
<ClCompile Include="src\UserInterface.c" />
<ClCompile Include="src\WorldTraveller.c" />
<ClCompile Include="src\Texture.c" />
@ -153,6 +154,7 @@
<ClInclude Include="src\include\Dengine\OpenGL.h" />
<ClInclude Include="src\include\Dengine\Renderer.h" />
<ClInclude Include="src\include\Dengine\Shader.h" />
<ClInclude Include="src\include\Dengine\String.h" />
<ClInclude Include="src\include\Dengine\Texture.h" />
<ClInclude Include="src\include\Dengine\UserInterface.h" />
<ClInclude Include="src\include\Dengine\WorldTraveller.h" />

View File

@ -51,6 +51,9 @@
<ClCompile Include="src\UserInterface.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\String.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="data\shaders\default.vert.glsl" />
@ -107,5 +110,8 @@
<ClInclude Include="src\include\Dengine\UserInterface.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\include\Dengine\String.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -39,7 +39,7 @@ char *common_strncpy(char *dest, const char *src, i32 numChars)
return dest;
}
char *common_memset(char *const ptr, const i32 value, const i32 numBytes)
u8 *common_memset(u8 *const ptr, const i32 value, const i32 numBytes)
{
for (i32 i = 0; i < numBytes; i++)
ptr[i] = value;

117
src/String.c Normal file
View File

@ -0,0 +1,117 @@
#include "Dengine/String.h"
#include "Dengine/Platform.h"
/*
* +-------------------------------------+
* | Header | C-String | Null Terminator |
* +-------------------------------------+
* |
* +--> Functions return the c-string for compatibility with other
* string libraries
*
* Headers are retrieved using pointer arithmetric from the C string. These
* strings are typechecked by their own typedef char String.
*/
typedef struct StringHeader
{
i32 len;
// NOTE(doyle): A string is stored as one contiguous chunk of memory. We
// don't use a pointer for storing the string as this'd require an extra
// 4 bytes to store the pointer, which we don't need if everything is
// contiguous. The string follows on from the len, and we return the address
// of the string to simulate a pointer.
String string;
} StringHeader;
// TODO(doyle): string capacity- append if already enough space
INTERNAL StringHeader *string_getHeader(String *const string)
{
StringHeader *result = NULL;
// NOTE(doyle): C-String must be located at end of struct type for offset to
// be correct! We cannot just subtract the string-header since we start at
// the string ptr position
if (string)
{
i32 byteOffsetToHeader = sizeof(StringHeader) - sizeof(String *);
result = CAST(StringHeader *)((CAST(u8 *) string) - byteOffsetToHeader);
}
return result;
}
i32 string_len(String *const string)
{
if (!string) return -1;
StringHeader *header = string_getHeader(string);
i32 result = header->len;
return result;
}
String *const string_append(MemoryArena *const arena, String *oldString,
char *appendString, i32 appendLen)
{
if (!oldString || !appendString || !arena) return oldString;
/* Calculate size of new string */
StringHeader *oldHeader = string_getHeader(oldString);
i32 newLen = oldHeader->len + appendLen;
String *newString = string_makeLen(arena, newLen);
/* Append strings together */
String *insertPtr = newString;
common_strncpy(insertPtr, oldString, oldHeader->len);
insertPtr += oldHeader->len;
common_strncpy(insertPtr, appendString, appendLen);
/* Free old string */
string_free(arena, oldString);
return newString;
}
void string_free(MemoryArena *arena, String *string)
{
if (!string || !arena) return;
StringHeader *header = string_getHeader(string);
i32 bytesToFree = sizeof(StringHeader) + header->len;
common_memset((u8 *)header, 0, bytesToFree);
PLATFORM_MEM_FREE(arena, header, bytesToFree);
string = NULL;
}
String *const string_make(MemoryArena *const arena, char *string)
{
if (!arena) return NULL;
i32 len = common_strlen(string);
String *result = string_makeLen(arena, len);
common_strncpy(result, string, len);
return result;
}
String *const string_makeLen(MemoryArena *const arena, i32 len)
{
if (!arena) return NULL;
// NOTE(doyle): Allocate the string header size plus the len. But _note_
// that StringHeader contains a single String character. This has
// a side-effect of already preallocating a byte for the null-terminating
// character. Whilst the len of a string counts up to the last character
// _not_ including null-terminator.
i32 bytesToAllocate = sizeof(StringHeader) + len;
void *chunk = PLATFORM_MEM_ALLOC(arena, bytesToAllocate, u8);
if (!chunk) return NULL;
StringHeader *header = CAST(StringHeader *) chunk;
header->len = len;
return &header->string;
}

View File

@ -3,6 +3,7 @@
#include "Dengine/Debug.h"
#include "Dengine/Entity.h"
#include "Dengine/Platform.h"
#include "Dengine/String.h"
#include "Dengine/UserInterface.h"
enum State
@ -575,6 +576,30 @@ INTERNAL void unitTest(MemoryArena *arena)
ASSERT(common_atoi("+32", common_strlen("+32")) == 32);
ASSERT(common_atoi("+ 32", common_strlen("+ 32")) == 0);
asset_unitTest(arena);
i32 memBefore = arena->bytesAllocated;
String *hello = string_make(arena, "hello, ");
String *world = string_make(arena, "world");
ASSERT(string_len(hello) == 7);
ASSERT(string_len(world) == 5);
hello = string_append(arena, hello, world, string_len(world));
ASSERT(string_len(hello) == 12);
string_free(arena, hello);
string_free(arena, world);
hello = string_make(arena, "");
world = string_make(arena, "");
hello = string_append(arena, hello, world, string_len(world));
ASSERT(string_len(hello) == 0);
ASSERT(string_len(world) == 0);
string_free(arena, hello);
string_free(arena, world);
i32 memAfter = arena->bytesAllocated;
ASSERT(memBefore == memAfter);
}
// TODO(doyle): Remove and implement own random generator!

View File

@ -32,7 +32,7 @@ i32 common_strlen(const char *const string);
i32 common_strcmp(const char *a, const char *b);
void common_strncat(char *dest, const char *src, i32 numChars);
char *common_strncpy(char *dest, const char *src, i32 numChars);
char *common_memset(char *const ptr, const i32 value, const i32 numBytes);
u8 *common_memset(u8 *const ptr, const i32 value, const i32 numBytes);
// Max buffer size should be 11 for 32 bit integers
void common_itoa(i32 value, char *buf, i32 bufSize);

View File

@ -0,0 +1,17 @@
#ifndef DENGINE_STRING_H
#define DENGINE_STRING_H
#include "Dengine/Common.h"
typedef struct MemoryArena MemoryArena;
typedef char String;
i32 string_len(String *const string);
String *const string_append(MemoryArena *const arena, String *oldString,
String *appendString, i32 appendLen);
void string_free(MemoryArena *arena, String *string);
String *const string_make(MemoryArena *const arena, char *string);
String *const string_makeLen(MemoryArena *const arena, i32 len);
#endif