/***********************************************************************
THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY
DEVELOPER: Zihan Chen(vczh)
***********************************************************************/
#include "VlppOS.h"
#include "Vlpp.h"

/***********************************************************************
.\FILESYSTEM.LINUX.CPP
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/

#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>

#ifndef VCZH_GCC
static_assert(false, "Do not build this file for Windows applications.");
#endif

namespace vl
{
	namespace stream
	{
		extern Ptr<IFileStreamImpl>		CreateOSFileStreamImpl(const WString& fileName, FileStream::AccessRight accessRight);
	}

	namespace filesystem
	{
		using namespace collections;
		using namespace stream;

/***********************************************************************
LinuxFileSystemImpl
***********************************************************************/

		class LinuxFileSystemImpl : public feature_injection::FeatureImpl<IFileSystemImpl>
		{
		public:
			// FilePath operations implementation
			void Initialize(WString& fullPath) const override
			{
				{
					Array<wchar_t> buffer(fullPath.Length() + 1);
					wcscpy(&buffer[0], fullPath.Buffer());
					FilePath::NormalizeDelimiters(buffer);
					fullPath = &buffer[0];
				}

				if (fullPath.Length() == 0)
					fullPath = WString::Unmanaged(L"/");

				if (fullPath[0] != FilePath::Delimiter)
				{
					char buffer[PATH_MAX] = { 0 };
					getcwd(buffer, PATH_MAX);
					fullPath = atow(AString(buffer)) + WString::FromChar(FilePath::Delimiter) + fullPath;
				}

				{
					collections::List<WString> components;
					FilePath::GetPathComponents(fullPath, components);
					for (int i = 0; i < components.Count(); i++)
					{
						if (components[i] == L".")
						{
							components.RemoveAt(i);
							i--;
						}
						else if (components[i] == L"..")
						{
							if (i > 0)
							{
								components.RemoveAt(i);
								components.RemoveAt(i - 1);
								i -= 2;
							}
							else
							{
								throw ArgumentException(L"Illegal path.");
							}
						}
					}

					fullPath = FilePath::ComponentsToPath(components);
				}

				FilePath::TrimLastDelimiter(fullPath);
			}

			bool IsFile(const WString& fullPath) const override
			{
				struct stat info;
				AString path = wtoa(fullPath);
				int result = stat(path.Buffer(), &info);
				if(result != 0) return false;
				else return S_ISREG(info.st_mode);
			}

			bool IsFolder(const WString& fullPath) const override
			{
				struct stat info;
				AString path = wtoa(fullPath);
				int result = stat(path.Buffer(), &info);
				if(result != 0) return false;
				else return S_ISDIR(info.st_mode);
			}

			bool IsRoot(const WString& fullPath) const override
			{
				return fullPath == L"/";
			}

			WString GetRelativePathFor(const WString& fromPath, const WString& toPath) const override
			{
				if (fromPath.Length() == 0 || toPath.Length() == 0 || fromPath[0] != toPath[0])
				{
					return toPath;
				}

				collections::List<WString> srcComponents, tgtComponents, resultComponents;
				FilePath::GetPathComponents(IsFolder(fromPath) ? fromPath : FilePath(fromPath).GetFolder().GetFullPath(), srcComponents);
				FilePath::GetPathComponents(toPath, tgtComponents);

				int minLength = srcComponents.Count() <= tgtComponents.Count() ? srcComponents.Count() : tgtComponents.Count();
				int lastCommonComponent = 0;
				for (int i = 0; i < minLength; i++)
				{
					if (srcComponents[i] == tgtComponents[i])
					{
						lastCommonComponent = i;
					}
					else
						break;
				}

				for (int i = lastCommonComponent + 1; i < srcComponents.Count(); i++)
				{
					resultComponents.Add(L"..");
				}

				for (int i = lastCommonComponent + 1; i < tgtComponents.Count(); i++)
				{
					resultComponents.Add(tgtComponents[i]);
				}

				return FilePath::ComponentsToPath(resultComponents);
			}

			// File operations implementation
			bool FileDelete(const FilePath& filePath) const override
			{
				AString path = wtoa(filePath.GetFullPath());
				return unlink(path.Buffer()) == 0;
			}

			bool FileRename(const FilePath& filePath, const WString& newName) const override
			{
				AString oldFileName = wtoa(filePath.GetFullPath());
				AString newFileName = wtoa((filePath.GetFolder() / newName).GetFullPath());
				return rename(oldFileName.Buffer(), newFileName.Buffer()) == 0;
			}

			// Folder operations implementation
			bool GetFolders(const FilePath& folderPath, collections::List<Folder>& folders) const override
			{
				DIR *dir;
				AString searchPath = wtoa(folderPath.GetFullPath());

				if ((dir = opendir(searchPath.Buffer())) == NULL)
				{
					return false;
				}

				struct dirent* entry;
				while ((entry = readdir(dir)) != NULL)
				{
					WString childName = atow(AString(entry->d_name));
					FilePath childFullPath = folderPath / childName;
					if (childName != L"." && childName != L".." && childFullPath.IsFolder())
					{
						folders.Add(Folder(childFullPath));
					}
				}

				if (closedir(dir) != 0)
				{
					return false;
				}

				return true;
			}

			bool GetFiles(const FilePath& folderPath, collections::List<File>& files) const override
			{
				DIR* dir;
				AString searchPath = wtoa(folderPath.GetFullPath());

				if ((dir = opendir(searchPath.Buffer())) == NULL)
				{
					return false;
				}

				struct dirent* entry;
				while ((entry = readdir(dir)) != NULL)
				{
					FilePath childFullPath = folderPath / (atow(AString(entry->d_name)));
					if (childFullPath.IsFile())
					{
						files.Add(File(childFullPath));
					}
				}

				if (closedir(dir) != 0)
				{
					return false;
				}

				return true;
			}

			bool CreateFolder(const FilePath& folderPath) const override
			{
				AString path = wtoa(folderPath.GetFullPath());
				return mkdir(path.Buffer(), 0777) == 0;
			}

			bool DeleteFolder(const FilePath& folderPath) const override
			{
				AString path = wtoa(folderPath.GetFullPath());
				return rmdir(path.Buffer()) == 0;
			}

			bool FolderRename(const FilePath& folderPath, const WString& newName) const override
			{
				AString oldFileName = wtoa(folderPath.GetFullPath());
				AString newFileName = wtoa((folderPath.GetFolder() / newName).GetFullPath());
				return rename(oldFileName.Buffer(), newFileName.Buffer()) == 0;
			}

			Ptr<stream::IFileStreamImpl> GetFileStreamImpl(const WString& fileName, stream::FileStream::AccessRight accessRight) const override
			{
				return stream::CreateOSFileStreamImpl(fileName, accessRight);
			}
		};

/***********************************************************************
Global FileSystem Implementation
***********************************************************************/

		IFileSystemImpl* GetOSFileSystemImpl()
		{
			static LinuxFileSystemImpl osFileSystemImpl;
			return &osFileSystemImpl;
		}
	}
}


/***********************************************************************
.\LOCALE.LINUX.CPP
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/


#ifndef VCZH_GCC
static_assert(false, "Do not build this file for Windows applications.");
#endif

namespace vl
{
	ILocaleImpl* GetOSLocaleImpl()
	{
		static EnUsLocaleImpl linuxLocaleImpl;
		return &linuxLocaleImpl;
	}
}


/***********************************************************************
.\THREADING.LINUX.CPP
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/

#include <pthread.h>
#include <fcntl.h>
#include <semaphore.h>
#include <errno.h>
#if defined(__APPLE__) || defined(__APPLE_CC__)
#include <CoreFoundation/CoreFoundation.h>
#endif

#ifndef VCZH_GCC
static_assert(false, "Do not build this file for Windows applications.");
#endif

namespace vl
{
	using namespace threading_internal;
	using namespace collections;


/***********************************************************************
Thread
***********************************************************************/

	namespace threading_internal
	{
		struct ThreadData
		{
			pthread_t					id;
			EventObject					ev;
		};

		class ProceduredThread : public Thread
		{
		private:
			Thread::ThreadProcedure		procedure;
			void*						argument;
			bool						deleteAfterStopped;

		protected:
			void Run()
			{
				bool deleteAfterStopped = this->deleteAfterStopped;
				ThreadLocalStorage::FixStorages();
				try
				{
					procedure(this, argument);
					threadState=Thread::Stopped;
					internalData->ev.Signal();
					ThreadLocalStorage::ClearStorages();
				}
				catch (...)
				{
					ThreadLocalStorage::ClearStorages();
					throw;
				}
				if(deleteAfterStopped)
				{
					delete this;
				}
			}
		public:
			ProceduredThread(Thread::ThreadProcedure _procedure, void* _argument, bool _deleteAfterStopped)
				:procedure(_procedure)
				,argument(_argument)
				,deleteAfterStopped(_deleteAfterStopped)
			{
			}
		};

		class LambdaThread : public Thread
		{
		private:
			Func<void()>				procedure;
			bool						deleteAfterStopped;

		protected:
			void Run()
			{
				bool deleteAfterStopped = this->deleteAfterStopped;
				ThreadLocalStorage::FixStorages();
				try
				{
					procedure();
					threadState=Thread::Stopped;
					internalData->ev.Signal();
					ThreadLocalStorage::ClearStorages();
				}
				catch (...)
				{
					ThreadLocalStorage::ClearStorages();
					throw;
				}
				if(deleteAfterStopped)
				{
					delete this;
				}
			}
		public:
			LambdaThread(const Func<void()>& _procedure, bool _deleteAfterStopped)
				:procedure(_procedure)
				,deleteAfterStopped(_deleteAfterStopped)
			{
			}
		};
	}

	void InternalThreadProc(Thread* thread)
	{
		thread->Run();
	}

	void* InternalThreadProcWrapper(void* lpParameter)
	{
		InternalThreadProc((Thread*)lpParameter);
		return 0;
	}

	Thread::Thread()
	{
		internalData=new ThreadData;
		internalData->ev.CreateManualUnsignal(false);
		threadState=Thread::NotStarted;
	}

	Thread::~Thread()
	{
		if (internalData)
		{
			Stop();
			if (threadState!=Thread::NotStarted)
			{
				pthread_detach(internalData->id);
			}
			delete internalData;
		}
	}

	Thread* Thread::CreateAndStart(ThreadProcedure procedure, void* argument, bool deleteAfterStopped)
	{
		if(procedure)
		{
			Thread* thread=new ProceduredThread(procedure, argument, deleteAfterStopped);
			if(thread->Start())
			{
				return thread;
			}
			else
			{
				delete thread;
			}
		}
		return 0;
	}

	Thread* Thread::CreateAndStart(const Func<void()>& procedure, bool deleteAfterStopped)
	{
		Thread* thread=new LambdaThread(procedure, deleteAfterStopped);
		if(thread->Start())
		{
			return thread;
		}
		else
		{
			delete thread;
		}
		return 0;
	}

	void Thread::Sleep(vint ms)
	{
		if (ms >= 1000)
		{
			sleep(ms / 1000);
		}
		if (ms % 1000)
		{
			usleep((ms % 1000) * 1000);
		}
	}
	
	vint Thread::GetCPUCount()
	{
		return (vint)sysconf(_SC_NPROCESSORS_ONLN);
	}

	vint Thread::GetCurrentThreadId()
	{
		return (vint)::pthread_self();
	}

	bool Thread::Start()
	{
		if(threadState==Thread::NotStarted)
		{
			if(pthread_create(&internalData->id, nullptr, &InternalThreadProcWrapper, this)==0)
			{
				threadState=Thread::Running;
				return true;
			}
		}
		return false;
	}

	bool Thread::Wait()
	{
		return internalData->ev.Wait();
	}

	bool Thread::Stop()
	{
		if (threadState==Thread::Running)
		{
			if(pthread_cancel(internalData->id)==0)
			{
				threadState=Thread::Stopped;
				internalData->ev.Signal();
				return true;
			}
		}
		return false;
	}

	Thread::ThreadState Thread::GetState()
	{
		return threadState;
	}

/***********************************************************************
Mutex
***********************************************************************/

	namespace threading_internal
	{
		struct MutexData
		{
			Semaphore			sem;
		};
	};

	Mutex::Mutex()
	{
		internalData = new MutexData;
	}

	Mutex::~Mutex()
	{
		delete internalData;
	}

	bool Mutex::Create(bool owned, const WString& name)
	{
		return internalData->sem.Create(owned ? 0 : 1, 1, name);
	}

	bool Mutex::Open(bool inheritable, const WString& name)
	{
		return internalData->sem.Open(inheritable, name);
	}

	bool Mutex::Release()
	{
		return internalData->sem.Release();
	}

	bool Mutex::Wait()
	{
		return internalData->sem.Wait();
	}

/***********************************************************************
Semaphore
***********************************************************************/

	namespace threading_internal
	{
		struct SemaphoreData
		{
			sem_t			semUnnamed;
			sem_t*			semNamed = nullptr;
		};
	}

	Semaphore::Semaphore()
		:internalData(0)
	{
	}

	Semaphore::~Semaphore()
	{
		if (internalData)
		{
			if (internalData->semNamed)
			{
				sem_close(internalData->semNamed);
			}
			else
			{
				sem_destroy(&internalData->semUnnamed);
			}
			delete internalData;
		}
	}

	bool Semaphore::Create(vint initialCount, vint maxCount, const WString& name)
	{
		if (internalData) return false;
		if (initialCount > maxCount) return false;

		internalData = new SemaphoreData;
#if defined(__APPLE__)
        
		AString auuid;
		if(name.Length() == 0)
		{
			CFUUIDRef cfuuid = CFUUIDCreate(kCFAllocatorDefault);
			CFStringRef cfstr = CFUUIDCreateString(kCFAllocatorDefault, cfuuid);
			auuid = CFStringGetCStringPtr(cfstr, kCFStringEncodingASCII);

			CFRelease(cfstr);
			CFRelease(cfuuid);
		}
		auuid = auuid.Insert(0, "/");
		// OSX SEM_NAME_LENGTH = 31
		if(auuid.Length() >= 30)
			auuid = auuid.Sub(0, 30);
        
		if ((internalData->semNamed = sem_open(auuid.Buffer(), O_CREAT, O_RDWR, initialCount)) == SEM_FAILED)
		{
			delete internalData;
			internalData = 0;
			return false;
		}
        
#else
		if (name == L"")
		{
			if(sem_init(&internalData->semUnnamed, 0, (int)initialCount) == -1)
			{
				delete internalData;
				internalData = 0;
				return false;
			}
		}
		else
		{
			AString astr = wtoa(name);

			if ((internalData->semNamed = sem_open(astr.Buffer(), O_CREAT, 0777, initialCount)) == SEM_FAILED)
			{
				delete internalData;
				internalData = 0;
				return false;
			}
		}
#endif

		Release(initialCount);
		return true;
	}

	bool Semaphore::Open(bool inheritable, const WString& name)
	{
		if (internalData) return false;
		if (inheritable) return false;

		internalData = new SemaphoreData;
		if (!(internalData->semNamed = sem_open(wtoa(name).Buffer(), 0)))
		{
            delete internalData;
            internalData = 0;
			return false;
		}

		return true;
	}

	bool Semaphore::Release()
	{
		return Release(1);
	}

	vint Semaphore::Release(vint count)
	{
		for (vint i = 0; i < count; i++)
		{
			if (internalData->semNamed)
			{
				sem_post(internalData->semNamed);
			}
			else
			{
				sem_post(&internalData->semUnnamed);
			}
		}
		return true;
	}

	bool Semaphore::Wait()
	{
		if (internalData->semNamed)
		{
			return sem_wait(internalData->semNamed) == 0;
		}
		else
		{
			return sem_wait(&internalData->semUnnamed) == 0;
		}
	}

/***********************************************************************
EventObject
***********************************************************************/

	namespace threading_internal
	{
		struct EventData
		{
			bool				autoReset;
			volatile bool		signaled;
			CriticalSection		mutex;
			ConditionVariable	cond;
			atomic_vint			counter = 0;
		};
	}

	EventObject::EventObject()
	{
		internalData = nullptr;
	}

	EventObject::~EventObject()
	{
		if (internalData)
		{
			delete internalData;
		}
	}

	bool EventObject::CreateAutoUnsignal(bool signaled, const WString& name)
	{
		if (name!=L"") return false;
		if (internalData) return false;

		internalData = new EventData;
		internalData->autoReset = true;
		internalData->signaled = signaled;
		return true;
	}

	bool EventObject::CreateManualUnsignal(bool signaled, const WString& name)
	{
		if (name!=L"") return false;
		if (internalData) return false;

		internalData = new EventData;
		internalData->autoReset = false;
		internalData->signaled = signaled;
		return true;
	}

	bool EventObject::Signal()
	{
		if (!internalData) return false;

		internalData->mutex.Enter();
		internalData->signaled = true;
		if (internalData->counter)
		{
			if (internalData->autoReset)
			{
				internalData->cond.WakeOnePending();
				internalData->signaled = false;
			}
			else
			{
				internalData->cond.WakeAllPendings();
			}
		}
		internalData->mutex.Leave();
		return true;
	}

	bool EventObject::Unsignal()
	{
		if (!internalData) return false;

		internalData->mutex.Enter();
		internalData->signaled = false;
		internalData->mutex.Leave();
		return true;
	}

	bool EventObject::Wait()
	{
		if (!internalData) return false;

		internalData->mutex.Enter();
		if (internalData->signaled)
		{
			if (internalData->autoReset)
			{
				internalData->signaled = false;
			}
		}
		else
		{
			INCRC(&internalData->counter);
			internalData->cond.SleepWith(internalData->mutex);
			DECRC(&internalData->counter);
		}
		internalData->mutex.Leave();
		return true;
	}

/***********************************************************************
ThreadPoolLite
***********************************************************************/

	namespace threading_internal
	{
		struct ThreadPoolTask
		{
			Func<void()>			task;
			Ptr<ThreadPoolTask>		next;
		};

		struct ThreadPoolData
		{
			Semaphore				semaphore;
			EventObject				taskFinishEvent;
			Ptr<ThreadPoolTask>		taskBegin;
			Ptr<ThreadPoolTask>*	taskEnd = nullptr;
			volatile bool			stopping = false;
			List<Thread*>			taskThreads;
		};

		SpinLock					threadPoolLock;
		ThreadPoolData*				threadPoolData = nullptr;

		void ThreadPoolProc(Thread* thread, void* argument)
		{
			while (true)
			{
				Ptr<ThreadPoolTask> task;

				threadPoolData->semaphore.Wait();
				SPIN_LOCK(threadPoolLock)
				{
					if (threadPoolData->taskBegin)
					{
						task = threadPoolData->taskBegin;
						threadPoolData->taskBegin = task->next;
					}

					if (!threadPoolData->taskBegin)
					{
						threadPoolData->taskEnd = &threadPoolData->taskBegin;
						threadPoolData->taskFinishEvent.Signal();
					}
				}

				if (task)
				{
					ThreadLocalStorage::FixStorages();
					try
					{
						task->task();
						ThreadLocalStorage::ClearStorages();
					}
					catch (...)
					{
						ThreadLocalStorage::ClearStorages();
					}
				}
				else if (threadPoolData->stopping)
				{
					return;
				}
			}
		}

		bool ThreadPoolQueue(const Func<void()>& proc)
		{
			SPIN_LOCK(threadPoolLock)
			{
				if (!threadPoolData)
				{
					threadPoolData = new ThreadPoolData;
					threadPoolData->semaphore.Create(0, 65536);
					threadPoolData->taskFinishEvent.CreateManualUnsignal(false);
					threadPoolData->taskEnd = &threadPoolData->taskBegin;

					for (vint i = 0; i < Thread::GetCPUCount() * 4; i++)
					{
						threadPoolData->taskThreads.Add(Thread::CreateAndStart(&ThreadPoolProc, nullptr, false));
					}
				}

				if (threadPoolData)
				{
					if (threadPoolData->stopping)
					{
						return false;
					}

					auto task = Ptr(new ThreadPoolTask);
					task->task = proc;
					*threadPoolData->taskEnd = task;
					threadPoolData->taskEnd = &task->next;
					threadPoolData->semaphore.Release();
					threadPoolData->taskFinishEvent.Unsignal();
				}
			}
			return true;
		}

		bool ThreadPoolStop(bool discardPendingTasks)
		{
			SPIN_LOCK(threadPoolLock)
			{
				if (!threadPoolData) return false;
				if (threadPoolData->stopping) return false;

				threadPoolData->stopping = true;
				if (discardPendingTasks)
				{
					threadPoolData->taskEnd = &threadPoolData->taskBegin;
					threadPoolData->taskBegin = nullptr;
				}

				threadPoolData->semaphore.Release(threadPoolData->taskThreads.Count());
			}

			threadPoolData->taskFinishEvent.Wait();
			// TODO: (enumerable) foreach
			for (vint i = 0; i < threadPoolData->taskThreads.Count(); i++)
			{
				auto thread = threadPoolData->taskThreads[i];
				thread->Wait();
				delete thread;
			}
			threadPoolData->taskThreads.Clear();

			SPIN_LOCK(threadPoolLock)
			{
				delete threadPoolData;
				threadPoolData = nullptr;
			}
			return true;
		}
	}

	ThreadPoolLite::ThreadPoolLite()
	{
	}

	ThreadPoolLite::~ThreadPoolLite()
	{
	}

	bool ThreadPoolLite::Queue(void(*proc)(void*), void* argument)
	{
		return ThreadPoolQueue([proc, argument](){proc(argument);});
	}

	bool ThreadPoolLite::Queue(const Func<void()>& proc)
	{
		return ThreadPoolQueue(proc);
	}

	bool ThreadPoolLite::Stop(bool discardPendingTasks)
	{
		return ThreadPoolStop(discardPendingTasks);
	}

/***********************************************************************
CriticalSection
***********************************************************************/

	namespace threading_internal
	{
		struct CriticalSectionData
		{
			pthread_mutex_t		mutex;
		};
	}

	CriticalSection::CriticalSection()
	{
		internalData = new CriticalSectionData;
		pthread_mutex_init(&internalData->mutex, nullptr);
	}

	CriticalSection::~CriticalSection()
	{
		pthread_mutex_destroy(&internalData->mutex);
		delete internalData;
	}

	bool CriticalSection::TryEnter()
	{
		return pthread_mutex_trylock(&internalData->mutex) == 0;
	}

	void CriticalSection::Enter()
	{
		pthread_mutex_lock(&internalData->mutex);
	}

	void CriticalSection::Leave()
	{
		pthread_mutex_unlock(&internalData->mutex);
	}

	CriticalSection::Scope::Scope(CriticalSection& _criticalSection)
		:criticalSection(&_criticalSection)
	{
		criticalSection->Enter();
	}

	CriticalSection::Scope::~Scope()
	{
		criticalSection->Leave();
	}

/***********************************************************************
ReaderWriterLock
***********************************************************************/

	namespace threading_internal
	{
		struct ReaderWriterLockData
		{
			pthread_rwlock_t			rwlock;
		};
	}

	ReaderWriterLock::ReaderWriterLock()
	{
		internalData = new ReaderWriterLockData;
		pthread_rwlock_init(&internalData->rwlock, nullptr);
	}

	ReaderWriterLock::~ReaderWriterLock()
	{
		pthread_rwlock_destroy(&internalData->rwlock);
		delete internalData;
	}

	bool ReaderWriterLock::TryEnterReader()
	{
		return pthread_rwlock_tryrdlock(&internalData->rwlock) == 0;
	}

	void ReaderWriterLock::EnterReader()
	{
		pthread_rwlock_rdlock(&internalData->rwlock);
	}

	void ReaderWriterLock::LeaveReader()
	{
		pthread_rwlock_unlock(&internalData->rwlock);
	}

	bool ReaderWriterLock::TryEnterWriter()
	{
		return pthread_rwlock_trywrlock(&internalData->rwlock) == 0;
	}

	void ReaderWriterLock::EnterWriter()
	{
		pthread_rwlock_wrlock(&internalData->rwlock);
	}

	void ReaderWriterLock::LeaveWriter()
	{
		pthread_rwlock_unlock(&internalData->rwlock);
	}

	ReaderWriterLock::ReaderScope::ReaderScope(ReaderWriterLock& _lock)
		:lock(&_lock)
	{
		lock->EnterReader();
	}

	ReaderWriterLock::ReaderScope::~ReaderScope()
	{
		lock->LeaveReader();
	}

	ReaderWriterLock::WriterScope::WriterScope(ReaderWriterLock& _lock)
		:lock(&_lock)
	{
		lock->EnterWriter();
	}

	ReaderWriterLock::WriterScope::~WriterScope()
	{
		lock->LeaveReader();
	}

/***********************************************************************
ConditionVariable
***********************************************************************/

	namespace threading_internal
	{
		struct ConditionVariableData
		{
			pthread_cond_t			cond;
		};
	}

	ConditionVariable::ConditionVariable()
	{
		internalData = new ConditionVariableData;
		pthread_cond_init(&internalData->cond, nullptr);
	}

	ConditionVariable::~ConditionVariable()
	{
		pthread_cond_destroy(&internalData->cond);
		delete internalData;
	}

	bool ConditionVariable::SleepWith(CriticalSection& cs)
	{
		return pthread_cond_wait(&internalData->cond, &cs.internalData->mutex) == 0;
	}

	void ConditionVariable::WakeOnePending()
	{
		pthread_cond_signal(&internalData->cond);
	}

	void ConditionVariable::WakeAllPendings()
	{
		pthread_cond_broadcast(&internalData->cond);
	}

/***********************************************************************
ThreadLocalStorage
***********************************************************************/

#define KEY ((pthread_key_t&)key)

	ThreadLocalStorage::ThreadLocalStorage(Destructor _destructor)
		:destructor(_destructor)
	{
		static_assert(sizeof(key) >= sizeof(pthread_key_t), "ThreadLocalStorage's key storage is not large enouth.");
		PushStorage(this);
		auto error = pthread_key_create(&KEY, destructor);
		CHECK_ERROR(error != EAGAIN && error != ENOMEM, L"vl::ThreadLocalStorage::ThreadLocalStorage()#Failed to create a thread local storage index.");
	}

	ThreadLocalStorage::~ThreadLocalStorage()
	{
		pthread_key_delete(KEY);
	}

	void* ThreadLocalStorage::Get()
	{
		CHECK_ERROR(!disposed, L"vl::ThreadLocalStorage::Get()#Cannot access a disposed ThreadLocalStorage.");
		return pthread_getspecific(KEY);
	}

	void ThreadLocalStorage::Set(void* data)
	{
		CHECK_ERROR(!disposed, L"vl::ThreadLocalStorage::Set()#Cannot access a disposed ThreadLocalStorage.");
		pthread_setspecific(KEY, data);
	}

#undef KEY
}


/***********************************************************************
.\ENCODING\CHARFORMAT\CHARFORMAT.LINUX.CPP
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/

#include <string.h>

#ifndef VCZH_GCC
static_assert(false, "Do not build this file for Windows applications.");
#endif

namespace vl
{
	namespace stream
	{
		using namespace vl::encoding;

		bool IsMbcsLeadByte(char c)
		{
			return (vint8_t)c < 0;
		}

		void MbcsToWChar(wchar_t* wideBuffer, vint wideChars, vint wideReaded, char* mbcsBuffer, vint mbcsChars)
		{
			AString a = AString::CopyFrom(mbcsBuffer, mbcsChars);
			WString w = atow(a);
			memcpy(wideBuffer, w.Buffer(), wideReaded * sizeof(wchar_t));
		}

/***********************************************************************
MbcsEncoder
***********************************************************************/

		vint MbcsEncoder::WriteString(wchar_t* _buffer, vint chars)
		{
			WString w = WString::CopyFrom(_buffer, chars);
			AString a = wtoa(w);
			vint length = a.Length();
			vint result = stream->Write((void*)a.Buffer(), length);

			if (result != length)
			{
				Close();
				return 0;
			}
			return chars;
		}

/***********************************************************************
Helper Functions
***********************************************************************/

		extern bool CanBeMbcs(unsigned char* buffer, vint size);
		extern bool CanBeUtf8(unsigned char* buffer, vint size);
		extern bool CanBeUtf16(unsigned char* buffer, vint size, bool& hitSurrogatePairs);
		extern bool CanBeUtf16BE(unsigned char* buffer, vint size, bool& hitSurrogatePairs);
		
/***********************************************************************
TestEncoding
***********************************************************************/

		extern void TestEncodingInternal(
			unsigned char* buffer,
			vint size,
			BomEncoder::Encoding& encoding,
			bool containsBom,
			bool utf16HitSurrogatePairs,
			bool utf16BEHitSurrogatePairs,
			bool roughMbcs,
			bool roughUtf8,
			bool roughUtf16,
			bool roughUtf16BE
			)
		{
			if (roughUtf16 && roughUtf16BE && !roughUtf8)
			{
				if (utf16BEHitSurrogatePairs && !utf16HitSurrogatePairs)
				{
					encoding = BomEncoder::Utf16BE;
				}
				else
				{
					encoding = BomEncoder::Utf16;
				}
			}
			else
			{
				encoding = BomEncoder::Utf8;
			}
		}
	}
}

