mirror of
https://github.com/whoahq/whoa.git
synced 2026-03-18 05:31:07 +03:00
feat(util): add initial implementation of WowTime
This commit is contained in:
parent
cd167c54a3
commit
bfcceed8fd
@ -1,6 +1,7 @@
|
||||
file(GLOB PRIVATE_SOURCES
|
||||
"*.cpp"
|
||||
"guid/*.cpp"
|
||||
"time/*.cpp"
|
||||
)
|
||||
|
||||
if(WHOA_SYSTEM_MAC)
|
||||
|
||||
6
src/util/Time.hpp
Normal file
6
src/util/Time.hpp
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef UTIL_TIME_HPP
|
||||
#define UTIL_TIME_HPP
|
||||
|
||||
#include "util/time/WowTime.hpp"
|
||||
|
||||
#endif
|
||||
166
src/util/time/WowTime.cpp
Normal file
166
src/util/time/WowTime.cpp
Normal file
@ -0,0 +1,166 @@
|
||||
#include "util/time/WowTime.hpp"
|
||||
#include <storm/Error.hpp>
|
||||
#include <storm/String.hpp>
|
||||
|
||||
static const char* s_weekdays[] = {
|
||||
"Sun",
|
||||
"Mon",
|
||||
"Tue",
|
||||
"Wed",
|
||||
"Thu",
|
||||
"Fri",
|
||||
"Sat",
|
||||
};
|
||||
|
||||
void WowTime::WowDecodeTime(uint32_t value, int32_t* minute, int32_t* hour, int32_t* weekday, int32_t* monthday, int32_t* month, int32_t* year, int32_t* flags) {
|
||||
// Minute: bits 0-5 (6 bits, max 63)
|
||||
if (minute) {
|
||||
auto m = static_cast<int32_t>(value & 63);
|
||||
*minute = (m == 63) ? -1 : m;
|
||||
}
|
||||
|
||||
// Hour: bits 6-10 (5 bits, max 31)
|
||||
if (hour) {
|
||||
auto h = static_cast<int32_t>((value >> 6) & 31);
|
||||
*hour = (h == 31) ? -1 : h;
|
||||
}
|
||||
|
||||
// Weekday: bits 11-13 (3 bits, max 7)
|
||||
if (weekday) {
|
||||
auto wd = static_cast<int32_t>((value >> 11) & 7);
|
||||
*weekday = (wd == 7) ? -1 : wd;
|
||||
}
|
||||
|
||||
// Month day: bits 14-19 (6 bits, max 63)
|
||||
if (monthday) {
|
||||
auto md = static_cast<int32_t>((value >> 14) & 63);
|
||||
*monthday = (md == 63) ? -1 : md;
|
||||
}
|
||||
|
||||
// Month: bits 20-23 (4 bits, max 15)
|
||||
if (month) {
|
||||
auto mo = static_cast<int32_t>((value >> 20) & 15);
|
||||
*month = (mo == 15) ? -1 : mo;
|
||||
}
|
||||
|
||||
// Year: bits 24-28 (5 bits, max 31)
|
||||
if (year) {
|
||||
auto y = static_cast<int32_t>((value >> 24) & 31);
|
||||
*year = (y == 31) ? -1 : y;
|
||||
}
|
||||
|
||||
// Flags: bits 29-30 (2 bits, max 3)
|
||||
if (flags) {
|
||||
auto f = static_cast<int32_t>((value >> 29) & 3);
|
||||
*flags = (f == 3) ? -1 : f;
|
||||
}
|
||||
}
|
||||
|
||||
void WowTime::WowDecodeTime(uint32_t value, WowTime* time) {
|
||||
WowTime::WowDecodeTime(
|
||||
value,
|
||||
&time->m_minute,
|
||||
&time->m_hour,
|
||||
&time->m_weekday,
|
||||
&time->m_monthday,
|
||||
&time->m_month,
|
||||
&time->m_year,
|
||||
&time->m_flags
|
||||
);
|
||||
}
|
||||
|
||||
void WowTime::WowEncodeTime(uint32_t& value, int32_t minute, int32_t hour, int32_t weekday, int32_t monthday, int32_t month, int32_t year, int32_t flags) {
|
||||
STORM_ASSERT(minute == -1 || (minute >= 0 && minute < 60));
|
||||
STORM_ASSERT(hour == -1 || (hour >= 0 && hour < 24));
|
||||
STORM_ASSERT(weekday == -1 || (weekday >= 0 && weekday < 7));
|
||||
STORM_ASSERT(monthday == -1 || (monthday >= 0 && monthday < 32));
|
||||
STORM_ASSERT(month == -1 || (month >= 0 && month < 12));
|
||||
STORM_ASSERT(year == -1 || year >= 0 && year <= ((1 << 5) - 1));
|
||||
STORM_ASSERT(flags >= 0 && flags <= ((1 << 2) - 1));
|
||||
|
||||
value = ((flags & 3) << 29) // Flags: bits 29-30 (2 bits, max 3)
|
||||
| ((year & 31) << 24) // Year: bits 24-28 (5 bits, max 31)
|
||||
| ((month & 15) << 20) // Month: bits 20-23 (4 bits, max 15)
|
||||
| ((monthday & 63) << 14) // Month day: bits 14-19 (6 bits, max 63)
|
||||
| ((weekday & 7) << 11) // Weekday: bits 11-13 (3 bits, max 7)
|
||||
| ((hour & 31) << 6) // Hour: bits 6-10 (5 bits, max 31)
|
||||
| (minute & 63); // Minute: bits 0-5 (6 bits, max 63)
|
||||
}
|
||||
|
||||
void WowTime::WowEncodeTime(uint32_t& value, const WowTime* time) {
|
||||
WowTime::WowEncodeTime(
|
||||
value,
|
||||
time->m_minute,
|
||||
time->m_hour,
|
||||
time->m_weekday,
|
||||
time->m_monthday,
|
||||
time->m_month,
|
||||
time->m_year,
|
||||
time->m_flags
|
||||
);
|
||||
}
|
||||
|
||||
char* WowTime::WowGetTimeString(WowTime* time, char* str, int32_t len) {
|
||||
uint32_t encoded;
|
||||
WowTime::WowEncodeTime(encoded, time);
|
||||
|
||||
if (encoded == 0) {
|
||||
SStrPrintf(str, len, "Not Set");
|
||||
return str;
|
||||
}
|
||||
|
||||
char yearStr[8];
|
||||
char monthStr[8];
|
||||
char monthdayStr[8];
|
||||
char weekdayStr[8];
|
||||
char hourStr[8];
|
||||
char minuteStr[8];
|
||||
|
||||
if (time->m_year >= 0) {
|
||||
SStrPrintf(yearStr, sizeof(yearStr), "%i", time->m_year + 2000);
|
||||
} else {
|
||||
SStrPrintf(yearStr, sizeof(yearStr), "A");
|
||||
}
|
||||
|
||||
if (time->m_month >= 0) {
|
||||
SStrPrintf(monthStr, sizeof(monthStr), "%i", time->m_month + 1);
|
||||
} else {
|
||||
SStrPrintf(monthStr, sizeof(monthStr), "A");
|
||||
}
|
||||
|
||||
if (time->m_monthday >= 0) {
|
||||
SStrPrintf(monthdayStr, sizeof(monthdayStr), "%i", time->m_monthday + 1);
|
||||
} else {
|
||||
SStrPrintf(monthdayStr, sizeof(monthdayStr), "A");
|
||||
}
|
||||
|
||||
if (time->m_weekday >= 0) {
|
||||
SStrPrintf(weekdayStr, sizeof(weekdayStr), s_weekdays[time->m_weekday]);
|
||||
} else {
|
||||
SStrPrintf(weekdayStr, sizeof(weekdayStr), "Any");
|
||||
}
|
||||
|
||||
if (time->m_hour >= 0) {
|
||||
SStrPrintf(hourStr, sizeof(hourStr), "%i", time->m_hour);
|
||||
} else {
|
||||
SStrPrintf(hourStr, sizeof(hourStr), "A");
|
||||
}
|
||||
|
||||
if (time->m_minute >= 0) {
|
||||
SStrPrintf(minuteStr, sizeof(minuteStr), "%2.2i", time->m_minute);
|
||||
} else {
|
||||
SStrPrintf(minuteStr, sizeof(minuteStr), "A");
|
||||
}
|
||||
|
||||
SStrPrintf(str, len, "%s/%s/%s (%s) %s:%s", monthStr, monthdayStr, yearStr, weekdayStr, hourStr, minuteStr);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
int32_t WowTime::GetHourAndMinutes() {
|
||||
if (this->m_hour < 0 || this->m_minute < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return this->m_hour * 60 + this->m_minute;
|
||||
}
|
||||
29
src/util/time/WowTime.hpp
Normal file
29
src/util/time/WowTime.hpp
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef UTIL_TIME_WOW_TIME_HPP
|
||||
#define UTIL_TIME_WOW_TIME_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
class WowTime {
|
||||
public:
|
||||
// Static functions
|
||||
static void WowDecodeTime(uint32_t value, int32_t* minute, int32_t* hour, int32_t* weekday, int32_t* monthday, int32_t* month, int32_t* year, int32_t* flags);
|
||||
static void WowDecodeTime(uint32_t value, WowTime* time);
|
||||
static void WowEncodeTime(uint32_t& value, int32_t minute, int32_t hour, int32_t weekday, int32_t monthday, int32_t month, int32_t year, int32_t flags);
|
||||
static void WowEncodeTime(uint32_t& value, const WowTime* time);
|
||||
static char* WowGetTimeString(WowTime* time, char* str, int32_t len);
|
||||
|
||||
// Member variables
|
||||
int32_t m_minute = -1;
|
||||
int32_t m_hour = -1;
|
||||
int32_t m_weekday = -1;
|
||||
int32_t m_monthday = -1;
|
||||
int32_t m_month = -1;
|
||||
int32_t m_year = -1;
|
||||
int32_t m_flags = 0x0;
|
||||
int32_t m_holidayOffset = 0;
|
||||
|
||||
// Member functions
|
||||
int32_t GetHourAndMinutes();
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -5,6 +5,7 @@ if(WHOA_SYSTEM_MAC)
|
||||
"gx/*.cpp"
|
||||
"gx/font/*.cpp"
|
||||
"util/*.cpp"
|
||||
"util/time/*.cpp"
|
||||
)
|
||||
|
||||
set_source_files_properties(${PRIVATE_SOURCES}
|
||||
|
||||
146
test/util/time/WowTime.cpp
Normal file
146
test/util/time/WowTime.cpp
Normal file
@ -0,0 +1,146 @@
|
||||
#include "util/time/WowTime.hpp"
|
||||
#include "catch.hpp"
|
||||
#include "storm/String.hpp"
|
||||
|
||||
TEST_CASE("WowTime::WowTime", "[util]") {
|
||||
SECTION("constructs correctly") {
|
||||
WowTime time;
|
||||
|
||||
CHECK(time.m_minute == -1);
|
||||
CHECK(time.m_hour == -1);
|
||||
CHECK(time.m_weekday == -1);
|
||||
CHECK(time.m_monthday == -1);
|
||||
CHECK(time.m_month == -1);
|
||||
CHECK(time.m_year == -1);
|
||||
CHECK(time.m_flags == 0x0);
|
||||
CHECK(time.m_holidayOffset == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("WowTime::WowDecodeTime", "[util]") {
|
||||
SECTION("decodes 1234567890 as expected") {
|
||||
uint32_t value = 1234567890;
|
||||
WowTime time;
|
||||
|
||||
WowTime::WowDecodeTime(value, &time.m_minute, &time.m_hour, &time.m_weekday, &time.m_monthday, &time.m_month, &time.m_year, &time.m_flags);
|
||||
|
||||
CHECK(time.m_minute == 18);
|
||||
CHECK(time.m_hour == 11);
|
||||
CHECK(time.m_weekday == 0);
|
||||
CHECK(time.m_monthday == 24);
|
||||
CHECK(time.m_month == 9);
|
||||
CHECK(time.m_year == 9);
|
||||
CHECK(time.m_flags == 0x2);
|
||||
}
|
||||
|
||||
SECTION("decodes 0xFFFFFFFF as expected") {
|
||||
uint32_t value = 0xFFFFFFFF;
|
||||
WowTime time;
|
||||
|
||||
WowTime::WowDecodeTime(value, &time.m_minute, &time.m_hour, &time.m_weekday, &time.m_monthday, &time.m_month, &time.m_year, &time.m_flags);
|
||||
|
||||
CHECK(time.m_minute == -1);
|
||||
CHECK(time.m_hour == -1);
|
||||
CHECK(time.m_weekday == -1);
|
||||
CHECK(time.m_monthday == -1);
|
||||
CHECK(time.m_month == -1);
|
||||
CHECK(time.m_year == -1);
|
||||
CHECK(time.m_flags == -1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("WowTime::WowEncodeTime", "[util]") {
|
||||
SECTION("encodes 10/25/2009 (Sun) 11:18 with flag 0x2 set as expected") {
|
||||
uint32_t value = 0;
|
||||
|
||||
WowTime time;
|
||||
time.m_minute = 18;
|
||||
time.m_hour = 11;
|
||||
time.m_weekday = 0;
|
||||
time.m_monthday = 24;
|
||||
time.m_month = 9;
|
||||
time.m_year = 9;
|
||||
time.m_flags = 0x2;
|
||||
|
||||
WowTime::WowEncodeTime(value, &time);
|
||||
|
||||
REQUIRE(value == 1234567890);
|
||||
}
|
||||
|
||||
SECTION("encodes empty time as expected") {
|
||||
uint32_t value = 0;
|
||||
WowTime time;
|
||||
|
||||
WowTime::WowEncodeTime(value, &time);
|
||||
|
||||
REQUIRE(value == 0x1FFFFFFF);
|
||||
}
|
||||
|
||||
SECTION("encodes, decodes, and reencodes as expected") {
|
||||
uint32_t value = 0;
|
||||
|
||||
WowTime time1;
|
||||
time1.m_minute = 18;
|
||||
time1.m_hour = 11;
|
||||
time1.m_weekday = 0;
|
||||
time1.m_monthday = 24;
|
||||
time1.m_month = 9;
|
||||
time1.m_year = 9;
|
||||
time1.m_flags = 0x2;
|
||||
|
||||
WowTime time2;
|
||||
|
||||
CHECK(time2.m_minute != time1.m_minute);
|
||||
CHECK(time2.m_hour != time1.m_hour);
|
||||
CHECK(time2.m_weekday != time1.m_weekday);
|
||||
CHECK(time2.m_monthday != time1.m_monthday);
|
||||
CHECK(time2.m_month != time1.m_month);
|
||||
CHECK(time2.m_year != time1.m_year);
|
||||
CHECK(time2.m_flags != time1.m_flags);
|
||||
|
||||
WowTime::WowEncodeTime(value, &time1);
|
||||
WowTime::WowDecodeTime(value, &time2);
|
||||
|
||||
CHECK(time2.m_minute == time1.m_minute);
|
||||
CHECK(time2.m_hour == time1.m_hour);
|
||||
CHECK(time2.m_weekday == time1.m_weekday);
|
||||
CHECK(time2.m_monthday == time1.m_monthday);
|
||||
CHECK(time2.m_month == time1.m_month);
|
||||
CHECK(time2.m_year == time1.m_year);
|
||||
CHECK(time2.m_flags == time1.m_flags);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("WowTime::WowGetTimeString", "[util]") {
|
||||
SECTION("gets expected string") {
|
||||
WowTime time;
|
||||
time.m_minute = 18;
|
||||
time.m_hour = 11;
|
||||
time.m_weekday = 0;
|
||||
time.m_monthday = 24;
|
||||
time.m_month = 9;
|
||||
time.m_year = 9;
|
||||
time.m_flags = 0x2;
|
||||
|
||||
char buf[128];
|
||||
auto timeStr = WowTime::WowGetTimeString(&time, buf, sizeof(buf));
|
||||
|
||||
REQUIRE(!SStrCmp(timeStr, "10/25/2009 (Sun) 11:18"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("WowTime::GetHourAndMinutes", "[util]") {
|
||||
SECTION("gets expected hour and minutes for default constructed time") {
|
||||
WowTime time;
|
||||
|
||||
REQUIRE(time.GetHourAndMinutes() == 0);
|
||||
}
|
||||
|
||||
SECTION("gets expected hour and minutes for 11:18") {
|
||||
WowTime time;
|
||||
time.m_minute = 18;
|
||||
time.m_hour = 11;
|
||||
|
||||
REQUIRE(time.GetHourAndMinutes() == 11 * 60 + 18);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user