mirror of
https://github.com/holub/mame
synced 2025-04-22 00:11:58 +03:00
Introduced an 'util::arbitrary_clock' template class, to represent a clock that "knows" when the epoch starts (#2010)
* Introduced an 'util::arbitrary_clock' template class, to represent a clock that "knows" when the epoch starts Also: - Converted the NTFS filetime code to use util::arbitrary_clock - Converted the Mac datetime code to use util::atribrary_clock This is in preparation for a bigger change to Imgtool where I eliminate usage of time_t
This commit is contained in:
parent
ee19701c2c
commit
f809f0e08d
@ -58,39 +58,6 @@ uint32_t bcd_2_dec(uint32_t a)
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
GREGORIAN CALENDAR HELPERS
|
||||
***************************************************************************/
|
||||
|
||||
int gregorian_is_leap_year(int year)
|
||||
{
|
||||
return !((year % 100) ? (year % 4) : (year % 400));
|
||||
}
|
||||
|
||||
|
||||
/* months are one counted */
|
||||
|
||||
/**
|
||||
* @fn int gregorian_days_in_month(int month, int year)
|
||||
*
|
||||
* @brief Gregorian days in month.
|
||||
*
|
||||
* @param month The month.
|
||||
* @param year The year.
|
||||
*
|
||||
* @return An int.
|
||||
*/
|
||||
|
||||
int gregorian_days_in_month(int month, int year)
|
||||
{
|
||||
assert(month >= 1 && month <= 12);
|
||||
|
||||
int days[] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
|
||||
days[1] += gregorian_is_leap_year(year) ? 1 : 0;
|
||||
return days[month-1];
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
MISC
|
||||
***************************************************************************/
|
||||
|
@ -29,8 +29,48 @@ uint32_t bcd_2_dec(uint32_t a);
|
||||
GREGORIAN CALENDAR HELPERS
|
||||
***************************************************************************/
|
||||
|
||||
int gregorian_is_leap_year(int year);
|
||||
int gregorian_days_in_month(int month, int year);
|
||||
constexpr bool gregorian_is_leap_year(int year)
|
||||
{
|
||||
return !((year % 100) ? (year % 4) : (year % 400));
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// gregorian_days_in_month - given a year and a one-counted
|
||||
// month, return the amount of days in that month
|
||||
//-------------------------------------------------
|
||||
|
||||
inline int gregorian_days_in_month(int month, int year)
|
||||
{
|
||||
int result;
|
||||
switch (month)
|
||||
{
|
||||
case 4: case 6:
|
||||
case 9: case 11:
|
||||
// Thirty days have September, April, June, and November.
|
||||
result = 30;
|
||||
break;
|
||||
|
||||
case 1: case 3:
|
||||
case 5: case 7:
|
||||
case 8: case 10:
|
||||
case 12:
|
||||
// All the rest have Thirty One
|
||||
result = 31;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// No exceptions, but save one: Twenty Eight hath February
|
||||
// in fine, and each leap year Twenty Nine
|
||||
result = gregorian_is_leap_year(year) ? 29 : 28;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
|
@ -14,47 +14,48 @@
|
||||
|
||||
|
||||
namespace util {
|
||||
namespace {
|
||||
/***************************************************************************
|
||||
PROTOTYPES
|
||||
***************************************************************************/
|
||||
|
||||
util::ntfs_duration calculate_ntfs_offset();
|
||||
static std::chrono::system_clock::duration calculate_system_clock_adjustment();
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
GLOBAL VARIABLES
|
||||
***************************************************************************/
|
||||
|
||||
util::ntfs_duration f_ntfs_offset(calculate_ntfs_offset());
|
||||
std::chrono::system_clock::duration system_clock_adjustment(calculate_system_clock_adjustment());
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
IMPLEMENTATION
|
||||
***************************************************************************/
|
||||
|
||||
util::ntfs_duration calculate_ntfs_offset()
|
||||
static std::chrono::system_clock::duration calculate_system_clock_adjustment()
|
||||
{
|
||||
constexpr auto days_in_year(365);
|
||||
constexpr auto days_in_four_years((days_in_year * 4) + 1);
|
||||
constexpr auto days_in_century((days_in_four_years * 25) - 1);
|
||||
constexpr auto days_in_four_centuries((days_in_century * 4) + 1);
|
||||
|
||||
constexpr ntfs_duration day(std::chrono::hours(24));
|
||||
constexpr ntfs_duration year(day * days_in_year);
|
||||
constexpr ntfs_duration four_years(day * days_in_four_years);
|
||||
constexpr ntfs_duration century(day * days_in_century);
|
||||
constexpr ntfs_duration four_centuries(day * days_in_four_centuries);
|
||||
// can't use std::chrono::system_clock::duration here, out of fear of integer overflow
|
||||
typedef std::chrono::duration<std::int64_t, std::ratio<1, 1> > int64_second_duration;
|
||||
constexpr int64_second_duration day(std::chrono::hours(24));
|
||||
constexpr int64_second_duration year(day * days_in_year);
|
||||
constexpr int64_second_duration four_years(day * days_in_four_years);
|
||||
constexpr int64_second_duration century(day * days_in_century);
|
||||
constexpr int64_second_duration four_centuries(day * days_in_four_centuries);
|
||||
|
||||
std::time_t const zero(0);
|
||||
std::tm const epoch(*std::gmtime(&zero));
|
||||
|
||||
ntfs_duration result(day * epoch.tm_yday);
|
||||
std::chrono::system_clock::duration result(day * epoch.tm_yday);
|
||||
result += std::chrono::hours(epoch.tm_hour);
|
||||
result += std::chrono::minutes(epoch.tm_min);
|
||||
result += std::chrono::seconds(epoch.tm_sec);
|
||||
|
||||
int years(1900 - 1601 + epoch.tm_year);
|
||||
int years(1900 - 1970 + epoch.tm_year);
|
||||
result += four_centuries * (years / 400);
|
||||
years %= 400;
|
||||
result += century * (years / 100);
|
||||
@ -63,11 +64,9 @@ util::ntfs_duration calculate_ntfs_offset()
|
||||
years %= 4;
|
||||
result += year * years;
|
||||
|
||||
return result;
|
||||
return result - std::chrono::system_clock::from_time_t(0).time_since_epoch();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
|
||||
// -------------------------------------------------
|
||||
@ -76,7 +75,9 @@ util::ntfs_duration calculate_ntfs_offset()
|
||||
|
||||
std::chrono::system_clock::time_point system_clock_time_point_from_ntfs_duration(ntfs_duration d)
|
||||
{
|
||||
return std::chrono::system_clock::from_time_t(0) + std::chrono::duration_cast<std::chrono::system_clock::duration>(d - f_ntfs_offset);
|
||||
typedef arbitrary_clock<std::uint64_t, 1601, 1, 1, 0, 0, 0, std::ratio<1, 10000000 > > ntfs_clock;
|
||||
const std::chrono::time_point<ntfs_clock> tp(d);
|
||||
return ntfs_clock::to_system_clock(tp);
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
|
@ -14,11 +14,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "osdcore.h"
|
||||
#include "coreutil.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
|
||||
namespace util {
|
||||
/***************************************************************************
|
||||
GLOBAL VARIABLES
|
||||
***************************************************************************/
|
||||
|
||||
extern std::chrono::system_clock::duration system_clock_adjustment;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
@ -26,6 +34,212 @@ namespace util {
|
||||
typedef std::chrono::duration<std::uint64_t, std::ratio<1, 10000000> > ntfs_duration;
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
// arbitrary_clock - an std::chrono clock that "knows" the
|
||||
// date of the epoch's begining
|
||||
//---------------------------------------------------------
|
||||
|
||||
template<typename Rep, int Y, int M, int D, int H, int N, int S, typename Ratio>
|
||||
class arbitrary_clock
|
||||
{
|
||||
public:
|
||||
typedef Rep rep;
|
||||
typedef Ratio period;
|
||||
typedef std::chrono::duration<rep, period> duration;
|
||||
typedef std::chrono::time_point<arbitrary_clock> time_point;
|
||||
static constexpr int base_year = Y;
|
||||
static constexpr int base_month = M;
|
||||
static constexpr int base_day = D;
|
||||
static constexpr int base_hour = H;
|
||||
static constexpr int base_minute = N;
|
||||
static constexpr int base_second = S;
|
||||
|
||||
//---------------------------------------------------------
|
||||
// from_arbitrary_time_point - converts an arbitrary_clock
|
||||
// with a different scale to this arbitrary_clock's scale
|
||||
//---------------------------------------------------------
|
||||
|
||||
template<typename Rep2, int Y2, int M2, int D2, int H2, int N2, int S2, typename Ratio2>
|
||||
static time_point from_arbitrary_time_point(const std::chrono::time_point<arbitrary_clock<Rep2, Y2, M2, D2, H2, N2, S2, Ratio2> > &tp)
|
||||
{
|
||||
const int64_t our_absolute_day = absolute_day(Y, M, D);
|
||||
const int64_t their_absolute_day = absolute_day(Y2, M2, D2);
|
||||
|
||||
const auto our_fract_day = std::chrono::hours(H) + std::chrono::minutes(N) + std::chrono::seconds(S);
|
||||
const auto their_fract_day = std::chrono::hours(H2) + std::chrono::minutes(N2) + std::chrono::seconds(S2);
|
||||
|
||||
const std::chrono::duration<Rep, Ratio> adjustment(std::chrono::hours(24) * (their_absolute_day - our_absolute_day) + (their_fract_day - our_fract_day));
|
||||
const duration result_duration = std::chrono::duration_cast<duration>(tp.time_since_epoch() + adjustment);
|
||||
return time_point(result_duration);
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
// to_arbitrary_time_point - converts an arbitrary_clock
|
||||
// of this scale to one of different scale
|
||||
//---------------------------------------------------------
|
||||
|
||||
template<typename Rep2, int Y2, int M2, int D2, int H2, int N2, int S2, typename Ratio2>
|
||||
static std::chrono::time_point<arbitrary_clock<Rep2, Y2, M2, D2, H2, N2, S2, Ratio2> > to_arbitrary_time_point(const time_point &tp)
|
||||
{
|
||||
return arbitrary_clock<Rep2, Y2, M2, D2, H2, N2, S2, Ratio2>::from_arbitrary_time_point(tp);
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
// to_tm - formats a structure of type 'struct tm'
|
||||
//---------------------------------------------------------
|
||||
|
||||
static struct tm to_tm(const time_point &tp)
|
||||
{
|
||||
std::chrono::time_point<tm_conversion_clock> normalized_tp = to_arbitrary_time_point<
|
||||
std::int64_t,
|
||||
tm_conversion_clock::base_year,
|
||||
tm_conversion_clock::base_month,
|
||||
tm_conversion_clock::base_day,
|
||||
tm_conversion_clock::base_hour,
|
||||
tm_conversion_clock::base_minute,
|
||||
tm_conversion_clock::base_second,
|
||||
tm_conversion_clock::period>(tp);
|
||||
return internal_to_tm(normalized_tp.time_since_epoch());
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
// to_system_clock - converts to a system_clock time_point
|
||||
//---------------------------------------------------------
|
||||
|
||||
static std::chrono::time_point<std::chrono::system_clock> to_system_clock(const time_point &tp)
|
||||
{
|
||||
auto normalized_tp = to_arbitrary_time_point<
|
||||
std::int64_t,
|
||||
system_conversion_clock::base_year,
|
||||
system_conversion_clock::base_month,
|
||||
system_conversion_clock::base_day,
|
||||
system_conversion_clock::base_hour,
|
||||
system_conversion_clock::base_minute,
|
||||
system_conversion_clock::base_second,
|
||||
system_conversion_clock::period>(tp);
|
||||
return std::chrono::time_point<std::chrono::system_clock>(normalized_tp.time_since_epoch() + system_clock_adjustment);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// from_system_clock - converts from a system_clock time_point
|
||||
//---------------------------------------------------------
|
||||
|
||||
static time_point from_system_clock(const std::chrono::time_point<std::chrono::system_clock> &tp)
|
||||
{
|
||||
std::chrono::time_point<system_conversion_clock> normalized_tp(tp.time_since_epoch() - system_clock_adjustment);
|
||||
return from_arbitrary_time_point(normalized_tp);
|
||||
}
|
||||
|
||||
private:
|
||||
// By positioning the base year at 1601, we can ensure that:
|
||||
//
|
||||
// * years with leap years are at the end of every quadyear
|
||||
// * quadyears without leap years are at the end of every century
|
||||
// * centuries where the last quadyear has a leap year at the end are at the
|
||||
// end of every quadcentury
|
||||
typedef arbitrary_clock<std::int64_t, 1601, 1, 1, 0, 0, 0, std::ratio<1, 1> > tm_conversion_clock;
|
||||
|
||||
//---------------------------------------------------------
|
||||
// internal_to_tm - formats a structure of type 'struct tm'
|
||||
// based on a normalized clock
|
||||
//---------------------------------------------------------
|
||||
|
||||
static struct tm internal_to_tm(std::chrono::duration<std::int64_t, std::ratio<1, 1> > duration)
|
||||
{
|
||||
constexpr int days_in_year(365);
|
||||
constexpr int days_in_four_years((days_in_year * 4) + 1);
|
||||
constexpr int days_in_century((days_in_four_years * 25) - 1);
|
||||
constexpr int days_in_four_centuries((days_in_century * 4) + 1);
|
||||
|
||||
constexpr tm_conversion_clock::duration day(std::chrono::hours(24));
|
||||
constexpr tm_conversion_clock::duration year(day * days_in_year);
|
||||
constexpr tm_conversion_clock::duration four_years(day * days_in_four_years);
|
||||
constexpr tm_conversion_clock::duration century(day * days_in_century);
|
||||
constexpr tm_conversion_clock::duration four_centuries(day * days_in_four_centuries);
|
||||
|
||||
// figure out the day of week (note that 0 is Sunday, but January 1st 1601 is
|
||||
// a Monday, so we have to adjust by one day)
|
||||
const int day_of_week = int((duration + std::chrono::hours(24)) / day % 7);
|
||||
|
||||
// figure out the year
|
||||
const int four_centuries_count = int(duration / four_centuries);
|
||||
duration -= four_centuries_count * four_centuries;
|
||||
const int century_count = std::min(int(duration / century), 3);
|
||||
duration -= century_count * century;
|
||||
const int four_years_count = std::min(int(duration / four_years), 25);
|
||||
duration -= four_years_count * four_years;
|
||||
const int year_count = int(duration / year);
|
||||
duration -= year_count * year;
|
||||
const int actual_year = tm_conversion_clock::base_year + four_centuries_count * 400 + century_count * 100 + four_years_count * 4 + year_count;
|
||||
|
||||
// figure out the day in the year
|
||||
const int day_in_year = int(duration / day);
|
||||
duration -= day_in_year * day;
|
||||
|
||||
// figure out the month
|
||||
int month, day_in_month = day_in_year;
|
||||
for (month = 0; month < 12; month++)
|
||||
{
|
||||
int days_in_this_month = gregorian_days_in_month(month + 1, actual_year);
|
||||
if (day_in_month < days_in_this_month)
|
||||
break;
|
||||
day_in_month -= days_in_this_month;
|
||||
}
|
||||
if (month >= 12)
|
||||
throw false;
|
||||
|
||||
// figure out the time
|
||||
const int hour = int(duration / std::chrono::hours(1));
|
||||
duration -= std::chrono::hours(hour);
|
||||
const int minute = int(duration / std::chrono::minutes(1));
|
||||
duration -= std::chrono::minutes(minute);
|
||||
const int second = int(duration / std::chrono::seconds(1));
|
||||
duration -= std::chrono::seconds(second);
|
||||
|
||||
// populate the result and return
|
||||
struct tm result;
|
||||
memset(&result, 0, sizeof(result));
|
||||
result.tm_year = actual_year - 1900;
|
||||
result.tm_mon = month;
|
||||
result.tm_mday = day_in_month + 1;
|
||||
result.tm_yday = day_in_year;
|
||||
result.tm_sec = second;
|
||||
result.tm_min = minute;
|
||||
result.tm_hour = hour;
|
||||
result.tm_wday = day_of_week;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
typedef arbitrary_clock<std::int64_t, 1970, 1, 1, 0, 0, 0, std::chrono::system_clock::period > system_conversion_clock;
|
||||
|
||||
//-------------------------------------------------
|
||||
// absolute_day - returns the absolute day count
|
||||
// for the specified year/month/day
|
||||
//-------------------------------------------------
|
||||
|
||||
static int64_t absolute_day(int year, int month, int day)
|
||||
{
|
||||
// first factor the year
|
||||
int64_t result = (year - 1) * 365;
|
||||
result += (year - 1) / 4;
|
||||
result -= (year - 1) / 100;
|
||||
result += (year - 1) / 400;
|
||||
|
||||
// then the month
|
||||
for (int i = 1; i < month; i++)
|
||||
result += gregorian_days_in_month(i, year);
|
||||
|
||||
// then the day
|
||||
result += day - 1;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
INLINE FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
@ -2,7 +2,7 @@
|
||||
// copyright-holders:Raphael Nabet
|
||||
/****************************************************************************
|
||||
|
||||
macutil.c
|
||||
macutil.cpp
|
||||
|
||||
Imgtool Utility code for manipulating certain Apple/Mac data structures
|
||||
and conventions
|
||||
@ -10,20 +10,25 @@
|
||||
*****************************************************************************/
|
||||
|
||||
#include "macutil.h"
|
||||
#include "timeconv.h"
|
||||
|
||||
|
||||
typedef util::arbitrary_clock<std::uint32_t, 1904, 1, 1, 0, 0, 0, std::ratio<1, 1> > classic_mac_clock;
|
||||
|
||||
time_t mac_crack_time(uint32_t t)
|
||||
{
|
||||
/* not sure if this is correct... */
|
||||
return t - (((1970 - 1904) * 365) + 17) * 24 * 60 * 60;
|
||||
classic_mac_clock::duration d(t);
|
||||
std::chrono::time_point<std::chrono::system_clock> tp = classic_mac_clock::to_system_clock(std::chrono::time_point<classic_mac_clock>(d));
|
||||
return std::chrono::system_clock::to_time_t(tp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint32_t mac_setup_time(time_t t)
|
||||
{
|
||||
/* not sure if this is correct... */
|
||||
return t + (((1970 - 1904) * 365) + 17) * 24 * 60 * 60;
|
||||
auto system_time_point = std::chrono::system_clock::from_time_t(t);
|
||||
auto mac_time_point = classic_mac_clock::from_system_clock(system_time_point);
|
||||
return mac_time_point.time_since_epoch().count();
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user