latest SDK

This commit is contained in:
2021-12-14 00:28:25 -07:00
commit 68b10d413b
492 changed files with 80542 additions and 0 deletions

539
pfc/alloc.h Normal file
View File

@@ -0,0 +1,539 @@
#pragma once
namespace pfc {
static void * raw_malloc(t_size p_size) {
return p_size > 0 ? new_ptr_check_t(malloc(p_size)) : NULL;
}
static void raw_free(void * p_block) throw() {free(p_block);}
inline void* raw_realloc(void * p_ptr,t_size p_size) {
if (p_size == 0) {raw_free(p_ptr); return NULL;}
else if (p_ptr == NULL) return raw_malloc(p_size);
else return pfc::new_ptr_check_t(::realloc(p_ptr,p_size));
}
inline bool raw_realloc_inplace(void * p_block,t_size p_size) throw() {
if (p_block == NULL) return p_size == 0;
#ifdef _MSC_VER
if (p_size == 0) return false;
return _expand(p_block,p_size) != NULL;
#else
return false;
#endif
}
template<typename T>
t_size calc_array_width(t_size p_width) {
return pfc::mul_safe_t<std::bad_alloc,t_size>(p_width,sizeof(T));
}
template<typename T>
T * __raw_malloc_t(t_size p_size) {
return reinterpret_cast<T*>(raw_malloc(calc_array_width<T>(p_size)));
}
template<typename T>
void __raw_free_t(T * p_block) throw() {
raw_free(reinterpret_cast<void*>(p_block));
}
template<typename T>
T * __raw_realloc_t(T * p_block,t_size p_size) {
return reinterpret_cast<T*>(raw_realloc(p_block,calc_array_width<T>(p_size)));
}
template<typename T>
bool __raw_realloc_inplace_t(T * p_block,t_size p_size) {
return raw_realloc_inplace(p_block,calc_array_width<T>(p_size));
}
template<typename t_exception,typename t_int>
inline t_int safe_shift_left_t(t_int p_val,t_size p_shift = 1) {
t_int newval = p_val << p_shift;
if (newval >> p_shift != p_val) throw t_exception();
return newval;
}
template<typename t_item> class alloc_dummy {
private: typedef alloc_dummy<t_item> t_self;
public:
alloc_dummy() {}
void set_size(t_size p_size) {throw pfc::exception_not_implemented();}
t_size get_size() const {throw pfc::exception_not_implemented();}
const t_item & operator[](t_size p_index) const {throw pfc::exception_not_implemented();}
t_item & operator[](t_size p_index) {throw pfc::exception_not_implemented();}
bool is_ptr_owned(const void * p_item) const {return false;}
//set to true when we prioritize speed over memory usage
enum { alloc_prioritizes_speed = false };
//not mandatory
const t_item * get_ptr() const {throw pfc::exception_not_implemented();}
t_item * get_ptr() {throw pfc::exception_not_implemented();}
void prealloc(t_size) {throw pfc::exception_not_implemented();}
void force_reset() {throw pfc::exception_not_implemented();}
void move_from(t_self &) {throw pfc::exception_not_implemented();}
private:
const t_self & operator=(const t_self &) {throw pfc::exception_not_implemented();}
alloc_dummy(const t_self&) {throw pfc::exception_not_implemented();}
};
template<typename t_item>
bool is_pointer_in_range(const t_item * p_buffer,t_size p_buffer_size,const void * p_pointer) {
return p_pointer >= reinterpret_cast<const void*>(p_buffer) && p_pointer < reinterpret_cast<const void*>(p_buffer + p_buffer_size);
}
//! Simple inefficient fully portable allocator.
template<typename t_item> class alloc_simple {
private: typedef alloc_simple<t_item> t_self;
public:
alloc_simple() : m_data(NULL), m_size(0) {}
void set_size(t_size p_size) {
if (p_size != m_size) {
t_item * l_data = NULL;
if (p_size > 0) l_data = new t_item[p_size];
try {
pfc::memcpy_t(l_data,m_data,pfc::min_t(m_size,p_size));
} catch(...) {
delete[] l_data;
throw;
}
delete[] m_data;
m_data = l_data;
m_size = p_size;
}
}
t_size get_size() const {return m_size;}
const t_item & operator[](t_size p_index) const {PFC_ASSERT(p_index < m_size); return m_data[p_index];}
t_item & operator[](t_size p_index) {PFC_ASSERT(p_index < m_size); return m_data[p_index];}
bool is_ptr_owned(const void * p_item) const {return is_pointer_in_range(get_ptr(),get_size(),p_item);}
enum { alloc_prioritizes_speed = false };
t_item * get_ptr() {return m_data;}
const t_item * get_ptr() const {return m_data;}
void prealloc(t_size) {}
void force_reset() {set_size(0);}
~alloc_simple() {delete[] m_data;}
void move_from(t_self & other) {
delete[] m_data;
m_data = replace_null_t(other.m_data);
m_size = replace_null_t(other.m_size);
}
private:
const t_self & operator=(const t_self &) = delete;
alloc_simple(const t_self&) = delete;
t_item * m_data;
t_size m_size;
};
template<typename t_item> class __array_fast_helper_t {
private:
typedef __array_fast_helper_t<t_item> t_self;
public:
__array_fast_helper_t() : m_buffer(NULL), m_size(0), m_size_total(0) {}
void set_size(t_size p_size,t_size p_size_total) {
PFC_ASSERT(p_size <= p_size_total);
PFC_ASSERT(m_size <= m_size_total);
if (p_size_total > m_size_total) {
resize_storage(p_size_total);
resize_content(p_size);
} else {
resize_content(p_size);
resize_storage(p_size_total);
}
}
t_size get_size() const {return m_size;}
t_size get_size_total() const {return m_size_total;}
const t_item & operator[](t_size p_index) const {PFC_ASSERT(p_index < m_size); return m_buffer[p_index];}
t_item & operator[](t_size p_index) {PFC_ASSERT(p_index < m_size); return m_buffer[p_index];}
~__array_fast_helper_t() {
set_size(0,0);
}
t_item * get_ptr() {return m_buffer;}
const t_item * get_ptr() const {return m_buffer;}
bool is_ptr_owned(const void * p_item) const {return is_pointer_in_range(m_buffer,m_size_total,p_item);}
void move_from(t_self & other) {
set_size(0,0);
m_buffer = replace_null_t(other.m_buffer);
m_size = replace_null_t(other.m_size);
m_size_total = replace_null_t(other.m_size_total);
}
private:
const t_self & operator=(const t_self &) = delete;
__array_fast_helper_t(const t_self &) = delete;
void resize_content(t_size p_size) {
if (traits_t<t_item>::needs_constructor || traits_t<t_item>::needs_destructor) {
if (p_size > m_size) {//expand
do {
__unsafe__in_place_constructor_t(m_buffer[m_size]);
m_size++;
} while(m_size < p_size);
} else if (p_size < m_size) {
__unsafe__in_place_destructor_array_t(m_buffer + p_size, m_size - p_size);
m_size = p_size;
}
} else {
m_size = p_size;
}
}
void resize_storage(t_size p_size) {
PFC_ASSERT( m_size <= m_size_total );
PFC_ASSERT( m_size <= p_size );
if (m_size_total != p_size) {
if (pfc::traits_t<t_item>::realloc_safe) {
m_buffer = pfc::__raw_realloc_t(m_buffer,p_size);
m_size_total = p_size;
} else if (__raw_realloc_inplace_t(m_buffer,p_size)) {
//success
m_size_total = p_size;
} else {
t_item * newbuffer = pfc::__raw_malloc_t<t_item>(p_size);
try {
pfc::__unsafe__in_place_constructor_array_copy_t(newbuffer,m_size,m_buffer);
} catch(...) {
pfc::__raw_free_t(newbuffer);
throw;
}
pfc::__unsafe__in_place_destructor_array_t(m_buffer,m_size);
pfc::__raw_free_t(m_buffer);
m_buffer = newbuffer;
m_size_total = p_size;
}
}
}
t_item * m_buffer;
t_size m_size,m_size_total;
};
template<typename t_item> class __array_lite_helper_t {
private:
typedef __array_lite_helper_t<t_item> t_self;
public:
__array_lite_helper_t() : m_buffer(NULL), m_size(0) {}
void set_size(t_size p_size) {
if (p_size > m_size) { // expand
resize_storage(p_size);
resize_content(p_size);
} else if (p_size < m_size) { // shrink
resize_content(p_size);
resize_storage(p_size);
}
}
t_size get_size() const {return m_size;}
const t_item & operator[](t_size p_index) const {PFC_ASSERT(p_index < m_size); return m_buffer[p_index];}
t_item & operator[](t_size p_index) {PFC_ASSERT(p_index < m_size); return m_buffer[p_index];}
~__array_lite_helper_t() {
set_size(0);
}
t_item * get_ptr() {return m_buffer;}
const t_item * get_ptr() const {return m_buffer;}
bool is_ptr_owned(const void * p_item) const {return is_pointer_in_range(m_buffer,m_size,p_item);}
void move_from(t_self & other) {
set_size(0);
m_buffer = replace_null_t(other.m_buffer);
m_size = replace_null_t(other.m_size);
}
private:
const t_self & operator=(const t_self &) = delete;
__array_lite_helper_t(const t_self &) = delete;
void resize_content(t_size p_size) {
if (traits_t<t_item>::needs_constructor || traits_t<t_item>::needs_destructor) {
if (p_size > m_size) {//expand
do {
__unsafe__in_place_constructor_t(m_buffer[m_size]);
m_size++;
} while(m_size < p_size);
} else if (p_size < m_size) {
__unsafe__in_place_destructor_array_t(m_buffer + p_size, m_size - p_size);
m_size = p_size;
}
} else {
m_size = p_size;
}
}
void resize_storage(t_size p_size) {
PFC_ASSERT( m_size <= p_size );
if (pfc::traits_t<t_item>::realloc_safe) {
m_buffer = pfc::__raw_realloc_t(m_buffer,p_size);
//m_size_total = p_size;
} else if (__raw_realloc_inplace_t(m_buffer,p_size)) {
//success
//m_size_total = p_size;
} else {
t_item * newbuffer = pfc::__raw_malloc_t<t_item>(p_size);
try {
pfc::__unsafe__in_place_constructor_array_copy_t(newbuffer,m_size,m_buffer);
} catch(...) {
pfc::__raw_free_t(newbuffer);
throw;
}
pfc::__unsafe__in_place_destructor_array_t(m_buffer,m_size);
pfc::__raw_free_t(m_buffer);
m_buffer = newbuffer;
//m_size_total = p_size;
}
}
t_item * m_buffer;
t_size m_size;
};
template<typename t_item> class alloc_standard {
private: typedef alloc_standard<t_item> t_self;
public:
alloc_standard() {}
void set_size(t_size p_size) {m_content.set_size(p_size);}
t_size get_size() const {return m_content.get_size();}
const t_item & operator[](t_size p_index) const {return m_content[p_index];}
t_item & operator[](t_size p_index) {return m_content[p_index];}
const t_item * get_ptr() const {return m_content.get_ptr();}
t_item * get_ptr() {return m_content.get_ptr();}
bool is_ptr_owned(const void * p_item) const {return m_content.is_ptr_owned(p_item);}
void prealloc(t_size p_size) {}
void force_reset() {set_size(0);}
enum { alloc_prioritizes_speed = false };
void move_from(t_self & other) { m_content.move_from(other.m_content); }
private:
alloc_standard(const t_self &) = delete;
const t_self & operator=(const t_self&) = delete;
__array_lite_helper_t<t_item> m_content;
};
template<typename t_item> class alloc_fast {
private: typedef alloc_fast<t_item> t_self;
public:
alloc_fast() {}
void set_size(t_size p_size) {
t_size size_base = m_data.get_size_total();
if (size_base == 0) size_base = 1;
while(size_base < p_size) {
size_base = safe_shift_left_t<std::bad_alloc,t_size>(size_base,1);
}
while(size_base >> 2 > p_size) {
size_base >>= 1;
}
m_data.set_size(p_size,size_base);
}
t_size get_size() const {return m_data.get_size();}
const t_item & operator[](t_size p_index) const {return m_data[p_index];}
t_item & operator[](t_size p_index) {return m_data[p_index];}
const t_item * get_ptr() const {return m_data.get_ptr();}
t_item * get_ptr() {return m_data.get_ptr();}
bool is_ptr_owned(const void * p_item) const {return m_data.is_ptr_owned(p_item);}
void prealloc(t_size) {}
void force_reset() {m_data.set_size(0,0);}
enum { alloc_prioritizes_speed = true };
void move_from(t_self & other) { m_data.move_from(other.m_data); }
private:
alloc_fast(const t_self &) = delete;
const t_self & operator=(const t_self&) = delete;
__array_fast_helper_t<t_item> m_data;
};
template<typename t_item> class alloc_fast_aggressive {
private: typedef alloc_fast_aggressive<t_item> t_self;
public:
alloc_fast_aggressive() {}
void set_size(t_size p_size) {
t_size size_base = m_data.get_size_total();
if (size_base == 0) size_base = 1;
while(size_base < p_size) {
size_base = safe_shift_left_t<std::bad_alloc,t_size>(size_base,1);
}
m_data.set_size(p_size,size_base);
}
void prealloc(t_size p_size) {
if (p_size > 0) {
t_size size_base = m_data.get_size_total();
if (size_base == 0) size_base = 1;
while(size_base < p_size) {
size_base = safe_shift_left_t<std::bad_alloc,t_size>(size_base,1);
}
m_data.set_size(m_data.get_size(),size_base);
}
}
t_size get_size() const {return m_data.get_size();}
const t_item & operator[](t_size p_index) const {;return m_data[p_index];}
t_item & operator[](t_size p_index) {return m_data[p_index];}
const t_item * get_ptr() const {return m_data.get_ptr();}
t_item * get_ptr() {return m_data.get_ptr();}
bool is_ptr_owned(const void * p_item) const {return m_data.is_ptr_owned(p_item);}
void force_reset() {m_data.set_size(0,0);}
enum { alloc_prioritizes_speed = true };
void move_from(t_self & other) { m_data.move_from(other.m_data); }
private:
alloc_fast_aggressive(const t_self &) = delete;
const t_self & operator=(const t_self&) = delete;
__array_fast_helper_t<t_item> m_data;
};
template<t_size p_width> class alloc_fixed {
public:
template<typename t_item> class alloc {
private: typedef alloc<t_item> t_self;
public:
alloc() : m_size(0) {}
void set_size(t_size p_size) {
static_assert_t<sizeof(m_array) == sizeof(t_item[p_width])>();
if (p_size > p_width) throw pfc::exception_overflow();
else if (p_size > m_size) {
__unsafe__in_place_constructor_array_t(get_ptr()+m_size,p_size-m_size);
m_size = p_size;
} else if (p_size < m_size) {
__unsafe__in_place_destructor_array_t(get_ptr()+p_size,m_size-p_size);
m_size = p_size;
}
}
~alloc() {
if (pfc::traits_t<t_item>::needs_destructor) set_size(0);
}
t_size get_size() const {return m_size;}
t_item * get_ptr() {return reinterpret_cast<t_item*>(&m_array);}
const t_item * get_ptr() const {return reinterpret_cast<const t_item*>(&m_array);}
const t_item & operator[](t_size n) const {return get_ptr()[n];}
t_item & operator[](t_size n) {return get_ptr()[n];}
bool is_ptr_owned(const void * p_item) const {return is_pointer_in_range(get_ptr(),p_width,p_item);}
void prealloc(t_size) {}
void force_reset() {set_size(0);}
enum { alloc_prioritizes_speed = false };
void move_from(t_self & other) {
const size_t count = other.get_size();
set_size( count );
for(size_t w = 0; w < count; ++w) this->get_ptr()[w] = other.get_ptr()[w];
}
private:
alloc(const t_self&) {throw pfc::exception_not_implemented();}
const t_self& operator=(const t_self&) {throw pfc::exception_not_implemented();}
t_uint8 m_array[sizeof(t_item[p_width])];
t_size m_size;
};
};
template<t_size p_width, template<typename> class t_alloc = alloc_standard > class alloc_hybrid {
public:
template<typename t_item> class alloc {
private: typedef alloc<t_item> t_self;
public:
alloc() {}
void set_size(t_size p_size) {
if (p_size > p_width) {
m_fixed.set_size(p_width);
m_variable.set_size(p_size - p_width);
} else {
m_fixed.set_size(p_size);
m_variable.set_size(0);
}
}
t_item & operator[](t_size p_index) {
PFC_ASSERT(p_index < get_size());
if (p_index < p_width) return m_fixed[p_index];
else return m_variable[p_index - p_width];
}
const t_item & operator[](t_size p_index) const {
PFC_ASSERT(p_index < get_size());
if (p_index < p_width) return m_fixed[p_index];
else return m_variable[p_index - p_width];
}
t_size get_size() const {return m_fixed.get_size() + m_variable.get_size();}
bool is_ptr_owned(const void * p_item) const {return m_fixed.is_ptr_owned(p_item) || m_variable.is_ptr_owned(p_item);}
void prealloc(t_size p_size) {
if (p_size > p_width) m_variable.prealloc(p_size - p_width);
}
void force_reset() {
m_fixed.force_reset(); m_variable.force_reset();
}
enum { alloc_prioritizes_speed = t_alloc<t_item>::alloc_prioritizes_speed };
void move_from(t_self & other) {
m_fixed.move_from(other.m_fixed);
m_variable.move_from(other.m_variable);
}
private:
alloc(const t_self&) {throw pfc::exception_not_implemented();}
const t_self& operator=(const t_self&) {throw pfc::exception_not_implemented();}
typename alloc_fixed<p_width>::template alloc<t_item> m_fixed;
t_alloc<t_item> m_variable;
};
};
template<typename t_item> class traits_t<alloc_simple<t_item> > : public traits_default_movable {};
template<typename t_item> class traits_t<__array_fast_helper_t<t_item> > : public traits_default_movable {};
template<typename t_item> class traits_t<alloc_standard<t_item> > : public pfc::traits_t<__array_fast_helper_t<t_item> > {};
template<typename t_item> class traits_t<alloc_fast<t_item> > : public pfc::traits_t<__array_fast_helper_t<t_item> > {};
template<typename t_item> class traits_t<alloc_fast_aggressive<t_item> > : public pfc::traits_t<__array_fast_helper_t<t_item> > {};
#if 0//not working (compiler bug?)
template<t_size p_width,typename t_item> class traits_t<typename alloc_fixed<p_width>::template alloc<t_item> > : public pfc::traits_t<t_item> {
public:
enum {
needs_constructor = true,
};
};
template<t_size p_width,template<typename> class t_alloc,typename t_item>
class traits_t<typename alloc_hybrid<p_width,t_alloc>::template alloc<t_item> > : public traits_combined<t_alloc,typename alloc_fixed<p_width>::template alloc<t_item> > {};
#endif
};

361
pfc/array.h Normal file
View File

@@ -0,0 +1,361 @@
#pragma once
namespace pfc {
template<typename t_item, template<typename> class t_alloc = alloc_standard> class array_t;
//! Special simplififed version of array class that avoids stepping on landmines with classes without public copy operators/constructors.
template<typename _t_item>
class array_staticsize_t {
public: typedef _t_item t_item;
private: typedef array_staticsize_t<t_item> t_self;
public:
array_staticsize_t() : m_array(NULL), m_size(0) {}
array_staticsize_t(t_size p_size) : m_array(new t_item[p_size]), m_size(p_size) {}
~array_staticsize_t() {release_();}
//! Copy constructor nonfunctional when data type is not copyable.
array_staticsize_t(const t_self & p_source) : m_size(0), m_array(NULL) {
*this = p_source;
}
array_staticsize_t(t_self && p_source) {
move_(p_source);
}
//! Copy operator nonfunctional when data type is not copyable.
const t_self & operator=(const t_self & p_source) {
release_();
const t_size newsize = p_source.get_size();
if (newsize > 0) {
m_array = new t_item[newsize];
m_size = newsize;
for(t_size n = 0; n < newsize; n++) m_array[n] = p_source[n];
}
return *this;
}
//! Move operator.
const t_self & operator=(t_self && p_source) {
release_();
move_(p_source);
return *this;
}
void set_size_discard(t_size p_size) {
release_();
if (p_size > 0) {
m_array = new t_item[p_size];
m_size = p_size;
}
}
template<typename t_source>
void set_data_fromptr(const t_source * p_buffer,t_size p_count) {
if (p_count == m_size) {
pfc::copy_array_loop_t(*this,p_buffer,p_count);
} else {
t_item * arr = new t_item[p_count];
try {
pfc::copy_array_loop_t(arr, p_buffer, p_count);
} catch(...) { delete[] arr; throw; }
delete[] m_array;
m_array = arr;
m_size = p_count;
}
}
template<typename t_source>
void assign(t_source const * items, size_t count) {
set_data_fromptr( items, count );
}
t_size get_size() const {return m_size;}
t_size size() const {return m_size;} // std compat
const t_item * get_ptr() const {return m_array;}
t_item * get_ptr() {return m_array;}
const t_item & operator[](t_size p_index) const {PFC_ASSERT(p_index < get_size());return m_array[p_index];}
t_item & operator[](t_size p_index) {PFC_ASSERT(p_index < get_size());return m_array[p_index];}
template<typename t_source> bool is_owned(const t_source & p_item) {return pfc::is_pointer_in_range(get_ptr(),get_size(),&p_item);}
template<typename t_out> void enumerate(t_out & out) const { for(t_size walk = 0; walk < m_size; ++walk) out(m_array[walk]); }
private:
void release_() {
m_size = 0;
delete[] pfc::replace_null_t(m_array);
}
void move_(t_self & from) {
m_size = from.m_size;
m_array = from.m_array;
from.m_size = 0;
from.m_array = NULL;
}
t_item * m_array;
t_size m_size;
};
template<typename t_to,typename t_from>
void copy_array_t(t_to & p_to,const t_from & p_from) {
const t_size size = array_size_t(p_from);
if (p_to.has_owned_items(p_from)) {//avoid landmines with actual array data overlapping, or p_from being same as p_to
array_staticsize_t<typename t_to::t_item> temp;
temp.set_size_discard(size);
pfc::copy_array_loop_t(temp,p_from,size);
p_to.set_size(size);
pfc::copy_array_loop_t(p_to,temp,size);
} else {
p_to.set_size(size);
pfc::copy_array_loop_t(p_to,p_from,size);
}
}
template<typename t_array,typename t_value>
void fill_array_t(t_array & p_array,const t_value & p_value) {
const t_size size = array_size_t(p_array);
for(t_size n=0;n<size;n++) p_array[n] = p_value;
}
template<typename _t_item, template<typename> class t_alloc> class array_t {
public: typedef _t_item t_item;
private: typedef array_t<t_item,t_alloc> t_self;
public:
array_t() {}
array_t(const t_self & p_source) {copy_array_t(*this,p_source);}
template<typename t_source> array_t(const t_source & p_source) {copy_array_t(*this,p_source);}
const t_self & operator=(const t_self & p_source) {copy_array_t(*this,p_source); return *this;}
template<typename t_source> const t_self & operator=(const t_source & p_source) {copy_array_t(*this,p_source); return *this;}
array_t(t_self && p_source) {move_from(p_source);}
const t_self & operator=(t_self && p_source) {move_from(p_source); return *this;}
void set_size(t_size p_size) {m_alloc.set_size(p_size);}
void resize( size_t s ) { set_size(s); } // std compat
template<typename fill_t>
void set_size_fill(size_t p_size, fill_t const & filler) {
size_t before = get_size();
set_size( p_size );
for(size_t w = before; w < p_size; ++w) this->get_ptr()[w] = filler;
}
void set_size_in_range(size_t minSize, size_t maxSize) {
if (minSize >= maxSize) { set_size( minSize); return; }
size_t walk = maxSize;
for(;;) {
try {
set_size(walk);
return;
} catch(std::bad_alloc) {
if (walk <= minSize) throw;
// go on
}
walk >>= 1;
if (walk < minSize) walk = minSize;
}
}
void set_size_discard(t_size p_size) {m_alloc.set_size(p_size);}
void set_count(t_size p_count) {m_alloc.set_size(p_count);}
t_size get_size() const {return m_alloc.get_size();}
size_t size() const {return m_alloc.get_size();} // std compat
t_size get_count() const {return m_alloc.get_size();}
void force_reset() {m_alloc.force_reset();}
const t_item & operator[](t_size p_index) const {PFC_ASSERT(p_index < get_size());return m_alloc[p_index];}
t_item & operator[](t_size p_index) {PFC_ASSERT(p_index < get_size());return m_alloc[p_index];}
//! Warning: buffer pointer must not point to buffer allocated by this array (fixme).
template<typename t_source>
void set_data_fromptr(const t_source * p_buffer,t_size p_count) {
set_size(p_count);
pfc::copy_array_loop_t(*this,p_buffer,p_count);
}
template<typename t_array>
void append(const t_array & p_source) {
if (has_owned_items(p_source)) append(array_t<t_item>(p_source));
else {
const t_size source_size = array_size_t(p_source);
const t_size base = get_size();
increase_size(source_size);
for(t_size n=0;n<source_size;n++) m_alloc[base+n] = p_source[n];
}
}
template<typename t_insert>
void insert_multi(const t_insert & value, t_size base, t_size count) {
const t_size oldSize = get_size();
if (base > oldSize) base = oldSize;
increase_size(count);
pfc::memmove_t(get_ptr() + base + count, get_ptr() + base, oldSize - base);
pfc::fill_ptr_t(get_ptr() + base, count, value);
}
template<typename t_append> void append_multi(const t_append & value, t_size count) {insert_multi(value,~0,count);}
//! Warning: buffer pointer must not point to buffer allocated by this array (fixme).
template<typename t_append>
void append_fromptr(const t_append * p_buffer,t_size p_count) {
PFC_ASSERT( !is_owned(&p_buffer[0]) );
t_size base = get_size();
increase_size(p_count);
for(t_size n=0;n<p_count;n++) m_alloc[base+n] = p_buffer[n];
}
void increase_size(t_size p_delta) {
t_size new_size = get_size() + p_delta;
if (new_size < p_delta) throw std::bad_alloc();
set_size(new_size);
}
template<typename item_t>
void add_item( item_t && item ) {
const t_size base = get_size();
increase_size(1);
m_alloc[base] = std::forward<item_t>( item );
}
template<typename item_t>
void append_single_val( item_t && item ) {
const t_size base = get_size();
increase_size(1);
m_alloc[base] = std::forward<item_t>( item );
}
template<typename t_append>
void append_single(const t_append & p_item) {
if (is_owned(p_item)) append_single(t_append(p_item));
else {
const t_size base = get_size();
increase_size(1);
m_alloc[base] = p_item;
}
}
template<typename t_filler>
void fill(const t_filler & p_filler) {
const t_size max = get_size();
for(t_size n=0;n<max;n++) m_alloc[n] = p_filler;
}
void fill_null() {
const t_size max = get_size();
for(t_size n=0;n<max;n++) m_alloc[n] = 0;
}
void grow_size(t_size p_size) {
if (p_size > get_size()) set_size(p_size);
}
//not supported by some allocs
const t_item * get_ptr() const {return m_alloc.get_ptr();}
t_item * get_ptr() {return m_alloc.get_ptr();}
void prealloc(t_size p_size) {m_alloc.prealloc(p_size);}
template<typename t_array>
bool has_owned_items(const t_array & p_source) {
if (array_size_t(p_source) == 0) return false;
//how the hell would we properly check if any of source items is owned by us, in case source array implements some weird mixing of references of items from different sources?
//the most obvious way means evil bottleneck here (whether it matters or not from caller's point of view which does something O(n) already is another question)
//at least this will work fine with all standard classes which don't crossreference anyhow and always use own storage
//perhaps we'll traitify this someday later
return is_owned(p_source[0]);
}
template<typename t_source>
bool is_owned(const t_source & p_item) {
return m_alloc.is_ptr_owned(&p_item);
}
template<typename t_item>
void set_single(const t_item & p_item) {
set_size(1);
(*this)[0] = p_item;
}
template<typename t_callback> void enumerate(t_callback & p_callback) const { for(t_size n = 0; n < get_size(); n++ ) { p_callback((*this)[n]); } }
void move_from(t_self & other) {
m_alloc.move_from(other.m_alloc);
}
private:
t_alloc<t_item> m_alloc;
};
template<typename t_item,t_size p_width,template<typename> class t_alloc = alloc_standard >
class array_hybrid_t : public array_t<t_item, pfc::alloc_hybrid<p_width,t_alloc>::template alloc >
{};
template<typename t_item> class traits_t<array_staticsize_t<t_item> > : public traits_default_movable {};
template<typename t_item,template<typename> class t_alloc> class traits_t<array_t<t_item,t_alloc> > : public pfc::traits_t<t_alloc<t_item> > {};
template<typename t_comparator = comparator_default>
class comparator_array {
public:
template<typename t_array1, typename t_array2>
static int compare(const t_array1 & p_array1, const t_array2 & p_array2) {
t_size walk = 0;
for(;;) {
if (walk >= p_array1.get_size() && walk >= p_array2.get_size()) return 0;
else if (walk >= p_array1.get_size()) return -1;
else if (walk >= p_array2.get_size()) return 1;
else {
int state = t_comparator::compare(p_array1[walk],p_array2[walk]);
if (state != 0) return state;
}
++walk;
}
}
};
template<typename t_a1, typename t_a2>
static bool array_equals(const t_a1 & arr1, const t_a2 & arr2) {
const t_size s = array_size_t(arr1);
if (s != array_size_t(arr2)) return false;
for(t_size walk = 0; walk < s; ++walk) {
if (arr1[walk] != arr2[walk]) return false;
}
return true;
}
template<typename t_item, template<typename> class t_alloc = alloc_standard> class array_2d_t {
public:
array_2d_t() : m_d1(), m_d2() {}
void set_size(t_size d1, t_size d2) {
m_content.set_size(pfc::mul_safe_t<std::bad_alloc>(d1, d2));
m_d1 = d1; m_d2 = d2;
}
t_size get_dim1() const {return m_d1;}
t_size get_dim2() const {return m_d2;}
t_item & at(t_size i1, t_size i2) {
return * _transformPtr(m_content.get_ptr(), i1, i2);
}
const t_item & at(t_size i1, t_size i2) const {
return * _transformPtr(m_content.get_ptr(), i1, i2);
}
template<typename t_filler> void fill(const t_filler & p_filler) {m_content.fill(p_filler);}
void fill_null() {m_content.fill_null();}
t_item * rowPtr(t_size i1) {return _transformPtr(m_content.get_ptr(), i1, 0);}
const t_item * rowPtr(t_size i1) const {return _transformPtr(m_content.get_ptr(), i1, 0);}
const t_item * operator[](t_size i1) const {return rowPtr(i1);}
t_item * operator[](t_size i1) {return rowPtr(i1);}
private:
template<typename t_ptr> t_ptr _transformPtr(t_ptr ptr, t_size i1, t_size i2) const {
PFC_ASSERT( i1 < m_d1 ); PFC_ASSERT( i2 < m_d2 );
return ptr + i1 * m_d2 + i2;
}
pfc::array_t<t_item, t_alloc> m_content;
t_size m_d1, m_d2;
};
}

141
pfc/audio_math.cpp Normal file
View File

@@ -0,0 +1,141 @@
#include "pfc.h"
static audio_sample noopt_calculate_peak(const audio_sample * p_src,t_size p_num)
{
audio_sample peak = 0;
t_size num = p_num;
for(;num;num--)
{
audio_sample temp = (audio_sample)fabs(*(p_src++));
if (temp>peak) peak = temp;
}
return peak;
}
static void noopt_convert_to_32bit(const audio_sample * p_source,t_size p_count,t_int32 * p_output,float p_scale)
{
t_size num = p_count;
for(;num;--num)
{
t_int64 val = pfc::audio_math::rint64( *(p_source++) * p_scale );
if (val < -2147483648ll) val = -2147483648ll;
else if (val > 0x7FFFFFFF) val = 0x7FFFFFFF;
*(p_output++) = (t_int32) val;
}
}
inline static void noopt_convert_to_16bit(const audio_sample * p_source,t_size p_count,t_int16 * p_output,float p_scale) {
for(t_size n=0;n<p_count;n++) {
*(p_output++) = (t_int16) pfc::clip_t(pfc::audio_math::rint32(*(p_source++)*p_scale),-0x8000,0x7FFF);
}
}
inline static void noopt_convert_from_int16(const t_int16 * __restrict p_source,t_size p_count, audio_sample * __restrict p_output,float p_scale)
{
t_size num = p_count;
for(;num;num--)
*(p_output++) = (audio_sample)*(p_source++) * p_scale;
}
inline static void noopt_convert_from_int32(const t_int32 * __restrict p_source,t_size p_count,audio_sample * __restrict p_output,float p_scale)
{
t_size num = p_count;
for(;num;num--)
*(p_output++) = (audio_sample)*(p_source++) * p_scale;
}
inline static void noopt_scale(const audio_sample * p_source,t_size p_count,audio_sample * p_output,audio_sample p_scale)
{
for(t_size n=0;n<p_count;n++)
p_output[n] = p_source[n] * p_scale;
}
namespace pfc {
void audio_math::scale(const audio_sample * p_source,t_size p_count,audio_sample * p_output,audio_sample p_scale)
{
noopt_scale(p_source,p_count,p_output,p_scale);
}
void audio_math::convert_to_int16(const audio_sample * p_source,t_size p_count,t_int16 * p_output,audio_sample p_scale)
{
audio_sample scale = (audio_sample)(p_scale * 0x8000);
noopt_convert_to_16bit(p_source,p_count,p_output,scale);
}
audio_sample audio_math::convert_to_int16_calculate_peak(const audio_sample * p_source,t_size p_count,t_int16 * p_output,audio_sample p_scale)
{
//todo?
convert_to_int16(p_source,p_count,p_output,p_scale);
return p_scale * calculate_peak(p_source,p_count);
}
void audio_math::convert_from_int16(const t_int16 * p_source,t_size p_count,audio_sample * p_output,audio_sample p_scale)
{
audio_sample scale = (audio_sample) ( p_scale / (double) 0x8000 );
noopt_convert_from_int16(p_source,p_count,p_output,scale);
}
void audio_math::convert_to_int32(const audio_sample * p_source,t_size p_count,t_int32 * p_output,audio_sample p_scale)
{
audio_sample scale = (audio_sample)(p_scale * 0x80000000ul);
{
noopt_convert_to_32bit(p_source,p_count,p_output,scale);
}
}
audio_sample audio_math::convert_to_int32_calculate_peak(const audio_sample * p_source,t_size p_count,t_int32 * p_output,audio_sample p_scale)
{
convert_to_int32(p_source,p_count,p_output,p_scale);
return p_scale * calculate_peak(p_source,p_count);
}
void audio_math::convert_from_int32(const t_int32 * p_source,t_size p_count,audio_sample * p_output,audio_sample p_scale)
{
audio_sample scale = (audio_sample) ( p_scale / (double) 0x80000000ul );
noopt_convert_from_int32(p_source,p_count,p_output,scale);
}
audio_sample audio_math::calculate_peak(const audio_sample * p_source,t_size p_count)
{
return noopt_calculate_peak(p_source,p_count);
}
void audio_math::remove_denormals(audio_sample * p_buffer,t_size p_count) {
#if audio_sample_size == 32
t_uint32 * ptr = reinterpret_cast<t_uint32*>(p_buffer);
for(;p_count;p_count--)
{
t_uint32 t = *ptr;
if ((t & 0x007FFFFF) && !(t & 0x7F800000)) *ptr=0;
ptr++;
}
#elif audio_sample_size == 64
t_uint64 * ptr = reinterpret_cast<t_uint64*>(p_buffer);
for(;p_count;p_count--)
{
t_uint64 t = *ptr;
if ((t & 0x000FFFFFFFFFFFFF) && !(t & 0x7FF0000000000000)) *ptr=0;
ptr++;
}
#else
#error unsupported
#endif
}
void audio_math::add_offset(audio_sample * p_buffer,audio_sample p_delta,t_size p_count) {
for(t_size n=0;n<p_count;n++) {
p_buffer[n] += p_delta;
}
}
const audio_sample audio_math::float16scale = 65536.f;
}

73
pfc/audio_sample.cpp Normal file
View File

@@ -0,0 +1,73 @@
#include "pfc.h"
namespace pfc {
audio_sample audio_math::decodeFloat24ptr(const void * sourcePtr) {
PFC_STATIC_ASSERT(pfc::byte_order_is_little_endian);
union {
uint8_t bytes[4];
float v;
} u;
const uint8_t * s = reinterpret_cast<const uint8_t*>(sourcePtr);
u.bytes[0] = 0;
u.bytes[1] = s[0];
u.bytes[2] = s[1];
u.bytes[3] = s[2];
return u.v;
}
audio_sample audio_math::decodeFloat24ptrbs(const void * sourcePtr) {
PFC_STATIC_ASSERT(pfc::byte_order_is_little_endian);
union {
uint8_t bytes[4];
float v;
} u;
const uint8_t * s = reinterpret_cast<const uint8_t*>(sourcePtr);
u.bytes[0] = 0;
u.bytes[1] = s[2];
u.bytes[2] = s[1];
u.bytes[3] = s[0];
return u.v;
}
audio_sample audio_math::decodeFloat16(uint16_t source) {
const unsigned fractionBits = 10;
const unsigned widthBits = 16;
typedef uint16_t source_t;
/* typedef uint64_t out_t; typedef double retval_t;
enum {
outExponent = 11,
outFraction = 52,
outExponentShift = (1 << (outExponent-1))-1
};*/
typedef uint32_t out_t; typedef float retval_t;
enum {
outExponent = 8,
outFraction = 23,
outExponentShift = (1 << (outExponent-1))-1
};
const unsigned exponentBits = widthBits - fractionBits - 1;
// 1 bit sign | exponent | fraction
source_t fraction = source & (((source_t)1 << fractionBits)-1);
source >>= fractionBits;
int exponent = (int)( source & (((source_t)1 << exponentBits)-1) ) - (int)((1 << (exponentBits-1))-1);
source >>= exponentBits;
if (outExponent + outExponentShift <= 0) return 0;
out_t output = (out_t)( source&1 );
output <<= outExponent;
output |= (unsigned) (exponent + outExponentShift) & ( (1<<outExponent) - 1 );
output <<= outFraction;
int shift = (int) outFraction - (int) fractionBits;
if (shift < 0) output |= (out_t) (fraction >> -shift);
else output |= (out_t) (fraction << shift);
return *(retval_t*)&output / pfc::audio_math::float16scale;
}
unsigned audio_math::bitrate_kbps(uint64_t fileSize, double duration) {
if (fileSize > 0 && duration > 0) return (unsigned)floor((double)fileSize * 8 / (duration * 1000) + 0.5);
return 0;
}
}

92
pfc/audio_sample.h Normal file
View File

@@ -0,0 +1,92 @@
#pragma once
#include <math.h>
#define audio_sample_size 32
#if audio_sample_size == 32
typedef float audio_sample;
#define audio_sample_asm dword
#elif audio_sample_size == 64
typedef double audio_sample;
#define audio_sample_asm qword
#else
#error wrong audio_sample_size
#endif
#define audio_sample_bytes (audio_sample_size/8)
namespace pfc {
// made a class so it can be redirected to an alternate class more easily than with namespacing
// in win desktop fb2k these are implemented in a DLL
class audio_math {
public:
//! p_source/p_output can point to same buffer
static void scale(const audio_sample * p_source, t_size p_count, audio_sample * p_output, audio_sample p_scale);
static void convert_to_int16(const audio_sample * p_source, t_size p_count, t_int16 * p_output, audio_sample p_scale);
static void convert_to_int32(const audio_sample * p_source, t_size p_count, t_int32 * p_output, audio_sample p_scale);
static audio_sample convert_to_int16_calculate_peak(const audio_sample * p_source, t_size p_count, t_int16 * p_output, audio_sample p_scale);
static void convert_from_int16(const t_int16 * p_source, t_size p_count, audio_sample * p_output, audio_sample p_scale);
static void convert_from_int32(const t_int32 * p_source, t_size p_count, audio_sample * p_output, audio_sample p_scale);
static audio_sample convert_to_int32_calculate_peak(const audio_sample * p_source, t_size p_count, t_int32 * p_output, audio_sample p_scale);
static audio_sample calculate_peak(const audio_sample * p_source, t_size p_count);
static void remove_denormals(audio_sample * p_buffer, t_size p_count);
static void add_offset(audio_sample * p_buffer, audio_sample p_delta, t_size p_count);
static inline t_uint64 time_to_samples(double p_time, t_uint32 p_sample_rate) {
return (t_uint64)floor((double)p_sample_rate * p_time + 0.5);
}
static inline double samples_to_time(t_uint64 p_samples, t_uint32 p_sample_rate) {
PFC_ASSERT(p_sample_rate > 0);
return (double)p_samples / (double)p_sample_rate;
}
#if defined(_MSC_VER) && defined(_M_IX86)
inline static t_int64 rint64(audio_sample val) {
t_int64 rv;
_asm {
fld val;
fistp rv;
}
return rv;
}
#if defined(_M_IX86_FP) && _M_IX86_FP >= 1
static inline t_int32 rint32(float p_val) {
return (t_int32)_mm_cvtss_si32(_mm_load_ss(&p_val));
}
#else
inline static t_int32 rint32(audio_sample val) {
t_int32 rv;
_asm {
fld val;
fistp rv;
}
return rv;
}
#endif
#elif defined(_MSC_VER) && defined(_M_X64)
inline static t_int64 rint64(audio_sample val) { return (t_int64)floor(val + 0.5); }
static inline t_int32 rint32(float p_val) {
return (t_int32)_mm_cvtss_si32(_mm_load_ss(&p_val));
}
#else
inline static t_int64 rint64(audio_sample val) { return (t_int64)floor(val + 0.5); }
inline static t_int32 rint32(audio_sample val) { return (t_int32)floor(val + 0.5); }
#endif
static inline audio_sample gain_to_scale(double p_gain) { return (audio_sample)pow(10.0, p_gain / 20.0); }
static inline double scale_to_gain(double scale) { return 20.0*log10(scale); }
static const audio_sample float16scale;
static audio_sample decodeFloat24ptr(const void * sourcePtr);
static audio_sample decodeFloat24ptrbs(const void * sourcePtr);
static audio_sample decodeFloat16(uint16_t source);
static unsigned bitrate_kbps( uint64_t fileSize, double duration );
}; // class audio_math
} // namespace pfc

38
pfc/autoref.h Normal file
View File

@@ -0,0 +1,38 @@
#pragma once
#include <memory>
namespace pfc {
// autoref<> : turn arbitrary ptr that needs to be delete'd into a shared_ptr<> alike
template<typename obj_t> class autoref {
public:
autoref() {}
autoref(std::nullptr_t) {}
autoref(obj_t * source) {
attach(source);
}
void attach(obj_t * source) {
PFC_ASSERT( source != nullptr );
m_obj = std::make_shared<holder_t>(source);
}
void reset() {
m_obj.reset();
}
obj_t * operator->() const {
return m_obj->get_ptr();
}
obj_t * get() const {
if (! m_obj ) return nullptr;
return m_obj->get_ptr();
}
operator bool() const {
return !!m_obj;
}
private:
typedef pfc::ptrholder_t< obj_t > holder_t;
std::shared_ptr< holder_t > m_obj;
};
}

570
pfc/avltree.h Normal file
View File

@@ -0,0 +1,570 @@
#pragma once
namespace pfc {
template<typename t_storage>
class _avltree_node : public _list_node<t_storage> {
public:
typedef _list_node<t_storage> t_node;
typedef _avltree_node<t_storage> t_self;
template<typename t_param> _avltree_node(t_param const& param) : t_node(param), m_left(), m_right(), m_depth() {}
typedef refcounted_object_ptr_t<t_self> t_ptr;
typedef t_self* t_rawptr;
t_ptr m_left, m_right;
t_rawptr m_parent;
t_size m_depth;
void link_left(t_self* ptr) throw() {
m_left = ptr;
if (ptr != NULL) ptr->m_parent = this;
}
void link_right(t_self* ptr) throw() {
m_right = ptr;
if (ptr != NULL) ptr->m_parent = this;
}
void link_child(bool which,t_self* ptr) throw() {
(which ? m_right : m_left) = ptr;
if (ptr != NULL) ptr->m_parent = this;
}
void unlink() throw() {
m_left.release(); m_right.release(); m_parent = NULL; m_depth = 0;
}
inline void add_ref() throw() {this->refcount_add_ref();}
inline void release() throw() {this->refcount_release();}
inline t_rawptr child(bool which) const throw() {return which ? m_right.get_ptr() : m_left.get_ptr();}
inline bool which_child(const t_self* ptr) const throw() {return ptr == m_right.get_ptr();}
t_rawptr step(bool direction) throw() {
t_self* walk = this;
for(;;) {
t_self* t = walk->child(direction);
if (t != NULL) return t->peakchild(!direction);
for(;;) {
t = walk->m_parent;
if (t == NULL) return NULL;
if (t->which_child(walk) != direction) return t;
walk = t;
}
}
}
t_rawptr peakchild(bool direction) throw() {
t_self* walk = this;
for(;;) {
t_rawptr next = walk->child(direction);
if (next == NULL) return walk;
walk = next;
}
}
t_node * prev() throw() {return step(false);}
t_node * next() throw() {return step(true);}
private:
~_avltree_node() throw() {}
};
template<typename t_storage,typename t_comparator = comparator_default>
class avltree_t {
public:
typedef avltree_t<t_storage,t_comparator> t_self;
typedef pfc::const_iterator<t_storage> const_iterator;
typedef pfc::iterator<t_storage> iterator;
typedef t_storage t_item;
private:
typedef _avltree_node<t_storage> t_node;
#if 1//MSVC8 bug fix
typedef refcounted_object_ptr_t<t_node> t_nodeptr;
typedef t_node * t_noderawptr;
#else
typedef typename t_node::t_ptr t_nodeptr;
typedef typename t_node::t_rawptr t_noderawptr;
#endif
static bool is_ptr_valid(t_nodeptr const & p) { return p.is_valid(); }
static bool is_ptr_valid(t_node const * p) { return p != NULL; }
template<typename t_item1,typename t_item2>
inline static int compare(const t_item1 & p_item1, const t_item2 & p_item2) {
return t_comparator::compare(p_item1,p_item2);
}
t_nodeptr m_root;
static t_size calc_depth(const t_nodeptr & ptr)
{
return ptr.is_valid() ? 1+ptr->m_depth : 0;
}
static void recalc_depth(t_nodeptr const& ptr) {
ptr->m_depth = pfc::max_t(calc_depth(ptr->m_left), calc_depth(ptr->m_right));
}
static void assert_children(t_nodeptr ptr) {
PFC_ASSERT(ptr->m_depth == pfc::max_t(calc_depth(ptr->m_left),calc_depth(ptr->m_right)) );
}
static t_ssize test_depth(t_nodeptr const& ptr)
{
if (ptr==0) return 0;
else return calc_depth(ptr->m_right) - calc_depth(ptr->m_left);
}
static t_nodeptr extract_left_leaf(t_nodeptr & p_base) {
if (is_ptr_valid(p_base->m_left)) {
t_nodeptr ret = extract_left_leaf(p_base->m_left);
recalc_depth(p_base);
g_rebalance(p_base);
return ret;
} else {
t_nodeptr node = p_base;
p_base = node->m_right;
if (p_base.is_valid()) p_base->m_parent = node->m_parent;
node->m_right.release();
node->m_depth = 0;
node->m_parent = NULL;
return node;
}
}
static t_nodeptr extract_right_leaf(t_nodeptr & p_base) {
if (is_ptr_valid(p_base->m_right)) {
t_nodeptr ret = extract_right_leaf(p_base->m_right);
recalc_depth(p_base);
g_rebalance(p_base);
return ret;
} else {
t_nodeptr node = p_base;
p_base = node->m_left;
if (p_base.is_valid()) p_base->m_parent = node->m_parent;
node->m_left.release();
node->m_depth = 0;
node->m_parent = NULL;
return node;
}
}
static void remove_internal(t_nodeptr & p_node) {
t_nodeptr oldval = p_node;
if (p_node->m_left.is_empty()) {
p_node = p_node->m_right;
if (p_node.is_valid()) p_node->m_parent = oldval->m_parent;
} else if (p_node->m_right.is_empty()) {
p_node = p_node->m_left;
if (p_node.is_valid()) p_node->m_parent = oldval->m_parent;
} else {
t_nodeptr swap = extract_left_leaf(p_node->m_right);
swap->link_left(oldval->m_left.get_ptr());
swap->link_right(oldval->m_right.get_ptr());
swap->m_parent = oldval->m_parent;
recalc_depth(swap);
p_node = swap;
}
oldval->unlink();
}
template<typename t_nodewalk,typename t_callback>
static void __enum_items_recur(t_nodewalk * p_node,t_callback & p_callback) {
if (is_ptr_valid(p_node)) {
__enum_items_recur<t_nodewalk>(p_node->m_left.get_ptr(),p_callback);
p_callback (p_node->m_content);
__enum_items_recur<t_nodewalk>(p_node->m_right.get_ptr(),p_callback);
}
}
template<typename t_search>
static t_node * g_find_or_add_node(t_nodeptr & p_base,t_node * parent,t_search const & p_search,bool & p_new)
{
if (p_base.is_empty()) {
p_base = new t_node(p_search);
p_base->m_parent = parent;
p_new = true;
return p_base.get_ptr();
}
PFC_ASSERT( p_base->m_parent == parent );
int result = compare(p_base->m_content,p_search);
if (result > 0) {
t_node * ret = g_find_or_add_node<t_search>(p_base->m_left,p_base.get_ptr(),p_search,p_new);
PFC_ASSERT(compare(ret->m_content, p_search) == 0);
if (p_new) {
recalc_depth(p_base);
g_rebalance(p_base);
}
return ret;
} else if (result < 0) {
t_node * ret = g_find_or_add_node<t_search>(p_base->m_right,p_base.get_ptr(),p_search,p_new);
PFC_ASSERT(compare(ret->m_content, p_search) == 0);
if (p_new) {
recalc_depth(p_base);
g_rebalance(p_base);
}
return ret;
} else {
p_new = false;
return p_base.get_ptr();
}
}
template<typename t_search>
static t_storage * g_find_or_add(t_nodeptr & p_base,t_node * parent,t_search const & p_search,bool & p_new) {
return &g_find_or_add_node(p_base,parent,p_search,p_new)->m_content;
}
static void g_rotate_right(t_nodeptr & oldroot) {
t_nodeptr newroot ( oldroot->m_right );
oldroot->link_child(true, newroot->m_left.get_ptr());
newroot->m_left = oldroot;
newroot->m_parent = oldroot->m_parent;
oldroot->m_parent = newroot.get_ptr();
recalc_depth(oldroot);
recalc_depth(newroot);
oldroot = newroot;
}
static void g_rotate_left(t_nodeptr & oldroot) {
t_nodeptr newroot ( oldroot->m_left );
oldroot->link_child(false, newroot->m_right.get_ptr());
newroot->m_right = oldroot;
newroot->m_parent = oldroot->m_parent;
oldroot->m_parent = newroot.get_ptr();
recalc_depth(oldroot);
recalc_depth(newroot);
oldroot = newroot;
}
static void g_rebalance(t_nodeptr & p_node) {
t_ssize balance = test_depth(p_node);
if (balance > 1) {
//right becomes root
if (test_depth(p_node->m_right) < 0) {
g_rotate_left(p_node->m_right);
}
g_rotate_right(p_node);
} else if (balance < -1) {
//left becomes root
if (test_depth(p_node->m_left) > 0) {
g_rotate_right(p_node->m_left);
}
g_rotate_left(p_node);
}
selftest(p_node);
}
template<typename t_search>
static bool g_remove(t_nodeptr & p_node,t_search const & p_search) {
if (p_node.is_empty()) return false;
int result = compare(p_node->m_content,p_search);
if (result == 0) {
remove_internal(p_node);
if (is_ptr_valid(p_node)) {
recalc_depth(p_node);
g_rebalance(p_node);
}
return true;
} else {
if (g_remove<t_search>(result > 0 ? p_node->m_left : p_node->m_right,p_search)) {
recalc_depth(p_node);
g_rebalance(p_node);
return true;
} else {
return false;
}
}
}
static void selftest(t_nodeptr const& p_node) {
#if 0 //def _DEBUG//SLOW!
if (is_ptr_valid(p_node)) {
selftest(p_node->m_left);
selftest(p_node->m_right);
assert_children(p_node);
t_ssize delta = test_depth(p_node);
PFC_ASSERT(delta >= -1 && delta <= 1);
if (p_node->m_left.is_valid()) {
PFC_ASSERT( p_node.get_ptr() == p_node->m_left->m_parent );
}
if (p_node->m_right.is_valid()) {
PFC_ASSERT( p_node.get_ptr() == p_node->m_right->m_parent );
}
if (is_ptr_valid(p_node->m_parent)) {
PFC_ASSERT(p_node == p_node->m_parent->m_left || p_node == p_node->m_parent->m_right);
}
}
#endif
}
static t_size calc_count(const t_node * p_node) throw() {
if (is_ptr_valid(p_node)) {
return 1 + calc_count(p_node->m_left.get_ptr()) + calc_count(p_node->m_right.get_ptr());
} else {
return 0;
}
}
template<typename t_param>
t_storage * _find_item_ptr(t_param const & p_item) const {
t_node* ptr = m_root.get_ptr();
while(is_ptr_valid(ptr)) {
int result = compare(ptr->m_content,p_item);
if (result > 0) ptr=ptr->m_left.get_ptr();
else if (result < 0) ptr=ptr->m_right.get_ptr();
else return &ptr->m_content;
}
return NULL;
}
template<typename t_param>
t_node * _find_node_ptr(t_param const & p_item) const {
t_node* ptr = m_root.get_ptr();
while(is_ptr_valid(ptr)) {
int result = compare(ptr->m_content,p_item);
if (result > 0) ptr=ptr->m_left.get_ptr();
else if (result < 0) ptr=ptr->m_right.get_ptr();
else return ptr;
}
return NULL;
}
template<bool inclusive,bool above,typename t_search> t_storage * __find_nearest(const t_search & p_search) const {
t_node * ptr = m_root.get_ptr();
t_storage * found = NULL;
while(is_ptr_valid(ptr)) {
int result = compare(ptr->m_content,p_search);
if (above) result = -result;
if (inclusive && result == 0) {
//direct hit
found = &ptr->m_content;
break;
} else if (result < 0) {
//match
found = &ptr->m_content;
ptr = ptr->child(!above);
} else {
//mismatch
ptr = ptr->child(above);
}
}
return found;
}
public:
avltree_t() : m_root(NULL) {}
~avltree_t() {reset();}
const t_self & operator=(const t_self & p_other) {__copy(p_other);return *this;}
avltree_t(const t_self & p_other) : m_root(NULL) {try{__copy(p_other);} catch(...) {remove_all(); throw;}}
template<typename t_other> const t_self & operator=(const t_other & p_other) {copy_list_enumerated(*this,p_other);return *this;}
template<typename t_other> avltree_t(const t_other & p_other) : m_root(NULL) {try{copy_list_enumerated(*this,p_other);}catch(...){remove_all(); throw;}}
template<bool inclusive,bool above,typename t_search> const t_storage * find_nearest_item(const t_search & p_search) const {
return __find_nearest<inclusive,above>(p_search);
}
template<bool inclusive,bool above,typename t_search> t_storage * find_nearest_item(const t_search & p_search) {
return __find_nearest<inclusive,above>(p_search);
}
avltree_t( t_self && other ) {
m_root = std::move( other.m_root ); other.m_root.release();
}
const t_self & operator=( t_self && other ) {
move_from ( other ); return *this;
}
void move_from( t_self & other ) {
reset(); m_root = std::move( other.m_root ); other.m_root.release();
}
template<typename t_param>
t_storage & add_item(t_param const & p_item) {
bool dummy;
return add_item_ex(p_item,dummy);
}
template<typename t_param>
t_self & operator+=(const t_param & p_item) {add_item(p_item);return *this;}
template<typename t_param>
t_self & operator-=(const t_param & p_item) {remove_item(p_item);return *this;}
//! Returns true when the list has been altered, false when the item was already present before.
template<typename t_param>
bool add_item_check(t_param const & item) {
bool isNew = false;
g_find_or_add(m_root,NULL,item,isNew);
selftest(m_root);
return isNew;
}
template<typename t_param>
t_storage & add_item_ex(t_param const & p_item,bool & p_isnew) {
t_storage * ret = g_find_or_add(m_root,NULL,p_item,p_isnew);
selftest(m_root);
return *ret;
}
template<typename t_param>
void set_item(const t_param & p_item) {
bool isnew;
t_storage & found = add_item_ex(p_item,isnew);
if (isnew) found = p_item;
}
template<typename t_param>
const t_storage * find_item_ptr(t_param const & p_item) const {return _find_item_ptr(p_item);}
//! Unsafe! Caller must not modify items in a way that changes sort order!
template<typename t_param>
t_storage * find_item_ptr(t_param const & p_item) { return _find_item_ptr(p_item); }
template<typename t_param> const_iterator find(t_param const & item) const { return _find_node_ptr(item);}
//! Unsafe! Caller must not modify items in a way that changes sort order!
template<typename t_param> iterator find(t_param const & item) { return _find_node_ptr(item);}
template<typename t_param>
bool contains(const t_param & p_item) const {
return find_item_ptr(p_item) != NULL;
}
//! Same as contains().
template<typename t_param>
bool have_item(const t_param & p_item) const {return contains(p_item);}
void remove_all() throw() {
_unlink_recur(m_root);
m_root.release();
}
bool remove(const_iterator const& iter) {
PFC_ASSERT(iter.is_valid());
return remove_item(*iter);//OPTIMIZEME
//should never return false unless there's a bug in calling code
}
template<typename t_param>
bool remove_item(t_param const & p_item) {
bool ret = g_remove<t_param>(m_root,p_item);
selftest(m_root);
return ret;
}
t_size get_count() const throw() {
return calc_count(m_root.get_ptr());
}
template<typename t_callback>
void enumerate(t_callback & p_callback) const {
__enum_items_recur<const t_node>(m_root.get_ptr(),p_callback);
}
//! Allows callback to modify the tree content.
//! Unsafe! Caller must not modify items in a way that changes sort order!
template<typename t_callback>
void _enumerate_var(t_callback & p_callback) { __enum_items_recur<t_node>(m_root.get_ptr(),p_callback); }
template<typename t_param> iterator insert(const t_param & p_item) {
bool isNew;
t_node * ret = g_find_or_add_node(m_root,NULL,p_item,isNew);
selftest(m_root);
return ret;
}
//deprecated backwards compatibility method wrappers
template<typename t_param> t_storage & add(const t_param & p_item) {return add_item(p_item);}
template<typename t_param> t_storage & add_ex(const t_param & p_item,bool & p_isnew) {return add_item_ex(p_item,p_isnew);}
template<typename t_param> const t_storage * find_ptr(t_param const & p_item) const {return find_item_ptr(p_item);}
template<typename t_param> t_storage * find_ptr(t_param const & p_item) {return find_item_ptr(p_item);}
template<typename t_param> bool exists(t_param const & p_item) const {return have_item(p_item);}
void reset() {remove_all();}
const_iterator first() const throw() {return _firstlast(false);}
const_iterator last() const throw() {return _firstlast(true);}
//! Unsafe! Caller must not modify items in a way that changes sort order!
iterator _first_var() { return _firstlast(false); }
//! Unsafe! Caller must not modify items in a way that changes sort order!
iterator _last_var() { return _firstlast(true); }
const_iterator cfirst() const throw() {return _firstlast(false);}
const_iterator clast() const throw() {return _firstlast(true);}
template<typename t_param> bool get_first(t_param & p_item) const throw() {
const_iterator iter = first();
if (!iter.is_valid()) return false;
p_item = *iter;
return true;
}
template<typename t_param> bool get_last(t_param & p_item) const throw() {
const_iterator iter = last();
if (!iter.is_valid()) return false;
p_item = *iter;
return true;
}
static bool equals(const t_self & v1, const t_self & v2) {
return listEquals(v1,v2);
}
bool operator==(const t_self & other) const {return equals(*this,other);}
bool operator!=(const t_self & other) const {return !equals(*this,other);}
private:
static void _unlink_recur(t_nodeptr & node) {
if (node.is_valid()) {
_unlink_recur(node->m_left);
_unlink_recur(node->m_right);
node->unlink();
}
}
t_node* _firstlast(bool which) const throw() {
if (m_root.is_empty()) return NULL;
for(t_node * walk = m_root.get_ptr(); ; ) {
t_node * next = walk->child(which);
if (next == NULL) return walk;
PFC_ASSERT( next->m_parent == walk );
walk = next;
}
}
static t_nodeptr __copy_recur(t_node * p_source,t_node * parent) {
if (p_source == NULL) {
return NULL;
} else {
t_nodeptr newnode = new t_node(p_source->m_content);
newnode->m_depth = p_source->m_depth;
newnode->m_left = __copy_recur(p_source->m_left.get_ptr(),newnode.get_ptr());
newnode->m_right = __copy_recur(p_source->m_right.get_ptr(),newnode.get_ptr());
newnode->m_parent = parent;
return newnode;
}
}
void __copy(const t_self & p_other) {
reset();
m_root = __copy_recur(p_other.m_root.get_ptr(),NULL);
selftest(m_root);
}
};
template<typename t_storage,typename t_comparator>
class traits_t<avltree_t<t_storage,t_comparator> > : public traits_default_movable {};
}

118
pfc/base64.cpp Normal file
View File

@@ -0,0 +1,118 @@
#include "pfc.h"
namespace bitWriter {
static void set_bit(t_uint8 * p_stream,size_t p_offset, bool state) {
t_uint8 mask = 1 << (7-(p_offset&7));
t_uint8 & byte = p_stream[p_offset>>3];
byte = (byte & ~mask) | (state ? mask : 0);
}
static void set_bits(t_uint8 * stream, t_size offset, t_size word, t_size bits) {
for(t_size walk = 0; walk < bits; ++walk) {
t_uint8 bit = (t_uint8)((word >> (bits - walk - 1))&1);
set_bit(stream, offset+walk, bit != 0);
}
}
};
namespace pfc {
static const char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const uint8_t alphabetRev[256] =
{0x40,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3E,0xFF,0xFF,0xFF,0x3F
,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
,0xFF,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E
,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0xFF,0xFF,0xFF,0xFF,0xFF
,0xFF,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28
,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0xFF,0xFF,0xFF,0xFF,0xFF
,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
};
size_t base64_strlen( const char * text ) {
size_t ret = 0;
for ( size_t w = 0; ;++w ) {
uint8_t c = (uint8_t) text[w];
if (c == 0) break;
if ( alphabetRev[c] != 0xFF ) ++ret;
}
return ret;
}
t_size base64_decode_estimate(const char * text) {
t_size textLen = base64_strlen(text);
return textLen * 3 / 4;
}
void base64_decode(const char * text, void * out) {
size_t outWritePtr = 0;
size_t inTemp = 0;
uint8_t temp[3];
for ( size_t textWalk = 0 ; ; ++ textWalk ) {
const uint8_t c = (uint8_t) text[textWalk];
if (c == 0) break;
const uint8_t v = alphabetRev[ c ];
if ( v != 0xFF ) {
PFC_ASSERT( inTemp + 6 <= 24 );
bitWriter::set_bits(temp,inTemp,v,6);
inTemp += 6;
if ( inTemp == 24 ) {
memcpy( (uint8_t*) out + outWritePtr, temp, 3 );
outWritePtr += 3;
inTemp = 0;
}
}
}
if ( inTemp > 0 ) {
size_t delta = inTemp / 8;
memcpy( (uint8_t*) out + outWritePtr, temp, delta );
outWritePtr += delta;
inTemp = 0;
}
#if PFC_DEBUG
size_t estimated = base64_decode_estimate( text ) ;
PFC_ASSERT( outWritePtr == estimated );
#endif
}
void base64_encode(pfc::string_base & out, const void * in, t_size inSize) {
out.reset(); base64_encode_append(out, in, inSize);
}
void base64_encode_append(pfc::string_base & out, const void * in, t_size inSize) {
int shift = 0;
int accum = 0;
const t_uint8 * inPtr = reinterpret_cast<const t_uint8*>(in);
for(t_size walk = 0; walk < inSize; ++walk) {
accum <<= 8;
shift += 8;
accum |= inPtr[walk];
while ( shift >= 6 ) {
shift -= 6;
out << format_char( alphabet[(accum >> shift) & 0x3F] );
}
}
if (shift == 4) {
out << format_char( alphabet[(accum & 0xF)<<2] ) << "=";
} else if (shift == 2) {
out << format_char( alphabet[(accum & 0x3)<<4] ) << "==";
}
}
void base64_decode_to_string( pfc::string_base & out, const char * text ) {
char * ptr = out.lock_buffer( base64_decode_estimate( text ) );
base64_decode(text, ptr);
out.unlock_buffer();
}
void base64_encode_from_string( pfc::string_base & out, const char * in ) {
base64_encode( out, in, strlen(in) );
}
}

18
pfc/base64.h Normal file
View File

@@ -0,0 +1,18 @@
#pragma once
namespace pfc {
class string_base;
void base64_encode(pfc::string_base & out, const void * in, t_size inSize);
void base64_encode_append(pfc::string_base & out, const void * in, t_size inSize);
void base64_encode_from_string( pfc::string_base & out, const char * in );
t_size base64_decode_estimate(const char * text);
void base64_decode(const char * text, void * out);
template<typename t_buffer> void base64_decode_array(t_buffer & out, const char * text) {
PFC_STATIC_ASSERT( sizeof(out[0]) == 1 );
out.set_size_discard( base64_decode_estimate(text) );
base64_decode(text, out.get_ptr());
}
void base64_decode_to_string( pfc::string_base & out, const char * text );
}

83
pfc/binary_search.h Normal file
View File

@@ -0,0 +1,83 @@
#pragma once
namespace pfc {
class comparator_default;
template<typename t_comparator = comparator_default>
class binarySearch {
public:
template<typename t_container,typename t_param>
static bool run(const t_container & p_container,t_size p_base,t_size p_count,const t_param & p_param,t_size & p_result) {
t_size max = p_base + p_count;
t_size min = p_base;
while(min<max) {
t_size ptr = min + ( (max-min) >> 1);
int state = t_comparator::compare(p_param,p_container[ptr]);
if (state > 0) min = ptr + 1;
else if (state < 0) max = ptr;
else {
p_result = ptr;
return true;
}
}
p_result = min;
return false;
}
template<typename t_container,typename t_param>
static bool runGroupBegin(const t_container & p_container,t_size p_base,t_size p_count,const t_param & p_param,t_size & p_result) {
t_size max = p_base + p_count;
t_size min = p_base;
bool found = false;
while(min<max) {
t_size ptr = min + ( (max-min) >> 1);
int state = t_comparator::compare(p_param,p_container[ptr]);
if (state > 0) min = ptr + 1;
else if (state < 0) max = ptr;
else {
found = true; max = ptr;
}
}
p_result = min;
return found;
}
template<typename t_container,typename t_param>
static bool runGroupEnd(const t_container & p_container,t_size p_base,t_size p_count,const t_param & p_param,t_size & p_result) {
t_size max = p_base + p_count;
t_size min = p_base;
bool found = false;
while(min<max) {
t_size ptr = min + ( (max-min) >> 1);
int state = t_comparator::compare(p_param,p_container[ptr]);
if (state > 0) min = ptr + 1;
else if (state < 0) max = ptr;
else {
found = true; min = ptr + 1;
}
}
p_result = min;
return found;
}
template<typename t_container,typename t_param>
static bool runGroup(const t_container & p_container,t_size p_base,t_size p_count,const t_param & p_param,t_size & p_result,t_size & p_resultCount) {
if (!runGroupBegin(p_container,p_base,p_count,p_param,p_result)) {
p_resultCount = 0;
return false;
}
t_size groupEnd;
if (!runGroupEnd(p_container,p_result,p_count - p_result,p_param,groupEnd)) {
//should not happen..
PFC_ASSERT(0);
p_resultCount = 0;
return false;
}
PFC_ASSERT(groupEnd > p_result);
p_resultCount = groupEnd - p_result;
return true;
}
};
};

182
pfc/bit_array.cpp Normal file
View File

@@ -0,0 +1,182 @@
#include "pfc.h"
namespace pfc {
void bit_array::for_each(bool value, size_t base, size_t max, std::function<void(size_t)> f) const {
for( size_t idx = find_first(value, base, max); idx < max; idx = find_next(value, idx, max) ) {
f(idx);
}
}
t_size bit_array::find(bool val, t_size start, t_ssize count) const
{
t_ssize d, todo, ptr = start;
if (count == 0) return start;
else if (count<0) { d = -1; todo = -count; }
else { d = 1; todo = count; }
while (todo>0 && get(ptr) != val) { ptr += d;todo--; }
return ptr;
}
t_size bit_array::calc_count(bool val, t_size start, t_size count, t_size count_max) const
{
t_size found = 0;
t_size max = start + count;
t_size ptr;
for (ptr = find(val, start, count);found<count_max && ptr<max;ptr = find(val, ptr + 1, max - ptr - 1)) found++;
return found;
}
t_size bit_array::find_first(bool val, t_size start, t_size max) const {
return find(val, start, max - start);
}
t_size bit_array::find_next(bool val, t_size previous, t_size max) const {
return find(val, previous + 1, max - (previous + 1));
}
void bit_array::walk(size_t to, std::function< void ( size_t ) > f, bool val ) const {
for ( size_t w = find_first(val, 0, to ); w < to; w = find_next(val, w, to) ) {
f(w);
}
}
void bit_array::walkBack(size_t from, std::function<void (size_t) > f, bool val) const {
t_ssize walk = from;
if ( walk == 0 ) return;
for( ;; ) {
walk = find(val, walk-1, - walk );
if ( walk < 0 ) return;
f ( walk );
}
}
bit_array_var_impl::bit_array_var_impl( const bit_array & source, size_t sourceCount) {
for(size_t w = source.find_first( true, 0, sourceCount); w < sourceCount; w = source.find_next( true, w, sourceCount ) ) {
set(w, true);
}
}
bool bit_array_var_impl::get(t_size n) const {
return m_data.have_item(n);
}
t_size bit_array_var_impl::find(bool val,t_size start,t_ssize count) const {
if (!val) {
return bit_array::find(false, start, count); //optimizeme.
} else if (count > 0) {
const t_size * v = m_data.find_nearest_item<true, true>(start);
if (v == NULL || *v > start+count) return start + count;
return *v;
} else if (count < 0) {
const t_size * v = m_data.find_nearest_item<true, false>(start);
if (v == NULL || *v < start+count) return start + count;
return *v;
} else return start;
}
void bit_array_var_impl::set(t_size n,bool val) {
if (val) m_data += n;
else m_data -= n;
}
bit_array_flatIndexList::bit_array_flatIndexList() {
m_content.prealloc( 1024 );
}
void bit_array_flatIndexList::add( size_t n ) {
m_content.append_single_val( n );
}
bool bit_array_flatIndexList::get(t_size n) const {
size_t dummy;
return _find( n, dummy );
}
t_size bit_array_flatIndexList::find(bool val,t_size start,t_ssize count) const {
if (val == false) {
// unoptimized but not really used
return bit_array::find(val, start, count);
}
if (count==0) return start;
else if (count<0) {
size_t idx;
if (!_findNearestDown( start, idx ) || (t_ssize)m_content[idx] < (t_ssize)start+count) return start + count;
return m_content[idx];
} else { // count > 0
size_t idx;
if (!_findNearestUp( start, idx ) || m_content[idx] > start+count) return start + count;
return m_content[idx];
}
}
bool bit_array_flatIndexList::_findNearestUp( size_t val, size_t & outIdx ) const {
size_t idx;
if (_find( val, idx )) { outIdx = idx; return true; }
// we have a valid outIdx at where the bsearch gave up
PFC_ASSERT ( idx == 0 || m_content [ idx - 1 ] < val );
PFC_ASSERT ( idx == m_content.get_size() || m_content[ idx ] > val );
if (idx == m_content.get_size()) return false;
outIdx = idx;
return true;
}
bool bit_array_flatIndexList::_findNearestDown( size_t val, size_t & outIdx ) const {
size_t idx;
if (_find( val, idx )) { outIdx = idx; return true; }
// we have a valid outIdx at where the bsearch gave up
PFC_ASSERT ( idx == 0 || m_content [ idx - 1 ] < val );
PFC_ASSERT ( idx == m_content.get_size() || m_content[ idx ] > val );
if (idx == 0) return false;
outIdx = idx - 1;
return true;
}
void bit_array_flatIndexList::presort() {
pfc::sort_t( m_content, pfc::compare_t< size_t, size_t >, m_content.get_size( ) );
}
bit_array_bittable::bit_array_bittable(const pfc::bit_array & in, size_t inSize) : m_count() {
resize(inSize);
for (size_t w = in.find_first(true, 0, inSize); w < inSize; w = in.find_next(true, w, inSize)) {
set(w, true);
}
}
void bit_array_bittable::resize(t_size p_count)
{
t_size old_bytes = g_estimate_size(m_count);
m_count = p_count;
t_size bytes = g_estimate_size(m_count);
m_data.set_size(bytes);
if (bytes > old_bytes) pfc::memset_null_t(m_data.get_ptr() + old_bytes, bytes - old_bytes);
}
void bit_array_bittable::set(t_size n, bool val)
{
if (n<m_count)
{
g_set(m_data, n, val);
}
}
bool bit_array_bittable::get(t_size n) const
{
bool rv = false;
if (n<m_count) {
rv = g_get(m_data, n);
}
return rv;
}
t_size bit_array_one::find(bool p_val, t_size start, t_ssize count) const
{
if (count == 0) return start;
else if (p_val)
{
if (count>0)
return (val >= start && (t_ssize)val < (t_ssize)start + count) ? val : start + count;
else
return (val <= start && (t_ssize)val > (t_ssize)start + count) ? val : start + count;
}
else
{
if (start == val) return count>0 ? start + 1 : start - 1;
else return start;
}
}
} // namespace pfc

69
pfc/bit_array.h Normal file
View File

@@ -0,0 +1,69 @@
#pragma once
#include <functional>
namespace pfc {
//! Bit array interface class, constant version (you can only retrieve values). \n
//! Range of valid indexes depends on the context. When passing a bit_array as a parameter to some code, valid index range must be signaled independently.
class NOVTABLE bit_array {
public:
virtual bool get(t_size n) const = 0;
//! Returns the first occurance of val between start and start+count (excluding start+count), or start+count if not found; count may be negative to search back rather than forward. \n
//! Can be overridden by bit_array implementations for improved speed in specific cases.
virtual t_size find(bool val, t_size start, t_ssize count) const;
bool operator[](t_size n) const { return get(n); }
t_size calc_count(bool val, t_size start, t_size count, t_size count_max = ~0) const;//counts number of vals for start<=n<start+count
t_size find_first(bool val, t_size start, t_size max) const;
t_size find_next(bool val, t_size previous, t_size max) const;
void for_each( bool value, size_t base, size_t max, std::function<void(size_t)> f) const;
void walk(size_t to, std::function< void ( size_t ) > f, bool val = true ) const;
void walkBack(size_t from, std::function< void ( size_t ) > f, bool val = true ) const;
protected:
bit_array() {}
~bit_array() {}
};
//! Minimal lambda-based bit_array implementation, no find(), only get().
class bit_array_lambda : public bit_array {
public:
typedef std::function<bool (size_t)> f_t;
f_t f;
bit_array_lambda( f_t f_ ) : f(f_) { }
bool get(t_size n) const {return f(n);}
};
//! Bit array interface class, variable version (you can both set and retrieve values). \n
//! As with the constant version, valid index range depends on the context.
class NOVTABLE bit_array_var : public bit_array {
public:
virtual void set(t_size n,bool val)=0;
protected:
bit_array_var() {}
~bit_array_var() {}
};
class bit_array_wrapper_permutation : public bit_array {
public:
bit_array_wrapper_permutation(const t_size * p_permutation, t_size p_size) : m_permutation(p_permutation), m_size(p_size) {}
bool get(t_size n) const {
if (n < m_size) {
return m_permutation[n] != n;
} else {
return false;
}
}
private:
const t_size * const m_permutation;
const t_size m_size;
};
}
#define PFC_FOR_EACH_INDEX( bitArray, var, count ) \
for( size_t var = (bitArray).find_first( true, 0, (count) ); var < (count); var = (bitArray).find_next( true, var, (count) ) )

200
pfc/bit_array_impl.h Normal file
View File

@@ -0,0 +1,200 @@
#pragma once
namespace pfc {
template<typename T>
class bit_array_table_t : public bit_array
{
const T * data;
t_size count;
bool after;
public:
inline bit_array_table_t(const T * p_data,t_size p_count,bool p_after = false)
: data(p_data), count(p_count), after(p_after)
{
}
bool get(t_size n) const
{
if (n<count) return !!data[n];
else return after;
}
};
template<class T>
class bit_array_var_table_t : public bit_array_var
{
T * data;
t_size count;
bool after;
public:
inline bit_array_var_table_t(T * p_data,t_size p_count,bool p_after = false)
: data(p_data), count(p_count), after(p_after)
{
}
bool get(t_size n) const {
if (n<count) return !!data[n];
else return after;
}
void set(t_size n,bool val) {
if (n<count) data[n] = !!val;
}
};
typedef bit_array_table_t<bool> bit_array_table;
typedef bit_array_var_table_t<bool> bit_array_var_table;
class bit_array_range : public bit_array
{
t_size begin,end;
bool state;
public:
bit_array_range(t_size first,t_size count,bool p_state = true) : begin(first), end(first+count), state(p_state) {}
bool get(t_size n) const
{
bool rv = n>=begin && n<end;
if (!state) rv = !rv;
return rv;
}
};
//! Combines two arrays using the AND logical operator. \n
//! Valid index range is an intersection of valid index ranges of the parameter arrays.
class bit_array_and : public bit_array
{
const bit_array & a1, & a2;
public:
bit_array_and(const bit_array & p_a1, const bit_array & p_a2) : a1(p_a1), a2(p_a2) {}
bool get(t_size n) const {return a1.get(n) && a2.get(n);}
};
//! Combines two arrays using the OR logical operator. \n
//! Valid index range is an intersection of valid index ranges of the parameter arrays.
class bit_array_or : public bit_array
{
const bit_array & a1, & a2;
public:
bit_array_or(const bit_array & p_a1, const bit_array & p_a2) : a1(p_a1), a2(p_a2) {}
bool get(t_size n) const {return a1.get(n) || a2.get(n);}
};
//! Combines two arrays using the XOR logical operator. \n
//! Valid index range is an intersection of valid index ranges of the parameter arrays.
class bit_array_xor : public bit_array
{
const bit_array & a1, & a2;
public:
bit_array_xor(const bit_array & p_a1, const bit_array & p_a2) : a1(p_a1), a2(p_a2) {}
bool get(t_size n) const
{
bool v1 = a1.get(n), v2 = a2.get(n);
return (v1 && !v2) || (!v1 && v2);
}
};
//! Negation of another array. \n
//! Valid index range is the same as valid index range of the parameter array.
class bit_array_not : public bit_array
{
const bit_array & a1;
public:
bit_array_not(const bit_array & p_a1) : a1(p_a1) {}
bool get(t_size n) const {return !a1.get(n);}
t_size find(bool val,t_size start,t_ssize count) const
{return a1.find(!val,start,count);}
};
class bit_array_true : public bit_array
{
public:
bool get(t_size) const {return true;}
t_size find(bool val,t_size start,t_ssize count) const
{return val ? start : start+count;}
};
class bit_array_false : public bit_array
{
public:
bool get(t_size) const {return false;}
t_size find(bool val,t_size start,t_ssize count) const
{return val ? start+count : start;}
};
class bit_array_val : public bit_array
{
bool val;
public:
bit_array_val(bool v) : val(v) {}
bool get(t_size) const {return val;}
t_size find(bool p_val,t_size start,t_ssize count) const
{return val==p_val ? start : start+count;}
};
class bit_array_one : public bit_array
{
t_size val;
public:
bit_array_one(t_size p_val) : val(p_val) {}
virtual bool get(t_size n) const {return n==val;}
virtual t_size find(bool p_val, t_size start, t_ssize count) const;
};
//! Generic variable bit_array implementation. \n
//! Needs to be initialized with requested array size before use.
class bit_array_bittable : public bit_array_var
{
pfc::array_t<t_uint8> m_data;
t_size m_count;
public:
//helpers
template<typename t_array>
inline static bool g_get(const t_array & p_array,t_size idx)
{
return !! (p_array[idx>>3] & (1<<(idx&7)));
}
template<typename t_array>
inline static void g_set(t_array & p_array,t_size idx,bool val)
{
unsigned char & dst = p_array[idx>>3];
unsigned char mask = 1<<(idx&7);
dst = val ? dst|mask : dst&~mask;
}
inline static t_size g_estimate_size(t_size p_count) {return (p_count+7)>>3;}
void resize(t_size p_count);
bit_array_bittable(t_size p_count) : m_count(0) {resize(p_count);}
bit_array_bittable(const pfc::bit_array & in, size_t inSize);
bit_array_bittable() : m_count() {}
void set(t_size n, bool val);
bool get(t_size n) const;
size_t size() const {return m_count;}
};
//! Bit array that takes a permutation and signals indexes reordered by the permutation. \n
//! Valid index range same as length of the permutation.
class bit_array_order_changed : public bit_array {
public:
bit_array_order_changed(const t_size * p_order) : m_order(p_order) {}
bool get(t_size n) const
{
return m_order[n] != n;
}
private:
const t_size * m_order;
};
}
// #define for_each_bit_array(var,mask,val,start,count) for(var = mask.find(val,start,count);var<start+count;var=mask.find(val,var+1,count-(var+1-start)))

View File

@@ -0,0 +1,47 @@
#pragma once
namespace pfc {
//! Generic variable bit array implementation. \n
//! Not very efficient to handle lots of items set to true but offers fast searches for true values and accepts arbitrary indexes, contrary to bit_array_bittable. Note that searches for false values are relatively inefficient.
class bit_array_var_impl : public bit_array_var {
public:
bit_array_var_impl( ) {}
bit_array_var_impl( const bit_array & source, size_t sourceCount);
bool get(t_size n) const;
t_size find(bool val,t_size start,t_ssize count) const;
void set(t_size n,bool val);
void set(t_size n) {m_data += n;}
void unset(t_size n) {m_data -= n;}
t_size get_true_count() const {return m_data.get_count();}
void clear() {m_data.remove_all();}
private:
avltree_t<t_size> m_data;
};
//! Specialized implementation of bit_array. \n
//! Indended for scenarios where fast searching for true values in a large list is needed, combined with low footprint regardless of the amount of items.
//! Call add() repeatedly with the true val indexes. If the indexes were not added in increasing order, call presort() when done with adding.
class bit_array_flatIndexList : public bit_array {
public:
bit_array_flatIndexList();
void add( size_t n );
bool get(t_size n) const;
t_size find(bool val,t_size start,t_ssize count) const;
void presort();
size_t get_count() const { return m_content.get_size(); }
private:
bool _findNearestUp( size_t val, size_t & outIdx ) const;
bool _findNearestDown( size_t val, size_t & outIdx ) const;
bool _find( size_t val, size_t & outIdx ) const {
return pfc::bsearch_simple_inline_t( m_content, m_content.get_size(), val, outIdx);
}
pfc::array_t< size_t, pfc::alloc_fast > m_content;
};
}

19
pfc/bsearch.cpp Normal file
View File

@@ -0,0 +1,19 @@
#include "pfc.h"
//deprecated
/*
class NOVTABLE bsearch_callback
{
public:
virtual int test(t_size p_index) const = 0;
};
*/
namespace pfc {
bool bsearch(t_size p_count, bsearch_callback const & p_callback,t_size & p_result) {
return bsearch_inline_t(p_count,p_callback,p_result);
}
}

89
pfc/bsearch.h Normal file
View File

@@ -0,0 +1,89 @@
#pragma once
namespace pfc {
//deprecated
class NOVTABLE bsearch_callback
{
public:
virtual int test(t_size n) const = 0;
};
bool bsearch(t_size p_count, bsearch_callback const & p_callback,t_size & p_result);
template<typename t_container,typename t_compare, typename t_param>
class bsearch_callback_impl_simple_t : public bsearch_callback {
public:
int test(t_size p_index) const {
return m_compare(m_container[p_index],m_param);
}
bsearch_callback_impl_simple_t(const t_container & p_container,t_compare p_compare,const t_param & p_param)
: m_container(p_container), m_compare(p_compare), m_param(p_param)
{
}
private:
const t_container & m_container;
t_compare m_compare;
const t_param & m_param;
};
template<typename t_container,typename t_compare, typename t_param,typename t_permutation>
class bsearch_callback_impl_permutation_t : public bsearch_callback {
public:
int test(t_size p_index) const {
return m_compare(m_container[m_permutation[p_index]],m_param);
}
bsearch_callback_impl_permutation_t(const t_container & p_container,t_compare p_compare,const t_param & p_param,const t_permutation & p_permutation)
: m_container(p_container), m_compare(p_compare), m_param(p_param), m_permutation(p_permutation)
{
}
private:
const t_container & m_container;
t_compare m_compare;
const t_param & m_param;
const t_permutation & m_permutation;
};
template<typename t_container,typename t_compare, typename t_param>
bool bsearch_t(t_size p_count,const t_container & p_container,t_compare p_compare,const t_param & p_param,t_size & p_index) {
return bsearch(
p_count,
bsearch_callback_impl_simple_t<t_container,t_compare,t_param>(p_container,p_compare,p_param),
p_index);
}
template<typename t_container,typename t_compare,typename t_param,typename t_permutation>
bool bsearch_permutation_t(t_size p_count,const t_container & p_container,t_compare p_compare,const t_param & p_param,const t_permutation & p_permutation,t_size & p_index) {
t_size index;
if (bsearch(
p_count,
bsearch_callback_impl_permutation_t<t_container,t_compare,t_param,t_permutation>(p_container,p_compare,p_param,p_permutation),
index))
{
p_index = p_permutation[index];
return true;
} else {
return false;
}
}
template<typename t_container,typename t_compare, typename t_param>
bool bsearch_range_t(const t_size p_count,const t_container & p_container,t_compare p_compare,const t_param & p_param,t_size & p_range_base,t_size & p_range_count)
{
t_size probe;
if (!bsearch(
p_count,
bsearch_callback_impl_simple_t<t_container,t_compare,t_param>(p_container,p_compare,p_param),
probe)) return false;
t_size base = probe, count = 1;
while(base > 0 && p_compare(p_container[base-1],p_param) == 0) {base--; count++;}
while(base + count < p_count && p_compare(p_container[base+count],p_param) == 0) {count++;}
p_range_base = base;
p_range_count = count;
return true;
}
}

50
pfc/bsearch_inline.h Normal file
View File

@@ -0,0 +1,50 @@
#pragma once
namespace pfc {
//deprecated
template<typename t_callback>
inline bool bsearch_inline_t(t_size p_count, const t_callback & p_callback,t_size & p_result)
{
t_size max = p_count;
t_size min = 0;
t_size ptr;
while(min<max)
{
ptr = min + ( (max-min) >> 1);
int result = p_callback.test(ptr);
if (result<0) min = ptr + 1;
else if (result>0) max = ptr;
else
{
p_result = ptr;
return true;
}
}
p_result = min;
return false;
}
template<typename t_buffer,typename t_value>
inline bool bsearch_simple_inline_t(const t_buffer & p_buffer,t_size p_count,t_value const & p_value,t_size & p_result)
{
t_size max = p_count;
t_size min = 0;
t_size ptr;
while(min<max)
{
ptr = min + ( (max-min) >> 1);
if (p_value > p_buffer[ptr]) min = ptr + 1;
else if (p_value < p_buffer[ptr]) max = ptr;
else
{
p_result = ptr;
return true;
}
}
p_result = min;
return false;
}
}

256
pfc/byte_order.h Normal file
View File

@@ -0,0 +1,256 @@
#pragma once
namespace pfc {
void byteswap_raw(void * p_buffer,t_size p_bytes);
template<typename T> T byteswap_t(T p_source);
template<> inline char byteswap_t<char>(char p_source) {return p_source;}
template<> inline unsigned char byteswap_t<unsigned char>(unsigned char p_source) {return p_source;}
template<> inline signed char byteswap_t<signed char>(signed char p_source) {return p_source;}
template<typename T> T byteswap_int_t(T p_source) {
enum { width = sizeof(T) };
typedef typename sized_int_t<width>::t_unsigned tU;
tU in = p_source, out = 0;
for(unsigned walk = 0; walk < width; ++walk) {
out |= ((in >> (walk * 8)) & 0xFF) << ((width - 1 - walk) * 8);
}
return out;
}
#ifdef _MSC_VER//does this even help with performance/size?
template<> inline wchar_t byteswap_t<wchar_t>(wchar_t p_source) {return _byteswap_ushort(p_source);}
template<> inline short byteswap_t<short>(short p_source) {return _byteswap_ushort(p_source);}
template<> inline unsigned short byteswap_t<unsigned short>(unsigned short p_source) {return _byteswap_ushort(p_source);}
template<> inline int byteswap_t<int>(int p_source) {return _byteswap_ulong(p_source);}
template<> inline unsigned int byteswap_t<unsigned int>(unsigned int p_source) {return _byteswap_ulong(p_source);}
template<> inline long byteswap_t<long>(long p_source) {return _byteswap_ulong(p_source);}
template<> inline unsigned long byteswap_t<unsigned long>(unsigned long p_source) {return _byteswap_ulong(p_source);}
template<> inline long long byteswap_t<long long>(long long p_source) {return _byteswap_uint64(p_source);}
template<> inline unsigned long long byteswap_t<unsigned long long>(unsigned long long p_source) {return _byteswap_uint64(p_source);}
#else
template<> inline wchar_t byteswap_t<wchar_t>(wchar_t p_source) {return byteswap_int_t(p_source);}
template<> inline short byteswap_t<short>(short p_source) {return byteswap_int_t(p_source);}
template<> inline unsigned short byteswap_t<unsigned short>(unsigned short p_source) {return byteswap_int_t(p_source);}
template<> inline int byteswap_t<int>(int p_source) {return byteswap_int_t(p_source);}
template<> inline unsigned int byteswap_t<unsigned int>(unsigned int p_source) {return byteswap_int_t(p_source);}
template<> inline long byteswap_t<long>(long p_source) {return byteswap_int_t(p_source);}
template<> inline unsigned long byteswap_t<unsigned long>(unsigned long p_source) {return byteswap_int_t(p_source);}
template<> inline long long byteswap_t<long long>(long long p_source) {return byteswap_int_t(p_source);}
template<> inline unsigned long long byteswap_t<unsigned long long>(unsigned long long p_source) {return byteswap_int_t(p_source);}
#endif
template<> inline float byteswap_t<float>(float p_source) {
float ret;
*(t_uint32*) &ret = byteswap_t(*(const t_uint32*)&p_source );
return ret;
}
template<> inline double byteswap_t<double>(double p_source) {
double ret;
*(t_uint64*) &ret = byteswap_t(*(const t_uint64*)&p_source );
return ret;
}
//blargh at GUID byteswap issue
template<> inline GUID byteswap_t<GUID>(GUID p_guid) {
GUID ret;
ret.Data1 = pfc::byteswap_t(p_guid.Data1);
ret.Data2 = pfc::byteswap_t(p_guid.Data2);
ret.Data3 = pfc::byteswap_t(p_guid.Data3);
ret.Data4[0] = p_guid.Data4[0];
ret.Data4[1] = p_guid.Data4[1];
ret.Data4[2] = p_guid.Data4[2];
ret.Data4[3] = p_guid.Data4[3];
ret.Data4[4] = p_guid.Data4[4];
ret.Data4[5] = p_guid.Data4[5];
ret.Data4[6] = p_guid.Data4[6];
ret.Data4[7] = p_guid.Data4[7];
return ret;
}
#if ! defined(_MSC_VER) || _MSC_VER >= 1900
template<> inline char16_t byteswap_t<char16_t>(char16_t v) { return (char16_t)byteswap_t((uint16_t)v); }
template<> inline char32_t byteswap_t<char32_t>(char32_t v) { return (char32_t)byteswap_t((uint32_t)v); }
#endif
};
#ifdef _MSC_VER
#if defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM)
#define PFC_BYTE_ORDER_IS_BIG_ENDIAN 0
#endif
#else//_MSC_VER
#if defined(__APPLE__)
#include <architecture/byte_order.h>
#else
#include <endian.h>
#endif
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define PFC_BYTE_ORDER_IS_BIG_ENDIAN 0
#else
#define PFC_BYTE_ORDER_IS_BIG_ENDIAN 1
#endif
#endif//_MSC_VER
#ifdef PFC_BYTE_ORDER_IS_BIG_ENDIAN
#define PFC_BYTE_ORDER_IS_LITTLE_ENDIAN (!(PFC_BYTE_ORDER_IS_BIG_ENDIAN))
#else
#error please update byte order #defines
#endif
namespace pfc {
static const bool byte_order_is_big_endian = !!PFC_BYTE_ORDER_IS_BIG_ENDIAN;
static const bool byte_order_is_little_endian = !!PFC_BYTE_ORDER_IS_LITTLE_ENDIAN;
template<typename T> T byteswap_if_be_t(T p_param) {return byte_order_is_big_endian ? byteswap_t(p_param) : p_param;}
template<typename T> T byteswap_if_le_t(T p_param) {return byte_order_is_little_endian ? byteswap_t(p_param) : p_param;}
}
namespace byte_order {
#if PFC_BYTE_ORDER_IS_BIG_ENDIAN//big endian
template<typename T> inline void order_native_to_le_t(T& param) {param = pfc::byteswap_t(param);}
template<typename T> inline void order_native_to_be_t(T& param) {}
template<typename T> inline void order_le_to_native_t(T& param) {param = pfc::byteswap_t(param);}
template<typename T> inline void order_be_to_native_t(T& param) {}
#else//little endian
template<typename T> inline void order_native_to_le_t(T& param) {}
template<typename T> inline void order_native_to_be_t(T& param) {param = pfc::byteswap_t(param);}
template<typename T> inline void order_le_to_native_t(T& param) {}
template<typename T> inline void order_be_to_native_t(T& param) {param = pfc::byteswap_t(param);}
#endif
};
namespace pfc {
template<typename TInt,unsigned width,bool IsBigEndian>
class __EncodeIntHelper {
public:
inline static void Run(TInt p_value,t_uint8 * p_out) {
*p_out = (t_uint8)(p_value);
__EncodeIntHelper<TInt,width-1,IsBigEndian>::Run(p_value >> 8,p_out + (IsBigEndian ? -1 : 1));
}
};
template<typename TInt,bool IsBigEndian>
class __EncodeIntHelper<TInt,1,IsBigEndian> {
public:
inline static void Run(TInt p_value,t_uint8* p_out) {
*p_out = (t_uint8)(p_value);
}
};
template<typename TInt,bool IsBigEndian>
class __EncodeIntHelper<TInt,0,IsBigEndian> {
public:
inline static void Run(TInt,t_uint8*) {}
};
template<typename TInt>
inline void encode_little_endian(t_uint8 * p_buffer,TInt p_value) {
__EncodeIntHelper<TInt,sizeof(TInt),false>::Run(p_value,p_buffer);
}
template<typename TInt>
inline void encode_big_endian(t_uint8 * p_buffer,TInt p_value) {
__EncodeIntHelper<TInt,sizeof(TInt),true>::Run(p_value,p_buffer + (sizeof(TInt) - 1));
}
template<typename TInt,unsigned width,bool IsBigEndian>
class __DecodeIntHelper {
public:
inline static TInt Run(const t_uint8 * p_in) {
return (__DecodeIntHelper<TInt,width-1,IsBigEndian>::Run(p_in + (IsBigEndian ? -1 : 1)) << 8) + *p_in;
}
};
template<typename TInt,bool IsBigEndian>
class __DecodeIntHelper<TInt,1,IsBigEndian> {
public:
inline static TInt Run(const t_uint8* p_in) {return *p_in;}
};
template<typename TInt,bool IsBigEndian>
class __DecodeIntHelper<TInt,0,IsBigEndian> {
public:
inline static TInt Run(const t_uint8*) {return 0;}
};
template<typename TInt>
inline void decode_little_endian(TInt & p_out,const t_uint8 * p_buffer) {
p_out = __DecodeIntHelper<TInt,sizeof(TInt),false>::Run(p_buffer);
}
template<typename TInt>
inline void decode_big_endian(TInt & p_out,const t_uint8 * p_buffer) {
p_out = __DecodeIntHelper<TInt,sizeof(TInt),true>::Run(p_buffer + (sizeof(TInt) - 1));
}
template<typename TInt>
inline TInt decode_little_endian(const t_uint8 * p_buffer) {
TInt temp;
decode_little_endian(temp,p_buffer);
return temp;
}
template<typename TInt>
inline TInt decode_big_endian(const t_uint8 * p_buffer) {
TInt temp;
decode_big_endian(temp,p_buffer);
return temp;
}
template<bool IsBigEndian,typename TInt>
inline void decode_endian(TInt & p_out,const t_uint8 * p_buffer) {
if (IsBigEndian) decode_big_endian(p_out,p_buffer);
else decode_little_endian(p_out,p_buffer);
}
template<bool IsBigEndian,typename TInt>
inline void encode_endian(t_uint8 * p_buffer,TInt p_in) {
if (IsBigEndian) encode_big_endian(p_in,p_buffer);
else encode_little_endian(p_in,p_buffer);
}
template<unsigned width>
inline void reverse_bytes(t_uint8 * p_buffer) {
pfc::swap_t(p_buffer[0],p_buffer[width-1]);
reverse_bytes<width-2>(p_buffer+1);
}
template<> inline void reverse_bytes<1>(t_uint8 * ) { }
template<> inline void reverse_bytes<0>(t_uint8 * ) { }
inline int32_t readInt24(const void * mem) {
const uint8_t * p = (const uint8_t*) mem;
int32_t ret;
if (byte_order_is_little_endian) {
ret = p[0];
ret |= (uint32_t)p[1] << 8;
ret |= (int32_t)(int8_t)p[2] << 16;
return ret;
} else {
ret = p[2];
ret |= (uint32_t)p[1] << 8;
ret |= (int32_t)(int8_t)p[0] << 16;
return ret;
}
}
}

296
pfc/chain_list_v2.h Normal file
View File

@@ -0,0 +1,296 @@
#pragma once
namespace pfc {
template<typename t_item>
class __chain_list_elem : public _list_node<t_item> {
public:
typedef _list_node<t_item> t_node;
template<typename ... arg_t > __chain_list_elem( arg_t && ... args ) : t_node( std::forward<arg_t>(args) ... ) {m_prev = m_next = NULL;}
typedef __chain_list_elem<t_item> t_self;
t_self * m_prev, * m_next;
t_node * prev() throw() {return m_prev;}
t_node * next() throw() {return m_next;}
//helper wrappers
void add_ref() throw() {this->refcount_add_ref();}
void release() throw() {this->refcount_release();}
//workaround for cross-list-relinking case - never actually deletes p_elem
void __release_temporary() throw() {this->_refcount_release_temporary();}
};
//! Differences between chain_list_v2_t<> and old chain_list_t<>: \n
//! Iterators pointing to removed items as well as to items belonging to no longer existing list objects remain valid but they're no longer walkable - as if the referenced item was the only item in the list. The old class invalidated iterators on deletion instead.
template<typename _t_item>
class chain_list_v2_t {
public:
typedef _t_item t_item;
typedef chain_list_v2_t<t_item> t_self;
typedef ::pfc::iterator<t_item> iterator;
typedef ::pfc::const_iterator<t_item> const_iterator;
typedef __chain_list_elem<t_item> t_elem;
chain_list_v2_t() {}
chain_list_v2_t(const t_self & p_source) {
try {
*this = p_source;
} catch(...) {
remove_all();
throw;
}
}
chain_list_v2_t(t_self && p_source) {
append_move_from( p_source );
}
template<typename t_in> void _set(const t_in & in) {
remove_all(); _add(in);
}
template<typename t_in> void _add(const t_in & in) {
for(typename t_in::const_iterator iter = in.first(); iter.is_valid(); ++in) add_item(*iter);
}
template<typename t_in> t_self & operator=(const t_in & in) {_set(in); return *this;}
t_self & operator=(const t_self & p_other) {
remove_all();
for(t_elem * walk = p_other.m_first; walk != NULL; walk = walk->m_next) {
add_item(walk->m_content);
}
return *this;
}
t_self & operator=(t_self && p_other) {
move_from(p_other); return *this;
}
// templated constructors = spawn of satan
// template<typename t_other> chain_list_v2_t(const t_other & in) { try {_add(in);} catch(...) {remove_all(); throw;} }
t_size get_count() const {return m_count;}
iterator first() {return iterator(m_first);}
iterator last() {return iterator(m_last);}
const_iterator first() const {return const_iterator(m_first);}
const_iterator last() const {return const_iterator(m_last);}
const_iterator cfirst() const {return const_iterator(m_first);}
const_iterator clast() const {return const_iterator(m_last);}
void remove_single(const_iterator const & p_iter) {
PFC_ASSERT(p_iter.is_valid());
__unlink(_elem(p_iter));
}
void remove(const_iterator const & p_iter) {
PFC_ASSERT(p_iter.is_valid());
__unlink(_elem(p_iter));
}
void remove_all() throw() {
while(m_first != NULL) __unlink(m_first);
PFC_ASSERT(m_count == 0);
}
void remove_range(const_iterator const & p_from,const_iterator const & p_to) {
for(t_elem * walk = _elem(p_from);;) {
if (walk == NULL) {PFC_ASSERT(!"Should not get here"); break;}//should not happen unless there is a bug in calling code
t_elem * next = walk->m_next;
__unlink(walk);
if (walk == _elem(p_to)) break;
walk = next;
}
}
template<typename t_callback> void enumerate(t_callback & p_callback) const {__enumerate_chain<const t_elem>(m_first,p_callback);}
template<typename t_callback> void enumerate(t_callback & p_callback) {__enumerate_chain<t_elem>(m_first,p_callback);}
template<typename t_source> bool remove_item(const t_source & p_item) {
t_elem * elem;
if (__find(elem,p_item)) {
__unlink(elem);
return true;
} else {
return false;
}
}
~chain_list_v2_t() {remove_all();}
template<typename ... arg_t>
inline void add_item(arg_t && ... arg) {
__link_last(new t_elem(std::forward<arg_t>(arg) ... ));
}
template<typename t_source>
inline t_self & operator+=(t_source && p_source) {
add_item(std::forward<t_source>(p_source)); return *this;
}
iterator insert_last() {return __link_last(new t_elem);}
iterator insert_first() {return __link_first(new t_elem);}
iterator insert_after(const_iterator const & p_iter) {return __link_next(_elem(p_iter),new t_elem);}
iterator insert_before(const_iterator const & p_iter) {return __link_prev(_elem(p_iter),new t_elem);}
template<typename ... arg_t> iterator insert_last(arg_t && ... arg) {return __link_last(new t_elem(std::forward<arg_t>(arg) ...));}
template<typename ... arg_t> iterator insert_first(arg_t && ... arg) {return __link_first(new t_elem(std::forward<arg_t>(arg) ...));}
template<typename ... arg_t> iterator insert_after(const_iterator const & p_iter,arg_t && ... arg) {return __link_next(_elem(p_iter),new t_elem(std::forward<arg_t>(arg) ... ));}
template<typename ... arg_t> iterator insert_before(const_iterator const & p_iter,arg_t && ... arg) {return __link_prev(_elem(p_iter),new t_elem(std::forward<arg_t>(arg) ... ));}
template<typename t_source> const_iterator find_item(const t_source & p_item) const {
t_elem * elem;
if (!__find(elem,p_item)) return const_iterator();
return const_iterator(elem);
}
template<typename t_source> iterator find_item(const t_source & p_item) {
t_elem * elem;
if (!__find(elem,p_item)) return iterator();
return iterator(elem);
}
template<typename t_source> bool have_item(const t_source & p_item) const {
t_elem * dummy;
return __find(dummy,p_item);
}
template<typename t_source> void set_single(const t_source & p_item) {
remove_all(); add_item(p_item);
}
//! Slow!
const_iterator by_index(t_size p_index) const {return __by_index(p_index);}
//! Slow!
iterator by_index(t_size p_index) {return __by_index(p_index);}
t_self & operator<<(t_self & p_other) {
while(p_other.m_first != NULL) {
__link_last( p_other.__unlink_temporary(p_other.m_first) );
}
return *this;
}
t_self & operator>>(t_self & p_other) {
while(m_last != NULL) {
p_other.__link_first(__unlink_temporary(m_last));
}
return p_other;
}
//! Links an object that has been unlinked from another list. Unsafe.
void _link_last(const_iterator const& iter) {
PFC_ASSERT(iter.is_valid());
PFC_ASSERT( _elem(iter)->m_prev == NULL && _elem(iter)->m_next == NULL );
__link_last(_elem(iter));
}
//! Links an object that has been unlinked from another list. Unsafe.
void _link_first(const_iterator const& iter) {
PFC_ASSERT(iter.is_valid());
PFC_ASSERT( _elem(iter)->m_prev == NULL && _elem(iter)->m_next == NULL );
__link_first(_elem(iter));
}
void append_move_from( t_self & p_other ) {
while (p_other.m_first != NULL) {
__link_last(p_other.__unlink_temporary(p_other.m_first));
}
}
void move_from( t_self & p_other ) {
remove_all();
append_move_from( p_other );
}
private:
static t_elem * _elem(const_iterator const & iter) {
return static_cast<t_elem*>(iter._node());
}
t_elem * __by_index(t_size p_index) const {
t_elem * walk = m_first;
while(p_index > 0 && walk != NULL) {
p_index--;
walk = walk->m_next;
}
return walk;
}
template<typename t_elemwalk,typename t_callback>
static void __enumerate_chain(t_elemwalk * p_elem,t_callback & p_callback) {
t_elemwalk * walk = p_elem;
while(walk != NULL) {
p_callback(walk->m_content);
walk = walk->m_next;
}
}
template<typename t_source> bool __find(t_elem * & p_elem,const t_source & p_item) const {
for(t_elem * walk = m_first; walk != NULL; walk = walk->m_next) {
if (walk->m_content == p_item) {
p_elem = walk; return true;
}
}
return false;
}
void __unlink_helper(t_elem * p_elem) throw() {
(p_elem->m_prev == NULL ? m_first : p_elem->m_prev->m_next) = p_elem->m_next;
(p_elem->m_next == NULL ? m_last : p_elem->m_next->m_prev) = p_elem->m_prev;
p_elem->m_next = p_elem->m_prev = NULL;
}
//workaround for cross-list-relinking case - never actually deletes p_elem
t_elem * __unlink_temporary(t_elem * p_elem) throw() {
__unlink_helper(p_elem);
--m_count; p_elem->__release_temporary();
return p_elem;
}
t_elem * __unlink(t_elem * p_elem) throw() {
__unlink_helper(p_elem);
--m_count; p_elem->release();
return p_elem;
}
void __on_link(t_elem * p_elem) throw() {
p_elem->add_ref(); ++m_count;
}
t_elem * __link_first(t_elem * p_elem) throw() {
__on_link(p_elem);
p_elem->m_next = m_first;
p_elem->m_prev = NULL;
(m_first == NULL ? m_last : m_first->m_prev) = p_elem;
m_first = p_elem;
return p_elem;
}
t_elem * __link_last(t_elem * p_elem) throw() {
__on_link(p_elem);
p_elem->m_prev = m_last;
p_elem->m_next = NULL;
(m_last == NULL ? m_first : m_last->m_next) = p_elem;
m_last = p_elem;
return p_elem;
}
t_elem * __link_next(t_elem * p_prev,t_elem * p_elem) throw() {
__on_link(p_elem);
p_elem->m_prev = p_prev;
p_elem->m_next = p_prev->m_next;
(p_prev->m_next != NULL ? p_prev->m_next->m_prev : m_last) = p_elem;
p_prev->m_next = p_elem;
return p_elem;
}
t_elem * __link_prev(t_elem * p_next,t_elem * p_elem) throw() {
__on_link(p_elem);
p_elem->m_next = p_next;
p_elem->m_prev = p_next->m_prev;
(p_next->m_prev != NULL ? p_next->m_prev->m_next : m_first) = p_elem;
p_next->m_prev = p_elem;
return p_elem;
}
t_elem * m_first = nullptr, * m_last = nullptr;
t_size m_count = 0;
};
template<typename t_item> class traits_t<chain_list_v2_t<t_item> > : public traits_default_movable {};
class __chain_list_iterator_traits : public traits_default_movable {
public:
enum {
constructor_may_fail = false
};
};
template<typename t_item> class traits_t<const_iterator<t_item> > : public traits_t<refcounted_object_ptr_t<_list_node<t_item> > > {};
template<typename t_item> class traits_t<iterator<t_item> > : public traits_t<const_iterator<t_item> > {};
}//namespace pfc

46
pfc/cmd_thread.h Normal file
View File

@@ -0,0 +1,46 @@
#pragma once
#include "wait_queue.h"
#include <functional>
#include <mutex>
#include <memory>
namespace pfc {
class cmdThread {
public:
typedef std::function<void()> cmd_t;
typedef pfc::waitQueue<cmd_t> queue_t;
void add(cmd_t c) {
std::call_once(m_once, [this] {
auto q = std::make_shared<queue_t>();
pfc::splitThread([q] {
cmd_t cmd;
while (q->get(cmd)) {
cmd();
}
});
m_queue = q;
});
m_queue->put(c);
}
void shutdown() {
if (m_queue) {
m_queue->set_eof();
m_queue.reset();
}
}
~cmdThread() {
shutdown();
}
private:
std::shared_ptr< queue_t > m_queue;
std::once_flag m_once;
};
}

87
pfc/com_ptr_t.h Normal file
View File

@@ -0,0 +1,87 @@
#pragma once
#ifdef _WIN32
namespace pfc {
template<typename what> static void _COM_AddRef(what * ptr) {
if (ptr != NULL) ptr->AddRef();
}
template<typename what> static void _COM_Release(what * ptr) {
if (ptr != NULL) ptr->Release();
}
template<class T>
class com_ptr_t {
public:
typedef com_ptr_t<T> t_self;
com_ptr_t( nullptr_t ) throw() : m_ptr() {}
com_ptr_t() throw() : m_ptr() {}
template<typename source> inline com_ptr_t(source * p_ptr) throw() : m_ptr(p_ptr) {_COM_AddRef(m_ptr);}
com_ptr_t(const t_self & p_source) throw() : m_ptr(p_source.m_ptr) {_COM_AddRef(m_ptr);}
template<typename source> inline com_ptr_t(const com_ptr_t<source> & p_source) throw() : m_ptr(p_source.get_ptr()) {_COM_AddRef(m_ptr);}
inline ~com_ptr_t() throw() {_COM_Release(m_ptr);}
inline void copy(T * p_ptr) throw() {
_COM_Release(m_ptr);
m_ptr = p_ptr;
_COM_AddRef(m_ptr);
}
template<typename source> inline void copy(const com_ptr_t<source> & p_source) throw() {copy(p_source.get_ptr());}
inline void attach(T * p_ptr) throw() {
_COM_Release(m_ptr);
m_ptr = p_ptr;
}
inline const t_self & operator=(const t_self & p_source) throw() {copy(p_source); return *this;}
inline const t_self & operator=(T* p_source) throw() {copy(p_source); return *this;}
template<typename source> inline const t_self & operator=(const com_ptr_t<source> & p_source) throw() {copy(p_source); return *this;}
template<typename source> inline const t_self & operator=(source * p_ptr) throw() {copy(p_ptr); return *this;}
inline void release() throw() {
_COM_Release(m_ptr);
m_ptr = NULL;
}
inline T* operator->() const throw() {PFC_ASSERT(m_ptr);return m_ptr;}
inline T* get_ptr() const throw() {return m_ptr;}
inline T* duplicate_ptr() const throw() //should not be used ! temporary !
{
_COM_AddRef(m_ptr);
return m_ptr;
}
inline T* detach() throw() {
return replace_null_t(m_ptr);
}
inline bool is_valid() const throw() {return m_ptr != 0;}
inline bool is_empty() const throw() {return m_ptr == 0;}
inline bool operator==(const com_ptr_t<T> & p_item) const throw() {return m_ptr == p_item.m_ptr;}
inline bool operator!=(const com_ptr_t<T> & p_item) const throw() {return m_ptr != p_item.m_ptr;}
inline bool operator>(const com_ptr_t<T> & p_item) const throw() {return m_ptr > p_item.m_ptr;}
inline bool operator<(const com_ptr_t<T> & p_item) const throw() {return m_ptr < p_item.m_ptr;}
inline static void g_swap(com_ptr_t<T> & item1, com_ptr_t<T> & item2) throw() {
pfc::swap_t(item1.m_ptr,item2.m_ptr);
}
inline T** receive_ptr() throw() {release();return &m_ptr;}
inline void** receive_void_ptr() throw() {return (void**) receive_ptr();}
inline t_self & operator<<(t_self & p_source) throw() {attach(p_source.detach());return *this;}
inline t_self & operator>>(t_self & p_dest) throw() {p_dest.attach(detach());return *this;}
private:
T* m_ptr;
};
}
#endif

64
pfc/cpuid.cpp Normal file
View File

@@ -0,0 +1,64 @@
#include "pfc.h"
#if PFC_HAVE_CPUID
namespace pfc {
bool query_cpu_feature_set(unsigned p_value) {
#if _M_IX86_FP >= 2
// don't bother checking for SSE/SSE2 if compiled to use them
p_value &= ~(CPU_HAVE_SSE | CPU_HAVE_SSE2);
if (p_value == 0) return true;
#endif
#ifdef _MSC_VER
__try {
#endif
if (p_value & (CPU_HAVE_SSE | CPU_HAVE_SSE2 | CPU_HAVE_SSE3 | CPU_HAVE_SSSE3 | CPU_HAVE_SSE41 | CPU_HAVE_SSE42)) {
int buffer[4];
__cpuid(buffer,1);
if (p_value & CPU_HAVE_SSE) {
if ((buffer[3]&(1<<25)) == 0) return false;
}
if (p_value & CPU_HAVE_SSE2) {
if ((buffer[3]&(1<<26)) == 0) return false;
}
if (p_value & CPU_HAVE_SSE3) {
if ((buffer[2]&(1<<0)) == 0) return false;
}
if (p_value & CPU_HAVE_SSSE3) {
if ((buffer[2]&(1<<9)) == 0) return false;
}
if (p_value & CPU_HAVE_SSE41) {
if ((buffer[2]&(1<<19)) == 0) return false;
}
if (p_value & CPU_HAVE_SSE42) {
if ((buffer[2]&(1<<20)) == 0) return false;
}
}
#ifdef _M_IX86
if (p_value & (CPU_HAVE_3DNOW_EX | CPU_HAVE_3DNOW)) {
int buffer_amd[4];
__cpuid(buffer_amd,0x80000000);
if ((unsigned)buffer_amd[0] < 0x80000001) return false;
__cpuid(buffer_amd,0x80000001);
if (p_value & CPU_HAVE_3DNOW) {
if ((buffer_amd[3]&(1<<31)) == 0) return false;
}
if (p_value & CPU_HAVE_3DNOW_EX) {
if ((buffer_amd[3]&(1<<30)) == 0) return false;
}
}
#endif
return true;
#ifdef _MSC_VER
} __except(1) {
return false;
}
#endif
}
}
#endif

24
pfc/cpuid.h Normal file
View File

@@ -0,0 +1,24 @@
#pragma once
// CPUID stuff supported only on MSVC for now, irrelevant for non x86
#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
#define PFC_HAVE_CPUID 1
namespace pfc {
enum {
CPU_HAVE_3DNOW = 1 << 0,
CPU_HAVE_3DNOW_EX = 1 << 1,
CPU_HAVE_SSE = 1 << 2,
CPU_HAVE_SSE2 = 1 << 3,
CPU_HAVE_SSE3 = 1 << 4,
CPU_HAVE_SSSE3 = 1 << 5,
CPU_HAVE_SSE41 = 1 << 6,
CPU_HAVE_SSE42 = 1 << 7,
};
bool query_cpu_feature_set(unsigned p_value);
};
#endif
#ifndef PFC_HAVE_CPUID
#define PFC_HAVE_CPUID 0
#endif

23
pfc/event.h Normal file
View File

@@ -0,0 +1,23 @@
namespace pfc {
#ifdef _WIN32
typedef HANDLE eventHandle_t;
static const eventHandle_t eventInvalid = NULL;
class event : public win32_event {
public:
event() { create(true, false); }
HANDLE get_handle() const {return win32_event::get();}
};
#else
typedef int eventHandle_t;
static const eventHandle_t eventInvalid = -1;
typedef nix_event event;
#endif
}

33
pfc/filehandle.cpp Normal file
View File

@@ -0,0 +1,33 @@
#include "pfc.h"
#ifndef _WIN32
#include <unistd.h>
#endif
namespace pfc {
void fileHandleClose( fileHandle_t h ) {
if (h == fileHandleInvalid) return;
#ifdef _WIN32
CloseHandle( h );
#else
close( h );
#endif
}
fileHandle_t fileHandleDup( fileHandle_t h ) {
#ifdef _WIN32
auto proc = GetCurrentProcess();
HANDLE out;
if (!DuplicateHandle ( proc, h, proc, &out, 0, FALSE, DUPLICATE_SAME_ACCESS )) return fileHandleInvalid;
return out;
#else
return dup( h );
#endif
}
void fileHandle::close() {
fileHandleClose( h );
clear();
}
}

31
pfc/filehandle.h Normal file
View File

@@ -0,0 +1,31 @@
#pragma once
namespace pfc {
#ifdef _WIN32
typedef HANDLE fileHandle_t;
const fileHandle_t fileHandleInvalid = INVALID_HANDLE_VALUE;
#else
typedef int fileHandle_t;
const fileHandle_t fileHandleInvalid = -1;
#endif
void fileHandleClose( fileHandle_t h );
fileHandle_t fileHandleDup( fileHandle_t h );
class fileHandle {
public:
fileHandle( fileHandle_t val ) : h(val) {}
fileHandle() : h ( fileHandleInvalid ) {}
~fileHandle() { close(); }
fileHandle( fileHandle && other ) { h = other.h; other.clear(); }
void operator=( fileHandle && other ) { close(); h = other.h; other.clear(); }
void operator=( fileHandle_t other ) { close(); h = other; }
void close();
void clear() { h = fileHandleInvalid; }
bool isValid() { return h != fileHandleInvalid; }
fileHandle_t h;
private:
fileHandle( const fileHandle & );
void operator=( const fileHandle & );
};
}

196
pfc/guid.cpp Normal file
View File

@@ -0,0 +1,196 @@
#include "pfc.h"
#ifdef _WIN32
#include <Objbase.h>
#endif
/*
6B29FC40-CA47-1067-B31D-00DD010662DA
.
typedef struct _GUID { // size is 16
DWORD Data1;
WORD Data2;
WORD Data3;
BYTE Data4[8];
} GUID;
// {B296CF59-4D51-466f-8E0B-E57D3F91D908}
static const GUID <<name>> =
{ 0xb296cf59, 0x4d51, 0x466f, { 0x8e, 0xb, 0xe5, 0x7d, 0x3f, 0x91, 0xd9, 0x8 } };
*/
namespace {
class _GUID_from_text : public GUID
{
unsigned read_hex(char c);
unsigned read_byte(const char * ptr);
unsigned read_word(const char * ptr);
unsigned read_dword(const char * ptr);
void read_bytes(unsigned char * out,unsigned num,const char * ptr);
public:
_GUID_from_text(const char * text);
};
unsigned _GUID_from_text::read_hex(char c)
{
if (c>='0' && c<='9') return (unsigned)c - '0';
else if (c>='a' && c<='f') return 0xa + (unsigned)c - 'a';
else if (c>='A' && c<='F') return 0xa + (unsigned)c - 'A';
else return 0;
}
unsigned _GUID_from_text::read_byte(const char * ptr)
{
return (read_hex(ptr[0])<<4) | read_hex(ptr[1]);
}
unsigned _GUID_from_text::read_word(const char * ptr)
{
return (read_byte(ptr)<<8) | read_byte(ptr+2);
}
unsigned _GUID_from_text::read_dword(const char * ptr)
{
return (read_word(ptr)<<16) | read_word(ptr+4);
}
void _GUID_from_text::read_bytes(uint8_t * out,unsigned num,const char * ptr)
{
for(;num;num--)
{
*out = read_byte(ptr);
out++;ptr+=2;
}
}
_GUID_from_text::_GUID_from_text(const char * text)
{
if (*text=='{') text++;
const char * max;
{
const char * t = strchr(text,'}');
if (t) max = t;
else max = text + strlen(text);
}
(GUID)*this = pfc::guid_null;
do {
if (text+8>max) break;
Data1 = read_dword(text);
text += 8;
while(*text=='-') text++;
if (text+4>max) break;
Data2 = read_word(text);
text += 4;
while(*text=='-') text++;
if (text+4>max) break;
Data3 = read_word(text);
text += 4;
while(*text=='-') text++;
if (text+4>max) break;
read_bytes(Data4,2,text);
text += 4;
while(*text=='-') text++;
if (text+12>max) break;
read_bytes(Data4+2,6,text);
} while(false);
}
}
namespace pfc {
GUID GUID_from_text(const char * text) {
return _GUID_from_text( text );
}
static inline char print_hex_digit(unsigned val)
{
static const char table[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
PFC_ASSERT((val & ~0xF) == 0);
return table[val];
}
static void print_hex(unsigned val,char * &out,unsigned bytes)
{
unsigned n;
for(n=0;n<bytes;n++)
{
unsigned char c = (unsigned char)((val >> ((bytes - 1 - n) << 3)) & 0xFF);
*(out++) = print_hex_digit( c >> 4 );
*(out++) = print_hex_digit( c & 0xF );
}
*out = 0;
}
print_guid::print_guid(const GUID & p_guid)
{
char * out = m_data;
print_hex(p_guid.Data1,out,4);
*(out++) = '-';
print_hex(p_guid.Data2,out,2);
*(out++) = '-';
print_hex(p_guid.Data3,out,2);
*(out++) = '-';
print_hex(p_guid.Data4[0],out,1);
print_hex(p_guid.Data4[1],out,1);
*(out++) = '-';
print_hex(p_guid.Data4[2],out,1);
print_hex(p_guid.Data4[3],out,1);
print_hex(p_guid.Data4[4],out,1);
print_hex(p_guid.Data4[5],out,1);
print_hex(p_guid.Data4[6],out,1);
print_hex(p_guid.Data4[7],out,1);
*out = 0;
}
void print_hex_raw(const void * buffer,unsigned bytes,char * p_out)
{
char * out = p_out;
const unsigned char * in = (const unsigned char *) buffer;
unsigned n;
for(n=0;n<bytes;n++)
print_hex(in[n],out,1);
}
GUID createGUID() {
GUID out;
#ifdef _WIN32
if (FAILED(CoCreateGuid( & out ) ) ) crash();
#else
pfc::nixGetRandomData( &out, sizeof(out) );
#endif
return out;
}
}
const GUID pfc::guid_null = { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } };
namespace pfc {
format_guid_cpp::format_guid_cpp(const GUID & guid) {
*this << "{0x" << pfc::format_hex(guid.Data1,8) << ", 0x" << pfc::format_hex(guid.Data2, 4) << ", 0x" << pfc::format_hex(guid.Data3,4) << ", {0x" << pfc::format_hex(guid.Data4[0],2);
for(int n = 1; n < 8; ++n) {
*this << ", 0x" << pfc::format_hex(guid.Data4[n],2);
}
*this << "}}";
}
uint64_t halveGUID(const GUID & id) {
static_assert(sizeof(id) == 2 * sizeof(uint64_t), "sanity" );
union {
GUID g;
uint64_t u[2];
} u;
u.g = id;
return u.u[0] ^ u.u[1];
}
}

41
pfc/guid.h Normal file
View File

@@ -0,0 +1,41 @@
#pragma once
namespace pfc {
GUID GUID_from_text(const char * text);
class print_guid
{
public:
print_guid(const GUID & p_guid);
inline operator const char * () const {return m_data;}
inline const char * get_ptr() {return m_data;}
private:
char m_data[64];
};
inline int guid_compare(const GUID & g1,const GUID & g2) {return memcmp(&g1,&g2,sizeof(GUID));}
inline bool guid_equal(const GUID & g1,const GUID & g2) {return (g1 == g2) ? true : false;}
template<> inline int compare_t<GUID,GUID>(const GUID & p_item1,const GUID & p_item2) {return guid_compare(p_item1,p_item2);}
extern const GUID guid_null;
void print_hex_raw(const void * buffer,unsigned bytes,char * p_out);
inline GUID makeGUID(t_uint32 Data1, t_uint16 Data2, t_uint16 Data3, t_uint8 Data4_1, t_uint8 Data4_2, t_uint8 Data4_3, t_uint8 Data4_4, t_uint8 Data4_5, t_uint8 Data4_6, t_uint8 Data4_7, t_uint8 Data4_8) {
GUID guid = { Data1, Data2, Data3, {Data4_1, Data4_2, Data4_3, Data4_4, Data4_5, Data4_6, Data4_7, Data4_8 } };
return guid;
}
inline GUID xorGUID(const GUID & v1, const GUID & v2) {
GUID temp; memxor(&temp, &v1, &v2, sizeof(GUID)); return temp;
}
class format_guid_cpp : public string_formatter {
public:
format_guid_cpp(const GUID & guid);
};
GUID createGUID();
uint64_t halveGUID( const GUID & id );
}

51
pfc/instance_tracker.h Normal file
View File

@@ -0,0 +1,51 @@
#pragma once
namespace pfc {
template<typename t_object>
class instance_tracker_server_t {
public:
void add(t_object * p_object) {
m_list.add_item(p_object);
}
void remove(t_object * p_object) {
m_list.remove_item(p_object);
}
t_size get_count() const {return m_list.get_count();}
t_object * get_item(t_size p_index) {return m_list[p_index];}
t_object * operator[](t_size p_index) {return m_list[p_index];}
private:
ptr_list_hybrid_t<t_object,4> m_list;
};
template<typename t_object,instance_tracker_server_t<t_object> & p_server>
class instance_tracker_client_t {
public:
instance_tracker_client_t(t_object* p_ptr) : m_ptr(NULL), m_added(false) {initialize(p_ptr);}
instance_tracker_client_t() : m_ptr(NULL), m_added(false) {}
void initialize(t_object * p_ptr) {
uninitialize();
p_server.add(p_ptr);
m_ptr = p_ptr;
m_added = true;
}
void uninitialize() {
if (m_added) {
p_server.remove(m_ptr);
m_ptr = NULL;
m_added = false;
}
}
~instance_tracker_client_t() {
uninitialize();
}
private:
bool m_added;
t_object * m_ptr;
};
}

95
pfc/int_types.h Normal file
View File

@@ -0,0 +1,95 @@
#pragma once
#include <stdint.h>
typedef int64_t t_int64;
typedef uint64_t t_uint64;
typedef int32_t t_int32;
typedef uint32_t t_uint32;
typedef int16_t t_int16;
typedef uint16_t t_uint16;
typedef int8_t t_int8;
typedef uint8_t t_uint8;
typedef int t_int;
typedef unsigned int t_uint;
typedef float t_float32;
typedef double t_float64;
namespace pfc {
template<unsigned t_bytes>
class sized_int_t;
template<> class sized_int_t<1> {
public:
typedef t_uint8 t_unsigned;
typedef t_int8 t_signed;
};
template<> class sized_int_t<2> {
public:
typedef t_uint16 t_unsigned;
typedef t_int16 t_signed;
};
template<> class sized_int_t<4> {
public:
typedef t_uint32 t_unsigned;
typedef t_int32 t_signed;
};
template<> class sized_int_t<8> {
public:
typedef t_uint64 t_unsigned;
typedef t_int64 t_signed;
};
}
typedef size_t t_size;
typedef pfc::sized_int_t< sizeof(size_t) >::t_signed t_ssize;
inline t_size MulDiv_Size(t_size x,t_size y,t_size z) {return (t_size) ( ((t_uint64)x * (t_uint64)y) / (t_uint64)z );}
#define pfc_infinite (~0)
namespace pfc {
const t_uint16 infinite16 = (t_uint16)(~0);
const t_uint32 infinite32 = (t_uint32)(~0);
const t_uint64 infinite64 = (t_uint64)(~0);
const t_size infinite_size = (t_size)(~0);
template<typename T> class int_specs_t;
template<typename T>
class int_specs_signed_t {
public:
inline static T get_min() {return ((T)1<<(sizeof(T)*8-1));}
inline static T get_max() {return ~((T)1<<(sizeof(T)*8-1));}
enum {is_signed = true};
};
template<typename T>
class int_specs_unsigned_t {
public:
inline static T get_min() {return (T)0;}
inline static T get_max() {return (T)~0;}
enum {is_signed = false};
};
template<> class int_specs_t<char> : public int_specs_signed_t<char> {};
template<> class int_specs_t<unsigned char> : public int_specs_unsigned_t<unsigned char> {};
template<> class int_specs_t<short> : public int_specs_signed_t<short> {};
template<> class int_specs_t<unsigned short> : public int_specs_unsigned_t<unsigned short> {};
template<> class int_specs_t<int> : public int_specs_signed_t<int> {};
template<> class int_specs_t<unsigned int> : public int_specs_unsigned_t<unsigned int> {};
template<> class int_specs_t<long> : public int_specs_signed_t<long> {};
template<> class int_specs_t<unsigned long> : public int_specs_unsigned_t<unsigned long> {};
template<> class int_specs_t<long long> : public int_specs_signed_t<long long> {};
template<> class int_specs_t<unsigned long long> : public int_specs_unsigned_t<unsigned long long> {};
template<> class int_specs_t<wchar_t> : public int_specs_unsigned_t<wchar_t> {};
};

140
pfc/iterators.h Normal file
View File

@@ -0,0 +1,140 @@
#pragma once
#include "ref_counter.h"
namespace pfc {
//! Base class for list nodes. Implemented by list implementers.
template<typename t_item> class _list_node : public refcounted_object_root {
public:
typedef _list_node<t_item> t_self;
template<typename ... arg_t> _list_node(arg_t && ... arg) : m_content( std::forward<arg_t>(arg) ...) {}
t_item m_content;
virtual t_self * prev() throw() {return NULL;}
virtual t_self * next() throw() {return NULL;}
t_self * walk(bool forward) throw() {return forward ? next() : prev();}
};
template<typename t_item> class const_iterator {
public:
typedef _list_node<t_item> t_node;
typedef refcounted_object_ptr_t<t_node> t_nodeptr;
typedef const_iterator<t_item> t_self;
bool is_empty() const throw() {return m_content.is_empty();}
bool is_valid() const throw() {return m_content.is_valid();}
void invalidate() throw() {m_content = NULL;}
void walk(bool forward) throw() {m_content = m_content->walk(forward);}
void prev() throw() {m_content = m_content->prev();}
void next() throw() {m_content = m_content->next();}
//! For internal use / list implementations only! Do not call!
t_node* _node() const throw() {return m_content.get_ptr();}
const_iterator() {}
const_iterator(t_node* source) : m_content(source) {}
const_iterator(t_nodeptr const & source) : m_content(source) {}
const_iterator(t_self const & other) : m_content(other.m_content) {}
const_iterator(t_self && other) : m_content(std::move(other.m_content)) {}
t_self const & operator=(t_self const & other) {m_content = other.m_content; return *this;}
t_self const & operator=(t_self && other) {m_content = std::move(other.m_content); return *this;}
const t_item& operator*() const throw() {return m_content->m_content;}
const t_item* operator->() const throw() {return &m_content->m_content;}
const t_self & operator++() throw() {this->next(); return *this;}
const t_self & operator--() throw() {this->prev(); return *this;}
t_self operator++(int) throw() {t_self old = *this; this->next(); return old;}
t_self operator--(int) throw() {t_self old = *this; this->prev(); return old;}
bool operator==(const t_self & other) const throw() {return this->m_content == other.m_content;}
bool operator!=(const t_self & other) const throw() {return this->m_content != other.m_content;}
protected:
t_nodeptr m_content;
};
template<typename t_item> class iterator : public const_iterator<t_item> {
public:
typedef const_iterator<t_item> t_selfConst;
typedef iterator<t_item> t_self;
typedef _list_node<t_item> t_node;
typedef refcounted_object_ptr_t<t_node> t_nodeptr;
iterator() {}
iterator(t_node* source) : t_selfConst(source) {}
iterator(t_nodeptr const & source) : t_selfConst(source) {}
iterator(t_self const & other) : t_selfConst(other) {}
iterator(t_self && other) : t_selfConst(std::move(other)) {}
t_self const & operator=(t_self const & other) {this->m_content = other.m_content; return *this;}
t_self const & operator=(t_self && other) {this->m_content = std::move(other.m_content); return *this;}
t_item& operator*() const throw() {return this->m_content->m_content;}
t_item* operator->() const throw() {return &this->m_content->m_content;}
const t_self & operator++() throw() {this->next(); return *this;}
const t_self & operator--() throw() {this->prev(); return *this;}
t_self operator++(int) throw() {t_self old = *this; this->next(); return old;}
t_self operator--(int) throw() {t_self old = *this; this->prev(); return old;}
bool operator==(const t_self & other) const throw() {return this->m_content == other.m_content;}
bool operator!=(const t_self & other) const throw() {return this->m_content != other.m_content;}
};
template<typename t_comparator = comparator_default>
class comparator_list {
public:
template<typename t_list1, typename t_list2>
static int compare(const t_list1 & p_list1, const t_list2 & p_list2) {
typename t_list1::const_iterator iter1 = p_list1.first();
typename t_list2::const_iterator iter2 = p_list2.first();
for(;;) {
if (iter1.is_empty() && iter2.is_empty()) return 0;
else if (iter1.is_empty()) return -1;
else if (iter2.is_empty()) return 1;
else {
int state = t_comparator::compare(*iter1,*iter2);
if (state != 0) return state;
}
++iter1; ++iter2;
}
}
};
template<typename t_list1, typename t_list2>
static bool listEquals(const t_list1 & p_list1, const t_list2 & p_list2) {
typename t_list1::const_iterator iter1 = p_list1.first();
typename t_list2::const_iterator iter2 = p_list2.first();
for(;;) {
if (iter1.is_empty() && iter2.is_empty()) return true;
else if (iter1.is_empty() || iter2.is_empty()) return false;
else if (*iter1 != *iter2) return false;
++iter1; ++iter2;
}
}
template<typename comparator_t = comparator_default>
class comparator_stdlist {
public:
template<typename t_list1, typename t_list2>
static int compare(const t_list1 & p_list1, const t_list2 & p_list2) {
auto iter1 = p_list1.begin();
auto iter2 = p_list2.begin();
for(;;) {
const bool end1 = iter1 == p_list1.end();
const bool end2 = iter2 == p_list2.end();
if ( end1 && end2 ) return 0;
else if ( end1 ) return -1;
else if ( end2 ) return 1;
else {
int state = comparator_t::compare(*iter1,*iter2);
if (state != 0) return state;
}
++iter1; ++iter2;
}
}
};
}

640
pfc/list.h Normal file
View File

@@ -0,0 +1,640 @@
#pragma once
namespace pfc {
template<typename T>
class NOVTABLE list_base_const_t {
private: typedef list_base_const_t<T> t_self;
public:
typedef T t_item;
virtual t_size get_count() const = 0;
virtual void get_item_ex(T& p_out, t_size n) const = 0;
inline t_size get_size() const {return get_count();}
inline T get_item(t_size n) const {T temp; get_item_ex(temp,n); return temp;}
inline T operator[](t_size n) const {T temp; get_item_ex(temp,n); return temp;}
template<typename t_compare>
t_size find_duplicates_sorted_t(t_compare p_compare,bit_array_var & p_out) const
{
return ::pfc::find_duplicates_sorted_t<list_base_const_t<T> const &,t_compare>(*this,get_count(),p_compare,p_out);
}
template<typename t_compare,typename t_permutation>
t_size find_duplicates_sorted_permutation_t(t_compare p_compare,t_permutation const & p_permutation,bit_array_var & p_out)
{
return ::pfc::find_duplicates_sorted_permutation_t<list_base_const_t<T> const &,t_compare,t_permutation>(*this,get_count(),p_compare,p_permutation,p_out);
}
template<typename t_search>
t_size find_item(const t_search & p_item) const//returns index of first occurance, infinite if not found
{
t_size n,max = get_count();
for(n=0;n<max;n++)
if (get_item(n)==p_item) return n;
return ~0;
}
template<typename t_search>
inline bool have_item(const t_search & p_item) const {return find_item<t_search>(p_item)!=~0;}
template<typename t_compare, typename t_param>
bool bsearch_t(t_compare p_compare,t_param const & p_param,t_size &p_index) const {
return ::pfc::bsearch_t(get_count(),*this,p_compare,p_param,p_index);
}
template<typename t_compare,typename t_param,typename t_permutation>
bool bsearch_permutation_t(t_compare p_compare,t_param const & p_param,const t_permutation & p_permutation,t_size & p_index) const {
return ::pfc::bsearch_permutation_t(get_count(),*this,p_compare,p_param,p_permutation,p_index);
}
template<typename t_compare,typename t_permutation>
void sort_get_permutation_t(t_compare p_compare,t_permutation const & p_permutation) const {
::pfc::sort_get_permutation_t<list_base_const_t<T>,t_compare,t_permutation>(*this,p_compare,get_count(),p_permutation);
}
template<typename t_compare,typename t_permutation>
void sort_stable_get_permutation_t(t_compare p_compare,t_permutation const & p_permutation) const {
::pfc::sort_stable_get_permutation_t<list_base_const_t<T>,t_compare,t_permutation>(*this,p_compare,get_count(),p_permutation);
}
template<typename t_callback>
void enumerate(t_callback & p_callback) const {
for(t_size n = 0, m = get_count(); n < m; ++n ) {
p_callback( (*this)[n] );
}
}
static bool g_equals(const t_self & item1, const t_self & item2) {
const t_size count = item1.get_count();
if (count != item2.get_count()) return false;
for(t_size walk = 0; walk < count; ++walk) if (item1[walk] != item2[walk]) return false;
return true;
}
bool operator==(const t_self & item2) const {return g_equals(*this,item2);}
bool operator!=(const t_self & item2) const {return !g_equals(*this,item2);}
protected:
list_base_const_t() {}
~list_base_const_t() {}
list_base_const_t(const t_self &) {}
void operator=(const t_self &) {}
};
template<typename T>
class list_single_ref_t : public list_base_const_t<T>
{
public:
list_single_ref_t(const T & p_item,t_size p_count = 1) : m_item(p_item), m_count(p_count) {}
t_size get_count() const {return m_count;}
void get_item_ex(T& p_out,t_size n) const {PFC_ASSERT(n<m_count); p_out = m_item;}
private:
const T & m_item;
t_size m_count;
};
template<typename T>
class list_partial_ref_t : public list_base_const_t<T>
{
public:
list_partial_ref_t(const list_base_const_t<T> & p_list,t_size p_base,t_size p_count)
: m_list(p_list), m_base(p_base), m_count(p_count)
{
PFC_ASSERT(m_base + m_count <= m_list.get_count());
}
private:
const list_base_const_t<T> & m_list;
t_size m_base,m_count;
t_size get_count() const {return m_count;}
void get_item_ex(T & p_out,t_size n) const {m_list.get_item_ex(p_out,n+m_base);}
};
template<typename T,typename A>
class list_const_array_t : public list_base_const_t<T>
{
public:
inline list_const_array_t(A p_data,t_size p_count) : m_data(p_data), m_count(p_count) {}
t_size get_count() const {return m_count;}
void get_item_ex(T & p_out,t_size n) const {p_out = m_data[n];}
private:
A m_data;
t_size m_count;
};
template<typename t_array>
class list_const_array_ref_t : public list_base_const_t<typename t_array::t_item> {
public:
list_const_array_ref_t(const t_array & data) : m_data(data) {}
t_size get_count() const {return m_data.get_size();}
void get_item_ex(typename t_array::t_item & out, t_size n) const {out = m_data[n];}
private:
const t_array & m_data;
};
template<typename to,typename from>
class list_const_cast_t : public list_base_const_t<to>
{
public:
list_const_cast_t(const list_base_const_t<from> & p_from) : m_from(p_from) {}
t_size get_count() const {return m_from.get_count();}
void get_item_ex(to & p_out,t_size n) const
{
from temp;
m_from.get_item_ex(temp,n);
p_out = temp;
}
private:
const list_base_const_t<from> & m_from;
};
template<typename T,typename A>
class ptr_list_const_array_t : public list_base_const_t<T*>
{
public:
inline ptr_list_const_array_t(A p_data,t_size p_count) : m_data(p_data), m_count(p_count) {}
t_size get_count() const {return m_count;}
void get_item_ex(T* & p_out,t_size n) const {p_out = &m_data[n];}
private:
A m_data;
t_size m_count;
};
template<typename T>
class list_const_ptr_t : public list_base_const_t<T>
{
public:
inline list_const_ptr_t(const T * p_data,t_size p_count) : m_data(p_data), m_count(p_count) {}
t_size get_count() const {return m_count;}
void get_item_ex(T & p_out,t_size n) const {p_out = m_data[n];}
private:
const T * m_data;
t_size m_count;
};
template<typename T>
class NOVTABLE list_base_t : public list_base_const_t<T> {
private:
typedef list_base_t<T> t_self;
typedef const list_base_const_t<T> t_self_const;
public:
class NOVTABLE sort_callback
{
public:
virtual int compare(const T& p_item1,const T& p_item2) = 0;
};
virtual void filter_mask(const bit_array & mask) = 0;
virtual t_size insert_items(const list_base_const_t<T> & items,t_size base) = 0;
virtual void reorder_partial(t_size p_base,const t_size * p_data,t_size p_count) = 0;
virtual void sort(sort_callback & p_callback) = 0;
virtual void sort_stable(sort_callback & p_callback) = 0;
virtual void replace_item(t_size p_index,const T& p_item) = 0;
virtual void swap_item_with(t_size p_index,T & p_item) = 0;
virtual void swap_items(t_size p_index1,t_size p_index2) = 0;
inline void reorder(const t_size * p_data) {reorder_partial(0,p_data,this->get_count());}
inline t_size insert_item(const T & item,t_size base) {return insert_items(list_single_ref_t<T>(item),base);}
t_size insert_items_repeat(const T & item,t_size num,t_size base) {return insert_items(list_single_ref_t<T>(item,num),base);}
inline t_size add_items_repeat(T item,t_size num) {return insert_items_repeat(item,num,~0);}
t_size insert_items_fromptr(const T* source,t_size num,t_size base) {return insert_items(list_const_ptr_t<T>(source,num),base);}
inline t_size add_items_fromptr(const T* source,t_size num) {return insert_items_fromptr(source,num,~0);}
inline t_size add_items(const list_base_const_t<T> & items) {return insert_items(items,~0);}
inline t_size add_item(const T& item) {return insert_item(item,~0);}
inline void remove_mask(const bit_array & mask) {filter_mask(bit_array_not(mask));}
inline void remove_all() {filter_mask(bit_array_false());}
inline void truncate(t_size val) {if (val < this->get_count()) remove_mask(bit_array_range(val,this->get_count()-val,true));}
inline T replace_item_ex(t_size p_index,const T & p_item) {T ret = p_item;swap_item_with(p_index,ret);return ret;}
inline T operator[](t_size n) const {return this->get_item(n);}
template<typename t_compare>
class sort_callback_impl_t : public sort_callback
{
public:
sort_callback_impl_t(t_compare p_compare) : m_compare(p_compare) {}
int compare(const T& p_item1,const T& p_item2) {return m_compare(p_item1,p_item2);}
private:
t_compare m_compare;
};
class sort_callback_auto : public sort_callback
{
public:
int compare(const T& p_item1,const T& p_item2) {return ::pfc::compare_t(p_item1,p_item2);}
};
void sort() {sort_callback_auto cb;sort(cb);}
template<typename t_compare> void sort_t(t_compare p_compare) {sort_callback_impl_t<t_compare> cb(p_compare);sort(cb);}
template<typename t_compare> void sort_stable_t(t_compare p_compare) {sort_callback_impl_t<t_compare> cb(p_compare); sort_stable(cb);}
template<typename t_compare> void sort_remove_duplicates_t(t_compare p_compare)
{
sort_t<t_compare>(p_compare);
bit_array_bittable array(this->get_count());
if (this->template find_duplicates_sorted_t<t_compare>(p_compare,array) > 0)
remove_mask(array);
}
template<typename t_compare> void sort_stable_remove_duplicates_t(t_compare p_compare)
{
sort_stable_t<t_compare>(p_compare);
bit_array_bittable array(this->get_count());
if (this->template find_duplicates_sorted_t<t_compare>(p_compare,array) > 0)
remove_mask(array);
}
template<typename t_compare> void remove_duplicates_t(t_compare p_compare)
{
order_helper order(this->get_count());
sort_get_permutation_t<t_compare,order_helper&>(p_compare,order);
bit_array_bittable array(this->get_count());
if (this->template find_duplicates_sorted_permutation_t<t_compare,order_helper const&>(p_compare,order,array) > 0)
remove_mask(array);
}
template<typename t_func>
void for_each(t_func p_func) {
t_size n,max=this->get_count();
for(n=0;n<max;n++) p_func(this->get_item(n));
}
template<typename t_func>
void for_each(t_func p_func,const bit_array & p_mask) {
t_size n,max=this->get_count();
for(n=p_mask.find(true,0,max);n<max;n=p_mask.find(true,n+1,max-n-1)) {
p_func(this->get_item(n));
}
}
template<typename t_releasefunc>
void remove_mask_ex(const bit_array & p_mask,t_releasefunc p_func) {
this->template for_each<t_releasefunc>(p_func,p_mask);
remove_mask(p_mask);
}
template<typename t_releasefunc>
void remove_all_ex(t_releasefunc p_func) {
this->template for_each<t_releasefunc>(p_func);
remove_all();
}
template<typename t_in> t_self & operator=(t_in const & source) {remove_all(); add_items(source); return *this;}
template<typename t_in> t_self & operator+=(t_in const & p_source) {add_item(p_source); return *this;}
template<typename t_in> t_self & operator|=(t_in const & p_source) {add_items(p_source); return *this;}
protected:
list_base_t() {}
~list_base_t() {}
list_base_t(const t_self&) {}
void operator=(const t_self&) {}
};
template<typename T,typename t_storage>
class list_impl_t : public list_base_t<T>
{
public:
typedef list_base_t<T> t_base;
typedef list_impl_t<T, t_storage> t_self;
list_impl_t() {}
list_impl_t(const t_self & p_source) { add_items(p_source); }
void prealloc(t_size count) {m_buffer.prealloc(count);}
void set_count(t_size p_count) {m_buffer.set_size(p_count);}
void set_size(t_size p_count) {m_buffer.set_size(p_count);}
template<typename t_in>
t_size _insert_item_t(const t_in & item, t_size idx) {
return ::pfc::insert_t(m_buffer, item, idx);
}
template<typename t_in>
t_size insert_item(const t_in & item, t_size idx) {
return _insert_item_t(item, idx);
}
t_size insert_item(const T& item,t_size idx) {
return _insert_item_t(item, idx);
}
T remove_by_idx(t_size idx)
{
T ret = m_buffer[idx];
t_size n;
t_size max = m_buffer.get_size();
for(n=idx+1;n<max;n++) {
::pfc::move_t(m_buffer[n-1],m_buffer[n]);
}
m_buffer.set_size(max-1);
return ret;
}
inline void get_item_ex(T& p_out,t_size n) const
{
PFC_ASSERT(n>=0);
PFC_ASSERT(n<get_size());
p_out = m_buffer[n];
}
inline const T& get_item_ref(t_size n) const
{
PFC_ASSERT(n>=0);
PFC_ASSERT(n<get_size());
return m_buffer[n];
}
inline T get_item(t_size n) const
{
PFC_ASSERT(n >= 0);
PFC_ASSERT(n < get_size() );
return m_buffer[n];
};
inline t_size get_count() const {return m_buffer.get_size();}
inline t_size get_size() const {return m_buffer.get_size();}
inline const T & operator[](t_size n) const
{
PFC_ASSERT(n>=0);
PFC_ASSERT(n<get_size());
return m_buffer[n];
}
inline const T* get_ptr() const {return m_buffer.get_ptr();}
inline T* get_ptr() {return m_buffer.get_ptr();}
inline T& operator[](t_size n) {return m_buffer[n];}
inline void remove_from_idx(t_size idx,t_size num)
{
remove_mask(bit_array_range(idx,num));
}
t_size _insert_items_v(const list_base_const_t<T> & source,t_size base) { //workaround for inefficient operator[] on virtual-interface-accessed lists
t_size count = get_size();
if (base>count) base = count;
t_size num = source.get_count();
m_buffer.set_size(count+num);
if (count > base) {
for(t_size n=count-1;(int)n>=(int)base;n--) {
::pfc::move_t(m_buffer[n+num],m_buffer[n]);
}
}
for(t_size n=0;n<num;n++) {
source.get_item_ex(m_buffer[n+base],n);
}
return base;
}
// use _insert_items_v where it's more efficient
t_size insert_items(const list_base_const_t<T> & source,t_size base) {return _insert_items_v(source, base);}
t_size insert_items(const list_base_t<T> & source,t_size base) {return _insert_items_v(source, base);}
template<typename t_in>
t_size insert_items(const t_in & source,t_size base) {
t_size count = get_size();
if (base>count) base = count;
t_size num = array_size_t(source);
m_buffer.set_size(count+num);
if (count > base) {
for(t_size n=count-1;(int)n>=(int)base;n--) {
::pfc::move_t(m_buffer[n+num],m_buffer[n]);
}
}
for(t_size n=0;n<num;n++) {
m_buffer[n+base] = source[n];
}
return base;
}
template<typename t_in>
void add_items(const t_in & in) {insert_items(in, ~0);}
void get_items_mask(list_impl_t<T,t_storage> & out,const bit_array & mask)
{
mask.walk( get_size(), [&] (size_t n) {
out.add_item(m_buffer[n]);
} );
}
void filter_mask(const bit_array & mask)
{
t_size n,count = get_size(), total = 0;
n = total = mask.find(false,0,count);
if (n<count) {
for(n=mask.find(true,n+1,count-n-1);n<count;n=mask.find(true,n+1,count-n-1))
::pfc::move_t(m_buffer[total++],m_buffer[n]);
m_buffer.set_size(total);
}
}
void replace_item(t_size idx,const T& item)
{
PFC_ASSERT(idx>=0);
PFC_ASSERT(idx<get_size());
m_buffer[idx] = item;
}
void sort()
{
::pfc::sort_callback_impl_auto_wrap_t<t_storage> wrapper(m_buffer);
::pfc::sort(wrapper,get_size());
}
template<typename t_compare>
void sort_t(t_compare p_compare)
{
::pfc::sort_callback_impl_simple_wrap_t<t_storage,t_compare> wrapper(m_buffer,p_compare);
::pfc::sort(wrapper,get_size());
}
template<typename t_compare>
void sort_stable_t(t_compare p_compare)
{
::pfc::sort_callback_impl_simple_wrap_t<t_storage,t_compare> wrapper(m_buffer,p_compare);
::pfc::sort_stable(wrapper,get_size());
}
inline void reorder_partial(t_size p_base,const t_size * p_order,t_size p_count)
{
PFC_ASSERT(p_base+p_count<=get_size());
::pfc::reorder_partial_t(m_buffer,p_base,p_order,p_count);
}
template<typename t_compare>
t_size find_duplicates_sorted_t(t_compare p_compare,bit_array_var & p_out) const
{
return ::pfc::find_duplicates_sorted_t<list_impl_t<T,t_storage> const &,t_compare>(*this,get_size(),p_compare,p_out);
}
template<typename t_compare,typename t_permutation>
t_size find_duplicates_sorted_permutation_t(t_compare p_compare,t_permutation p_permutation,bit_array_var & p_out)
{
return ::pfc::find_duplicates_sorted_permutation_t<list_impl_t<T,t_storage> const &,t_compare,t_permutation>(*this,get_size(),p_compare,p_permutation,p_out);
}
void move_from(t_self & other) {
remove_all();
m_buffer = std::move(other.m_buffer);
}
private:
class sort_callback_wrapper
{
public:
explicit inline sort_callback_wrapper(typename t_base::sort_callback & p_callback) : m_callback(p_callback) {}
inline int operator()(const T& item1,const T& item2) const {return m_callback.compare(item1,item2);}
private:
typename t_base::sort_callback & m_callback;
};
public:
void sort(typename t_base::sort_callback & p_callback)
{
sort_t(sort_callback_wrapper(p_callback));
}
void sort_stable(typename t_base::sort_callback & p_callback)
{
sort_stable_t(sort_callback_wrapper(p_callback));
}
void remove_mask(const bit_array & mask) {filter_mask(bit_array_not(mask));}
void remove_mask(const bool * mask) {remove_mask(bit_array_table(mask,get_size()));}
void filter_mask(const bool * mask) {filter_mask(bit_array_table(mask,get_size()));}
t_size add_item(const T& item) {
return insert_item(item, ~0);
}
template<typename t_in> t_size add_item(const t_in & item) {
return insert_item(item, ~0);
}
void remove_all() {remove_mask(bit_array_true());}
void remove_item(const T& item)
{
t_size n,max = get_size();
bit_array_bittable mask(max);
for(n=0;n<max;n++)
mask.set(n,get_item(n)==item);
remove_mask(mask);
}
void swap_item_with(t_size p_index,T & p_item)
{
PFC_ASSERT(p_index < get_size());
swap_t(m_buffer[p_index],p_item);
}
void swap_items(t_size p_index1,t_size p_index2)
{
PFC_ASSERT(p_index1 < get_size());
PFC_ASSERT(p_index2 < get_size());
swap_t(m_buffer[p_index1],m_buffer[p_index2]);
}
inline static void g_swap(list_impl_t<T,t_storage> & p_item1,list_impl_t<T,t_storage> & p_item2)
{
swap_t(p_item1.m_buffer,p_item2.m_buffer);
}
template<typename t_search>
t_size find_item(const t_search & p_item) const//returns index of first occurance, infinite if not found
{
t_size n,max = get_size();
for(n=0;n<max;n++)
if (m_buffer[n]==p_item) return n;
return ~0;
}
template<typename t_search>
inline bool have_item(const t_search & p_item) const {return this->template find_item<t_search>(p_item)!=~0;}
template<typename t_in> t_self & operator=(t_in const & source) {remove_all(); add_items(source); return *this;}
template<typename t_in> t_self & operator+=(t_in const & p_source) {add_item(p_source); return *this;}
template<typename t_in> t_self & operator|=(t_in const & p_source) {add_items(p_source); return *this;}
protected:
t_storage m_buffer;
};
template<typename t_item, template<typename> class t_alloc = alloc_fast >
class list_t : public list_impl_t<t_item,array_t<t_item,t_alloc> > {
public:
typedef list_t<t_item, t_alloc> t_self;
template<typename t_in> t_self & operator=(t_in const & source) {this->remove_all(); this->add_items(source); return *this;}
template<typename t_in> t_self & operator+=(t_in const & p_source) {this->add_item(p_source); return *this;}
template<typename t_in> t_self & operator|=(t_in const & p_source) {this->add_items(p_source); return *this;}
};
template<typename t_item, t_size p_fixed_count, template<typename> class t_alloc = alloc_fast >
class list_hybrid_t : public list_impl_t<t_item,array_hybrid_t<t_item,p_fixed_count,t_alloc> > {
public:
typedef list_hybrid_t<t_item, p_fixed_count, t_alloc> t_self;
template<typename t_in> t_self & operator=(t_in const & source) {this->remove_all(); this->add_items(source); return *this;}
template<typename t_in> t_self & operator+=(t_in const & p_source) {this->add_item(p_source); return *this;}
template<typename t_in> t_self & operator|=(t_in const & p_source) {this->add_items(p_source); return *this;}
};
template<typename T>
class ptr_list_const_cast_t : public list_base_const_t<const T *>
{
public:
inline ptr_list_const_cast_t(const list_base_const_t<T*> & p_param) : m_param(p_param) {}
t_size get_count() const {return m_param.get_count();}
void get_item_ex(const T * & p_out,t_size n) const {T* temp; m_param.get_item_ex(temp,n); p_out = temp;}
private:
const list_base_const_t<T*> & m_param;
};
template<typename T,typename P>
class list_const_permutation_t : public list_base_const_t<T>
{
public:
inline list_const_permutation_t(const list_base_const_t<T> & p_list,P p_permutation) : m_list(p_list), m_permutation(p_permutation) {}
t_size get_count() const {return m_list.get_count();}
void get_item_ex(T & p_out,t_size n) const {m_list.get_item_ex(p_out,m_permutation[n]);}
private:
P m_permutation;
const list_base_const_t<T> & m_list;
};
template<class T>
class list_permutation_t : public list_base_const_t<T>
{
public:
t_size get_count() const {return m_count;}
void get_item_ex(T & p_out,t_size n) const {m_base.get_item_ex(p_out,m_order[n]);}
list_permutation_t(const list_base_const_t<T> & p_base,const t_size * p_order,t_size p_count)
: m_base(p_base), m_order(p_order), m_count(p_count)
{
PFC_ASSERT(m_base.get_count() >= m_count);
}
private:
const list_base_const_t<T> & m_base;
const t_size * m_order;
t_size m_count;
};
template<typename item, template<typename> class alloc> class traits_t<list_t<item, alloc> > : public combine_traits<traits_t<alloc<item> >, traits_vtable> {};
}

72
pfc/lockless.h Normal file
View File

@@ -0,0 +1,72 @@
#pragma once
#include <functional>
#ifdef _MSC_VER
#include <intrin.h>
#endif
namespace pfc {
class threadSafeInt {
public:
typedef long t_val;
threadSafeInt(t_val p_val = 0) : m_val(p_val) {}
long operator++() throw() { return inc(); }
long operator--() throw() { return dec(); }
long operator++(int) throw() { return inc() - 1; }
long operator--(int) throw() { return dec() + 1; }
operator t_val() const throw() { return m_val; }
t_val exchange(t_val newVal) {
#ifdef _MSC_VER
return InterlockedExchange(&m_val, newVal);
#else
return __sync_lock_test_and_set(&m_val, newVal);
#endif
}
private:
t_val inc() {
#ifdef _MSC_VER
return _InterlockedIncrement(&m_val);
#else
return __sync_add_and_fetch(&m_val, 1);
#endif
}
t_val dec() {
#ifdef _MSC_VER
return _InterlockedDecrement(&m_val);
#else
return __sync_sub_and_fetch(&m_val, 1);
#endif
}
volatile t_val m_val;
};
typedef threadSafeInt counter;
typedef threadSafeInt refcounter;
void yield(); // forward declaration
//! Minimalist class to call some function only once. \n
//! Presumes low probability of concurrent run() calls actually happening, \n
//! but frequent calls once already initialized, hence only using basic volatile bool check. \n
//! If using a modern compiler you might want to use std::call_once instead. \n
//! The called function is not expected to throw exceptions.
class runOnceLock {
public:
void run(std::function<void()> f) {
if (m_done) return;
if (m_once.exchange(1) == 0) {
f();
m_done = true;
} else {
while (!m_done) yield();
}
}
private:
threadSafeInt m_once;
volatile bool m_done = false;
};
}

268
pfc/map.h Normal file
View File

@@ -0,0 +1,268 @@
#pragma once
namespace pfc {
PFC_DECLARE_EXCEPTION(exception_map_entry_not_found,exception,"Map entry not found");
template<typename t_destination> class __map_overwrite_wrapper {
public:
__map_overwrite_wrapper(t_destination & p_destination) : m_destination(p_destination) {}
template<typename t_key,typename t_value> void operator() (const t_key & p_key,const t_value & p_value) {m_destination.set(p_key,p_value);}
private:
t_destination & m_destination;
};
template<typename t_storage_key, typename t_storage_value, typename t_comparator = comparator_default>
class map_t {
private:
typedef map_t<t_storage_key,t_storage_value,t_comparator> t_self;
public:
typedef t_storage_key t_key; typedef t_storage_value t_value;
template<typename _t_key,typename _t_value>
void set(const _t_key & p_key, const _t_value & p_value) {
bool isnew;
t_storage & storage = m_data.add_ex(t_search_set<_t_key,_t_value>(p_key,p_value), isnew);
if (!isnew) storage.m_value = p_value;
}
template<typename _t_key>
t_storage_value & find_or_add(_t_key const & p_key) {
return m_data.add(t_search_query<_t_key>(p_key)).m_value;
}
template<typename _t_key>
t_storage_value & find_or_add_ex(_t_key const & p_key,bool & p_isnew) {
return m_data.add_ex(t_search_query<_t_key>(p_key),p_isnew).m_value;
}
template<typename _t_key>
bool have_item(const _t_key & p_key) const {
return m_data.have_item(t_search_query<_t_key>(p_key));
}
template<typename _t_key,typename _t_value>
bool query(const _t_key & p_key,_t_value & p_value) const {
const t_storage * storage = m_data.find_ptr(t_search_query<_t_key>(p_key));
if (storage == NULL) return false;
p_value = storage->m_value;
return true;
}
template<typename _t_key>
const t_storage_value & operator[] (const _t_key & p_key) const {
const t_storage_value * ptr = query_ptr(p_key);
if (ptr == NULL) throw exception_map_entry_not_found();
return *ptr;
}
template<typename _t_key>
t_storage_value & operator[] (const _t_key & p_key) {
return find_or_add(p_key);
}
template<typename _t_key>
const t_storage_value * query_ptr(const _t_key & p_key) const {
const t_storage * storage = m_data.find_ptr(t_search_query<_t_key>(p_key));
if (storage == NULL) return NULL;
return &storage->m_value;
}
template<typename _t_key>
t_storage_value * query_ptr(const _t_key & p_key) {
t_storage * storage = m_data.find_ptr(t_search_query<_t_key>(p_key));
if (storage == NULL) return NULL;
return &storage->m_value;
}
template<typename _t_key>
bool query_ptr(const _t_key & p_key, const t_storage_value * & out) const {
const t_storage * storage = m_data.find_ptr(t_search_query<_t_key>(p_key));
if (storage == NULL) return false;
out = &storage->m_value;
return true;
}
template<typename _t_key>
bool query_ptr(const _t_key & p_key, t_storage_value * & out) {
t_storage * storage = m_data.find_ptr(t_search_query<_t_key>(p_key));
if (storage == NULL) return false;
out = &storage->m_value;
return true;
}
template<bool inclusive,bool above,typename _t_key>
const t_storage_value * query_nearest_ptr(_t_key & p_key) const {
const t_storage * storage = m_data.template find_nearest_item<inclusive,above>(t_search_query<_t_key>(p_key));
if (storage == NULL) return NULL;
p_key = storage->m_key;
return &storage->m_value;
}
template<bool inclusive,bool above,typename _t_key>
t_storage_value * query_nearest_ptr(_t_key & p_key) {
t_storage * storage = m_data.template find_nearest_item<inclusive,above>(t_search_query<_t_key>(p_key));
if (storage == NULL) return NULL;
p_key = storage->m_key;
return &storage->m_value;
}
template<bool inclusive,bool above,typename _t_key,typename _t_value>
bool query_nearest(_t_key & p_key,_t_value & p_value) const {
const t_storage * storage = m_data.template find_nearest_item<inclusive,above>(t_search_query<_t_key>(p_key));
if (storage == NULL) return false;
p_key = storage->m_key;
p_value = storage->m_value;
return true;
}
template<typename _t_key>
bool remove(const _t_key & p_key) {
return m_data.remove_item(t_search_query<_t_key>(p_key));
}
template<typename t_callback>
void enumerate(t_callback && p_callback) const {
enumeration_wrapper<t_callback> cb(p_callback);
m_data.enumerate(cb);
}
template<typename t_callback>
void enumerate(t_callback && p_callback) {
enumeration_wrapper_var<t_callback> cb(p_callback);
m_data._enumerate_var(cb);
}
t_size get_count() const throw() {return m_data.get_count();}
void remove_all() throw() {m_data.remove_all();}
template<typename t_source>
void overwrite(const t_source & p_source) {
__map_overwrite_wrapper<t_self> wrapper(*this);
p_source.enumerate(wrapper);
}
//backwards compatibility method wrappers
template<typename _t_key> bool exists(const _t_key & p_key) const {return have_item(p_key);}
template<typename _t_key> bool get_first(_t_key & p_out) const {
t_retrieve_key<_t_key> wrap(p_out);
return m_data.get_first(wrap);
}
template<typename _t_key> bool get_last(_t_key & p_out) const {
t_retrieve_key<_t_key> wrap(p_out);
return m_data.get_last(wrap);
}
map_t() {}
map_t( const t_self & other ) : m_data( other.m_data ) {}
map_t( t_self && other ) : m_data( std::move(other.m_data) ) {}
const t_self & operator=( const t_self & other ) {m_data = other.m_data; return *this;}
const t_self & operator=( t_self && other ) { m_data = std::move(other.m_data); return *this; }
void move_from(t_self & other) {
m_data.move_from( other.m_data );
}
private:
template<typename _t_key>
struct t_retrieve_key {
typedef t_retrieve_key<_t_key> t_self;
t_retrieve_key(_t_key & p_key) : m_key(p_key) {}
template<typename t_what> const t_self & operator=(const t_what & p_what) {m_key = p_what.m_key; return *this;}
_t_key & m_key;
};
template<typename _t_key>
struct t_search_query {
t_search_query(const _t_key & p_key) : m_key(p_key) {}
_t_key const & m_key;
};
template<typename _t_key,typename _t_value>
struct t_search_set {
t_search_set(const _t_key & p_key, const _t_value & p_value) : m_key(p_key), m_value(p_value) {}
_t_key const & m_key;
_t_value const & m_value;
};
struct t_storage {
const t_storage_key m_key;
t_storage_value m_value;
template<typename _t_key>
t_storage(t_search_query<_t_key> const & p_source) : m_key(p_source.m_key), m_value() {}
template<typename _t_key,typename _t_value>
t_storage(t_search_set<_t_key,_t_value> const & p_source) : m_key(p_source.m_key), m_value(p_source.m_value) {}
static bool equals(const t_storage & v1, const t_storage & v2) {return v1.m_key == v2.m_key && v1.m_value == v2.m_value;}
bool operator==(const t_storage & other) const {return equals(*this,other);}
bool operator!=(const t_storage & other) const {return !equals(*this,other);}
};
class comparator_wrapper {
public:
template<typename t1,typename t2>
inline static int compare(const t1 & p_item1,const t2 & p_item2) {
return t_comparator::compare(p_item1.m_key,p_item2.m_key);
}
};
template<typename t_callback>
class enumeration_wrapper {
public:
enumeration_wrapper(t_callback & p_callback) : m_callback(p_callback) {}
void operator()(const t_storage & p_item) {m_callback(p_item.m_key,p_item.m_value);}
private:
t_callback & m_callback;
};
template<typename t_callback>
class enumeration_wrapper_var {
public:
enumeration_wrapper_var(t_callback & p_callback) : m_callback(p_callback) {}
void operator()(t_storage & p_item) {m_callback(implicit_cast<t_storage_key const&>(p_item.m_key),p_item.m_value);}
private:
t_callback & m_callback;
};
typedef avltree_t<t_storage,comparator_wrapper> t_content;
t_content m_data;
public:
typedef traits_t<t_content> traits;
typedef typename t_content::const_iterator const_iterator;
typedef typename t_content::iterator iterator;
iterator first() throw() {return m_data._first_var();}
iterator last() throw() {return m_data._last_var();}
const_iterator first() const throw() {return m_data.first();}
const_iterator last() const throw() {return m_data.last();}
const_iterator cfirst() const throw() {return m_data.first();}
const_iterator clast() const throw() {return m_data.last();}
template<typename _t_key> iterator find(const _t_key & key) {return m_data.find(t_search_query<_t_key>(key));}
template<typename _t_key> const_iterator find(const _t_key & key) const {return m_data.find(t_search_query<_t_key>(key));}
static bool equals(const t_self & v1, const t_self & v2) {
return t_content::equals(v1.m_data,v2.m_data);
}
bool operator==(const t_self & other) const {return equals(*this,other);}
bool operator!=(const t_self & other) const {return !equals(*this,other);}
bool remove(iterator const& iter) {
PFC_ASSERT(iter.is_valid());
return m_data.remove(iter);
//should never return false unless there's a bug in calling code
}
bool remove(const_iterator const& iter) {
PFC_ASSERT(iter.is_valid());
return m_data.remove(iter);
//should never return false unless there's a bug in calling code
}
};
}

137
pfc/memalign.h Normal file
View File

@@ -0,0 +1,137 @@
#pragma once
#ifndef _MSC_VER
#include <stdlib.h>
#endif
namespace pfc {
template<unsigned alignBytes = 16>
class mem_block_aligned {
public:
typedef mem_block_aligned<alignBytes> self_t;
mem_block_aligned() : m_ptr(), m_size() {}
void * ptr() {return m_ptr;}
const void * ptr() const {return m_ptr;}
void * get_ptr() {return m_ptr;}
const void * get_ptr() const {return m_ptr;}
size_t size() const {return m_size;}
size_t get_size() const {return m_size;}
void resize(size_t s) {
if (s == m_size) {
// nothing to do
} else if (s == 0) {
_free(m_ptr);
m_ptr = NULL;
} else {
void * ptr;
#ifdef _MSC_VER
if (m_ptr == NULL) ptr = _aligned_malloc(s, alignBytes);
else ptr = _aligned_realloc(m_ptr, s, alignBytes);
if ( ptr == NULL ) throw std::bad_alloc();
#else
#ifdef __ANDROID__
if ((ptr = memalign( alignBytes, s )) == NULL) throw std::bad_alloc();
#else
if (posix_memalign( &ptr, alignBytes, s ) < 0) throw std::bad_alloc();
#endif
if (m_ptr != NULL) {
memcpy( ptr, m_ptr, min_t<size_t>( m_size, s ) );
_free( m_ptr );
}
#endif
m_ptr = ptr;
}
m_size = s;
}
void set_size(size_t s) {resize(s);}
~mem_block_aligned() {
_free(m_ptr);
}
self_t const & operator=(self_t const & other) {
assign(other);
return *this;
}
mem_block_aligned(self_t const & other) : m_ptr(), m_size() {
assign(other);
}
void assign(self_t const & other) {
resize(other.size());
memcpy(ptr(), other.ptr(), size());
}
mem_block_aligned(self_t && other) {
m_ptr = other.m_ptr;
m_size = other.m_size;
other.m_ptr = NULL; other.m_size = 0;
}
self_t const & operator=(self_t && other) {
_free(m_ptr);
m_ptr = other.m_ptr;
m_size = other.m_size;
other.m_ptr = NULL; other.m_size = 0;
return *this;
}
private:
static void _free(void * ptr) {
#ifdef _MSC_VER
_aligned_free(ptr);
#else
free(ptr);
#endif
}
void * m_ptr;
size_t m_size;
};
template<typename obj_t, unsigned alignBytes = 16>
class mem_block_aligned_t {
public:
typedef mem_block_aligned_t<obj_t, alignBytes> self_t;
void resize(size_t s) { m.resize( multiply_guarded(s, sizeof(obj_t) ) ); }
void set_size(size_t s) {resize(s);}
size_t size() const { return m.size() / sizeof(obj_t); }
size_t get_size() const {return size();}
obj_t * ptr() { return reinterpret_cast<obj_t*>(m.ptr()); }
const obj_t * ptr() const { return reinterpret_cast<const obj_t*>(m.ptr()); }
obj_t * get_ptr() { return reinterpret_cast<obj_t*>(m.ptr()); }
const obj_t * get_ptr() const { return reinterpret_cast<const obj_t*>(m.ptr()); }
mem_block_aligned_t() {}
private:
mem_block_aligned<alignBytes> m;
};
template<typename obj_t, unsigned alignBytes = 16>
class mem_block_aligned_incremental_t {
public:
typedef mem_block_aligned_t<obj_t, alignBytes> self_t;
void resize(size_t s) {
if (s > m.size()) {
m.resize( multiply_guarded<size_t>(s, 3) / 2 );
}
m_size = s;
}
void set_size(size_t s) {resize(s);}
size_t size() const { return m_size; }
size_t get_size() const {return m_size; }
obj_t * ptr() { return m.ptr(); }
const obj_t * ptr() const { return m.ptr(); }
obj_t * get_ptr() { return m.ptr(); }
const obj_t * get_ptr() const { return m.ptr(); }
mem_block_aligned_incremental_t() : m_size() {}
mem_block_aligned_incremental_t(self_t const & other) : m(other.m), m_size(other.m_size) {}
mem_block_aligned_incremental_t(self_t && other) : m(std::move(other.m)), m_size(other.m_size) { other.m_size = 0; }
self_t const & operator=(self_t const & other) {m = other.m; m_size = other.m_size; return *this;}
self_t const & operator=(self_t && other) {m = std::move(other.m); m_size = other.m_size; other.m_size = 0; return *this;}
private:
mem_block_aligned_t<obj_t, alignBytes> m;
size_t m_size;
};
}

274
pfc/nix-objects.cpp Normal file
View File

@@ -0,0 +1,274 @@
#include "pfc.h"
#ifndef _WIN32
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <poll.h>
#ifdef __APPLE__
#include <mach-o/dyld.h>
#endif
namespace pfc {
void nixFormatError( string_base & str, int code ) {
char buffer[512] = {};
strerror_r(code, buffer, sizeof(buffer));
str = buffer;
}
void setNonBlocking( int fd, bool bNonBlocking ) {
int flags = fcntl(fd, F_GETFL, 0);
int flags2 = flags;
if (bNonBlocking) flags2 |= O_NONBLOCK;
else flags2 &= ~O_NONBLOCK;
if (flags2 != flags) fcntl(fd, F_SETFL, flags2);
}
void setCloseOnExec( int fd, bool bCloseOnExec ) {
int flags = fcntl(fd, F_GETFD);
int flags2 = flags;
if (bCloseOnExec) flags2 |= FD_CLOEXEC;
else flags2 &= ~FD_CLOEXEC;
if (flags != flags2) fcntl(fd, F_SETFD, flags2);
}
void setInheritable( int fd, bool bInheritable ) {
setCloseOnExec( fd, !bInheritable );
}
void createPipe( int fd[2], bool bInheritable ) {
#if defined(__linux__) && defined(O_CLOEXEC)
if (pipe2(fd, bInheritable ? 0 : O_CLOEXEC) < 0) throw exception_nix();
#else
if (pipe(fd) < 0) throw exception_nix();
if (!bInheritable) {
setInheritable( fd[0], false );
setInheritable( fd[1], false );
}
#endif
}
exception_nix::exception_nix() {
_init(errno);
}
exception_nix::exception_nix(int code) {
_init(code);
}
void exception_nix::_init(int code) {
m_code = code;
nixFormatError(m_msg, code);
}
timeval makeTimeVal( double timeSeconds ) {
timeval tv = {};
uint64_t temp = (uint64_t) floor( timeSeconds * 1000000.0 + 0.5);
tv.tv_usec = (uint32_t) (temp % 1000000);
tv.tv_sec = (uint32_t) (temp / 1000000);
return tv;
}
double importTimeval(const timeval & in) {
return (double)in.tv_sec + (double)in.tv_usec / 1000000.0;
}
void fdSet::operator+=( int fd ) {
m_fds.insert( fd );
}
void fdSet::operator-=( int fd ) {
m_fds.erase(fd);
}
bool fdSet::operator[] (int fd ) {
return m_fds.find( fd ) != m_fds.end();
}
void fdSet::clear() {
m_fds.clear();
}
void fdSet::operator+=( fdSet const & other ) {
for(auto i = other.m_fds.begin(); i != other.m_fds.end(); ++ i ) {
(*this) += *i;
}
}
int fdSelect::Select() {
return Select_( -1 );
}
int fdSelect::Select( double timeOutSeconds ) {
int ms;
if (timeOutSeconds < 0) {
ms = -1;
} else if (timeOutSeconds == 0) {
ms = 0;
} else {
ms = pfc::rint32( timeOutSeconds * 1000 );
if (ms < 1) ms = 1;
}
return Select_( ms );
}
int fdSelect::Select_( int timeOutMS ) {
fdSet total = Reads;
total += Writes;
total += Errors;
const size_t count = total.m_fds.size();
pfc::array_t< pollfd > v;
v.set_size_discard( count );
size_t walk = 0;
for( auto i = total.m_fds.begin(); i != total.m_fds.end(); ++ i ) {
const int fd = *i;
auto & f = v[walk++];
f.fd = fd;
f.events = (Reads[fd] ? POLLIN : 0) | (Writes[fd] ? POLLOUT : 0);
// POLLERR ignored in events, only used in revents
f.revents = 0;
}
int status = poll(v.get_ptr(), (int)count, timeOutMS);
if (status < 0) throw exception_nix();
Reads.clear(); Writes.clear(); Errors.clear();
if (status > 0) {
for(walk = 0; walk < count; ++walk) {
auto & f = v[walk];
if (f.revents & POLLIN) Reads += f.fd;
if (f.revents & POLLOUT) Writes += f.fd;
if (f.revents & POLLERR) Errors += f.fd;
}
}
return status;
}
bool fdCanRead( int fd ) {
return fdWaitRead( fd, 0 );
}
bool fdCanWrite( int fd ) {
return fdWaitWrite( fd, 0 );
}
bool fdWaitRead( int fd, double timeOutSeconds ) {
fdSelect sel; sel.Reads += fd;
return sel.Select( timeOutSeconds ) > 0;
}
bool fdWaitWrite( int fd, double timeOutSeconds ) {
fdSelect sel; sel.Writes += fd;
return sel.Select( timeOutSeconds ) > 0;
}
nix_event::nix_event() {
createPipe( m_fd );
setNonBlocking( m_fd[0] );
setNonBlocking( m_fd[1] );
}
nix_event::~nix_event() {
close( m_fd[0] );
close( m_fd[1] );
}
void nix_event::set_state( bool state ) {
if (state) {
// Ensure that there is a byte in the pipe
if (!fdCanRead(m_fd[0] ) ) {
uint8_t dummy = 0;
write( m_fd[1], &dummy, 1);
}
} else {
// Keep reading until clear
for(;;) {
uint8_t dummy;
if (read(m_fd[0], &dummy, 1 ) != 1) break;
}
}
}
bool nix_event::wait_for( double p_timeout_seconds ) {
return fdWaitRead( m_fd[0], p_timeout_seconds );
}
bool nix_event::g_wait_for( int p_event, double p_timeout_seconds ) {
return fdWaitRead( p_event, p_timeout_seconds );
}
int nix_event::g_twoEventWait( int h1, int h2, double timeout ) {
fdSelect sel;
sel.Reads += h1;
sel.Reads += h2;
int state = sel.Select( timeout );
if (state < 0) throw exception_nix();
if (state == 0) return 0;
if (sel.Reads[ h1 ] ) return 1;
if (sel.Reads[ h2 ] ) return 2;
crash(); // should not get here
return 0;
}
int nix_event::g_twoEventWait( nix_event & ev1, nix_event & ev2, double timeout ) {
return g_twoEventWait( ev1.get_handle(), ev2.get_handle(), timeout );
}
void nixSleep(double seconds) {
fdSelect sel; sel.Select( seconds );
}
void sleepSeconds(double seconds) {
return nixSleep(seconds);
}
void yield() {
return nixSleep(0.001);
}
double nixGetTime() {
timeval tv = {};
gettimeofday(&tv, NULL);
return importTimeval(tv);
}
bool nixReadSymLink( string_base & strOut, const char * path ) {
size_t l = 1024;
for(;;) {
array_t<char> buffer; buffer.set_size( l + 1 );
ssize_t rv = (size_t) readlink(path, buffer.get_ptr(), l);
if (rv < 0) return false;
if ((size_t)rv <= l) {
buffer.get_ptr()[rv] = 0;
strOut = buffer.get_ptr();
return true;
}
l *= 2;
}
}
bool nixSelfProcessPath( string_base & strOut ) {
#ifdef __APPLE__
uint32_t len = 0;
_NSGetExecutablePath(NULL, &len);
array_t<char> temp; temp.set_size( len + 1 ); temp.fill_null();
_NSGetExecutablePath(temp.get_ptr(), &len);
strOut = temp.get_ptr();
return true;
#else
return nixReadSymLink( strOut, PFC_string_formatter() << "/proc/" << (unsigned) getpid() << "/exe");
#endif
}
void nixGetRandomData( void * outPtr, size_t outBytes ) {
try {
fileHandle randomData;
randomData = open("/dev/urandom", O_RDONLY);
if (randomData.h < 0) throw exception_nix();
if (read(randomData.h, outPtr, outBytes) != outBytes) throw exception_nix();
}
catch (std::exception const & e) {
throw std::runtime_error("getRandomData failure");
}
}
#ifndef __APPLE__ // for Apple they are implemented in Obj-C
bool isShiftKeyPressed() {return false;}
bool isCtrlKeyPressed() {return false;}
bool isAltKeyPressed() {return false;}
#endif
}
void uSleepSeconds( double seconds, bool ) {
pfc::nixSleep( seconds );
}
#endif // _WIN32

110
pfc/nix-objects.h Normal file
View File

@@ -0,0 +1,110 @@
#pragma once
#include <sys/select.h>
#include <sys/time.h>
#include <set>
namespace pfc {
void nixFormatError( string_base & str, int code );
class exception_nix : public std::exception {
public:
exception_nix();
exception_nix(int code);
~exception_nix() throw() { }
int code() const throw() {return m_code;}
const char * what() const throw() {return m_msg.get_ptr();}
private:
void _init(int code);
int m_code;
string8 m_msg;
};
// Toggles non-blocking mode on a file descriptor.
void setNonBlocking( int fd, bool bNonBlocking = true );
// Toggles close-on-exec mode on a file descriptor.
void setCloseOnExec( int fd, bool bCloseOnExec = true );
// Toggles inheritable mode on a file descriptor. Reverse of close-on-exec.
void setInheritable( int fd, bool bInheritable = true );
// Creates a pipe. The pipe is NOT inheritable by default (close-on-exec set).
void createPipe( int fd[2], bool bInheritable = false );
timeval makeTimeVal( double seconds );
double importTimeval(const timeval & tv);
class fdSet {
public:
void operator+=( int fd );
void operator-=( int fd );
bool operator[] (int fd );
void clear();
void operator+=( fdSet const & other );
std::set<int> m_fds;
};
bool fdCanRead( int fd );
bool fdCanWrite( int fd );
bool fdWaitRead( int fd, double timeOutSeconds );
bool fdWaitWrite( int fd, double timeOutSeconds );
class fdSelect {
public:
int Select();
int Select( double timeOutSeconds );
int Select_( int timeOutMS );
fdSet Reads, Writes, Errors;
};
void nixSleep(double seconds);
class nix_event {
public:
nix_event();
~nix_event();
void set_state( bool state );
bool is_set( ) {return wait_for(0); }
bool wait_for( double p_timeout_seconds );
static bool g_wait_for( int p_event, double p_timeout_seconds );
int get_handle() const {return m_fd[0]; }
// Two-wait event functions, return 0 on timeout, 1 on evt1 set, 2 on evt2 set
static int g_twoEventWait( nix_event & ev1, nix_event & ev2, double timeout );
static int g_twoEventWait( int h1, int h2, double timeOut );
private:
nix_event(nix_event const&);
void operator=(nix_event const&);
int m_fd[2];
};
double nixGetTime();
bool nixReadSymLink( string_base & strOut, const char * path );
bool nixSelfProcessPath( string_base & strOut );
void nixGetRandomData( void * outPtr, size_t outBytes );
bool isShiftKeyPressed();
bool isCtrlKeyPressed();
bool isAltKeyPressed();
}
void uSleepSeconds( double seconds, bool );

85
pfc/notifyList.h Normal file
View File

@@ -0,0 +1,85 @@
#pragma once
#include <functional>
#include <map>
#include <memory>
namespace pfc {
class notifyList {
public:
typedef size_t token_t;
typedef std::function<void () > notify_t;
token_t add( notify_t f ) {
auto token = ++ m_increment;
m_notify[token] = f;
return token;
}
void remove( token_t t ) {
m_notify.erase(t);
}
void dispatch() {
// Safeguard against someone altering our state in mid-dispatch
auto temp = m_notify;
for( auto walk = temp.begin(); walk != temp.end(); ++ walk ) {
if ( m_notify.count( walk->first ) > 0 ) { // still there?
walk->second();
}
}
}
static std::shared_ptr<notifyList> make() {
return std::make_shared<notifyList>();
}
private:
token_t m_increment = 0;
std::map<token_t, notify_t> m_notify;
};
typedef std::shared_ptr< notifyList > notifyListRef_t;
class notifyEntry {
public:
notifyEntry() {}
notifyEntry & operator<<( notifyList & l ) {
PFC_ASSERT( m_list == nullptr );
m_list = &l;
return *this;
}
notifyEntry & operator<<( notifyListRef_t l ) {
PFC_ASSERT( m_list == nullptr );
m_listShared = l;
m_list = &*l;
return *this;
}
notifyEntry & operator<<( notifyList::notify_t f ) {
PFC_ASSERT( m_list != nullptr );
PFC_ASSERT( m_token == 0 );
m_token = m_list->add( f );
return *this;
}
void clear() {
if ( m_list != nullptr && m_token != 0 ) {
m_list->remove(m_token);
m_token = 0;
}
}
~notifyEntry() {
clear();
}
private:
notifyListRef_t m_listShared;
notifyList * m_list = nullptr;
notifyList::token_t m_token = 0;
notifyEntry( const notifyEntry & ) = delete;
void operator=( const notifyEntry & ) = delete;
};
}

61
pfc/obj-c.mm Normal file
View File

@@ -0,0 +1,61 @@
//
// PFC-ObjC.m
// pfc-test
//
// Created by PEPE on 28/07/14.
// Copyright (c) 2014 PEPE. All rights reserved.
//
#ifdef __APPLE__
#import <Foundation/Foundation.h>
#include <TargetConditionals.h>
#if TARGET_OS_MAC && !TARGET_OS_IPHONE
#import <Cocoa/Cocoa.h>
#endif
#include "pfc.h"
namespace pfc {
void * thread::g_entry(void * arg) {
@autoreleasepool {
reinterpret_cast<thread*>(arg)->entry();
}
return NULL;
}
void thread::appleStartThreadPrologue() {
if (![NSThread isMultiThreaded]) [[[NSThread alloc] init] start];
}
bool isShiftKeyPressed() {
#if TARGET_OS_MAC && !TARGET_OS_IPHONE
return ( [NSEvent modifierFlags] & NSShiftKeyMask ) != 0;
#else
return false;
#endif
}
bool isCtrlKeyPressed() {
#if TARGET_OS_MAC && !TARGET_OS_IPHONE
return ( [NSEvent modifierFlags] & NSControlKeyMask ) != 0;
#else
return false;
#endif
}
bool isAltKeyPressed() {
#if TARGET_OS_MAC && !TARGET_OS_IPHONE
return ( [NSEvent modifierFlags] & NSAlternateKeyMask ) != 0;
#else
return false;
#endif
}
void inAutoReleasePool(std::function<void()> f) {
@autoreleasepool {
f();
}
}
}
#endif

73
pfc/order_helper.h Normal file
View File

@@ -0,0 +1,73 @@
#pragma once
namespace pfc {
PFC_DECLARE_EXCEPTION( exception_invalid_permutation, exception_invalid_params, "Invalid permutation" );
t_size permutation_find_reverse(t_size const * order, t_size count, t_size value);
//! For critical sanity checks. Speed: O(n), allocates memory.
bool permutation_is_valid(t_size const * order, t_size count);
//! For critical sanity checks. Speed: O(n), allocates memory.
void permutation_validate(t_size const * order, t_size count);
//! Creates a permutation that moves selected items in a list box by the specified delta-offset.
void create_move_items_permutation(t_size * p_output,t_size p_count,const class bit_array & p_selection,int p_delta);
void create_move_item_permutation( size_t * p_output, size_t p_count, size_t from, size_t to );
bool create_drop_permutation(size_t * out, size_t itemCount, pfc::bit_array const & maskSelected, size_t insertMark );
}
class order_helper
{
pfc::array_t<t_size> m_data;
public:
order_helper(t_size p_size) {
m_data.set_size(p_size);
for(t_size n=0;n<p_size;n++) m_data[n]=n;
}
order_helper(const order_helper & p_order) {*this = p_order;}
static bool g_is_identity(const t_size * order, t_size count) {
for(t_size walk = 0; walk < count; ++walk) {
if (order[walk] != walk) return false;
}
return true;
}
template<typename t_array> static bool g_is_identity(const t_array & p_array) {
const t_size count = pfc::array_size_t(p_array);
for(t_size walk = 0; walk < count; ++walk) if (p_array[walk] != walk) return false;
return true;
}
template<typename t_int>
static void g_fill(t_int * p_order,const t_size p_count) {
t_size n; for(n=0;n<p_count;n++) p_order[n] = (t_int)n;
}
template<typename t_array>
static void g_fill(t_array & p_array) {
t_size n; const t_size max = pfc::array_size_t(p_array);
for(n=0;n<max;n++) p_array[n] = n;
}
t_size get_item(t_size ptr) const {return m_data[ptr];}
t_size & operator[](t_size ptr) {return m_data[ptr];}
t_size operator[](t_size ptr) const {return m_data[ptr];}
static void g_swap(t_size * p_data,t_size ptr1,t_size ptr2);
inline void swap(t_size ptr1,t_size ptr2) {pfc::swap_t(m_data[ptr1],m_data[ptr2]);}
const t_size * get_ptr() const {return m_data.get_ptr();}
//! Insecure - may deadlock or crash on invalid permutation content. In theory faster than walking the permutation, but still O(n).
static t_size g_find_reverse(const t_size * order,t_size val);
//! Insecure - may deadlock or crash on invalid permutation content. In theory faster than walking the permutation, but still O(n).
inline t_size find_reverse(t_size val) {return g_find_reverse(m_data.get_ptr(),val);}
static void g_reverse(t_size * order,t_size base,t_size count);
inline void reverse(t_size base,t_size count) {g_reverse(m_data.get_ptr(),base,count);}
t_size get_count() const {return m_data.get_size();}
};

339
pfc/other.cpp Normal file
View File

@@ -0,0 +1,339 @@
#include "pfc.h"
#ifdef _MSC_VER
#include <intrin.h>
#include <assert.h>
#endif
#ifndef _MSC_VER
#include <signal.h>
#endif
#if defined(__ANDROID__)
#include <android/log.h>
#endif
#include <math.h>
#include "pfc-fb2k-hooks.h"
namespace pfc {
bool permutation_is_valid(t_size const * order, t_size count) {
bit_array_bittable found(count);
for(t_size walk = 0; walk < count; ++walk) {
if (order[walk] >= count) return false;
if (found[walk]) return false;
found.set(walk,true);
}
return true;
}
void permutation_validate(t_size const * order, t_size count) {
if (!permutation_is_valid(order,count)) throw exception_invalid_permutation();
}
t_size permutation_find_reverse(t_size const * order, t_size count, t_size value) {
if (value >= count) return ~0;
for(t_size walk = 0; walk < count; ++walk) {
if (order[walk] == value) return walk;
}
return ~0;
}
void create_move_item_permutation( size_t * order, size_t count, size_t from, size_t to ) {
PFC_ASSERT( from < count );
PFC_ASSERT( to < count );
for ( size_t w = 0; w < count; ++w ) {
size_t i = w;
if ( w == to ) i = from;
else if ( w < to && w >= from ) {
++i;
} else if ( w > to && w <= from ) {
--i;
}
order[w] = i;
}
}
void create_move_items_permutation(t_size * p_output,t_size p_count,const bit_array & p_selection,int p_delta) {
t_size * const order = p_output;
const t_size count = p_count;
pfc::array_t<bool> selection; selection.set_size(p_count);
for(t_size walk = 0; walk < count; ++walk) {
order[walk] = walk;
selection[walk] = p_selection[walk];
}
if (p_delta<0)
{
for(;p_delta<0;p_delta++)
{
t_size idx;
for(idx=1;idx<count;idx++)
{
if (selection[idx] && !selection[idx-1])
{
pfc::swap_t(order[idx],order[idx-1]);
pfc::swap_t(selection[idx],selection[idx-1]);
}
}
}
}
else
{
for(;p_delta>0;p_delta--)
{
t_size idx;
for(idx=count-2;(int)idx>=0;idx--)
{
if (selection[idx] && !selection[idx+1])
{
pfc::swap_t(order[idx],order[idx+1]);
pfc::swap_t(selection[idx],selection[idx+1]);
}
}
}
}
}
bool create_drop_permutation(size_t * out, size_t itemCount, pfc::bit_array const & maskSelected, size_t insertMark ) {
const t_size count = itemCount;
if (insertMark > count) insertMark = count;
{
t_size selBefore = 0;
for(t_size walk = 0; walk < insertMark; ++walk) {
if (maskSelected[walk]) selBefore++;
}
insertMark -= selBefore;
}
{
pfc::array_t<t_size> permutation, selected, nonselected;
const t_size selcount = maskSelected.calc_count( true, 0, count );
selected.set_size(selcount); nonselected.set_size(count - selcount);
permutation.set_size(count);
if (insertMark > nonselected.get_size()) insertMark = nonselected.get_size();
for(t_size walk = 0, swalk = 0, nwalk = 0; walk < count; ++walk) {
if (maskSelected[walk]) {
selected[swalk++] = walk;
} else {
nonselected[nwalk++] = walk;
}
}
for(t_size walk = 0; walk < insertMark; ++walk) {
permutation[walk] = nonselected[walk];
}
for(t_size walk = 0; walk < selected.get_size(); ++walk) {
permutation[insertMark + walk] = selected[walk];
}
for(t_size walk = insertMark; walk < nonselected.get_size(); ++walk) {
permutation[selected.get_size() + walk] = nonselected[walk];
}
for(t_size walk = 0; walk < permutation.get_size(); ++walk) {
if (permutation[walk] != walk) {
memcpy(out, permutation.get_ptr(), count * sizeof(size_t));
return true;
}
}
}
return false;
}
}
void order_helper::g_swap(t_size * data,t_size ptr1,t_size ptr2)
{
t_size temp = data[ptr1];
data[ptr1] = data[ptr2];
data[ptr2] = temp;
}
t_size order_helper::g_find_reverse(const t_size * order,t_size val)
{
t_size prev = val, next = order[val];
while(next != val)
{
prev = next;
next = order[next];
}
return prev;
}
void order_helper::g_reverse(t_size * order,t_size base,t_size count)
{
t_size max = count>>1;
t_size n;
t_size base2 = base+count-1;
for(n=0;n<max;n++)
g_swap(order,base+n,base2-n);
}
namespace pfc {
void crashImpl() {
#if defined(_MSC_VER)
__debugbreak();
#else
#if defined(__ANDROID__) && PFC_DEBUG
nixSleep(1);
#endif
raise(SIGINT);
#endif
}
void crash() {
crashHook();
}
} // namespace pfc
void pfc::byteswap_raw(void * p_buffer,const t_size p_bytes) {
t_uint8 * ptr = (t_uint8*)p_buffer;
t_size n;
for(n=0;n<p_bytes>>1;n++) swap_t(ptr[n],ptr[p_bytes-n-1]);
}
void pfc::outputDebugLine(const char * msg) {
#ifdef _WIN32
OutputDebugString(pfc::stringcvt::string_os_from_utf8(PFC_string_formatter() << msg << "\n") );
#elif defined(__ANDROID__)
__android_log_write(ANDROID_LOG_INFO, "Debug", msg);
#else
printf("%s\n", msg);
#endif
}
#if PFC_DEBUG
#ifdef _WIN32
void pfc::myassert_win32(const wchar_t * _Message, const wchar_t *_File, unsigned _Line) {
if (IsDebuggerPresent()) pfc::crash();
PFC_DEBUGLOG << "PFC_ASSERT failure: " << _Message;
PFC_DEBUGLOG << "PFC_ASSERT location: " << _File << " : " << _Line;
_wassert(_Message,_File,_Line);
}
#else
void pfc::myassert(const char * _Message, const char *_File, unsigned _Line)
{
PFC_DEBUGLOG << "Assert failure: \"" << _Message << "\" in: " << _File << " line " << _Line;
crash();
}
#endif
#endif
t_uint64 pfc::pow_int(t_uint64 base, t_uint64 exp) {
t_uint64 mul = base;
t_uint64 val = 1;
t_uint64 mask = 1;
while(exp != 0) {
if (exp & mask) {
val *= mul;
exp ^= mask;
}
mul = mul * mul;
mask <<= 1;
}
return val;
}
double pfc::exp_int( const double base, const int expS ) {
// return pow(base, (double)v);
bool neg;
unsigned exp;
if (expS < 0) {
neg = true;
exp = (unsigned) -expS;
} else {
neg = false;
exp = (unsigned) expS;
}
double v = 1.0;
if (true) {
if (exp) {
double mul = base;
for(;;) {
if (exp & 1) v *= mul;
exp >>= 1;
if (exp == 0) break;
mul *= mul;
}
}
} else {
for(unsigned i = 0; i < exp; ++i) {
v *= base;
}
}
if (neg) v = 1.0 / v;
return v;
}
t_int32 pfc::rint32(double p_val) { return (t_int32)floor(p_val + 0.5); }
t_int64 pfc::rint64(double p_val) { return (t_int64)floor(p_val + 0.5); }
namespace pfc {
// bigmem impl
void bigmem::resize(size_t newSize) {
clear();
m_data.set_size((newSize + slice - 1) / slice);
m_data.fill_null();
for (size_t walk = 0; walk < m_data.get_size(); ++walk) {
size_t thisSlice = slice;
if (walk + 1 == m_data.get_size()) {
size_t cut = newSize % slice;
if (cut) thisSlice = cut;
}
void* ptr = malloc(thisSlice);
if (ptr == NULL) { clear(); throw std::bad_alloc(); }
m_data[walk] = (uint8_t*)ptr;
}
m_size = newSize;
}
void bigmem::clear() {
for (size_t walk = 0; walk < m_data.get_size(); ++walk) free(m_data[walk]);
m_data.set_size(0);
m_size = 0;
}
void bigmem::read(void * ptrOut, size_t bytes, size_t offset) {
PFC_ASSERT(offset + bytes <= size());
uint8_t * outWalk = (uint8_t*)ptrOut;
while (bytes > 0) {
size_t o1 = offset / slice, o2 = offset % slice;
size_t delta = slice - o2; if (delta > bytes) delta = bytes;
memcpy(outWalk, m_data[o1] + o2, delta);
offset += delta;
bytes -= delta;
outWalk += delta;
}
}
void bigmem::write(const void * ptrIn, size_t bytes, size_t offset) {
PFC_ASSERT(offset + bytes <= size());
const uint8_t * inWalk = (const uint8_t*)ptrIn;
while (bytes > 0) {
size_t o1 = offset / slice, o2 = offset % slice;
size_t delta = slice - o2; if (delta > bytes) delta = bytes;
memcpy(m_data[o1] + o2, inWalk, delta);
offset += delta;
bytes -= delta;
inWalk += delta;
}
}
uint8_t * bigmem::_slicePtr(size_t which) { return m_data[which]; }
size_t bigmem::_sliceCount() { return m_data.get_size(); }
size_t bigmem::_sliceSize(size_t which) {
if (which + 1 == _sliceCount()) {
size_t s = m_size % slice;
if (s) return s;
}
return slice;
}
}

289
pfc/other.h Normal file
View File

@@ -0,0 +1,289 @@
#pragma once
namespace pfc {
template<class T>
class vartoggle_t {
T oldval; T & var;
public:
vartoggle_t(T & p_var,const T & val) : var(p_var) {
oldval = var;
var = val;
}
~vartoggle_t() {var = oldval;}
};
template<class T>
class vartoggle_volatile_t {
T oldval; volatile T & var;
public:
vartoggle_volatile_t(volatile T & p_var,const T & val) : var(p_var) {
oldval = var;
var = val;
}
~vartoggle_volatile_t() {var = oldval;}
};
typedef vartoggle_t<bool> booltoggle;
};
#ifdef _MSC_VER
class fpu_control
{
unsigned old_val;
unsigned mask;
public:
inline fpu_control(unsigned p_mask,unsigned p_val)
{
mask = p_mask;
_controlfp_s(&old_val,p_val,mask);
}
inline ~fpu_control()
{
unsigned dummy;
_controlfp_s(&dummy,old_val,mask);
}
};
class fpu_control_roundnearest : private fpu_control
{
public:
fpu_control_roundnearest() : fpu_control(_MCW_RC,_RC_NEAR) {}
};
class fpu_control_flushdenormal : private fpu_control
{
public:
fpu_control_flushdenormal() : fpu_control(_MCW_DN,_DN_FLUSH) {}
};
class fpu_control_default : private fpu_control
{
public:
fpu_control_default() : fpu_control(_MCW_DN|_MCW_RC,_DN_FLUSH|_RC_NEAR) {}
};
#ifdef _M_IX86
class sse_control {
public:
sse_control(unsigned p_mask,unsigned p_val) : m_mask(p_mask) {
__control87_2(p_val,p_mask,NULL,&m_oldval);
}
~sse_control() {
__control87_2(m_oldval,m_mask,NULL,&m_oldval);
}
private:
unsigned m_mask,m_oldval;
};
class sse_control_flushdenormal : private sse_control {
public:
sse_control_flushdenormal() : sse_control(_MCW_DN,_DN_FLUSH) {}
};
#endif
#endif
namespace pfc {
class releaser_delete {
public:
template<typename T> static void release(T* p_ptr) {delete p_ptr;}
};
class releaser_delete_array {
public:
template<typename T> static void release(T* p_ptr) {delete[] p_ptr;}
};
class releaser_free {
public:
static void release(void * p_ptr) {free(p_ptr);}
};
//! Assumes t_freefunc to never throw exceptions.
template<typename T,typename t_releaser = releaser_delete >
class ptrholder_t {
private:
typedef ptrholder_t<T,t_releaser> t_self;
public:
inline ptrholder_t(T* p_ptr) : m_ptr(p_ptr) {}
inline ptrholder_t() : m_ptr(NULL) {}
inline ~ptrholder_t() {t_releaser::release(m_ptr);}
inline bool is_valid() const {return m_ptr != NULL;}
inline bool is_empty() const {return m_ptr == NULL;}
inline T* operator->() const {return m_ptr;}
inline T* get_ptr() const {return m_ptr;}
inline void release() {t_releaser::release(replace_null_t(m_ptr));;}
inline void attach(T * p_ptr) {release(); m_ptr = p_ptr;}
inline const t_self & operator=(T * p_ptr) {set(p_ptr);return *this;}
inline T* detach() {return pfc::replace_null_t(m_ptr);}
inline T& operator*() const {return *m_ptr;}
inline t_self & operator<<(t_self & p_source) {attach(p_source.detach());return *this;}
inline t_self & operator>>(t_self & p_dest) {p_dest.attach(detach());return *this;}
//deprecated
inline void set(T * p_ptr) {attach(p_ptr);}
ptrholder_t(t_self&& other) { m_ptr = other.detach(); }
const t_self& operator=(t_self&& other) { attach(other.detach()); return this; }
private:
ptrholder_t(const t_self &) {throw pfc::exception_not_implemented();}
const t_self & operator=(const t_self & ) {throw pfc::exception_not_implemented();}
T* m_ptr;
};
//avoid "void&" breakage
template<typename t_releaser>
class ptrholder_t<void,t_releaser> {
private:
typedef void T;
typedef ptrholder_t<T,t_releaser> t_self;
public:
inline ptrholder_t(T* p_ptr) : m_ptr(p_ptr) {}
inline ptrholder_t() : m_ptr(NULL) {}
inline ~ptrholder_t() {t_releaser::release(m_ptr);}
inline bool is_valid() const {return m_ptr != NULL;}
inline bool is_empty() const {return m_ptr == NULL;}
inline T* operator->() const {return m_ptr;}
inline T* get_ptr() const {return m_ptr;}
inline void release() {t_releaser::release(replace_null_t(m_ptr));;}
inline void attach(T * p_ptr) {release(); m_ptr = p_ptr;}
inline const t_self & operator=(T * p_ptr) {set(p_ptr);return *this;}
inline T* detach() {return pfc::replace_null_t(m_ptr);}
inline t_self & operator<<(t_self & p_source) {attach(p_source.detach());return *this;}
inline t_self & operator>>(t_self & p_dest) {p_dest.attach(detach());return *this;}
//deprecated
inline void set(T * p_ptr) {attach(p_ptr);}
private:
ptrholder_t(const t_self &) {throw pfc::exception_not_implemented();}
const t_self & operator=(const t_self & ) {throw pfc::exception_not_implemented();}
T* m_ptr;
};
PFC_NORETURN void crash();
void outputDebugLine(const char * msg);
class debugLog : public string_formatter {
public:
~debugLog() { outputDebugLine(this->get_ptr()); }
};
#define PFC_DEBUGLOG ::pfc::debugLog()._formatter()
template<typename t_type,t_type p_initval>
class int_container_helper {
public:
int_container_helper() : m_val(p_initval) {}
t_type m_val;
};
//warning: not multi-thread-safe
template<typename t_base>
class instanceTracker : public t_base {
private:
typedef instanceTracker<t_base> t_self;
public:
TEMPLATE_CONSTRUCTOR_FORWARD_FLOOD_WITH_INITIALIZER(instanceTracker,t_base,{g_list += this;});
instanceTracker(const t_self & p_other) : t_base( (const t_base &)p_other) {g_list += this;}
~instanceTracker() {g_list -= this;}
typedef pfc::avltree_t<t_self*> t_list;
static const t_list & instanceList() {return g_list;}
template<typename t_callback> static void forEach(t_callback & p_callback) {instanceList().enumerate(p_callback);}
private:
static t_list g_list;
};
template<typename t_base>
typename instanceTracker<t_base>::t_list instanceTracker<t_base>::g_list;
//warning: not multi-thread-safe
template<typename TClass>
class instanceTrackerV2 {
private:
typedef instanceTrackerV2<TClass> t_self;
public:
instanceTrackerV2(const t_self & p_other) {g_list += static_cast<TClass*>(this);}
instanceTrackerV2() {g_list += static_cast<TClass*>(this);}
~instanceTrackerV2() {g_list -= static_cast<TClass*>(this);}
typedef pfc::avltree_t<TClass*> t_instanceList;
static const t_instanceList & instanceList() {return g_list;}
template<typename t_callback> static void forEach(t_callback & p_callback) {instanceList().enumerate(p_callback);}
private:
static t_instanceList g_list;
};
template<typename TClass>
typename instanceTrackerV2<TClass>::t_instanceList instanceTrackerV2<TClass>::g_list;
struct objDestructNotifyData {
bool m_flag;
objDestructNotifyData * m_next;
};
class objDestructNotify {
public:
objDestructNotify() : m_data() {}
~objDestructNotify() {
set();
}
void set() {
objDestructNotifyData * w = m_data;
while(w) {
w->m_flag = true; w = w->m_next;
}
}
objDestructNotifyData * m_data;
};
class objDestructNotifyScope : private objDestructNotifyData {
public:
objDestructNotifyScope(objDestructNotify &obj) : m_obj(&obj) {
m_next = m_obj->m_data;
m_obj->m_data = this;
}
~objDestructNotifyScope() {
if (!m_flag) m_obj->m_data = m_next;
}
bool get() const {return m_flag;}
PFC_CLASS_NOT_COPYABLE_EX(objDestructNotifyScope)
private:
objDestructNotify * m_obj;
};
class bigmem {
public:
enum {slice = 1024*1024};
bigmem() : m_size() {}
~bigmem() {clear();}
void resize(size_t newSize);
size_t size() const {return m_size;}
void clear();
void read(void * ptrOut, size_t bytes, size_t offset);
void write(const void * ptrIn, size_t bytes, size_t offset);
uint8_t * _slicePtr(size_t which);
size_t _sliceCount();
size_t _sliceSize(size_t which);
private:
array_t<uint8_t*> m_data;
size_t m_size;
PFC_CLASS_NOT_COPYABLE_EX(bigmem)
};
double exp_int( double base, int exp );
}

297
pfc/pathUtils.cpp Normal file
View File

@@ -0,0 +1,297 @@
#include "pfc.h"
static_assert(L'Ö' == 0xD6, "Compile as Unicode!!!");
namespace pfc { namespace io { namespace path {
#ifdef _WINDOWS
#define KPathSeparators "\\/|"
#else
#define KPathSeparators "/"
#endif
string getFileName(string path) {
t_size split = path.lastIndexOfAnyChar(KPathSeparators);
if (split == ~0) return path;
else return path.subString(split+1);
}
string getFileNameWithoutExtension(string path) {
string fn = getFileName(path);
t_size split = fn.lastIndexOf('.');
if (split == ~0) return fn;
else return fn.subString(0,split);
}
string getFileExtension(string path) {
string fn = getFileName(path);
t_size split = fn.lastIndexOf('.');
if (split == ~0) return "";
else return fn.subString(split);
}
string getDirectory(string filePath) {return getParent(filePath);}
string getParent(string filePath) {
t_size split = filePath.lastIndexOfAnyChar(KPathSeparators);
if (split == ~0) return "";
#ifdef _WINDOWS
if (split > 0 && getIllegalNameChars().contains(filePath[split-1])) {
if (split + 1 < filePath.length()) return filePath.subString(0,split+1);
else return "";
}
#endif
return filePath.subString(0,split);
}
string combine(string basePath,string fileName) {
if (basePath.length() > 0) {
if (!isSeparator(basePath.lastChar())) {
basePath += getDefaultSeparator();
}
return basePath + fileName;
} else {
//todo?
return fileName;
}
}
bool isSeparator(char c) {
return strchr(KPathSeparators, c) != nullptr;
}
string getSeparators() {
return KPathSeparators;
}
const char * charReplaceDefault(char c) {
switch (c) {
case '*':
return "x";
case '\"':
return "\'\'";
case ':':
case '/':
case '\\':
return "-";
case '?':
return "";
default:
return "_";
}
}
const char * charReplaceModern(char c) {
switch (c) {
case '*':
return u8"";
case '\"':
return u8"''";
case ':':
return u8"";
case '/':
return u8"";
case '\\':
return u8"";
case '?':
return u8"";
case '<':
return u8"˂";
case '>':
return u8"˃";
case '|':
return u8"";
default:
return "_";
}
}
string replaceIllegalPathChars(string fn, charReplace_t replaceIllegalChar) {
string illegal = getIllegalNameChars();
string separators = getSeparators();
string_formatter output;
for(t_size walk = 0; walk < fn.length(); ++walk) {
const char c = fn[walk];
if (separators.contains(c)) {
output.add_byte(getDefaultSeparator());
} else if (string::isNonTextChar(c) || illegal.contains(c)) {
string replacement = replaceIllegalChar(c);
if (replacement.containsAnyChar(illegal)) /*per-OS weirdness security*/ replacement = "_";
output << replacement.ptr();
} else {
output.add_byte(c);
}
}
return output.toString();
}
string replaceIllegalNameChars(string fn, bool allowWC, charReplace_t replaceIllegalChar) {
const string illegal = getIllegalNameChars(allowWC);
string_formatter output;
for(t_size walk = 0; walk < fn.length(); ++walk) {
const char c = fn[walk];
if (string::isNonTextChar(c) || illegal.contains(c)) {
string replacement = replaceIllegalChar(c);
if (replacement.containsAnyChar(illegal)) /*per-OS weirdness security*/ replacement = "_";
output << replacement.ptr();
} else {
output.add_byte(c);
}
}
return output.toString();
}
bool isInsideDirectory(pfc::string directory, pfc::string inside) {
//not very efficient
string walk = inside;
for(;;) {
walk = getParent(walk);
if (walk == "") return false;
if (equals(directory,walk)) return true;
}
}
bool isDirectoryRoot(string path) {
return getParent(path).isEmpty();
}
//OS-dependant part starts here
char getDefaultSeparator() {
#ifdef _WINDOWS
return '\\';
#else
return '/';
#endif
}
#ifdef _WINDOWS
#define KIllegalNameCharsEx ":<>\""
#else
// Mac OS allows : in filenames but does funny things presenting them in Finder, so don't use it
#define KIllegalNameCharsEx ":"
#endif
#define KWildcardChars "*?"
#define KIllegalNameChars KPathSeparators KIllegalNameCharsEx KWildcardChars
#define KIllegalNameChars_noWC KPathSeparators KIllegalNameCharsEx
static string g_illegalNameChars ( KIllegalNameChars );
static string g_illegalNameChars_noWC ( KIllegalNameChars_noWC );
string getIllegalNameChars(bool allowWC) {
return allowWC ? g_illegalNameChars_noWC : g_illegalNameChars;
}
#ifdef _WINDOWS
static const char * const specialIllegalNames[] = {
"con", "aux", "lst", "prn", "nul", "eof", "inp", "out"
};
enum { maxPathComponent = 255 };
static size_t safeTruncat( const char * str, size_t maxLen ) {
size_t i = 0;
size_t ret = 0;
for( ; i < maxLen; ++ i ) {
auto d = pfc::utf8_char_len( str + ret );
if ( d == 0 ) break;
ret += d;
}
return ret;
}
static size_t utf8_length( const char * str ) {
size_t ret = 0;
for (; ++ret;) {
size_t d = pfc::utf8_char_len( str );
if ( d == 0 ) break;
str += d;
}
return ret;
}
static string truncatePathComponent( string name, bool preserveExt ) {
if (name.length() <= maxPathComponent) return name;
if (preserveExt) {
auto dot = name.lastIndexOf('.');
if (dot != pfc_infinite) {
const auto ext = name.subString(dot);
const auto extLen = utf8_length( ext.c_str() );
if (extLen < maxPathComponent) {
auto lim = maxPathComponent - extLen;
lim = safeTruncat( name.c_str(), lim );
if (lim < dot) {
return name.subString(0, lim) + ext;
}
}
}
}
size_t truncat = safeTruncat( name.c_str(), maxPathComponent );
return name.subString(0, truncat);
}
#endif // _WINDOWS
static string trailingSanity(string name, bool preserveExt, const char * lstIllegal) {
const auto isIllegalTrailingChar = [lstIllegal](char c) {
return strchr(lstIllegal, c) != nullptr;
};
t_size end = name.length();
if (preserveExt) {
size_t offset = pfc::string_find_last(name.c_str(), '.');
if (offset < end) end = offset;
}
const size_t endEx = end;
while (end > 0) {
if (!isIllegalTrailingChar(name[end - 1])) break;
--end;
}
t_size begin = 0;
while (begin < end) {
if (!isIllegalTrailingChar(name[begin])) break;
++begin;
}
if (end < endEx || begin > 0) {
name = name.subString(begin, end - begin) + name.subString(endEx);
}
return name;
}
string validateFileName(string name, bool allowWC, bool preserveExt, charReplace_t replaceIllegalChar) {
if (!allowWC) { // special fix for filenames that consist only of question marks
size_t end = name.length();
if (preserveExt) {
size_t offset = pfc::string_find_last(name.c_str(), '.');
if (offset < end) end = offset;
}
bool unnamed = true;
for (size_t walk = 0; walk < end; ++walk) {
if (name[walk] != '?') unnamed = false;
}
if (unnamed) {
name = string("[unnamed]") + name.subString(end);
}
}
// Trailing sanity AFTER replaceIllegalNameChars
// replaceIllegalNameChars may remove chars exposing illegal prefix/suffix chars
name = replaceIllegalNameChars(name, allowWC, replaceIllegalChar);
if (name.length() > 0 && !allowWC) {
pfc::string8 lstIllegal = " ";
if (!preserveExt) lstIllegal += ".";
name = trailingSanity(name, preserveExt, lstIllegal);
}
#ifdef _WINDOWS
name = truncatePathComponent(name, preserveExt);
for( unsigned w = 0; w < _countof(specialIllegalNames); ++w ) {
if (pfc::stringEqualsI_ascii( name.c_str(), specialIllegalNames[w] ) ) {
name += "-";
break;
}
}
#endif
if (name.isEmpty()) name = "_";
return name;
}
}}} // namespaces

42
pfc/pathUtils.h Normal file
View File

@@ -0,0 +1,42 @@
#pragma once
#include <functional>
#include "stringNew.h"
namespace pfc {
namespace io {
namespace path {
#ifdef _WINDOWS
typedef string::comparatorCaseInsensitive comparator;
#else
typedef string::comparatorCaseSensitive comparator; // wild assumption
#endif
typedef std::function<const char* (char)> charReplace_t;
const char * charReplaceDefault(char);
const char * charReplaceModern(char);
string getFileName(string path);
string getFileNameWithoutExtension(string path);
string getFileExtension(string path);
string getParent(string filePath);
string getDirectory(string filePath);//same as getParent()
string combine(string basePath,string fileName);
char getDefaultSeparator();
string getSeparators();
bool isSeparator(char c);
string getIllegalNameChars(bool allowWC = false);
string replaceIllegalNameChars(string fn, bool allowWC = false, charReplace_t replace = charReplaceDefault);
string replaceIllegalPathChars(string fn, charReplace_t replace = charReplaceDefault);
bool isInsideDirectory(pfc::string directory, pfc::string inside);
bool isDirectoryRoot(string path);
string validateFileName(string name, bool allowWC = false, bool preserveExt = false, charReplace_t replace = charReplaceDefault);//removes various illegal things from the name, exact effect depends on the OS, includes removal of the invalid characters
template<typename t1, typename t2> inline bool equals(const t1 & v1, const t2 & v2) {return comparator::compare(v1,v2) == 0;}
template<typename t1, typename t2> inline int compare( t1 const & p1, t2 const & p2 ) {return comparator::compare(p1, p2); }
}
}
}

4
pfc/pfc-fb2k-hooks.cpp Normal file
View File

@@ -0,0 +1,4 @@
#include "pfc.h"
#include "pfc-fb2k-hooks.h"
#include "suppress_fb2k_hooks.h"

9
pfc/pfc-fb2k-hooks.h Normal file
View File

@@ -0,0 +1,9 @@
#pragma once
namespace pfc {
void crashImpl();
BOOL winFormatSystemErrorMessageImpl(pfc::string_base & p_out, DWORD p_code);
void crashHook();
BOOL winFormatSystemErrorMessageHook(pfc::string_base & p_out, DWORD p_code);
}

17
pfc/pfc-license.txt Normal file
View File

@@ -0,0 +1,17 @@
Copyright (C) 2002-2021 Peter Pawlowski
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be remove5d or altered from any source distribution.

9
pfc/pfc-readme.txt Normal file
View File

@@ -0,0 +1,9 @@
PFC : Peter's Foundation Classes
A library of loosely connected classes used by foobar2000 codebase; freely available and reusable for other projects.
PFC is not state-of-art code. Many parts of it exist only to keep old bits of foobar2000 codebase ( also third party foobar2000 components ) compiling without modification. For an example, certain classes predating 'pfc' namespace use exist outside the namespace.
Regarding build configurations-
"Release FB2K" and "Debug FB2K" suppress the compilation of pfc-fb2k-hooks.cpp - which allows relevant calls to be redirected to shared.dll
These configurations should be used when compiling fb2k components. Regular configurations should be used for non fb2k apps instead.

231
pfc/pfc.h Normal file
View File

@@ -0,0 +1,231 @@
#ifndef ___PFC_H___
#define ___PFC_H___
// Global flag - whether it's OK to leak static objects as they'll be released anyway by process death
#ifndef PFC_LEAK_STATIC_OBJECTS
#define PFC_LEAK_STATIC_OBJECTS 1
#endif
#ifdef __clang__
// Suppress a warning for a common practice in pfc/fb2k code
#pragma clang diagnostic ignored "-Wdelete-non-virtual-dtor"
#endif
#if !defined(_WINDOWS) && (defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) || defined(_WIN32_WCE))
#define _WINDOWS
#endif
#ifdef _WINDOWS
#include "targetver.h"
#ifndef STRICT
#define STRICT
#endif
#ifndef _SYS_GUID_OPERATOR_EQ_
#define _NO_SYS_GUID_OPERATOR_EQ_ //fix retarded warning with operator== on GUID returning int
#endif
// WinSock2.h *before* Windows.h or else VS2017 15.3 breaks
#include <WinSock2.h>
#include <windows.h>
#if !defined(PFC_WINDOWS_STORE_APP) && !defined(PFC_WINDOWS_DESKTOP_APP)
#ifdef WINAPI_FAMILY_PARTITION
#if ! WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
#define PFC_WINDOWS_STORE_APP // Windows store or Windows phone app, not a desktop app
#endif // #if ! WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
#endif // #ifdef WINAPI_FAMILY_PARTITION
#ifndef PFC_WINDOWS_STORE_APP
#define PFC_WINDOWS_DESKTOP_APP
#endif
#endif // #if !defined(PFC_WINDOWS_STORE_APP) && !defined(PFC_WINDOWS_DESKTOP_APP)
#ifndef _SYS_GUID_OPERATOR_EQ_
__inline bool __InlineIsEqualGUID(REFGUID rguid1, REFGUID rguid2)
{
return (
((unsigned long *) &rguid1)[0] == ((unsigned long *) &rguid2)[0] &&
((unsigned long *) &rguid1)[1] == ((unsigned long *) &rguid2)[1] &&
((unsigned long *) &rguid1)[2] == ((unsigned long *) &rguid2)[2] &&
((unsigned long *) &rguid1)[3] == ((unsigned long *) &rguid2)[3]);
}
inline bool operator==(REFGUID guidOne, REFGUID guidOther) {return __InlineIsEqualGUID(guidOne,guidOther);}
inline bool operator!=(REFGUID guidOne, REFGUID guidOther) {return !__InlineIsEqualGUID(guidOne,guidOther);}
#endif
#include <tchar.h>
#else // not Windows
#include <stdint.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h> // memcmp
typedef struct {
uint32_t Data1;
uint16_t Data2;
uint16_t Data3;
uint8_t Data4[ 8 ];
} GUID; //same as win32 GUID
inline bool operator==(const GUID & p_item1,const GUID & p_item2) {
return memcmp(&p_item1,&p_item2,sizeof(GUID)) == 0;
}
inline bool operator!=(const GUID & p_item1,const GUID & p_item2) {
return memcmp(&p_item1,&p_item2,sizeof(GUID)) != 0;
}
#endif // Windows vs not Windows
#define PFC_MEMORY_SPACE_LIMIT ((t_uint64)1<<(sizeof(void*)*8-1))
#define PFC_ALLOCA_LIMIT (4096)
#define INDEX_INVALID ((unsigned)(-1))
#include <exception>
#include <stdexcept>
#include <new>
#define _PFC_WIDESTRING(_String) L ## _String
#define PFC_WIDESTRING(_String) _PFC_WIDESTRING(_String)
#if defined(_DEBUG) || defined(DEBUG)
#define PFC_DEBUG 1
#else
#define PFC_DEBUG 0
#endif
#if ! PFC_DEBUG
#ifndef NDEBUG
#pragma message("WARNING: release build without NDEBUG")
#endif
#define PFC_ASSERT(_Expression) ((void)0)
#define PFC_ASSERT_SUCCESS(_Expression) (void)( (_Expression), 0)
#define PFC_ASSERT_NO_EXCEPTION(_Expression) { _Expression; }
#else
#ifdef _WIN32
namespace pfc { void myassert_win32(const wchar_t * _Message, const wchar_t *_File, unsigned _Line); }
#define PFC_ASSERT(_Expression) (void)( (!!(_Expression)) || (pfc::myassert_win32(PFC_WIDESTRING(#_Expression), PFC_WIDESTRING(__FILE__), __LINE__), 0) )
#define PFC_ASSERT_SUCCESS(_Expression) PFC_ASSERT(_Expression)
#else
namespace pfc { void myassert (const char * _Message, const char *_File, unsigned _Line); }
#define PFC_ASSERT(_Expression) (void)( (!!(_Expression)) || (pfc::myassert(#_Expression, __FILE__, __LINE__), 0) )
#define PFC_ASSERT_SUCCESS(_Expression) PFC_ASSERT( _Expression )
#endif
#define PFC_ASSERT_NO_EXCEPTION(_Expression) { try { _Expression; } catch(...) { PFC_ASSERT(!"Should not get here - unexpected exception"); } }
#endif
#ifdef _MSC_VER
#if PFC_DEBUG
#define NOVTABLE
#else
#define NOVTABLE _declspec(novtable)
#endif
#if PFC_DEBUG
#define ASSUME(X) PFC_ASSERT(X)
#else
#define ASSUME(X) __assume(X)
#endif
#define PFC_DEPRECATE(X) // __declspec(deprecated(X)) don't do this since VS2015 defaults to erroring these
#define PFC_NORETURN __declspec(noreturn)
#define PFC_NOINLINE __declspec(noinline)
#else
#define NOVTABLE
#define ASSUME(X) PFC_ASSERT(X)
#define PFC_DEPRECATE(X)
#define PFC_NORETURN __attribute__ ((noreturn))
#define PFC_NOINLINE
#endif
namespace pfc {
void selftest();
}
#include "int_types.h"
#include "traits.h"
#include "bit_array.h"
#include "primitives.h"
#include "alloc.h"
#include "array.h"
#include "bit_array_impl.h"
#include "binary_search.h"
#include "bsearch_inline.h"
#include "bsearch.h"
#include "sort.h"
#include "order_helper.h"
#include "list.h"
#include "ptr_list.h"
#include "string_base.h"
#include "string_list.h"
#include "lockless.h"
#include "ref_counter.h"
#include "iterators.h"
#include "avltree.h"
#include "map.h"
#include "bit_array_impl_part2.h"
#include "timers.h"
#include "guid.h"
#include "byte_order.h"
#include "other.h"
#include "chain_list_v2.h"
#include "rcptr.h"
#include "com_ptr_t.h"
#include "string_conv.h"
#include "stringNew.h"
#include "pathUtils.h"
#include "instance_tracker.h"
#include "threads.h"
#include "base64.h"
#include "primitives_part2.h"
#include "cpuid.h"
#include "memalign.h"
#ifdef _WIN32
#include "synchro_win.h"
#else
#include "synchro_nix.h"
#endif
#include "syncd_storage.h"
#ifdef _WIN32
#include "win-objects.h"
#else
#include "nix-objects.h"
#endif
#include "event.h"
#include "audio_sample.h"
#include "wildcard.h"
#include "filehandle.h"
#define PFC_INCLUDED 1
#ifndef PFC_SET_THREAD_DESCRIPTION
#define PFC_SET_THREAD_DESCRIPTION(X)
#endif
#endif //___PFC_H___

521
pfc/pfc.vcxproj Normal file
View File

@@ -0,0 +1,521 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug FB2K|Win32">
<Configuration>Debug FB2K</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug FB2K|x64">
<Configuration>Debug FB2K</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release FB2K|Win32">
<Configuration>Release FB2K</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release FB2K|x64">
<Configuration>Release FB2K</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}</ProjectGuid>
<RootNamespace>pfc</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release FB2K|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release FB2K|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release FB2K|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release FB2K|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|Win32'">$(Configuration)\</IntDir>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release FB2K|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release FB2K|Win32'">$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pfc.h</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<TreatSpecificWarningsAsErrors>4715</TreatSpecificWarningsAsErrors>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Lib>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pfc.h</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<TreatSpecificWarningsAsErrors>4715</TreatSpecificWarningsAsErrors>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<FloatingPointModel>Fast</FloatingPointModel>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Lib>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pfc.h</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<TreatSpecificWarningsAsErrors>4715</TreatSpecificWarningsAsErrors>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Lib>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pfc.h</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<TreatSpecificWarningsAsErrors>4715</TreatSpecificWarningsAsErrors>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Lib>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<StringPooling>true</StringPooling>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FloatingPointModel>Fast</FloatingPointModel>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pfc.h</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalOptions>/d2notypeopt %(AdditionalOptions)</AdditionalOptions>
<TreatSpecificWarningsAsErrors>4715</TreatSpecificWarningsAsErrors>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<OmitFramePointers>true</OmitFramePointers>
<PreprocessorDefinitions>NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Lib>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release FB2K|Win32'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<StringPooling>true</StringPooling>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FloatingPointModel>Fast</FloatingPointModel>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pfc.h</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalOptions>/d2notypeopt %(AdditionalOptions)</AdditionalOptions>
<TreatSpecificWarningsAsErrors>4715</TreatSpecificWarningsAsErrors>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<OmitFramePointers>true</OmitFramePointers>
<PreprocessorDefinitions>NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Lib>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<StringPooling>true</StringPooling>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FloatingPointModel>Fast</FloatingPointModel>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pfc.h</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<AdditionalOptions>/d2notypeopt %(AdditionalOptions)</AdditionalOptions>
<TreatSpecificWarningsAsErrors>4715</TreatSpecificWarningsAsErrors>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<OmitFramePointers>true</OmitFramePointers>
<PreprocessorDefinitions>NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Lib>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release FB2K|x64'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
<StringPooling>true</StringPooling>
<BufferSecurityCheck>false</BufferSecurityCheck>
<FloatingPointModel>Fast</FloatingPointModel>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pfc.h</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<AdditionalOptions>/d2notypeopt %(AdditionalOptions)</AdditionalOptions>
<TreatSpecificWarningsAsErrors>4715</TreatSpecificWarningsAsErrors>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<OmitFramePointers>true</OmitFramePointers>
<PreprocessorDefinitions>NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x0409</Culture>
</ResourceCompile>
<Lib>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="alloc.h" />
<ClInclude Include="array.h" />
<ClInclude Include="audio_sample.h" />
<ClInclude Include="autoref.h" />
<ClInclude Include="avltree.h" />
<ClInclude Include="base64.h" />
<ClInclude Include="binary_search.h" />
<ClInclude Include="bit_array.h" />
<ClInclude Include="bit_array_impl.h" />
<ClInclude Include="bit_array_impl_part2.h" />
<ClInclude Include="bsearch.h" />
<ClInclude Include="bsearch_inline.h" />
<ClInclude Include="byte_order.h" />
<ClInclude Include="chain_list_v2.h" />
<ClInclude Include="cmd_thread.h" />
<ClInclude Include="com_ptr_t.h" />
<ClInclude Include="cpuid.h" />
<ClInclude Include="event.h" />
<ClInclude Include="filehandle.h" />
<ClInclude Include="guid.h" />
<ClInclude Include="instance_tracker.h" />
<ClInclude Include="int_types.h" />
<ClInclude Include="iterators.h" />
<ClInclude Include="list.h" />
<ClInclude Include="lockless.h" />
<ClInclude Include="map.h" />
<ClInclude Include="memalign.h" />
<ClInclude Include="nix-objects.h" />
<ClInclude Include="notifyList.h" />
<ClInclude Include="order_helper.h" />
<ClInclude Include="other.h" />
<ClInclude Include="pathUtils.h" />
<ClInclude Include="pfc-fb2k-hooks.h" />
<ClInclude Include="pfc.h" />
<ClInclude Include="pocket_char_ops.h" />
<ClInclude Include="pool.h" />
<ClInclude Include="pp-gettickcount.h" />
<ClInclude Include="pp-winapi.h" />
<ClInclude Include="primitives.h" />
<ClInclude Include="primitives_part2.h" />
<ClInclude Include="ptrholder.h" />
<ClInclude Include="ptr_list.h" />
<ClInclude Include="rcptr.h" />
<ClInclude Include="ref_counter.h" />
<ClInclude Include="sort.h" />
<ClInclude Include="splitString.h" />
<ClInclude Include="stdsort.h" />
<ClInclude Include="string8_impl.h" />
<ClInclude Include="string_base.h" />
<ClInclude Include="string_conv.h" />
<ClInclude Include="string_list.h" />
<ClInclude Include="stringNew.h" />
<ClInclude Include="suppress_fb2k_hooks.h" />
<ClInclude Include="syncd_storage.h" />
<ClInclude Include="synchro.h" />
<ClInclude Include="synchro_win.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="threads.h" />
<ClInclude Include="timers.h" />
<ClInclude Include="traits.h" />
<ClInclude Include="wait_queue.h" />
<ClInclude Include="weakRef.h" />
<ClInclude Include="wildcard.h" />
<ClInclude Include="win-objects.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="audio_math.cpp" />
<ClCompile Include="audio_sample.cpp" />
<ClCompile Include="base64.cpp" />
<ClCompile Include="bit_array.cpp" />
<ClCompile Include="bsearch.cpp">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|x64'">Disabled</Optimization>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|Win32'">EnableFastChecks</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|x64'">EnableFastChecks</BasicRuntimeChecks>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release FB2K|x64'">MaxSpeed</Optimization>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release FB2K|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="cpuid.cpp" />
<ClCompile Include="filehandle.cpp" />
<ClCompile Include="guid.cpp">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|x64'">Disabled</Optimization>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|Win32'">EnableFastChecks</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|x64'">EnableFastChecks</BasicRuntimeChecks>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release FB2K|x64'">MaxSpeed</Optimization>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release FB2K|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="nix-objects.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release FB2K|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release FB2K|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="other.cpp">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|x64'">Disabled</Optimization>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|Win32'">EnableFastChecks</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|x64'">EnableFastChecks</BasicRuntimeChecks>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release FB2K|x64'">MaxSpeed</Optimization>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release FB2K|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="pathUtils.cpp" />
<ClCompile Include="pfc-fb2k-hooks.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release FB2K|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release FB2K|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="printf.cpp" />
<ClCompile Include="selftest.cpp" />
<ClCompile Include="sort.cpp">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|x64'">Disabled</Optimization>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|Win32'">EnableFastChecks</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|x64'">EnableFastChecks</BasicRuntimeChecks>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release FB2K|x64'">MaxSpeed</Optimization>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release FB2K|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="stdafx.cpp">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|x64'">Disabled</Optimization>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|Win32'">EnableFastChecks</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|x64'">EnableFastChecks</BasicRuntimeChecks>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|x64'">Create</PrecompiledHeader>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release FB2K|x64'">MaxSpeed</Optimization>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release FB2K|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release FB2K|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release FB2K|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="string_base.cpp" />
<ClCompile Include="string_conv.cpp" />
<ClCompile Include="stringNew.cpp" />
<ClCompile Include="threads.cpp" />
<ClCompile Include="timers.cpp" />
<ClCompile Include="utf8.cpp">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|x64'">Disabled</Optimization>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|Win32'">EnableFastChecks</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug FB2K|x64'">EnableFastChecks</BasicRuntimeChecks>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release FB2K|x64'">MaxSpeed</Optimization>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release FB2K|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="wildcard.cpp" />
<ClCompile Include="win-objects.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="pfc-license.txt" />
<None Include="pfc-readme.txt" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

290
pfc/pfc.vcxproj.filters Normal file
View File

@@ -0,0 +1,290 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="audio_math.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="audio_sample.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="base64.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="bit_array.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="bsearch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="cpuid.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="filehandle.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="guid.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="nix-objects.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="pathUtils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="other.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="pfc-fb2k-hooks.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="printf.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="selftest.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="sort.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="stdafx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="string_base.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="string_conv.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="stringNew.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="threads.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="timers.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="utf8.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="wildcard.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="win-objects.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="alloc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="array.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="audio_sample.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="autoref.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="avltree.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="base64.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="binary_search.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="bit_array.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="bit_array_impl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="bit_array_impl_part2.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="bsearch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="bsearch_inline.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="byte_order.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="chain_list_v2.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="cmd_thread.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="com_ptr_t.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="cpuid.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="event.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="filehandle.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="guid.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="instance_tracker.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="int_types.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="iterators.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="list.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="lockless.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="map.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="memalign.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="nix-objects.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="notifyList.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="order_helper.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="other.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="pathUtils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="pfc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="pfc-fb2k-hooks.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="pocket_char_ops.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="pool.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="pp-gettickcount.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="pp-winapi.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="primitives.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="primitives_part2.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ptr_list.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ptrholder.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="rcptr.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ref_counter.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="splitString.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="sort.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="string_base.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="string_conv.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="string_list.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="string8_impl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="stringNew.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="syncd_storage.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="synchro.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="synchro_win.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="threads.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="timers.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="traits.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="wait_queue.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="weakRef.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="wildcard.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="win-objects.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="suppress_fb2k_hooks.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="stdsort.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="targetver.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="pfc-license.txt">
<Filter>Doc</Filter>
</None>
<None Include="pfc-readme.txt">
<Filter>Doc</Filter>
</None>
</ItemGroup>
<ItemGroup>
<Filter Include="Doc">
<UniqueIdentifier>{70b1137d-0c8f-4bb0-8adb-d406ad38bdd0}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files">
<UniqueIdentifier>{225fc8b6-5fca-4e3f-b56e-1ad97e992841}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{e1ea3e94-74b7-464e-ab17-69508b52a4e6}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>

245
pfc/pocket_char_ops.h Normal file
View File

@@ -0,0 +1,245 @@
#pragma once
// Standalone header (no dependencies) with implementations of PFC UTF-8 & UTF-16 manipulation routines
static const uint8_t mask_tab[6] = { 0x80,0xE0,0xF0,0xF8,0xFC,0xFE };
static const uint8_t val_tab[6] = { 0,0xC0,0xE0,0xF0,0xF8,0xFC };
size_t utf8_char_len_from_header(char p_c) throw()
{
size_t cnt = 0;
for (;;)
{
if ((p_c & mask_tab[cnt]) == val_tab[cnt]) break;
if (++cnt >= 6) return 0;
}
return cnt + 1;
}
size_t utf8_decode_char(const char *p_utf8, unsigned & wide) throw() {
const uint8_t * utf8 = (const uint8_t*)p_utf8;
const size_t max = 6;
if (utf8[0]<0x80) {
wide = utf8[0];
return utf8[0]>0 ? 1 : 0;
}
wide = 0;
unsigned res = 0;
unsigned n;
unsigned cnt = 0;
for (;;)
{
if ((*utf8&mask_tab[cnt]) == val_tab[cnt]) break;
if (++cnt >= max) return 0;
}
cnt++;
if (cnt == 2 && !(*utf8 & 0x1E)) return 0;
if (cnt == 1)
res = *utf8;
else
res = (0xFF >> (cnt + 1))&*utf8;
for (n = 1; n<cnt; n++)
{
if ((utf8[n] & 0xC0) != 0x80)
return 0;
if (!res && n == 2 && !((utf8[n] & 0x7F) >> (7 - cnt)))
return 0;
res = (res << 6) | (utf8[n] & 0x3F);
}
wide = res;
return cnt;
}
size_t utf8_decode_char(const char *p_utf8, unsigned & wide, size_t max) throw()
{
const uint8_t * utf8 = (const uint8_t*)p_utf8;
if (max == 0) {
wide = 0;
return 0;
}
if (utf8[0]<0x80) {
wide = utf8[0];
return utf8[0]>0 ? 1 : 0;
}
if (max>6) max = 6;
wide = 0;
unsigned res = 0;
unsigned n;
unsigned cnt = 0;
for (;;)
{
if ((*utf8&mask_tab[cnt]) == val_tab[cnt]) break;
if (++cnt >= max) return 0;
}
cnt++;
if (cnt == 2 && !(*utf8 & 0x1E)) return 0;
if (cnt == 1)
res = *utf8;
else
res = (0xFF >> (cnt + 1))&*utf8;
for (n = 1; n<cnt; n++)
{
if ((utf8[n] & 0xC0) != 0x80)
return 0;
if (!res && n == 2 && !((utf8[n] & 0x7F) >> (7 - cnt)))
return 0;
res = (res << 6) | (utf8[n] & 0x3F);
}
wide = res;
return cnt;
}
size_t utf8_encode_char(unsigned wide, char * target) throw()
{
size_t count;
if (wide < 0x80)
count = 1;
else if (wide < 0x800)
count = 2;
else if (wide < 0x10000)
count = 3;
else if (wide < 0x200000)
count = 4;
else if (wide < 0x4000000)
count = 5;
else if (wide <= 0x7FFFFFFF)
count = 6;
else
return 0;
//if (count>max) return 0;
if (target == 0)
return count;
switch (count)
{
case 6:
target[5] = 0x80 | (wide & 0x3F);
wide = wide >> 6;
wide |= 0x4000000;
case 5:
target[4] = 0x80 | (wide & 0x3F);
wide = wide >> 6;
wide |= 0x200000;
case 4:
target[3] = 0x80 | (wide & 0x3F);
wide = wide >> 6;
wide |= 0x10000;
case 3:
target[2] = 0x80 | (wide & 0x3F);
wide = wide >> 6;
wide |= 0x800;
case 2:
target[1] = 0x80 | (wide & 0x3F);
wide = wide >> 6;
wide |= 0xC0;
case 1:
target[0] = wide & 0xFF;
}
return count;
}
size_t utf16_encode_char(unsigned cur_wchar, char16_t * out) throw()
{
if (cur_wchar < 0x10000) {
*out = (char16_t)cur_wchar; return 1;
} else if (cur_wchar < (1 << 20)) {
unsigned c = cur_wchar - 0x10000;
//MSDN:
//The first (high) surrogate is a 16-bit code value in the range U+D800 to U+DBFF. The second (low) surrogate is a 16-bit code value in the range U+DC00 to U+DFFF. Using surrogates, Unicode can support over one million characters. For more details about surrogates, refer to The Unicode Standard, version 2.0.
out[0] = (char16_t)(0xD800 | (0x3FF & (c >> 10)));
out[1] = (char16_t)(0xDC00 | (0x3FF & c));
return 2;
} else {
*out = '?'; return 1;
}
}
size_t utf16_decode_char(const char16_t * p_source, unsigned * p_out, size_t p_source_length) throw() {
if (p_source_length == 0) { *p_out = 0; return 0; } else if (p_source_length == 1) {
*p_out = p_source[0];
return 1;
} else {
size_t retval = 0;
unsigned decoded = p_source[0];
if (decoded != 0)
{
retval = 1;
if ((decoded & 0xFC00) == 0xD800)
{
unsigned low = p_source[1];
if ((low & 0xFC00) == 0xDC00)
{
decoded = 0x10000 + (((decoded & 0x3FF) << 10) | (low & 0x3FF));
retval = 2;
}
}
}
*p_out = decoded;
return retval;
}
}
unsigned utf8_get_char(const char * src)
{
unsigned rv = 0;
utf8_decode_char(src, rv);
return rv;
}
size_t utf8_char_len(const char * s, size_t max) throw()
{
unsigned dummy;
return utf8_decode_char(s, dummy, max);
}
size_t skip_utf8_chars(const char * ptr, size_t count) throw()
{
size_t num = 0;
for (; count && ptr[num]; count--)
{
size_t d = utf8_char_len(ptr + num, (size_t)(-1));
if (d <= 0) break;
num += d;
}
return num;
}
bool is_valid_utf8(const char * param, size_t max) {
size_t walk = 0;
while (walk < max && param[walk] != 0) {
size_t d;
unsigned dummy;
d = utf8_decode_char(param + walk, dummy, max - walk);
if (d == 0) return false;
walk += d;
if (walk > max) {
// should not get here
return false;
}
}
return true;
}

42
pfc/pool.h Normal file
View File

@@ -0,0 +1,42 @@
#pragma once
#include "synchro.h"
#include <memory>
#include <list>
namespace pfc {
template<typename obj_t>
class objPool {
public:
objPool() : m_maxCount(pfc_infinite) {}
typedef std::shared_ptr<obj_t> objRef_t;
objRef_t get() {
insync(m_sync);
auto i = m_pool.begin();
if ( i == m_pool.end() ) return nullptr;
auto ret = *i;
m_pool.erase(i);
return ret;
}
objRef_t make() {
auto obj = get();
if ( ! obj ) obj = std::make_shared<obj_t>();
return obj;
}
void setMaxCount(size_t c) {
insync(m_sync);
m_maxCount = c;
}
void put(objRef_t obj) {
insync(m_sync);
if ( m_pool.size() < m_maxCount ) {
m_pool.push_back(obj);
}
}
private:
size_t m_maxCount;
std::list<objRef_t> m_pool;
critical_section m_sync;
};
}

16
pfc/pp-gettickcount.h Normal file
View File

@@ -0,0 +1,16 @@
#if !defined(PP_GETTICKCOUNT_H_INCLUDED) && defined(_WIN32)
#define PP_GETTICKCOUNT_H_INCLUDED
namespace PP {
#if _WIN32_WINNT >= 0x600
typedef uint64_t tickcount_t;
inline tickcount_t getTickCount() { return ::GetTickCount64(); }
#else
#define PFC_TICKCOUNT_32BIT
typedef uint32_t tickcount_t;
inline tickcount_t getTickCount() { return ::GetTickCount(); }
#endif
}
#endif // #if !defined(PP_GETTICKCOUNT_H_INCLUDED) && defined(_WIN32)

105
pfc/pp-winapi.h Normal file
View File

@@ -0,0 +1,105 @@
#if !defined(PP_WINAPI_H_INCLUDED) && defined(_WIN32)
#define PP_WINAPI_H_INCLUDED
#ifdef WINAPI_FAMILY_PARTITION
#if ! WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
#ifndef CreateEvent // SPECIAL HACK: disable this stuff if somehow these functions are already defined
inline HANDLE CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCTSTR lpName) {
DWORD flags = 0;
if (bManualReset) flags |= CREATE_EVENT_MANUAL_RESET;
if (bInitialState) flags |= CREATE_EVENT_INITIAL_SET;
DWORD rights = SYNCHRONIZE | EVENT_MODIFY_STATE;
return CreateEventEx(lpEventAttributes, lpName, flags, rights);
}
#define CreateEvent CreateEventW
inline DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) {
return WaitForSingleObjectEx(hHandle, dwMilliseconds, FALSE);
}
inline DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL bWaitAll, DWORD dwMilliseconds) {
return WaitForMultipleObjectsEx(nCount, lpHandles, bWaitAll, dwMilliseconds, FALSE);
}
inline void InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection) {
InitializeCriticalSectionEx(lpCriticalSection, 0, 0);
}
#endif // #ifndef CreateEvent
#ifndef CreateMutex
inline HANDLE CreateMutexW(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCTSTR lpName) {
DWORD rights = MUTEX_MODIFY_STATE | SYNCHRONIZE;
DWORD flags = 0;
if (bInitialOwner) flags |= CREATE_MUTEX_INITIAL_OWNER;
return CreateMutexExW(lpMutexAttributes, lpName, flags, rights);
}
#define CreateMutex CreateMutexW
#endif // CreateMutex
#ifndef FindFirstFile
inline HANDLE FindFirstFileW(LPCTSTR lpFileName, LPWIN32_FIND_DATA lpFindFileData) {
return FindFirstFileEx(lpFileName, FindExInfoStandard, lpFindFileData, FindExSearchNameMatch, NULL, 0);
}
#define FindFirstFile FindFirstFileW
#endif // #ifndef FindFirstFile
// No reliable way to detect if GetFileSizeEx is present?? Give ours another name
inline BOOL GetFileSizeEx_Fallback(HANDLE hFile, PLARGE_INTEGER lpFileSize) {
FILE_STANDARD_INFO info;
if (!GetFileInformationByHandleEx(hFile, FileStandardInfo, &info, sizeof(info))) return FALSE;
*lpFileSize = info.EndOfFile;
return TRUE;
}
#define PP_GetFileSizeEx_Fallback_Present
#ifndef CreateFile
inline HANDLE CreateFileW(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) {
CREATEFILE2_EXTENDED_PARAMETERS arg = {};
arg.dwSize = sizeof(arg);
arg.hTemplateFile = hTemplateFile;
arg.lpSecurityAttributes = lpSecurityAttributes;
arg.dwFileAttributes = dwFlagsAndAttributes & 0x0000FFFF;
arg.dwFileFlags = dwFlagsAndAttributes & 0xFFFF0000;
return CreateFile2(lpFileName, dwDesiredAccess, dwShareMode, dwCreationDisposition, &arg);
}
#define CreateFile CreateFileW
#endif // #ifndef CreateFile
#ifndef GetFileAttributes
inline DWORD GetFileAttributesW(const wchar_t * path) {
WIN32_FILE_ATTRIBUTE_DATA data = {};
if (!GetFileAttributesEx(path, GetFileExInfoStandard, &data)) return 0xFFFFFFFF;
return data.dwFileAttributes;
}
#define GetFileAttributes GetFileAttributesW
#endif // #ifndef GetFileAttributes
#endif // #if ! WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
#endif // #ifdef WINAPI_FAMILY_PARTITION
#ifndef PP_GetFileSizeEx_Fallback_Present
#define GetFileSizeEx_Fallback GetFileSizeEx
#endif
#endif // !defined(PP_WINAPI_H_INCLUDED) && defined(_WIN32)

933
pfc/primitives.h Normal file
View File

@@ -0,0 +1,933 @@
#pragma once
#include <functional>
#define tabsize(x) ((size_t)(sizeof(x)/sizeof(*x)))
#define PFC_TABSIZE(x) ((size_t)(sizeof(x)/sizeof(*x)))
#define TEMPLATE_CONSTRUCTOR_FORWARD_FLOOD_WITH_INITIALIZER(THISCLASS,MEMBER,INITIALIZER) \
THISCLASS() : MEMBER() INITIALIZER \
template<typename t_param1> THISCLASS(const t_param1 & p_param1) : MEMBER(p_param1) INITIALIZER \
template<typename t_param1,typename t_param2> THISCLASS(const t_param1 & p_param1,const t_param2 & p_param2) : MEMBER(p_param1,p_param2) INITIALIZER \
template<typename t_param1,typename t_param2,typename t_param3> THISCLASS(const t_param1 & p_param1,const t_param2 & p_param2,const t_param3 & p_param3) : MEMBER(p_param1,p_param2,p_param3) INITIALIZER \
template<typename t_param1,typename t_param2,typename t_param3,typename t_param4> THISCLASS(const t_param1 & p_param1,const t_param2 & p_param2,const t_param3 & p_param3,const t_param4 & p_param4) : MEMBER(p_param1,p_param2,p_param3,p_param4) INITIALIZER \
template<typename t_param1,typename t_param2,typename t_param3,typename t_param4,typename t_param5> THISCLASS(const t_param1 & p_param1,const t_param2 & p_param2,const t_param3 & p_param3,const t_param4 & p_param4,const t_param5 & p_param5) : MEMBER(p_param1,p_param2,p_param3,p_param4,p_param5) INITIALIZER \
template<typename t_param1,typename t_param2,typename t_param3,typename t_param4,typename t_param5,typename t_param6> THISCLASS(const t_param1 & p_param1,const t_param2 & p_param2,const t_param3 & p_param3,const t_param4 & p_param4,const t_param5 & p_param5,const t_param6 & p_param6) : MEMBER(p_param1,p_param2,p_param3,p_param4,p_param5,p_param6) INITIALIZER \
template<typename t_param1,typename t_param2,typename t_param3,typename t_param4,typename t_param5,typename t_param6, typename t_param7> THISCLASS(const t_param1 & p_param1,const t_param2 & p_param2,const t_param3 & p_param3,const t_param4 & p_param4,const t_param5 & p_param5,const t_param6 & p_param6,const t_param7 & p_param7) : MEMBER(p_param1,p_param2,p_param3,p_param4,p_param5,p_param6,p_param7) INITIALIZER \
template<typename t_param1,typename t_param2,typename t_param3,typename t_param4,typename t_param5,typename t_param6, typename t_param7, typename t_param8> THISCLASS(const t_param1 & p_param1,const t_param2 & p_param2,const t_param3 & p_param3,const t_param4 & p_param4,const t_param5 & p_param5,const t_param6 & p_param6,const t_param7 & p_param7, const t_param8 & p_param8) : MEMBER(p_param1,p_param2,p_param3,p_param4,p_param5,p_param6,p_param7, p_param8) INITIALIZER
#define TEMPLATE_CONSTRUCTOR_FORWARD_FLOOD(THISCLASS,MEMBER) TEMPLATE_CONSTRUCTOR_FORWARD_FLOOD_WITH_INITIALIZER(THISCLASS,MEMBER,{})
#ifdef _WIN32
#ifndef _MSC_VER
#error MSVC expected
#endif
// MSVC specific - part of fb2k ABI - cannot ever change on MSVC/Windows
#define PFC_DECLARE_EXCEPTION(NAME,BASECLASS,DEFAULTMSG) \
class NAME : public BASECLASS { \
public: \
static const char * g_what() {return DEFAULTMSG;} \
NAME() : BASECLASS(DEFAULTMSG,0) {} \
NAME(const char * p_msg) : BASECLASS(p_msg) {} \
NAME(const char * p_msg,int) : BASECLASS(p_msg,0) {} \
NAME(const NAME & p_source) : BASECLASS(p_source) {} \
};
namespace pfc {
template<typename t_exception> PFC_NORETURN inline void throw_exception_with_message(const char * p_message) {
throw t_exception(p_message);
}
}
#else
#define PFC_DECLARE_EXCEPTION(NAME,BASECLASS,DEFAULTMSG) \
class NAME : public BASECLASS { \
public: \
static const char * g_what() {return DEFAULTMSG;} \
const char* what() const throw() {return DEFAULTMSG;} \
};
namespace pfc {
template<typename t_base> class __exception_with_message_t : public t_base {
private: typedef __exception_with_message_t<t_base> t_self;
public:
__exception_with_message_t(const char * p_message) : m_message(NULL) {
set_message(p_message);
}
__exception_with_message_t() : m_message(NULL) {}
__exception_with_message_t(const t_self & p_source) : m_message(NULL) {set_message(p_source.m_message);}
const char* what() const throw() {return m_message != NULL ? m_message : "unnamed exception";}
const t_self & operator=(const t_self & p_source) {set_message(p_source.m_message);}
~__exception_with_message_t() throw() {cleanup();}
private:
void set_message(const char * p_message) throw() {
cleanup();
if (p_message != NULL) m_message = strdup(p_message);
}
void cleanup() throw() {
if (m_message != NULL) {free(m_message); m_message = NULL;}
}
char * m_message;
};
template<typename t_exception> PFC_NORETURN void throw_exception_with_message(const char * p_message) {
throw __exception_with_message_t<t_exception>(p_message);
}
}
#endif
namespace pfc {
template<typename p_type1,typename p_type2> class assert_same_type;
template<typename p_type> class assert_same_type<p_type,p_type> {};
template<typename p_type1,typename p_type2>
class is_same_type { public: enum {value = false}; };
template<typename p_type>
class is_same_type<p_type,p_type> { public: enum {value = true}; };
template<bool val> class static_assert_t;
template<> class static_assert_t<true> {};
#define PFC_STATIC_ASSERT(X) { ::pfc::static_assert_t<(X)>(); }
template<typename t_type>
void assert_raw_type() {static_assert_t< !traits_t<t_type>::needs_constructor && !traits_t<t_type>::needs_destructor >();}
template<typename t_type> class assert_byte_type;
template<> class assert_byte_type<char> {};
template<> class assert_byte_type<unsigned char> {};
template<> class assert_byte_type<signed char> {};
template<typename t_type> void __unsafe__memcpy_t(t_type * p_dst,const t_type * p_src,t_size p_count) {
::memcpy(reinterpret_cast<void*>(p_dst), reinterpret_cast<const void*>(p_src), p_count * sizeof(t_type));
}
template<typename t_type> void __unsafe__in_place_destructor_t(t_type & p_item) throw() {
if (traits_t<t_type>::needs_destructor) try{ p_item.~t_type(); } catch(...) {}
}
template<typename t_type> void __unsafe__in_place_constructor_t(t_type & p_item) {
if (traits_t<t_type>::needs_constructor) {
t_type * ret = new(&p_item) t_type;
PFC_ASSERT(ret == &p_item);
(void) ret; // suppress warning
}
}
template<typename t_type> void __unsafe__in_place_destructor_array_t(t_type * p_items, t_size p_count) throw() {
if (traits_t<t_type>::needs_destructor) {
t_type * walk = p_items;
for(t_size n=p_count;n;--n) __unsafe__in_place_destructor_t(*(walk++));
}
}
template<typename t_type> t_type * __unsafe__in_place_constructor_array_t(t_type * p_items,t_size p_count) {
if (traits_t<t_type>::needs_constructor) {
t_size walkptr = 0;
try {
for(walkptr=0;walkptr<p_count;++walkptr) __unsafe__in_place_constructor_t(p_items[walkptr]);
} catch(...) {
__unsafe__in_place_destructor_array_t(p_items,walkptr);
throw;
}
}
return p_items;
}
template<typename t_type> t_type * __unsafe__in_place_resize_array_t(t_type * p_items,t_size p_from,t_size p_to) {
if (p_from < p_to) __unsafe__in_place_constructor_array_t(p_items + p_from, p_to - p_from);
else if (p_from > p_to) __unsafe__in_place_destructor_array_t(p_items + p_to, p_from - p_to);
return p_items;
}
template<typename t_type,typename t_copy> void __unsafe__in_place_constructor_copy_t(t_type & p_item,const t_copy & p_copyfrom) {
if (traits_t<t_type>::needs_constructor) {
t_type * ret = new(&p_item) t_type(p_copyfrom);
PFC_ASSERT(ret == &p_item);
(void) ret; // suppress warning
} else {
p_item = p_copyfrom;
}
}
template<typename t_type,typename t_copy> t_type * __unsafe__in_place_constructor_array_copy_t(t_type * p_items,t_size p_count, const t_copy * p_copyfrom) {
t_size walkptr = 0;
try {
for(walkptr=0;walkptr<p_count;++walkptr) __unsafe__in_place_constructor_copy_t(p_items[walkptr],p_copyfrom[walkptr]);
} catch(...) {
__unsafe__in_place_destructor_array_t(p_items,walkptr);
throw;
}
return p_items;
}
template<typename t_type,typename t_copy> t_type * __unsafe__in_place_constructor_array_copy_partial_t(t_type * p_items,t_size p_count, const t_copy * p_copyfrom,t_size p_copyfrom_count) {
if (p_copyfrom_count > p_count) p_copyfrom_count = p_count;
__unsafe__in_place_constructor_array_copy_t(p_items,p_copyfrom_count,p_copyfrom);
try {
__unsafe__in_place_constructor_array_t(p_items + p_copyfrom_count,p_count - p_copyfrom_count);
} catch(...) {
__unsafe__in_place_destructor_array_t(p_items,p_copyfrom_count);
throw;
}
return p_items;
}
template<typename t_ret> t_ret implicit_cast(t_ret val) {return val;}
template<typename t_ret,typename t_param>
t_ret * safe_ptr_cast(t_param * p_param) {
if (pfc::is_same_type<t_ret,t_param>::value) return p_param;
else {
if (p_param == NULL) return NULL;
else return p_param;
}
}
typedef std::exception exception;
PFC_DECLARE_EXCEPTION(exception_overflow,exception,"Overflow");
PFC_DECLARE_EXCEPTION(exception_bug_check,exception,"Bug check");
PFC_DECLARE_EXCEPTION(exception_invalid_params,exception_bug_check,"Invalid parameters");
PFC_DECLARE_EXCEPTION(exception_unexpected_recursion,exception_bug_check,"Unexpected recursion");
PFC_DECLARE_EXCEPTION(exception_not_implemented,exception_bug_check,"Feature not implemented");
PFC_DECLARE_EXCEPTION(exception_dynamic_assert,exception_bug_check,"dynamic_assert failure");
template<typename t_ret,typename t_param>
t_ret downcast_guarded(const t_param & p_param) {
t_ret temp = (t_ret) p_param;
if ((t_param) temp != p_param) throw exception_overflow();
return temp;
}
template<typename t_exception,typename t_ret,typename t_param>
t_ret downcast_guarded_ex(const t_param & p_param) {
t_ret temp = (t_ret) p_param;
if ((t_param) temp != p_param) throw t_exception();
return temp;
}
template<typename t_acc,typename t_add>
void accumulate_guarded(t_acc & p_acc, const t_add & p_add) {
t_acc delta = downcast_guarded<t_acc>(p_add);
delta += p_acc;
if (delta < p_acc) throw exception_overflow();
p_acc = delta;
}
//deprecated
inline void bug_check_assert(bool p_condition, const char * p_msg) {
if (!p_condition) {
PFC_ASSERT(0);
throw_exception_with_message<exception_bug_check>(p_msg);
}
}
//deprecated
inline void bug_check_assert(bool p_condition) {
if (!p_condition) {
PFC_ASSERT(0);
throw exception_bug_check();
}
}
inline void dynamic_assert(bool p_condition, const char * p_msg) {
if (!p_condition) {
PFC_ASSERT(0);
throw_exception_with_message<exception_dynamic_assert>(p_msg);
}
}
inline void dynamic_assert(bool p_condition) {
if (!p_condition) {
PFC_ASSERT(0);
throw exception_dynamic_assert();
}
}
template<typename T>
inline void swap_multi_t(T * p_buffer1,T * p_buffer2,t_size p_size) {
T * walk1 = p_buffer1, * walk2 = p_buffer2;
for(t_size n=p_size;n;--n) {
T temp (* walk1);
*walk1 = *walk2;
*walk2 = temp;
walk1++; walk2++;
}
}
template<typename T,t_size p_size>
inline void swap_multi_t(T * p_buffer1,T * p_buffer2) {
T * walk1 = p_buffer1, * walk2 = p_buffer2;
for(t_size n=p_size;n;--n) {
T temp (* walk1);
*walk1 = *walk2;
*walk2 = temp;
walk1++; walk2++;
}
}
template<t_size p_size>
inline void __unsafe__swap_raw_t(void * p_object1, void * p_object2) {
if (p_size % sizeof(t_size) == 0) {
swap_multi_t<t_size,p_size/sizeof(t_size)>(reinterpret_cast<t_size*>(p_object1),reinterpret_cast<t_size*>(p_object2));
} else {
swap_multi_t<t_uint8,p_size>(reinterpret_cast<t_uint8*>(p_object1),reinterpret_cast<t_uint8*>(p_object2));
}
}
template<typename T>
inline void swap_t(T & p_item1, T & p_item2) {
if (traits_t<T>::realloc_safe) {
__unsafe__swap_raw_t<sizeof(T)>( reinterpret_cast<void*>( &p_item1 ), reinterpret_cast<void*>( &p_item2 ) );
} else {
T temp( std::move(p_item2) );
p_item2 = std::move(p_item1);
p_item1 = std::move(temp);
}
}
//! This is similar to plain p_item1 = p_item2; assignment, but optimized for the case where p_item2 content is no longer needed later on. This can be overridden for specific classes for optimal performance. \n
//! p_item2 value is undefined after performing a move_t. For an example, in certain cases move_t will fall back to swap_t.
template<typename T>
inline void move_t(T & p_item1, T & p_item2) {
typedef traits_t<T> t;
if (t::needs_constructor || t::needs_destructor) {
if (t::realloc_safe) swap_t(p_item1, p_item2);
else p_item1 = std::move( p_item2 );
} else {
p_item1 = std::move( p_item2 );
}
}
template<typename t_array>
t_size array_size_t(const t_array & p_array) {return p_array.get_size();}
template<typename t_item, t_size p_width>
t_size array_size_t(const t_item (&p_array)[p_width]) {return p_width;}
template<typename t_array, typename t_item> static bool array_isLast(const t_array & arr, const t_item & item) {
const t_size size = pfc::array_size_t(arr);
return size > 0 && arr[size-1] == item;
}
template<typename t_array, typename t_item> static bool array_isFirst(const t_array & arr, const t_item & item) {
const t_size size = pfc::array_size_t(arr);
return size > 0 && arr[0] == item;
}
template<typename t_array,typename t_filler>
inline void fill_t(t_array & p_buffer,const t_size p_count, const t_filler & p_filler) {
for(t_size n=0;n<p_count;n++)
p_buffer[n] = p_filler;
}
template<typename t_array,typename t_filler>
inline void fill_ptr_t(t_array * p_buffer,const t_size p_count, const t_filler & p_filler) {
for(t_size n=0;n<p_count;n++)
p_buffer[n] = p_filler;
}
template<typename t_item1, typename t_item2>
inline int compare_t(const t_item1 & p_item1, const t_item2 & p_item2) {
if (p_item1 < p_item2) return -1;
else if (p_item1 > p_item2) return 1;
else return 0;
}
//! For use with avltree/map etc.
class comparator_default {
public:
template<typename t_item1,typename t_item2>
inline static int compare(const t_item1 & p_item1,const t_item2 & p_item2) {return pfc::compare_t(p_item1,p_item2);}
};
template<typename t_comparator = pfc::comparator_default> class comparator_pointer { public:
template<typename t_item1,typename t_item2> static int compare(const t_item1 & p_item1,const t_item2 & p_item2) {return t_comparator::compare(*p_item1,*p_item2);}
};
template<typename t_primary,typename t_secondary> class comparator_dual { public:
template<typename t_item1,typename t_item2> static int compare(const t_item1 & p_item1,const t_item2 & p_item2) {
int state = t_primary::compare(p_item1,p_item2);
if (state != 0) return state;
return t_secondary::compare(p_item1,p_item2);
}
};
class comparator_memcmp {
public:
template<typename t_item1,typename t_item2>
inline static int compare(const t_item1 & p_item1,const t_item2 & p_item2) {
static_assert_t<sizeof(t_item1) == sizeof(t_item2)>();
return memcmp(&p_item1,&p_item2,sizeof(t_item1));
}
};
template<typename t_source1, typename t_source2>
t_size subtract_sorted_lists_calculate_count(const t_source1 & p_source1, const t_source2 & p_source2) {
t_size walk1 = 0, walk2 = 0, walk_out = 0;
const t_size max1 = p_source1.get_size(), max2 = p_source2.get_size();
for(;;) {
int state;
if (walk1 < max1 && walk2 < max2) {
state = pfc::compare_t(p_source1[walk1],p_source2[walk2]);
} else if (walk1 < max1) {
state = -1;
} else if (walk2 < max2) {
state = 1;
} else {
break;
}
if (state < 0) walk_out++;
if (state <= 0) walk1++;
if (state >= 0) walk2++;
}
return walk_out;
}
//! Subtracts p_source2 contents from p_source1 and stores result in p_destination. Both source lists must be sorted.
//! Note: duplicates will be carried over (and ignored for p_source2).
template<typename t_destination, typename t_source1, typename t_source2>
void subtract_sorted_lists(t_destination & p_destination,const t_source1 & p_source1, const t_source2 & p_source2) {
p_destination.set_size(subtract_sorted_lists_calculate_count(p_source1,p_source2));
t_size walk1 = 0, walk2 = 0, walk_out = 0;
const t_size max1 = p_source1.get_size(), max2 = p_source2.get_size();
for(;;) {
int state;
if (walk1 < max1 && walk2 < max2) {
state = pfc::compare_t(p_source1[walk1],p_source2[walk2]);
} else if (walk1 < max1) {
state = -1;
} else if (walk2 < max2) {
state = 1;
} else {
break;
}
if (state < 0) p_destination[walk_out++] = p_source1[walk1];
if (state <= 0) walk1++;
if (state >= 0) walk2++;
}
}
template<typename t_source1, typename t_source2>
t_size merge_sorted_lists_calculate_count(const t_source1 & p_source1, const t_source2 & p_source2) {
t_size walk1 = 0, walk2 = 0, walk_out = 0;
const t_size max1 = p_source1.get_size(), max2 = p_source2.get_size();
for(;;) {
int state;
if (walk1 < max1 && walk2 < max2) {
state = pfc::compare_t(p_source1[walk1],p_source2[walk2]);
} else if (walk1 < max1) {
state = -1;
} else if (walk2 < max2) {
state = 1;
} else {
break;
}
if (state <= 0) walk1++;
if (state >= 0) walk2++;
walk_out++;
}
return walk_out;
}
//! Merges p_source1 and p_source2, storing content in p_destination. Both source lists must be sorted.
//! Note: duplicates will be carried over.
template<typename t_destination, typename t_source1, typename t_source2>
void merge_sorted_lists(t_destination & p_destination,const t_source1 & p_source1, const t_source2 & p_source2) {
p_destination.set_size(merge_sorted_lists_calculate_count(p_source1,p_source2));
t_size walk1 = 0, walk2 = 0, walk_out = 0;
const t_size max1 = p_source1.get_size(), max2 = p_source2.get_size();
for(;;) {
int state;
if (walk1 < max1 && walk2 < max2) {
state = pfc::compare_t(p_source1[walk1],p_source2[walk2]);
} else if (walk1 < max1) {
state = -1;
} else if (walk2 < max2) {
state = 1;
} else {
break;
}
if (state < 0) {
p_destination[walk_out] = p_source1[walk1++];
} else if (state > 0) {
p_destination[walk_out] = p_source2[walk2++];
} else {
p_destination[walk_out] = p_source1[walk1];
walk1++; walk2++;
}
walk_out++;
}
}
template<typename t_array,typename T>
inline t_size append_t(t_array & p_array,const T & p_item)
{
t_size old_count = p_array.get_size();
p_array.set_size(old_count + 1);
p_array[old_count] = p_item;
return old_count;
}
template<typename t_array,typename T>
inline t_size append_swap_t(t_array & p_array,T & p_item)
{
t_size old_count = p_array.get_size();
p_array.set_size(old_count + 1);
swap_t(p_array[old_count],p_item);
return old_count;
}
template<typename t_array>
inline t_size insert_uninitialized_t(t_array & p_array,t_size p_index) {
t_size old_count = p_array.get_size();
if (p_index > old_count) p_index = old_count;
p_array.set_size(old_count + 1);
for(t_size n=old_count;n>p_index;n--) move_t(p_array[n], p_array[n-1]);
return p_index;
}
template<typename t_array,typename T>
inline t_size insert_t(t_array & p_array,const T & p_item,t_size p_index) {
t_size old_count = p_array.get_size();
if (p_index > old_count) p_index = old_count;
p_array.set_size(old_count + 1);
for(t_size n=old_count;n>p_index;n--)
move_t(p_array[n], p_array[n-1]);
p_array[p_index] = p_item;
return p_index;
}
template<typename array1_t, typename array2_t>
void insert_array_t( array1_t & outArray, size_t insertAt, array2_t const & inArray, size_t inArraySize) {
const size_t oldSize = outArray.get_size();
if (insertAt > oldSize) insertAt = oldSize;
const size_t newSize = oldSize + inArraySize;
outArray.set_size( newSize );
for(size_t m = oldSize; m != insertAt; --m) {
move_t( outArray[ m - 1 + inArraySize], outArray[m - 1] );
}
for(size_t w = 0; w < inArraySize; ++w) {
outArray[ insertAt + w ] = inArray[ w ];
}
}
template<typename t_array,typename in_array_t>
inline t_size insert_multi_t(t_array & p_array,const in_array_t & p_items, size_t p_itemCount, t_size p_index) {
const t_size old_count = p_array.get_size();
const size_t new_count = old_count + p_itemCount;
if (p_index > old_count) p_index = old_count;
p_array.set_size(new_count);
size_t toMove = old_count - p_index;
for(size_t w = 0; w < toMove; ++w) {
move_t( p_array[new_count - 1 - w], p_array[old_count - 1 - w] );
}
for(size_t w = 0; w < p_itemCount; ++w) {
p_array[p_index+w] = p_items[w];
}
return p_index;
}
template<typename t_array,typename T>
inline t_size insert_swap_t(t_array & p_array,T & p_item,t_size p_index) {
t_size old_count = p_array.get_size();
if (p_index > old_count) p_index = old_count;
p_array.set_size(old_count + 1);
for(t_size n=old_count;n>p_index;n--)
swap_t(p_array[n],p_array[n-1]);
swap_t(p_array[p_index],p_item);
return p_index;
}
template<typename T>
inline T max_t(const T & item1, const T & item2) {return item1 > item2 ? item1 : item2;};
template<typename T>
inline T min_t(const T & item1, const T & item2) {return item1 < item2 ? item1 : item2;};
template<typename T>
inline T abs_t(T item) {return item<0 ? -item : item;}
template<typename T>
inline T sqr_t(T item) {return item * item;}
template<typename T>
inline T clip_t(const T & p_item, const T & p_min, const T & p_max) {
if (p_item < p_min) return p_min;
else if (p_item <= p_max) return p_item;
else return p_max;
}
template<typename T>
inline void delete_t(T* ptr) {delete ptr;}
template<typename T>
inline void delete_array_t(T* ptr) {delete[] ptr;}
template<typename T>
inline T* clone_t(T* ptr) {return new T(*ptr);}
template<typename t_exception,typename t_int>
inline t_int mul_safe_t(t_int p_val1,t_int p_val2) {
if (p_val1 == 0 || p_val2 == 0) return 0;
t_int temp = (t_int) (p_val1 * p_val2);
if (temp / p_val1 != p_val2) throw t_exception();
return temp;
}
template<typename t_int>
t_int multiply_guarded(t_int v1, t_int v2) {
return mul_safe_t<exception_overflow>(v1, v2);
}
template<typename t_int> t_int add_unsigned_clipped(t_int v1, t_int v2) {
t_int v = v1 + v2;
if (v < v1) return ~0;
return v;
}
template<typename t_int> t_int sub_unsigned_clipped(t_int v1, t_int v2) {
t_int v = v1 - v2;
if (v > v1) return 0;
return v;
}
template<typename t_int> void acc_unsigned_clipped(t_int & v1, t_int v2) {
v1 = add_unsigned_clipped(v1, v2);
}
template<typename t_src,typename t_dst>
void memcpy_t(t_dst* p_dst,const t_src* p_src,t_size p_count) {
for(t_size n=0;n<p_count;n++) p_dst[n] = p_src[n];
}
template<typename t_dst,typename t_src>
void copy_array_loop_t(t_dst & p_dst,const t_src & p_src,t_size p_count) {
for(t_size n=0;n<p_count;n++) p_dst[n] = p_src[n];
}
template<typename t_src,typename t_dst>
void memcpy_backwards_t(t_dst * p_dst,const t_src * p_src,t_size p_count) {
p_dst += p_count; p_src += p_count;
for(t_size n=0;n<p_count;n++) *(--p_dst) = *(--p_src);
}
template<typename T,typename t_val>
void memset_t(T * p_buffer,const t_val & p_val,t_size p_count) {
for(t_size n=0;n<p_count;n++) p_buffer[n] = p_val;
}
template<typename T,typename t_val>
void memset_t(T &p_buffer,const t_val & p_val) {
const t_size width = pfc::array_size_t(p_buffer);
for(t_size n=0;n<width;n++) p_buffer[n] = p_val;
}
template<typename T>
void memset_null_t(T * p_buffer,t_size p_count) {
for(t_size n=0;n<p_count;n++) p_buffer[n] = 0;
}
template<typename T>
void memset_null_t(T &p_buffer) {
const t_size width = pfc::array_size_t(p_buffer);
for(t_size n=0;n<width;n++) p_buffer[n] = 0;
}
template<typename T>
void memmove_t(T* p_dst,const T* p_src,t_size p_count) {
if (p_dst == p_src) {/*do nothing*/}
else if (p_dst > p_src && p_dst < p_src + p_count) memcpy_backwards_t<T>(p_dst,p_src,p_count);
else memcpy_t<T>(p_dst,p_src,p_count);
}
template<typename TVal> void memxor_t(TVal * out, const TVal * s1, const TVal * s2, t_size count) {
for(t_size walk = 0; walk < count; ++walk) out[walk] = s1[walk] ^ s2[walk];
}
static void memxor(void * target, const void * source1, const void * source2, t_size size) {
memxor_t( reinterpret_cast<t_uint8*>(target), reinterpret_cast<const t_uint8*>(source1), reinterpret_cast<const t_uint8*>(source2), size);
}
template<typename T>
T* new_ptr_check_t(T* p_ptr) {
if (p_ptr == NULL) throw std::bad_alloc();
return p_ptr;
}
template<typename T>
int sgn_t(const T & p_val) {
if (p_val < 0) return -1;
else if (p_val > 0) return 1;
else return 0;
}
template<typename T> const T* empty_string_t();
template<> inline const char * empty_string_t<char>() {return "";}
template<> inline const wchar_t * empty_string_t<wchar_t>() {return L"";}
template<typename t_type,typename t_newval>
t_type replace_t(t_type & p_var,const t_newval & p_newval) {
t_type oldval = p_var;
p_var = p_newval;
return oldval;
}
template<typename t_type>
t_type replace_null_t(t_type & p_var) {
t_type ret = p_var;
p_var = 0;
return ret;
}
template<t_size p_size_pow2>
inline bool is_ptr_aligned_t(const void * p_ptr) {
static_assert_t< (p_size_pow2 & (p_size_pow2 - 1)) == 0 >();
return ( ((t_size)p_ptr) & (p_size_pow2-1) ) == 0;
}
template<typename t_array>
void array_rangecheck_t(const t_array & p_array,t_size p_index) {
if (p_index >= pfc::array_size_t(p_array)) throw pfc::exception_overflow();
}
template<typename t_array>
void array_rangecheck_t(const t_array & p_array,t_size p_from,t_size p_to) {
if (p_from > p_to) throw pfc::exception_overflow();
array_rangecheck_t(p_array,p_from); array_rangecheck_t(p_array,p_to);
}
t_int32 rint32(double p_val);
t_int64 rint64(double p_val);
template<typename array_t, typename pred_t>
inline size_t remove_if_t( array_t & arr, pred_t pred ) {
const size_t inCount = arr.size();
size_t walk = 0;
for( walk = 0; walk < inCount; ++ walk ) {
if ( pred(arr[walk]) ) break;
}
size_t total = walk;
for( ; walk < inCount; ++ walk ) {
if ( !pred(arr[walk] ) ) {
move_t(arr[total++], arr[walk]);
}
}
arr.resize(total);
return total;
}
template<typename t_array>
inline t_size remove_mask_t(t_array & p_array,const bit_array & p_mask)//returns amount of items left
{
t_size n,count = p_array.size(), total = 0;
n = total = p_mask.find(true,0,count);
if (n<count)
{
for(n=p_mask.find(false,n+1,count-n-1);n<count;n=p_mask.find(false,n+1,count-n-1))
move_t(p_array[total++],p_array[n]);
p_array.resize(total);
return total;
}
else return count;
}
template<typename t_array,typename t_compare>
t_size find_duplicates_sorted_t(t_array p_array,t_size p_count,t_compare p_compare,bit_array_var & p_out) {
t_size ret = 0;
t_size n;
if (p_count > 0)
{
p_out.set(0,false);
for(n=1;n<p_count;n++)
{
bool found = p_compare(p_array[n-1],p_array[n]) == 0;
if (found) ret++;
p_out.set(n,found);
}
}
return ret;
}
template<typename t_array,typename t_compare,typename t_permutation>
t_size find_duplicates_sorted_permutation_t(t_array p_array,t_size p_count,t_compare p_compare,t_permutation const & p_permutation,bit_array_var & p_out) {
t_size ret = 0;
t_size n;
if (p_count > 0) {
p_out.set(p_permutation[0],false);
for(n=1;n<p_count;n++)
{
bool found = p_compare(p_array[p_permutation[n-1]],p_array[p_permutation[n]]) == 0;
if (found) ret++;
p_out.set(p_permutation[n],found);
}
}
return ret;
}
template<typename t_char>
t_size strlen_t(const t_char * p_string,t_size p_length = ~0) {
for(t_size walk = 0;;walk++) {
if (walk >= p_length || p_string[walk] == 0) return walk;
}
}
template<typename t_array>
class __list_to_array_enumerator {
public:
__list_to_array_enumerator(t_array & p_array) : m_walk(), m_array(p_array) {}
template<typename t_item>
void operator() (const t_item & p_item) {
PFC_ASSERT(m_walk < m_array.get_size());
m_array[m_walk++] = p_item;
}
void finalize() {
PFC_ASSERT(m_walk == m_array.get_size());
}
private:
t_size m_walk;
t_array & m_array;
};
template<typename t_list,typename t_array>
void list_to_array(t_array & p_array,const t_list & p_list) {
p_array.set_size(p_list.get_count());
__list_to_array_enumerator<t_array> enumerator(p_array);
p_list.enumerate(enumerator);
enumerator.finalize();
}
template<typename t_receiver>
class enumerator_add_item {
public:
enumerator_add_item(t_receiver & p_receiver) : m_receiver(p_receiver) {}
template<typename t_item> void operator() (const t_item & p_item) {m_receiver.add_item(p_item);}
private:
t_receiver & m_receiver;
};
template<typename t_receiver,typename t_giver>
void overwrite_list_enumerated(t_receiver & p_receiver,const t_giver & p_giver) {
enumerator_add_item<t_receiver> wrapper(p_receiver);
p_giver.enumerate(wrapper);
}
template<typename t_receiver,typename t_giver>
void copy_list_enumerated(t_receiver & p_receiver,const t_giver & p_giver) {
p_receiver.remove_all();
overwrite_list_enumerated(p_receiver,p_giver);
}
inline bool lxor(bool p_val1,bool p_val2) {
return p_val1 == !p_val2;
}
template<typename t_val>
inline void min_acc(t_val & p_acc,const t_val & p_val) {
if (p_val < p_acc) p_acc = p_val;
}
template<typename t_val>
inline void max_acc(t_val & p_acc,const t_val & p_val) {
if (p_val > p_acc) p_acc = p_val;
}
t_uint64 pow_int(t_uint64 base, t_uint64 exp);
template<typename t_val>
class incrementScope {
public:
incrementScope(t_val & i) : v(i) {++v;}
~incrementScope() {--v;}
private:
t_val & v;
};
inline unsigned countBits32(uint32_t i) {
const uint32_t mask = 0x11111111;
uint32_t acc = i & mask;
acc += (i >> 1) & mask;
acc += (i >> 2) & mask;
acc += (i >> 3) & mask;
const uint32_t mask2 = 0x0F0F0F0F;
uint32_t acc2 = acc & mask2;
acc2 += (acc >> 4) & mask2;
const uint32_t mask3 = 0x00FF00FF;
uint32_t acc3 = acc2 & mask3;
acc3 += (acc2 >> 8) & mask3;
return (acc3 & 0xFFFF) + ((acc3 >> 16) & 0xFFFF);
}
// Forward declarations
template<typename t_to,typename t_from>
void copy_array_t(t_to & p_to,const t_from & p_from);
template<typename t_array,typename t_value>
void fill_array_t(t_array & p_array,const t_value & p_value);
// Generic no-op for breakpointing stuff
inline void nop() {}
class onLeaving {
public:
onLeaving() {}
onLeaving( std::function<void () > f_ ) : f(f_) {}
~onLeaving() {
if (f) f();
}
std::function<void () > f;
private:
void operator=( onLeaving const & ) = delete;
onLeaving( const onLeaving & ) = delete;
};
template<typename obj_t>
class singleton {
public:
static obj_t instance;
};
template<typename obj_t>
obj_t singleton<obj_t>::instance;
};
#define PFC_SINGLETON(X) ::pfc::singleton<X>::instance
#define PFC_CLASS_NOT_COPYABLE(THISCLASSNAME,THISTYPE) \
private: \
THISCLASSNAME(const THISTYPE&) = delete; \
const THISTYPE & operator=(const THISTYPE &) = delete;
#define PFC_CLASS_NOT_COPYABLE_EX(THISTYPE) PFC_CLASS_NOT_COPYABLE(THISTYPE,THISTYPE)

26
pfc/primitives_part2.h Normal file
View File

@@ -0,0 +1,26 @@
#pragma once
namespace pfc {
template<typename t_list1, typename t_list2>
static bool guess_reorder_pattern(pfc::array_t<t_size> & out, const t_list1 & from, const t_list2 & to) {
typedef typename t_list1::t_item t_item;
const t_size count = from.get_size();
if (count != to.get_size()) return false;
out.set_size(count);
for(t_size walk = 0; walk < count; ++walk) out[walk] = walk;
//required output: to[n] = from[out[n]];
typedef pfc::chain_list_v2_t<t_size> t_queue;
pfc::map_t<t_item, t_queue > content;
for(t_size walk = 0; walk < count; ++walk) {
content.find_or_add(from[walk]).add_item(walk);
}
for(t_size walk = 0; walk < count; ++walk) {
t_queue * q = content.query_ptr(to[walk]);
if (q == NULL) return false;
if (q->get_count() == 0) return false;
out[walk] = *q->first();
q->remove(q->first());
}
return true;
}
}

121
pfc/printf.cpp Normal file
View File

@@ -0,0 +1,121 @@
#include "pfc.h"
//implementations of deprecated string_printf methods, with a pragma to disable warnings when they reference other deprecated methods.
#ifndef _MSC_VER
#define _itoa_s itoa
#define _ultoa_s ultoa
#endif
#ifdef _MSC_VER
#pragma warning(disable:4996)
#endif
namespace pfc {
void string_printf::run(const char * fmt,va_list list) {g_run(*this,fmt,list);}
string_printf_va::string_printf_va(const char * fmt,va_list list) {string_printf::g_run(*this,fmt,list);}
void string_printf::g_run(string_base & out,const char * fmt,va_list list)
{
out.reset();
while(*fmt)
{
if (*fmt=='%')
{
fmt++;
if (*fmt=='%')
{
out.add_char('%');
fmt++;
}
else
{
bool force_sign = false;
if (*fmt=='+')
{
force_sign = true;
fmt++;
}
char padchar = (*fmt == '0') ? '0' : ' ';
t_size pad = 0;
while(*fmt>='0' && *fmt<='9')
{
pad = pad * 10 + (*fmt - '0');
fmt++;
}
if (*fmt=='s' || *fmt=='S')
{
const char * ptr = va_arg(list,const char*);
t_size len = strlen(ptr);
if (pad>len) out.add_chars(padchar,pad-len);
out.add_string(ptr);
fmt++;
}
else if (*fmt=='i' || *fmt=='I' || *fmt=='d' || *fmt=='D')
{
int val = va_arg(list,int);
if (force_sign && val>0) out.add_char('+');
pfc::format_int temp( val );
t_size len = strlen(temp);
if (pad>len) out.add_chars(padchar,pad-len);
out.add_string(temp);
fmt++;
}
else if (*fmt=='u' || *fmt=='U')
{
int val = va_arg(list,int);
if (force_sign && val>0) out.add_char('+');
pfc::format_uint temp(val);
t_size len = strlen(temp);
if (pad>len) out.add_chars(padchar,pad-len);
out.add_string(temp);
fmt++;
}
else if (*fmt=='x' || *fmt=='X')
{
auto val = va_arg(list,unsigned);
if (force_sign && val>0) out.add_char('+');
pfc::format_uint temp(val, 0, 16);
if (*fmt=='X')
{
char * t = const_cast< char* > ( temp.get_ptr() );
while(*t)
{
if (*t>='a' && *t<='z')
*t += 'A' - 'a';
t++;
}
}
t_size len = strlen(temp);
if (pad>len) out.add_chars(padchar,pad-len);
out.add_string(temp);
fmt++;
}
else if (*fmt=='c' || *fmt=='C')
{
out.add_char(va_arg(list,int));
fmt++;
}
}
}
else
{
out.add_char(*(fmt++));
}
}
}
string_printf::string_printf(const char * fmt,...)
{
va_list list;
va_start(list,fmt);
run(fmt,list);
va_end(list);
}
}

43
pfc/ptr_list.h Normal file
View File

@@ -0,0 +1,43 @@
#pragma once
namespace pfc {
template<class T, class B = list_t<T*> >
class ptr_list_t : public B
{
public:
ptr_list_t() {}
ptr_list_t(const ptr_list_t<T> & p_source) {*this = p_source;}
void free_by_idx(t_size n) {free_mask(bit_array_one(n));}
void free_all() {this->remove_all_ex(free);}
void free_mask(const bit_array & p_mask) {this->remove_mask_ex(p_mask,free);}
void delete_item(T* ptr) {delete_by_idx(find_item(ptr));}
void delete_by_idx(t_size p_index) {
delete_mask(bit_array_one(p_index));
}
void delete_all() {
this->remove_all_ex(pfc::delete_t<T>);
}
void delete_mask(const bit_array & p_mask) {
this->remove_mask_ex(p_mask,pfc::delete_t<T>);
}
T * operator[](t_size n) const {return this->get_item(n);}
};
template<typename T,t_size N>
class ptr_list_hybrid_t : public ptr_list_t<T,list_hybrid_t<T*,N> > {
public:
ptr_list_hybrid_t() {}
ptr_list_hybrid_t(const ptr_list_hybrid_t<T,N> & p_source) {*this = p_source;}
};
typedef ptr_list_t<void> ptr_list;
template<typename item, typename base> class traits_t<ptr_list_t<item, base> > : public traits_t<base> {};
}

3
pfc/ptrholder.h Normal file
View File

@@ -0,0 +1,3 @@
#pragma once
// added for compatibility with fb2k mobile

177
pfc/rcptr.h Normal file
View File

@@ -0,0 +1,177 @@
#pragma once
namespace pfc {
struct _rcptr_null;
typedef _rcptr_null* t_rcptr_null;
static const t_rcptr_null rcptr_null = NULL;
class rc_container_base {
public:
long add_ref() throw() {
return ++m_counter;
}
long release() throw() {
long ret = --m_counter;
if (ret == 0) PFC_ASSERT_NO_EXCEPTION( delete this );
return ret;
}
protected:
virtual ~rc_container_base() {}
private:
refcounter m_counter;
};
template<typename t_object>
class rc_container_t : public rc_container_base {
public:
template<typename ... arg_t>
rc_container_t(arg_t && ... arg) : m_object(std::forward<arg_t>(arg) ...) {}
t_object m_object;
};
template<typename t_object>
class rcptr_t {
private:
typedef rcptr_t<t_object> t_self;
typedef rc_container_base t_container;
typedef rc_container_t<t_object> t_container_impl;
public:
rcptr_t(t_rcptr_null) throw() {_clear();}
rcptr_t() throw() {_clear();}
rcptr_t(const t_self & p_source) throw() {__init(p_source);}
t_self const & operator=(const t_self & p_source) throw() {__copy(p_source); return *this;}
template<typename t_source>
rcptr_t(const rcptr_t<t_source> & p_source) throw() {__init(p_source);}
template<typename t_source>
const t_self & operator=(const rcptr_t<t_source> & p_source) throw() {__copy(p_source); return *this;}
rcptr_t(t_self && p_source) throw() {_move(p_source);}
const t_self & operator=(t_self && p_source) throw() {release(); _move(p_source); return *this;}
const t_self & operator=(t_rcptr_null) throw() {release(); return *this;}
/* template<typename t_object_cast>
operator rcptr_t<t_object_cast>() const throw() {
rcptr_t<t_object_cast> temp;
if (is_valid()) temp.__set_from_cast(this->m_container,this->m_ptr);
return temp;
}*/
template<typename t_other>
bool operator==(const rcptr_t<t_other> & p_other) const throw() {
return m_container == p_other.__container();
}
template<typename t_other>
bool operator!=(const rcptr_t<t_other> & p_other) const throw() {
return m_container != p_other.__container();
}
void __set_from_cast(t_container * p_container,t_object * p_ptr) throw() {
//addref first because in rare cases this is the same pointer as the one we currently own
if (p_container != NULL) p_container->add_ref();
release();
m_container = p_container;
m_ptr = p_ptr;
}
bool is_valid() const throw() {return m_container != NULL;}
bool is_empty() const throw() {return m_container == NULL;}
~rcptr_t() throw() {release();}
void release() throw() {
t_container * temp = m_container;
m_ptr = NULL;
m_container = NULL;
if (temp != NULL) temp->release();
}
template<typename t_object_cast>
rcptr_t<t_object_cast> static_cast_t() const throw() {
rcptr_t<t_object_cast> temp;
if (is_valid()) temp.__set_from_cast(this->m_container,static_cast<t_object_cast*>(this->m_ptr));
return temp;
}
void new_t() {
on_new(new t_container_impl());
}
template<typename ... arg_t>
void new_t(arg_t && ... arg) {
on_new(new t_container_impl(std::forward<arg_t>(arg) ...));
}
static t_self g_new_t() {
t_self temp;
temp.new_t();
return temp;
}
template<typename ... arg_t>
static t_self g_new_t(arg_t && ... arg) {
t_self temp;
temp.new_t(std::forward<arg_t>(arg) ...);
return temp;
}
t_object & operator*() const throw() {return *this->m_ptr;}
t_object * operator->() const throw() {return this->m_ptr;}
t_container * __container() const throw() {return m_container;}
// FOR INTERNAL USE ONLY
void _clear() throw() {m_container = NULL; m_ptr = NULL;}
private:
template<typename t_source>
void __init(const rcptr_t<t_source> & p_source) throw() {
m_container = p_source.__container();
m_ptr = &*p_source;
if (m_container != NULL) m_container->add_ref();
}
template<typename t_source>
void _move(rcptr_t<t_source> & p_source) throw() {
m_container = p_source.__container();
m_ptr = &*p_source;
p_source._clear();
}
template<typename t_source>
void __copy(const rcptr_t<t_source> & p_source) throw() {
__set_from_cast(p_source.__container(),&*p_source);
}
void on_new(t_container_impl * p_container) throw() {
this->release();
p_container->add_ref();
this->m_ptr = &p_container->m_object;
this->m_container = p_container;
}
t_container * m_container;
t_object * m_ptr;
};
template<typename t_object, typename ... arg_t>
rcptr_t<t_object> rcnew_t(arg_t && ... arg) {
rcptr_t<t_object> temp;
temp.new_t(std::forward<arg_t>(arg) ...);
return temp;
}
class traits_rcptr : public traits_default {
public:
enum { realloc_safe = true, constructor_may_fail = false };
};
template<typename T> class traits_t<rcptr_t<T> > : public traits_rcptr {};
}

104
pfc/ref_counter.h Normal file
View File

@@ -0,0 +1,104 @@
#pragma once
namespace pfc {
class NOVTABLE refcounted_object_root
{
public:
void refcount_add_ref() throw() {++m_counter;}
void refcount_release() throw() {if (--m_counter == 0) delete this;}
void _refcount_release_temporary() throw() {--m_counter;}//for internal use only!
protected:
refcounted_object_root() {}
virtual ~refcounted_object_root() {}
private:
refcounter m_counter;
};
template<typename T>
class refcounted_object_ptr_t {
private:
typedef refcounted_object_ptr_t<T> t_self;
public:
inline refcounted_object_ptr_t() throw() : m_ptr(NULL) {}
inline refcounted_object_ptr_t(T* p_ptr) throw() : m_ptr(NULL) {copy(p_ptr);}
inline refcounted_object_ptr_t(const t_self & p_source) throw() : m_ptr(NULL) {copy(p_source);}
inline refcounted_object_ptr_t(t_self && p_source) throw() { m_ptr = p_source.m_ptr; p_source.m_ptr = NULL; }
template<typename t_source>
inline refcounted_object_ptr_t(t_source * p_ptr) throw() : m_ptr(NULL) {copy(p_ptr);}
template<typename t_source>
inline refcounted_object_ptr_t(const refcounted_object_ptr_t<t_source> & p_source) throw() : m_ptr(NULL) {copy(p_source);}
inline ~refcounted_object_ptr_t() throw() {if (m_ptr != NULL) m_ptr->refcount_release();}
template<typename t_source>
inline void copy(t_source * p_ptr) throw() {
T* torel = pfc::replace_t(m_ptr,pfc::safe_ptr_cast<T>(p_ptr));
if (m_ptr != NULL) m_ptr->refcount_add_ref();
if (torel != NULL) torel->refcount_release();
}
template<typename t_source>
inline void copy(const refcounted_object_ptr_t<t_source> & p_source) throw() {copy(p_source.get_ptr());}
inline const t_self & operator=(const t_self & p_source) throw() {copy(p_source); return *this;}
inline const t_self & operator=(t_self && p_source) throw() {attach(p_source.detach()); return *this;}
inline const t_self & operator=(T * p_ptr) throw() {copy(p_ptr); return *this;}
template<typename t_source> inline t_self & operator=(const refcounted_object_ptr_t<t_source> & p_source) throw() {copy(p_source); return *this;}
template<typename t_source> inline t_self & operator=(t_source * p_ptr) throw() {copy(p_ptr); return *this;}
inline void release() throw() {
T * temp = pfc::replace_t(m_ptr,(T*)NULL);
if (temp != NULL) temp->refcount_release();
}
inline T& operator*() const throw() {return *m_ptr;}
inline T* operator->() const throw() {PFC_ASSERT(m_ptr != NULL);return m_ptr;}
inline T* get_ptr() const throw() {return m_ptr;}
inline bool is_valid() const throw() {return m_ptr != NULL;}
inline bool is_empty() const throw() {return m_ptr == NULL;}
inline bool operator==(const t_self & p_item) const throw() {return m_ptr == p_item.get_ptr();}
inline bool operator!=(const t_self & p_item) const throw() {return m_ptr != p_item.get_ptr();}
inline bool operator>(const t_self & p_item) const throw() {return m_ptr > p_item.get_ptr();}
inline bool operator<(const t_self & p_item) const throw() {return m_ptr < p_item.get_ptr();}
inline T* _duplicate_ptr() const throw()//should not be used ! temporary !
{
if (m_ptr) m_ptr->refcount_add_ref();
return m_ptr;
}
inline T* detach() throw() {//should not be used ! temporary !
T* ret = m_ptr;
m_ptr = 0;
return ret;
}
inline void attach(T * p_ptr) throw() {//should not be used ! temporary !
release();
m_ptr = p_ptr;
}
inline t_self & operator<<(t_self & p_source) throw() {attach(p_source.detach());return *this;}
inline t_self & operator>>(t_self & p_dest) throw() {p_dest.attach(detach());return *this;}
private:
T* m_ptr;
};
template<typename T>
class traits_t<refcounted_object_ptr_t<T> > : public traits_default {
public:
enum { realloc_safe = true, constructor_may_fail = false};
};
};

94
pfc/selftest.cpp Normal file
View File

@@ -0,0 +1,94 @@
#include "pfc.h"
namespace {
class foo {};
}
inline pfc::string_base & operator<<(pfc::string_base & p_fmt,foo p_source) {p_fmt.add_string_("FOO"); return p_fmt;}
namespace {
using namespace pfc;
class thread_selftest : public thread {
public:
void threadProc() {
pfc::event ev;
ev.wait_for(1);
m_event.set_state(true);
ev.wait_for(1);
}
pfc::event m_event;
void selftest() {
lores_timer timer; timer.start();
this->start();
if (!m_event.wait_for(-1)) {
PFC_ASSERT(!"Should not get here");
return;
}
PFC_ASSERT(fabs(timer.query() - 1.0) < 0.1);
this->waitTillDone();
PFC_ASSERT(fabs(timer.query() - 2.0) < 0.1);
}
};
}
namespace pfc {
// Self test routines that need to be executed to do their payload
void selftest_runtime() {
{
thread_selftest t; t.selftest();
}
{
pfc::map_t<pfc::string8, int, pfc::comparator_strcmp> map;
map["1"] = 1;
map["2"] = 2;
map["3"] = 3;
PFC_ASSERT(map.get_count() == 3);
PFC_ASSERT(map["1"] == 1);
PFC_ASSERT(map["2"] == 2);
PFC_ASSERT(map["3"] == 3);
}
}
// Self test routines that fail at compile time if there's something seriously wrong
void selftest_static() {
PFC_STATIC_ASSERT(sizeof(t_uint8) == 1);
PFC_STATIC_ASSERT(sizeof(t_uint16) == 2);
PFC_STATIC_ASSERT(sizeof(t_uint32) == 4);
PFC_STATIC_ASSERT(sizeof(t_uint64) == 8);
PFC_STATIC_ASSERT(sizeof(t_int8) == 1);
PFC_STATIC_ASSERT(sizeof(t_int16) == 2);
PFC_STATIC_ASSERT(sizeof(t_int32) == 4);
PFC_STATIC_ASSERT(sizeof(t_int64) == 8);
PFC_STATIC_ASSERT(sizeof(t_float32) == 4);
PFC_STATIC_ASSERT(sizeof(t_float64) == 8);
PFC_STATIC_ASSERT(sizeof(t_size) == sizeof(void*));
PFC_STATIC_ASSERT(sizeof(t_ssize) == sizeof(void*));
PFC_STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4);
PFC_STATIC_ASSERT(sizeof(GUID) == 16);
typedef pfc::avltree_t<int> t_asdf;
t_asdf asdf; asdf.add_item(1);
t_asdf::iterator iter = asdf._first_var();
t_asdf::const_iterator iter2 = asdf._first_var();
PFC_string_formatter() << "foo" << 1337 << foo();
pfc::list_t<int> l; l.add_item(3);
}
void selftest() {
selftest_static(); selftest_runtime();
debugLog out; out << "PFC selftest OK";
}
}

268
pfc/sort.cpp Normal file
View File

@@ -0,0 +1,268 @@
#include "pfc.h"
#if defined(_M_IX86) || defined(_M_IX64)
#include <intrin.h>
#define PFC_HAVE_RDTSC
#endif
namespace pfc {
void swap_void(void * item1,void * item2,t_size width)
{
unsigned char * ptr1 = (unsigned char*)item1, * ptr2 = (unsigned char*)item2;
t_size n;
unsigned char temp;
for(n=0;n<width;n++)
{
temp = *ptr2;
*ptr2 = *ptr1;
*ptr1 = temp;
ptr1++;
ptr2++;
}
}
void reorder(reorder_callback & p_callback,const t_size * p_order,t_size p_count)
{
t_size done_size = bit_array_bittable::g_estimate_size(p_count);
pfc::array_hybrid_t<unsigned char,1024> done;
done.set_size(done_size);
pfc::memset_t(done,(unsigned char)0);
t_size n;
for(n=0;n<p_count;n++)
{
t_size next = p_order[n];
if (next!=n && !bit_array_bittable::g_get(done,n))
{
t_size prev = n;
do
{
PFC_ASSERT(!bit_array_bittable::g_get(done,next));
PFC_ASSERT(next>n);
PFC_ASSERT(n<p_count);
p_callback.swap(prev,next);
bit_array_bittable::g_set(done,next,true);
prev = next;
next = p_order[next];
} while(next!=n);
//bit_array_bittable::g_set(done,n,true);
}
}
}
void reorder_void(void * data,t_size width,const t_size * order,t_size num,void (*swapfunc)(void * item1,void * item2,t_size width))
{
unsigned char * base = (unsigned char *) data;
t_size done_size = bit_array_bittable::g_estimate_size(num);
pfc::array_hybrid_t<unsigned char,1024> done;
done.set_size(done_size);
pfc::memset_t(done,(unsigned char)0);
t_size n;
for(n=0;n<num;n++)
{
t_size next = order[n];
if (next!=n && !bit_array_bittable::g_get(done,n))
{
t_size prev = n;
do
{
PFC_ASSERT(!bit_array_bittable::g_get(done,next));
PFC_ASSERT(next>n);
PFC_ASSERT(n<num);
swapfunc(base+width*prev,base+width*next,width);
bit_array_bittable::g_set(done,next,true);
prev = next;
next = order[next];
} while(next!=n);
//bit_array_bittable::g_set(done,n,true);
}
}
}
namespace {
class sort_callback_impl_legacy : public sort_callback
{
public:
sort_callback_impl_legacy(
void * p_base,t_size p_width,
int (*p_comp)(const void *, const void *),
void (*p_swap)(void *, void *, t_size)
) :
m_base((char*)p_base), m_width(p_width),
m_comp(p_comp), m_swap(p_swap)
{
}
int compare(t_size p_index1, t_size p_index2) const
{
return m_comp(m_base + p_index1 * m_width, m_base + p_index2 * m_width);
}
void swap(t_size p_index1, t_size p_index2)
{
m_swap(m_base + p_index1 * m_width, m_base + p_index2 * m_width, m_width);
}
private:
char * m_base;
t_size m_width;
int (*m_comp)(const void *, const void *);
void (*m_swap)(void *, void *, t_size);
};
}
void sort_void_ex (
void *base,
t_size num,
t_size width,
int (*comp)(const void *, const void *),
void (*swap)(void *, void *, t_size) )
{
sort_callback_impl_legacy cb(base,width,comp,swap);
sort(cb,num);
}
static void squaresort(pfc::sort_callback & p_callback,t_size const p_base,t_size const p_count) {
const t_size max = p_base + p_count;
for(t_size walk = p_base + 1; walk < max; ++walk) {
for(t_size prev = p_base; prev < walk; ++prev) {
p_callback.swap_check(prev,walk);
}
}
}
inline static void __sort_2elem_helper(pfc::sort_callback & p_callback,t_size & p_elem1,t_size & p_elem2) {
if (p_callback.compare(p_elem1,p_elem2) > 0) pfc::swap_t(p_elem1,p_elem2);
}
#ifdef PFC_HAVE_RDTSC
static inline t_uint64 uniqueVal() {return __rdtsc();}
#else
static counter uniqueValCounter;
static counter::t_val uniqueVal() {
return ++uniqueValCounter;
}
#endif
static t_size myrand(t_size count) {
const uint64_t rm = (uint64_t)RAND_MAX + 1;
uint64_t m = 1;
uint64_t v = 0;
for(;;) {
v += rand() * m;
m *= rm;
if (m >= count) break;
}
v ^= uniqueVal();
return (t_size)(v % count);
}
inline static t_size __pivot_helper(pfc::sort_callback & p_callback,t_size const p_base,t_size const p_count) {
PFC_ASSERT(p_count > 2);
//t_size val1 = p_base, val2 = p_base + (p_count / 2), val3 = p_base + (p_count - 1);
t_size val1 = myrand(p_count), val2 = myrand(p_count-1), val3 = myrand(p_count-2);
if (val2 >= val1) val2++;
if (val3 >= val1) val3++;
if (val3 >= val2) val3++;
val1 += p_base; val2 += p_base; val3 += p_base;
__sort_2elem_helper(p_callback,val1,val2);
__sort_2elem_helper(p_callback,val1,val3);
__sort_2elem_helper(p_callback,val2,val3);
return val2;
}
static void newsort(pfc::sort_callback & p_callback,t_size const p_base,t_size const p_count) {
if (p_count <= 4) {
squaresort(p_callback,p_base,p_count);
return;
}
t_size pivot = __pivot_helper(p_callback,p_base,p_count);
{
const t_size target = p_base + p_count - 1;
if (pivot != target) {
p_callback.swap(pivot,target); pivot = target;
}
}
t_size partition = p_base;
{
bool asdf = false;
for(t_size walk = p_base; walk < pivot; ++walk) {
const int comp = p_callback.compare(walk,pivot);
bool trigger = false;
if (comp == 0) {
trigger = asdf;
asdf = !asdf;
} else if (comp < 0) {
trigger = true;
}
if (trigger) {
if (partition != walk) p_callback.swap(partition,walk);
partition++;
}
}
}
if (pivot != partition) {
p_callback.swap(pivot,partition); pivot = partition;
}
newsort(p_callback,p_base,pivot-p_base);
newsort(p_callback,pivot+1,p_count-(pivot+1-p_base));
}
void sort(pfc::sort_callback & p_callback,t_size p_num) {
srand((unsigned int)(uniqueVal() ^ p_num));
newsort(p_callback,0,p_num);
}
void sort_void(void * base,t_size num,t_size width,int (*comp)(const void *, const void *) )
{
sort_void_ex(base,num,width,comp,swap_void);
}
sort_callback_stabilizer::sort_callback_stabilizer(sort_callback & p_chain,t_size p_count)
: m_chain(p_chain)
{
m_order.set_size(p_count);
t_size n;
for(n=0;n<p_count;n++) m_order[n] = n;
}
int sort_callback_stabilizer::compare(t_size p_index1, t_size p_index2) const
{
int ret = m_chain.compare(p_index1,p_index2);
if (ret == 0) ret = pfc::sgn_t((t_ssize)m_order[p_index1] - (t_ssize)m_order[p_index2]);
return ret;
}
void sort_callback_stabilizer::swap(t_size p_index1, t_size p_index2)
{
m_chain.swap(p_index1,p_index2);
pfc::swap_t(m_order[p_index1],m_order[p_index2]);
}
void sort_stable(sort_callback & p_callback,t_size p_count)
{
sort_callback_stabilizer cb(p_callback,p_count);
sort(cb,p_count);
}
}

192
pfc/sort.h Normal file
View File

@@ -0,0 +1,192 @@
#pragma once
namespace pfc {
void swap_void(void * item1,void * item2,t_size width);
void reorder_void(void * data,t_size width,const t_size * order,t_size num,void (*swapfunc)(void * item1,void * item2,t_size width) = swap_void);
class NOVTABLE reorder_callback
{
public:
virtual void swap(t_size p_index1,t_size p_index2) = 0;
};
void reorder(reorder_callback & p_callback,const t_size * p_order,t_size p_count);
template<typename t_container>
class reorder_callback_impl_t : public reorder_callback
{
public:
reorder_callback_impl_t(t_container & p_data) : m_data(p_data) {}
void swap(t_size p_index1,t_size p_index2)
{
pfc::swap_t(m_data[p_index1],m_data[p_index2]);
}
private:
t_container & m_data;
};
class reorder_callback_impl_delta : public reorder_callback
{
public:
reorder_callback_impl_delta(reorder_callback & p_data,t_size p_delta) : m_data(p_data), m_delta(p_delta) {}
void swap(t_size p_index1,t_size p_index2)
{
m_data.swap(p_index1+m_delta,p_index2+m_delta);
}
private:
reorder_callback & m_data;
t_size m_delta;
};
template<typename t_container>
void reorder_t(t_container & p_data,const t_size * p_order,t_size p_count)
{
reorder_callback_impl_t<t_container> cb(p_data);
reorder(cb,p_order,p_count);
}
template<typename t_container>
void reorder_partial_t(t_container & p_data,t_size p_base,const t_size * p_order,t_size p_count)
{
reorder_callback_impl_t<t_container> cb1(p_data);
reorder_callback_impl_delta cb2( cb1, p_base );
reorder(cb2,p_order,p_count);
// reorder(reorder_callback_impl_delta(reorder_callback_impl_t<t_container>(p_data),p_base),p_order,p_count);
}
template<typename T>
class reorder_callback_impl_ptr_t : public reorder_callback
{
public:
reorder_callback_impl_ptr_t(T * p_data) : m_data(p_data) {}
void swap(t_size p_index1,t_size p_index2)
{
pfc::swap_t(m_data[p_index1],m_data[p_index2]);
}
private:
T* m_data;
};
template<typename T>
void reorder_ptr_t(T* p_data,const t_size * p_order,t_size p_count)
{
reorder_callback_impl_ptr_t<T> cb(p_data);
reorder(cb,p_order,p_count);
}
class NOVTABLE sort_callback
{
public:
virtual int compare(t_size p_index1, t_size p_index2) const = 0;
virtual void swap(t_size p_index1, t_size p_index2) = 0;
void swap_check(t_size p_index1, t_size p_index2) {if (compare(p_index1,p_index2) > 0) swap(p_index1,p_index2);}
};
class sort_callback_stabilizer : public sort_callback
{
public:
sort_callback_stabilizer(sort_callback & p_chain,t_size p_count);
virtual int compare(t_size p_index1, t_size p_index2) const;
virtual void swap(t_size p_index1, t_size p_index2);
private:
sort_callback & m_chain;
array_t<t_size> m_order;
};
void sort(sort_callback & p_callback,t_size p_count);
void sort_stable(sort_callback & p_callback,t_size p_count);
void sort_void_ex(void *base,t_size num,t_size width, int (*comp)(const void *, const void *),void (*swap)(void *, void *, t_size) );
void sort_void(void * base,t_size num,t_size width,int (*comp)(const void *, const void *) );
template<typename t_container,typename t_compare>
class sort_callback_impl_simple_wrap_t : public sort_callback
{
public:
sort_callback_impl_simple_wrap_t(t_container & p_data, t_compare p_compare) : m_data(p_data), m_compare(p_compare) {}
int compare(t_size p_index1, t_size p_index2) const
{
return m_compare(m_data[p_index1],m_data[p_index2]);
}
void swap(t_size p_index1, t_size p_index2)
{
swap_t(m_data[p_index1],m_data[p_index2]);
}
private:
t_container & m_data;
t_compare m_compare;
};
template<typename t_container>
class sort_callback_impl_auto_wrap_t : public sort_callback
{
public:
sort_callback_impl_auto_wrap_t(t_container & p_data) : m_data(p_data) {}
int compare(t_size p_index1, t_size p_index2) const
{
return compare_t(m_data[p_index1],m_data[p_index2]);
}
void swap(t_size p_index1, t_size p_index2)
{
swap_t(m_data[p_index1],m_data[p_index2]);
}
private:
t_container & m_data;
};
template<typename t_container,typename t_compare,typename t_permutation>
class sort_callback_impl_permutation_wrap_t : public sort_callback
{
public:
sort_callback_impl_permutation_wrap_t(const t_container & p_data, t_compare p_compare,t_permutation const & p_permutation) : m_data(p_data), m_compare(p_compare), m_permutation(p_permutation) {}
int compare(t_size p_index1, t_size p_index2) const
{
return m_compare(m_data[m_permutation[p_index1]],m_data[m_permutation[p_index2]]);
}
void swap(t_size p_index1, t_size p_index2)
{
swap_t(m_permutation[p_index1],m_permutation[p_index2]);
}
private:
const t_container & m_data;
t_compare m_compare;
t_permutation const & m_permutation;
};
template<typename t_container,typename t_compare>
static void sort_t(t_container & p_data,t_compare p_compare,t_size p_count)
{
sort_callback_impl_simple_wrap_t<t_container,t_compare> cb(p_data,p_compare);
sort(cb,p_count);
}
template<typename t_container,typename t_compare>
static void sort_stable_t(t_container & p_data,t_compare p_compare,t_size p_count)
{
sort_callback_impl_simple_wrap_t<t_container,t_compare> cb(p_data,p_compare);
sort_stable(cb,p_count);
}
template<typename t_container,typename t_compare,typename t_permutation>
static void sort_get_permutation_t(const t_container & p_data,t_compare p_compare,t_size p_count,t_permutation const & p_permutation)
{
sort_callback_impl_permutation_wrap_t<t_container,t_compare,t_permutation> cb(p_data,p_compare,p_permutation);
sort(cb,p_count);
}
template<typename t_container,typename t_compare,typename t_permutation>
static void sort_stable_get_permutation_t(const t_container & p_data,t_compare p_compare,t_size p_count,t_permutation const & p_permutation)
{
sort_callback_impl_permutation_wrap_t<t_container,t_compare,t_permutation> cb(p_data,p_compare,p_permutation);
sort_stable(cb,p_count);
}
}

3
pfc/splitString.h Normal file
View File

@@ -0,0 +1,3 @@
#pragma once
// added for compatibility with fb2k mobile

2
pfc/stdafx.cpp Normal file
View File

@@ -0,0 +1,2 @@
//cpp used to generate precompiled header
#include "pfc.h"

28
pfc/stdsort.h Normal file
View File

@@ -0,0 +1,28 @@
#pragma once
// OPTIONAL pfc feature, include on need to use basis
// std sort interop methods
#include <algorithm>
#include <functional>
#include <vector>
namespace pfc {
std::vector<size_t> sort_identity( size_t count ) {
std::vector<size_t> ret; ret.resize(count);
for( size_t walk = 0; walk < ret.size(); ++ walk) ret[walk] = walk;
return ret;
}
template<typename iterator_t, typename predicate_t>
std::vector<size_t> sort_get_order(iterator_t i1, iterator_t i2, predicate_t pred ) {
auto ret = sort_identity( i2 - i1 );
auto pred2 = [pred, i1] (size_t idx1, size_t idx2) {
return pred( *(i1+idx1), *(i1+idx2));
};
std::sort(ret.begin(), ret.end(), pred2);
return ret;
}
}

119
pfc/string8_impl.h Normal file
View File

@@ -0,0 +1,119 @@
#pragma once
namespace pfc {
template<template<typename> class t_alloc>
void string8_t<t_alloc>::add_string(const char * ptr,t_size len)
{
if (m_data.is_owned(ptr)) {
add_string(string8(ptr,len));
} else {
len = strlen_max(ptr,len);
add_string_nc(ptr, len);
}
}
template<template<typename> class t_alloc>
void string8_t<t_alloc>::set_string(const char * ptr,t_size len) {
if (m_data.is_owned(ptr)) {
set_string_(string8(ptr,len));
} else {
len = strlen_max(ptr,len);
set_string_nc(ptr, len);
}
}
template<template<typename> class t_alloc>
void string8_t<t_alloc>::set_char(unsigned offset,char c)
{
if (!c) truncate(offset);
else if (offset<used) m_data[offset]=c;
}
template<template<typename> class t_alloc>
void string8_t<t_alloc>::fix_filename_chars(char def,char leave)//replace "bad" characters, leave parameter can be used to keep eg. path separators
{
t_size n;
for(n=0;n<used;n++)
if (m_data[n]!=leave && pfc::is_path_bad_char(m_data[n])) m_data[n]=def;
}
template<template<typename> class t_alloc>
void string8_t<t_alloc>::remove_chars(t_size first,t_size count)
{
if (first>used) first = used;
if (first+count>used) count = used-first;
if (count>0)
{
t_size n;
for(n=first+count;n<=used;n++)
m_data[n-count]=m_data[n];
used -= count;
makespace(used+1);
}
}
template<template<typename> class t_alloc>
void string8_t<t_alloc>::insert_chars(t_size first,const char * src, t_size count)
{
if (first > used) first = used;
makespace(used+count+1);
t_size n;
for(n=used;(int)n>=(int)first;n--)
m_data[n+count] = m_data[n];
for(n=0;n<count;n++)
m_data[first+n] = src[n];
used+=count;
}
template<template<typename> class t_alloc>
void string8_t<t_alloc>::insert_chars(t_size first,const char * src) {insert_chars(first,src,strlen(src));}
template<template<typename> class t_alloc>
t_size string8_t<t_alloc>::replace_nontext_chars(char p_replace)
{
t_size ret = 0;
for(t_size n=0;n<used;n++)
{
if ((unsigned char)m_data[n] < 32) {m_data[n] = p_replace; ret++; }
}
return ret;
}
template<template<typename> class t_alloc>
t_size string8_t<t_alloc>::replace_byte(char c1,char c2,t_size start)
{
PFC_ASSERT(c1 != 0); PFC_ASSERT(c2 != 0);
t_size n, ret = 0;
for(n=start;n<used;n++)
{
if (m_data[n] == c1) {m_data[n] = c2; ret++;}
}
return ret;
}
template<template<typename> class t_alloc>
t_size string8_t<t_alloc>::replace_char(unsigned c1,unsigned c2,t_size start)
{
if (c1 < 128 && c2 < 128) return replace_byte((char)c1,(char)c2,start);
string8 temp(get_ptr()+start);
truncate(start);
const char * ptr = temp;
t_size rv = 0;
while(*ptr)
{
unsigned test;
t_size delta = utf8_decode_char(ptr,test);
if (delta==0 || test==0) break;
if (test == c1) {test = c2;rv++;}
add_char(test);
ptr += delta;
}
return rv;
}
}

82
pfc/stringNew.cpp Normal file
View File

@@ -0,0 +1,82 @@
#include "pfc.h"
namespace pfc {
t_size string::indexOf(char c,t_size base) const {
return pfc::string_find_first(ptr(),c,base);
}
t_size string::lastIndexOf(char c,t_size base) const {
return pfc::string_find_last(ptr(),c,base);
}
t_size string::indexOf(stringp s,t_size base) const {
return pfc::string_find_first(ptr(),s.ptr(),base);
}
t_size string::lastIndexOf(stringp s,t_size base) const {
return pfc::string_find_last(ptr(),s.ptr(),base);
}
t_size string::indexOfAnyChar(stringp _s,t_size base) const {
string s ( _s );
const t_size len = length();
const char* content = ptr();
for(t_size walk = 0; walk < len; ++walk) {
if (s.contains(content[walk])) return walk;
}
return ~0;
}
t_size string::lastIndexOfAnyChar(stringp _s,t_size base) const {
string s ( _s );
const char* content = ptr();
for(t_size _walk = length(); _walk > 0; --_walk) {
const t_size walk = _walk-1;
if (s.contains(content[walk])) return walk;
}
return ~0;
}
bool string::startsWith(char c) const {
return (*this)[0] == c;
}
bool string::startsWith(string s) const {
const char * walk = ptr();
const char * subWalk = s.ptr();
for(;;) {
if (*subWalk == 0) return true;
if (*walk != *subWalk) return false;
walk++; subWalk++;
}
}
bool string::endsWith(char c) const {
const t_size len = length();
if (len == 0) return false;
return ptr()[len-1] == c;
}
bool string::endsWith(string s) const {
const t_size len = length(), subLen = s.length();
if (subLen > len) return false;
return subString(len - subLen) == s;
}
char string::firstChar() const {
return (*this)[0];
}
char string::lastChar() const {
const t_size len = length();
return len > 0 ? (*this)[len-1] : (char)0;
}
string string::replace(stringp strOld, stringp strNew) const {
t_size walk = 0;
string ret;
for(;;) {
t_size next = indexOf(strOld, walk);
if (next == ~0) {
ret += subString(walk); break;
}
ret += subString(walk,next-walk) + strNew;
walk = next + strOld.length();
}
return ret;
}
bool string::contains(char c) const {return indexOf(c) != ~0;}
bool string::contains(stringp s) const {return indexOf(s) != ~0;}
bool string::containsAnyChar(stringp s) const {return indexOfAnyChar(s) != ~0;}
}

262
pfc/stringNew.h Normal file
View File

@@ -0,0 +1,262 @@
#pragma once
namespace pfc {
//helper, const methods only
class _stringEmpty : public string_base {
public:
const char * get_ptr() const {return "";}
void add_string(const char * ,t_size) {throw exception_not_implemented();}
void set_string(const char * ,t_size) {throw exception_not_implemented();}
void truncate(t_size) {throw exception_not_implemented();}
t_size get_length() const {return 0;}
char * lock_buffer(t_size) {throw exception_not_implemented();}
void unlock_buffer() {throw exception_not_implemented();}
};
class stringp;
//! New EXPERIMENTAL string class, allowing efficient copies and returning from functions. \n
//! Does not implement the string_base interface so you still need string8 in many cases. \n
//! Safe to pass between DLLs, but since a reference is used, objects possibly created by other DLLs must be released before owning DLLs are unloaded.
class string {
public:
typedef rcptr_t<string_base const> t_data;
typedef rcptr_t<string8> t_dataImpl;
string() : m_content(rcnew_t<_stringEmpty>()) {}
string(const char * p_source) : m_content(rcnew_t<string8>(p_source)) {}
string(const char * p_source, t_size p_sourceLen) : m_content(rcnew_t<string8>(p_source,p_sourceLen)) {}
string(char * p_source) : m_content(rcnew_t<string8>(p_source)) {}
string(char * p_source, t_size p_sourceLen) : m_content(rcnew_t<string8>(p_source,p_sourceLen)) {}
string(t_data const & p_source) : m_content(p_source) {}
string(string_part_ref source) : m_content(rcnew_t<string8>(source)) {}
template<typename TSource> string(const TSource & p_source);
string(const string& other) : m_content(other.m_content) {}
string(string&& other) : m_content(std::move(other.m_content)) {}
const string& operator=(const string& other) {m_content = other.m_content; return *this;}
const string& operator=(string&& other) {m_content = std::move(other.m_content); return *this;}
string const & toString() const {return *this;}
//warning, not length-checked anymore!
static string g_concatenateRaw(const char * item1, t_size len1, const char * item2, t_size len2) {
t_dataImpl impl; impl.new_t();
char * buffer = impl->lock_buffer(len1+len2);
memcpy_t(buffer,item1,len1);
memcpy_t(buffer+len1,item2,len2);
impl->unlock_buffer();
return string(t_data(impl));
}
string operator+(const string& p_item2) const {
return g_concatenateRaw(ptr(),length(),p_item2.ptr(),p_item2.length());
}
string operator+(const char * p_item2) const {
return g_concatenateRaw(ptr(),length(),p_item2,strlen(p_item2));
}
template<typename TSource> string operator+(const TSource & p_item2) const;
template<typename TSource>
const string & operator+=(const TSource & p_item) {
*this = *this + p_item;
return *this;
}
string subString(t_size base) const {
if (base > length()) throw exception_overflow();
return string(ptr() + base);
}
string subString(t_size base, t_size count) const {
return string(ptr() + base,count);
}
string toLower() const {
string8_fastalloc temp; temp.prealloc(128);
stringToLowerAppend(temp,ptr(),SIZE_MAX);
return string(temp.get_ptr());
}
string toUpper() const {
string8_fastalloc temp; temp.prealloc(128);
stringToUpperAppend(temp,ptr(),SIZE_MAX);
return string(temp.get_ptr());
}
string clone() const {return string(ptr());}
//! @returns ~0 if not found.
t_size indexOf(char c,t_size base = 0) const;
//! @returns ~0 if not found.
t_size lastIndexOf(char c,t_size base = SIZE_MAX) const;
//! @returns ~0 if not found.
t_size indexOf(stringp s,t_size base = 0) const;
//! @returns ~0 if not found.
t_size lastIndexOf(stringp s,t_size base = SIZE_MAX) const;
//! @returns ~0 if not found.
t_size indexOfAnyChar(stringp s,t_size base = 0) const;
//! @returns ~0 if not found.
t_size lastIndexOfAnyChar(stringp s,t_size base = SIZE_MAX) const;
bool contains(char c) const;
bool contains(stringp s) const;
bool containsAnyChar(stringp s) const;
bool startsWith(char c) const;
bool startsWith(string s) const;
bool endsWith(char c) const;
bool endsWith(string s) const;
char firstChar() const;
char lastChar() const;
string replace(stringp strOld, stringp strNew) const;
static int g_compare(const string & p_item1, const string & p_item2) {return strcmp(p_item1.ptr(),p_item2.ptr());}
bool operator==(const string& p_other) const {return g_compare(*this,p_other) == 0;}
bool operator!=(const string& p_other) const {return g_compare(*this,p_other) != 0;}
bool operator<(const string& p_other) const {return g_compare(*this,p_other) < 0;}
bool operator>(const string& p_other) const {return g_compare(*this,p_other) > 0;}
bool operator<=(const string& p_other) const {return g_compare(*this,p_other) <= 0;}
bool operator>=(const string& p_other) const {return g_compare(*this,p_other) >= 0;}
const char * ptr() const {return m_content->get_ptr();}
const char * get_ptr() const {return m_content->get_ptr();}
const char * c_str() const { return get_ptr(); }
t_size length() const {return m_content->get_length();}
t_size get_length() const {return m_content->get_length();}
void set_string(const char * ptr, t_size len = SIZE_MAX) {
*this = string(ptr, len);
}
static bool isNonTextChar(char c) {return c >= 0 && c < 32;}
char operator[](t_size p_index) const {
PFC_ASSERT(p_index <= length());
return ptr()[p_index];
}
bool isEmpty() const {return length() == 0;}
class _comparatorCommon {
protected:
template<typename T> static const char * myStringToPtr(const T& val) {return stringToPtr(val);}
static const char * myStringToPtr(string_part_ref) {
PFC_ASSERT(!"Should never get here"); throw exception_invalid_params();
}
};
class comparatorCaseSensitive : private _comparatorCommon {
public:
template<typename T1,typename T2>
static int compare(T1 const& v1, T2 const& v2) {
if (is_same_type<T1, string_part_ref>::value || is_same_type<T2, string_part_ref>::value) {
return compare_ex(stringToRef(v1), stringToRef(v2));
} else {
return strcmp(myStringToPtr(v1),myStringToPtr(v2));
}
}
static int compare_ex(string_part_ref v1, string_part_ref v2) {
return strcmp_ex(v1.m_ptr, v1.m_len, v2.m_ptr, v2.m_len);
}
static int compare_ex(const char * v1, t_size l1, const char * v2, t_size l2) {
return strcmp_ex(v1, l1, v2, l2);
}
};
class comparatorCaseInsensitive : private _comparatorCommon {
public:
template<typename T1,typename T2>
static int compare(T1 const& v1, T2 const& v2) {
if (is_same_type<T1, string_part_ref>::value || is_same_type<T2, string_part_ref>::value) {
return stringCompareCaseInsensitiveEx(stringToRef(v1), stringToRef(v2));
} else {
return stringCompareCaseInsensitive(myStringToPtr(v1),myStringToPtr(v2));
}
}
};
class comparatorCaseInsensitiveASCII : private _comparatorCommon {
public:
template<typename T1,typename T2>
static int compare(T1 const& v1, T2 const& v2) {
if (is_same_type<T1, string_part_ref>::value || is_same_type<T2, string_part_ref>::value) {
return compare_ex(stringToRef(v1), stringToRef(v2));
} else {
return stricmp_ascii(myStringToPtr(v1),myStringToPtr(v2));
}
}
static int compare_ex(string_part_ref v1, string_part_ref v2) {
return stricmp_ascii_ex(v1.m_ptr, v1.m_len, v2.m_ptr, v2.m_len);
}
static int compare_ex(const char * v1, t_size l1, const char * v2, t_size l2) {
return stricmp_ascii_ex(v1, l1, v2, l2);
}
};
static bool g_equals(const string & p_item1, const string & p_item2) {return p_item1 == p_item2;}
static bool g_equalsCaseInsensitive(const string & p_item1, const string & p_item2) {return comparatorCaseInsensitive::compare(p_item1,p_item2) == 0;}
t_data _content() const {return m_content;}
private:
t_data m_content;
};
template<typename T> inline string toString(T const& val) {return val.toString();}
template<> inline string toString(t_int64 const& val) {return format_int(val).get_ptr();}
template<> inline string toString(t_int32 const& val) {return format_int(val).get_ptr();}
template<> inline string toString(t_int16 const& val) {return format_int(val).get_ptr();}
template<> inline string toString(t_uint64 const& val) {return format_uint(val).get_ptr();}
template<> inline string toString(t_uint32 const& val) {return format_uint(val).get_ptr();}
template<> inline string toString(t_uint16 const& val) {return format_uint(val).get_ptr();}
template<> inline string toString(float const& val) {return format_float(val).get_ptr();}
template<> inline string toString(double const& val) {return format_float(val).get_ptr();}
template<> inline string toString(char const& val) {return string(&val,1);}
inline const char * toString(std::exception const& val) {return val.what();}
template<typename TSource> string::string(const TSource & p_source) {
*this = pfc::toString(p_source);
}
template<typename TSource> string string::operator+(const TSource & p_item2) const {
return *this + pfc::toString(p_item2);
}
//! "String parameter" helper class, to use in function parameters, allowing functions to take any type of string as a parameter (const char*, string_base, string).
class stringp {
public:
stringp(const char * ptr) : m_ptr(ptr) {}
stringp(string const &s) : m_ptr(s.ptr()), m_s(s._content()) {}
stringp(string_base const &s) : m_ptr(s.get_ptr()) {}
template<typename TWhat> stringp(const TWhat& in) : m_ptr(in.toString()) {}
operator const char*() const {return m_ptr;}
const char * ptr() const {return m_ptr;}
const char * get_ptr() const {return m_ptr;}
string str() const {return m_s.is_valid() ? string(m_s) : string(m_ptr);}
operator string() const {return str();}
string toString() const {return str();}
t_size length() const {return m_s.is_valid() ? m_s->length() : strlen(m_ptr);}
const char * c_str() const { return ptr(); }
private:
const char * const m_ptr;
string::t_data m_s;
};
template<typename TList>
string stringCombineList(const TList & list, stringp separator) {
typename TList::const_iterator iter = list.first();
string acc;
if (iter.is_valid()) {
acc = *iter;
for(++iter; iter.is_valid(); ++iter) {
acc = acc + separator + *iter;
}
}
return acc;
}
class string;
template<> class traits_t<string> : public traits_default {};
}

1367
pfc/string_base.cpp Normal file

File diff suppressed because it is too large Load Diff

1112
pfc/string_base.h Normal file

File diff suppressed because it is too large Load Diff

499
pfc/string_conv.cpp Normal file
View File

@@ -0,0 +1,499 @@
#include "pfc.h"
namespace {
template<typename t_char, bool isChecked = true>
class string_writer_t {
public:
string_writer_t(t_char * p_buffer,t_size p_size) : m_buffer(p_buffer), m_size(p_size), m_writeptr(0) {}
void write(t_char p_char) {
if (isChecked) {
if (m_writeptr < m_size) {
m_buffer[m_writeptr++] = p_char;
}
} else {
m_buffer[m_writeptr++] = p_char;
}
}
void write_multi(const t_char * p_buffer,t_size p_count) {
if (isChecked) {
const t_size delta = pfc::min_t<t_size>(p_count,m_size-m_writeptr);
for(t_size n=0;n<delta;n++) {
m_buffer[m_writeptr++] = p_buffer[n];
}
} else {
for(t_size n = 0; n < p_count; ++n) {
m_buffer[m_writeptr++] = p_buffer[n];
}
}
}
void write_as_utf8(unsigned p_char) {
if (isChecked) {
char temp[6];
t_size n = pfc::utf8_encode_char(p_char,temp);
write_multi(temp,n);
} else {
m_writeptr += pfc::utf8_encode_char(p_char, m_buffer + m_writeptr);
}
}
void write_as_wide(unsigned p_char) {
if (isChecked) {
wchar_t temp[2];
t_size n = pfc::wide_encode_char(p_char,temp);
write_multi(temp,n);
} else {
m_writeptr += pfc::wide_encode_char(p_char, m_buffer + m_writeptr);
}
}
t_size finalize() {
if (isChecked) {
if (m_size == 0) return 0;
t_size terminator = pfc::min_t<t_size>(m_writeptr,m_size-1);
m_buffer[terminator] = 0;
return terminator;
} else {
m_buffer[m_writeptr] = 0;
return m_writeptr;
}
}
bool is_overrun() const {
return m_writeptr >= m_size;
}
private:
t_char * m_buffer;
t_size m_size;
t_size m_writeptr;
};
static const uint16_t mappings1252[] = {
/*0x80*/ 0x20AC, // #EURO SIGN
/*0x81*/ 0, // #UNDEFINED
/*0x82*/ 0x201A, // #SINGLE LOW-9 QUOTATION MARK
/*0x83*/ 0x0192, // #LATIN SMALL LETTER F WITH HOOK
/*0x84*/ 0x201E, // #DOUBLE LOW-9 QUOTATION MARK
/*0x85*/ 0x2026, // #HORIZONTAL ELLIPSIS
/*0x86*/ 0x2020, // #DAGGER
/*0x87*/ 0x2021, // #DOUBLE DAGGER
/*0x88*/ 0x02C6, // #MODIFIER LETTER CIRCUMFLEX ACCENT
/*0x89*/ 0x2030, // #PER MILLE SIGN
/*0x8A*/ 0x0160, // #LATIN CAPITAL LETTER S WITH CARON
/*0x8B*/ 0x2039, // #SINGLE LEFT-POINTING ANGLE QUOTATION MARK
/*0x8C*/ 0x0152, // #LATIN CAPITAL LIGATURE OE
/*0x8D*/ 0, // #UNDEFINED
/*0x8E*/ 0x017D, // #LATIN CAPITAL LETTER Z WITH CARON
/*0x8F*/ 0, // #UNDEFINED
/*0x90*/ 0, // #UNDEFINED
/*0x91*/ 0x2018, // #LEFT SINGLE QUOTATION MARK
/*0x92*/ 0x2019, // #RIGHT SINGLE QUOTATION MARK
/*0x93*/ 0x201C, // #LEFT DOUBLE QUOTATION MARK
/*0x94*/ 0x201D, // #RIGHT DOUBLE QUOTATION MARK
/*0x95*/ 0x2022, // #BULLET
/*0x96*/ 0x2013, // #EN DASH
/*0x97*/ 0x2014, // #EM DASH
/*0x98*/ 0x02DC, // #SMALL TILDE
/*0x99*/ 0x2122, // #TRADE MARK SIGN
/*0x9A*/ 0x0161, // #LATIN SMALL LETTER S WITH CARON
/*0x9B*/ 0x203A, // #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
/*0x9C*/ 0x0153, // #LATIN SMALL LIGATURE OE
/*0x9D*/ 0, // #UNDEFINED
/*0x9E*/ 0x017E, // #LATIN SMALL LETTER Z WITH CARON
/*0x9F*/ 0x0178, // #LATIN CAPITAL LETTER Y WITH DIAERESIS
};
static bool charImport1252(uint32_t & unichar, char c) {
uint8_t uc = (uint8_t) c;
if (uc == 0) return false;
else if (uc < 0x80) {unichar = uc; return true;}
else if (uc < 0xA0) {
uint32_t t = mappings1252[uc-0x80];
if (t == 0) return false;
unichar = t; return true;
} else {
unichar = uc; return true;
}
}
static bool charExport1252(char & c, uint32_t unichar) {
if (unichar == 0) return false;
else if (unichar < 0x80 || (unichar >= 0xa0 && unichar <= 0xFF)) {c = (char)(uint8_t)unichar; return true;}
for(size_t walk = 0; walk < PFC_TABSIZE(mappings1252); ++walk) {
if (unichar == mappings1252[walk]) {
c = (char)(uint8_t)(walk + 0x80);
return true;
}
}
return false;
}
struct asciiMap_t {uint16_t from; uint8_t to;};
static const asciiMap_t g_asciiMap[] = {
{160,32},{161,33},{162,99},{164,36},{165,89},{166,124},{169,67},{170,97},{171,60},{173,45},{174,82},{178,50},{179,51},{183,46},{184,44},{185,49},{186,111},{187,62},{192,65},{193,65},{194,65},{195,65},{196,65},{197,65},{198,65},{199,67},{200,69},{201,69},{202,69},{203,69},{204,73},{205,73},{206,73},{207,73},{208,68},{209,78},{210,79},{211,79},{212,79},{213,79},{214,79},{216,79},{217,85},{218,85},{219,85},{220,85},{221,89},{224,97},{225,97},{226,97},{227,97},{228,97},{229,97},{230,97},{231,99},{232,101},{233,101},{234,101},{235,101},{236,105},{237,105},{238,105},{239,105},{241,110},{242,111},{243,111},{244,111},{245,111},{246,111},{248,111},{249,117},{250,117},{251,117},{252,117},{253,121},{255,121},{256,65},{257,97},{258,65},{259,97},{260,65},{261,97},{262,67},{263,99},{264,67},{265,99},{266,67},{267,99},{268,67},{269,99},{270,68},{271,100},{272,68},{273,100},{274,69},{275,101},{276,69},{277,101},{278,69},{279,101},{280,69},{281,101},{282,69},{283,101},{284,71},{285,103},{286,71},{287,103},{288,71},{289,103},{290,71},{291,103},{292,72},{293,104},{294,72},{295,104},{296,73},{297,105},{298,73},{299,105},{300,73},{301,105},{302,73},{303,105},{304,73},{305,105},{308,74},{309,106},{310,75},{311,107},{313,76},{314,108},{315,76},{316,108},{317,76},{318,108},{321,76},{322,108},{323,78},{324,110},{325,78},{326,110},{327,78},{328,110},{332,79},{333,111},{334,79},{335,111},{336,79},{337,111},{338,79},{339,111},{340,82},{341,114},{342,82},{343,114},{344,82},{345,114},{346,83},{347,115},{348,83},{349,115},{350,83},{351,115},{352,83},{353,115},{354,84},{355,116},{356,84},{357,116},{358,84},{359,116},{360,85},{361,117},{362,85},{363,117},{364,85},{365,117},{366,85},{367,117},{368,85},{369,117},{370,85},{371,117},{372,87},{373,119},{374,89},{375,121},{376,89},{377,90},{378,122},{379,90},{380,122},{381,90},{382,122},{384,98},{393,68},{401,70},{402,102},{407,73},{410,108},{415,79},{416,79},{417,111},{427,116},{430,84},{431,85},{432,117},{438,122},{461,65},{462,97},{463,73},{464,105},{465,79},{466,111},{467,85},{468,117},{469,85},{470,117},{471,85},{472,117},{473,85},{474,117},{475,85},{476,117},{478,65},{479,97},{484,71},{485,103},{486,71},{487,103},{488,75},{489,107},{490,79},{491,111},{492,79},{493,111},{496,106},{609,103},{697,39},{698,34},{700,39},{708,94},{710,94},{712,39},{715,96},{717,95},{732,126},{768,96},{770,94},{771,126},{782,34},{817,95},{818,95},{8192,32},{8193,32},{8194,32},{8195,32},{8196,32},{8197,32},{8198,32},{8208,45},{8209,45},{8211,45},{8212,45},{8216,39},{8217,39},{8218,44},{8220,34},{8221,34},{8222,34},{8226,46},{8230,46},{8242,39},{8245,96},{8249,60},{8250,62},{8482,84},{65281,33},{65282,34},{65283,35},{65284,36},{65285,37},{65286,38},{65287,39},{65288,40},{65289,41},{65290,42},{65291,43},{65292,44},{65293,45},{65294,46},{65295,47},{65296,48},{65297,49},{65298,50},{65299,51},{65300,52},{65301,53},{65302,54},{65303,55},{65304,56},{65305,57},{65306,58},{65307,59},{65308,60},{65309,61},{65310,62},{65312,64},{65313,65},{65314,66},{65315,67},{65316,68},{65317,69},{65318,70},{65319,71},{65320,72},{65321,73},{65322,74},{65323,75},{65324,76},{65325,77},{65326,78},{65327,79},{65328,80},{65329,81},{65330,82},{65331,83},{65332,84},{65333,85},{65334,86},{65335,87},{65336,88},{65337,89},{65338,90},{65339,91},{65340,92},{65341,93},{65342,94},{65343,95},{65344,96},{65345,97},{65346,98},{65347,99},{65348,100},{65349,101},{65350,102},{65351,103},{65352,104},{65353,105},{65354,106},{65355,107},{65356,108},{65357,109},{65358,110},{65359,111},{65360,112},{65361,113},{65362,114},{65363,115},{65364,116},{65365,117},{65366,118},{65367,119},{65368,120},{65369,121},{65370,122},{65371,123},{65372,124},{65373,125},{65374,126}};
}
namespace pfc {
namespace stringcvt {
char charToASCII( unsigned c ) {
if (c < 128) return (char)c;
unsigned lo = 0, hi = PFC_TABSIZE(g_asciiMap);
while( lo < hi ) {
const unsigned mid = (lo + hi) / 2;
const asciiMap_t entry = g_asciiMap[mid];
if ( c > entry.from ) {
lo = mid + 1;
} else if (c < entry.from) {
hi = mid;
} else {
return (char)entry.to;
}
}
return '?';
}
t_size convert_utf8_to_wide(wchar_t * p_out,t_size p_out_size,const char * p_in,t_size p_in_size) {
const t_size insize = p_in_size;
t_size inptr = 0;
string_writer_t<wchar_t> writer(p_out,p_out_size);
while(inptr < insize && !writer.is_overrun()) {
unsigned newchar = 0;
t_size delta = utf8_decode_char(p_in + inptr,newchar,insize - inptr);
if (delta == 0 || newchar == 0) break;
PFC_ASSERT(inptr + delta <= insize);
inptr += delta;
writer.write_as_wide(newchar);
}
return writer.finalize();
}
t_size convert_utf8_to_wide_unchecked(wchar_t * p_out,const char * p_in) {
t_size inptr = 0;
string_writer_t<wchar_t,false> writer(p_out,~0);
while(!writer.is_overrun()) {
unsigned newchar = 0;
t_size delta = utf8_decode_char(p_in + inptr,newchar);
if (delta == 0 || newchar == 0) break;
inptr += delta;
writer.write_as_wide(newchar);
}
return writer.finalize();
}
t_size convert_wide_to_utf8(char * p_out,t_size p_out_size,const wchar_t * p_in,t_size p_in_size) {
const t_size insize = p_in_size;
t_size inptr = 0;
string_writer_t<char> writer(p_out,p_out_size);
while(inptr < insize && !writer.is_overrun()) {
unsigned newchar = 0;
t_size delta = wide_decode_char(p_in + inptr,&newchar,insize - inptr);
if (delta == 0 || newchar == 0) break;
PFC_ASSERT(inptr + delta <= insize);
inptr += delta;
writer.write_as_utf8(newchar);
}
return writer.finalize();
}
t_size estimate_utf8_to_wide(const char * p_in) {
t_size inptr = 0;
t_size retval = 1;//1 for null terminator
for(;;) {
unsigned newchar = 0;
t_size delta = utf8_decode_char(p_in + inptr,newchar);
if (delta == 0 || newchar == 0) break;
inptr += delta;
{
wchar_t temp[2];
retval += wide_encode_char(newchar,temp);
}
}
return retval;
}
t_size estimate_utf8_to_wide(const char * p_in,t_size p_in_size) {
const t_size insize = p_in_size;
t_size inptr = 0;
t_size retval = 1;//1 for null terminator
while(inptr < insize) {
unsigned newchar = 0;
t_size delta = utf8_decode_char(p_in + inptr,newchar,insize - inptr);
if (delta == 0 || newchar == 0) break;
PFC_ASSERT(inptr + delta <= insize);
inptr += delta;
{
wchar_t temp[2];
retval += wide_encode_char(newchar,temp);
}
}
return retval;
}
t_size estimate_wide_to_utf8(const wchar_t * p_in,t_size p_in_size) {
const t_size insize = p_in_size;
t_size inptr = 0;
t_size retval = 1;//1 for null terminator
while(inptr < insize) {
unsigned newchar = 0;
t_size delta = wide_decode_char(p_in + inptr,&newchar,insize - inptr);
if (delta == 0 || newchar == 0) break;
PFC_ASSERT(inptr + delta <= insize);
inptr += delta;
{
char temp[6];
delta = utf8_encode_char(newchar,temp);
if (delta == 0) break;
retval += delta;
}
}
return retval;
}
t_size estimate_wide_to_win1252( const wchar_t * p_in, t_size p_in_size ) {
const t_size insize = p_in_size;
t_size inptr = 0;
t_size retval = 1;//1 for null terminator
while(inptr < insize) {
unsigned newchar = 0;
t_size delta = wide_decode_char(p_in + inptr,&newchar,insize - inptr);
if (delta == 0 || newchar == 0) break;
PFC_ASSERT(inptr + delta <= insize);
inptr += delta;
++retval;
}
return retval;
}
t_size convert_wide_to_win1252( char * p_out, t_size p_out_size, const wchar_t * p_in, t_size p_in_size ) {
const t_size insize = p_in_size;
t_size inptr = 0;
string_writer_t<char> writer(p_out,p_out_size);
while(inptr < insize && !writer.is_overrun()) {
unsigned newchar = 0;
t_size delta = wide_decode_char(p_in + inptr,&newchar,insize - inptr);
if (delta == 0 || newchar == 0) break;
PFC_ASSERT(inptr + delta <= insize);
inptr += delta;
char temp;
if (!charExport1252( temp, newchar )) temp = '?';
writer.write( temp );
}
return writer.finalize();
}
t_size estimate_win1252_to_wide( const char * p_source, t_size p_source_size ) {
return strlen_max_t( p_source, p_source_size ) + 1;
}
t_size convert_win1252_to_wide( wchar_t * p_out, t_size p_out_size, const char * p_in, t_size p_in_size ) {
const t_size insize = p_in_size;
t_size inptr = 0;
string_writer_t<wchar_t> writer(p_out,p_out_size);
while(inptr < insize && !writer.is_overrun()) {
char inChar = p_in[inptr];
if (inChar == 0) break;
++inptr;
unsigned out;
if (!charImport1252( out , inChar )) out = '?';
writer.write_as_wide( out );
}
return writer.finalize();
}
t_size estimate_utf8_to_win1252( const char * p_in, t_size p_in_size ) {
const t_size insize = p_in_size;
t_size inptr = 0;
t_size retval = 1;//1 for null terminator
while(inptr < insize) {
unsigned newchar = 0;
t_size delta = utf8_decode_char(p_in + inptr,newchar,insize - inptr);
if (delta == 0 || newchar == 0) break;
PFC_ASSERT(inptr + delta <= insize);
inptr += delta;
++retval;
}
return retval;
}
t_size convert_utf8_to_win1252( char * p_out, t_size p_out_size, const char * p_in, t_size p_in_size ) {
const t_size insize = p_in_size;
t_size inptr = 0;
string_writer_t<char> writer(p_out,p_out_size);
while(inptr < insize && !writer.is_overrun()) {
unsigned newchar = 0;
t_size delta = utf8_decode_char(p_in + inptr,newchar,insize - inptr);
if (delta == 0 || newchar == 0) break;
PFC_ASSERT(inptr + delta <= insize);
inptr += delta;
char temp;
if (!charExport1252( temp, newchar )) temp = '?';
writer.write( temp );
}
return writer.finalize();
}
t_size estimate_win1252_to_utf8( const char * p_in, t_size p_in_size ) {
const size_t insize = p_in_size;
t_size inptr = 0;
t_size retval = 1; // 1 for null terminator
while(inptr < insize) {
unsigned newchar;
char c = p_in[inptr];
if (c == 0) break;
++inptr;
if (!charImport1252( newchar, c)) newchar = '?';
char temp[6];
retval += pfc::utf8_encode_char( newchar, temp );
}
return retval;
}
t_size convert_win1252_to_utf8( char * p_out, t_size p_out_size, const char * p_in, t_size p_in_size ) {
const t_size insize = p_in_size;
t_size inptr = 0;
string_writer_t<char> writer(p_out,p_out_size);
while(inptr < insize && !writer.is_overrun()) {
char inChar = p_in[inptr];
if (inChar == 0) break;
++inptr;
unsigned out;
if (!charImport1252( out , inChar )) out = '?';
writer.write_as_utf8( out );
}
return writer.finalize();
}
t_size estimate_utf8_to_ascii( const char * p_source, t_size p_source_size ) {
return estimate_utf8_to_win1252( p_source, p_source_size );
}
t_size convert_utf8_to_ascii( char * p_out, t_size p_out_size, const char * p_in, t_size p_in_size ) {
const t_size insize = p_in_size;
t_size inptr = 0;
string_writer_t<char> writer(p_out,p_out_size);
while(inptr < insize && !writer.is_overrun()) {
unsigned newchar = 0;
t_size delta = utf8_decode_char(p_in + inptr,newchar,insize - inptr);
if (delta == 0 || newchar == 0) break;
PFC_ASSERT(inptr + delta <= insize);
inptr += delta;
writer.write( charToASCII(newchar) );
}
return writer.finalize();
}
// 2016-05-16 additions
// Explicit UTF-16 converters
t_size estimate_utf16_to_utf8( const char16_t * p_in, size_t p_in_size ) {
const t_size insize = p_in_size;
t_size inptr = 0;
t_size retval = 1;//1 for null terminator
while(inptr < insize) {
unsigned newchar = 0;
t_size delta = utf16_decode_char(p_in + inptr,&newchar,insize - inptr);
if (delta == 0 || newchar == 0) break;
PFC_ASSERT(inptr + delta <= insize);
inptr += delta;
{
char temp[6];
delta = utf8_encode_char(newchar,temp);
if (delta == 0) break;
retval += delta;
}
}
return retval;
}
t_size convert_utf16_to_utf8( char * p_out, size_t p_out_size, const char16_t * p_in, size_t p_in_size ) {
const t_size insize = p_in_size;
t_size inptr = 0;
string_writer_t<char> writer(p_out,p_out_size);
while(inptr < insize && !writer.is_overrun()) {
unsigned newchar = 0;
t_size delta = utf16_decode_char(p_in + inptr,&newchar,insize - inptr);
if (delta == 0 || newchar == 0) break;
PFC_ASSERT(inptr + delta <= insize);
inptr += delta;
writer.write_as_utf8(newchar);
}
return writer.finalize();
}
}
}
#ifdef _WINDOWS
namespace pfc {
namespace stringcvt {
t_size convert_codepage_to_wide(unsigned p_codepage,wchar_t * p_out,t_size p_out_size,const char * p_source,t_size p_source_size) {
if (p_out_size == 0) return 0;
memset(p_out,0,p_out_size * sizeof(*p_out));
MultiByteToWideChar(p_codepage,0,p_source, pfc::downcast_guarded<int>(p_source_size),p_out, pfc::downcast_guarded<int>(p_out_size));
p_out[p_out_size-1] = 0;
return wcslen(p_out);
}
t_size convert_wide_to_codepage(unsigned p_codepage,char * p_out,t_size p_out_size,const wchar_t * p_source,t_size p_source_size) {
if (p_out_size == 0) return 0;
memset(p_out,0,p_out_size * sizeof(*p_out));
WideCharToMultiByte(p_codepage,0,p_source,pfc::downcast_guarded<int>(p_source_size),p_out,pfc::downcast_guarded<int>(p_out_size),0,FALSE);
p_out[p_out_size-1] = 0;
return strlen(p_out);
}
t_size estimate_codepage_to_wide(unsigned p_codepage,const char * p_source,t_size p_source_size) {
return MultiByteToWideChar(p_codepage,0,p_source, pfc::downcast_guarded<int>(strlen_max(p_source,p_source_size)),0,0) + 1;
}
t_size estimate_wide_to_codepage(unsigned p_codepage,const wchar_t * p_source,t_size p_source_size) {
return WideCharToMultiByte(p_codepage,0,p_source, pfc::downcast_guarded<int>(wcslen_max(p_source,p_source_size)),0,0,0,FALSE) + 1;
}
}
}
#endif //_WINDOWS
pfc::string_base & operator<<(pfc::string_base & p_fmt, const wchar_t * p_str) {
p_fmt.add_string(pfc::stringcvt::string_utf8_from_wide(p_str) ); return p_fmt;
}

584
pfc/string_conv.h Normal file
View File

@@ -0,0 +1,584 @@
#pragma once
namespace pfc {
namespace stringcvt {
//! Converts UTF-8 characters to wide character.
//! @param p_out Output buffer, receives converted string, with null terminator.
//! @param p_out_size Size of output buffer, in characters. If converted string is too long, it will be truncated. Null terminator is always written, unless p_out_size is zero.
//! @param p_source String to convert.
//! @param p_source_size Number of characters to read from p_source. If reading stops if null terminator is encountered earlier.
//! @returns Number of characters written, not counting null terminator.
t_size convert_utf8_to_wide(wchar_t * p_out,t_size p_out_size,const char * p_source,t_size p_source_size);
//! Estimates buffer size required to convert specified UTF-8 string to widechar.
//! @param p_source String to be converted.
//! @param p_source_size Number of characters to read from p_source. If reading stops if null terminator is encountered earlier.
//! @returns Number of characters to allocate, including space for null terminator.
t_size estimate_utf8_to_wide(const char * p_source,t_size p_source_size);
t_size estimate_utf8_to_wide(const char * p_source);
//! Converts wide character string to UTF-8.
//! @param p_out Output buffer, receives converted string, with null terminator.
//! @param p_out_size Size of output buffer, in characters. If converted string is too long, it will be truncated. Null terminator is always written, unless p_out_size is zero.
//! @param p_source String to convert.
//! @param p_source_size Number of characters to read from p_source. If reading stops if null terminator is encountered earlier.
//! @returns Number of characters written, not counting null terminator.
t_size convert_wide_to_utf8(char * p_out,t_size p_out_size,const wchar_t * p_source,t_size p_source_size);
//! Estimates buffer size required to convert specified wide character string to UTF-8.
//! @param p_source String to be converted.
//! @param p_source_size Number of characters to read from p_source. If reading stops if null terminator is encountered earlier.
//! @returns Number of characters to allocate, including space for null terminator.
t_size estimate_wide_to_utf8(const wchar_t * p_source,t_size p_source_size);
t_size estimate_utf8_to_ascii( const char * p_source, t_size p_source_size );
t_size convert_utf8_to_ascii( char * p_out, t_size p_out_size, const char * p_source, t_size p_source_size );
t_size estimate_wide_to_win1252( const wchar_t * p_source, t_size p_source_size );
t_size convert_wide_to_win1252( char * p_out, t_size p_out_size, const wchar_t * p_source, t_size p_source_size );
t_size estimate_win1252_to_wide( const char * p_source, t_size p_source_size );
t_size convert_win1252_to_wide( wchar_t * p_out, t_size p_out_size, const char * p_source, t_size p_source_size );
t_size estimate_utf8_to_win1252( const char * p_source, t_size p_source_size );
t_size convert_utf8_to_win1252( char * p_out, t_size p_out_size, const char * p_source, t_size p_source_size );
t_size estimate_win1252_to_utf8( const char * p_source, t_size p_source_size );
t_size convert_win1252_to_utf8( char * p_out, t_size p_out_size, const char * p_source, t_size p_source_size );
// 2016-05-16 additions
// Explicit UTF-16 converters
t_size estimate_utf16_to_utf8( const char16_t * p_source, size_t p_source_size );
t_size convert_utf16_to_utf8( char * p_out, size_t p_out_size, const char16_t * p_source, size_t p_source_size );
//! estimate_utf8_to_wide_quick() functions use simple math to determine buffer size required for the conversion. The result is not accurate length of output string - it's just a safe estimate of required buffer size, possibly bigger than what's really needed. \n
//! These functions are meant for scenarios when speed is more important than memory usage.
inline t_size estimate_utf8_to_wide_quick(t_size sourceLen) {
return sourceLen + 1;
}
inline t_size estimate_utf8_to_wide_quick(const char * source) {
return estimate_utf8_to_wide_quick(strlen(source));
}
inline t_size estimate_utf8_to_wide_quick(const char * source, t_size sourceLen) {
return estimate_utf8_to_wide_quick(strlen_max(source, sourceLen));
}
t_size convert_utf8_to_wide_unchecked(wchar_t * p_out,const char * p_source);
template<typename t_char> const t_char * null_string_t();
template<> inline const char * null_string_t<char>() {return "";}
template<> inline const wchar_t * null_string_t<wchar_t>() {return L"";}
template<typename t_char> t_size strlen_t(const t_char * p_string,t_size p_string_size = ~0) {
for(t_size n=0;n<p_string_size;n++) {
if (p_string[n] == 0) return n;
}
return p_string_size;
}
template<typename t_char> bool string_is_empty_t(const t_char * p_string,t_size p_string_size = ~0) {
if (p_string_size == 0) return true;
return p_string[0] == 0;
}
template<typename t_char,template<typename t_allocitem> class t_alloc = pfc::alloc_standard> class char_buffer_t {
public:
char_buffer_t() {}
char_buffer_t(const char_buffer_t & p_source) : m_buffer(p_source.m_buffer) {}
void set_size(t_size p_count) {m_buffer.set_size(p_count);}
t_char * get_ptr_var() {return m_buffer.get_ptr();}
const t_char * get_ptr() const {
return m_buffer.get_size() > 0 ? m_buffer.get_ptr() : null_string_t<t_char>();
}
private:
pfc::array_t<t_char,t_alloc> m_buffer;
};
template<template<typename t_allocitem> class t_alloc = pfc::alloc_standard>
class string_utf8_from_wide_t {
public:
string_utf8_from_wide_t() {}
string_utf8_from_wide_t(const wchar_t * p_source,t_size p_source_size = ~0) {convert(p_source,p_source_size);}
void convert(const wchar_t * p_source,t_size p_source_size = ~0) {
t_size size = estimate_wide_to_utf8(p_source,p_source_size);
m_buffer.set_size(size);
convert_wide_to_utf8( m_buffer.get_ptr_var(),size,p_source,p_source_size);
}
operator const char * () const {return get_ptr();}
const char * get_ptr() const {return m_buffer.get_ptr();}
const char * toString() const {return get_ptr();}
bool is_empty() const {return string_is_empty_t(get_ptr());}
t_size length() const {return strlen_t(get_ptr());}
private:
char_buffer_t<char,t_alloc> m_buffer;
};
typedef string_utf8_from_wide_t<> string_utf8_from_wide;
template<template<typename t_allocitem> class t_alloc = pfc::alloc_standard>
class string_wide_from_utf8_t {
public:
string_wide_from_utf8_t() {}
string_wide_from_utf8_t(const char* p_source) {convert(p_source);}
string_wide_from_utf8_t(const char* p_source,t_size p_source_size) {convert(p_source,p_source_size);}
void convert(const char* p_source,t_size p_source_size) {
const t_size size = estimate_size(p_source, p_source_size);
m_buffer.set_size(size);
convert_utf8_to_wide( m_buffer.get_ptr_var(),size,p_source,p_source_size );
}
void convert(const char * p_source) {
m_buffer.set_size( estimate_size(p_source) );
convert_utf8_to_wide_unchecked(m_buffer.get_ptr_var(), p_source);
}
operator const wchar_t * () const {return get_ptr();}
const wchar_t * get_ptr() const {return m_buffer.get_ptr();}
bool is_empty() const {return string_is_empty_t(get_ptr());}
t_size length() const {return strlen_t(get_ptr());}
void append(const char* p_source,t_size p_source_size) {
const t_size base = length();
const t_size size = estimate_size(p_source, p_source_size);
m_buffer.set_size(base + size);
convert_utf8_to_wide( m_buffer.get_ptr_var() + base, size, p_source, p_source_size );
}
void append(const char * p_source) {
const t_size base = length();
m_buffer.set_size( base + estimate_size(p_source) );
convert_utf8_to_wide_unchecked(m_buffer.get_ptr_var() + base, p_source);
}
enum { alloc_prioritizes_speed = t_alloc<wchar_t>::alloc_prioritizes_speed };
private:
inline t_size estimate_size(const char * source, t_size sourceLen) {
return alloc_prioritizes_speed ? estimate_utf8_to_wide_quick(source, sourceLen) : estimate_utf8_to_wide(source,sourceLen);
}
inline t_size estimate_size(const char * source) {
return alloc_prioritizes_speed ? estimate_utf8_to_wide_quick(source) : estimate_utf8_to_wide(source,~0);
}
char_buffer_t<wchar_t,t_alloc> m_buffer;
};
typedef string_wide_from_utf8_t<> string_wide_from_utf8;
typedef string_wide_from_utf8_t<alloc_fast_aggressive> string_wide_from_utf8_fast;
template<template<typename t_allocitem> class t_alloc = pfc::alloc_standard>
class string_wide_from_win1252_t {
public:
string_wide_from_win1252_t() {}
string_wide_from_win1252_t(const char * p_source,t_size p_source_size = ~0) {convert(p_source,p_source_size);}
void convert(const char * p_source,t_size p_source_size = ~0) {
t_size size = estimate_win1252_to_wide(p_source,p_source_size);
m_buffer.set_size(size);
convert_win1252_to_wide(m_buffer.get_ptr_var(),size,p_source,p_source_size);
}
operator const wchar_t * () const {return get_ptr();}
const wchar_t * get_ptr() const {return m_buffer.get_ptr();}
bool is_empty() const {return string_is_empty_t(get_ptr());}
t_size length() const {return strlen_t(get_ptr());}
private:
char_buffer_t<wchar_t,t_alloc> m_buffer;
};
typedef string_wide_from_win1252_t<> string_wide_from_win1252;
template<template<typename t_allocitem> class t_alloc = pfc::alloc_standard>
class string_win1252_from_wide_t {
public:
string_win1252_from_wide_t() {}
string_win1252_from_wide_t(const wchar_t * p_source,t_size p_source_size = ~0) {convert(p_source,p_source_size);}
void convert(const wchar_t * p_source,t_size p_source_size = ~0) {
t_size size = estimate_wide_to_win1252(p_source,p_source_size);
m_buffer.set_size(size);
convert_wide_to_win1252(m_buffer.get_ptr_var(),size,p_source,p_source_size);
}
operator const char * () const {return get_ptr();}
const char * get_ptr() const {return m_buffer.get_ptr();}
bool is_empty() const {return string_is_empty_t(get_ptr());}
t_size length() const {return strlen_t(get_ptr());}
private:
char_buffer_t<char,t_alloc> m_buffer;
};
typedef string_win1252_from_wide_t<> string_win1252_from_wide;
template<template<typename t_allocitem> class t_alloc = pfc::alloc_standard>
class string_utf8_from_win1252_t {
public:
string_utf8_from_win1252_t() {}
string_utf8_from_win1252_t(const char * p_source,t_size p_source_size = ~0) {convert(p_source,p_source_size);}
void convert(const char * p_source,t_size p_source_size = ~0) {
t_size size = estimate_win1252_to_utf8(p_source,p_source_size);
m_buffer.set_size(size);
convert_win1252_to_utf8(m_buffer.get_ptr_var(),size,p_source,p_source_size);
}
operator const char * () const {return get_ptr();}
const char * get_ptr() const {return m_buffer.get_ptr();}
bool is_empty() const {return string_is_empty_t(get_ptr());}
t_size length() const {return strlen_t(get_ptr());}
private:
char_buffer_t<char,t_alloc> m_buffer;
};
typedef string_utf8_from_win1252_t<> string_utf8_from_win1252;
template<template<typename t_allocitem> class t_alloc = pfc::alloc_standard>
class string_win1252_from_utf8_t {
public:
string_win1252_from_utf8_t() {}
string_win1252_from_utf8_t(const char * p_source,t_size p_source_size = ~0) {convert(p_source,p_source_size);}
void convert(const char * p_source,t_size p_source_size = ~0) {
t_size size = estimate_utf8_to_win1252(p_source,p_source_size);
m_buffer.set_size(size);
convert_utf8_to_win1252(m_buffer.get_ptr_var(),size,p_source,p_source_size);
}
operator const char * () const {return get_ptr();}
const char * get_ptr() const {return m_buffer.get_ptr();}
bool is_empty() const {return string_is_empty_t(get_ptr());}
t_size length() const {return strlen_t(get_ptr());}
private:
char_buffer_t<char,t_alloc> m_buffer;
};
typedef string_win1252_from_utf8_t<> string_win1252_from_utf8;
class string_ascii_from_utf8 {
public:
string_ascii_from_utf8() {}
string_ascii_from_utf8( const char * p_source, t_size p_source_size = ~0) { convert(p_source, p_source_size); }
void convert( const char * p_source, t_size p_source_size = ~0) {
t_size size = estimate_utf8_to_ascii(p_source, p_source_size);
m_buffer.set_size(size);
convert_utf8_to_ascii(m_buffer.get_ptr_var(), size, p_source, p_source_size);
}
operator const char * () const {return get_ptr();}
const char * get_ptr() const {return m_buffer.get_ptr();}
bool is_empty() const {return string_is_empty_t(get_ptr());}
t_size length() const {return strlen_t(get_ptr());}
private:
char_buffer_t<char, pfc::alloc_fast_aggressive> m_buffer;
};
class string_utf8_from_utf16 {
public:
string_utf8_from_utf16() {}
string_utf8_from_utf16( const char16_t * p_source, size_t p_source_size = ~0) {convert(p_source, p_source_size);}
void convert( const char16_t * p_source, size_t p_source_size = ~0) {
size_t size = estimate_utf16_to_utf8(p_source, p_source_size);
m_buffer.set_size(size);
convert_utf16_to_utf8(m_buffer.get_ptr_var(), size, p_source, p_source_size );
}
operator const char * () const {return get_ptr();}
const char * get_ptr() const {return m_buffer.get_ptr();}
bool is_empty() const {return string_is_empty_t(get_ptr());}
t_size length() const {return strlen_t(get_ptr());}
private:
char_buffer_t<char, pfc::alloc_fast_aggressive> m_buffer;
};
}
#ifdef _WINDOWS
namespace stringcvt {
enum {
codepage_system = CP_ACP,
codepage_ascii = 20127,
codepage_iso_8859_1 = 28591,
};
//! Converts string from specified codepage to wide character.
//! @param p_out Output buffer, receives converted string, with null terminator.
//! @param p_codepage Codepage ID of source string.
//! @param p_source String to convert.
//! @param p_source_size Number of characters to read from p_source. If reading stops if null terminator is encountered earlier.
//! @param p_out_size Size of output buffer, in characters. If converted string is too long, it will be truncated. Null terminator is always written, unless p_out_size is zero.
//! @returns Number of characters written, not counting null terminator.
t_size convert_codepage_to_wide(unsigned p_codepage,wchar_t * p_out,t_size p_out_size,const char * p_source,t_size p_source_size);
//! Estimates buffer size required to convert specified string from specified codepage to wide character.
//! @param p_codepage Codepage ID of source string.
//! @param p_source String to be converted.
//! @param p_source_size Number of characters to read from p_source. If reading stops if null terminator is encountered earlier.
//! @returns Number of characters to allocate, including space for null terminator.
t_size estimate_codepage_to_wide(unsigned p_codepage,const char * p_source,t_size p_source_size);
//! Converts string from wide character to specified codepage.
//! @param p_codepage Codepage ID of source string.
//! @param p_out Output buffer, receives converted string, with null terminator.
//! @param p_out_size Size of output buffer, in characters. If converted string is too long, it will be truncated. Null terminator is always written, unless p_out_size is zero.
//! @param p_source String to convert.
//! @param p_source_size Number of characters to read from p_source. If reading stops if null terminator is encountered earlier.
//! @returns Number of characters written, not counting null terminator.
t_size convert_wide_to_codepage(unsigned p_codepage,char * p_out,t_size p_out_size,const wchar_t * p_source,t_size p_source_size);
//! Estimates buffer size required to convert specified wide character string to specified codepage.
//! @param p_codepage Codepage ID of source string.
//! @param p_source String to be converted.
//! @param p_source_size Number of characters to read from p_source. If reading stops if null terminator is encountered earlier.
//! @returns Number of characters to allocate, including space for null terminator.
t_size estimate_wide_to_codepage(unsigned p_codepage,const wchar_t * p_source,t_size p_source_size);
//! Converts string from system codepage to wide character.
//! @param p_out Output buffer, receives converted string, with null terminator.
//! @param p_source String to convert.
//! @param p_source_size Number of characters to read from p_source. If reading stops if null terminator is encountered earlier.
//! @param p_out_size Size of output buffer, in characters. If converted string is too long, it will be truncated. Null terminator is always written, unless p_out_size is zero.
//! @returns Number of characters written, not counting null terminator.
inline t_size convert_ansi_to_wide(wchar_t * p_out,t_size p_out_size,const char * p_source,t_size p_source_size) {
return convert_codepage_to_wide(codepage_system,p_out,p_out_size,p_source,p_source_size);
}
//! Estimates buffer size required to convert specified system codepage string to wide character.
//! @param p_source String to be converted.
//! @param p_source_size Number of characters to read from p_source. If reading stops if null terminator is encountered earlier.
//! @returns Number of characters to allocate, including space for null terminator.
inline t_size estimate_ansi_to_wide(const char * p_source,t_size p_source_size) {
return estimate_codepage_to_wide(codepage_system,p_source,p_source_size);
}
//! Converts string from wide character to system codepage.
//! @param p_out Output buffer, receives converted string, with null terminator.
//! @param p_out_size Size of output buffer, in characters. If converted string is too long, it will be truncated. Null terminator is always written, unless p_out_size is zero.
//! @param p_source String to convert.
//! @param p_source_size Number of characters to read from p_source. If reading stops if null terminator is encountered earlier.
//! @returns Number of characters written, not counting null terminator.
inline t_size convert_wide_to_ansi(char * p_out,t_size p_out_size,const wchar_t * p_source,t_size p_source_size) {
return convert_wide_to_codepage(codepage_system,p_out,p_out_size,p_source,p_source_size);
}
//! Estimates buffer size required to convert specified wide character string to system codepage.
//! @param p_source String to be converted.
//! @param p_source_size Number of characters to read from p_source. If reading stops if null terminator is encountered earlier.
//! @returns Number of characters to allocate, including space for null terminator.
inline t_size estimate_wide_to_ansi(const wchar_t * p_source,t_size p_source_size) {
return estimate_wide_to_codepage(codepage_system,p_source,p_source_size);
}
template<template<typename t_allocitem> class t_alloc = pfc::alloc_standard>
class string_wide_from_codepage_t {
public:
string_wide_from_codepage_t() {}
string_wide_from_codepage_t(const string_wide_from_codepage_t<t_alloc> & p_source) : m_buffer(p_source.m_buffer) {}
string_wide_from_codepage_t(unsigned p_codepage,const char * p_source,t_size p_source_size = ~0) {convert(p_codepage,p_source,p_source_size);}
void convert(unsigned p_codepage,const char * p_source,t_size p_source_size = ~0) {
t_size size = estimate_codepage_to_wide(p_codepage,p_source,p_source_size);
m_buffer.set_size(size);
convert_codepage_to_wide(p_codepage, m_buffer.get_ptr_var(),size,p_source,p_source_size);
}
operator const wchar_t * () const {return get_ptr();}
const wchar_t * get_ptr() const {return m_buffer.get_ptr();}
bool is_empty() const {return string_is_empty_t(get_ptr());}
t_size length() const {return strlen_t(get_ptr());}
private:
char_buffer_t<wchar_t,t_alloc> m_buffer;
};
typedef string_wide_from_codepage_t<> string_wide_from_codepage;
template<template<typename t_allocitem> class t_alloc = pfc::alloc_standard>
class string_codepage_from_wide_t {
public:
string_codepage_from_wide_t() {}
string_codepage_from_wide_t(const string_codepage_from_wide_t<t_alloc> & p_source) : m_buffer(p_source.m_buffer) {}
string_codepage_from_wide_t(unsigned p_codepage,const wchar_t * p_source,t_size p_source_size = ~0) {convert(p_codepage,p_source,p_source_size);}
void convert(unsigned p_codepage,const wchar_t * p_source,t_size p_source_size = ~0) {
t_size size = estimate_wide_to_codepage(p_codepage,p_source,p_source_size);
m_buffer.set_size(size);
convert_wide_to_codepage(p_codepage, m_buffer.get_ptr_var(),size,p_source,p_source_size);
}
operator const char * () const {return get_ptr();}
const char * get_ptr() const {return m_buffer.get_ptr();}
bool is_empty() const {return string_is_empty_t(get_ptr());}
t_size length() const {return strlen_t(get_ptr());}
private:
char_buffer_t<char,t_alloc> m_buffer;
};
typedef string_codepage_from_wide_t<> string_codepage_from_wide;
class string_codepage_from_utf8 {
public:
string_codepage_from_utf8() {}
string_codepage_from_utf8(const string_codepage_from_utf8 & p_source) : m_buffer(p_source.m_buffer) {}
string_codepage_from_utf8(unsigned p_codepage,const char * p_source,t_size p_source_size = ~0) {convert(p_codepage,p_source,p_source_size);}
void convert(unsigned p_codepage,const char * p_source,t_size p_source_size = ~0) {
string_wide_from_utf8 temp;
temp.convert(p_source,p_source_size);
t_size size = estimate_wide_to_codepage(p_codepage,temp,SIZE_MAX);
m_buffer.set_size(size);
convert_wide_to_codepage(p_codepage,m_buffer.get_ptr_var(),size,temp,~0);
}
operator const char * () const {return get_ptr();}
const char * get_ptr() const {return m_buffer.get_ptr();}
bool is_empty() const {return string_is_empty_t(get_ptr());}
t_size length() const {return strlen_t(get_ptr());}
private:
char_buffer_t<char> m_buffer;
};
class string_utf8_from_codepage {
public:
string_utf8_from_codepage() {}
string_utf8_from_codepage(const string_utf8_from_codepage & p_source) : m_buffer(p_source.m_buffer) {}
string_utf8_from_codepage(unsigned p_codepage,const char * p_source,t_size p_source_size = ~0) {convert(p_codepage,p_source,p_source_size);}
void convert(unsigned p_codepage,const char * p_source,t_size p_source_size = ~0) {
string_wide_from_codepage temp;
temp.convert(p_codepage,p_source,p_source_size);
t_size size = estimate_wide_to_utf8(temp,SIZE_MAX);
m_buffer.set_size(size);
convert_wide_to_utf8( m_buffer.get_ptr_var(),size,temp,SIZE_MAX);
}
operator const char * () const {return get_ptr();}
const char * get_ptr() const {return m_buffer.get_ptr();}
bool is_empty() const {return string_is_empty_t(get_ptr());}
t_size length() const {return strlen_t(get_ptr());}
private:
char_buffer_t<char> m_buffer;
};
class string_utf8_from_ansi {
public:
string_utf8_from_ansi() {}
string_utf8_from_ansi(const string_utf8_from_ansi & p_source) : m_buffer(p_source.m_buffer) {}
string_utf8_from_ansi(const char * p_source,t_size p_source_size = ~0) : m_buffer(codepage_system,p_source,p_source_size) {}
operator const char * () const {return get_ptr();}
const char * get_ptr() const {return m_buffer.get_ptr();}
const char * toString() const {return get_ptr();}
bool is_empty() const {return string_is_empty_t(get_ptr());}
t_size length() const {return strlen_t(get_ptr());}
void convert(const char * p_source,t_size p_source_size = ~0) {m_buffer.convert(codepage_system,p_source,p_source_size);}
private:
string_utf8_from_codepage m_buffer;
};
class string_ansi_from_utf8 {
public:
string_ansi_from_utf8() {}
string_ansi_from_utf8(const string_ansi_from_utf8 & p_source) : m_buffer(p_source.m_buffer) {}
string_ansi_from_utf8(const char * p_source,t_size p_source_size = ~0) : m_buffer(codepage_system,p_source,p_source_size) {}
operator const char * () const {return get_ptr();}
const char * get_ptr() const {return m_buffer.get_ptr();}
bool is_empty() const {return string_is_empty_t(get_ptr());}
t_size length() const {return strlen_t(get_ptr());}
void convert(const char * p_source,t_size p_source_size = ~0) {m_buffer.convert(codepage_system,p_source,p_source_size);}
private:
string_codepage_from_utf8 m_buffer;
};
class string_wide_from_ansi {
public:
string_wide_from_ansi() {}
string_wide_from_ansi(const string_wide_from_ansi & p_source) : m_buffer(p_source.m_buffer) {}
string_wide_from_ansi(const char * p_source,t_size p_source_size = ~0) : m_buffer(codepage_system,p_source,p_source_size) {}
operator const wchar_t * () const {return get_ptr();}
const wchar_t * get_ptr() const {return m_buffer.get_ptr();}
bool is_empty() const {return string_is_empty_t(get_ptr());}
t_size length() const {return strlen_t(get_ptr());}
void convert(const char * p_source,t_size p_source_size = ~0) {m_buffer.convert(codepage_system,p_source,p_source_size);}
private:
string_wide_from_codepage m_buffer;
};
class string_ansi_from_wide {
public:
string_ansi_from_wide() {}
string_ansi_from_wide(const string_ansi_from_wide & p_source) : m_buffer(p_source.m_buffer) {}
string_ansi_from_wide(const wchar_t * p_source,t_size p_source_size = ~0) : m_buffer(codepage_system,p_source,p_source_size) {}
operator const char * () const {return get_ptr();}
const char * get_ptr() const {return m_buffer.get_ptr();}
bool is_empty() const {return string_is_empty_t(get_ptr());}
t_size length() const {return strlen_t(get_ptr());}
void convert(const wchar_t * p_source,t_size p_source_size = ~0) {m_buffer.convert(codepage_system,p_source,p_source_size);}
private:
string_codepage_from_wide m_buffer;
};
#ifdef UNICODE
typedef string_wide_from_utf8 string_os_from_utf8;
typedef string_utf8_from_wide string_utf8_from_os;
typedef string_wide_from_utf8_fast string_os_from_utf8_fast;
#else
typedef string_ansi_from_utf8 string_os_from_utf8;
typedef string_utf8_from_ansi string_utf8_from_os;
typedef string_ansi_from_utf8 string_os_from_utf8_fast;
#endif
class string_utf8_from_os_ex {
public:
template<typename t_source> string_utf8_from_os_ex(const t_source * source, t_size sourceLen = ~0) {
convert(source,sourceLen);
}
void convert(const char * source, t_size sourceLen = ~0) {
m_buffer = string_utf8_from_ansi(source,sourceLen);
}
void convert(const wchar_t * source, t_size sourceLen = ~0) {
m_buffer = string_utf8_from_wide(source,sourceLen);
}
operator const char * () const {return get_ptr();}
const char * get_ptr() const {return m_buffer.get_ptr();}
bool is_empty() const {return m_buffer.is_empty();}
t_size length() const {return m_buffer.length();}
const char * toString() const {return get_ptr();}
private:
string8 m_buffer;
};
}
#else
namespace stringcvt {
typedef string_win1252_from_wide string_ansi_from_wide;
typedef string_wide_from_win1252 string_wide_from_ansi;
typedef string_win1252_from_utf8 string_ansi_from_utf8;
typedef string_utf8_from_win1252 string_utf8_from_ansi;
}
#endif
};
pfc::string_base & operator<<(pfc::string_base & p_fmt, const wchar_t * p_str);

41
pfc/string_list.h Normal file
View File

@@ -0,0 +1,41 @@
#pragma once
namespace pfc {
typedef list_base_const_t<const char*> string_list_const;
class string_list_impl : public string_list_const
{
public:
t_size get_count() const {return m_data.get_size();}
void get_item_ex(const char* & p_out, t_size n) const {p_out = m_data[n];}
const char * operator[] (t_size n) const {return m_data[n];}
void add_item(const char * p_string) {pfc::append_t(m_data, p_string);}
template<typename t_what> void add_items(const t_what & p_source) {_append(p_source);}
void remove_all() {m_data.set_size(0);}
string_list_impl() {}
template<typename t_what> string_list_impl(const t_what & p_source) {_copy(p_source);}
template<typename t_what> string_list_impl & operator=(const t_what & p_source) {_copy(p_source); return *this;}
template<typename t_what> string_list_impl & operator|=(const string_list_impl & p_source) {_append(p_source); return *this;}
template<typename t_what> string_list_impl & operator+=(const t_what & p_source) {pfc::append_t(m_data, p_source); return *this;}
private:
template<typename t_what> void _append(const t_what & p_source) {
const t_size toadd = p_source.get_size(), base = m_data.get_size();
m_data.set_size(base+toadd);
for(t_size n=0;n<toadd;n++) m_data[base+n] = p_source[n];
}
template<typename t_what> void _copy(const t_what & p_source) {
const t_size newcount = p_source.get_size();
m_data.set_size(newcount);
for(t_size n=0;n<newcount;n++) m_data[n] = p_source[n];
}
pfc::array_t<pfc::string8,pfc::alloc_fast> m_data;
};
}

19
pfc/suppress_fb2k_hooks.h Normal file
View File

@@ -0,0 +1,19 @@
#pragma once
/*
foobar2000 shared.dll hook implementations
If you're getting linker multiple-definition errors on these, change build configuration of PFC from "Debug" / "Release" to "Debug FB2K" / "Release FB2K"
Configurations with "FB2K" suffix disable compilation of pfc-fb2k-hooks.cpp allowing these methods to be redirected to shared.dll calls
*/
namespace pfc {
void crashImpl();
BOOL winFormatSystemErrorMessageImpl(pfc::string_base & p_out, DWORD p_code);
void crashHook() {
crashImpl();
}
BOOL winFormatSystemErrorMessageHook(pfc::string_base & p_out, DWORD p_code) {
return winFormatSystemErrorMessageImpl(p_out, p_code);
}
}

95
pfc/syncd_storage.h Normal file
View File

@@ -0,0 +1,95 @@
#pragma once
namespace pfc {
// Read/write lock guarded object store for safe concurrent access
template<typename t_object>
class syncd_storage {
private:
typedef syncd_storage<t_object> t_self;
public:
syncd_storage() {}
template<typename t_source>
syncd_storage(const t_source & p_source) : m_object(p_source) {}
template<typename t_source>
void set(t_source const & p_in) {
inWriteSync(m_sync);
m_object = p_in;
}
template<typename t_destination>
void get(t_destination & p_out) const {
inReadSync(m_sync);
p_out = m_object;
}
t_object get() const {
inReadSync(m_sync);
return m_object;
}
template<typename t_source>
const t_self & operator=(t_source const & p_source) {set(p_source); return *this;}
private:
mutable ::pfc::readWriteLock m_sync;
t_object m_object;
};
// Read/write lock guarded object store for safe concurrent access
// With 'has changed since last read' flag
template<typename t_object>
class syncd_storage_flagged {
private:
typedef syncd_storage_flagged<t_object> t_self;
public:
syncd_storage_flagged() : m_changed_flag(false) {}
template<typename t_source>
syncd_storage_flagged(const t_source & p_source, bool initChanged = false) : m_changed_flag(initChanged), m_object(p_source) {}
void set_changed(bool p_flag = true) {
inWriteSync(m_sync);
m_changed_flag = p_flag;
}
template<typename t_source>
void set(t_source const & p_in) {
inWriteSync(m_sync);
m_object = p_in;
m_changed_flag = true;
}
bool has_changed() const {
inReadSync(m_sync);
return m_changed_flag;
}
t_object peek() const {inReadSync(m_sync); return m_object;}
template<typename t_destination>
bool get_if_changed(t_destination & p_out) {
inReadSync(m_sync);
if (m_changed_flag) {
p_out = m_object;
m_changed_flag = false;
return true;
} else {
return false;
}
}
t_object get() {
inReadSync(m_sync);
m_changed_flag = false;
return m_object;
}
t_object get( bool & bHasChanged ) {
inReadSync(m_sync);
bHasChanged = m_changed_flag;
m_changed_flag = false;
return m_object;
}
template<typename t_destination>
void get(t_destination & p_out) {
inReadSync(m_sync);
p_out = m_object;
m_changed_flag = false;
}
template<typename t_source>
const t_self & operator=(t_source const & p_source) {set(p_source); return *this;}
private:
mutable volatile bool m_changed_flag;
mutable ::pfc::readWriteLock m_sync;
t_object m_object;
};
}

16
pfc/synchro.h Normal file
View File

@@ -0,0 +1,16 @@
#pragma once
// added for compatibility with fb2k mobile
namespace pfc {
class dummyLock {
public:
void enterRead() {}
void enterWrite() {}
void leaveRead() {}
void leaveWrite() {}
void enter() {}
void leave() {}
void lock() {}
void unlock() {}
};
}

33
pfc/synchro_nix.cpp Normal file
View File

@@ -0,0 +1,33 @@
#include "pfc.h"
#ifndef _WIN32
namespace pfc {
void mutexBase::create( const pthread_mutexattr_t * attr ) {
if (pthread_mutex_init( &obj, attr) != 0) {
throw exception_bug_check();
}
}
void mutexBase::destroy() {
pthread_mutex_destroy( &obj );
}
void mutexBase::createRecur() {
mutexAttr a; a.setRecursive(); create(&a.attr);
}
void mutexBase::create( const mutexAttr & a ) {
create( & a.attr );
}
void readWriteLockBase::create( const pthread_rwlockattr_t * attr ) {
if (pthread_rwlock_init( &obj, attr) != 0) {
throw exception_bug_check();
}
}
void readWriteLockBase::create( const readWriteLockAttr & a) {
create(&a.attr);
}
}
#endif // _WIN32

146
pfc/synchro_nix.h Normal file
View File

@@ -0,0 +1,146 @@
#include <pthread.h>
namespace pfc {
class mutexAttr {
public:
mutexAttr() {pthread_mutexattr_init(&attr);}
~mutexAttr() {pthread_mutexattr_destroy(&attr);}
void setType(int type) {pthread_mutexattr_settype(&attr, type);}
int getType() const {int rv = 0; pthread_mutexattr_gettype(&attr, &rv); return rv; }
void setRecursive() {setType(PTHREAD_MUTEX_RECURSIVE);}
bool isRecursive() {return getType() == PTHREAD_MUTEX_RECURSIVE;}
void setProcessShared() {pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);}
operator const pthread_mutexattr_t & () const {return attr;}
operator pthread_mutexattr_t & () {return attr;}
pthread_mutexattr_t attr;
private:
mutexAttr(const mutexAttr&); void operator=(const mutexAttr&);
};
class mutexBase {
public:
void lock() throw() {pthread_mutex_lock(&obj);}
void unlock() throw() {pthread_mutex_unlock(&obj);}
void enter() throw() {lock();}
void leave() throw() {unlock();}
void create( const pthread_mutexattr_t * attr );
void create( const mutexAttr & );
void createRecur();
void destroy();
protected:
mutexBase() {}
~mutexBase() {}
private:
pthread_mutex_t obj;
void operator=( const mutexBase & );
mutexBase( const mutexBase & );
};
class mutex : public mutexBase {
public:
mutex() {create(NULL);}
~mutex() {destroy();}
};
class mutexRecur : public mutexBase {
public:
mutexRecur() {createRecur();}
~mutexRecur() {destroy();}
};
class mutexRecurStatic : public mutexBase {
public:
mutexRecurStatic() {createRecur();}
};
class mutexScope {
public:
mutexScope( mutexBase * m ) throw() : m_mutex(m) { m_mutex->enter(); }
mutexScope( mutexBase & m ) throw() : m_mutex(&m) { m_mutex->enter(); }
~mutexScope( ) throw() {m_mutex->leave();}
private:
void operator=( const mutexScope & ); mutexScope( const mutexScope & );
mutexBase * m_mutex;
};
class readWriteLockAttr {
public:
readWriteLockAttr() {pthread_rwlockattr_init( & attr ); }
~readWriteLockAttr() {pthread_rwlockattr_destroy( & attr ) ;}
void setProcessShared( bool val = true ) {
pthread_rwlockattr_setpshared( &attr, val ? PTHREAD_PROCESS_SHARED : PTHREAD_PROCESS_PRIVATE );
}
pthread_rwlockattr_t attr;
private:
readWriteLockAttr( const readWriteLockAttr &); void operator=(const readWriteLockAttr & );
};
class readWriteLockBase {
public:
void create( const pthread_rwlockattr_t * attr );
void create( const readWriteLockAttr & );
void destroy() {pthread_rwlock_destroy( & obj ); }
void enterRead() {pthread_rwlock_rdlock( &obj ); }
void enterWrite() {pthread_rwlock_wrlock( &obj ); }
void leaveRead() {pthread_rwlock_unlock( &obj ); }
void leaveWrite() {pthread_rwlock_unlock( &obj ); }
protected:
readWriteLockBase() {}
~readWriteLockBase() {}
private:
pthread_rwlock_t obj;
void operator=( const readWriteLockBase & ); readWriteLockBase( const readWriteLockBase & );
};
class readWriteLock : public readWriteLockBase {
public:
readWriteLock() {create(NULL);}
~readWriteLock() {destroy();}
};
class _readWriteLock_scope_read {
public:
_readWriteLock_scope_read( readWriteLockBase & lock ) : m_lock( lock ) { m_lock.enterRead(); }
~_readWriteLock_scope_read() {m_lock.leaveRead();}
private:
_readWriteLock_scope_read( const _readWriteLock_scope_read &);
void operator=( const _readWriteLock_scope_read &);
readWriteLockBase & m_lock;
};
class _readWriteLock_scope_write {
public:
_readWriteLock_scope_write( readWriteLockBase & lock ) : m_lock( lock ) { m_lock.enterWrite(); }
~_readWriteLock_scope_write() {m_lock.leaveWrite();}
private:
_readWriteLock_scope_write( const _readWriteLock_scope_write &);
void operator=( const _readWriteLock_scope_write &);
readWriteLockBase & m_lock;
};
}
typedef pfc::mutexRecur critical_section;
typedef pfc::mutexRecurStatic critical_section_static;
typedef pfc::mutexScope c_insync;
#define insync(X) c_insync blah____sync(X)
#define inReadSync( X ) ::pfc::_readWriteLock_scope_read _asdf_l_readWriteLock_scope_read( X )
#define inWriteSync( X ) ::pfc::_readWriteLock_scope_write _asdf_l_readWriteLock_scope_write( X )

114
pfc/synchro_win.h Normal file
View File

@@ -0,0 +1,114 @@
#pragma once
class _critical_section_base {
protected:
CRITICAL_SECTION sec;
public:
_critical_section_base() {}
inline void enter() throw() {EnterCriticalSection(&sec);}
inline void leave() throw() {LeaveCriticalSection(&sec);}
inline void create() throw() {
#ifdef PFC_WINDOWS_DESKTOP_APP
InitializeCriticalSection(&sec);
#else
InitializeCriticalSectionEx(&sec,0,0);
#endif
}
inline void destroy() throw() {DeleteCriticalSection(&sec);}
inline bool tryEnter() throw() { return !!TryEnterCriticalSection(&sec); }
private:
_critical_section_base(const _critical_section_base&);
void operator=(const _critical_section_base&);
};
// Static-lifetime critical section, no cleanup - valid until process termination
class critical_section_static : public _critical_section_base {
public:
critical_section_static() {create();}
#if !PFC_LEAK_STATIC_OBJECTS
~critical_section_static() {destroy();}
#endif
};
// Regular critical section, intended for any lifetime scopes
class critical_section : public _critical_section_base {
public:
critical_section() {create();}
~critical_section() {destroy();}
};
template<typename lock_t>
class c_insync_
{
private:
lock_t& m_section;
public:
c_insync_(lock_t * p_section) throw() : m_section(*p_section) {m_section.enter();}
c_insync_(lock_t & p_section) throw() : m_section(p_section) {m_section.enter();}
~c_insync_() throw() {m_section.leave();}
};
typedef c_insync_<_critical_section_base> c_insync;
// Old typedef for backwards compat
#define insync(X) c_insync blah____sync(X)
// New typedef
#define PFC_INSYNC(X) c_insync_<decltype(X)> blah____sync(X)
namespace pfc {
// Read write lock - Vista-and-newer friendly lock that allows concurrent reads from a resource that permits such
// Warning, non-recursion proof
class readWriteLock {
public:
readWriteLock() : theLock() {
}
void enterRead() {
AcquireSRWLockShared( & theLock );
}
void enterWrite() {
AcquireSRWLockExclusive( & theLock );
}
void leaveRead() {
ReleaseSRWLockShared( & theLock );
}
void leaveWrite() {
ReleaseSRWLockExclusive( &theLock );
}
private:
readWriteLock(const readWriteLock&) = delete;
void operator=(const readWriteLock&) = delete;
SRWLOCK theLock;
};
class _readWriteLock_scope_read {
public:
_readWriteLock_scope_read( readWriteLock & lock ) : m_lock( lock ) { m_lock.enterRead(); }
~_readWriteLock_scope_read() {m_lock.leaveRead();}
private:
_readWriteLock_scope_read( const _readWriteLock_scope_read &) = delete;
void operator=( const _readWriteLock_scope_read &) = delete;
readWriteLock & m_lock;
};
class _readWriteLock_scope_write {
public:
_readWriteLock_scope_write( readWriteLock & lock ) : m_lock( lock ) { m_lock.enterWrite(); }
~_readWriteLock_scope_write() {m_lock.leaveWrite();}
private:
_readWriteLock_scope_write( const _readWriteLock_scope_write &) = delete;
void operator=( const _readWriteLock_scope_write &) = delete;
readWriteLock & m_lock;
};
#define inReadSync( X ) ::pfc::_readWriteLock_scope_read _asdf_l_readWriteLock_scope_read( X )
#define inWriteSync( X ) ::pfc::_readWriteLock_scope_write _asdf_l_readWriteLock_scope_write( X )
typedef ::critical_section mutex;
typedef ::c_insync mutexScope;
}

6
pfc/targetver.h Normal file
View File

@@ -0,0 +1,6 @@
#pragma once
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0601
#include <SDKDDKVer.h>
#endif

210
pfc/threads.cpp Normal file
View File

@@ -0,0 +1,210 @@
#include "pfc.h"
#ifdef _WIN32
#include "pp-winapi.h"
#endif
#ifdef __APPLE__
#include <sys/sysctl.h>
#include <sys/stat.h>
#endif
#include <thread>
namespace pfc {
t_size getOptimalWorkerThreadCount() {
return std::thread::hardware_concurrency();
}
t_size getOptimalWorkerThreadCountEx(t_size taskCountLimit) {
if (taskCountLimit <= 1) return 1;
return pfc::min_t(taskCountLimit,getOptimalWorkerThreadCount());
}
void thread::entry() {
try {
threadProc();
} catch(...) {}
}
void thread::couldNotCreateThread() {
// Something terminally wrong, better crash leaving a good debug trace
crash();
}
#ifdef _WIN32
thread::thread() : m_thread(INVALID_HANDLE_VALUE)
{
}
void thread::close() {
if (isActive()) {
int ctxPriority = GetThreadPriority( GetCurrentThread() );
if (ctxPriority > GetThreadPriority( m_thread ) ) SetThreadPriority( m_thread, ctxPriority );
if (WaitForSingleObject(m_thread,INFINITE) != WAIT_OBJECT_0) couldNotCreateThread();
CloseHandle(m_thread); m_thread = INVALID_HANDLE_VALUE;
}
}
bool thread::isActive() const {
return m_thread != INVALID_HANDLE_VALUE;
}
static HANDLE MyBeginThread( unsigned (__stdcall * proc)(void *) , void * arg, DWORD * outThreadID, int priority) {
HANDLE thread;
#ifdef PFC_WINDOWS_DESKTOP_APP
thread = (HANDLE)_beginthreadex(NULL, 0, proc, arg, CREATE_SUSPENDED, (unsigned int*)outThreadID);
#else
thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)proc, arg, CREATE_SUSPENDED, outThreadID);
#endif
if (thread == NULL) thread::couldNotCreateThread();
SetThreadPriority(thread, priority);
ResumeThread(thread);
return thread;
}
void thread::winStart(int priority, DWORD * outThreadID) {
close();
m_thread = MyBeginThread(g_entry, reinterpret_cast<void*>(this), outThreadID, priority);
}
void thread::startWithPriority(int priority) {
winStart(priority, NULL);
}
void thread::setPriority(int priority) {
PFC_ASSERT(isActive());
SetThreadPriority(m_thread, priority);
}
void thread::start() {
startWithPriority(GetThreadPriority(GetCurrentThread()));
}
unsigned CALLBACK thread::g_entry(void* p_instance) {
reinterpret_cast<thread*>(p_instance)->entry(); return 0;
}
int thread::getPriority() {
PFC_ASSERT(isActive());
return GetThreadPriority( m_thread );
}
int thread::currentPriority() {
return GetThreadPriority( GetCurrentThread() );
}
#else
thread::thread() : m_thread(), m_threadValid() {
}
#ifndef __APPLE__ // Apple specific entrypoint in obj-c.mm
void * thread::g_entry( void * arg ) {
reinterpret_cast<thread*>( arg )->entry();
return NULL;
}
#endif
void thread::startWithPriority(int priority) {
close();
#ifdef __APPLE__
appleStartThreadPrologue();
#endif
pthread_t thread;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
if (pthread_create(&thread, &attr, g_entry, reinterpret_cast<void*>(this)) < 0) couldNotCreateThread();
pthread_attr_destroy(&attr);
m_threadValid = true;
m_thread = thread;
}
void thread::setPriority(int priority) {
PFC_ASSERT(isActive());
// not avail
}
int thread::getPriority() {
return 0; // not avail
}
int thread::currentPriority() {
return 0; // not avail
}
void thread::start() {
startWithPriority(currentPriority());
}
void thread::close() {
if (m_threadValid) {
void * rv = NULL;
pthread_join( m_thread, & rv ); m_thread = 0;
m_threadValid = false;
}
}
bool thread::isActive() const {
return m_threadValid;
}
#endif
#ifdef _WIN32
unsigned CALLBACK winSplitThreadProc(void* arg) {
auto f = reinterpret_cast<std::function<void() > *>(arg);
(*f)();
delete f;
return 0;
}
#else
void * nixSplitThreadProc(void * arg) {
auto f = reinterpret_cast<std::function<void() > *>(arg);
#ifdef __APPLE__
inAutoReleasePool([f] {
(*f)();
delete f;
});
#else
(*f)();
delete f;
#endif
return NULL;
}
#endif
void splitThread(std::function<void() > f) {
ptrholder_t< std::function<void() > > arg ( new std::function<void() >(f) );
#ifdef _WIN32
HANDLE h = MyBeginThread(winSplitThreadProc, arg.get_ptr(), NULL, GetThreadPriority(GetCurrentThread()));
CloseHandle(h);
#else
#ifdef __APPLE__
thread::appleStartThreadPrologue();
#endif
pthread_t thread;
if (pthread_create(&thread, NULL, nixSplitThreadProc, arg.get_ptr()) < 0) thread::couldNotCreateThread();
pthread_detach(thread);
#endif
arg.detach();
}
#ifndef __APPLE__
// Stub for non Apple
void inAutoReleasePool(std::function<void()> f) { f(); }
#endif
void thread2::startHereWithPriority(std::function<void()> e, int priority) {
setEntry(e); startWithPriority(priority);
}
void thread2::startHere(std::function<void()> e) {
setEntry(e); start();
}
void thread2::setEntry(std::function<void()> e) {
PFC_ASSERT(!isActive());
m_entryPoint = e;
}
void thread2::threadProc() {
m_entryPoint();
}
}

77
pfc/threads.h Normal file
View File

@@ -0,0 +1,77 @@
#pragma once
#include <functional>
#ifdef _WIN32
#include <process.h>
#else
#include <pthread.h>
#endif
namespace pfc {
t_size getOptimalWorkerThreadCount();
t_size getOptimalWorkerThreadCountEx(t_size taskCountLimit);
//! IMPORTANT: all classes derived from thread must call waitTillDone() in their destructor, to avoid object destruction during a virtual function call!
class thread {
public:
//! Critical error handler function, never returns
PFC_NORETURN static void couldNotCreateThread();
thread();
~thread() {PFC_ASSERT(!isActive()); waitTillDone();}
void startWithPriority(int priority);
void setPriority(int priority);
int getPriority();
void start();
bool isActive() const;
void waitTillDone() {close();}
static int currentPriority();
#ifdef _WIN32
void winStart(int priority, DWORD * outThreadID);
HANDLE winThreadHandle() { return m_thread; }
#else
pthread_t posixThreadHandle() { return m_thread; }
#endif
#ifdef __APPLE__
static void appleStartThreadPrologue();
#endif
protected:
virtual void threadProc() {PFC_ASSERT(!"Stub thread entry - should not get here");}
private:
void close();
#ifdef _WIN32
static unsigned CALLBACK g_entry(void* p_instance);
#else
static void * g_entry( void * arg );
#endif
void entry();
#ifdef _WIN32
HANDLE m_thread;
#else
pthread_t m_thread;
bool m_threadValid; // there is no invalid pthread_t, so we keep a separate 'valid' flag
#endif
PFC_CLASS_NOT_COPYABLE_EX(thread)
};
//! Thread class using lambda entrypoint rather than function override
class thread2 : public thread {
public:
~thread2() { waitTillDone(); }
void startHereWithPriority(std::function<void()> e, int priority);
void startHere(std::function<void()> e);
void setEntry(std::function<void()> e);
private:
void threadProc();
std::function<void()> m_entryPoint;
};
void splitThread(std::function<void() > f);
//! Apple specific; executes the function in a release pool scope. \n
//! On non Apple platforms it just invokes the function.
void inAutoReleasePool(std::function<void()> f);
}

112
pfc/timers.cpp Normal file
View File

@@ -0,0 +1,112 @@
#include "pfc.h"
#if defined(_WIN32) && defined(PFC_HAVE_PROFILER)
#include <ShlObj.h>
#endif
namespace pfc {
#ifdef PFC_HAVE_PROFILER
profiler_static::profiler_static(const char * p_name)
{
name = p_name;
total_time = 0;
num_called = 0;
}
static void profilerMsg(const char* msg) {
#ifdef _WIN32
if (!IsDebuggerPresent()) {
static HANDLE hWriteTo = INVALID_HANDLE_VALUE;
static bool initialized = false;
if (!initialized) {
initialized = true;
wchar_t path[1024] = {};
if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, SHGFP_TYPE_CURRENT, path))) {
size_t l = wcslen(path);
if (l > 0) {
if (path[l - 1] != '\\') {
wcscat_s(path, L"\\");
}
wchar_t fn[256];
wsprintf(fn, L"profiler-%u.txt", GetProcessId(GetCurrentProcess()));
wcscat_s(path, fn);
hWriteTo = CreateFile(path, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, 0, NULL);
}
}
}
if (hWriteTo != INVALID_HANDLE_VALUE) {
SetFilePointer(hWriteTo, 0, 0, SEEK_END);
pfc::string8 temp = msg;
temp += "\r\n";
DWORD written = 0;
WriteFile(hWriteTo, temp.c_str(), temp.length(), &written, NULL);
}
}
#endif
outputDebugLine(msg);
}
profiler_static::~profiler_static()
{
try {
pfc::string_fixed_t<511> message;
message << "profiler: " << pfc::format_pad_left<pfc::string_fixed_t<127> >(48,' ',name) << " - " <<
pfc::format_pad_right<pfc::string_fixed_t<128> >(16,' ',pfc::format_uint(total_time) ) << " cycles";
if (num_called > 0) {
message << " (executed " << num_called << " times, " << (total_time / num_called) << " average)";
}
profilerMsg(message);
} catch(...) {
//should never happen
OutputDebugString(_T("unexpected profiler failure\n"));
}
}
#endif
#ifndef _WIN32
void hires_timer::start() {
m_start = nixGetTime();
}
double hires_timer::query() const {
return nixGetTime() - m_start;
}
double hires_timer::query_reset() {
double t = nixGetTime();
double r = t - m_start;
m_start = t;
return r;
}
pfc::string8 hires_timer::queryString(unsigned precision) const {
return format_time_ex( query(), precision ).get_ptr();
}
#endif
uint64_t fileTimeWtoU(uint64_t ft) {
return (ft - 116444736000000000 + /*rounding*/10000000/2) / 10000000;
}
uint64_t fileTimeUtoW(uint64_t ft) {
return (ft * 10000000) + 116444736000000000;
}
#ifndef _WIN32
uint64_t fileTimeUtoW(const timespec & ts) {
uint64_t ft = (uint64_t)ts.tv_sec * 10000000 + (uint64_t)ts.tv_nsec / 100;
return ft + 116444736000000000;
}
#endif
uint64_t fileTimeNow() {
#ifdef _WIN32
uint64_t ret;
GetSystemTimeAsFileTime((FILETIME*)&ret);
return ret;
#else
return fileTimeUtoW(time(NULL));
#endif
}
}

145
pfc/timers.h Normal file
View File

@@ -0,0 +1,145 @@
#pragma once
#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
#define PFC_HAVE_PROFILER
#include <intrin.h>
namespace pfc {
class profiler_static {
public:
profiler_static(const char * p_name);
~profiler_static();
void add_time(t_int64 delta) { total_time += delta;num_called++; }
private:
const char * name;
t_uint64 total_time, num_called;
};
class profiler_local {
public:
profiler_local(profiler_static * p_owner) {
owner = p_owner;
start = __rdtsc();
}
~profiler_local() {
t_int64 end = __rdtsc();
owner->add_time(end - start);
}
private:
t_int64 start;
profiler_static * owner;
};
}
#define profiler(name) \
static pfc::profiler_static profiler_static_##name(#name); \
pfc::profiler_local profiler_local_##name(&profiler_static_##name);
#endif
#ifdef _WIN32
namespace pfc {
// ALWAYS define 64bit tickcount - don't cause mayhem if different modules are compiled for different Windows versions
typedef uint64_t tickcount_t;
inline tickcount_t getTickCount() { return GetTickCount64(); }
class hires_timer {
public:
hires_timer() : m_start() {}
void start() {
m_start = g_query();
}
double query() const {
return _query( g_query() );
}
double query_reset() {
t_uint64 current = g_query();
double ret = _query(current);
m_start = current;
return ret;
}
pfc::string8 queryString(unsigned precision = 6) const {
return pfc::format_time_ex( query(), precision ).get_ptr();
}
private:
double _query(t_uint64 p_val) const {
return (double)( p_val - m_start ) / (double) g_query_freq();
}
static t_uint64 g_query() {
LARGE_INTEGER val;
if (!QueryPerformanceCounter(&val)) throw pfc::exception_not_implemented();
return val.QuadPart;
}
static t_uint64 g_query_freq() {
LARGE_INTEGER val;
if (!QueryPerformanceFrequency(&val)) throw pfc::exception_not_implemented();
return val.QuadPart;
}
t_uint64 m_start;
};
class lores_timer {
public:
lores_timer() {}
void start() {
_start(getTickCount());
}
double query() const {
return _query(getTickCount());
}
double query_reset() {
tickcount_t time = getTickCount();
double ret = _query(time);
_start(time);
return ret;
}
pfc::string8 queryString(unsigned precision = 3) const {
return pfc::format_time_ex( query(), precision ).get_ptr();
}
private:
void _start(tickcount_t p_time) {
m_start = p_time;
}
double _query(tickcount_t p_time) const {
return (double)(p_time - m_start) / 1000.0;
}
t_uint64 m_start = 0;
};
}
#else // not _WIN32
namespace pfc {
class hires_timer {
public:
hires_timer() : m_start() {}
void start();
double query() const;
double query_reset();
pfc::string8 queryString(unsigned precision = 3) const;
private:
double m_start;
};
typedef hires_timer lores_timer;
}
#endif // _WIN32
#ifndef _WIN32
struct timespec;
#endif
namespace pfc {
uint64_t fileTimeWtoU(uint64_t ft);
uint64_t fileTimeUtoW(uint64_t ft);
#ifndef _WIN32
uint64_t fileTimeUtoW( timespec const & ts );
#endif
uint64_t fileTimeNow();
}

85
pfc/traits.h Normal file
View File

@@ -0,0 +1,85 @@
#pragma once
namespace pfc {
class traits_default {
public:
enum {
realloc_safe = false,
needs_destructor = true,
needs_constructor = true,
constructor_may_fail = true
};
};
class traits_default_movable {
public:
enum {
realloc_safe = true,
needs_destructor = true,
needs_constructor = true,
constructor_may_fail = true
};
};
class traits_rawobject : public traits_default {
public:
enum {
realloc_safe = true,
needs_destructor = false,
needs_constructor = false,
constructor_may_fail = false
};
};
class traits_vtable {
public:
enum {
realloc_safe = true,
needs_destructor = true,
needs_constructor = true,
constructor_may_fail = false
};
};
template<typename T> class traits_t : public traits_default {};
template<typename traits1,typename traits2>
class combine_traits {
public:
enum {
realloc_safe = (traits1::realloc_safe && traits2::realloc_safe),
needs_destructor = (traits1::needs_destructor || traits2::needs_destructor),
needs_constructor = (traits1::needs_constructor || traits2::needs_constructor),
constructor_may_fail = (traits1::constructor_may_fail || traits2::constructor_may_fail),
};
};
template<typename type1, typename type2>
class traits_combined : public combine_traits<traits_t<type1>,traits_t<type2> > {};
template<typename T> class traits_t<T*> : public traits_rawobject {};
template<> class traits_t<char> : public traits_rawobject {};
template<> class traits_t<unsigned char> : public traits_rawobject {};
template<> class traits_t<signed char> : public traits_rawobject {};
template<> class traits_t<wchar_t> : public traits_rawobject {};
template<> class traits_t<short> : public traits_rawobject {};
template<> class traits_t<unsigned short> : public traits_rawobject {};
template<> class traits_t<int> : public traits_rawobject {};
template<> class traits_t<unsigned int> : public traits_rawobject {};
template<> class traits_t<long> : public traits_rawobject {};
template<> class traits_t<unsigned long> : public traits_rawobject {};
template<> class traits_t<long long> : public traits_rawobject {};
template<> class traits_t<unsigned long long> : public traits_rawobject {};
template<> class traits_t<bool> : public traits_rawobject {};
template<> class traits_t<float> : public traits_rawobject {};
template<> class traits_t<double> : public traits_rawobject {};
template<> class traits_t<GUID> : public traits_rawobject {};
template<typename T,t_size p_count>
class traits_t<T[p_count]> : public traits_t<T> {};
}

107
pfc/utf8.cpp Normal file
View File

@@ -0,0 +1,107 @@
#include "pfc.h"
namespace pfc {
//utf8 stuff
#include "pocket_char_ops.h"
#ifdef _MSC_VER
t_size utf16_decode_char(const wchar_t * p_source,unsigned * p_out,t_size p_source_length) throw() {
PFC_STATIC_ASSERT( sizeof(wchar_t) == sizeof(char16_t) );
return wide_decode_char( p_source, p_out, p_source_length );
}
t_size utf16_encode_char(unsigned c,wchar_t * out) throw() {
PFC_STATIC_ASSERT( sizeof(wchar_t) == sizeof(char16_t) );
return wide_encode_char( c, out );
}
#endif
t_size wide_decode_char(const wchar_t * p_source,unsigned * p_out,t_size p_source_length) throw() {
PFC_STATIC_ASSERT( sizeof( wchar_t ) == sizeof( char16_t ) || sizeof( wchar_t ) == sizeof( unsigned ) );
if (sizeof( wchar_t ) == sizeof( char16_t ) ) {
return utf16_decode_char( reinterpret_cast< const char16_t *>(p_source), p_out, p_source_length );
} else {
if (p_source_length == 0) { * p_out = 0; return 0; }
* p_out = p_source [ 0 ];
return 1;
}
}
t_size wide_encode_char(unsigned c,wchar_t * out) throw() {
PFC_STATIC_ASSERT( sizeof( wchar_t ) == sizeof( char16_t ) || sizeof( wchar_t ) == sizeof( unsigned ) );
if (sizeof( wchar_t ) == sizeof( char16_t ) ) {
return utf16_encode_char( c, reinterpret_cast< char16_t * >(out) );
} else {
* out = (wchar_t) c;
return 1;
}
}
bool is_lower_ascii(const char * param)
{
while(*param)
{
if (*param<0) return false;
param++;
}
return true;
}
static bool check_end_of_string(const char * ptr)
{
return !*ptr;
}
unsigned strcpy_utf8_truncate(const char * src,char * out,unsigned maxbytes)
{
unsigned rv = 0 , ptr = 0;
if (maxbytes>0)
{
maxbytes--;//for null
while(!check_end_of_string(src) && maxbytes>0)
{
unsigned delta = (unsigned)utf8_char_len(src);
if (delta>maxbytes || delta==0) break;
maxbytes -= delta;
do
{
out[ptr++] = *(src++);
} while(--delta);
rv = ptr;
}
out[rv]=0;
}
return rv;
}
t_size strlen_utf8(const char * p,t_size num) throw()
{
unsigned w;
t_size d;
t_size ret = 0;
for(;num;)
{
d = utf8_decode_char(p,w);
if (w==0 || d<=0) break;
ret++;
p+=d;
num-=d;
}
return ret;
}
t_size utf8_chars_to_bytes(const char * string,t_size count) throw()
{
t_size bytes = 0;
while(count)
{
unsigned dummy;
t_size delta = utf8_decode_char(string+bytes,dummy);
if (delta==0) break;
bytes += delta;
count--;
}
return bytes;
}
}

190
pfc/wait_queue.h Normal file
View File

@@ -0,0 +1,190 @@
#pragma once
#include <list>
#include "synchro.h"
namespace pfc {
template<typename obj_t>
class waitQueue {
public:
waitQueue() : m_eof() {}
void put( obj_t const & obj ) {
mutexScope guard( m_mutex );
m_list.push_back( obj );
if ( m_list.size() == 1 ) m_canRead.set_state( true );
}
void put( obj_t && obj ) {
mutexScope guard( m_mutex );
m_list.push_back( std::move(obj) );
if ( m_list.size() == 1 ) m_canRead.set_state( true );
}
void set_eof() {
mutexScope guard(m_mutex);
m_eof = true;
m_canRead.set_state(true);
}
bool wait_read( double timeout ) {
return m_canRead.wait_for( timeout );
}
eventHandle_t get_event_handle() {
return m_canRead.get_handle();
}
bool get( obj_t & out ) {
for ( ;; ) {
m_canRead.wait_for(-1);
mutexScope guard(m_mutex);
auto i = m_list.begin();
if ( i == m_list.end() ) {
if (m_eof) return false;
continue;
}
out = std::move(*i);
m_list.erase( i );
didGet();
return true;
}
}
bool get( obj_t & out, pfc::eventHandle_t hAbort, bool * didAbort = nullptr ) {
if (didAbort != nullptr) * didAbort = false;
for ( ;; ) {
if (pfc::event::g_twoEventWait( hAbort, m_canRead.get_handle(), -1) == 1) {
if (didAbort != nullptr) * didAbort = true;
return false;
}
mutexScope guard(m_mutex);
auto i = m_list.begin();
if ( i == m_list.end() ) {
if (m_eof) return false;
continue;
}
out = std::move(*i);
m_list.erase( i );
didGet();
return true;
}
}
void clear() {
mutexScope guard(m_mutex);
m_eof = false;
m_list.clear();
m_canRead.set_state(false);
}
private:
void didGet() {
if (!m_eof && m_list.size() == 0) m_canRead.set_state(false);
}
bool m_eof;
std::list<obj_t> m_list;
mutex m_mutex;
event m_canRead;
};
template<typename obj_t_>
class waitQueue2 {
protected:
typedef obj_t_ obj_t;
typedef std::list<obj_t_> list_t;
virtual bool canWriteCheck(list_t const &) { return true; }
public:
void waitWrite() {
m_canWrite.wait_for(-1);
}
bool waitWrite(pfc::eventHandle_t hAbort) {
return event::g_twoEventWait( hAbort, m_canWrite.get_handle(), -1) == 2;
}
eventHandle_t waitWriteHandle() {
return m_canWrite.get_handle();
}
waitQueue2() : m_eof() {
m_canWrite.set_state(true);
}
void put(obj_t const & obj) {
mutexScope guard(m_mutex);
m_list.push_back(obj);
if (m_list.size() == 1) m_canRead.set_state(true);
refreshCanWrite();
}
void put(obj_t && obj) {
mutexScope guard(m_mutex);
m_list.push_back(std::move(obj));
if (m_list.size() == 1) m_canRead.set_state(true);
refreshCanWrite();
}
void set_eof() {
mutexScope guard(m_mutex);
m_eof = true;
m_canRead.set_state(true);
m_canWrite.set_state(false);
}
bool get(obj_t & out) {
for (;; ) {
m_canRead.wait_for(-1);
mutexScope guard(m_mutex);
auto i = m_list.begin();
if (i == m_list.end()) {
if (m_eof) return false;
continue;
}
out = std::move(*i);
m_list.erase(i);
didGet();
return true;
}
}
bool get(obj_t & out, pfc::eventHandle_t hAbort, bool * didAbort = nullptr) {
if (didAbort != nullptr) * didAbort = false;
for (;; ) {
if (pfc::event::g_twoEventWait(hAbort, m_canRead.get_handle(), -1) == 1) {
if (didAbort != nullptr) * didAbort = true;
return false;
}
mutexScope guard(m_mutex);
auto i = m_list.begin();
if (i == m_list.end()) {
if (m_eof) return false;
continue;
}
out = std::move(*i);
m_list.erase(i);
didGet();
return true;
}
}
void clear() {
mutexScope guard(m_mutex);
m_list.clear();
m_eof = false;
m_canRead.set_state(false);
m_canWrite.set_state(true);
}
private:
void didGet() {
if (m_eof) return;
if (m_list.size() == 0) {
m_canRead.set_state(false);
m_canWrite.set_state(true);
} else {
m_canWrite.set_state(canWriteCheck(m_list));
}
}
void refreshCanWrite() {
m_canWrite.set_state( !m_eof && canWriteCheck(m_list));
}
bool m_eof;
std::list<obj_t> m_list;
mutex m_mutex;
event m_canRead, m_canWrite;
};
}

71
pfc/weakRef.h Normal file
View File

@@ -0,0 +1,71 @@
#pragma once
// PFC weakRef class
// Create weak references to objects that automatically become invalidated upon destruction of the object
// Note that this is NOT thread safe and meant for single thread usage. If you require thread safety, provide your own means, such as mutexlocking of weakRef::get() and the destruction of your objects.
#include <memory> // std::shared_ptr
namespace pfc {
typedef std::shared_ptr<const bool> weakRefKillSwitch_t;
template<typename target_t>
class weakRef {
typedef weakRef<target_t> self_t;
public:
static self_t _make(target_t * target, weakRefKillSwitch_t ks) {
self_t ret;
ret.m_target = target;
ret.m_ks = ks;
return ret;
}
bool isValid() const {
return m_ks && !*m_ks;
}
target_t * get() const {
if (!isValid()) return nullptr;
return m_target;
}
target_t * operator() () const {
return get();
}
private:
target_t * m_target = nullptr;
weakRefKillSwitch_t m_ks;
};
template<typename class_t>
class weakRefTarget {
public:
weakRefTarget() {}
typedef weakRef<class_t> weakRef_t;
weakRef<class_t> weakRef() {
PFC_ASSERT(!*m_ks);
class_t * ptr = static_cast<class_t*>(this);
return weakRef_t::_make(ptr, m_ks);
}
// Optional: explicitly invalidates all weak references to this object. Called implicitly by the destructor, but you can do it yourself earlier.
void weakRefShutdown() {
*m_ks = true;
}
~weakRefTarget() {
weakRefShutdown();
}
// Optional: obtain a reference to the killswitch if you wish to use it directly
weakRefKillSwitch_t weakRefKS() const {
return m_ks;
}
private:
std::shared_ptr<bool> m_ks = std::make_shared<bool>(false);
weakRefTarget(const weakRefTarget &) = delete;
void operator=(const weakRefTarget &) = delete;
};
}

50
pfc/wildcard.cpp Normal file
View File

@@ -0,0 +1,50 @@
#include "pfc.h"
static bool test_recur(const char * fn,const char * rm,bool b_sep)
{
for(;;)
{
if ((b_sep && *rm==';') || *rm==0) return *fn==0;
else if (*rm=='*')
{
rm++;
do
{
if (test_recur(fn,rm,b_sep)) return true;
} while(pfc::utf8_advance(fn));
return false;
}
else if (*fn==0) return false;
else if (*rm!='?' && pfc::charLower(pfc::utf8_get_char(fn))!=pfc::charLower(pfc::utf8_get_char(rm))) return false;
fn = pfc::utf8_char_next(fn); rm = pfc::utf8_char_next(rm);
}
}
bool wildcard_helper::test_path(const char * path,const char * pattern,bool b_sep) {return test(path + pfc::scan_filename(path),pattern,b_sep);}
bool wildcard_helper::test(const char * fn,const char * pattern,bool b_sep)
{
if (!b_sep) return test_recur(fn,pattern,false);
const char * rm=pattern;
while(*rm)
{
if (test_recur(fn,rm,true)) return true;
while(*rm && *rm!=';') rm++;
if (*rm==';')
{
while(*rm==';') rm++;
while(*rm==' ') rm++;
}
};
return false;
}
bool wildcard_helper::has_wildcards(const char * str) {return strchr(str,'*') || strchr(str,'?');}
const char * wildcard_helper::get_wildcard_list() {return "*?";}
bool wildcard_helper::is_wildcard(char c) {
return c == '*' || c == '?';
}

10
pfc/wildcard.h Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
namespace wildcard_helper
{
bool test_path(const char * path,const char * pattern,bool b_separate_by_semicolon = false);//will extract filename from path first
bool test(const char * str,const char * pattern,bool b_separate_by_semicolon = false);//tests if str matches pattern
bool has_wildcards(const char * str);
const char * get_wildcard_list();
bool is_wildcard(char c);
};

431
pfc/win-objects.cpp Normal file
View File

@@ -0,0 +1,431 @@
#include "pfc.h"
#include "pp-winapi.h"
#ifdef _WIN32
#include "pfc-fb2k-hooks.h"
namespace pfc {
BOOL winFormatSystemErrorMessageImpl(pfc::string_base & p_out,DWORD p_code) {
switch(p_code) {
case ERROR_CHILD_NOT_COMPLETE:
p_out = "Application cannot be run in Win32 mode.";
return TRUE;
case ERROR_INVALID_ORDINAL:
p_out = "Invalid ordinal.";
return TRUE;
case ERROR_INVALID_STARTING_CODESEG:
p_out = "Invalid code segment.";
return TRUE;
case ERROR_INVALID_STACKSEG:
p_out = "Invalid stack segment.";
return TRUE;
case ERROR_INVALID_MODULETYPE:
p_out = "Invalid module type.";
return TRUE;
case ERROR_INVALID_EXE_SIGNATURE:
p_out = "Invalid executable signature.";
return TRUE;
case ERROR_BAD_EXE_FORMAT:
p_out = "Not a valid Win32 application.";
return TRUE;
case ERROR_EXE_MACHINE_TYPE_MISMATCH:
p_out = "Machine type mismatch.";
return TRUE;
case ERROR_EXE_CANNOT_MODIFY_SIGNED_BINARY:
case ERROR_EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY:
p_out = "Unable to modify a signed binary.";
return TRUE;
default:
{
TCHAR temp[512];
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,p_code,0,temp,_countof(temp),0) == 0) return FALSE;
for(t_size n=0;n<_countof(temp);n++) {
switch(temp[n]) {
case '\n':
case '\r':
temp[n] = ' ';
break;
}
}
p_out = stringcvt::string_utf8_from_os(temp,_countof(temp));
return TRUE;
}
break;
}
}
void winPrefixPath(pfc::string_base & out, const char * p_path) {
if (pfc::string_has_prefix(p_path, "..\\") || strstr(p_path, "\\..\\") ) {
// do not touch relative paths if we somehow got them here
out = p_path;
return;
}
const char * prepend_header = "\\\\?\\";
const char * prepend_header_net = "\\\\?\\UNC\\";
if (pfc::strcmp_partial( p_path, prepend_header ) == 0) { out = p_path; return; }
out.reset();
if (pfc::strcmp_partial(p_path,"\\\\") != 0) {
out << prepend_header << p_path;
} else {
out << prepend_header_net << (p_path+2);
}
};
BOOL winFormatSystemErrorMessage(pfc::string_base & p_out, DWORD p_code) {
return winFormatSystemErrorMessageHook( p_out, p_code );
}
void winUnPrefixPath(pfc::string_base & out, const char * p_path) {
const char * prepend_header = "\\\\?\\";
const char * prepend_header_net = "\\\\?\\UNC\\";
if (pfc::strcmp_partial(p_path, prepend_header_net) == 0) {
out = PFC_string_formatter() << "\\\\" << (p_path + strlen(prepend_header_net) );
return;
}
if (pfc::strcmp_partial(p_path, prepend_header) == 0) {
out = (p_path + strlen(prepend_header));
return;
}
out = p_path;
}
string8 winPrefixPath(const char * in) {
string8 temp; winPrefixPath(temp, in); return temp;
}
string8 winUnPrefixPath(const char * in) {
string8 temp; winUnPrefixPath(temp, in); return temp;
}
} // namespace pfc
format_win32_error::format_win32_error(DWORD p_code) {
pfc::LastErrorRevertScope revert;
if (p_code == 0) m_buffer = "Undefined error";
else if (!pfc::winFormatSystemErrorMessage(m_buffer,p_code)) m_buffer << "Unknown error code (" << (unsigned)p_code << ")";
}
format_hresult::format_hresult(HRESULT p_code) {
if (!pfc::winFormatSystemErrorMessage(m_buffer,(DWORD)p_code)) m_buffer = "Unknown error code";
stamp_hex(p_code);
}
format_hresult::format_hresult(HRESULT p_code, const char * msgOverride) {
m_buffer = msgOverride;
stamp_hex(p_code);
}
void format_hresult::stamp_hex(HRESULT p_code) {
m_buffer << " (0x" << pfc::format_hex((t_uint32)p_code, 8) << ")";
}
#ifdef PFC_WINDOWS_DESKTOP_APP
namespace pfc {
HWND findOwningPopup(HWND p_wnd)
{
HWND walk = p_wnd;
while (walk != 0 && (GetWindowLong(walk, GWL_STYLE) & WS_CHILD) != 0)
walk = GetParent(walk);
return walk ? walk : p_wnd;
}
string8 getWindowClassName(HWND wnd) {
TCHAR temp[1024] = {};
if (GetClassName(wnd, temp, PFC_TABSIZE(temp)) == 0) {
PFC_ASSERT(!"Should not get here");
return "";
}
return pfc::stringcvt::string_utf8_from_os(temp).get_ptr();
}
void setWindowText(HWND wnd, const char * txt) {
SetWindowText(wnd, stringcvt::string_os_from_utf8(txt));
}
string8 getWindowText(HWND wnd) {
PFC_ASSERT(wnd != NULL);
int len = GetWindowTextLength(wnd);
if (len >= 0)
{
len++;
pfc::array_t<TCHAR> temp;
temp.set_size(len);
temp[0] = 0;
if (GetWindowText(wnd, temp.get_ptr(), len) > 0)
{
return stringcvt::string_utf8_from_os(temp.get_ptr(), len).get_ptr();
}
}
return "";
}
}
void uAddWindowStyle(HWND p_wnd,LONG p_style) {
SetWindowLong(p_wnd,GWL_STYLE, GetWindowLong(p_wnd,GWL_STYLE) | p_style);
}
void uRemoveWindowStyle(HWND p_wnd,LONG p_style) {
SetWindowLong(p_wnd,GWL_STYLE, GetWindowLong(p_wnd,GWL_STYLE) & ~p_style);
}
void uAddWindowExStyle(HWND p_wnd,LONG p_style) {
SetWindowLong(p_wnd,GWL_EXSTYLE, GetWindowLong(p_wnd,GWL_EXSTYLE) | p_style);
}
void uRemoveWindowExStyle(HWND p_wnd,LONG p_style) {
SetWindowLong(p_wnd,GWL_EXSTYLE, GetWindowLong(p_wnd,GWL_EXSTYLE) & ~p_style);
}
unsigned MapDialogWidth(HWND p_dialog,unsigned p_value) {
RECT temp;
temp.left = 0; temp.right = p_value; temp.top = temp.bottom = 0;
if (!MapDialogRect(p_dialog,&temp)) return 0;
return temp.right;
}
bool IsKeyPressed(unsigned vk) {
return (GetKeyState(vk) & 0x8000) ? true : false;
}
//! Returns current modifier keys pressed, using win32 MOD_* flags.
unsigned GetHotkeyModifierFlags() {
unsigned ret = 0;
if (IsKeyPressed(VK_CONTROL)) ret |= MOD_CONTROL;
if (IsKeyPressed(VK_SHIFT)) ret |= MOD_SHIFT;
if (IsKeyPressed(VK_MENU)) ret |= MOD_ALT;
if (IsKeyPressed(VK_LWIN) || IsKeyPressed(VK_RWIN)) ret |= MOD_WIN;
return ret;
}
bool CClipboardOpenScope::Open(HWND p_owner) {
Close();
if (OpenClipboard(p_owner)) {
m_open = true;
return true;
} else {
return false;
}
}
void CClipboardOpenScope::Close() {
if (m_open) {
m_open = false;
CloseClipboard();
}
}
CGlobalLockScope::CGlobalLockScope(HGLOBAL p_handle) : m_handle(p_handle), m_ptr(GlobalLock(p_handle)) {
if (m_ptr == NULL) throw std::bad_alloc();
}
CGlobalLockScope::~CGlobalLockScope() {
if (m_ptr != NULL) GlobalUnlock(m_handle);
}
bool IsPointInsideControl(const POINT& pt, HWND wnd) {
HWND walk = WindowFromPoint(pt);
for(;;) {
if (walk == NULL) return false;
if (walk == wnd) return true;
if (GetWindowLong(walk,GWL_STYLE) & WS_POPUP) return false;
walk = GetParent(walk);
}
}
bool IsPopupWindowChildOf(HWND child, HWND parent) {
HWND walk = child;
while (walk != parent && walk != NULL) {
walk = GetParent(walk);
}
return walk == parent;
}
bool IsWindowChildOf(HWND child, HWND parent) {
HWND walk = child;
while(walk != parent && walk != NULL && (GetWindowLong(walk,GWL_STYLE) & WS_CHILD) != 0) {
walk = GetParent(walk);
}
return walk == parent;
}
void ResignActiveWindow(HWND wnd) {
if (IsPopupWindowChildOf(GetActiveWindow(), wnd)) {
HWND parent = GetParent(wnd);
if ( parent != NULL ) SetActiveWindow(parent);
}
}
void win32_menu::release() {
if (m_menu != NULL) {
DestroyMenu(m_menu);
m_menu = NULL;
}
}
void win32_menu::create_popup() {
release();
SetLastError(NO_ERROR);
m_menu = CreatePopupMenu();
if (m_menu == NULL) throw exception_win32(GetLastError());
}
#endif // #ifdef PFC_WINDOWS_DESKTOP_APP
void win32_event::create(bool p_manualreset,bool p_initialstate) {
release();
SetLastError(NO_ERROR);
m_handle = CreateEvent(NULL,p_manualreset ? TRUE : FALSE, p_initialstate ? TRUE : FALSE,NULL);
if (m_handle == NULL) throw exception_win32(GetLastError());
}
void win32_event::release() {
HANDLE temp = detach();
if (temp != NULL) CloseHandle(temp);
}
DWORD win32_event::g_calculate_wait_time(double p_seconds) {
DWORD time = 0;
if (p_seconds> 0) {
time = pfc::rint32(p_seconds * 1000.0);
if (time == 0) time = 1;
} else if (p_seconds < 0) {
time = INFINITE;
}
return time;
}
//! Returns true when signaled, false on timeout
bool win32_event::g_wait_for(HANDLE p_event,double p_timeout_seconds) {
SetLastError(NO_ERROR);
DWORD status = WaitForSingleObject(p_event,g_calculate_wait_time(p_timeout_seconds));
switch(status) {
case WAIT_FAILED:
throw exception_win32(GetLastError());
case WAIT_OBJECT_0:
return true;
case WAIT_TIMEOUT:
return false;
default:
pfc::crash();
}
}
void win32_event::set_state(bool p_state) {
PFC_ASSERT(m_handle != NULL);
if (p_state) SetEvent(m_handle);
else ResetEvent(m_handle);
}
int win32_event::g_twoEventWait( HANDLE ev1, HANDLE ev2, double timeout ) {
HANDLE h[2] = {ev1, ev2};
switch(WaitForMultipleObjects(2, h, FALSE, g_calculate_wait_time( timeout ) )) {
default:
pfc::crash();
case WAIT_TIMEOUT:
return 0;
case WAIT_OBJECT_0:
return 1;
case WAIT_OBJECT_0 + 1:
return 2;
}
}
int win32_event::g_twoEventWait( win32_event & ev1, win32_event & ev2, double timeout ) {
return g_twoEventWait( ev1.get_handle(), ev2.get_handle(), timeout );
}
#ifdef PFC_WINDOWS_DESKTOP_APP
void win32_icon::release() {
HICON temp = detach();
if (temp != NULL) DestroyIcon(temp);
}
void win32_accelerator::load(HINSTANCE p_inst,const TCHAR * p_id) {
release();
SetLastError(NO_ERROR);
m_accel = LoadAccelerators(p_inst,p_id);
if (m_accel == NULL) {
throw exception_win32(GetLastError());
}
}
void win32_accelerator::release() {
if (m_accel != NULL) {
DestroyAcceleratorTable(m_accel);
m_accel = NULL;
}
}
#endif // #ifdef PFC_WINDOWS_DESKTOP_APP
void uSleepSeconds(double p_time,bool p_alertable) {
SleepEx(win32_event::g_calculate_wait_time(p_time),p_alertable ? TRUE : FALSE);
}
#ifdef PFC_WINDOWS_DESKTOP_APP
WORD GetWindowsVersionCode() throw() {
const DWORD ver = GetVersion();
return (WORD)HIBYTE(LOWORD(ver)) | ((WORD)LOBYTE(LOWORD(ver)) << 8);
}
namespace pfc {
bool isShiftKeyPressed() {
return IsKeyPressed(VK_SHIFT);
}
bool isCtrlKeyPressed() {
return IsKeyPressed(VK_CONTROL);
}
bool isAltKeyPressed() {
return IsKeyPressed(VK_MENU);
}
void winSetThreadDescription(HANDLE hThread, const wchar_t * desc) {
#if _WIN32_WINNT >= 0xA00
SetThreadDescription(hThread, desc);
#else
auto proc = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "SetThreadDescription");
if (proc != nullptr) {
typedef HRESULT(__stdcall * pSetThreadDescription_t)(HANDLE hThread, PCWSTR lpThreadDescription);
auto proc2 = reinterpret_cast<pSetThreadDescription_t>(proc);
proc2(hThread, desc);
}
#endif
}
}
#else
// If unknown / not available on this architecture, return false always
namespace pfc {
bool isShiftKeyPressed() {
return false;
}
bool isCtrlKeyPressed() {
return false;
}
bool isAltKeyPressed() {
return false;
}
}
#endif // #ifdef PFC_WINDOWS_DESKTOP_APP
namespace pfc {
void winSleep( double seconds ) {
DWORD ms = INFINITE;
if (seconds > 0) {
ms = rint32(seconds * 1000);
if (ms < 1) ms = 1;
} else if (seconds == 0) {
ms = 0;
}
Sleep(ms);
}
void sleepSeconds(double seconds) {
winSleep(seconds);
}
void yield() {
Sleep(1);
}
}
#endif // _WIN32

341
pfc/win-objects.h Normal file
View File

@@ -0,0 +1,341 @@
#pragma once
namespace pfc {
BOOL winFormatSystemErrorMessage(pfc::string_base & p_out,DWORD p_code);
// Prefix filesystem paths with \\?\ and \\?\UNC where appropriate.
void winPrefixPath(pfc::string_base & out, const char * p_path);
// Reverse winPrefixPath
void winUnPrefixPath(pfc::string_base & out, const char * p_path);
string8 winPrefixPath( const char * in );
string8 winUnPrefixPath( const char * in );
class LastErrorRevertScope {
public:
LastErrorRevertScope() : m_val(GetLastError()) {}
~LastErrorRevertScope() { SetLastError(m_val); }
private:
const DWORD m_val;
};
string8 getWindowText(HWND wnd);
void setWindowText(HWND wnd, const char * txt);
string8 getWindowClassName( HWND wnd );
HWND findOwningPopup(HWND wnd);
}
class format_win32_error {
public:
format_win32_error(DWORD p_code);
const char * get_ptr() const {return m_buffer.get_ptr();}
operator const char*() const {return m_buffer.get_ptr();}
private:
pfc::string8 m_buffer;
};
class format_hresult {
public:
format_hresult(HRESULT p_code);
format_hresult(HRESULT p_code, const char * msgOverride);
const char * get_ptr() const {return m_buffer.get_ptr();}
operator const char*() const {return m_buffer.get_ptr();}
private:
void stamp_hex(HRESULT p_code);
pfc::string_formatter m_buffer;
};
class exception_win32 : public std::exception {
public:
exception_win32(DWORD p_code) : std::exception(format_win32_error(p_code)), m_code(p_code) {}
DWORD get_code() const {return m_code;}
private:
DWORD m_code;
};
#ifdef PFC_WINDOWS_DESKTOP_APP
void uAddWindowStyle(HWND p_wnd,LONG p_style);
void uRemoveWindowStyle(HWND p_wnd,LONG p_style);
void uAddWindowExStyle(HWND p_wnd,LONG p_style);
void uRemoveWindowExStyle(HWND p_wnd,LONG p_style);
unsigned MapDialogWidth(HWND p_dialog,unsigned p_value);
bool IsKeyPressed(unsigned vk);
//! Returns current modifier keys pressed, using win32 MOD_* flags.
unsigned GetHotkeyModifierFlags();
class CClipboardOpenScope {
public:
CClipboardOpenScope() : m_open(false) {}
~CClipboardOpenScope() {Close();}
bool Open(HWND p_owner);
void Close();
private:
bool m_open;
PFC_CLASS_NOT_COPYABLE_EX(CClipboardOpenScope)
};
class CGlobalLockScope {
public:
CGlobalLockScope(HGLOBAL p_handle);
~CGlobalLockScope();
void * GetPtr() const {return m_ptr;}
t_size GetSize() const {return GlobalSize(m_handle);}
private:
void * m_ptr;
HGLOBAL m_handle;
PFC_CLASS_NOT_COPYABLE_EX(CGlobalLockScope)
};
template<typename TItem> class CGlobalLockScopeT {
public:
CGlobalLockScopeT(HGLOBAL handle) : m_scope(handle) {}
TItem * GetPtr() const {return reinterpret_cast<TItem*>(m_scope.GetPtr());}
t_size GetSize() const {
const t_size val = m_scope.GetSize();
PFC_ASSERT( val % sizeof(TItem) == 0 );
return val / sizeof(TItem);
}
private:
CGlobalLockScope m_scope;
};
//! Resigns active window status passing it to the parent window, if wnd or a child popup of is active. \n
//! Use this to mitigate Windows 10 1809 active window handling bugs - call prior to DestroyWindow()
void ResignActiveWindow(HWND wnd);
//! Is point inside a control?
bool IsPointInsideControl(const POINT& pt, HWND wnd);
//! Is <child> a control inside <parent> window? Also returns true if child==parent.
bool IsWindowChildOf(HWND child, HWND parent);
//! Is <child> window a child (popup or control) of <parent> window? Also returns true if child==parent.
bool IsPopupWindowChildOf(HWND child, HWND parent);
class win32_menu {
public:
win32_menu(HMENU p_initval) : m_menu(p_initval) {}
win32_menu() : m_menu(NULL) {}
~win32_menu() {release();}
void release();
void set(HMENU p_menu) {release(); m_menu = p_menu;}
void create_popup();
HMENU get() const {return m_menu;}
HMENU detach() {return pfc::replace_t(m_menu,(HMENU)NULL);}
bool is_valid() const {return m_menu != NULL;}
private:
win32_menu(const win32_menu &) = delete;
void operator=(const win32_menu &) = delete;
HMENU m_menu;
};
#endif
class win32_event {
public:
win32_event() : m_handle(NULL) {}
~win32_event() {release();}
void create(bool p_manualreset,bool p_initialstate);
void set(HANDLE p_handle) {release(); m_handle = p_handle;}
HANDLE get() const {return m_handle;}
HANDLE get_handle() const {return m_handle;}
HANDLE detach() {return pfc::replace_t(m_handle,(HANDLE)NULL);}
bool is_valid() const {return m_handle != NULL;}
void release();
//! Returns true when signaled, false on timeout
bool wait_for(double p_timeout_seconds) {return g_wait_for(get(),p_timeout_seconds);}
static DWORD g_calculate_wait_time(double p_seconds);
//! Returns true when signaled, false on timeout
static bool g_wait_for(HANDLE p_event,double p_timeout_seconds);
void set_state(bool p_state);
bool is_set() { return wait_for(0); }
// Two-wait event functions, return 0 on timeout, 1 on evt1 set, 2 on evt2 set
static int g_twoEventWait( win32_event & ev1, win32_event & ev2, double timeout );
static int g_twoEventWait( HANDLE ev1, HANDLE ev2, double timeout );
private:
win32_event(const win32_event&) = delete;
void operator=(const win32_event &) = delete;
HANDLE m_handle;
};
void uSleepSeconds(double p_time,bool p_alertable);
#ifdef PFC_WINDOWS_DESKTOP_APP
class win32_icon {
public:
win32_icon(HICON p_initval) : m_icon(p_initval) {}
win32_icon() : m_icon(NULL) {}
~win32_icon() {release();}
void release();
void set(HICON p_icon) {release(); m_icon = p_icon;}
HICON get() const {return m_icon;}
HICON detach() {return pfc::replace_t(m_icon,(HICON)NULL);}
bool is_valid() const {return m_icon != NULL;}
private:
win32_icon(const win32_icon&) = delete;
const win32_icon & operator=(const win32_icon &) = delete;
HICON m_icon;
};
class win32_accelerator {
public:
win32_accelerator() : m_accel(NULL) {}
~win32_accelerator() {release();}
HACCEL get() const {return m_accel;}
void load(HINSTANCE p_inst,const TCHAR * p_id);
void release();
private:
HACCEL m_accel;
PFC_CLASS_NOT_COPYABLE_EX(win32_accelerator);
};
class SelectObjectScope {
public:
SelectObjectScope(HDC p_dc,HGDIOBJ p_obj) throw() : m_dc(p_dc), m_obj(SelectObject(p_dc,p_obj)) {}
~SelectObjectScope() throw() {SelectObject(m_dc,m_obj);}
private:
PFC_CLASS_NOT_COPYABLE_EX(SelectObjectScope)
HDC m_dc;
HGDIOBJ m_obj;
};
class OffsetWindowOrgScope {
public:
OffsetWindowOrgScope(HDC dc, const POINT & pt) throw() : m_dc(dc), m_pt(pt) {
OffsetWindowOrgEx(m_dc, m_pt.x, m_pt.y, NULL);
}
~OffsetWindowOrgScope() throw() {
OffsetWindowOrgEx(m_dc, -m_pt.x, -m_pt.y, NULL);
}
private:
const HDC m_dc;
const POINT m_pt;
};
class DCStateScope {
public:
DCStateScope(HDC p_dc) throw() : m_dc(p_dc) {
m_state = SaveDC(m_dc);
}
~DCStateScope() throw() {
RestoreDC(m_dc,m_state);
}
private:
const HDC m_dc;
int m_state;
};
#endif // #ifdef PFC_WINDOWS_DESKTOP_APP
class exception_com : public std::exception {
public:
exception_com(HRESULT p_code) : std::exception(format_hresult(p_code)), m_code(p_code) {}
exception_com(HRESULT p_code, const char * msg) : std::exception(format_hresult(p_code, msg)), m_code(p_code) {}
HRESULT get_code() const {return m_code;}
private:
HRESULT m_code;
};
#ifdef PFC_WINDOWS_DESKTOP_APP
// Same format as _WIN32_WINNT macro.
WORD GetWindowsVersionCode() throw();
#endif
//! Simple implementation of a COM reference counter. The initial reference count is zero, so it can be used with pfc::com_ptr_t<> with plain operator=/constructor rather than attach().
template<typename TBase> class ImplementCOMRefCounter : public TBase {
public:
template<typename ... arg_t> ImplementCOMRefCounter(arg_t && ... arg) : TBase(std::forward<arg_t>(arg) ...) {}
ULONG STDMETHODCALLTYPE AddRef() override {
return ++m_refcounter;
}
ULONG STDMETHODCALLTYPE Release() override {
long val = --m_refcounter;
if (val == 0) delete this;
return val;
}
protected:
virtual ~ImplementCOMRefCounter() {}
private:
pfc::refcounter m_refcounter;
};
template<typename TPtr>
class CoTaskMemObject {
public:
CoTaskMemObject() : m_ptr() {}
~CoTaskMemObject() {CoTaskMemFree(m_ptr);}
void Reset() {CoTaskMemFree(pfc::replace_null_t(m_ptr));}
TPtr * Receive() {Reset(); return &m_ptr;}
TPtr m_ptr;
PFC_CLASS_NOT_COPYABLE(CoTaskMemObject, CoTaskMemObject<TPtr> );
};
namespace pfc {
bool isShiftKeyPressed();
bool isCtrlKeyPressed();
bool isAltKeyPressed();
class winHandle {
public:
winHandle(HANDLE h_ = INVALID_HANDLE_VALUE) : h(h_) {}
~winHandle() { Close(); }
void Close() {
if (h != INVALID_HANDLE_VALUE && h != NULL ) { CloseHandle(h); h = INVALID_HANDLE_VALUE; }
}
void Attach(HANDLE h_) { Close(); h = h_; }
HANDLE Detach() { HANDLE t = h; h = INVALID_HANDLE_VALUE; return t; }
HANDLE Get() const { return h; }
operator HANDLE() const { return h; }
HANDLE h;
private:
winHandle(const winHandle&) = delete;
void operator=(const winHandle&) = delete;
};
void winSleep( double seconds );
void sleepSeconds(double seconds);
void yield();
#ifdef PFC_WINDOWS_DESKTOP_APP
void winSetThreadDescription(HANDLE hThread, const wchar_t * desc);
#if PFC_DEBUG
#define PFC_SET_THREAD_DESCRIPTION(msg) ::pfc::winSetThreadDescription(GetCurrentThread(), L##msg);
#define PFC_SET_THREAD_DESCRIPTION_SUPPORTED
#endif // PFC_DEBUG
#endif // PFC_WINDOWS_DESKTOP_APP
}