[API BREAKING] Remove conversion from weekday to unsigned

* There has been a great deal of anguish over the encoding of
  weekdays:  whether [0, 6] maps to [Sunday, Saturday] or
  [1, 7] maps to [Monday, Sunday].  This commit attempts
  to address that issue, but will break a small amount of
  code at compile-time.  See below on how to fix that.

* The weekday constructor used to accept [0, 6] to represent
  [Sunday, Saturday].  It now accepts [0, 7] to represent
  [Sunday, Saturday] with both 0 and 7 mapping to Sunday.

* The conversion from weekday to unsigned has been removed.

* To convert a weekday to unsigned replace:

      auto u = unsigned{wd};

  with:

      auto u = (wd - Sunday).count();

  This maps [Sunday, Saturday] to [0, 6], which is the
  C/POSIX mapping.  If you prefer the ISO mapping
  ([Monday, Sunday] -> [1, 7]), then do:

      auto u = (wd - Monday).count() + 1;
This commit is contained in:
Howard Hinnant 2018-06-02 22:56:10 -04:00
parent 6c4d333026
commit 40b83654b6
4 changed files with 34 additions and 34 deletions

View File

@ -431,7 +431,6 @@ public:
CONSTCD14 weekday& operator+=(const days& d) NOEXCEPT; CONSTCD14 weekday& operator+=(const days& d) NOEXCEPT;
CONSTCD14 weekday& operator-=(const days& d) NOEXCEPT; CONSTCD14 weekday& operator-=(const days& d) NOEXCEPT;
CONSTCD11 explicit operator unsigned() const NOEXCEPT;
CONSTCD11 bool ok() const NOEXCEPT; CONSTCD11 bool ok() const NOEXCEPT;
CONSTCD11 weekday_indexed operator[](unsigned index) const NOEXCEPT; CONSTCD11 weekday_indexed operator[](unsigned index) const NOEXCEPT;
@ -439,6 +438,14 @@ public:
private: private:
static CONSTCD11 unsigned char weekday_from_days(int z) NOEXCEPT; static CONSTCD11 unsigned char weekday_from_days(int z) NOEXCEPT;
friend CONSTCD11 bool operator==(const weekday& x, const weekday& y) NOEXCEPT;
friend CONSTCD14 days operator-(const weekday& x, const weekday& y) NOEXCEPT;
friend CONSTCD14 weekday operator+(const weekday& x, const days& y) NOEXCEPT;
template<class CharT, class Traits>
friend std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, const weekday& wd);
friend class weekday_indexed;
}; };
CONSTCD11 bool operator==(const weekday& x, const weekday& y) NOEXCEPT; CONSTCD11 bool operator==(const weekday& x, const weekday& y) NOEXCEPT;
@ -1765,7 +1772,7 @@ weekday::weekday_from_days(int z) NOEXCEPT
CONSTCD11 CONSTCD11
inline inline
weekday::weekday(unsigned wd) NOEXCEPT weekday::weekday(unsigned wd) NOEXCEPT
: wd_(static_cast<decltype(wd_)>(wd)) : wd_(static_cast<decltype(wd_)>(wd != 7 ? wd : 0))
{} {}
CONSTCD11 CONSTCD11
@ -1803,13 +1810,6 @@ weekday::operator-=(const days& d) NOEXCEPT
return *this; return *this;
} }
CONSTCD11
inline
weekday::operator unsigned() const NOEXCEPT
{
return static_cast<unsigned>(wd_);
}
CONSTCD11 inline bool weekday::ok() const NOEXCEPT {return wd_ <= 6;} CONSTCD11 inline bool weekday::ok() const NOEXCEPT {return wd_ <= 6;}
CONSTCD11 CONSTCD11
@ -1817,7 +1817,7 @@ inline
bool bool
operator==(const weekday& x, const weekday& y) NOEXCEPT operator==(const weekday& x, const weekday& y) NOEXCEPT
{ {
return static_cast<unsigned>(x) == static_cast<unsigned>(y); return x.wd_ == y.wd_;
} }
CONSTCD11 CONSTCD11
@ -1833,8 +1833,9 @@ inline
days days
operator-(const weekday& x, const weekday& y) NOEXCEPT operator-(const weekday& x, const weekday& y) NOEXCEPT
{ {
auto const diff = static_cast<unsigned>(x) - static_cast<unsigned>(y); auto const wdu = x.wd_ - y.wd_;
return days{diff <= 6 ? diff : diff + 7}; auto const wk = (wdu >= 0 ? wdu : wdu-6) / 7;
return days{wdu - wk * 7};
} }
CONSTCD14 CONSTCD14
@ -1842,7 +1843,7 @@ inline
weekday weekday
operator+(const weekday& x, const days& y) NOEXCEPT operator+(const weekday& x, const days& y) NOEXCEPT
{ {
auto const wdu = static_cast<long long>(static_cast<unsigned>(x)) + y.count(); auto const wdu = static_cast<long long>(static_cast<unsigned>(x.wd_)) + y.count();
auto const wk = (wdu >= 0 ? wdu : wdu-6) / 7; auto const wk = (wdu >= 0 ? wdu : wdu-6) / 7;
return weekday{static_cast<unsigned>(wdu - wk * 7)}; return weekday{static_cast<unsigned>(wdu - wk * 7)};
} }
@ -1874,7 +1875,7 @@ operator<<(std::basic_ostream<CharT, Traits>& os, const weekday& wd)
os << format(fmt, wd); os << format(fmt, wd);
} }
else else
os << static_cast<unsigned>(wd) << " is not a valid weekday"; os << static_cast<unsigned>(wd.wd_) << " is not a valid weekday";
return os; return os;
} }
@ -1939,13 +1940,13 @@ CONSTDATA date::month October{10};
CONSTDATA date::month November{11}; CONSTDATA date::month November{11};
CONSTDATA date::month December{12}; CONSTDATA date::month December{12};
CONSTDATA date::weekday Sunday{0u}; CONSTDATA date::weekday Monday{1};
CONSTDATA date::weekday Monday{1u}; CONSTDATA date::weekday Tuesday{2};
CONSTDATA date::weekday Tuesday{2u}; CONSTDATA date::weekday Wednesday{3};
CONSTDATA date::weekday Wednesday{3u}; CONSTDATA date::weekday Thursday{4};
CONSTDATA date::weekday Thursday{4u}; CONSTDATA date::weekday Friday{5};
CONSTDATA date::weekday Friday{5u}; CONSTDATA date::weekday Saturday{6};
CONSTDATA date::weekday Saturday{6u}; CONSTDATA date::weekday Sunday{7};
// weekday_indexed // weekday_indexed
@ -1975,7 +1976,7 @@ weekday_indexed::ok() const NOEXCEPT
CONSTCD11 CONSTCD11
inline inline
weekday_indexed::weekday_indexed(const date::weekday& wd, unsigned index) NOEXCEPT weekday_indexed::weekday_indexed(const date::weekday& wd, unsigned index) NOEXCEPT
: wd_(static_cast<decltype(wd_)>(static_cast<unsigned>(wd))) : wd_(static_cast<decltype(wd_)>(static_cast<unsigned>(wd.wd_)))
, index_(static_cast<decltype(index_)>(index)) , index_(static_cast<decltype(index_)>(index))
{} {}
@ -4337,11 +4338,11 @@ extract_weekday(std::basic_ostream<CharT, Traits>& os, const fields<Duration>& f
os.setstate(std::ios::failbit); os.setstate(std::ios::failbit);
return 7; return 7;
} }
unsigned wd; weekday wd;
if (fds.ymd.ok()) if (fds.ymd.ok())
{ {
wd = static_cast<unsigned>(weekday{fds.ymd}); wd = weekday{fds.ymd};
if (fds.wd.ok() && wd != static_cast<unsigned>(fds.wd)) if (fds.wd.ok() && wd != fds.wd)
{ {
// fds.ymd and fds.wd are inconsistent // fds.ymd and fds.wd are inconsistent
os.setstate(std::ios::failbit); os.setstate(std::ios::failbit);
@ -4349,8 +4350,8 @@ extract_weekday(std::basic_ostream<CharT, Traits>& os, const fields<Duration>& f
} }
} }
else else
wd = static_cast<unsigned>(fds.wd); wd = fds.wd;
return wd; return static_cast<unsigned>((wd - Sunday).count());
} }
template <class CharT, class Traits, class Duration> template <class CharT, class Traits, class Duration>
@ -7216,8 +7217,8 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
if (ymd.ok()) if (ymd.ok())
{ {
if (wd == not_a_weekday) if (wd == not_a_weekday)
wd = static_cast<int>(static_cast<unsigned>(weekday(ymd))); wd = static_cast<int>((weekday(ymd) - Sunday).count());
else if (wd != static_cast<int>(static_cast<unsigned>(weekday(ymd)))) else if (wd != static_cast<int>((weekday(ymd) - Sunday).count()))
goto broken; goto broken;
if (!computed) if (!computed)
{ {

View File

@ -451,7 +451,7 @@ weekday::weekday(unsigned wd) NOEXCEPT
CONSTCD11 CONSTCD11
inline inline
weekday::weekday(date::weekday wd) NOEXCEPT weekday::weekday(date::weekday wd) NOEXCEPT
: wd_(to_iso_encoding(static_cast<unsigned>(wd))) : wd_((wd-date::Monday).count() + 1)
{} {}
CONSTCD11 CONSTCD11

View File

@ -77,11 +77,9 @@ static_assert( std::is_trivially_move_assignable<date::weekday>{}, "");
static_assert( std::is_nothrow_constructible<date::weekday, unsigned>{}, ""); static_assert( std::is_nothrow_constructible<date::weekday, unsigned>{}, "");
static_assert( std::is_nothrow_constructible<date::weekday, date::sys_days>{}, ""); static_assert( std::is_nothrow_constructible<date::weekday, date::sys_days>{}, "");
static_assert( std::is_nothrow_constructible<unsigned, date::weekday>{}, "");
static_assert(!std::is_convertible<unsigned, date::weekday>{}, ""); static_assert(!std::is_convertible<unsigned, date::weekday>{}, "");
static_assert( std::is_convertible<date::sys_days, date::weekday>{}, ""); static_assert( std::is_convertible<date::sys_days, date::weekday>{}, "");
static_assert(!std::is_convertible<date::weekday, unsigned>{}, ""); static_assert(!std::is_convertible<date::weekday, unsigned>{}, "");
static_assert(static_cast<unsigned>(date::weekday{1u}) == 1, "");
static_assert( date::weekday{0u}.ok(), ""); static_assert( date::weekday{0u}.ok(), "");
static_assert( date::weekday{1u}.ok(), ""); static_assert( date::weekday{1u}.ok(), "");
@ -90,7 +88,8 @@ static_assert( date::weekday{3u}.ok(), "");
static_assert( date::weekday{4u}.ok(), ""); static_assert( date::weekday{4u}.ok(), "");
static_assert( date::weekday{5u}.ok(), ""); static_assert( date::weekday{5u}.ok(), "");
static_assert( date::weekday{6u}.ok(), ""); static_assert( date::weekday{6u}.ok(), "");
static_assert(!date::weekday{7u}.ok(), ""); static_assert( date::weekday{7u}.ok(), "");
static_assert(!date::weekday{8u}.ok(), "");
void void
test_weekday_arithmetic() test_weekday_arithmetic()

View File

@ -171,7 +171,7 @@ test_with_date_weekday()
auto constexpr d1 = iso_week::sun; auto constexpr d1 = iso_week::sun;
static_assert(unsigned{d1} == 7, ""); static_assert(unsigned{d1} == 7, "");
auto constexpr d2 = date::weekday{d1}; auto constexpr d2 = date::weekday{d1};
static_assert(unsigned{d2} == 0, ""); static_assert(d2 == date::Sunday, "");
auto constexpr d3 = iso_week::weekday{d2}; auto constexpr d3 = iso_week::weekday{d2};
static_assert(unsigned{d3} == 7, ""); static_assert(unsigned{d3} == 7, "");
} }