#pragma once #include #include #include "ps1/system.h" namespace util { /* Misc. template utilities */ template static inline T min(T a, T b) { return (a < b) ? a : b; } template static inline T max(T a, T b) { return (a > b) ? a : b; } template static inline T clamp(T value, T minValue, T maxValue) { return (value < minValue) ? minValue : ((value > maxValue) ? maxValue : value); } // These shall only be used with unsigned types. template static inline T truncateToMultiple(T value, T length) { return value - (value % length); } template static inline T roundUpToMultiple(T value, T length) { T diff = value % length; return diff ? (value - diff + length) : value; } static inline uint16_t swapEndian(uint16_t value) { value = ((value & 0x00ff) << 8) | ((value & 0xff00) >> 8); return value; } static inline uint32_t swapEndian(uint32_t value) { value = ((value & 0x0000ffff) << 16) | ((value & 0xffff0000) >> 16); value = ((value & 0x00ff00ff) << 8) | ((value & 0xff00ff00) >> 8); return value; } template static constexpr inline T forcedCast(X item) { return reinterpret_cast(reinterpret_cast(item)); } /* String hashing (http://www.cse.yorku.ca/~oz/hash.html) */ using Hash = uint32_t; template static constexpr inline Hash hash( const T *const data, size_t length = -1, Hash value = 0 ) { if (*data && length) return hash( &data[1], length - 1, Hash(*data) + (value << 6) + (value << 16) - value ); return value; } Hash hash(const char *str, char terminator = 0); Hash hash(const uint8_t *data, size_t length); /* Simple ring buffer */ template class RingBuffer { private: T _items[N]; size_t _head, _tail; public: size_t length; inline RingBuffer(void) : _head(0), _tail(0), length(0) {} inline T *pushItem(void) volatile { if (length >= N) return nullptr; size_t i = _tail; _tail = (i + 1) % N; length++; return &_items[i]; } inline T *popItem(void) volatile { if (!length) return nullptr; size_t i = _head; _head = (i + 1) % N; length--; return &_items[i]; } inline T *peekItem(void) const { if (!length) return nullptr; return &_items[_head]; } }; /* Tween/animation classes */ static constexpr int TWEEN_UNIT = 1 << 12; class LinearEasing { public: template static inline T apply(T value) { return value; } }; class QuadInEasing { public: template static inline T apply(T value) { return (value * value) / TWEEN_UNIT; } }; class QuadOutEasing { public: template static inline T apply(T value) { return (value * 2) - ((value * value) / TWEEN_UNIT); } }; template class Tween { private: T _base, _delta; int _endTime, _timeScale; public: inline Tween(void) { setValue(static_cast(0)); } inline Tween(T start) { setValue(start); } inline T getValue(int time) const { int remaining = time - _endTime; if (remaining >= 0) return _base + _delta; return _base + ( _delta * E::apply(remaining * _timeScale + TWEEN_UNIT) ) / TWEEN_UNIT; } inline T getTargetValue(void) const { return _base + _delta; } inline bool isDone(int time) const { return time >= _endTime; } inline void setValue(int time, T start, T target, int duration) { //assert(duration <= 0x800); _base = start; _delta = target - start; _endTime = time + duration; _timeScale = TWEEN_UNIT / duration; } inline void setValue(int time, T target, int duration) { setValue(time, getValue(time), target, duration); } inline void setValue(T target) { _base = target; _delta = static_cast(0); _endTime = 0; } }; /* Logger (basically a ring buffer of lines) */ static constexpr int MAX_LOG_LINE_LENGTH = 128; static constexpr int MAX_LOG_LINES = 32; class Logger { private: char _lines[MAX_LOG_LINES][MAX_LOG_LINE_LENGTH]; int _tail; public: bool enableSyslog; // 0 = last line, 1 = second to last, etc. inline const char *getLine(int line) const { return _lines[size_t(_tail - (line + 1)) % MAX_LOG_LINES]; } Logger(void); void clear(void); void log(const char *format, ...); }; extern Logger logger; /* Other APIs */ uint8_t dsCRC8(const uint8_t *data, size_t length); uint16_t zsCRC16(const uint8_t *data, size_t length); size_t hexToString(char *output, const uint8_t *input, size_t length, char sep = 0); size_t serialNumberToString(char *output, const uint8_t *input); size_t encodeBase45(char *output, const uint8_t *input, size_t length); } //#define LOG(...) util::logger.log(__VA_ARGS__) #define LOG(fmt, ...) \ util::logger.log("%s(%d): " fmt, __func__, __LINE__ __VA_OPT__(,) __VA_ARGS__) static constexpr inline util::Hash operator""_h( const char *const literal, size_t length ) { return util::hash(literal, length); }