deleting old files (either renamed or part of crn_threading_win32.cpp, etc.)
This commit is contained in:
@@ -1,431 +0,0 @@
|
||||
// File: crn_condition_var.cpp
|
||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
||||
#include "crn_core.h"
|
||||
#include "crn_condition_var.h"
|
||||
#include "crn_spinlock.h"
|
||||
#include "crn_winhdr.h"
|
||||
|
||||
namespace crnlib
|
||||
{
|
||||
void spinlock::lock(uint32 max_spins, bool yielding, bool memoryBarrier)
|
||||
{
|
||||
if (g_number_of_processors <= 1)
|
||||
max_spins = 1;
|
||||
|
||||
uint32 spinCount = 0;
|
||||
uint32 yieldCount = 0;
|
||||
|
||||
for ( ; ; )
|
||||
{
|
||||
CRNLIB_ASSUME(sizeof(long) == sizeof(int32));
|
||||
if (!InterlockedExchange((volatile long*)&m_flag, TRUE))
|
||||
break;
|
||||
|
||||
YieldProcessor();
|
||||
YieldProcessor();
|
||||
YieldProcessor();
|
||||
YieldProcessor();
|
||||
YieldProcessor();
|
||||
YieldProcessor();
|
||||
YieldProcessor();
|
||||
YieldProcessor();
|
||||
|
||||
spinCount++;
|
||||
if ((yielding) && (spinCount >= max_spins))
|
||||
{
|
||||
switch (yieldCount)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
spinCount = 0;
|
||||
|
||||
Sleep(0);
|
||||
|
||||
yieldCount++;
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
if (g_number_of_processors <= 1)
|
||||
spinCount = 0;
|
||||
else
|
||||
spinCount = max_spins / 2;
|
||||
|
||||
Sleep(1);
|
||||
|
||||
yieldCount++;
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
if (g_number_of_processors <= 1)
|
||||
spinCount = 0;
|
||||
else
|
||||
spinCount = max_spins;
|
||||
|
||||
Sleep(2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (memoryBarrier)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
MemoryBarrier();
|
||||
#elif defined(__MINGW32__) && defined(__MINGW64__)
|
||||
__sync_synchronize();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void spinlock::unlock()
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
MemoryBarrier();
|
||||
#elif defined(__MINGW32__) && defined(__MINGW64__)
|
||||
__sync_synchronize();
|
||||
#endif
|
||||
|
||||
m_flag = FALSE;
|
||||
}
|
||||
|
||||
mutex::mutex(unsigned int spin_count)
|
||||
{
|
||||
CRNLIB_ASSUME(sizeof(mutex) >= sizeof(CRITICAL_SECTION));
|
||||
|
||||
void *p = m_buf;
|
||||
CRITICAL_SECTION &m_cs = *static_cast<CRITICAL_SECTION *>(p);
|
||||
|
||||
BOOL status = true;
|
||||
#ifdef _XBOX
|
||||
InitializeCriticalSectionAndSpinCount(&m_cs, spin_count);
|
||||
#else
|
||||
status = InitializeCriticalSectionAndSpinCount(&m_cs, spin_count);
|
||||
#endif
|
||||
if (!status)
|
||||
crnlib_fail("mutex::mutex: InitializeCriticalSectionAndSpinCount failed", __FILE__, __LINE__);
|
||||
|
||||
#ifdef CRNLIB_BUILD_DEBUG
|
||||
m_lock_count = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
mutex::~mutex()
|
||||
{
|
||||
void *p = m_buf;
|
||||
CRITICAL_SECTION &m_cs = *static_cast<CRITICAL_SECTION *>(p);
|
||||
|
||||
#ifdef CRNLIB_BUILD_DEBUG
|
||||
if (m_lock_count)
|
||||
crnlib_assert("mutex::~mutex: mutex is still locked", __FILE__, __LINE__);
|
||||
#endif
|
||||
DeleteCriticalSection(&m_cs);
|
||||
}
|
||||
|
||||
void mutex::lock()
|
||||
{
|
||||
void *p = m_buf;
|
||||
CRITICAL_SECTION &m_cs = *static_cast<CRITICAL_SECTION *>(p);
|
||||
|
||||
EnterCriticalSection(&m_cs);
|
||||
#ifdef CRNLIB_BUILD_DEBUG
|
||||
m_lock_count++;
|
||||
#endif
|
||||
}
|
||||
|
||||
void mutex::unlock()
|
||||
{
|
||||
void *p = m_buf;
|
||||
CRITICAL_SECTION &m_cs = *static_cast<CRITICAL_SECTION *>(p);
|
||||
|
||||
#ifdef CRNLIB_BUILD_DEBUG
|
||||
if (!m_lock_count)
|
||||
crnlib_assert("mutex::unlock: mutex is not locked", __FILE__, __LINE__);
|
||||
m_lock_count--;
|
||||
#endif
|
||||
LeaveCriticalSection(&m_cs);
|
||||
}
|
||||
|
||||
void mutex::set_spin_count(unsigned int count)
|
||||
{
|
||||
void *p = m_buf;
|
||||
CRITICAL_SECTION &m_cs = *static_cast<CRITICAL_SECTION *>(p);
|
||||
|
||||
SetCriticalSectionSpinCount(&m_cs, count);
|
||||
}
|
||||
|
||||
semaphore::semaphore(int32 initialCount, int32 maximumCount, const char* pName)
|
||||
{
|
||||
m_handle = CreateSemaphoreA(NULL, initialCount, maximumCount, pName);
|
||||
if (NULL == m_handle)
|
||||
{
|
||||
CRNLIB_FAIL("semaphore: CreateSemaphore() failed");
|
||||
}
|
||||
}
|
||||
|
||||
semaphore::~semaphore()
|
||||
{
|
||||
if (m_handle)
|
||||
{
|
||||
CloseHandle(m_handle);
|
||||
m_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void semaphore::release(int32 releaseCount, int32 *pPreviousCount)
|
||||
{
|
||||
CRNLIB_ASSUME(sizeof(LONG) == sizeof(int32));
|
||||
if (0 == ReleaseSemaphore(m_handle, releaseCount, (LPLONG)pPreviousCount))
|
||||
{
|
||||
CRNLIB_FAIL("semaphore: ReleaseSemaphore() failed");
|
||||
}
|
||||
}
|
||||
|
||||
bool semaphore::wait(uint32 milliseconds)
|
||||
{
|
||||
uint32 result = WaitForSingleObject(m_handle, milliseconds);
|
||||
|
||||
if (WAIT_FAILED == result)
|
||||
{
|
||||
CRNLIB_FAIL("semaphore: WaitForSingleObject() failed");
|
||||
}
|
||||
|
||||
return WAIT_OBJECT_0 == result;
|
||||
}
|
||||
|
||||
event::event(bool manual_reset, bool initial_state, const char* pName)
|
||||
{
|
||||
m_handle = CreateEventA(NULL, manual_reset, initial_state, pName);
|
||||
|
||||
if (NULL == m_handle)
|
||||
CRNLIB_FAIL("event: CreateEvent() failed");
|
||||
}
|
||||
|
||||
event::~event()
|
||||
{
|
||||
if (m_handle)
|
||||
{
|
||||
CloseHandle(m_handle);
|
||||
m_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void event::set(void)
|
||||
{
|
||||
SetEvent(m_handle);
|
||||
}
|
||||
|
||||
void event::reset(void)
|
||||
{
|
||||
ResetEvent(m_handle);
|
||||
}
|
||||
|
||||
void event::pulse(void)
|
||||
{
|
||||
PulseEvent(m_handle);
|
||||
}
|
||||
|
||||
bool event::wait(uint32 milliseconds)
|
||||
{
|
||||
uint32 result = WaitForSingleObject(m_handle, milliseconds);
|
||||
|
||||
if (result == WAIT_FAILED)
|
||||
{
|
||||
CRNLIB_FAIL("event: WaitForSingleObject() failed");
|
||||
}
|
||||
|
||||
return (result == WAIT_OBJECT_0);
|
||||
}
|
||||
|
||||
condition_var::condition_var(uint spin_count) :
|
||||
m_condition_var_lock(1, 1),
|
||||
m_tls(TlsAlloc()),
|
||||
m_cur_age(0),
|
||||
m_max_waiter_array_index(-1)
|
||||
{
|
||||
CRNLIB_ASSERT(TLS_OUT_OF_INDEXES != m_tls);
|
||||
|
||||
m_waiters_array_lock.set_spin_count(spin_count);
|
||||
|
||||
m_waiters_array_lock.lock();
|
||||
|
||||
for (uint i = 0; i < cMaxWaitingThreads; i++)
|
||||
m_waiters[i].clear();
|
||||
|
||||
m_waiters_array_lock.unlock();
|
||||
}
|
||||
|
||||
condition_var::~condition_var()
|
||||
{
|
||||
TlsFree(m_tls);
|
||||
}
|
||||
|
||||
void condition_var::lock()
|
||||
{
|
||||
uint32 cur_count = get_cur_lock_count();
|
||||
CRNLIB_ASSERT(cur_count != 0xFFFFFFFF);
|
||||
cur_count++;
|
||||
set_cur_lock_count(cur_count);
|
||||
|
||||
if (1 == cur_count)
|
||||
m_condition_var_lock.wait();
|
||||
}
|
||||
|
||||
void condition_var::unlock()
|
||||
{
|
||||
uint32 cur_count = get_cur_lock_count();
|
||||
CRNLIB_ASSERT(cur_count);
|
||||
cur_count--;
|
||||
set_cur_lock_count(cur_count);
|
||||
|
||||
if (!cur_count)
|
||||
leave_and_scan();
|
||||
}
|
||||
|
||||
void condition_var::leave_and_scan(int index_to_ignore)
|
||||
{
|
||||
m_waiters_array_lock.lock();
|
||||
|
||||
uint best_age = 0;
|
||||
int best_index = -1;
|
||||
for (int i = 0; i <= m_max_waiter_array_index; i++)
|
||||
{
|
||||
waiting_thread& waiter = m_waiters[i];
|
||||
|
||||
if ((i != index_to_ignore) && (waiter.m_occupied) && (!waiter.m_satisfied))
|
||||
{
|
||||
uint age = m_cur_age - waiter.m_age;
|
||||
|
||||
if ((age > best_age) || (best_index < 0))
|
||||
{
|
||||
if ((!waiter.m_callback_func) || (waiter.m_callback_func(waiter.m_pCallback_ptr, waiter.m_callback_data)))
|
||||
{
|
||||
best_age = age;
|
||||
best_index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (best_index >= 0)
|
||||
{
|
||||
waiting_thread& waiter = m_waiters[best_index];
|
||||
waiter.m_satisfied = true;
|
||||
waiter.m_event.set();
|
||||
m_waiters_array_lock.unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_waiters_array_lock.unlock();
|
||||
m_condition_var_lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
uint32 condition_var::get_cur_lock_count() const
|
||||
{
|
||||
return (uint32)((intptr_t)TlsGetValue(m_tls));
|
||||
}
|
||||
|
||||
int condition_var::wait(
|
||||
pCondition_func pCallback, void* pCallback_data_ptr, uint64 callback_data,
|
||||
uint num_wait_handles, const void** pWait_handles, uint32 max_time_to_wait)
|
||||
{
|
||||
CRNLIB_ASSERT(get_cur_lock_count());
|
||||
|
||||
// First, see if the calling thread's condition function is satisfied. If so, there's no need to wait.
|
||||
if ((pCallback) && (pCallback(pCallback_data_ptr, callback_data)))
|
||||
return 0;
|
||||
|
||||
// Add this thread to the list of waiters.
|
||||
m_waiters_array_lock.lock();
|
||||
|
||||
uint i;
|
||||
for (i = 0; i < cMaxWaitingThreads; i++)
|
||||
if (!m_waiters[i].m_occupied)
|
||||
break;
|
||||
|
||||
CRNLIB_VERIFY(i != cMaxWaitingThreads);
|
||||
|
||||
m_max_waiter_array_index = math::maximum<int>(m_max_waiter_array_index, i);
|
||||
|
||||
waiting_thread& waiter = m_waiters[i];
|
||||
|
||||
waiter.m_callback_func = pCallback;
|
||||
waiter.m_pCallback_ptr = pCallback_data_ptr;
|
||||
waiter.m_callback_data = callback_data;
|
||||
waiter.m_satisfied = false;
|
||||
waiter.m_occupied = true;
|
||||
waiter.m_age = m_cur_age++;
|
||||
waiter.m_event.reset();
|
||||
|
||||
m_waiters_array_lock.unlock();
|
||||
|
||||
// Now leave the condition_var and scan to see if there are any satisfied waiters.
|
||||
leave_and_scan(i);
|
||||
|
||||
// Let's wait for this thread's condition to be satisfied, or until timeout, or until one of the user supplied handles is signaled.
|
||||
int return_index = 0;
|
||||
|
||||
const uint cMaxWaitHandles = 64;
|
||||
CRNLIB_ASSERT(num_wait_handles < cMaxWaitHandles);
|
||||
|
||||
HANDLE handles[cMaxWaitHandles];
|
||||
|
||||
handles[0] = waiter.m_event.get_handle();
|
||||
uint total_handles = 1;
|
||||
|
||||
if (num_wait_handles)
|
||||
{
|
||||
CRNLIB_ASSERT(pWait_handles);
|
||||
memcpy(handles + total_handles, pWait_handles, sizeof(HANDLE) * num_wait_handles);
|
||||
total_handles += num_wait_handles;
|
||||
}
|
||||
|
||||
uint32 result;
|
||||
if (max_time_to_wait == UINT32_MAX)
|
||||
{
|
||||
do
|
||||
{
|
||||
result = WaitForMultipleObjects(total_handles, handles, FALSE, 2000);
|
||||
} while (result == WAIT_TIMEOUT);
|
||||
}
|
||||
else
|
||||
result = WaitForMultipleObjects(total_handles, handles, FALSE, max_time_to_wait);
|
||||
|
||||
if ((result == WAIT_ABANDONED) || (result == WAIT_TIMEOUT))
|
||||
return_index = -1;
|
||||
else
|
||||
return_index = result - WAIT_OBJECT_0;
|
||||
|
||||
// See if our condition was satisfied, and remove this thread from the waiter list.
|
||||
m_waiters_array_lock.lock();
|
||||
|
||||
const bool was_satisfied = waiter.m_satisfied;
|
||||
|
||||
waiter.m_occupied = false;
|
||||
|
||||
m_waiters_array_lock.unlock();
|
||||
|
||||
if (0 == return_index)
|
||||
{
|
||||
CRNLIB_ASSERT(was_satisfied);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Enter the condition_var if a user supplied handle was signaled. This guarantees that on exit of this function we're still inside the condition_var, no matter
|
||||
// what happened during the WaitForMultipleObjects() call.
|
||||
if (!was_satisfied)
|
||||
m_condition_var_lock.wait();
|
||||
}
|
||||
|
||||
return return_index;
|
||||
}
|
||||
|
||||
void condition_var::set_cur_lock_count(uint32 newCount)
|
||||
{
|
||||
TlsSetValue(m_tls, (void*)newCount);
|
||||
}
|
||||
|
||||
} // namespace crnlib
|
||||
@@ -1,91 +0,0 @@
|
||||
// File: crn_condition_var.h
|
||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
||||
// Inspired by the "monitor" class in "Win32 Multithreaded Programming" by Cohen and Woodring.
|
||||
// Also see http://en.wikipedia.org/wiki/Monitor_(synchronization)
|
||||
#pragma once
|
||||
|
||||
#include "crn_mutex.h"
|
||||
#include "crn_event.h"
|
||||
#include "crn_semaphore.h"
|
||||
|
||||
namespace crnlib
|
||||
{
|
||||
class condition_var
|
||||
{
|
||||
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(condition_var);
|
||||
|
||||
public:
|
||||
condition_var(uint spin_count = 4096U);
|
||||
~condition_var();
|
||||
|
||||
// Locks the condition_var.
|
||||
// Recursive locks are supported.
|
||||
void lock();
|
||||
|
||||
// Returns TRUE if the thread owning this condition function should stop waiting.
|
||||
// This function will always be called from within the condition_var, but it may be called from several different threads!
|
||||
typedef bool (*pCondition_func)(void* pCallback_data_ptr, uint64 callback_data);
|
||||
|
||||
// Temporarily leaves the lock and waits for a condition to be satisfied.
|
||||
// If pCallback is NULL, this method will return after another thread enters and exits the lock (like a Vista-style condition variable).
|
||||
// Otherwise, this method will only return when the specified condition function returns TRUE when another thread exits the lock.
|
||||
// When this method returns, the calling thread will be inside the lock.
|
||||
// Returns -1 on timeout or error, 0 if the wait was satisfied, or 1 or higher if one of the extra wait handles became signaled.
|
||||
// It is highly recommended you use a non-null condition callback. If you don't be sure to check for race conditions!
|
||||
int wait(pCondition_func pCallback = NULL, void* pCallback_data_ptr = NULL, uint64 callback_data = 0,
|
||||
uint num_wait_handles = 0, const void** pWait_handles = NULL, uint32 max_time_to_wait = UINT32_MAX);
|
||||
|
||||
// Unlocks the condition_var. Another thread may be woken up if its condition function has become satisfied.
|
||||
void unlock();
|
||||
|
||||
uint32 get_cur_lock_count() const;
|
||||
|
||||
private:
|
||||
enum { cMaxWaitingThreads = 16, cMaxWaitingThreadsMask = cMaxWaitingThreads - 1 };
|
||||
|
||||
semaphore m_condition_var_lock;
|
||||
mutex m_waiters_array_lock;
|
||||
uint32 m_tls;
|
||||
uint m_cur_age;
|
||||
|
||||
struct waiting_thread
|
||||
{
|
||||
uint64 m_callback_data;
|
||||
void* m_pCallback_ptr;
|
||||
pCondition_func m_callback_func;
|
||||
uint m_age;
|
||||
bool m_satisfied;
|
||||
bool m_occupied;
|
||||
|
||||
event m_event;
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_callback_data = 0;
|
||||
m_pCallback_ptr = NULL;
|
||||
m_callback_func = NULL;
|
||||
m_age = 0;
|
||||
m_satisfied = false;
|
||||
m_occupied = false;
|
||||
}
|
||||
};
|
||||
waiting_thread m_waiters[cMaxWaitingThreads];
|
||||
|
||||
int m_max_waiter_array_index;
|
||||
|
||||
void set_cur_lock_count(uint32 newCount);
|
||||
|
||||
void leave_and_scan(int index_to_ignore = -1);
|
||||
};
|
||||
|
||||
class scoped_condition_var
|
||||
{
|
||||
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(scoped_condition_var);
|
||||
public:
|
||||
inline scoped_condition_var(condition_var& m) : m_condition_var(m) { m_condition_var.lock(); }
|
||||
inline ~scoped_condition_var() { m_condition_var.unlock(); }
|
||||
private:
|
||||
condition_var& m_condition_var;
|
||||
};
|
||||
|
||||
} // namespace crnlib
|
||||
@@ -1,715 +0,0 @@
|
||||
// File: crn_dynamic_wstring.cpp
|
||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
||||
#include "crn_core.h"
|
||||
#include "crn_dynamic_wstring.h"
|
||||
#include "crn_winhdr.h"
|
||||
|
||||
namespace crnlib
|
||||
{
|
||||
dynamic_wstring g_empty_dynamic_wstring;
|
||||
|
||||
dynamic_wstring::dynamic_wstring(eVarArg dummy, const wchar_t* p, ...) :
|
||||
m_buf_size(0), m_len(0), m_pStr(NULL)
|
||||
{
|
||||
dummy;
|
||||
|
||||
CRNLIB_ASSERT(p);
|
||||
|
||||
va_list args;
|
||||
va_start(args, p);
|
||||
format_args(p, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
dynamic_wstring::dynamic_wstring(const wchar_t* p) :
|
||||
m_buf_size(0), m_len(0), m_pStr(NULL)
|
||||
{
|
||||
CRNLIB_ASSERT(p);
|
||||
set(p);
|
||||
}
|
||||
|
||||
dynamic_wstring::dynamic_wstring(const wchar_t* p, uint len) :
|
||||
m_buf_size(0), m_len(0), m_pStr(NULL)
|
||||
{
|
||||
CRNLIB_ASSERT(p);
|
||||
set_from_buf(p, len);
|
||||
}
|
||||
|
||||
dynamic_wstring::dynamic_wstring(const dynamic_wstring& other) :
|
||||
m_buf_size(0), m_len(0), m_pStr(NULL)
|
||||
{
|
||||
set(other);
|
||||
}
|
||||
|
||||
void dynamic_wstring::clear()
|
||||
{
|
||||
check();
|
||||
|
||||
if (m_pStr)
|
||||
{
|
||||
crnlib_delete_array(m_pStr);
|
||||
m_pStr = NULL;
|
||||
|
||||
m_len = 0;
|
||||
m_buf_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void dynamic_wstring::empty()
|
||||
{
|
||||
truncate(0);
|
||||
}
|
||||
|
||||
void dynamic_wstring::optimize()
|
||||
{
|
||||
if (!m_len)
|
||||
clear();
|
||||
else
|
||||
{
|
||||
uint min_buf_size = math::next_pow2((uint)m_len + 1);
|
||||
if (m_buf_size > min_buf_size)
|
||||
{
|
||||
wchar_t* p = crnlib_new_array<wchar_t>(min_buf_size);
|
||||
memcpy(p, m_pStr, (m_len + 1) * sizeof(wchar_t));
|
||||
|
||||
crnlib_delete_array(m_pStr);
|
||||
m_pStr = p;
|
||||
|
||||
m_buf_size = static_cast<uint16>(min_buf_size);
|
||||
|
||||
check();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int dynamic_wstring::compare(const wchar_t* p, bool case_sensitive) const
|
||||
{
|
||||
CRNLIB_ASSERT(p);
|
||||
|
||||
const int result = (case_sensitive ? wcscmp : _wcsicmp)(get_ptr_priv(), p);
|
||||
|
||||
if (result < 0)
|
||||
return -1;
|
||||
else if (result > 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dynamic_wstring::compare(const dynamic_wstring& rhs, bool case_sensitive) const
|
||||
{
|
||||
return compare(rhs.get_ptr_priv(), case_sensitive);
|
||||
}
|
||||
|
||||
dynamic_wstring& dynamic_wstring::set(const wchar_t* p, uint max_len)
|
||||
{
|
||||
CRNLIB_ASSERT(p);
|
||||
|
||||
const uint len = math::minimum<uint>(max_len, static_cast<uint>(wcslen(p)));
|
||||
CRNLIB_ASSERT(len < UINT16_MAX);
|
||||
|
||||
if ((!len) || (len >= UINT16_MAX))
|
||||
clear();
|
||||
else if ((m_pStr) && (p >= m_pStr) && (p < (m_pStr + m_buf_size)))
|
||||
{
|
||||
if (m_pStr != p)
|
||||
memmove(m_pStr, p, len * sizeof(wchar_t));
|
||||
m_pStr[len] = L'\0';
|
||||
m_len = static_cast<uint16>(len);
|
||||
}
|
||||
else if (ensure_buf(len, false))
|
||||
{
|
||||
m_len = static_cast<uint16>(len);
|
||||
memcpy(m_pStr, p, (m_len + 1) * sizeof(wchar_t));
|
||||
}
|
||||
|
||||
check();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
dynamic_wstring& dynamic_wstring::set(const dynamic_wstring& other, uint max_len)
|
||||
{
|
||||
if (this == &other)
|
||||
{
|
||||
if (max_len < m_len)
|
||||
{
|
||||
m_pStr[max_len] = L'\0';
|
||||
m_len = static_cast<uint16>(max_len);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint len = math::minimum<uint>(max_len, other.m_len);
|
||||
|
||||
if (!len)
|
||||
clear();
|
||||
else if (ensure_buf(len, false))
|
||||
{
|
||||
m_len = static_cast<uint16>(len);
|
||||
memcpy(m_pStr, other.get_ptr_priv(), m_len * sizeof(wchar_t));
|
||||
m_pStr[len] = L'\0';
|
||||
}
|
||||
}
|
||||
|
||||
check();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool dynamic_wstring::set_len(uint new_len, wchar_t fill_char)
|
||||
{
|
||||
if ((new_len >= UINT16_MAX) || (!fill_char))
|
||||
return false;
|
||||
|
||||
uint cur_len = m_len;
|
||||
|
||||
if (ensure_buf(new_len, true))
|
||||
{
|
||||
if (new_len > cur_len)
|
||||
{
|
||||
for (uint i = 0; i < (new_len - cur_len); i++)
|
||||
m_pStr[cur_len + i] = fill_char;
|
||||
}
|
||||
|
||||
m_pStr[new_len] = L'\0';
|
||||
|
||||
m_len = static_cast<uint16>(new_len);
|
||||
|
||||
check();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
dynamic_wstring& dynamic_wstring::set_from_buf(const void* pBuf, uint buf_size, bool little_endian)
|
||||
{
|
||||
CRNLIB_ASSERT(pBuf);
|
||||
|
||||
if (buf_size >= UINT16_MAX)
|
||||
{
|
||||
clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
for (uint i = 0; i < buf_size; i++)
|
||||
{
|
||||
if (static_cast<const wchar_t*>(pBuf)[i] == L'\0')
|
||||
{
|
||||
CRNLIB_ASSERT(0);
|
||||
clear();
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
if (ensure_buf(buf_size, false))
|
||||
{
|
||||
utils::copy_words(reinterpret_cast<uint16*>(m_pStr), reinterpret_cast<const uint16*>(pBuf), buf_size, c_crnlib_little_endian_platform != little_endian);
|
||||
|
||||
m_pStr[buf_size] = L'\0';
|
||||
|
||||
m_len = static_cast<uint16>(buf_size);
|
||||
|
||||
check();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
dynamic_wstring& dynamic_wstring::set_char(uint index, wchar_t c)
|
||||
{
|
||||
CRNLIB_ASSERT(index <= m_len);
|
||||
|
||||
if (!c)
|
||||
truncate(index);
|
||||
else if (index < m_len)
|
||||
{
|
||||
m_pStr[index] = c;
|
||||
|
||||
check();
|
||||
}
|
||||
else if (index == m_len)
|
||||
append_char(c);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
dynamic_wstring& dynamic_wstring::append_char(wchar_t c)
|
||||
{
|
||||
if (ensure_buf(m_len + 1))
|
||||
{
|
||||
m_pStr[m_len] = c;
|
||||
m_pStr[m_len + 1] = L'\0';
|
||||
m_len++;
|
||||
check();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
dynamic_wstring& dynamic_wstring::truncate(uint new_len)
|
||||
{
|
||||
if (new_len < m_len)
|
||||
{
|
||||
m_pStr[new_len] = L'\0';
|
||||
m_len = static_cast<uint16>(new_len);
|
||||
check();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
dynamic_wstring& dynamic_wstring::tolower()
|
||||
{
|
||||
if (m_len)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
_wcslwr_s(get_ptr_priv(), m_buf_size);
|
||||
#else
|
||||
_wcslwr(get_ptr_priv());
|
||||
#endif
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
dynamic_wstring& dynamic_wstring::toupper()
|
||||
{
|
||||
if (m_len)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
_wcsupr_s(get_ptr_priv(), m_buf_size);
|
||||
#else
|
||||
_wcsupr(get_ptr_priv());
|
||||
#endif
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
dynamic_wstring& dynamic_wstring::append(const wchar_t* p)
|
||||
{
|
||||
CRNLIB_ASSERT(p);
|
||||
|
||||
uint len = static_cast<uint>(wcslen(p));
|
||||
uint new_total_len = m_len + len;
|
||||
if ((new_total_len) && ensure_buf(new_total_len))
|
||||
{
|
||||
memcpy(m_pStr + m_len, p, (len + 1) * sizeof(wchar_t));
|
||||
m_len = static_cast<uint16>(m_len + len);
|
||||
check();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
dynamic_wstring& dynamic_wstring::append(const dynamic_wstring& other)
|
||||
{
|
||||
uint len = other.m_len;
|
||||
uint new_total_len = m_len + len;
|
||||
if ((new_total_len) && ensure_buf(new_total_len))
|
||||
{
|
||||
memcpy(m_pStr + m_len, other.get_ptr_priv(), (len + 1) * sizeof(wchar_t));
|
||||
m_len = static_cast<uint16>(m_len + len);
|
||||
check();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
dynamic_wstring operator+ (const wchar_t* p, const dynamic_wstring& a)
|
||||
{
|
||||
return dynamic_wstring(p).append(a);
|
||||
}
|
||||
|
||||
dynamic_wstring operator+ (const dynamic_wstring& a, const wchar_t* p)
|
||||
{
|
||||
return dynamic_wstring(a).append(p);
|
||||
}
|
||||
|
||||
dynamic_wstring operator+ (const dynamic_wstring& a, const dynamic_wstring& b)
|
||||
{
|
||||
return dynamic_wstring(a).append(b);
|
||||
}
|
||||
|
||||
dynamic_wstring& dynamic_wstring::format_args(const wchar_t* p, va_list args)
|
||||
{
|
||||
CRNLIB_ASSERT(p);
|
||||
|
||||
const uint cBufSize = 4096;
|
||||
wchar_t buf[cBufSize];
|
||||
|
||||
#ifdef _MSC_VER
|
||||
int l = _vsnwprintf_s(buf, cBufSize, _TRUNCATE, p, args);
|
||||
#else
|
||||
int l = _vsnwprintf(buf, cBufSize, p, args);
|
||||
#endif
|
||||
if (l <= 0)
|
||||
clear();
|
||||
else if (ensure_buf(l, false))
|
||||
{
|
||||
memcpy(m_pStr, buf, (l + 1) * sizeof(wchar_t));
|
||||
|
||||
m_len = static_cast<uint16>(l);
|
||||
|
||||
check();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
dynamic_wstring& dynamic_wstring::format(const wchar_t* p, ...)
|
||||
{
|
||||
CRNLIB_ASSERT(p);
|
||||
|
||||
va_list args;
|
||||
va_start(args, p);
|
||||
format_args(p, args);
|
||||
va_end(args);
|
||||
return *this;
|
||||
}
|
||||
|
||||
dynamic_wstring& dynamic_wstring::crop(uint start, uint len)
|
||||
{
|
||||
if (start >= m_len)
|
||||
{
|
||||
clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
len = math::minimum<uint>(len, m_len - start);
|
||||
|
||||
if (start)
|
||||
memmove(get_ptr_priv(), get_ptr_priv() + start, len * sizeof(wchar_t));
|
||||
|
||||
m_pStr[len] = L'\0';
|
||||
|
||||
m_len = static_cast<uint16>(len);
|
||||
|
||||
check();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
dynamic_wstring& dynamic_wstring::substring(uint start, uint end)
|
||||
{
|
||||
CRNLIB_ASSERT(start <= end);
|
||||
if (start > end)
|
||||
return *this;
|
||||
return crop(start, end - start);
|
||||
}
|
||||
|
||||
dynamic_wstring& dynamic_wstring::left(uint len)
|
||||
{
|
||||
return substring(0, len);
|
||||
}
|
||||
|
||||
dynamic_wstring& dynamic_wstring::mid(uint start, uint len)
|
||||
{
|
||||
return crop(start, len);
|
||||
}
|
||||
|
||||
dynamic_wstring& dynamic_wstring::right(uint start)
|
||||
{
|
||||
return substring(start, get_len());
|
||||
}
|
||||
|
||||
dynamic_wstring& dynamic_wstring::tail(uint num)
|
||||
{
|
||||
return substring(math::maximum<int>(static_cast<int>(get_len()) - static_cast<int>(num), 0), get_len());
|
||||
}
|
||||
|
||||
dynamic_wstring& dynamic_wstring::unquote()
|
||||
{
|
||||
if (m_len >= 2)
|
||||
{
|
||||
if ( ((*this)[0] == L'\"') && ((*this)[m_len - 1] == L'\"') )
|
||||
{
|
||||
return mid(1, m_len - 2);
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
int dynamic_wstring::find_left(const wchar_t* p, bool case_sensitive) const
|
||||
{
|
||||
CRNLIB_ASSERT(p);
|
||||
|
||||
const int p_len = (int)wcslen(p);
|
||||
|
||||
for (int i = 0; i <= (m_len - p_len); i++)
|
||||
if ((case_sensitive ? wcsncmp : _wcsnicmp)(p, &m_pStr[i], p_len) == 0)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool dynamic_wstring::contains(const wchar_t* p, bool case_sensitive) const
|
||||
{
|
||||
return find_left(p, case_sensitive) >= 0;
|
||||
}
|
||||
|
||||
uint dynamic_wstring::count_char(wchar_t c) const
|
||||
{
|
||||
uint count = 0;
|
||||
for (uint i = 0; i < m_len; i++)
|
||||
if (m_pStr[i] == c)
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
int dynamic_wstring::find_left(wchar_t c) const
|
||||
{
|
||||
for (uint i = 0; i < m_len; i++)
|
||||
if (m_pStr[i] == c)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dynamic_wstring::find_right(wchar_t c) const
|
||||
{
|
||||
for (int i = (int)m_len - 1; i >= 0; i--)
|
||||
if (m_pStr[i] == c)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dynamic_wstring::find_right(const wchar_t* p, bool case_sensitive) const
|
||||
{
|
||||
CRNLIB_ASSERT(p);
|
||||
const int p_len = (int)wcslen(p);
|
||||
|
||||
for (int i = m_len - p_len; i >= 0; i--)
|
||||
if ((case_sensitive ? wcsncmp : _wcsnicmp)(p, &m_pStr[i], p_len) == 0)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
dynamic_wstring& dynamic_wstring::trim()
|
||||
{
|
||||
int s, e;
|
||||
for (s = 0; s < (int)m_len; s++)
|
||||
if (!iswspace(m_pStr[s]))
|
||||
break;
|
||||
|
||||
for (e = m_len - 1; e > s; e--)
|
||||
if (!iswspace(m_pStr[e]))
|
||||
break;
|
||||
|
||||
return crop(s, e - s + 1);
|
||||
}
|
||||
|
||||
dynamic_wstring& dynamic_wstring::trim_crlf()
|
||||
{
|
||||
int s = 0, e;
|
||||
|
||||
for (e = m_len - 1; e > s; e--)
|
||||
if ((m_pStr[e] != 13) && (m_pStr[e] != 10))
|
||||
break;
|
||||
|
||||
return crop(s, e - s + 1);
|
||||
}
|
||||
|
||||
dynamic_wstring& dynamic_wstring::remap(int from_char, int to_char)
|
||||
{
|
||||
for (uint i = 0; i < m_len; i++)
|
||||
if (m_pStr[i] == from_char)
|
||||
m_pStr[i] = (wchar_t)to_char;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifdef CRNLIB_BUILD_DEBUG
|
||||
void dynamic_wstring::check() const
|
||||
{
|
||||
if (!m_pStr)
|
||||
{
|
||||
CRNLIB_ASSERT(!m_buf_size && !m_len);
|
||||
}
|
||||
else
|
||||
{
|
||||
CRNLIB_ASSERT(m_buf_size);
|
||||
CRNLIB_ASSERT((m_buf_size == UINT16_MAX) || math::is_power_of_2((uint32)m_buf_size));
|
||||
CRNLIB_ASSERT(m_len < m_buf_size);
|
||||
CRNLIB_ASSERT(wcslen(m_pStr) == m_len);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool dynamic_wstring::ensure_buf(uint len, bool preserve_contents)
|
||||
{
|
||||
uint buf_size_needed = len + 1;
|
||||
|
||||
CRNLIB_ASSERT(buf_size_needed <= UINT16_MAX);
|
||||
|
||||
if (buf_size_needed <= UINT16_MAX)
|
||||
{
|
||||
if (buf_size_needed > m_buf_size)
|
||||
expand_buf(buf_size_needed, preserve_contents);
|
||||
}
|
||||
|
||||
return m_buf_size >= buf_size_needed;
|
||||
}
|
||||
|
||||
bool dynamic_wstring::expand_buf(uint new_buf_size, bool preserve_contents)
|
||||
{
|
||||
new_buf_size = math::minimum<uint>(UINT16_MAX, math::next_pow2(math::maximum<uint>(m_buf_size, new_buf_size)));
|
||||
|
||||
if (new_buf_size != m_buf_size)
|
||||
{
|
||||
wchar_t* p = crnlib_new_array<wchar_t>(new_buf_size);
|
||||
|
||||
if (preserve_contents)
|
||||
memcpy(p, get_ptr_priv(), (m_len + 1) * sizeof(wchar_t));
|
||||
|
||||
crnlib_delete_array(m_pStr);
|
||||
m_pStr = p;
|
||||
|
||||
m_buf_size = static_cast<uint16>(new_buf_size);
|
||||
|
||||
if (preserve_contents)
|
||||
check();
|
||||
}
|
||||
|
||||
return m_buf_size >= new_buf_size;
|
||||
}
|
||||
|
||||
void dynamic_wstring::swap(dynamic_wstring& other)
|
||||
{
|
||||
utils::swap(other.m_buf_size, m_buf_size);
|
||||
utils::swap(other.m_len, m_len);
|
||||
utils::swap(other.m_pStr, m_pStr);
|
||||
}
|
||||
|
||||
int dynamic_wstring::serialize(void* pBuf, uint buf_size, bool little_endian) const
|
||||
{
|
||||
CRNLIB_ASSERT(pBuf);
|
||||
|
||||
uint buf_left = buf_size;
|
||||
|
||||
if (m_len > UINT16_MAX)
|
||||
return -1;
|
||||
|
||||
if (!utils::write_val((uint16)m_len, pBuf, buf_left, little_endian))
|
||||
return -1;
|
||||
|
||||
if (buf_left < (m_len * sizeof(wchar_t)))
|
||||
return -1;
|
||||
|
||||
utils::copy_words(reinterpret_cast<uint16*>(pBuf), reinterpret_cast<const uint16*>(get_ptr_priv()), m_len, little_endian != c_crnlib_little_endian_platform);
|
||||
|
||||
buf_left -= m_len * sizeof(wchar_t);
|
||||
|
||||
return buf_size - buf_left;
|
||||
}
|
||||
|
||||
int dynamic_wstring::deserialize(const void* pBuf, uint buf_size, bool little_endian)
|
||||
{
|
||||
CRNLIB_ASSERT(pBuf);
|
||||
|
||||
uint buf_left = buf_size;
|
||||
|
||||
if (buf_left < sizeof(uint16)) return -1;
|
||||
|
||||
uint16 l;
|
||||
if (!utils::read_obj(l, pBuf, buf_left, little_endian))
|
||||
return -1;
|
||||
|
||||
if (buf_left < (l * sizeof(wchar_t)))
|
||||
return -1;
|
||||
|
||||
set_from_buf(pBuf, l, little_endian);
|
||||
|
||||
buf_left -= l * sizeof(wchar_t);
|
||||
|
||||
return buf_size - buf_left;
|
||||
}
|
||||
|
||||
dynamic_wstring::dynamic_wstring(const char* p) :
|
||||
m_buf_size(0), m_len(0), m_pStr(NULL)
|
||||
{
|
||||
set(p);
|
||||
}
|
||||
|
||||
dynamic_wstring::dynamic_wstring(const dynamic_string& s) :
|
||||
m_buf_size(0), m_len(0), m_pStr(NULL)
|
||||
{
|
||||
set(s.get_ptr());
|
||||
}
|
||||
|
||||
dynamic_wstring& dynamic_wstring::set(const char* p)
|
||||
{
|
||||
CRNLIB_ASSERT(p);
|
||||
if (!p)
|
||||
{
|
||||
clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint l = static_cast<uint>(strlen(p));
|
||||
if (!l)
|
||||
{
|
||||
clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
const uint num_needed = static_cast<uint>(MultiByteToWideChar(CP_ACP, 0, p, l, NULL, 0));
|
||||
if (!num_needed)
|
||||
{
|
||||
clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
if (!ensure_buf(num_needed, false))
|
||||
{
|
||||
clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
const uint num_written = static_cast<uint>(MultiByteToWideChar(CP_ACP, 0, p, l, m_pStr, num_needed));
|
||||
CRNLIB_ASSERT(num_needed == num_written);
|
||||
|
||||
m_pStr[num_written] = L'\0';
|
||||
m_len = static_cast<uint16>(num_written);
|
||||
|
||||
check();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
dynamic_string& dynamic_wstring::as_ansi(dynamic_string& buf)
|
||||
{
|
||||
if (!m_len)
|
||||
{
|
||||
buf.clear();
|
||||
return buf;
|
||||
}
|
||||
|
||||
const uint num_needed = WideCharToMultiByte(CP_ACP, 0, m_pStr, m_len, NULL, 0, NULL, NULL);
|
||||
if (num_needed <= 0)
|
||||
{
|
||||
buf.clear();
|
||||
return buf;
|
||||
}
|
||||
|
||||
if (!buf.ensure_buf(num_needed, false))
|
||||
{
|
||||
buf.clear();
|
||||
return buf;
|
||||
}
|
||||
|
||||
const uint num_written = WideCharToMultiByte(CP_ACP, 0, m_pStr, m_len, buf.get_ptr_raw(), num_needed, NULL, NULL);
|
||||
CRNLIB_ASSERT(num_written == num_needed);
|
||||
|
||||
buf.get_ptr_raw()[num_written] = 0;
|
||||
buf.m_len = static_cast<uint16>(num_written);
|
||||
|
||||
buf.check();
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
dynamic_wstring& dynamic_wstring::operator= (const dynamic_string& rhs)
|
||||
{
|
||||
return set(rhs.get_ptr());
|
||||
}
|
||||
|
||||
} // namespace crnlib
|
||||
@@ -1,159 +0,0 @@
|
||||
// File: crn_dynamic_wstring.h
|
||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
||||
#pragma once
|
||||
|
||||
namespace crnlib
|
||||
{
|
||||
// UCS-2 string class (plane 0 characters only)
|
||||
class dynamic_wstring
|
||||
{
|
||||
public:
|
||||
inline dynamic_wstring() : m_buf_size(0), m_len(0), m_pStr(NULL) { }
|
||||
dynamic_wstring(eVarArg dummy, const wchar_t* p, ...);
|
||||
dynamic_wstring(const wchar_t* p);
|
||||
dynamic_wstring(const wchar_t* p, uint len);
|
||||
dynamic_wstring(const dynamic_wstring& other);
|
||||
|
||||
// Conversion from UCS-2 to ANSI and vice versa
|
||||
explicit dynamic_wstring(const char* p);
|
||||
explicit dynamic_wstring(const dynamic_string& s);
|
||||
dynamic_wstring& set(const char* p);
|
||||
dynamic_string& as_ansi(dynamic_string& buf);
|
||||
|
||||
inline ~dynamic_wstring() { CRNLIB_ASSUME(sizeof(wchar_t) == sizeof(uint16)); if (m_pStr) crnlib_delete_array(m_pStr); }
|
||||
|
||||
// Truncates the string to 0 chars and frees the buffer.
|
||||
void clear();
|
||||
void optimize();
|
||||
|
||||
// Truncates the string to 0 chars, but does not free the buffer.
|
||||
void empty();
|
||||
|
||||
inline uint get_len() const { return m_len; }
|
||||
inline bool is_empty() const { return !m_len; }
|
||||
|
||||
inline const wchar_t* get_ptr() const { return m_pStr ? m_pStr : L""; }
|
||||
|
||||
inline const wchar_t* get_ptr_raw() const { return m_pStr; }
|
||||
inline wchar_t* get_ptr_raw() { return m_pStr; }
|
||||
|
||||
inline wchar_t operator[] (uint i) const { CRNLIB_ASSERT(i <= m_len); return get_ptr()[i]; }
|
||||
|
||||
inline operator size_t() const { return fast_hash(get_ptr(), m_len * sizeof(wchar_t)) ^ fast_hash(&m_len, sizeof(m_len)); }
|
||||
|
||||
int compare(const wchar_t* p, bool case_sensitive = false) const;
|
||||
int compare(const dynamic_wstring& rhs, bool case_sensitive = false) const;
|
||||
|
||||
inline bool operator== (const dynamic_wstring& rhs) const { return compare(rhs) == 0; }
|
||||
inline bool operator== (const wchar_t* p) const { return compare(p) == 0; }
|
||||
|
||||
inline bool operator!= (const dynamic_wstring& rhs) const { return compare(rhs) != 0; }
|
||||
inline bool operator!= (const wchar_t* p) const { return compare(p) != 0; }
|
||||
|
||||
inline bool operator< (const dynamic_wstring& rhs) const { return compare(rhs) < 0; }
|
||||
inline bool operator< (const wchar_t* p) const { return compare(p) < 0; }
|
||||
|
||||
inline bool operator> (const dynamic_wstring& rhs) const { return compare(rhs) > 0; }
|
||||
inline bool operator> (const wchar_t* p) const { return compare(p) > 0; }
|
||||
|
||||
inline bool operator<= (const dynamic_wstring& rhs) const { return compare(rhs) <= 0; }
|
||||
inline bool operator<= (const wchar_t* p) const { return compare(p) <= 0; }
|
||||
|
||||
inline bool operator>= (const dynamic_wstring& rhs) const { return compare(rhs) >= 0; }
|
||||
inline bool operator>= (const wchar_t* p) const { return compare(p) >= 0; }
|
||||
|
||||
friend inline bool operator== (const wchar_t* p, const dynamic_wstring& rhs) { return rhs.compare(p) == 0; }
|
||||
|
||||
dynamic_wstring& set(const wchar_t* p, uint max_len = UINT_MAX);
|
||||
dynamic_wstring& set(const dynamic_wstring& other, uint max_len = UINT_MAX);
|
||||
|
||||
bool set_len(uint new_len, wchar_t fill_char = ' ');
|
||||
|
||||
// Set from non-zero terminated buffer.
|
||||
// little_endian is the endianness of the buffer's data
|
||||
dynamic_wstring& set_from_buf(const void* pBuf, uint buf_size, bool little_endian = c_crnlib_little_endian_platform);
|
||||
|
||||
dynamic_wstring& operator= (const dynamic_wstring& rhs) { return set(rhs); }
|
||||
dynamic_wstring& operator= (const dynamic_string& rhs);
|
||||
dynamic_wstring& operator= (const wchar_t* p) { return set(p); }
|
||||
dynamic_wstring& operator= (const char* p) { return set(p); }
|
||||
|
||||
dynamic_wstring& set_char(uint index, wchar_t c);
|
||||
dynamic_wstring& append_char(wchar_t c);
|
||||
dynamic_wstring& append_char(int c) { CRNLIB_ASSERT((c >= 0) && (c <= 0xFFFF)); return append_char(static_cast<wchar_t>(c)); }
|
||||
dynamic_wstring& truncate(uint new_len);
|
||||
dynamic_wstring& tolower();
|
||||
dynamic_wstring& toupper();
|
||||
|
||||
dynamic_wstring& append(const wchar_t* p);
|
||||
dynamic_wstring& append(const dynamic_wstring& other);
|
||||
dynamic_wstring& operator += (const wchar_t* p) { return append(p); }
|
||||
dynamic_wstring& operator += (const dynamic_wstring& other) { return append(other); }
|
||||
|
||||
friend dynamic_wstring operator+ (const wchar_t* p, const dynamic_wstring& a);
|
||||
friend dynamic_wstring operator+ (const dynamic_wstring& a, const wchar_t* p);
|
||||
friend dynamic_wstring operator+ (const dynamic_wstring& a, const dynamic_wstring& b);
|
||||
|
||||
dynamic_wstring& format_args(const wchar_t* p, va_list args);
|
||||
dynamic_wstring& format(const wchar_t* p, ...);
|
||||
|
||||
dynamic_wstring& crop(uint start, uint len);
|
||||
dynamic_wstring& substring(uint start, uint end);
|
||||
dynamic_wstring& left(uint len);
|
||||
dynamic_wstring& mid(uint start, uint len);
|
||||
dynamic_wstring& right(uint start);
|
||||
dynamic_wstring& tail(uint num);
|
||||
|
||||
dynamic_wstring& unquote();
|
||||
|
||||
uint count_char(wchar_t c) const;
|
||||
|
||||
int find_left(const wchar_t* p, bool case_sensitive = false) const;
|
||||
int find_left(wchar_t c) const;
|
||||
|
||||
int find_right(wchar_t c) const;
|
||||
int find_right(const wchar_t* p, bool case_sensitive = false) const;
|
||||
|
||||
bool contains(const wchar_t* p, bool case_sensitive = false) const;
|
||||
|
||||
dynamic_wstring& trim();
|
||||
dynamic_wstring& trim_crlf();
|
||||
|
||||
dynamic_wstring& remap(int from_char, int to_char);
|
||||
|
||||
void swap(dynamic_wstring& other);
|
||||
|
||||
int serialize(void* pBuf, uint buf_size, bool little_endian) const;
|
||||
int deserialize(const void* pBuf, uint buf_size, bool little_endian);
|
||||
|
||||
private:
|
||||
// These values are in characters, not bytes!
|
||||
uint16 m_buf_size;
|
||||
uint16 m_len;
|
||||
wchar_t* m_pStr;
|
||||
|
||||
#ifdef CRNLIB_BUILD_DEBUG
|
||||
void check() const;
|
||||
#else
|
||||
void check() const { }
|
||||
#endif
|
||||
|
||||
bool ensure_buf(uint len, bool preserve_contents = true);
|
||||
bool expand_buf(uint new_buf_size, bool preserve_contents);
|
||||
|
||||
const wchar_t* get_ptr_priv() const { return m_pStr ? m_pStr : L""; }
|
||||
wchar_t* get_ptr_priv() { return (wchar_t*)(m_pStr ? m_pStr : L""); }
|
||||
};
|
||||
|
||||
typedef crnlib::vector<dynamic_wstring> dynamic_wstring_array;
|
||||
|
||||
extern dynamic_wstring g_empty_dynamic_wstring;
|
||||
|
||||
CRNLIB_DEFINE_BITWISE_MOVABLE(dynamic_wstring);
|
||||
|
||||
inline void swap (dynamic_wstring& a, dynamic_wstring& b)
|
||||
{
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
} // namespace crnlib
|
||||
@@ -1,27 +0,0 @@
|
||||
// File: crn_event.h
|
||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
||||
#pragma once
|
||||
|
||||
namespace crnlib
|
||||
{
|
||||
class event
|
||||
{
|
||||
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(event);
|
||||
|
||||
public:
|
||||
event(bool manual_reset = false, bool initial_state = false, const char* pName = NULL);
|
||||
~event();
|
||||
|
||||
inline void *get_handle(void) const { return m_handle; }
|
||||
|
||||
void set(void);
|
||||
void reset(void);
|
||||
void pulse(void);
|
||||
bool wait(uint32 milliseconds = UINT32_MAX);
|
||||
|
||||
private:
|
||||
void *m_handle;
|
||||
};
|
||||
|
||||
} // namespace crnlib
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
// File: crn_mutex.h
|
||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
||||
#pragma once
|
||||
|
||||
namespace crnlib
|
||||
{
|
||||
class mutex
|
||||
{
|
||||
mutex(const mutex&);
|
||||
mutex& operator= (const mutex&);
|
||||
|
||||
public:
|
||||
mutex(unsigned int spin_count = 0);
|
||||
~mutex();
|
||||
void lock();
|
||||
void unlock();
|
||||
void set_spin_count(unsigned int count);
|
||||
|
||||
private:
|
||||
int m_buf[12];
|
||||
|
||||
#ifdef CRNLIB_BUILD_DEBUG
|
||||
unsigned int m_lock_count;
|
||||
#endif
|
||||
};
|
||||
|
||||
class scoped_mutex
|
||||
{
|
||||
scoped_mutex(const scoped_mutex&);
|
||||
scoped_mutex& operator= (const scoped_mutex&);
|
||||
|
||||
public:
|
||||
inline scoped_mutex(mutex& m) : m_mutex(m) { m_mutex.lock(); }
|
||||
inline ~scoped_mutex() { m_mutex.unlock(); }
|
||||
|
||||
private:
|
||||
mutex& m_mutex;
|
||||
};
|
||||
|
||||
} // namespace crnlib
|
||||
@@ -1,25 +0,0 @@
|
||||
// File: crn_semaphore.h
|
||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
||||
#pragma once
|
||||
|
||||
namespace crnlib
|
||||
{
|
||||
class semaphore
|
||||
{
|
||||
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(semaphore);
|
||||
|
||||
public:
|
||||
semaphore(int32 initialCount = 0, int32 maximumCount = 1, const char* pName = NULL);
|
||||
~semaphore();
|
||||
|
||||
inline void *get_handle(void) const { return m_handle; }
|
||||
|
||||
void release(int32 releaseCount = 1, int32 *pPreviousCount = NULL);
|
||||
|
||||
bool wait(uint32 milliseconds = UINT32_MAX);
|
||||
|
||||
private:
|
||||
void *m_handle;
|
||||
};
|
||||
|
||||
} // namespace crnlib
|
||||
@@ -1,38 +0,0 @@
|
||||
// File: crn_spinlock.h
|
||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
||||
#pragma once
|
||||
|
||||
namespace crnlib
|
||||
{
|
||||
// Simple non-recursive spinlock.
|
||||
class spinlock
|
||||
{
|
||||
public:
|
||||
inline spinlock() : m_flag(0) { }
|
||||
|
||||
void lock(uint32 max_spins = 4096, bool yielding = true, bool memoryBarrier = true);
|
||||
|
||||
inline void lock_no_barrier(uint32 max_spins = 4096, bool yielding = true) { lock(max_spins, yielding, false); }
|
||||
|
||||
void unlock();
|
||||
|
||||
inline void unlock_no_barrier() { m_flag = CRNLIB_FALSE; }
|
||||
|
||||
private:
|
||||
volatile int32 m_flag;
|
||||
};
|
||||
|
||||
class scoped_spinlock
|
||||
{
|
||||
scoped_spinlock(const scoped_spinlock&);
|
||||
scoped_spinlock& operator= (const scoped_spinlock&);
|
||||
|
||||
public:
|
||||
inline scoped_spinlock(spinlock& lock) : m_lock(lock) { m_lock.lock(); }
|
||||
inline ~scoped_spinlock() { m_lock.unlock(); }
|
||||
|
||||
private:
|
||||
spinlock& m_lock;
|
||||
};
|
||||
|
||||
} // namespace crnlib
|
||||
@@ -1,243 +0,0 @@
|
||||
// File: crn_task_pool.cpp
|
||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
||||
#include "crn_core.h"
|
||||
#include "crn_task_pool.h"
|
||||
#include <process.h>
|
||||
|
||||
#include "crn_winhdr.h"
|
||||
|
||||
namespace crnlib
|
||||
{
|
||||
task_pool::task_pool() :
|
||||
m_num_threads(0),
|
||||
m_num_outstanding_tasks(0),
|
||||
m_exit_flag(false)
|
||||
{
|
||||
utils::zero_object(m_threads);
|
||||
}
|
||||
|
||||
task_pool::task_pool(uint num_threads) :
|
||||
m_num_threads(0),
|
||||
m_num_outstanding_tasks(0),
|
||||
m_exit_flag(false)
|
||||
{
|
||||
utils::zero_object(m_threads);
|
||||
bool status = init(num_threads);
|
||||
CRNLIB_VERIFY(status);
|
||||
}
|
||||
|
||||
task_pool::~task_pool()
|
||||
{
|
||||
deinit();
|
||||
}
|
||||
|
||||
bool task_pool::init(uint num_threads)
|
||||
{
|
||||
CRNLIB_ASSERT(num_threads <= cMaxThreads);
|
||||
num_threads = math::minimum<uint>(num_threads, cMaxThreads);
|
||||
|
||||
deinit();
|
||||
|
||||
m_task_condition_var.lock();
|
||||
|
||||
m_num_threads = num_threads;
|
||||
|
||||
bool succeeded = true;
|
||||
for (uint i = 0; i < num_threads; i++)
|
||||
{
|
||||
m_threads[i] = (HANDLE)_beginthreadex(NULL, 32768, thread_func, this, 0, NULL);
|
||||
|
||||
CRNLIB_ASSERT(m_threads[i] != 0);
|
||||
if (!m_threads[i])
|
||||
{
|
||||
succeeded = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_task_condition_var.unlock();
|
||||
|
||||
if (!succeeded)
|
||||
{
|
||||
deinit();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void task_pool::deinit()
|
||||
{
|
||||
if (m_num_threads)
|
||||
{
|
||||
m_task_condition_var.lock();
|
||||
|
||||
m_exit_flag = true;
|
||||
|
||||
m_task_condition_var.unlock();
|
||||
|
||||
for (uint i = 0; i < m_num_threads; i++)
|
||||
{
|
||||
if (m_threads[i])
|
||||
{
|
||||
for ( ; ; )
|
||||
{
|
||||
uint32 result = WaitForSingleObject(m_threads[i], 1000);
|
||||
if (result == WAIT_OBJECT_0)
|
||||
break;
|
||||
}
|
||||
|
||||
CloseHandle(m_threads[i]);
|
||||
|
||||
m_threads[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
m_num_threads = 0;
|
||||
|
||||
m_exit_flag = false;
|
||||
}
|
||||
|
||||
m_tasks.clear();
|
||||
m_num_outstanding_tasks = 0;
|
||||
}
|
||||
|
||||
uint task_pool::get_num_threads() const
|
||||
{
|
||||
return m_num_threads;
|
||||
}
|
||||
|
||||
void task_pool::queue_task(task_callback_func pFunc, uint64 data, void* pData_ptr)
|
||||
{
|
||||
CRNLIB_ASSERT(pFunc);
|
||||
|
||||
m_task_condition_var.lock();
|
||||
|
||||
task tsk;
|
||||
tsk.m_callback = pFunc;
|
||||
tsk.m_data = data;
|
||||
tsk.m_pData_ptr = pData_ptr;
|
||||
tsk.m_flags = 0;
|
||||
m_tasks.push_back(tsk);
|
||||
|
||||
m_num_outstanding_tasks++;
|
||||
|
||||
m_task_condition_var.unlock();
|
||||
}
|
||||
|
||||
// It's the object's responsibility to crnlib_delete pObj within the execute_task() method, if needed!
|
||||
void task_pool::queue_task(executable_task* pObj, uint64 data, void* pData_ptr)
|
||||
{
|
||||
CRNLIB_ASSERT(pObj);
|
||||
|
||||
m_task_condition_var.lock();
|
||||
|
||||
task tsk;
|
||||
tsk.m_pObj = pObj;
|
||||
tsk.m_data = data;
|
||||
tsk.m_pData_ptr = pData_ptr;
|
||||
tsk.m_flags = cTaskFlagObject;
|
||||
m_tasks.push_back(tsk);
|
||||
|
||||
m_num_outstanding_tasks++;
|
||||
|
||||
m_task_condition_var.unlock();
|
||||
}
|
||||
|
||||
bool task_pool::join_condition_func(void* pCallback_data_ptr, uint64 callback_data)
|
||||
{
|
||||
callback_data;
|
||||
|
||||
task_pool* pPool = static_cast<task_pool*>(pCallback_data_ptr);
|
||||
|
||||
return (!pPool->m_num_outstanding_tasks) || pPool->m_exit_flag;
|
||||
}
|
||||
|
||||
void task_pool::process_task(task& tsk)
|
||||
{
|
||||
if (tsk.m_flags & cTaskFlagObject)
|
||||
tsk.m_pObj->execute_task(tsk.m_data, tsk.m_pData_ptr);
|
||||
else
|
||||
tsk.m_callback(tsk.m_data, tsk.m_pData_ptr);
|
||||
|
||||
m_task_condition_var.lock();
|
||||
|
||||
m_num_outstanding_tasks--;
|
||||
|
||||
m_task_condition_var.unlock();
|
||||
}
|
||||
|
||||
void task_pool::join()
|
||||
{
|
||||
for ( ; ; )
|
||||
{
|
||||
m_task_condition_var.lock();
|
||||
|
||||
if (!m_tasks.empty())
|
||||
{
|
||||
task tsk(m_tasks.front());
|
||||
m_tasks.pop_front();
|
||||
|
||||
m_task_condition_var.unlock();
|
||||
|
||||
process_task(tsk);
|
||||
}
|
||||
else
|
||||
{
|
||||
int result = m_task_condition_var.wait(join_condition_func, this);
|
||||
result;
|
||||
CRNLIB_ASSERT(result >= 0);
|
||||
|
||||
m_task_condition_var.unlock();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool task_pool::wait_condition_func(void* pCallback_data_ptr, uint64 callback_data)
|
||||
{
|
||||
callback_data;
|
||||
|
||||
task_pool* pPool = static_cast<task_pool*>(pCallback_data_ptr);
|
||||
|
||||
return (!pPool->m_tasks.empty()) || pPool->m_exit_flag;
|
||||
}
|
||||
|
||||
unsigned __stdcall task_pool::thread_func(void* pContext)
|
||||
{
|
||||
//set_thread_name(GetCurrentThreadId(), "taskpoolhelper");
|
||||
|
||||
task_pool* pPool = static_cast<task_pool*>(pContext);
|
||||
|
||||
for ( ; ; )
|
||||
{
|
||||
pPool->m_task_condition_var.lock();
|
||||
|
||||
int result = pPool->m_task_condition_var.wait(wait_condition_func, pPool);
|
||||
|
||||
CRNLIB_ASSERT(result >= 0);
|
||||
|
||||
if ((result < 0) || (pPool->m_exit_flag))
|
||||
{
|
||||
pPool->m_task_condition_var.unlock();
|
||||
break;
|
||||
}
|
||||
|
||||
if (pPool->m_tasks.empty())
|
||||
pPool->m_task_condition_var.unlock();
|
||||
else
|
||||
{
|
||||
task tsk(pPool->m_tasks.front());
|
||||
pPool->m_tasks.pop_front();
|
||||
|
||||
pPool->m_task_condition_var.unlock();
|
||||
|
||||
pPool->process_task(tsk);
|
||||
}
|
||||
}
|
||||
|
||||
_endthreadex(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace crnlib
|
||||
@@ -1,140 +0,0 @@
|
||||
// File: crn_task_pool.h
|
||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
||||
#pragma once
|
||||
#include "crn_condition_var.h"
|
||||
#include <deque>
|
||||
|
||||
namespace crnlib
|
||||
{
|
||||
class task_pool
|
||||
{
|
||||
public:
|
||||
task_pool();
|
||||
task_pool(uint num_threads);
|
||||
~task_pool();
|
||||
|
||||
enum { cMaxThreads = 16 };
|
||||
bool init(uint num_threads);
|
||||
void deinit();
|
||||
|
||||
uint get_num_threads() const;
|
||||
|
||||
// C-style task callback
|
||||
typedef void (*task_callback_func)(uint64 data, void* pData_ptr);
|
||||
void queue_task(task_callback_func pFunc, uint64 data = 0, void* pData_ptr = NULL);
|
||||
|
||||
class executable_task
|
||||
{
|
||||
public:
|
||||
virtual void execute_task(uint64 data, void* pData_ptr) = 0;
|
||||
};
|
||||
|
||||
// It's the caller's responsibility to crnlib_delete pObj within the execute_task() method, if needed!
|
||||
void queue_task(executable_task* pObj, uint64 data = 0, void* pData_ptr = NULL);
|
||||
|
||||
template<typename S, typename T>
|
||||
inline void queue_object_task(S* pObject, T pObject_method, uint64 data = 0, void* pData_ptr = NULL);
|
||||
|
||||
void join();
|
||||
|
||||
private:
|
||||
uint m_num_threads;
|
||||
|
||||
uint m_num_outstanding_tasks;
|
||||
|
||||
void* m_threads[cMaxThreads];
|
||||
|
||||
bool m_exit_flag;
|
||||
|
||||
condition_var m_task_condition_var;
|
||||
|
||||
enum task_flags
|
||||
{
|
||||
cTaskFlagObject = 1
|
||||
};
|
||||
|
||||
struct task
|
||||
{
|
||||
uint64 m_data;
|
||||
void* m_pData_ptr;
|
||||
|
||||
union
|
||||
{
|
||||
task_callback_func m_callback;
|
||||
executable_task* m_pObj;
|
||||
};
|
||||
|
||||
uint m_flags;
|
||||
};
|
||||
|
||||
std::deque<task> m_tasks;
|
||||
|
||||
void process_task(task& tsk);
|
||||
|
||||
static bool join_condition_func(void* pCallback_data_ptr, uint64 callback_data);
|
||||
static bool wait_condition_func(void* pCallback_data_ptr, uint64 callback_data);
|
||||
static unsigned __stdcall thread_func(void* pContext);
|
||||
};
|
||||
|
||||
enum object_task_flags
|
||||
{
|
||||
cObjectTaskFlagDefault = 0,
|
||||
cObjectTaskFlagDeleteAfterExecution = 1
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class object_task : public task_pool::executable_task
|
||||
{
|
||||
public:
|
||||
object_task(uint flags = cObjectTaskFlagDefault) :
|
||||
m_pObject(NULL),
|
||||
m_pMethod(NULL),
|
||||
m_flags(flags)
|
||||
{
|
||||
}
|
||||
|
||||
typedef void (T::*object_method_ptr)(uint64 data, void* pData_ptr);
|
||||
|
||||
object_task(T* pObject, object_method_ptr pMethod, uint flags = cObjectTaskFlagDefault) :
|
||||
m_pObject(pObject),
|
||||
m_pMethod(pMethod),
|
||||
m_flags(flags)
|
||||
{
|
||||
CRNLIB_ASSERT(pObject && pMethod);
|
||||
}
|
||||
|
||||
void init(T* pObject, object_method_ptr pMethod, uint flags = cObjectTaskFlagDefault)
|
||||
{
|
||||
CRNLIB_ASSERT(pObject && pMethod);
|
||||
|
||||
m_pObject = pObject;
|
||||
m_pMethod = pMethod;
|
||||
m_flags = flags;
|
||||
}
|
||||
|
||||
T* get_object() const { return m_pObject; }
|
||||
object_method_ptr get_method() const { return m_pMethod; }
|
||||
|
||||
virtual void execute_task(uint64 data, void* pData_ptr)
|
||||
{
|
||||
(m_pObject->*m_pMethod)(data, pData_ptr);
|
||||
|
||||
if (m_flags & cObjectTaskFlagDeleteAfterExecution)
|
||||
crnlib_delete(this);
|
||||
}
|
||||
|
||||
protected:
|
||||
T* m_pObject;
|
||||
|
||||
object_method_ptr m_pMethod;
|
||||
|
||||
uint m_flags;
|
||||
};
|
||||
|
||||
template<typename S, typename T>
|
||||
inline void task_pool::queue_object_task(S* pObject, T pObject_method, uint64 data, void* pData_ptr)
|
||||
{
|
||||
queue_task(crnlib_new< object_task<S> >(pObject, pObject_method, cObjectTaskFlagDeleteAfterExecution), data, pData_ptr);
|
||||
}
|
||||
|
||||
} // namespace crnlib
|
||||
@@ -1,116 +0,0 @@
|
||||
// File: crn_win32_console.cpp
|
||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
||||
#include "crn_core.h"
|
||||
#include "crn_win32_console.h"
|
||||
#include "crn_winhdr.h"
|
||||
|
||||
namespace crnlib
|
||||
{
|
||||
void win32_console::init()
|
||||
{
|
||||
console::init();
|
||||
console::add_console_output_func(console_output_func, NULL);
|
||||
}
|
||||
|
||||
void win32_console::deinit()
|
||||
{
|
||||
console::remove_console_output_func(console_output_func);
|
||||
console::deinit();
|
||||
}
|
||||
|
||||
void win32_console::tick()
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef CRNLIB_PLATFORM_PC
|
||||
bool win32_console::console_output_func(eConsoleMessageType type, const wchar_t* pMsg, void* pData)
|
||||
{
|
||||
pData;
|
||||
|
||||
if (console::get_output_disabled())
|
||||
return true;
|
||||
|
||||
HANDLE cons = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
DWORD attr = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
|
||||
switch (type)
|
||||
{
|
||||
case cDebugConsoleMessage: attr = FOREGROUND_BLUE | FOREGROUND_INTENSITY; break;
|
||||
case cMessageConsoleMessage: attr = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; break;
|
||||
case cWarningConsoleMessage: attr = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY; break;
|
||||
case cErrorConsoleMessage: attr = FOREGROUND_RED | FOREGROUND_INTENSITY; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (INVALID_HANDLE_VALUE != cons)
|
||||
SetConsoleTextAttribute(cons, (WORD)attr);
|
||||
|
||||
if (console::get_prefixes())
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case cDebugConsoleMessage:
|
||||
wprintf(L"Debug: %s", pMsg);
|
||||
break;
|
||||
case cWarningConsoleMessage:
|
||||
wprintf(L"Warning: %s", pMsg);
|
||||
break;
|
||||
case cErrorConsoleMessage:
|
||||
wprintf(L"Error: %s", pMsg);
|
||||
break;
|
||||
default:
|
||||
wprintf(L"%s", pMsg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wprintf(L"%s", pMsg);
|
||||
}
|
||||
|
||||
if (console::get_crlf())
|
||||
wprintf(L"\n");
|
||||
|
||||
if (INVALID_HANDLE_VALUE != cons)
|
||||
SetConsoleTextAttribute(cons, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
bool win32_console::console_output_func(eConsoleMessageType type, const wchar_t* pMsg, void* pData)
|
||||
{
|
||||
if (console::get_output_disabled())
|
||||
return true;
|
||||
|
||||
if (console::get_prefixes())
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case cDebugConsoleMessage:
|
||||
wprintf(L"Debug: %s", pMsg);
|
||||
break;
|
||||
case cWarningConsoleMessage:
|
||||
wprintf(L"Warning: %s", pMsg);
|
||||
break;
|
||||
case cErrorConsoleMessage:
|
||||
wprintf(L"Error: %s", pMsg);
|
||||
break;
|
||||
default:
|
||||
wprintf(L"%s", pMsg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wprintf(L"%s", pMsg);
|
||||
}
|
||||
|
||||
if (console::get_crlf())
|
||||
wprintf(L"\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace crnlib
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
// File: crn_win32_console.h
|
||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
||||
#pragma once
|
||||
#include "crn_console.h"
|
||||
#include "crn_event.h"
|
||||
|
||||
namespace crnlib
|
||||
{
|
||||
class win32_console
|
||||
{
|
||||
public:
|
||||
static void init();
|
||||
static void deinit();
|
||||
static void tick();
|
||||
|
||||
private:
|
||||
static bool console_output_func(eConsoleMessageType type, const wchar_t* pMsg, void* pData);
|
||||
|
||||
};
|
||||
|
||||
} // namespace crnlib
|
||||
@@ -1,69 +0,0 @@
|
||||
// File: crn_win32_file_utils.cpp
|
||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
||||
#include "crn_core.h"
|
||||
#include "crn_win32_file_utils.h"
|
||||
#include "crn_winhdr.h"
|
||||
|
||||
namespace crnlib
|
||||
{
|
||||
bool win32_file_utils::does_file_exist(const wchar_t* pFilename)
|
||||
{
|
||||
const DWORD fullAttributes = GetFileAttributesW(pFilename);
|
||||
|
||||
if (fullAttributes == INVALID_FILE_ATTRIBUTES)
|
||||
return false;
|
||||
|
||||
if (fullAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool win32_file_utils::does_dir_exist(const wchar_t* pDir)
|
||||
{
|
||||
//-- Get the file attributes.
|
||||
DWORD fullAttributes = GetFileAttributesW(pDir);
|
||||
|
||||
if (fullAttributes == INVALID_FILE_ATTRIBUTES)
|
||||
return false;
|
||||
|
||||
if (fullAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool win32_file_utils::get_file_size(const wchar_t* pFilename, uint64& file_size)
|
||||
{
|
||||
file_size = 0;
|
||||
|
||||
WIN32_FILE_ATTRIBUTE_DATA attr;
|
||||
|
||||
if (0 == GetFileAttributesExW(pFilename, GetFileExInfoStandard, &attr))
|
||||
return false;
|
||||
|
||||
if (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
return false;
|
||||
|
||||
file_size = static_cast<uint64>(attr.nFileSizeLow) | (static_cast<uint64>(attr.nFileSizeHigh) << 32U);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool win32_file_utils::get_file_size(const wchar_t* pFilename, uint32& file_size)
|
||||
{
|
||||
uint64 file_size64;
|
||||
if (!get_file_size(pFilename, file_size64))
|
||||
{
|
||||
file_size = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file_size64 > UINT32_MAX)
|
||||
file_size64 = UINT32_MAX;
|
||||
|
||||
file_size = static_cast<uint32>(file_size64);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace crnlib
|
||||
@@ -1,15 +0,0 @@
|
||||
// File: crn_win32_file_utils.h
|
||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
||||
#pragma once
|
||||
|
||||
namespace crnlib
|
||||
{
|
||||
struct win32_file_utils
|
||||
{
|
||||
static bool does_file_exist(const wchar_t* pFilename);
|
||||
static bool does_dir_exist(const wchar_t* pDir);
|
||||
static bool get_file_size(const wchar_t* pFilename, uint64& file_size);
|
||||
static bool get_file_size(const wchar_t* pFilename, uint32& file_size);
|
||||
};
|
||||
|
||||
} // namespace crnlib
|
||||
@@ -1,176 +0,0 @@
|
||||
// File: crn_win32_find_files.cpp
|
||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
||||
#include "crn_core.h"
|
||||
#include "crn_win32_find_files.h"
|
||||
#include "crn_win32_file_utils.h"
|
||||
#include "crn_strutils.h"
|
||||
|
||||
namespace crnlib
|
||||
{
|
||||
bool find_files::find(const wchar_t* pBasepath, const wchar_t* pFilespec, uint flags)
|
||||
{
|
||||
m_last_error = S_OK;
|
||||
m_files.resize(0);
|
||||
|
||||
return find_internal(pBasepath, L"", pFilespec, flags);
|
||||
}
|
||||
|
||||
bool find_files::find(const wchar_t* pSpec, uint flags)
|
||||
{
|
||||
dynamic_wstring find_name(pSpec);
|
||||
|
||||
if (!full_path(find_name))
|
||||
return false;
|
||||
|
||||
dynamic_wstring find_pathname, find_filename;
|
||||
if (!split_path(find_name.get_ptr(), find_pathname, find_filename))
|
||||
return false;
|
||||
|
||||
return find(find_pathname.get_ptr(), find_filename.get_ptr(), flags);
|
||||
}
|
||||
|
||||
bool find_files::find_internal(const wchar_t* pBasepath, const wchar_t* pRelpath, const wchar_t* pFilespec, uint flags)
|
||||
{
|
||||
WIN32_FIND_DATAW find_data;
|
||||
|
||||
dynamic_wstring filename;
|
||||
|
||||
dynamic_wstring_array child_paths;
|
||||
if (flags & cFlagRecursive)
|
||||
{
|
||||
if (wcslen(pRelpath))
|
||||
combine_path(filename, pBasepath, pRelpath, L"*");
|
||||
else
|
||||
combine_path(filename, pBasepath, L"*");
|
||||
|
||||
HANDLE handle = FindFirstFileW(filename.get_ptr(), &find_data);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
HRESULT hres = GetLastError();
|
||||
if ((hres != NO_ERROR) && (hres != ERROR_FILE_NOT_FOUND))
|
||||
{
|
||||
m_last_error = hres;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
const bool is_dir = (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
|
||||
bool skip = !is_dir;
|
||||
if (is_dir)
|
||||
skip = (wcscmp(find_data.cFileName, L".") == 0) || (wcscmp(find_data.cFileName, L"..") == 0);
|
||||
|
||||
if (find_data.dwFileAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_TEMPORARY))
|
||||
skip = true;
|
||||
|
||||
if (find_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
|
||||
{
|
||||
if ((flags & cFlagAllowHidden) == 0)
|
||||
skip = true;
|
||||
}
|
||||
|
||||
if (!skip)
|
||||
{
|
||||
dynamic_wstring child_path(find_data.cFileName);
|
||||
if ((!child_path.count_char(L'?')) && (!child_path.count_char(L'*')))
|
||||
child_paths.push_back(child_path);
|
||||
}
|
||||
|
||||
} while (FindNextFileW(handle, &find_data) != 0);
|
||||
|
||||
HRESULT hres = GetLastError();
|
||||
|
||||
FindClose(handle);
|
||||
handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
if (hres != ERROR_NO_MORE_FILES)
|
||||
{
|
||||
m_last_error = hres;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wcslen(pRelpath))
|
||||
combine_path(filename, pBasepath, pRelpath, pFilespec);
|
||||
else
|
||||
combine_path(filename, pBasepath, pFilespec);
|
||||
|
||||
HANDLE handle = FindFirstFileW(filename.get_ptr(), &find_data);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
HRESULT hres = GetLastError();
|
||||
if ((hres != NO_ERROR) && (hres != ERROR_FILE_NOT_FOUND))
|
||||
{
|
||||
m_last_error = hres;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
const bool is_dir = (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
|
||||
bool skip = false;
|
||||
if (is_dir)
|
||||
skip = (wcscmp(find_data.cFileName, L".") == 0) || (wcscmp(find_data.cFileName, L"..") == 0);
|
||||
|
||||
if (find_data.dwFileAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_TEMPORARY))
|
||||
skip = true;
|
||||
|
||||
if (find_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
|
||||
{
|
||||
if ((flags & cFlagAllowHidden) == 0)
|
||||
skip = true;
|
||||
}
|
||||
|
||||
if (!skip)
|
||||
{
|
||||
if (((is_dir) && (flags & cFlagAllowDirs)) || ((!is_dir) && (flags & cFlagAllowFiles)))
|
||||
{
|
||||
m_files.resize(m_files.size() + 1);
|
||||
file_desc& file = m_files.back();
|
||||
file.m_is_dir = is_dir;
|
||||
file.m_base = pBasepath;
|
||||
file.m_name = find_data.cFileName;
|
||||
file.m_rel = pRelpath;
|
||||
if (wcslen(pRelpath))
|
||||
combine_path(file.m_fullname, pBasepath, pRelpath, find_data.cFileName);
|
||||
else
|
||||
combine_path(file.m_fullname, pBasepath, find_data.cFileName);
|
||||
}
|
||||
}
|
||||
|
||||
} while (FindNextFileW(handle, &find_data) != 0);
|
||||
|
||||
HRESULT hres = GetLastError();
|
||||
|
||||
FindClose(handle);
|
||||
|
||||
if (hres != ERROR_NO_MORE_FILES)
|
||||
{
|
||||
m_last_error = hres;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint i = 0; i < child_paths.size(); i++)
|
||||
{
|
||||
dynamic_wstring child_path;
|
||||
if (wcslen(pRelpath))
|
||||
combine_path(child_path, pRelpath, child_paths[i].get_ptr());
|
||||
else
|
||||
child_path = child_paths[i];
|
||||
|
||||
if (!find_internal(pBasepath, child_path.get_ptr(), pFilespec, flags))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace crnlib
|
||||
@@ -1,55 +0,0 @@
|
||||
// File: crn_win32_find_files.h
|
||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
||||
#pragma once
|
||||
#include "crn_winhdr.h"
|
||||
|
||||
namespace crnlib
|
||||
{
|
||||
class find_files
|
||||
{
|
||||
public:
|
||||
struct file_desc
|
||||
{
|
||||
inline file_desc() : m_is_dir(false) { }
|
||||
|
||||
dynamic_wstring m_fullname;
|
||||
dynamic_wstring m_base;
|
||||
dynamic_wstring m_rel;
|
||||
dynamic_wstring m_name;
|
||||
bool m_is_dir;
|
||||
|
||||
inline bool operator== (const file_desc& other) const { return m_fullname == other.m_fullname; }
|
||||
inline bool operator< (const file_desc& other) const { return m_fullname < other.m_fullname; }
|
||||
|
||||
inline operator size_t() const { return static_cast<size_t>(m_fullname); }
|
||||
};
|
||||
|
||||
typedef crnlib::vector<file_desc> file_desc_vec;
|
||||
|
||||
find_files() : m_last_error(S_OK) { }
|
||||
|
||||
enum flags
|
||||
{
|
||||
cFlagRecursive = 1,
|
||||
cFlagAllowDirs = 2,
|
||||
cFlagAllowFiles = 4,
|
||||
cFlagAllowHidden = 8
|
||||
};
|
||||
|
||||
bool find(const wchar_t* pBasepath, const wchar_t* pFilespec, uint flags = cFlagAllowFiles);
|
||||
|
||||
bool find(const wchar_t* pSpec, uint flags = cFlagAllowFiles);
|
||||
|
||||
inline HRESULT get_last_error() const { return m_last_error; }
|
||||
|
||||
const file_desc_vec& get_files() const { return m_files; }
|
||||
|
||||
private:
|
||||
file_desc_vec m_files;
|
||||
HRESULT m_last_error;
|
||||
|
||||
bool find_internal(const wchar_t* pBasepath, const wchar_t* pRelpath, const wchar_t* pFilespec, uint flags);
|
||||
|
||||
}; // class find_files
|
||||
|
||||
} // namespace crnlib
|
||||
@@ -1,36 +0,0 @@
|
||||
// File: crn_win32_threading.cpp
|
||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
||||
#include "crn_core.h"
|
||||
#include "crn_win32_threading.h"
|
||||
#include "crn_winhdr.h"
|
||||
|
||||
namespace crnlib
|
||||
{
|
||||
uint g_number_of_processors = 1;
|
||||
|
||||
int32 interlocked_compare_exchange32(int32 volatile *Destination, int32 Exchange, int32 Comperand)
|
||||
{
|
||||
CRNLIB_ASSUME(sizeof(LONG) == sizeof(int32));
|
||||
return InterlockedCompareExchange((volatile LONG*)Destination, Exchange, Comperand);
|
||||
}
|
||||
|
||||
int32 interlocked_increment32(int32 volatile *lpAddend)
|
||||
{
|
||||
return InterlockedIncrement((volatile LONG*)lpAddend);
|
||||
}
|
||||
|
||||
int32 interlocked_exchange_add32(int32 volatile *Addend, int32 Value)
|
||||
{
|
||||
return InterlockedExchangeAdd((volatile LONG*)Addend, Value);
|
||||
}
|
||||
|
||||
int32 interlocked_exchange32(int32 volatile *Target, int32 Value)
|
||||
{
|
||||
return InterlockedExchange((volatile LONG*)Target, Value);
|
||||
}
|
||||
|
||||
uint32 get_current_thread_id()
|
||||
{
|
||||
return GetCurrentThreadId();
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
// File: crn_win32_threading.h
|
||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
||||
#pragma once
|
||||
|
||||
namespace crnlib
|
||||
{
|
||||
// g_number_of_processors defaults to 1. Will be higher on multicore machines.
|
||||
extern uint g_number_of_processors;
|
||||
|
||||
int32 interlocked_compare_exchange32(int32 volatile *Destination, int32 Exchange, int32 Comperand);
|
||||
int32 interlocked_increment32(int32 volatile *lpAddend);
|
||||
int32 interlocked_exchange_add32(int32 volatile *Addend, int32 Value);
|
||||
int32 interlocked_exchange32(int32 volatile *Target, int32 Value);
|
||||
uint32 get_current_thread_id();
|
||||
|
||||
} // namespace crnlib
|
||||
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
// File: crn_win32_timer.cpp
|
||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
||||
#include "crn_core.h"
|
||||
#include "crn_win32_timer.h"
|
||||
#include "crn_winhdr.h"
|
||||
|
||||
namespace crnlib
|
||||
{
|
||||
uint64 timer::g_init_ticks;
|
||||
uint64 timer::g_freq;
|
||||
double timer::g_inv_freq;
|
||||
|
||||
timer::timer() :
|
||||
m_start_time(0),
|
||||
m_stop_time(0),
|
||||
m_started(false),
|
||||
m_stopped(false)
|
||||
{
|
||||
if (!g_inv_freq) init();
|
||||
}
|
||||
|
||||
timer::timer(timer_ticks start_ticks)
|
||||
{
|
||||
if (!g_inv_freq) init();
|
||||
|
||||
m_start_time = start_ticks;
|
||||
|
||||
m_started = true;
|
||||
m_stopped = false;
|
||||
}
|
||||
|
||||
void timer::start(timer_ticks start_ticks)
|
||||
{
|
||||
m_start_time = start_ticks;
|
||||
|
||||
m_started = true;
|
||||
m_stopped = false;
|
||||
}
|
||||
|
||||
void timer::start()
|
||||
{
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&m_start_time);
|
||||
|
||||
m_started = true;
|
||||
m_stopped = false;
|
||||
}
|
||||
|
||||
void timer::stop()
|
||||
{
|
||||
CRNLIB_ASSERT(m_started);
|
||||
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&m_stop_time);
|
||||
|
||||
m_stopped = true;
|
||||
}
|
||||
|
||||
double timer::get_elapsed_secs() const
|
||||
{
|
||||
CRNLIB_ASSERT(m_started);
|
||||
if (!m_started)
|
||||
return 0;
|
||||
|
||||
uint64 stop_time = m_stop_time;
|
||||
if (!m_stopped)
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&stop_time);
|
||||
|
||||
uint64 delta = stop_time - m_start_time;
|
||||
return delta * g_inv_freq;
|
||||
}
|
||||
|
||||
uint64 timer::get_elapsed_us() const
|
||||
{
|
||||
CRNLIB_ASSERT(m_started);
|
||||
if (!m_started)
|
||||
return 0;
|
||||
|
||||
uint64 stop_time = m_stop_time;
|
||||
if (!m_stopped)
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&stop_time);
|
||||
|
||||
uint64 delta = stop_time - m_start_time;
|
||||
return (delta * 1000000ULL + (g_freq >> 1U)) / g_freq;
|
||||
}
|
||||
|
||||
void timer::init()
|
||||
{
|
||||
if (!g_inv_freq)
|
||||
{
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*)&g_freq);
|
||||
g_inv_freq = 1.0f / g_freq;
|
||||
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&g_init_ticks);
|
||||
}
|
||||
}
|
||||
|
||||
timer_ticks timer::get_init_ticks()
|
||||
{
|
||||
if (!g_inv_freq) init();
|
||||
|
||||
return g_init_ticks;
|
||||
}
|
||||
|
||||
timer_ticks timer::get_ticks()
|
||||
{
|
||||
if (!g_inv_freq) init();
|
||||
|
||||
timer_ticks ticks;
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&ticks);
|
||||
return ticks;
|
||||
}
|
||||
|
||||
double timer::ticks_to_secs(timer_ticks ticks)
|
||||
{
|
||||
if (!g_inv_freq) init();
|
||||
|
||||
return ticks * g_inv_freq;
|
||||
}
|
||||
|
||||
} // namespace crnlib
|
||||
@@ -1,40 +0,0 @@
|
||||
// File: crn_win32_timer.h
|
||||
// See Copyright Notice and license at the end of inc/crnlib.h
|
||||
#pragma once
|
||||
|
||||
namespace crnlib
|
||||
{
|
||||
typedef uint64 timer_ticks;
|
||||
|
||||
class timer
|
||||
{
|
||||
public:
|
||||
timer();
|
||||
timer(timer_ticks start_ticks);
|
||||
|
||||
void start();
|
||||
void start(timer_ticks start_ticks);
|
||||
|
||||
void stop();
|
||||
|
||||
double get_elapsed_secs() const;
|
||||
uint64 get_elapsed_us() const;
|
||||
|
||||
static void init();
|
||||
static timer_ticks get_init_ticks();
|
||||
static timer_ticks get_ticks();
|
||||
static double ticks_to_secs(timer_ticks ticks);
|
||||
|
||||
private:
|
||||
static uint64 g_init_ticks;
|
||||
static uint64 g_freq;
|
||||
static double g_inv_freq;
|
||||
|
||||
uint64 m_start_time;
|
||||
uint64 m_stop_time;
|
||||
|
||||
bool m_started : 1;
|
||||
bool m_stopped : 1;
|
||||
};
|
||||
|
||||
} // namespace crnlib
|
||||
Reference in New Issue
Block a user