xenia/third_party/crunch/crnlib/crn_value.h

1026 lines
24 KiB
C++

// File: crn_value.h
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
#include "crn_strutils.h"
#include "crn_dynamic_string.h"
#include "crn_vec.h"
namespace crnlib
{
enum value_data_type
{
cDTInvalid,
cDTString,
cDTBool,
cDTInt,
cDTUInt,
cDTFloat,
cDTVec3F,
cDTVec3I,
cDTTotal
};
extern const char* gValueDataTypeStrings[cDTTotal + 1];
class value
{
public:
value() :
m_type(cDTInvalid)
{
}
value(const char* pStr) :
m_pStr(crnlib_new<dynamic_string>(pStr)), m_type(cDTString)
{
}
value(const dynamic_string& str) :
m_pStr(crnlib_new<dynamic_string>(str)), m_type(cDTString)
{
}
explicit value(bool v) :
m_bool(v), m_type(cDTBool)
{
}
value(int v) :
m_int(v), m_type(cDTInt)
{
}
value(uint v) :
m_uint(v), m_type(cDTUInt)
{
}
value(float v) :
m_float(v), m_type(cDTFloat)
{
}
value(const vec3F& v) :
m_pVec3F(crnlib_new<vec3F>(v)), m_type(cDTVec3F)
{
}
value(const vec3I& v) :
m_pVec3I(crnlib_new<vec3I>(v)), m_type(cDTVec3I)
{
}
~value()
{
switch (m_type)
{
case cDTString:
crnlib_delete(m_pStr);
break;
case cDTVec3F:
crnlib_delete(m_pVec3F);
break;
case cDTVec3I:
crnlib_delete(m_pVec3I);
break;
default:
break;
}
}
value(const value& other) :
m_type(cDTInvalid)
{
*this = other;
}
value& operator= (const value& other)
{
if (this == &other)
return *this;
change_type(other.m_type);
switch (other.m_type)
{
case cDTString: m_pStr->set(*other.m_pStr); break;
case cDTBool: m_bool = other.m_bool; break;
case cDTInt: m_int = other.m_int; break;
case cDTUInt: m_uint = other.m_uint; break;
case cDTFloat: m_float = other.m_float; break;
case cDTVec3F: m_pVec3F->set(*other.m_pVec3F); break;
case cDTVec3I: m_pVec3I->set(*other.m_pVec3I); break;
default: break;
}
return *this;
}
inline value_data_type get_data_type() const { return m_type; }
void clear()
{
clear_dynamic();
m_type = cDTInvalid;
}
void set_string(const char* pStr)
{
set_str(pStr);
}
void set_int(int v)
{
clear_dynamic();
m_type = cDTInt;
m_int = v;
}
void set_uint(uint v)
{
clear_dynamic();
m_type = cDTUInt;
m_uint = v;
}
void set_bool(bool v)
{
clear_dynamic();
m_type = cDTBool;
m_bool = v;
}
void set_float(float v)
{
clear_dynamic();
m_type = cDTFloat;
m_float = v;
}
void set_vec(const vec3F& v)
{
change_type(cDTVec3F);
m_pVec3F->set(v);
}
void set_vec(const vec3I& v)
{
change_type(cDTVec3I);
m_pVec3I->set(v);
}
bool parse(const char* p)
{
if ((!p) || (!p[0]))
{
clear();
return false;
}
if (_stricmp(p, "false") == 0)
{
set_bool(false);
return true;
}
else if (_stricmp(p, "true") == 0)
{
set_bool(true);
return true;
}
if (p[0] == '\"')
{
dynamic_string str;
str = p + 1;
if (!str.is_empty())
{
if (str[str.get_len() - 1] == '\"')
{
str.left(str.get_len() - 1);
set_str(str);
return true;
}
}
}
if (strchr(p, ',') != NULL)
{
float fx = 0, fy = 0, fz = 0;
#ifdef _MSC_VER
if (sscanf_s(p, "%f,%f,%f", &fx, &fy, &fz) == 3)
#else
if (sscanf(p, "%f,%f,%f", &fx, &fy, &fz) == 3)
#endif
{
bool as_float = true;
int ix = 0, iy = 0, iz = 0;
#ifdef _MSC_VER
if (sscanf_s(p, "%i,%i,%i", &ix, &iy, &iz) == 3)
#else
if (sscanf(p, "%i,%i,%i", &ix, &iy, &iz) == 3)
#endif
{
if ((ix == fx) && (iy == fy) && (iz == fz))
as_float = false;
}
if (as_float)
set_vec(vec3F(fx, fy, fz));
else
set_vec(vec3I(ix, iy, iz));
return true;
}
}
const char* q = p;
bool success = string_to_uint(q, m_uint);
if ((success) && (*q == 0))
{
set_uint(m_uint);
return true;
}
q = p;
success = string_to_int(q, m_int);
if ((success) && (*q == 0))
{
set_int(m_int);
return true;
}
q = p;
success = string_to_float(q, m_float);
if ((success) && (*q == 0))
{
set_float(m_float);
return true;
}
set_string(p);
return true;
}
dynamic_string& get_as_string(dynamic_string& dst) const
{
switch (m_type)
{
case cDTInvalid: dst.clear(); break;
case cDTString: dst = *m_pStr; break;
case cDTBool: dst = m_bool ? "TRUE" : "FALSE"; break;
case cDTInt: dst.format("%i", m_int); break;
case cDTUInt: dst.format("%u", m_uint); break;
case cDTFloat: dst.format("%f", m_float); break;
case cDTVec3F: dst.format("%f,%f,%f", (*m_pVec3F)[0], (*m_pVec3F)[1], (*m_pVec3F)[2]); break;
case cDTVec3I: dst.format("%i,%i,%i", (*m_pVec3I)[0], (*m_pVec3I)[1], (*m_pVec3I)[2]); break;
default: break;
}
return dst;
}
bool get_as_int(int& val, uint component = 0) const
{
switch (m_type)
{
case cDTInvalid:
{
val = 0;
return false;
}
case cDTString:
{
const char* p = m_pStr->get_ptr();
return string_to_int(p, val);
}
case cDTBool: val = m_bool; break;
case cDTInt: val = m_int; break;
case cDTUInt:
{
if (m_uint > INT_MAX)
{
val = 0;
return false;
}
val = m_uint;
break;
}
case cDTFloat:
{
if ((m_float < INT_MIN) || (m_float > INT_MAX))
{
val = 0;
return false;
}
val = (int)m_float;
break;
}
case cDTVec3F:
{
if (component > 2)
{
val = 0;
return false;
}
if (((*m_pVec3F)[component] < INT_MIN) || ((*m_pVec3F)[component] > INT_MAX))
{
val = 0;
return false;
}
val = (int)(*m_pVec3F)[component];
break;
}
case cDTVec3I:
{
if (component > 2)
{
val = 0;
return false;
}
val = (int)(*m_pVec3I)[component];
break;
}
default: break;
}
return true;
}
bool get_as_uint(uint& val, uint component = 0) const
{
switch (m_type)
{
case cDTInvalid:
{
val = 0;
return false;
}
case cDTString:
{
const char* p = m_pStr->get_ptr();
return string_to_uint(p, val);
}
case cDTBool:
{
val = m_bool;
break;
}
case cDTInt:
{
if (m_int < 0)
{
val = 0;
return false;
}
val = (uint)m_int;
break;
}
case cDTUInt:
{
val = m_uint;
break;
}
case cDTFloat:
{
if ((m_float < 0) || (m_float > UINT_MAX))
{
val = 0;
return false;
}
val = (uint)m_float;
break;
}
case cDTVec3F:
{
if (component > 2)
{
val = 0;
return false;
}
if (((*m_pVec3F)[component] < 0) || ((*m_pVec3F)[component] > UINT_MAX))
{
val = 0;
return false;
}
val = (uint)(*m_pVec3F)[component];
break;
}
case cDTVec3I:
{
if (component > 2)
{
val = 0;
return false;
}
if ((*m_pVec3I)[component] < 0)
{
val = 0;
return false;
}
val = (uint)(*m_pVec3I)[component];
break;
}
default: break;
}
return true;
}
bool get_as_bool(bool& val, uint component = 0) const
{
switch (m_type)
{
case cDTInvalid:
{
val = false;
return false;
}
case cDTString:
{
const char* p = m_pStr->get_ptr();
return string_to_bool(p, val);
}
case cDTBool:
{
val = m_bool;
break;
}
case cDTInt:
{
val = (m_int != 0);
break;
}
case cDTUInt:
{
val = (m_uint != 0);
break;
}
case cDTFloat:
{
val = (m_float != 0);
break;
}
case cDTVec3F:
{
if (component > 2)
{
val = false;
return false;
}
val = ((*m_pVec3F)[component] != 0);
break;
}
case cDTVec3I:
{
if (component > 2)
{
val = false;
return false;
}
val = ((*m_pVec3I)[component] != 0);
break;
}
default: break;
}
return true;
}
bool get_as_float(float& val, uint component = 0) const
{
switch (m_type)
{
case cDTInvalid:
{
val = 0;
return false;
}
case cDTString:
{
const char* p = m_pStr->get_ptr();
return string_to_float(p, val);
}
case cDTBool:
{
val = m_bool;
break;
}
case cDTInt:
{
val = (float)m_int;
break;
}
case cDTUInt:
{
val = (float)m_uint;
break;
}
case cDTFloat:
{
val = m_float;
break;
}
case cDTVec3F:
{
if (component > 2)
{
val = 0;
return false;
}
val = (*m_pVec3F)[component];
break;
}
case cDTVec3I:
{
if (component > 2)
{
val = 0;
return false;
}
val = (float)(*m_pVec3I)[component];
break;
}
default: break;
}
return true;
}
bool get_as_vec(vec3F& val) const
{
switch (m_type)
{
case cDTInvalid:
{
val.clear();
return false;
}
case cDTString:
{
const char* p = m_pStr->get_ptr();
float x = 0, y = 0, z = 0;
#ifdef _MSC_VER
if (sscanf_s(p, "%f,%f,%f", &x, &y, &z) == 3)
#else
if (sscanf(p, "%f,%f,%f", &x, &y, &z) == 3)
#endif
{
val.set(x, y, z);
return true;
}
else
{
val.clear();
return false;
}
}
case cDTBool:
{
val.set(m_bool);
break;
}
case cDTInt:
{
val.set(static_cast<float>(m_int));
break;
}
case cDTUInt:
{
val.set(static_cast<float>(m_uint));
break;
}
case cDTFloat:
{
val.set(m_float);
break;
}
case cDTVec3F:
{
val = *m_pVec3F;
break;
}
case cDTVec3I:
{
val.set((float)(*m_pVec3I)[0], (float)(*m_pVec3I)[1], (float)(*m_pVec3I)[2]);
break;
}
default: break;
}
return true;
}
bool get_as_vec(vec3I& val) const
{
switch (m_type)
{
case cDTInvalid:
{
val.clear();
return false;
}
case cDTString:
{
const char* p = m_pStr->get_ptr();
float x = 0, y = 0, z = 0;
#ifdef _MSC_VER
if (sscanf_s(p, "%f,%f,%f", &x, &y, &z) == 3)
#else
if (sscanf(p, "%f,%f,%f", &x, &y, &z) == 3)
#endif
{
if ((x < INT_MIN) || (x > INT_MAX) || (y < INT_MIN) || (y > INT_MAX) || (z < INT_MIN) || (z > INT_MAX))
{
val.clear();
return false;
}
val.set((int)x, (int)y, (int)z);
return true;
}
else
{
val.clear();
return false;
}
break;
}
case cDTBool:
{
val.set(m_bool);
break;
}
case cDTInt:
{
val.set(m_int);
break;
}
case cDTUInt:
{
val.set(m_uint);
break;
}
case cDTFloat:
{
val.set((int)m_float);
break;
}
case cDTVec3F:
{
val.set((int)(*m_pVec3F)[0], (int)(*m_pVec3F)[1], (int)(*m_pVec3F)[2]);
break;
}
case cDTVec3I:
{
val = *m_pVec3I;
break;
}
default: break;
}
return true;
}
bool set_zero()
{
switch (m_type)
{
case cDTInvalid:
{
return false;
}
case cDTString:
{
m_pStr->empty();
break;
}
case cDTBool:
{
m_bool = false;
break;
}
case cDTInt:
{
m_int = 0;
break;
}
case cDTUInt:
{
m_uint = 0;
break;
}
case cDTFloat:
{
m_float = 0;
break;
}
case cDTVec3F:
{
m_pVec3F->clear();
break;
}
case cDTVec3I:
{
m_pVec3I->clear();
break;
}
default: break;
}
return true;
}
bool is_vector() const
{
switch (m_type)
{
case cDTVec3F:
case cDTVec3I:
return true;
default: break;
}
return false;
}
uint get_num_components() const
{
switch (m_type)
{
case cDTVec3F:
case cDTVec3I:
return 3;
default: break;
}
return 1;
}
bool is_numeric() const
{
switch (m_type)
{
case cDTInt:
case cDTUInt:
case cDTFloat:
case cDTVec3F:
case cDTVec3I:
return true;
default: break;
}
return false;
}
bool is_float() const
{
switch (m_type)
{
case cDTFloat:
case cDTVec3F:
return true;
default: break;
}
return false;
}
bool is_integer() const
{
switch (m_type)
{
case cDTInt:
case cDTUInt:
case cDTVec3I:
return true;
default: break;
}
return false;
}
bool is_signed() const
{
switch (m_type)
{
case cDTInt:
case cDTFloat:
case cDTVec3F:
case cDTVec3I:
return true;
default: break;
}
return false;
}
bool is_string() const
{
return m_type == cDTString;
}
int serialize(void* pBuf, uint buf_size, bool little_endian) const
{
uint buf_left = buf_size;
uint8 t = (uint8)m_type;
if (!utils::write_obj(t, pBuf, buf_left, little_endian)) return -1;
switch (m_type)
{
case cDTString:
{
int bytes_written = m_pStr->serialize(pBuf, buf_left, little_endian);
if (bytes_written < 0) return -1;
pBuf = static_cast<uint8*>(pBuf) + bytes_written;
buf_left -= bytes_written;
break;
}
case cDTBool:
{
if (!utils::write_obj(m_bool, pBuf, buf_left, little_endian)) return -1;
break;
}
case cDTInt:
case cDTUInt:
case cDTFloat:
{
if (!utils::write_obj(m_float, pBuf, buf_left, little_endian)) return -1;
break;
}
case cDTVec3F:
{
for (uint i = 0; i < 3; i++)
if (!utils::write_obj((*m_pVec3F)[i], pBuf, buf_left, little_endian)) return -1;
break;
}
case cDTVec3I:
{
for (uint i = 0; i < 3; i++)
if (!utils::write_obj((*m_pVec3I)[i], pBuf, buf_left, little_endian)) return -1;
break;
}
default: break;
}
return buf_size - buf_left;
}
int deserialize(const void* pBuf, uint buf_size, bool little_endian)
{
uint buf_left = buf_size;
uint8 t;
if (!utils::read_obj(t, pBuf, buf_left, little_endian)) return -1;
if (t >= cDTTotal)
return -1;
m_type = static_cast<value_data_type>(t);
switch (m_type)
{
case cDTString:
{
change_type(cDTString);
int bytes_read = m_pStr->deserialize(pBuf, buf_left, little_endian);
if (bytes_read < 0) return -1;
pBuf = static_cast<const uint8*>(pBuf) + bytes_read;
buf_left -= bytes_read;
break;
}
case cDTBool:
{
if (!utils::read_obj(m_bool, pBuf, buf_left, little_endian)) return -1;
break;
}
case cDTInt:
case cDTUInt:
case cDTFloat:
{
if (!utils::read_obj(m_float, pBuf, buf_left, little_endian)) return -1;
break;
}
case cDTVec3F:
{
change_type(cDTVec3F);
for (uint i = 0; i < 3; i++)
if (!utils::read_obj((*m_pVec3F)[i], pBuf, buf_left, little_endian)) return -1;
break;
}
case cDTVec3I:
{
change_type(cDTVec3I);
for (uint i = 0; i < 3; i++)
if (!utils::read_obj((*m_pVec3I)[i], pBuf, buf_left, little_endian)) return -1;
break;
}
default: break;
}
return buf_size - buf_left;
}
void swap(value& other)
{
for (uint i = 0; i < cUnionSize; i++)
std::swap(m_union[i], other.m_union[i]);
std::swap(m_type, other.m_type);
}
private:
void clear_dynamic()
{
if (m_type == cDTVec3F)
{
crnlib_delete(m_pVec3F);
m_pVec3F = NULL;
m_type = cDTInvalid;
}
else if (m_type == cDTVec3I)
{
crnlib_delete(m_pVec3I);
m_pVec3I = NULL;
m_type = cDTInvalid;
}
else if (m_type == cDTString)
{
crnlib_delete(m_pStr);
m_pStr = NULL;
m_type = cDTInvalid;
}
}
void change_type(value_data_type type)
{
if (type != m_type)
{
clear_dynamic();
m_type = type;
switch (m_type)
{
case cDTString:
m_pStr = crnlib_new<dynamic_string>();
break;
case cDTVec3F:
m_pVec3F = crnlib_new<vec3F>();
break;
case cDTVec3I:
m_pVec3I = crnlib_new<vec3I>();
break;
default: break;
}
}
}
void set_str(const dynamic_string& s)
{
if (m_type == cDTString)
m_pStr->set(s);
else
{
clear_dynamic();
m_type = cDTString;
m_pStr = crnlib_new<dynamic_string>(s);
}
}
void set_str(const char* p)
{
if (m_type == cDTString)
m_pStr->set(p);
else
{
clear_dynamic();
m_type = cDTString;
m_pStr = crnlib_new<dynamic_string>(p);
}
}
enum { cUnionSize = 1 };
union
{
bool m_bool;
int m_int;
uint m_uint;
float m_float;
vec3F* m_pVec3F;
vec3I* m_pVec3I;
dynamic_string* m_pStr;
uint m_union[cUnionSize];
};
value_data_type m_type;
};
} // namespace crnlib