String.cpp #2

  • //
  • guest/
  • brandon_m_bare/
  • Sprawl/
  • brandon_m_bare/
  • string/
  • String.cpp
  • View
  • Commits
  • Open Download .zip Download (9 KB)
#include "String.hpp"
#include "../memory/PoolAllocator.hpp"
#include <stdint.h>

#ifdef _WIN32
#	pragma warning(disable: 4351)
#endif

namespace sprawl
{
	String::Holder::Holder()
		: m_staticData()
		, m_dynamicData(nullptr)
		, m_data(nullptr)
		, m_refCount(1)
		, m_length(0)
		, m_hash(0)
		, m_hashComputed(false)
	{
		//
	}

	String::Holder::Holder(const char* data)
		: m_staticData()
		, m_dynamicData(nullptr)
		, m_data(nullptr)
		, m_refCount(1)
		, m_length(strlen(data))
		, m_hash(0)
		, m_hashComputed(false)
	{
		if( m_length < staticDataSize )
		{
			memcpy(m_staticData, data, m_length);
			m_staticData[m_length] = '\0';
			m_data = m_staticData;
		}
		else
		{
			m_dynamicData = new char[m_length+1];
			memcpy(m_dynamicData, data, m_length);
			m_dynamicData[m_length] = '\0';
			m_data = m_dynamicData;
		}
	}

	String::Holder::Holder(const char* data, size_t length)
		: m_staticData()
		, m_dynamicData(nullptr)
		, m_data(nullptr)
		, m_refCount(1)
		, m_length(length)
		, m_hash(0)
		, m_hashComputed(false)
	{
		if( m_length < staticDataSize )
		{
			memcpy(m_staticData, data, m_length);
			m_staticData[m_length] = '\0';
			m_data = m_staticData;
		}
		else
		{
			m_dynamicData = new char[m_length+1];
			memcpy(m_dynamicData, data, m_length);
			m_dynamicData[m_length] = '\0';
			m_data = m_dynamicData;
		}
	}

	String::Holder::Holder(StringLiteral const& literal)
		: m_staticData()
		, m_dynamicData(nullptr)
		, m_data(literal.m_ptr)
		, m_refCount(1)
		, m_length(literal.m_length)
		, m_hash(0)
		, m_hashComputed(false)
	{
		//
	}

	void String::Holder::IncRef()
	{
		++m_refCount;
	}

	bool String::Holder::DecRef()
	{
		return (--m_refCount == 0);
	}

	String::Holder* String::Holder::CreateHolder()
	{
		typedef memory::PoolAllocator<sizeof(String::Holder)> holderAlloc;

		String::Holder* ret = (String::Holder*)holderAlloc::alloc();
		return ret;
	}

	void String::Holder::FreeHolder(Holder* holder)
	{
		typedef memory::PoolAllocator<sizeof(String::Holder)> holderAlloc;

		holder->~Holder();
		holderAlloc::free(holder);
	}

	String::Holder::~Holder()
	{
		if(m_dynamicData)
		{
			delete[] m_dynamicData;
		}
	}

	/*static*/ String::Holder String::ms_emptyHolder(StringLiteral(""));

	String::String()
		: m_holder(&ms_emptyHolder)
	{

	}

	String::String(const char* const data)
		: m_holder(Holder::CreateHolder())
	{
		new (m_holder) Holder(data);
	}

	String::String(const char* const data, size_t length)
		: m_holder(Holder::CreateHolder())
	{
		new (m_holder) Holder(data, length);
	}

	String::String(String const& other)
		: m_holder(other.m_holder)
	{
		if(m_holder != &ms_emptyHolder)
		{
			m_holder->IncRef();
		}
	}

	String::String(String&& other)
		: m_holder(other.m_holder)
	{
		//Don't change ref count here, it's staying the same because it's being *moved*
		other.m_holder = &ms_emptyHolder;
	}

	String::String(std::string const& stlString)
		: m_holder(Holder::CreateHolder())
	{
		new (m_holder) Holder(stlString.c_str(), stlString.length());
	}	

	String::String(StringLiteral const& stringLiteral)
		: m_holder(Holder::CreateHolder())
	{
		new (m_holder) Holder(stringLiteral);
	}

	String::~String()
	{
		if(m_holder != &ms_emptyHolder && m_holder->DecRef())
		{
			Holder::FreeHolder(m_holder);
		}
	}
	
	sprawl::String String::operator+(sprawl::String const& other) const
	{
		sprawl::String ret;
		ret.m_holder = Holder::CreateHolder();
		new (ret.m_holder) Holder();
		size_t fullLength = m_holder->m_length + other.m_holder->m_length;
		if(fullLength < Holder::staticDataSize)
		{
			memcpy(ret.m_holder->m_staticData, m_holder->m_data, m_holder->m_length);
			memcpy(ret.m_holder->m_staticData + m_holder->m_length, other.m_holder->m_data, other.m_holder->m_length);
			ret.m_holder->m_staticData[fullLength] = '\0';
			ret.m_holder->m_data = ret.m_holder->m_staticData;
		}
		else
		{
			ret.m_holder->m_dynamicData = new char[fullLength+1];
			memcpy(ret.m_holder->m_dynamicData, m_holder->m_data, m_holder->m_length);
			memcpy(ret.m_holder->m_dynamicData + m_holder->m_length, other.m_holder->m_data, other.m_holder->m_length);
			ret.m_holder->m_dynamicData[fullLength] = '\0';
			ret.m_holder->m_data = ret.m_holder->m_dynamicData;
		}
		ret.m_holder->m_length = fullLength;
		return std::move(ret);
	}

	sprawl::String String::operator+(const char* other) const
	{
		sprawl::String ret;
		ret.m_holder = Holder::CreateHolder();
		new (ret.m_holder) Holder();
		size_t length = strlen(other);
		size_t fullLength = m_holder->m_length + length;
		if(fullLength < Holder::staticDataSize)
		{
			memcpy(ret.m_holder->m_staticData, m_holder->m_data, m_holder->m_length);
			memcpy(ret.m_holder->m_staticData + m_holder->m_length, other, length);
			ret.m_holder->m_staticData[fullLength] = '\0';
			ret.m_holder->m_data = ret.m_holder->m_staticData;
		}
		else
		{
			ret.m_holder->m_dynamicData = new char[fullLength+1];
			memcpy(ret.m_holder->m_dynamicData, m_holder->m_data, m_holder->m_length);
			memcpy(ret.m_holder->m_dynamicData + m_holder->m_length, other, length);
			ret.m_holder->m_dynamicData[fullLength] = '\0';
			ret.m_holder->m_data = ret.m_holder->m_dynamicData;
		}
		ret.m_holder->m_length = fullLength;
		return std::move(ret);
	}

	sprawl::String& String::operator+=(sprawl::String const& other)
	{
		Holder* newHolder = Holder::CreateHolder();
		new (newHolder) Holder();

		size_t fullLength = m_holder->m_length + other.m_holder->m_length;
		if(fullLength < Holder::staticDataSize)
		{
			memcpy(newHolder->m_staticData, m_holder->m_data, m_holder->m_length);
			memcpy(newHolder->m_staticData + m_holder->m_length, other.m_holder->m_data, other.m_holder->m_length);
			newHolder->m_staticData[fullLength] = '\0';
			newHolder->m_data = newHolder->m_staticData;
		}
		else
		{
			newHolder->m_dynamicData = new char[fullLength+1];
			memcpy(newHolder->m_dynamicData, m_holder->m_data, m_holder->m_length);
			memcpy(newHolder->m_dynamicData + m_holder->m_length, other.m_holder->m_data, other.m_holder->m_length);
			newHolder->m_dynamicData[fullLength] = '\0';
			newHolder->m_data = newHolder->m_dynamicData;
		}
		newHolder->m_length = fullLength;
		Holder::FreeHolder(m_holder);
		m_holder = newHolder;
		return *this;
	}

	sprawl::String& String::operator+=(const char* other)
	{
		Holder* newHolder = Holder::CreateHolder();
		new (newHolder) Holder();
		size_t length = strlen(other);
		size_t fullLength = m_holder->m_length + length;

		if(fullLength < Holder::staticDataSize)
		{
			memcpy(newHolder->m_staticData, m_holder->m_data, m_holder->m_length);
			memcpy(newHolder->m_staticData + m_holder->m_length, other, length);
			newHolder->m_staticData[fullLength] = '\0';
			newHolder->m_data = newHolder->m_staticData;
		}
		else
		{
			newHolder->m_dynamicData = new char[fullLength+1];
			memcpy(newHolder->m_dynamicData, m_holder->m_data, m_holder->m_length);
			memcpy(newHolder->m_dynamicData + m_holder->m_length, other, length);
			newHolder->m_dynamicData[fullLength] = '\0';
			newHolder->m_data = newHolder->m_dynamicData;
		}
		newHolder->m_length = fullLength;
		Holder::FreeHolder(m_holder);
		m_holder = newHolder;
		return *this;
	}
	
	String& String::operator=(String const& other)
	{
		if(m_holder != &ms_emptyHolder && m_holder->DecRef())
		{
			Holder::FreeHolder(m_holder);
		}

		m_holder = other.m_holder;

		if(m_holder != &ms_emptyHolder)
		{
			m_holder->IncRef();
		}
		return *this;
	}

	String& String::operator=(String&& other)
	{
		if(m_holder != &ms_emptyHolder && m_holder->DecRef())
		{
			Holder::FreeHolder(m_holder);
		}

		m_holder = other.m_holder;
		other.m_holder = &ms_emptyHolder;

		return *this;
	}
	
	bool String::operator<(String const& other) const
	{
		if(m_holder == other.m_holder)
		{
			return false;
		}
		if(m_holder == &ms_emptyHolder)
		{
			return false;
		}
		if(other.m_holder == &ms_emptyHolder)
		{
			return true;
		}
		size_t length = other.m_holder->m_length < m_holder->m_length ? other.m_holder->m_length : m_holder->m_length;
		const char* const left = m_holder->m_data;
		const char* const right = other.m_holder->m_data;
		for(size_t i = 0; i < length; ++i)
		{
			if(left[i] == right[i])
				continue;

			return left[i] < right[i];
		}
		return m_holder->m_length < other.m_holder->m_length;
	}

	String String::GetOwned() const
	{
		if (m_holder->m_data == m_holder->m_dynamicData || m_holder->m_data == m_holder->m_staticData)
		{
			return *this;
		}
		return String(m_holder->m_data, m_holder->m_length);
	}

	std::string String::toStdString() const
	{
		if(m_holder == &ms_emptyHolder)
		{
			static std::string emptyStr;
			return emptyStr;
		}
		return std::string(m_holder->m_data, m_holder->m_length);
	}
}
# Change User Description Committed
#2 18645 brandon_m_bare Integrated latest version of libsprawl.
#1 15089 brandon_m_bare First integration of sprawl.
//guest/ShadauxCat/Sprawl/Mainline/string/String.cpp
#4 14816 ShadauxCat Filled in some more filesystem functions, added appropriate unit tests.
Only a few remain.

#review-14817
#3 14783 ShadauxCat Style corrections (placement of const)

#review-14784
#2 14216 ShadauxCat -Moved some global sprawl::Strings into local scope in json serialization test because of initialization order issues in the memory allocator on mac.
This is a temporary fix, and a real fix will come by making the pool allocator work in explicitly-sized pieces and putting all the code for those pieces into a cpp file.
-Fixed a large number of warnings on mac/linux that were exposed by fixes to csbuild
-Fixed compile errors on mac due to malloc and alloca not being defined, fixed by #include <stdlib.h> in appropriate places
-Fixed mac os x trying to link against pthread erroneously
-Provided os x implementation of time library
-Fixed compile errors on os x due to std::unordered_map whining about the difference between an allocator that allocates std::pair<key, value> and one that allocates std::pair<key const, value>, which, of course, is that the allocator will be no different at all.
-Fixed an actual issue where one unordered_map was allocating only key_type instead of std::pair<key_type, value_type>
-Fixed a memory leak where coroutine objects would never be cleaned up because either Yield() or reactivate_() will never return (and thus never clean up their stack memory and thus never release any dynamic memory held in stack objects) depending on the situation - if the function runs to completion, reactivate_() never returns after calling swapcontext(); meanwhile, if the function does not run to completion, Yield() never returns after calling Pause(). This behavior will need to be well-documented because it will affect client-side code as well. Stack memory within a coroutine should not rely on RAII behavior.
-Fixed compile failure when creating a StlWrapper with a const value_type

#review-14217
#1 11496 ShadauxCat Initial checkin: Current states for csbuild and libSprawl