From 2f02cb8966964ea7a6f5d875ed9f3434ea05ab59 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 30 Nov 1999 21:55:00 +0000 Subject: [PATCH] wxDateTime starting to work, more tests for it and for threads in console sample git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@4779 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/latex/wx/thread.tex | 4 +- include/wx/datetime.h | 390 +++++++----------------------------- include/wx/datetime.inl | 328 ++++++++++++++++++++++++++++++ include/wx/longlong.h | 19 +- samples/console/console.cpp | 157 +++++++++++++-- src/common/datetime.cpp | 140 ++++++++++++- src/common/string.cpp | 5 +- 7 files changed, 690 insertions(+), 353 deletions(-) create mode 100644 include/wx/datetime.inl diff --git a/docs/latex/wx/thread.tex b/docs/latex/wx/thread.tex index 77c2814a59..cfdbc20879 100644 --- a/docs/latex/wx/thread.tex +++ b/docs/latex/wx/thread.tex @@ -105,7 +105,9 @@ threads). Delete() may be called for thread in any state: running, paused or even not yet created. Moreover, it must be called if \helpref{Create}{wxthreadcreate} or \helpref{Run}{wxthreadrun} fail to free -the memory occupied by the thread object. +the memory occupied by the thread object. However, you should not call Delete() +on a detached thread which already terminated - doing so will probably result +in a crash because the thread object doesn't exist any more. For detached threads Delete() will also delete the C++ thread object, but it will not do this for joinable ones. diff --git a/include/wx/datetime.h b/include/wx/datetime.h index bf7cab1fcc..ffc3bf6c13 100644 --- a/include/wx/datetime.h +++ b/include/wx/datetime.h @@ -10,8 +10,8 @@ // Licence: wxWindows license ///////////////////////////////////////////////////////////////////////////// -#ifndef _WX_TIME_H -#define _WX_TIME_H +#ifndef _WX_DATETIME_H +#define _WX_DATETIME_H #ifdef __GNUG__ #pragma interface "datetime.h" @@ -26,6 +26,14 @@ class WXDLLEXPORT wxDateTime; class WXDLLEXPORT wxTimeSpan; class WXDLLEXPORT wxDateSpan; +// don't use inline functions in debug builds - we don't care about +// performances and this only leads to increased rebuild time (because every +// time an inline method is changed, all files including the header must be +// rebuilt) +#ifdef __WXDEBUG__ + #define inline +#endif // Debug + /* * TODO Well, everything :-) * @@ -350,7 +358,10 @@ public: static Month GetCurrentMonth(Calendar cal = Gregorian); // returns TRUE if the given year is a leap year in the given calendar - static bool IsLeapYear(int year, Calendar cal = Gregorian); + static bool IsLeapYear(int year = Inv_Year, Calendar cal = Gregorian); + + // get the century (19 for 1999, 20 for 2000 and -5 for 492 BC) + static int GetCentury(int year = Inv_Year); // returns the number of days in this year (356 or 355 for Gregorian // calendar usually :-) @@ -493,12 +504,12 @@ public: // of the month (see helper function SetToLastWeekDay()) bool SetToWeekDay(WeekDay weekday, int n = 1, - wxDateTime_t month = Inv_Month, + Month month = Inv_Month, int year = Inv_Year); // sets to the last weekday in the given month, year inline bool SetToLastWeekDay(WeekDay weekday, - wxDateTime_t month = Inv_Month, + Month month = Inv_Month, int year = Inv_Year); // sets the date to the given day of the given week in the year, @@ -506,8 +517,10 @@ public: // numWeek is > 53) bool SetToTheWeek(wxDateTime_t numWeek, WeekDay weekday = Mon); - // get the century (19 for 1999, 20 for 2000 and -5 for 492 BC) - int GetCentury() const; + // sets the date to the last day of the given (or current) month or the + // given (or current) year + wxDateTime& SetToLastMonthDay(Month month = Inv_Month, + int year = Inv_Year); // The definitions below were taken verbatim from // @@ -582,7 +595,7 @@ public: // get the month day (in 1..31 range, 0 if date is invalid) wxDateTime_t GetDay() const { return GetTm().mday; } // get the day of the week (Inv_WeekDay if date is invalid) - WeekDay GetDayOfWeek() const { return GetTm().GetWeekDay(); } + WeekDay GetWeekDay() const { return GetTm().GetWeekDay(); } // get the hour of the day wxDateTime_t GetHour() const { return GetTm().hour; } // get the minute @@ -701,10 +714,17 @@ public: // get the internal representation inline wxLongLong GetValue() const; -private: // a helper function to get the current time_t - static inline time_t GetTimeNow() { return time((time_t *)NULL); } + static time_t GetTimeNow() { return time((time_t *)NULL); } + // another one to get the current time broken down + static struct tm *GetTmNow() + { + time_t t = GetTimeNow(); + return localtime(&t); + } + +private: // the current country - as it's the same for all program objects (unless // it runs on a _really_ big cluster system :-), this is a static member: // see SetCountry() and GetCountry() @@ -907,7 +927,25 @@ public: // ------------------------------------------------------------------------ // this many years/months/weeks/days - wxDateSpan(int years, int months, int weeks, int days); + wxDateSpan(int years = 0, int months = 0, int weeks = 0, int days = 0) + { + m_years = years; + m_months = months; + m_weeks = weeks; + m_days = days; + } + + // get an object for the given number of days + static wxDateSpan Days(int days) { return wxDateSpan(0, 0, 0, days); } + + // get an object for the given number of weeks + static wxDateSpan Weeks(int weeks) { return wxDateSpan(0, 0, weeks, 0); } + + // get an object for the given number of months + static wxDateSpan Months(int mon) { return wxDateSpan(0, mon, 0, 0); } + + // get an object for the given number of years + static wxDateSpan Years(int years) { return wxDateSpan(years, 0, 0, 0); } // default copy ctor is ok @@ -971,6 +1009,23 @@ WXDLLEXPORT_DATA(extern wxDateSpan) wxMonth; WXDLLEXPORT_DATA(extern wxDateSpan) wxWeek; WXDLLEXPORT_DATA(extern wxDateSpan) wxDay; +// ============================================================================ +// inline functions implementation +// ============================================================================ + +// don't include inline functions definitions when we're included from anything +// else than datetime.cpp in debug builds: this minimizes rebuilds if we change +// some inline function and the performance doesn't matter in the debug builds. + +#if !defined(__WXDEBUG__) || defined(wxDEFINE_TIME_CONSTANTS) + #define INCLUDED_FROM_WX_DATETIME_H + #include "wx/datetime.inl" + #undef INCLUDED_FROM_WX_DATETIME_H +#endif + +// if we defined it to be empty above, restore it now +#undef inline + // ============================================================================ // binary operators // ============================================================================ @@ -1088,315 +1143,4 @@ inline WXDLLEXPORT wxDateSpan operator+(const wxDateSpan& rt1, rt1.GetDays() + rt2.GetDays()); } -// ============================================================================ -// inline functions implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxDateTime statics -// ---------------------------------------------------------------------------- - -/* static */ -wxDateTime::Country wxDateTime::GetCountry() -{ - return ms_country; -} - -// ---------------------------------------------------------------------------- -// wxDateTime construction -// ---------------------------------------------------------------------------- - -// only define this once, when included from datetime.cpp -#ifdef wxDEFINE_TIME_CONSTANTS - const unsigned int wxDateTime::TIME_T_FACTOR = 1000; -#endif // wxDEFINE_TIME_CONSTANTS - -wxDateTime::IsInStdRange() const -{ - return m_time >= 0l && (m_time / (long)TIME_T_FACTOR) < LONG_MAX; -} - -/* static */ -wxDateTime wxDateTime::Now() -{ - return wxDateTime(GetTimeNow()); -} - -wxDateTime& wxDateTime::Set(time_t timet) -{ - m_time = timet * TIME_T_FACTOR; - - return *this; -} - -wxDateTime& wxDateTime::SetToCurrent() -{ - return Set(GetTimeNow()); -} - -wxDateTime::wxDateTime(time_t timet) -{ - Set(timet); -} - -wxDateTime::wxDateTime(const struct tm& tm) -{ - Set(tm); -} - -wxDateTime::wxDateTime(const Tm& tm) -{ - Set(tm); -} - -wxDateTime& wxDateTime::Set(const Tm& tm) -{ - wxASSERT_MSG( tm.IsValid(), _T("invalid broken down date/time") ); - - return Set(tm.mday, (Month)tm.mon, tm.year, tm.hour, tm.min, tm.sec); -} - -wxDateTime::wxDateTime(wxDateTime_t hour, - wxDateTime_t minute, - wxDateTime_t second, - wxDateTime_t millisec) -{ - Set(hour, minute, second, millisec); -} - -wxDateTime::wxDateTime(wxDateTime_t day, - Month month, - int year, - wxDateTime_t hour, - wxDateTime_t minute, - wxDateTime_t second, - wxDateTime_t millisec) -{ - Set(day, month, year, hour, minute, second, millisec); -} - -// ---------------------------------------------------------------------------- -// wxDateTime accessors -// ---------------------------------------------------------------------------- - -wxLongLong wxDateTime::GetValue() const -{ - wxASSERT_MSG( IsValid(), "invalid wxDateTime"); - - return m_time; -} - -time_t wxDateTime::GetTicks() const -{ - wxASSERT_MSG( IsValid(), "invalid wxDateTime"); - if ( !IsInStdRange() ) - { - return (time_t)-1; - } - - return (time_t)((m_time / (long)TIME_T_FACTOR).GetLo()); -} - -bool wxDateTime::SetToLastWeekDay(WeekDay weekday, - wxDateTime_t month, - int year) -{ - SetToWeekDay(weekday, -1, month, year); -} - -// ---------------------------------------------------------------------------- -// wxDateTime comparison -// ---------------------------------------------------------------------------- - -bool wxDateTime::IsEqualTo(const wxDateTime& datetime) const -{ - wxASSERT_MSG( IsValid() && datetime.IsValid(), "invalid wxDateTime"); - - return m_time == datetime.m_time; -} - -bool wxDateTime::operator==(const wxDateTime& datetime) const -{ - return IsEqualTo(datetime); -} - -bool wxDateTime::operator!=(const wxDateTime& datetime) const -{ - return !IsEqualTo(datetime); -} - -bool wxDateTime::IsEarlierThan(const wxDateTime& datetime) const -{ - wxASSERT_MSG( IsValid() && datetime.IsValid(), "invalid wxDateTime"); - - return m_time < datetime.m_time; -} - -bool wxDateTime::IsLaterThan(const wxDateTime& datetime) const -{ - wxASSERT_MSG( IsValid() && datetime.IsValid(), "invalid wxDateTime"); - - return m_time > datetime.m_time; -} - -bool wxDateTime::IsStrictlyBetween(const wxDateTime& t1, - const wxDateTime& t2) const -{ - // no need for assert, will be checked by the functions we call - return IsLaterThan(t1) && IsEarlierThan(t2); -} - -bool wxDateTime::IsBetween(const wxDateTime& t1, const wxDateTime& t2) const -{ - // no need for assert, will be checked by the functions we call - return IsEqualTo(t1) || IsEqualTo(t2) || IsStrictlyBetween(t1, t2); -} - -// ---------------------------------------------------------------------------- -// wxDateTime arithmetics -// ---------------------------------------------------------------------------- - -wxDateTime& wxDateTime::Add(const wxTimeSpan& diff) -{ - wxASSERT_MSG( IsValid(), "invalid wxDateTime"); - - m_time += diff.GetValue(); - - return *this; -} - -wxDateTime& wxDateTime::operator+=(const wxTimeSpan& diff) -{ - return Add(diff); -} - -wxDateTime& wxDateTime::Substract(const wxTimeSpan& diff) -{ - wxASSERT_MSG( IsValid(), "invalid wxDateTime"); - - m_time -= diff.GetValue(); - - return *this; -} - -wxDateTime& wxDateTime::operator-=(const wxTimeSpan& diff) -{ - return Substract(diff); -} - -wxTimeSpan wxDateTime::Substract(const wxDateTime& datetime) const -{ - wxASSERT_MSG( IsValid() && datetime.IsValid(), "invalid wxDateTime"); - - return wxTimeSpan(datetime.GetValue() - GetValue()); -} - -wxTimeSpan wxDateTime::operator-(const wxDateTime& datetime) const -{ - return Substract(datetime); -} - -wxDateTime& wxDateTime::Substract(const wxDateSpan& diff) -{ - return Add(diff.Negate()); -} - -wxDateTime& wxDateTime::operator-=(const wxDateSpan& diff) -{ - return Substract(diff); -} - -wxDateTime& wxDateTime::operator+=(const wxDateSpan& diff) -{ - return Add(diff); -} - -// ---------------------------------------------------------------------------- -// wxTimeSpan -// ---------------------------------------------------------------------------- - -wxTimeSpan& wxTimeSpan::Add(const wxTimeSpan& diff) -{ - m_diff += diff.GetValue(); - - return *this; -} - -wxTimeSpan& wxTimeSpan::Substract(const wxTimeSpan& diff) -{ - m_diff -= diff.GetValue(); - - return *this; -} - -wxTimeSpan& wxTimeSpan::Multiply(int n) -{ - m_diff *= n; - - return *this; -} - -wxTimeSpan wxTimeSpan::operator*(int n) const -{ - wxTimeSpan result(*this); - result.Multiply(n); - - return result; -} - -wxTimeSpan wxTimeSpan::Abs() const -{ - return wxTimeSpan(GetValue().Abs()); -} - -bool wxTimeSpan::IsEqualTo(const wxTimeSpan& ts) const -{ - return GetValue() == ts.GetValue(); -} - -bool wxTimeSpan::IsLongerThan(const wxTimeSpan& ts) const -{ - return Abs() > ts.Abs(); -} - -// ---------------------------------------------------------------------------- -// wxDateSpan -// ---------------------------------------------------------------------------- - -wxDateSpan& -wxDateSpan::operator+=(const wxDateSpan& other) -{ - m_years += other.m_years; - m_months += other.m_months; - m_weeks += other.m_weeks; - m_days += other.m_days; - - return *this; -} - -wxDateSpan& wxDateSpan::operator*=(int factor) -{ - m_years *= m_years; - m_months *= m_months; - m_weeks *= m_weeks; - m_days *= m_days; - - return *this; -} - -wxDateSpan wxDateSpan::Negate() const -{ - return wxDateSpan(-m_years, -m_months, -m_weeks, -m_days); -} - -wxDateSpan& wxDateSpan::Neg() -{ - m_years = -m_years; - m_months = -m_months; - m_weeks = -m_weeks; - m_days = -m_days; - - return *this; -} - -#endif // _WX_TIME_H +#endif // _WX_DATETIME_H diff --git a/include/wx/datetime.inl b/include/wx/datetime.inl new file mode 100644 index 0000000000..1ae112d5ad --- /dev/null +++ b/include/wx/datetime.inl @@ -0,0 +1,328 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/datetime.inl +// Purpose: definition of inline functions of wxDateTime and related +// classes declared in datetime.h +// Author: Vadim Zeitlin +// Remarks: having the inline functions here allows us to minimize the +// dependencies (and hence the rebuild time) in debug builds. +// Modified by: +// Created: 30.11.99 +// RCS-ID: $Id$ +// Copyright: (c) 1999 Vadim Zeitlin +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDED_FROM_WX_DATETIME_H + #error "This file is only included by wx/datetime.h, don't include it manually!" +#endif + +// ---------------------------------------------------------------------------- +// wxDateTime statics +// ---------------------------------------------------------------------------- + +/* static */ +wxDateTime::Country wxDateTime::GetCountry() +{ + return ms_country; +} + +// ---------------------------------------------------------------------------- +// wxDateTime construction +// ---------------------------------------------------------------------------- + +// only define this once, when included from datetime.cpp +#ifdef wxDEFINE_TIME_CONSTANTS + const unsigned int wxDateTime::TIME_T_FACTOR = 1000; +#endif // wxDEFINE_TIME_CONSTANTS + +wxDateTime::IsInStdRange() const +{ + return m_time >= 0l && (m_time / (long)TIME_T_FACTOR) < LONG_MAX; +} + +/* static */ +wxDateTime wxDateTime::Now() +{ + return wxDateTime(GetTimeNow()); +} + +wxDateTime& wxDateTime::Set(time_t timet) +{ + // assign first to avoid long multiplication overflow! + m_time = timet; + m_time *= TIME_T_FACTOR; + + return *this; +} + +wxDateTime& wxDateTime::SetToCurrent() +{ + return Set(GetTimeNow()); +} + +wxDateTime::wxDateTime(time_t timet) +{ + Set(timet); +} + +wxDateTime::wxDateTime(const struct tm& tm) +{ + Set(tm); +} + +wxDateTime::wxDateTime(const Tm& tm) +{ + Set(tm); +} + +wxDateTime& wxDateTime::Set(const Tm& tm) +{ + wxASSERT_MSG( tm.IsValid(), _T("invalid broken down date/time") ); + + return Set(tm.mday, (Month)tm.mon, tm.year, tm.hour, tm.min, tm.sec); +} + +wxDateTime::wxDateTime(wxDateTime_t hour, + wxDateTime_t minute, + wxDateTime_t second, + wxDateTime_t millisec) +{ + Set(hour, minute, second, millisec); +} + +wxDateTime::wxDateTime(wxDateTime_t day, + Month month, + int year, + wxDateTime_t hour, + wxDateTime_t minute, + wxDateTime_t second, + wxDateTime_t millisec) +{ + Set(day, month, year, hour, minute, second, millisec); +} + +// ---------------------------------------------------------------------------- +// wxDateTime accessors +// ---------------------------------------------------------------------------- + +wxLongLong wxDateTime::GetValue() const +{ + wxASSERT_MSG( IsValid(), "invalid wxDateTime"); + + return m_time; +} + +time_t wxDateTime::GetTicks() const +{ + wxASSERT_MSG( IsValid(), "invalid wxDateTime"); + if ( !IsInStdRange() ) + { + return (time_t)-1; + } + + return (time_t)((m_time / (long)TIME_T_FACTOR).GetLo()); +} + +bool wxDateTime::SetToLastWeekDay(WeekDay weekday, + Month month, + int year) +{ + return SetToWeekDay(weekday, -1, month, year); +} + +// ---------------------------------------------------------------------------- +// wxDateTime comparison +// ---------------------------------------------------------------------------- + +bool wxDateTime::IsEqualTo(const wxDateTime& datetime) const +{ + wxASSERT_MSG( IsValid() && datetime.IsValid(), "invalid wxDateTime"); + + return m_time == datetime.m_time; +} + +bool wxDateTime::operator==(const wxDateTime& datetime) const +{ + return IsEqualTo(datetime); +} + +bool wxDateTime::operator!=(const wxDateTime& datetime) const +{ + return !IsEqualTo(datetime); +} + +bool wxDateTime::IsEarlierThan(const wxDateTime& datetime) const +{ + wxASSERT_MSG( IsValid() && datetime.IsValid(), "invalid wxDateTime"); + + return m_time < datetime.m_time; +} + +bool wxDateTime::IsLaterThan(const wxDateTime& datetime) const +{ + wxASSERT_MSG( IsValid() && datetime.IsValid(), "invalid wxDateTime"); + + return m_time > datetime.m_time; +} + +bool wxDateTime::IsStrictlyBetween(const wxDateTime& t1, + const wxDateTime& t2) const +{ + // no need for assert, will be checked by the functions we call + return IsLaterThan(t1) && IsEarlierThan(t2); +} + +bool wxDateTime::IsBetween(const wxDateTime& t1, const wxDateTime& t2) const +{ + // no need for assert, will be checked by the functions we call + return IsEqualTo(t1) || IsEqualTo(t2) || IsStrictlyBetween(t1, t2); +} + +// ---------------------------------------------------------------------------- +// wxDateTime arithmetics +// ---------------------------------------------------------------------------- + +wxDateTime& wxDateTime::Add(const wxTimeSpan& diff) +{ + wxASSERT_MSG( IsValid(), "invalid wxDateTime"); + + m_time += diff.GetValue(); + + return *this; +} + +wxDateTime& wxDateTime::operator+=(const wxTimeSpan& diff) +{ + return Add(diff); +} + +wxDateTime& wxDateTime::Substract(const wxTimeSpan& diff) +{ + wxASSERT_MSG( IsValid(), "invalid wxDateTime"); + + m_time -= diff.GetValue(); + + return *this; +} + +wxDateTime& wxDateTime::operator-=(const wxTimeSpan& diff) +{ + return Substract(diff); +} + +wxTimeSpan wxDateTime::Substract(const wxDateTime& datetime) const +{ + wxASSERT_MSG( IsValid() && datetime.IsValid(), "invalid wxDateTime"); + + return wxTimeSpan(datetime.GetValue() - GetValue()); +} + +wxTimeSpan wxDateTime::operator-(const wxDateTime& datetime) const +{ + return Substract(datetime); +} + +wxDateTime& wxDateTime::Substract(const wxDateSpan& diff) +{ + return Add(diff.Negate()); +} + +wxDateTime& wxDateTime::operator-=(const wxDateSpan& diff) +{ + return Substract(diff); +} + +wxDateTime& wxDateTime::operator+=(const wxDateSpan& diff) +{ + return Add(diff); +} + +// ---------------------------------------------------------------------------- +// wxTimeSpan +// ---------------------------------------------------------------------------- + +wxTimeSpan& wxTimeSpan::Add(const wxTimeSpan& diff) +{ + m_diff += diff.GetValue(); + + return *this; +} + +wxTimeSpan& wxTimeSpan::Substract(const wxTimeSpan& diff) +{ + m_diff -= diff.GetValue(); + + return *this; +} + +wxTimeSpan& wxTimeSpan::Multiply(int n) +{ + m_diff *= n; + + return *this; +} + +wxTimeSpan wxTimeSpan::operator*(int n) const +{ + wxTimeSpan result(*this); + result.Multiply(n); + + return result; +} + +wxTimeSpan wxTimeSpan::Abs() const +{ + return wxTimeSpan(GetValue().Abs()); +} + +bool wxTimeSpan::IsEqualTo(const wxTimeSpan& ts) const +{ + return GetValue() == ts.GetValue(); +} + +bool wxTimeSpan::IsLongerThan(const wxTimeSpan& ts) const +{ + return GetValue().Abs() > ts.GetValue().Abs(); +} + +// ---------------------------------------------------------------------------- +// wxDateSpan +// ---------------------------------------------------------------------------- + +wxDateSpan& +wxDateSpan::operator+=(const wxDateSpan& other) +{ + m_years += other.m_years; + m_months += other.m_months; + m_weeks += other.m_weeks; + m_days += other.m_days; + + return *this; +} + +wxDateSpan& wxDateSpan::operator*=(int factor) +{ + m_years *= m_years; + m_months *= m_months; + m_weeks *= m_weeks; + m_days *= m_days; + + return *this; +} + +wxDateSpan wxDateSpan::Negate() const +{ + return wxDateSpan(-m_years, -m_months, -m_weeks, -m_days); +} + +wxDateSpan& wxDateSpan::Neg() +{ + m_years = -m_years; + m_months = -m_months; + m_weeks = -m_weeks; + m_days = -m_days; + + return *this; +} + + diff --git a/include/wx/longlong.h b/include/wx/longlong.h index cedac4f92b..c9b582b7a3 100644 --- a/include/wx/longlong.h +++ b/include/wx/longlong.h @@ -24,11 +24,12 @@ // ---------------------------------------------------------------------------- // to avoid compilation problems on 64bit machines with ambiguous method calls -// we will need this +// we will need to define this #undef wxLongLongIsLong // NB: we #define and not typedef wxLongLong_t because we want to be able to -// use 'unsigned wxLongLong_t' as well +// use 'unsigned wxLongLong_t' as well and because we use "#ifdef +// wxLongLong_t" below #if defined(SIZEOF_LONG) && (SIZEOF_LONG == 8) #define wxLongLong_t long #define wxLongLongIsLong @@ -98,7 +99,7 @@ public: m_ll |= (wxLongLong_t) lo; } - // default copy ctor is ok in both cases + // default copy ctor is ok // no dtor @@ -112,10 +113,10 @@ public: // accessors // get high part long GetHi() const - { return (long)((m_ll & 0xFFFFFFFF00000000l) >> 32); } + { return (long)(m_ll >> 32); } // get low part unsigned long GetLo() const - { return (unsigned long) (m_ll & 0x00000000FFFFFFFFl); } + { return (unsigned long)m_ll; } // get absolute value wxLongLongNative& Abs() { if ( m_ll < 0 ) m_ll = -m_ll; return *this; } @@ -123,6 +124,8 @@ public: // convert to native long long wxLongLong_t GetValue() const { return m_ll; } + // don't provide implicit conversion to wxLongLong_t or we will have an + // ambiguity for all arithmetic operations //operator wxLongLong_t() const { return m_ll; } // operations @@ -200,8 +203,12 @@ public: // multiplication/division wxLongLongNative operator*(const wxLongLongNative& ll) const { return wxLongLongNative(m_ll * ll.m_ll); } + wxLongLongNative operator*(long l) const + { return wxLongLongNative(m_ll * l); } wxLongLongNative& operator*=(const wxLongLongNative& ll) { m_ll *= ll.m_ll; return *this; } + wxLongLongNative& operator*=(long l) + { m_ll *= l; return *this; } wxLongLongNative operator/(const wxLongLongNative& ll) const { return wxLongLongNative(m_ll / ll.m_ll); } @@ -209,6 +216,8 @@ public: { return wxLongLongNative(m_ll / l); } wxLongLongNative& operator/=(const wxLongLongNative& ll) { m_ll /= ll.m_ll; return *this; } + wxLongLongNative& operator/=(long l) + { m_ll /= l; return *this; } wxLongLongNative operator%(const wxLongLongNative& ll) const { return wxLongLongNative(m_ll % ll.m_ll); } diff --git a/samples/console/console.cpp b/samples/console/console.cpp index f72458ddd5..f83df94ab8 100644 --- a/samples/console/console.cpp +++ b/samples/console/console.cpp @@ -32,8 +32,8 @@ //#define TEST_ARRAYS //#define TEST_LOG //#define TEST_STRINGS -#define TEST_THREADS -//#define TEST_TIME +//#define TEST_THREADS +#define TEST_TIME //#define TEST_LONGLONG // ============================================================================ @@ -93,9 +93,26 @@ static void TestSpeed() static void TestDivision() { - wxLongLong ll = 0x38417388; // some number < LONG_MAX + #define MAKE_LL(x1, x2, x3, x4) wxLongLong((x1 << 16) | x2, (x3 << 16) | x3) - wxASSERT( (ll / 1000l)*1000l == ll ); + // seed pseudo random generator + //srand((unsigned)time(NULL)); + + size_t nTested = 0; + for ( size_t n = 0; n < 10000; n++ ) + { + // get a random wxLongLong (shifting by 12 the MSB ensures that the + // multiplication will not overflow) + wxLongLong ll = MAKE_LL((rand() >> 12), rand(), rand(), rand()); + + wxASSERT( (ll * 1000l)/1000l == ll ); + + nTested++; + } + + printf("\n*** Tested %u divisions/multiplications: ok\n", nTested); + + #undef MAKE_LL } #endif // TEST_LONGLONG @@ -108,6 +125,60 @@ static void TestDivision() #include +// this test miscellaneous static wxDateTime functions +static void TestTimeStatic() +{ + puts("\n*** wxDateTime static methods test ***"); + + // some info about the current date + int year = wxDateTime::GetCurrentYear(); + printf("Current year %d is %sa leap one and has %d days.\n", + year, + wxDateTime::IsLeapYear(year) ? "" : "not ", + wxDateTime::GetNumberOfDays(year)); + + wxDateTime::Month month = wxDateTime::GetCurrentMonth(); + printf("Current month is '%s' ('%s') and it has %d days\n", + wxDateTime::GetMonthName(month, TRUE).c_str(), + wxDateTime::GetMonthName(month).c_str(), + wxDateTime::GetNumberOfDays(month)); + + // leap year logic + static const nYears = 5; + static const int years[2][nYears] = + { + // first line: the years to test + { 1990, 1976, 2000, 2030, 1984, }, + + // second line: TRUE if leap, FALSE otherwise + { FALSE, TRUE, TRUE, FALSE, TRUE } + }; + + for ( size_t n = 0; n < nYears; n++ ) + { + int year = years[0][n]; + bool should = years[1][n] != 0; + + printf("Year %d is %sa leap year (should be: %s)\n", + year, + wxDateTime::IsLeapYear(year) ? "" : "not ", + should ? "yes" : "no"); + + wxASSERT( should == wxDateTime::IsLeapYear(year) ); + } +} + +// test constructing wxDateTime objects +static void TestTimeSet() +{ + puts("\n*** wxDateTime construction test ***"); + + printf("Current time:\t%s\n", wxDateTime::Now().Format().c_str()); + printf("Unix epoch:\t%s\n", wxDateTime((time_t)0).Format().c_str()); + printf("Today noon:\t%s\n", wxDateTime(12, 0).Format().c_str()); + printf("May 29, 1976:\t%s\n", wxDateTime(29, wxDateTime::May, 1976).Format().c_str()); +} + #endif // TEST_TIME // ---------------------------------------------------------------------------- @@ -200,7 +271,7 @@ void MyDetachedThread::OnExit() void TestDetachedThreads() { - puts("*** Testing detached threads ***"); + puts("\n*** Testing detached threads ***"); static const size_t nThreads = 3; MyDetachedThread *threads[nThreads]; @@ -226,7 +297,7 @@ void TestDetachedThreads() void TestJoinableThreads() { - puts("*** Testing a joinable thread (a loooong calculation...) ***"); + puts("\n*** Testing a joinable thread (a loooong calculation...) ***"); // calc 10! in the background MyJoinableThread thread(10); @@ -238,7 +309,9 @@ void TestJoinableThreads() void TestThreadSuspend() { - MyDetachedThread *thread = new MyDetachedThread(30, 'X'); + puts("\n*** Testing thread suspend/resume functions ***"); + + MyDetachedThread *thread = new MyDetachedThread(15, 'X'); thread->Run(); @@ -271,6 +344,56 @@ void TestThreadSuspend() puts(""); } +void TestThreadDelete() +{ + // As above, using Sleep() is only for testing here - we must use some + // synchronisation object instead to ensure that the thread is still + // running when we delete it - deleting a detached thread which already + // terminated will lead to a crash! + + puts("\n*** Testing thread delete function ***"); + + MyDetachedThread *thread1 = new MyDetachedThread(30, 'Y'); + + thread1->Run(); + + wxThread::Sleep(300); + + thread1->Delete(); + + puts("\nDeleted a running thread."); + + MyDetachedThread *thread2 = new MyDetachedThread(30, 'Z'); + + thread2->Run(); + + wxThread::Sleep(300); + + thread2->Pause(); + + thread2->Delete(); + + puts("\nDeleted a sleeping thread."); + + MyJoinableThread *thread3 = new MyJoinableThread(20); + thread3->Run(); + + thread3->Delete(); + + puts("\nDeleted a joinable thread."); + + MyJoinableThread *thread4 = new MyJoinableThread(2); + thread4->Run(); + + wxThread::Sleep(300); + + thread4->Delete(); + + puts("\nDeleted a joinable thread which already terminated."); + + puts(""); +} + #endif // TEST_THREADS // ---------------------------------------------------------------------------- @@ -421,12 +544,15 @@ int main(int argc, char **argv) if ( argc > 1 && argv[1][0] == 't' ) wxLog::AddTraceMask("thread"); - TestThreadSuspend(); if ( 0 ) - { - TestDetachedThreads(); - TestJoinableThreads(); - } + TestDetachedThreads(); + if ( 0 ) + TestJoinableThreads(); + if ( 0 ) + TestThreadSuspend(); + if ( 1 ) + TestThreadDelete(); + #endif // TEST_THREADS #ifdef TEST_LONGLONG @@ -437,11 +563,8 @@ int main(int argc, char **argv) #endif // TEST_LONGLONG #ifdef TEST_TIME - wxDateTime time = wxDateTime::Now(); - printf("Current time: '%s', current year %u is %sa leap one", - time.Format().c_str(), - time.GetYear(), - wxDateTime::IsLeapYear(time.GetYear()) ? "" : "not"); + TestTimeStatic(); + TestTimeSet(); #endif // TEST_TIME wxUninitialize(); diff --git a/src/common/datetime.cpp b/src/common/datetime.cpp index f254ddc7e5..46f65d001f 100644 --- a/src/common/datetime.cpp +++ b/src/common/datetime.cpp @@ -54,6 +54,7 @@ static wxDateTime::wxDateTime_t gs_daysInMonth[2][12] = // private functions // ---------------------------------------------------------------------------- +// this function is a wrapper around strftime(3) static wxString CallStrftime(const wxChar *format, const tm* tm) { wxChar buf[1024]; @@ -66,6 +67,28 @@ static wxString CallStrftime(const wxChar *format, const tm* tm) return wxString(buf); } +// if year and/or month have invalid values, replace them with the current ones +static void ReplaceDefaultYearMonthWithCurrent(int *year, + wxDateTime::Month *month) +{ + struct tm *tmNow = NULL; + + if ( *year == wxDateTime::Inv_Year ) + { + tmNow = wxDateTime::GetTmNow(); + + *year = 1900 + tmNow->tm_year; + } + + if ( *month == wxDateTime::Inv_Month ) + { + if ( !tmNow ) + tmNow = wxDateTime::GetTmNow(); + + *month = (wxDateTime::Month)tmNow->tm_mon; + } +} + // ============================================================================ // implementation of wxDateTime // ============================================================================ @@ -122,6 +145,9 @@ void wxDateTime::Tm::ComputeWeekDay() /* static */ bool wxDateTime::IsLeapYear(int year, wxDateTime::Calendar cal) { + if ( year == Inv_Year ) + year = GetCurrentYear(); + if ( cal == Gregorian ) { // in Gregorian calendar leap years are those divisible by 4 except @@ -197,6 +223,30 @@ wxDateTime::Month wxDateTime::GetCurrentMonth(wxDateTime::Calendar cal) return Inv_Month; } +/* static */ +wxDateTime::wxDateTime_t wxDateTime::GetNumberOfDays(int year, Calendar cal) +{ + if ( year == Inv_Year ) + { + // take the current year if none given + year = GetCurrentYear(); + } + + switch ( cal ) + { + case Gregorian: + case Julian: + return IsLeapYear(year) ? 366 : 365; + break; + + default: + wxFAIL_MSG(_T("unsupported calendar")); + break; + } + + return 0; +} + /* static */ wxDateTime::wxDateTime_t wxDateTime::GetNumberOfDays(wxDateTime::Month month, int year, @@ -310,12 +360,9 @@ wxDateTime& wxDateTime::Set(wxDateTime_t day, ms_InvDateTime, _T("Invalid time in wxDateTime::Set()") ); - if ( year == Inv_Year ) - year = GetCurrentYear(); - if ( month == Inv_Month ) - month = GetCurrentMonth(); + ReplaceDefaultYearMonthWithCurrent(&year, &month); - wxCHECK_MSG( day < GetNumberOfDays(month, year), ms_InvDateTime, + wxCHECK_MSG( day <= GetNumberOfDays(month, year), ms_InvDateTime, _T("Invalid date in wxDateTime::Set()") ); // the range of time_t type (inclusive) @@ -324,7 +371,7 @@ wxDateTime& wxDateTime::Set(wxDateTime_t day, // test only the year instead of testing for the exact end of the Unix // time_t range - it doesn't bring anything to do more precise checks - if ( year >= yearMaxInRange && year <= yearMaxInRange ) + if ( year >= yearMinInRange && year <= yearMaxInRange ) { // use the standard library version if the date is in range - this is // probably more efficient than our code @@ -473,6 +520,87 @@ wxDateTime& wxDateTime::Add(const wxDateSpan& diff) return *this; } +// ---------------------------------------------------------------------------- +// Weekday and monthday stuff +// ---------------------------------------------------------------------------- + +wxDateTime& wxDateTime::SetToLastMonthDay(Month month, + int year) +{ + // take the current month/year if none specified + ReplaceDefaultYearMonthWithCurrent(&year, &month); + + return Set(gs_daysInMonth[IsLeapYear(year)][month], month, year); +} + +bool wxDateTime::SetToWeekDay(WeekDay weekday, + int n, + Month month, + int year) +{ + wxCHECK_MSG( weekday != Inv_WeekDay, FALSE, _T("invalid weekday") ); + + // we don't check explicitly that -5 <= n <= 5 because we will return FALSE + // anyhow in such case - but may be should still give an assert for it? + + // take the current month/year if none specified + ReplaceDefaultYearMonthWithCurrent(&year, &month); + + wxDateTime dt; + + // TODO this probably could be optimised somehow... + + if ( n > 0 ) + { + // get the first day of the month + dt.Set(1, month, year); + + // get its wday + WeekDay wdayFirst = dt.GetWeekDay(); + + // go to the first weekday of the month + int diff = weekday - wdayFirst; + if ( diff < 0 ) + diff += 7; + + // add advance n-1 weeks more + diff += 7*(n - 1); + + dt -= wxDateSpan::Days(diff); + } + else + { + // get the last day of the month + dt.SetToLastMonthDay(month, year); + + // get its wday + WeekDay wdayLast = dt.GetWeekDay(); + + // go to the last weekday of the month + int diff = wdayLast - weekday; + if ( diff < 0 ) + diff += 7; + + // and rewind n-1 weeks from there + diff += 7*(n - 1); + + dt -= wxDateSpan::Days(diff); + } + + // check that it is still in the same month + if ( dt.GetMonth() == month ) + { + *this = dt; + + return TRUE; + } + else + { + // no such day in this month + return FALSE; + } +} + // ---------------------------------------------------------------------------- // wxDateTime to/from text representations // ---------------------------------------------------------------------------- diff --git a/src/common/string.cpp b/src/common/string.cpp index 280e105f25..fe8480cd45 100644 --- a/src/common/string.cpp +++ b/src/common/string.cpp @@ -203,7 +203,10 @@ extern int WXDLLEXPORT wxVsnprintf(wxChar *buf, size_t len, // vsnprintf() will not terminate the string with '\0' if there is not // enough place, but we want the string to always be NUL terminated int rc = wxVsnprintfA(buf, len - 1, format, argptr); - buf[len] = 0; + if ( rc == -1 ) + { + buf[len] = 0; + } return rc; #endif // Unicode/ANSI -- 2.45.2