mirror of
https://github.com/bkaradzic/bx.git
synced 2026-06-08 03:03:48 +00:00
Added bx::toHuman. (#370)
This commit is contained in:
committed by
GitHub
parent
2b946b4668
commit
a6168a9d1c
@@ -240,9 +240,8 @@ namespace bx
|
||||
|
||||
template<uint16_t MaxCapacityT>
|
||||
inline constexpr FixedStringT<MaxCapacityT>::FixedStringT()
|
||||
: m_len(0)
|
||||
: m_pod{ .storage = { '\0' }, .len = 0 }
|
||||
{
|
||||
m_storage[0] = '\0';
|
||||
}
|
||||
|
||||
template<uint16_t MaxCapacityT>
|
||||
@@ -273,45 +272,51 @@ namespace bx
|
||||
template<uint16_t MaxCapacityT>
|
||||
inline constexpr void FixedStringT<MaxCapacityT>::set(const StringView& _str)
|
||||
{
|
||||
int32_t copied = strCopy(m_storage, MaxCapacityT, _str);
|
||||
m_len = copied;
|
||||
int32_t copied = strCopy(m_pod.storage, MaxCapacityT, _str);
|
||||
m_pod.len = copied;
|
||||
}
|
||||
|
||||
template<uint16_t MaxCapacityT>
|
||||
inline constexpr void FixedStringT<MaxCapacityT>::append(const StringView& _str)
|
||||
{
|
||||
m_len += strCopy(&m_storage[m_len], MaxCapacityT-m_len, _str);
|
||||
m_pod.len += strCopy(&m_pod.storage[m_pod.len], MaxCapacityT-m_pod.len, _str);
|
||||
}
|
||||
|
||||
template<uint16_t MaxCapacityT>
|
||||
inline constexpr void FixedStringT<MaxCapacityT>::clear()
|
||||
{
|
||||
m_len = 0;
|
||||
m_storage[0] = '\0';
|
||||
m_pod.len = 0;
|
||||
m_pod.storage[0] = '\0';
|
||||
}
|
||||
|
||||
template<uint16_t MaxCapacityT>
|
||||
inline constexpr bool FixedStringT<MaxCapacityT>::isEmpty() const
|
||||
{
|
||||
return 0 == m_len;
|
||||
return 0 == m_pod.len;
|
||||
}
|
||||
|
||||
template<uint16_t MaxCapacityT>
|
||||
inline constexpr int32_t FixedStringT<MaxCapacityT>::getLength() const
|
||||
{
|
||||
return m_len;
|
||||
return m_pod.len;
|
||||
}
|
||||
|
||||
template<uint16_t MaxCapacityT>
|
||||
inline constexpr const char* FixedStringT<MaxCapacityT>::getCPtr() const
|
||||
{
|
||||
return m_storage;
|
||||
return m_pod.storage;
|
||||
}
|
||||
|
||||
template<uint16_t MaxCapacityT>
|
||||
inline constexpr FixedStringT<MaxCapacityT>::operator StringView() const
|
||||
{
|
||||
return StringView(m_storage, m_len);
|
||||
return StringView(m_pod.storage, m_pod.len);
|
||||
}
|
||||
|
||||
template<uint16_t MaxCapacityT>
|
||||
inline FixedStringT<MaxCapacityT>::Pod& FixedStringT<MaxCapacityT>::asPod()
|
||||
{
|
||||
return m_pod;
|
||||
}
|
||||
|
||||
template<AllocatorI** AllocatorT>
|
||||
@@ -596,4 +601,52 @@ namespace bx
|
||||
return narrowCastTest(_out, tmp);
|
||||
}
|
||||
|
||||
template<uint16_t MaxCapacityT>
|
||||
inline FixedStringT<MaxCapacityT> toHuman(uint64_t _value)
|
||||
{
|
||||
FixedStringT<MaxCapacityT> result;
|
||||
auto& pod = result.asPod();
|
||||
|
||||
pod.len = formatHumanNumber(pod.storage, MaxCapacityT, double(_value), 0);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
template<uint16_t MaxCapacityT>
|
||||
inline FixedStringT<MaxCapacityT> toHuman(uint64_t _value, Units::Enum _units, uint8_t _numFrac)
|
||||
{
|
||||
FixedStringT<MaxCapacityT> result;
|
||||
auto& pod = result.asPod();
|
||||
|
||||
switch (_units)
|
||||
{
|
||||
case Units::Kilo:
|
||||
pod.len = formatHumanNumber(pod.storage, MaxCapacityT, double(_value), _numFrac, 1000.0, "", " KMGTPEZY");
|
||||
break;
|
||||
|
||||
case Units::KiloByte:
|
||||
pod.len = formatHumanNumber(pod.storage, MaxCapacityT, double(_value), _numFrac, 1000.0, "B", "BkMGTPEZY");
|
||||
break;
|
||||
|
||||
case Units::KibiByte:
|
||||
default:
|
||||
pod.len = formatHumanNumber(pod.storage, MaxCapacityT, double(_value), _numFrac, 1024.0, "iB", "BKMGTPEZY");
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
template<uint16_t MaxCapacityT>
|
||||
inline FixedStringT<MaxCapacityT> toHuman(Ticks _value, uint8_t _numFrac)
|
||||
{
|
||||
FixedStringT<MaxCapacityT> result;
|
||||
auto& pod = result.asPod();
|
||||
|
||||
const double value = toSeconds<double>(_value);
|
||||
pod.len = formatHumanNumber(pod.storage, MaxCapacityT, value, _numFrac, 1000.0, "s", "pnum ", 4);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
} // namespace bx
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace bx
|
||||
}
|
||||
|
||||
inline constexpr Ticks Ticks::operator+ (Ticks _rhs) const { return Ticks(ticks + _rhs.ticks); }
|
||||
inline constexpr Ticks Ticks::operator- ( ) const { return Ticks(-ticks); }
|
||||
inline constexpr Ticks Ticks::operator- (Ticks _rhs) const { return Ticks(ticks - _rhs.ticks); }
|
||||
inline constexpr Ticks Ticks::operator* (float _rhs) const { return Ticks(int64_t(double(ticks * _rhs) ) ); }
|
||||
inline constexpr Ticks& Ticks::operator+=(Ticks _rhs) { ticks += _rhs.ticks; return *this; }
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#define BX_STRING_H_HEADER_GUARD
|
||||
|
||||
#include "allocator.h"
|
||||
#include "timer.h"
|
||||
|
||||
namespace bx
|
||||
{
|
||||
@@ -15,8 +16,9 @@ namespace bx
|
||||
{
|
||||
enum Enum //!< Units:
|
||||
{
|
||||
Kilo, //!< SI units
|
||||
Kibi, //!< IEC prefix
|
||||
Kilo,
|
||||
KiloByte, //!< SI units
|
||||
KibiByte, //!< IEC prefix
|
||||
};
|
||||
};
|
||||
|
||||
@@ -152,6 +154,12 @@ namespace bx
|
||||
class FixedStringT
|
||||
{
|
||||
public:
|
||||
struct Pod
|
||||
{
|
||||
char storage[MaxCapacityT];
|
||||
int32_t len;
|
||||
};
|
||||
|
||||
///
|
||||
constexpr FixedStringT();
|
||||
|
||||
@@ -192,9 +200,12 @@ namespace bx
|
||||
///
|
||||
constexpr operator StringView() const;
|
||||
|
||||
///
|
||||
///
|
||||
Pod& asPod();
|
||||
|
||||
private:
|
||||
char m_storage[MaxCapacityT];
|
||||
int32_t m_len;
|
||||
Pod m_pod;
|
||||
};
|
||||
|
||||
///
|
||||
@@ -458,10 +469,25 @@ namespace bx
|
||||
/// @param[in] _numFrac Number of fraction digits.
|
||||
/// @returns Length of output string.
|
||||
///
|
||||
int32_t formatHumanNumber(char* _out, int32_t _count, double _value, int32_t _numFrac);
|
||||
int32_t formatHumanNumber(char* _out, uint32_t _count, double _value, uint8_t _numFrac, const StringView& _unit = "", char _prefix = ' ');
|
||||
|
||||
///
|
||||
int32_t formatHumanNumber(char* _out, uint32_t _count, double _value, uint8_t _numFrac, double _unitStep, const StringView& _unit, const StringView& _prefix, uint8_t _basePrefix = 0);
|
||||
|
||||
///
|
||||
template<uint16_t MaxCapacityT = 32>
|
||||
FixedStringT<MaxCapacityT> toHuman(uint64_t _value);
|
||||
|
||||
///
|
||||
template<uint16_t MaxCapacityT = 32>
|
||||
FixedStringT<MaxCapacityT> toHuman(uint64_t _value, Units::Enum _units, uint8_t _numFrac = 2);
|
||||
|
||||
///
|
||||
template<uint16_t MaxCapacityT = 32>
|
||||
FixedStringT<MaxCapacityT> toHuman(Ticks _value, uint8_t _numFrac = 4);
|
||||
|
||||
/// Convert size in bytes to human readable string kibi units.
|
||||
int32_t prettify(char* _out, int32_t _count, uint64_t _value, Units::Enum _units = Units::Kibi);
|
||||
int32_t prettify(char* _out, int32_t _count, uint64_t _value, Units::Enum _units = Units::KibiByte);
|
||||
|
||||
/// Converts bool value to string.
|
||||
int32_t toString(char* _out, int32_t _max, bool _value);
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace bx
|
||||
|
||||
/// Binary arithmetic operators.
|
||||
constexpr Ticks operator+ (Ticks _rhs) const;
|
||||
constexpr Ticks operator- () const;
|
||||
constexpr Ticks operator- (Ticks _rhs) const;
|
||||
constexpr Ticks operator* (float _rhs) const;
|
||||
constexpr Ticks& operator+=(Ticks _rhs);
|
||||
|
||||
@@ -1280,7 +1280,7 @@ namespace bx
|
||||
return total;
|
||||
}
|
||||
|
||||
int32_t formatHumanNumber(char* _out, int32_t _count, double _value, int32_t _numFrac)
|
||||
int32_t formatHumanNumber(char* _out, uint32_t _count, double _value, uint8_t _numFrac, const StringView& _unit, char _prefix)
|
||||
{
|
||||
char temp[64];
|
||||
int32_t len = snprintf(temp, sizeof(temp), "%.*f", _numFrac, _value);
|
||||
@@ -1309,7 +1309,7 @@ namespace bx
|
||||
const int32_t commas = (intPartLen > 3) ? (intPartLen - 1) / 3 : 0;
|
||||
const int32_t total = intPartLen + fracPartLen + commas;
|
||||
|
||||
if (_count < total)
|
||||
if (_count < uint32_t(total) )
|
||||
{
|
||||
if (0 < _count)
|
||||
{
|
||||
@@ -1320,7 +1320,15 @@ namespace bx
|
||||
}
|
||||
|
||||
char* out = _out + total;
|
||||
if (_unit.isEmpty()
|
||||
&& ' ' == _prefix)
|
||||
{
|
||||
*out = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(out, _count - total, " %c%S", _prefix, &_unit);
|
||||
}
|
||||
|
||||
if (0 != fracPartLen)
|
||||
{
|
||||
@@ -1344,39 +1352,41 @@ namespace bx
|
||||
return total;
|
||||
}
|
||||
|
||||
static const char s_units[] = { 'B', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' };
|
||||
|
||||
template<uint32_t Kilo, char KiloCh0, char KiloCh1, CharFn fn>
|
||||
inline int32_t prettify(char* _out, int32_t _count, uint64_t _value)
|
||||
int32_t formatHumanNumber(char* _out, uint32_t _count, double _value, uint8_t _numFrac, double _unitStep, const StringView& _unit, const StringView& _prefix, uint8_t _basePrefix)
|
||||
{
|
||||
uint8_t idx = 0;
|
||||
uint8_t idx = _basePrefix;
|
||||
double value = double(_value);
|
||||
while (_value != (_value&0x7ff)
|
||||
&& idx < BX_COUNTOF(s_units) )
|
||||
const double invUnitStep = 1.0/double(_unitStep);
|
||||
const uint8_t numPrefixes = narrowCast<uint8_t>(_prefix.getLength() );
|
||||
|
||||
if (0.0 != _value)
|
||||
{
|
||||
_value /= Kilo;
|
||||
value *= 1.0/double(Kilo);
|
||||
while (value >= _unitStep
|
||||
&& idx < numPrefixes)
|
||||
{
|
||||
value *= invUnitStep;
|
||||
++idx;
|
||||
}
|
||||
|
||||
char human[32];
|
||||
formatHumanNumber(human, sizeof(human), value, 2);
|
||||
while (value < 1.0
|
||||
&& idx > 0)
|
||||
{
|
||||
value *= _unitStep;
|
||||
--idx;
|
||||
}
|
||||
}
|
||||
|
||||
return snprintf(_out, _count, "%s %c%c%c", human
|
||||
, fn(s_units[idx])
|
||||
, idx > 0 ? KiloCh0 : '\0'
|
||||
, KiloCh1
|
||||
);
|
||||
return formatHumanNumber(_out, _count, value, _numFrac, 0 == idx ? "" : _unit, _prefix.getPtr()[idx]);
|
||||
}
|
||||
|
||||
int32_t prettify(char* _out, int32_t _count, uint64_t _value, Units::Enum _units)
|
||||
{
|
||||
if (Units::Kilo == _units)
|
||||
{
|
||||
return prettify<1000, 'B', '\0', toNoop>(_out, _count, _value);
|
||||
return formatHumanNumber(_out, _count, double(_value), 0, 1000.0, "B", "BkMGTPEZY");
|
||||
}
|
||||
|
||||
return prettify<1024, 'i', 'B', toUpper>(_out, _count, _value);
|
||||
return formatHumanNumber(_out, _count, double(_value), 0, 1024.0, "iB", "BKMGTPEZY");
|
||||
}
|
||||
|
||||
} // namespace bx
|
||||
|
||||
@@ -163,26 +163,26 @@ TEST_CASE("HandleHashTable", "")
|
||||
|
||||
bx::StringView sv0("test0");
|
||||
|
||||
bool ok = hm.insert(bx::hash<bx::HashMurmur2A>(sv0), 0);
|
||||
bool ok = hm.insert(bx::hash<bx::HashMurmur3>(sv0), 0);
|
||||
REQUIRE(ok);
|
||||
|
||||
ok = hm.insert(bx::hash<bx::HashMurmur2A>(sv0), 0);
|
||||
ok = hm.insert(bx::hash<bx::HashMurmur3>(sv0), 0);
|
||||
REQUIRE(!ok);
|
||||
REQUIRE(1 == hm.getNumElements() );
|
||||
|
||||
bx::StringView sv1("test1");
|
||||
|
||||
ok = hm.insert(bx::hash<bx::HashMurmur2A>(sv1), 0);
|
||||
ok = hm.insert(bx::hash<bx::HashMurmur3>(sv1), 0);
|
||||
REQUIRE(ok);
|
||||
REQUIRE(2 == hm.getNumElements() );
|
||||
|
||||
hm.removeByHandle(0);
|
||||
REQUIRE(0 == hm.getNumElements() );
|
||||
|
||||
ok = hm.insert(bx::hash<bx::HashMurmur2A>(sv0), 0);
|
||||
ok = hm.insert(bx::hash<bx::HashMurmur3>(sv0), 0);
|
||||
REQUIRE(ok);
|
||||
|
||||
hm.removeByKey(bx::hash<bx::HashMurmur2A>(sv0) );
|
||||
hm.removeByKey(bx::hash<bx::HashMurmur3>(sv0) );
|
||||
REQUIRE(0 == hm.getNumElements() );
|
||||
|
||||
for (uint32_t ii = 0, num = hm.getMaxCapacity(); ii < num; ++ii)
|
||||
|
||||
@@ -26,7 +26,7 @@ TEST_CASE("prettify", "[string]")
|
||||
prettify(tmp, BX_COUNTOF(tmp), 4000, bx::Units::Kilo);
|
||||
REQUIRE(0 == bx::strCmp(tmp, "4 kB") );
|
||||
|
||||
prettify(tmp, BX_COUNTOF(tmp), 4096, bx::Units::Kibi);
|
||||
prettify(tmp, BX_COUNTOF(tmp), 4096, bx::Units::KibiByte);
|
||||
REQUIRE(0 == bx::strCmp(tmp, "4 KiB") );
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user