Commits

Dmitry Ivanov  committed 91166b9

base lib

  • Participants
  • Parent commits c98d22c

Comments (0)

Files changed (4)

+Yet Another String Library
+by Dmitry Ivanov (jimon.j1m0n@gmail.com)
+
+features : 
+
+1) support UTF-8
+2) strings pool container
+3) fast string compare and copy
+
+class :
+
+yString - base string class, contains reference to pool (or string literal), also contains pseudo hash
+yStringContainer - actually contains strings, data pool abstraction
+yStringConcate - strings concate methods (printf format), use yString for buffer
+
+todo :
+
+1) add memory allocation override to yStringContainer
+2) add detail documentation of string patterns
+
+license :
+
+Copyright (C) 2012 Dmitry Ivanov
+
+	Permission is hereby granted, free of charge, to any person obtaining
+	a copy of this software and associated documentation files (the
+	"Software"), to deal in the Software without restriction, including
+	without limitation the rights to use, copy, modify, merge, publish,
+	distribute, sublicense, and/or sell copies of the Software, and to
+	permit persons to whom the Software is furnished to do so, subject
+	to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+	in all copies or substantial portions of the Software.
+
+	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+	MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+	IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+	CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+	TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+	SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+/*
+Copyright (C) 2012 Dmitry Ivanov
+
+	Permission is hereby granted, free of charge, to any person obtaining
+	a copy of this software and associated documentation files (the
+	"Software"), to deal in the Software without restriction, including
+	without limitation the rights to use, copy, modify, merge, publish,
+	distribute, sublicense, and/or sell copies of the Software, and to
+	permit persons to whom the Software is furnished to do so, subject
+	to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+	in all copies or substantial portions of the Software.
+
+	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+	MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+	IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+	CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+	TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+	SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+// Yet Another String Library by Dmitry Ivanov aka jimon
+// support UTF-8
+//
+// example and tests functions
+
+#include <iostream>
+#include <conio.h>
+
+#include "yasc.h"
+
+// ------------------------------------------------- example 1
+// show basic string allocation
+void example1()
+{
+	printf("---- example 1\n");
+
+	// any string must be allocated on pool, yStringContainer contains string pool
+	yStringContainer container;
+
+	// reserve pool
+	container.Reserve(64);
+
+	// allocate string at pool with size 8 bytes
+	yString playerName = container.Allocate(16);
+
+	// write something to string
+	int count = sprintf(playerName.GetRaw(), "testname");
+	playerName.SetLength(count); // don't forget to write length
+
+	// get string from C string literal (non memory alloc here)
+	yString compare1 = "othername";
+	yString compare2 = "testname";
+
+	// compare strings
+	bool isCorrect1 = (playerName == compare1);
+	bool isCorrect2 = (playerName == compare2);
+
+	printf("'%s' compare '%s' = %i\n", playerName.c_str(), compare1.c_str(), isCorrect1);
+	printf("'%s' compare '%s' = %i\n", playerName.c_str(), compare2.c_str(), isCorrect2);
+
+	printf("---- example 1 end\n");
+}
+
+// ------------------------------------------------- example 2
+// show basic string concate
+void example2()
+{
+	printf("---- example 2\n");
+
+	yStringContainer container(64);
+	yStringConcate concate(container.Allocate(32));
+
+	yString hello = "Hello"; // let first part as string literal
+
+	yString world = container.Allocate(6);
+	memcpy(world.GetRaw(), "world", 6); // other part we get dynamic (think of this as simulation function)
+	world.SetLength(5);
+	
+	// lets concate hello world
+	concate.Add("%s, %s", hello.c_str(), world.c_str());
+	concate.Add(" !");
+	yString helloWorld = concate.BakeToString();
+	printf("result 1 : '%s'\n", helloWorld.c_str());
+
+	// lets make clone of hello world
+	yString helloWorldClone = container.Clone(helloWorld);
+	printf("result 2 : '%s'\n", helloWorldClone.c_str());
+
+	// lets concate new string
+	yString test = concate.Add("test, ").Add("test %i", 2).BakeToString();
+	printf("result 3 : '%s'\n", test.c_str());
+
+	// lets output now hello world, as you now concate works at buffer string, and after each BakeToString it return this buffer string
+	printf("result 4 : '%s'\n", helloWorld.c_str());
+
+	// so we figure out that concate override out helloWorld string, this right
+	// lets check helloWorldClone
+	printf("result 5 : '%s'\n", helloWorldClone.c_str());
+
+	// as expected it works, so if you want store concate result, you should place in at any container
+	// but if you work with result at place, and want to know when data changed, you can simple compare strings
+	// old string data is invalid, but compare methods works, thanks to hash compare
+	bool compare1 = (helloWorld == test);
+	printf("result 6 : %i\n", compare1);
+
+	// so compare return false, as expected, but as you already know, if you doesnt store result, data become invalid, so next compare also false
+	bool compare2 = (helloWorld == helloWorldClone);
+	printf("result 7 : %i\n", compare2);
+
+	printf("---- example 2 end\n");
+}
+
+// ------------------------------------------------- example 3
+// show multiply containers usage
+void example3()
+{
+	printf("---- example 3\n");
+
+	yStringContainer container1(64);
+	yStringContainer container2(64);
+
+	yString a = container1.Allocate(32);
+	yString b = container2.Allocate(32);
+
+	a.SetLength(sprintf(a.GetRaw(), "some test"));
+	b.SetLength(sprintf(b.GetRaw(), "some test"));
+
+	bool compare1 = (a == b); // standart compare
+
+	yString c = a;
+
+	bool compare2 = (a == c); // hash compare, ultrafast
+
+	printf("result : %i %i\n", compare1, compare2);
+
+	printf("---- example 3 end\n");
+}
+
+// ------------------------------------------------- main
+int main()
+{
+	printf("yasc tests\n");
+
+	example1();
+	example2();
+	example3();
+
+	printf("yasc tests ended\n");
+	printf("press any key...");
+
+	_getch();
+	return 0;
+}
+/*
+Copyright (C) 2012 Dmitry Ivanov
+
+	Permission is hereby granted, free of charge, to any person obtaining
+	a copy of this software and associated documentation files (the
+	"Software"), to deal in the Software without restriction, including
+	without limitation the rights to use, copy, modify, merge, publish,
+	distribute, sublicense, and/or sell copies of the Software, and to
+	permit persons to whom the Software is furnished to do so, subject
+	to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+	in all copies or substantial portions of the Software.
+
+	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+	MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+	IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+	CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+	TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+	SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+// Yet Another String Library by Dmitry Ivanov aka jimon
+// support UTF-8
+//
+// yString - base string class, contains reference to pool (or string literal), also contains pseudo hash
+// yStringContainer - actually contains strings, data pool abstraction
+// yStringConcate - strings concate methods (printf format), use yString for buffer
+
+#ifndef H_YASC_H
+#define H_YASC_H
+
+#include <stdio.h>
+#include <stdarg.h>
+
+// ---------------------------------------------------------------------------------------------------------------- config
+
+// standard sizes
+//typedef size_t ySize;
+//typedef size_t yHash;
+
+// optimized sizes
+typedef unsigned int ySize;
+typedef unsigned int yHash;
+
+// enable or disable asserts
+#if 1
+	#include <assert.h>
+	#define Y_ASSERT(__expr) assert(__expr)
+#else
+	#define Y_ASSERT(__expr)
+#endif
+
+// use safe version of vsprintf
+//#define Y_SAFE_VSPRINTF
+
+// ---------------------------------------------------------------------------------------------------------------- UTF-8 service
+
+// convert UTF-8 character to UTF-32 character, UB if input is nullptr
+inline unsigned char yUTF8toUTF32(const char * input, unsigned int & result)
+{
+	if((input[0] & 0xFC) == 0xFC)
+	{
+		result = ((input[0] & 0x01) << 30) | ((input[1] & 0x3F) << 24) | ((input[2] & 0x3F) << 18) | ((input[3] & 0x3F) << 12) | ((input[4] & 0x3F) << 6) | (input[5] & 0x3F);
+		return 6;
+	}
+	else if((input[0] & 0xF8) == 0xF8)
+	{
+		result = ((input[0] & 0x03) << 24) | ((input[1] & 0x3F) << 18) | ((input[2] & 0x3F) << 12) | ((input[3] & 0x3F) << 6) | (input[4] & 0x3F);
+		return 5;
+	}
+	else if((input[0] & 0xF0) == 0xF0)
+	{
+		result = ((input[0] & 0x07) << 18) | ((input[1] & 0x3F) << 12) | ((input[2] & 0x3F) << 6) | (input[3] & 0x3F);
+		return 4;
+	}
+	else if((input[0] & 0xE0) == 0xE0)
+	{
+		result = ((input[0] & 0x0F) << 12) | ((input[1] & 0x3F) << 6) | (input[2] & 0x3F);
+		return 3;
+	}
+	else if((input[0] & 0xC0) == 0xC0)
+	{
+		result = ((input[0] & 0x1F) << 6) | (input[1] & 0x3F);
+		return 2;
+	}
+	else
+	{
+		result = input[0];
+		return 1;
+	}
+}
+
+// return size of UTF-8 character, UB if input is nullptr
+inline unsigned char yUTF8GetCharacterSize(const char * input)
+{
+	if((input[0] & 0xFC) == 0xFC)
+		return 6;
+	else if((input[0] & 0xF8) == 0xF8)
+		return 5;
+	else if((input[0] & 0xF0) == 0xF0)
+		return 4;
+	else if((input[0] & 0xE0) == 0xE0)
+		return 3;
+	else if((input[0] & 0xC0) == 0xC0)
+		return 2;
+	else
+		return 1;
+}
+
+// return count of UTF8 characters in input, return 0 if input is nullptr
+inline ySize yUTF8GetLength(const char * input)
+{
+	if(!input)
+		return 0;
+
+	ySize result = 0;
+	while(*input != '\0')
+	{
+		input += yUTF8GetCharacterSize(input);
+		++result;
+	}
+	return result;
+}
+
+// ---------------------------------------------------------------------------------------------------------------- string
+
+class yStringContainer;
+
+// YASC string
+class yString
+{
+public:
+	// construct read-write string from pointer and owner
+	inline yString(char * stringData, yStringContainer * setOwner, ySize setSize, ySize setLength = 0, yHash setHash = 0)
+		:raw(stringData), rawReadOnly(stringData), owner(setOwner), size(setSize), length(setLength), hash(setHash)
+	{
+	}
+
+	// construct read only string from string literal
+	inline yString(const char * stringLiteral = nullptr)
+		:rawReadOnly(stringLiteral), raw(nullptr), owner(nullptr), size(0), length(0), hash(0)
+	{
+		if(rawReadOnly)
+		{
+			size = strlen(rawReadOnly);
+			length = yUTF8GetLength(rawReadOnly);
+		}
+	}
+
+	inline yString(const yString & other)
+		:rawReadOnly(other.rawReadOnly), raw(other.raw), owner(other.owner), size(other.size), hash(other.hash)
+	{
+	}
+
+	inline const char * c_str() const {return rawReadOnly;}
+
+	inline char * GetRaw() const {return raw;}
+	inline const char * GetRawRO() const {return rawReadOnly;}
+
+	inline void SetSize(ySize setSize) {size = setSize;}
+
+	// get size in bytes
+	inline ySize GetSize() const {return size;}
+
+	inline void SetLength(ySize setLength) {length = setLength;}
+
+	// get length in characters
+	inline ySize GetLength() const {return length;}
+
+	inline void PushHash() {++hash;}
+
+	// get string hash
+	inline yHash GetHash() const {return hash;}
+
+	inline bool IsEqual(const yString & other) const
+	{
+		if(rawReadOnly == other.rawReadOnly)
+		{
+			Y_ASSERT(owner == other.owner);
+			return hash == other.hash;
+		}
+		else if(rawReadOnly && other.rawReadOnly)
+			return !strcmp(rawReadOnly, other.rawReadOnly);
+		else if(!(rawReadOnly || other.rawReadOnly))
+			return true;
+		else
+			return false;
+	}
+
+	inline bool operator == (const yString & other) const {return IsEqual(other);}
+	inline bool operator != (const yString & other) const {return !IsEqual(other);}
+
+protected:
+	const char * rawReadOnly;
+	char * raw;
+
+	yStringContainer * owner;
+	ySize size;
+	ySize length;
+	yHash hash;
+};
+
+// ---------------------------------------------------------------------------------------------------------------- container
+
+class yStringContainer
+{
+public:
+	yStringContainer()
+		:pool(nullptr), poolSize(0), allocated(0)
+	{
+	}
+
+	// init container with size in bytes
+	yStringContainer(ySize size)
+		:pool(nullptr), poolSize(0), allocated(0)
+	{
+		Reserve(size);
+	}
+
+	~yStringContainer()
+	{
+		Clear();
+	}
+
+	void Reserve(ySize size)
+	{
+		Y_ASSERT(pool == nullptr);
+
+		pool = (char*)malloc(size);
+		poolSize = size;
+		allocated = 0;
+	}
+
+	void Clear()
+	{
+		if(pool == nullptr)
+			return;
+
+		free(pool);
+		pool = nullptr;
+		poolSize = 0;
+		allocated = 0;
+	}
+
+	inline yString Allocate(ySize size)
+	{
+		yString string(pool + allocated, this, size);
+		allocated += size;
+		return string;
+	}
+
+	// copy other string to this container, and return new string
+	inline yString Clone(const yString & string)
+	{
+		yString result = Allocate(string.GetSize());
+		result.SetLength(string.GetLength());
+		memcpy(result.GetRaw(), string.GetRawRO(), string.GetSize());
+		return result;
+	}
+
+	// return total pool size in bytes
+	inline ySize GetPoolSize() const {return poolSize;}
+
+	// return allocated size in bytes
+	inline ySize GetSize() const {return allocated;}
+
+protected:
+	char * pool;
+	ySize poolSize;
+	ySize allocated;
+};
+
+// ---------------------------------------------------------------------------------------------------------------- concate
+
+class yStringConcate
+{
+public:
+	inline yStringConcate()
+		:freePosition(0)
+	{
+	}
+
+	inline yStringConcate(const yString & buffer)
+		:string(buffer), freePosition(0)
+	{
+	}
+
+	inline void SetBuffer(const yString & buffer)
+	{
+		string = buffer;
+		freePosition = 0;
+	}
+
+	inline yStringConcate & Add(const char * formatStr, ...)
+	{
+		Y_ASSERT((freePosition + 1) < string.GetSize());
+		va_list args;
+		va_start(args, formatStr);
+		#ifdef Y_SAFE_VSPRINTF
+			freePosition += vsprintf_s(string.GetRaw() + freePosition, string.GetSize() - freePosition, formatStr, args);
+		#else
+			freePosition += vsprintf(string.GetRaw() + freePosition, formatStr, args);
+		#endif
+		va_end(args);
+		Y_ASSERT((freePosition + 1) <= string.GetSize());
+		return *this;
+	}
+
+	inline yString BakeToString()
+	{
+		string.GetRaw()[freePosition++] = '\0';
+		string.PushHash();
+
+		yString result(string);
+		result.SetSize(freePosition);
+		result.SetLength(yUTF8GetLength(result.GetRawRO()));
+		freePosition = 0;
+
+		return result;
+	}
+
+private:
+	yStringConcate(const yStringConcate & other) {}
+
+protected:
+	yString string;
+	ySize freePosition;
+};
+
+#endif

File yasc.vcxproj

+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{46606D32-EB3B-4C19-9E1C-6F57E5ACA6C4}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>yasc</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <AdditionalIncludeDirectories>../include</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <AdditionalIncludeDirectories>../include</AdditionalIncludeDirectories>
+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClInclude Include="yasc.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="tests.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="readme.txt" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>