From 203efdc6b7b57329ee3431e468300ca01a99fd4c Mon Sep 17 00:00:00 2001
From: Jonathan Wakely
Date: Mon, 4 Nov 2024 11:23:30 +0000
Subject: [PATCH 1/7] Build programs as C++20
Use ubuntu-24.04 and g++-14 for GitHub workflows.
---
.github/workflows/check-build.yml | 4 ++--
.github/workflows/check-pr.yml | 4 ++--
.github/workflows/deploy.yml | 4 ++--
Makefile | 2 +-
bin/build_pgms.bat | 10 +++++-----
5 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/.github/workflows/check-build.yml b/.github/workflows/check-build.yml
index 9f4f278138..5b9e82393f 100644
--- a/.github/workflows/check-build.yml
+++ b/.github/workflows/check-build.yml
@@ -15,7 +15,7 @@ on:
jobs:
build:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
@@ -23,7 +23,7 @@ jobs:
fetch-depth: 1
- name: Compile binary programs
- run: make pgms
+ run: make CXX=g++-14 pgms
- name: Check for carriage returns
run: |
diff --git a/.github/workflows/check-pr.yml b/.github/workflows/check-pr.yml
index 9e11dcbca1..d6bfc601f4 100644
--- a/.github/workflows/check-pr.yml
+++ b/.github/workflows/check-pr.yml
@@ -13,7 +13,7 @@ on:
jobs:
build:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
@@ -21,7 +21,7 @@ jobs:
fetch-depth: 1
- name: Compile binary programs
- run: make pgms
+ run: make CXX=g++-14 pgms
- name: Extract issue timestamps from published files
run: |
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 270a7d452c..6401694f4f 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -9,7 +9,7 @@ on:
jobs:
update-html-pages:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
steps:
- name: Use cached git repo
@@ -51,7 +51,7 @@ jobs:
run: make dates
- name: Build programs
- run: make pgms -j 4
+ run: make CXX=g++-14 pgms -j 4
- name: Generate HTML lists
run: make lists
diff --git a/Makefile b/Makefile
index 77e5bbf2fd..8e8b3501df 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
# The binaries that we want to build
PGMS := bin/lists bin/section_data bin/toc_diff bin/list_issues bin/set_status
-CXXFLAGS := -std=c++17 -Wall -g -O2 -D_GLIBCXX_ASSERTIONS
+CXXFLAGS := -std=c++20 -Wall -g -O2 -D_GLIBCXX_ASSERTIONS
CPPFLAGS := -MMD
# Running 'make debug' is equivalent to 'make DEBUG=1'
diff --git a/bin/build_pgms.bat b/bin/build_pgms.bat
index 54fa375b30..0982debb4c 100644
--- a/bin/build_pgms.bat
+++ b/bin/build_pgms.bat
@@ -1,7 +1,7 @@
echo "Use -m32 switch to force 32-bit build"
-g++ %* -std=c++17 -DNDEBUG -O2 -o bin/lists.exe src/date.cpp src/issues.cpp src/status.cpp src/sections.cpp src/mailing_info.cpp src/report_generator.cpp src/metadata.cpp src/lists.cpp
-g++ %* -std=c++17 -o bin/section_data.exe src/section_data.cpp
-g++ %* -std=c++17 -o bin/toc_diff.exe src/toc_diff.cpp
-g++ %* -std=c++17 -DNDEBUG -O2 -o bin/list_issues.exe src/date.cpp src/issues.cpp src/status.cpp src/sections.cpp src/metadata.cpp src/list_issues.cpp
-g++ %* -std=c++17 -DNDEBUG -O2 -o bin/set_status.exe src/set_status.cpp src/status.cpp
+g++ %* -std=c++20 -DNDEBUG -O2 -o bin/lists.exe src/date.cpp src/issues.cpp src/status.cpp src/sections.cpp src/mailing_info.cpp src/report_generator.cpp src/metadata.cpp src/lists.cpp
+g++ %* -std=c++20 -o bin/section_data.exe src/section_data.cpp
+g++ %* -std=c++20 -o bin/toc_diff.exe src/toc_diff.cpp
+g++ %* -std=c++20 -DNDEBUG -O2 -o bin/list_issues.exe src/date.cpp src/issues.cpp src/status.cpp src/sections.cpp src/metadata.cpp src/list_issues.cpp
+g++ %* -std=c++20 -DNDEBUG -O2 -o bin/set_status.exe src/set_status.cpp src/status.cpp
From 8e9f7deecaf1a3dad8cbda6b36927ef3239052d9 Mon Sep 17 00:00:00 2001
From: Jonathan Wakely
Date: Mon, 4 Nov 2024 11:24:33 +0000
Subject: [PATCH 2/7] Use string::starts_with
---
src/list_issues.cpp | 2 +-
src/lists.cpp | 2 +-
src/sections.cpp | 2 +-
src/status.cpp | 6 ++----
4 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/src/list_issues.cpp b/src/list_issues.cpp
index d112723027..09e3b20124 100644
--- a/src/list_issues.cpp
+++ b/src/list_issues.cpp
@@ -61,7 +61,7 @@ auto read_file_into_string(fs::path const & filename) -> std::string {
auto is_issue_xml_file(fs::directory_entry const & e) {
if (e.is_regular_file()) {
fs::path f = e.path().filename();
- return f.string().compare(0, 5, "issue") == 0 && f.extension() == ".xml";
+ return f.string().starts_with("issue") && f.extension() == ".xml";
}
return false;
}
diff --git a/src/lists.cpp b/src/lists.cpp
index 01d5a5b86f..96e476e5e9 100644
--- a/src/lists.cpp
+++ b/src/lists.cpp
@@ -73,7 +73,7 @@ auto read_file_into_string(fs::path const & filename) -> std::string {
auto is_issue_xml_file(fs::directory_entry const & e) {
if (e.is_regular_file()) {
fs::path f = e.path().filename();
- return f.string().compare(0, 5, "issue") == 0 && f.extension() == ".xml";
+ return f.string().starts_with("issue") && f.extension() == ".xml";
}
return false;
}
diff --git a/src/sections.cpp b/src/sections.cpp
index 0dac83ebbb..546ee39bba 100644
--- a/src/sections.cpp
+++ b/src/sections.cpp
@@ -180,7 +180,7 @@ auto lwg::format_section_tag_as_link(section_map & section_db, section_tag const
std::string url;
if (!tag.prefix.empty()) {
std::string_view fund_ts = "fund.ts";
- if (tag.prefix.compare(0, fund_ts.size(), fund_ts) == 0) {
+ if (tag.prefix.starts_with(fund_ts)) {
std::string_view version = tag.prefix;
version.remove_prefix(fund_ts.size());
if (version.empty())
diff --git a/src/status.cpp b/src/status.cpp
index 642807aba2..12badc2b47 100644
--- a/src/status.cpp
+++ b/src/status.cpp
@@ -73,9 +73,7 @@ auto lwg::is_closed(std::string_view stat) -> bool {
}
auto lwg::is_tentative(std::string_view stat) -> bool {
- // a more efficient implementation will use some variation of strcmp
- std::string_view tent{"Tentatively"};
- return 0 == stat.compare(0, tent.size(), tent);
+ return stat.starts_with("Tentatively");
}
auto lwg::is_assigned_to_another_group(std::string_view stat) -> bool {
@@ -104,7 +102,7 @@ auto lwg::is_ready(std::string_view stat) -> bool {
// Functions to "normalize" a status string
namespace {
auto remove_prefix(std::string_view str, std::string_view prefix) -> std::string_view {
- if (0 == str.compare(0, prefix.size(), prefix)) {
+ if (str.starts_with(prefix)) {
str.remove_prefix(prefix.size() + 1);
}
return str;
From 53445bf3b918ceb8db05e6799643355bb0fbbff5 Mon Sep 17 00:00:00 2001
From: Jonathan Wakely
Date: Mon, 4 Nov 2024 12:41:23 +0000
Subject: [PATCH 3/7] Replace src/date.cpp with C++20 and
Use workarounds for missing chrono::parse and chrono::clock_cast.
---
Makefile | 4 +-
bin/build_pgms.bat | 4 +-
src/date.cpp | 344 ---------------------------------------
src/date.h | 328 -------------------------------------
src/issues.cpp | 69 ++++----
src/issues.h | 7 +-
src/list_issues.cpp | 2 +-
src/lists.cpp | 4 +-
src/report_generator.cpp | 43 +----
9 files changed, 51 insertions(+), 754 deletions(-)
delete mode 100644 src/date.cpp
delete mode 100644 src/date.h
diff --git a/Makefile b/Makefile
index 8e8b3501df..ff9210079c 100644
--- a/Makefile
+++ b/Makefile
@@ -35,13 +35,13 @@ pgms: $(PGMS)
-include src/*.d
-bin/lists: src/date.o src/issues.o src/status.o src/sections.o src/mailing_info.o src/report_generator.o src/lists.o src/metadata.o
+bin/lists: src/issues.o src/status.o src/sections.o src/mailing_info.o src/report_generator.o src/lists.o src/metadata.o
bin/section_data: src/section_data.o
bin/toc_diff: src/toc_diff.o
-bin/list_issues: src/date.o src/issues.o src/status.o src/sections.o src/list_issues.o src/metadata.o
+bin/list_issues: src/issues.o src/status.o src/sections.o src/list_issues.o src/metadata.o
bin/set_status: src/set_status.o src/status.o
diff --git a/bin/build_pgms.bat b/bin/build_pgms.bat
index 0982debb4c..0c09376f44 100644
--- a/bin/build_pgms.bat
+++ b/bin/build_pgms.bat
@@ -1,7 +1,7 @@
echo "Use -m32 switch to force 32-bit build"
-g++ %* -std=c++20 -DNDEBUG -O2 -o bin/lists.exe src/date.cpp src/issues.cpp src/status.cpp src/sections.cpp src/mailing_info.cpp src/report_generator.cpp src/metadata.cpp src/lists.cpp
+g++ %* -std=c++20 -DNDEBUG -O2 -o bin/lists.exe src/issues.cpp src/status.cpp src/sections.cpp src/mailing_info.cpp src/report_generator.cpp src/metadata.cpp src/lists.cpp
g++ %* -std=c++20 -o bin/section_data.exe src/section_data.cpp
g++ %* -std=c++20 -o bin/toc_diff.exe src/toc_diff.cpp
-g++ %* -std=c++20 -DNDEBUG -O2 -o bin/list_issues.exe src/date.cpp src/issues.cpp src/status.cpp src/sections.cpp src/metadata.cpp src/list_issues.cpp
+g++ %* -std=c++20 -DNDEBUG -O2 -o bin/list_issues.exe src/issues.cpp src/status.cpp src/sections.cpp src/metadata.cpp src/list_issues.cpp
g++ %* -std=c++20 -DNDEBUG -O2 -o bin/set_status.exe src/set_status.cpp src/status.cpp
diff --git a/src/date.cpp b/src/date.cpp
deleted file mode 100644
index 72b5ee80e4..0000000000
--- a/src/date.cpp
+++ /dev/null
@@ -1,344 +0,0 @@
-// I, Howard Hinnant, hereby place this code in the public domain.
-
-#ifdef _MSC_VER
-# define _CRT_SECURE_NO_WARNINGS
-#endif
-
-#include "date.h"
-#include
-
-namespace gregorian
-{
-
-namespace detail
-{
-
-unsigned spec::id_next = 0;
-
-} // detail
-
-
-//static const unsigned char date::lastDay_s[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-static constexpr unsigned char date_lastDay_s[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-
-const detail::spec last;
-const detail::spec first;
-
-
-date::date() {
- time_t systime;
- time(&systime);
- struct tm* now = std::localtime(&systime);
- year_ = (unsigned short)(now->tm_year+1900);
- month_ = (unsigned char)(now->tm_mon+1);
- day_ = (unsigned char)(now->tm_mday);
- fix_from_ymd();
-}
-
-date::date(detail::day_month_spec dm, gregorian::year y)
- : year_{(unsigned short)y.value}
- , month_{(unsigned char)dm.m_.value}
- , day_{dm.d_.d_}
- {
- init();
-}
-
-date::date(gregorian::day d, detail::month_year_spec my)
- : year_{(unsigned short)my.y_.value}
- , month_{(unsigned char)my.m_.value}
- , day_{d.d_}
- {
- init();
-}
-
-
-void date::init() {
- if (day_ & 0xE0) {
- int dow = ((day_ & 0xE0) >> 5) - 1;
- int n = day_ & 0x1F;
- if (n == 0) {
- n = 6;
- }
- day_ = 0;
- encode(dow, n);
- }
- else if (day_ == 0) {
- encode(-1, 6);
- }
- fix_from_ymd();
-}
-
-
-void date::decode(int& dow, int& n) const noexcept {
- if (day_ & 0xE0) {
- dow = ((day_ & 0xE0) >> 5) - 1;
- }
- else {
- dow = -1;
- }
- n = month_ >> 4;
-}
-
-
-void date::encode(int dow, int n) noexcept {
- day_ &= 0x1F;
- month_ &= 0x0F;
- if (dow >= 0) {
- day_ |= (unsigned char)((dow + 1) << 5);
- }
- month_ |= (unsigned char)(n << 4);
-}
-
-// This could be turned into a constexpr free-function taking 'year' by value as its argument.
-// However, there would be no advantage in the application we are currently working on.
-auto date::is_leap() const noexcept -> bool {
- if (year_ > 1582) {
- if (year_ % 400 == 0) {
- return true;
- }
- if (year_ % 100 == 0) {
- return false;
- }
- }
- return year_ % 4 == 0;
-}
-
-void date::fix_from_ymd() {
- int dow, n;
- decode(dow, n);
- int d = day();
- int m = month();
- int y = year();
- if (0 <= dow and dow <= 6) {
- if (n == 0 or n > 6) {
- throw bad_date{};
- }
- date tmp1 = gregorian::day(1) / m / y;
- date tmp2 = last / m / y;
- int wd = tmp1.day_of_week();
- int delta{0};
- if (dow != wd) {
- if (dow < wd) {
- delta += 7 - (wd - dow);
- }
- else {
- delta += dow - wd;
- }
- }
- delta += (n-1)*7;
- if (n == 6 and delta >= tmp2.day()) {
- delta -= 7 * ((delta - tmp2.day()) / 7 + 1);
- }
- tmp1 += delta;
- if (tmp1.month() != m) {
- throw bad_date{};
- }
- *this = tmp1;
- encode(dow, n);
- return;
- }
-
- if (dow != -1) {
- throw bad_date{};
- }
- if (n != 0 and n != 6) {
- throw bad_date();
- }
- if ((d == 0 and n == 0) or m == 0 or m > 12) {
- throw bad_date{};
- }
-
- if (n == 6) {
- d = 0;
- }
-
- unsigned long jdate = 0;
- bool leap = is_leap();
- if (leap and m == 2) {
- if (d > 29) {
- throw bad_date{};
- }
- if (n == 6) {
- d = 29;
- }
- }
- else {
- if (d > date_lastDay_s[m-1]) {
- throw bad_date{};
- }
- if (n == 6) {
- d = date_lastDay_s[m-1];
- }
- }
-
- if (y == 1582 and m == 10 and d >= 5 and d <= 14) {
- throw bad_date{};
- }
-
- if (y > 0) {
- jdate = 365U * y + 1; // Jan 1, 0 == 1 and y 0 is leap y
- --y;
- jdate += y / 4;
- if (y >= 1700) {
- jdate += -(y-1600) / 100 + (y-1600) / 400;
- }
- ++y;
- }
-
- for (int i = 0; i < m-1; ++i) {
- jdate += date_lastDay_s[i];
- }
- if (leap and m > 2) {
- ++jdate;
- }
- jdate += d;
- // If date >= 10/15/1582 then subtract 10
- if (jdate >= 578114) {
- jdate -= 10;
- }
-
-// if (y >= 1582) {
-// if (y == 1582) {
-// if (m >= 10) {
-// if (m == 10) {
-// if (d >= 15) {
-// jdate -= 10;
-// }
-// }
-// else { // m > 10
-// jdate -= 10;
-// }
-// }
-// }
-// else { // y > 1582
-// jdate -= 10;
-// }
-// }
-
- if (jdate <= 0) {
- throw bad_date{};
- }
-
- jdate_ = jdate;
- year_ = (unsigned short)y;
- month_ = (unsigned char)m;
- day_ = (unsigned char)d;
- encode(dow, n);
-}
-
-
-void date::fix_from_jdate() {
- if (jdate_ <= 0) {
- throw bad_date{};
- }
-
- int dow, n;
- decode(dow, n);
- year_ = static_cast(jdate_ / 365.2475);
- date lower = gregorian::day(1) / 1 / year_;
- date upper = gregorian::day(31) / 12 / year_;
- for(;;) {
- if (lower.jdate_ > jdate_) {
- --year_;
- }
- else if (upper.jdate_ < jdate_) {
- ++year_;
- }
- else {
- break;
- }
- lower = gregorian::day(1) / 1 / year_;
- upper = gregorian::day(31) / 12 / year_;
- }
-
- month_ = static_cast((jdate_ - lower.jdate_) / 30 + 1);
- if (month_ > 12) {
- month_ = 12;
- }
-
- for(;;) {
- lower = gregorian::day(1) / month_ / year_;
- upper = gregorian::last / month_ / year_;
- if (lower.jdate_ > jdate_) {
- --month_;
- }
- else if (upper.jdate_ < jdate_) {
- ++month_;
- }
- else {
- break;
- }
- }
-
- day_ = static_cast(jdate_ - lower.jdate_ + 1);
- if (year_ == 1582 and month_ == 10 and day_ >= 5) {
- day_ += 10;
- }
-}
-
-
-auto date::operator+=(int d) -> date & {
- jdate_ += d;
- fix_from_jdate();
- return *this;
-}
-
-} // gregorian
-
-// gcc will not recognise 'noexcept' specifier as matching the header
-auto gregorian::operator*(detail::spec s, week_day wd) -> day {
- day d{1};
- d.d_ = (unsigned char)((wd.d_+1) << 5);
- if (s == first) {
- d.d_ |= 1;
- }
- return d;
-}
-
-
-auto gregorian::operator*(int n, week_day wd) -> day {
- day d{1};
- if (n < 1 or n > 5) {
- throw bad_date{};
- }
- d.d_ = (unsigned char)(((wd.d_+1) << 5) | n);
- return d;
-}
-
-
-auto gregorian::operator+(const date& dt, month mnth) -> date {
- int dow, n;
- dt.decode(dow, n);
- int y = dt.year();
- int m = dt.month();
- int d = dt.day();
- int new_month = m - 1 + mnth.value;
- if (new_month < 0) {
- int delta = ((-new_month - 1) / 12 + 1) * 12;
- y -= delta / 12;
- new_month += delta;
- }
- else if (new_month > 11) {
- int delta = ((new_month - 12) / 12 + 1) * 12;
- y += delta / 12;
- new_month -= delta;
- }
- m = new_month + 1;
- date result{y, m, d};
- result.encode(dow, n);
- result.fix_from_ymd();
- return result;
-}
-
-
-auto gregorian::operator+(date const & dt, year yr) -> date {
- int dow, n;
- dt.decode(dow, n);
- int y = dt.year() + yr.value;
- int m = dt.month();
- int d = dt.day();
- date result{y, m, d};
- result.encode(dow, n);
- result.fix_from_ymd();
- return result;
-}
diff --git a/src/date.h b/src/date.h
deleted file mode 100644
index bd54f9f32e..0000000000
--- a/src/date.h
+++ /dev/null
@@ -1,328 +0,0 @@
-// I, Howard Hinnant, hereby place this code in the public domain.
-// Since tweaked by Alisdair Meredith, also in the public domain.
-
-#ifndef DATE_H
-#define DATE_H
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-namespace gregorian
-{
-
-struct day;
-struct date;
-
-namespace detail
-{
-
-struct spec {
- spec() noexcept : id_{id_next++} {}
-
- bool operator == (const spec& y) const noexcept { return id_ == y.id_; }
- bool operator != (const spec& y) const noexcept { return id_ != y.id_; }
-
-private:
- unsigned id_;
- static unsigned id_next;
-
- friend struct gregorian::day;
-};
-
-} // detail
-
-extern detail::spec const last;
-extern detail::spec const first;
-
-struct bad_date : std::exception {
- char const * what() const noexcept override { return "bad_date"; }
-};
-
-
-struct week_day
-{
- constexpr week_day(int d)
- : d_{(d < 0 or d > 6) ? throw bad_date{} : d}
- {
- }
-
-private:
- int d_;
-
- friend struct ::gregorian::date;
- friend day operator*(detail::spec s, week_day wd);
- friend day operator*( int n, week_day wd);
-};
-
-
-struct day {
- constexpr day(int d)
- : d_{(d < 1 or d > 31) ? throw bad_date{} : (unsigned char)d}
- {
- }
-
- day(detail::spec s) noexcept : d_{(unsigned char)s.id_} {}
-
-private:
- unsigned char d_;
-
- friend struct gregorian::date;
- friend day operator*(detail::spec s, week_day wd);
- friend day operator*( int n, week_day wd);
-};
-
-
-struct month {
- constexpr month(int m) noexcept : value{m} {}
- int value;
-};
-
-
-struct year {
- constexpr year(int y) noexcept : value{y} {}
- int value;
-};
-
-
-static constexpr week_day sun{0};
-static constexpr week_day mon{1};
-static constexpr week_day tue{2};
-static constexpr week_day wed{3};
-static constexpr week_day thu{4};
-static constexpr week_day fri{5};
-static constexpr week_day sat{6};
-
-static constexpr month jan{1};
-static constexpr month feb{2};
-static constexpr month mar{3};
-static constexpr month apr{4};
-static constexpr month may{5};
-static constexpr month jun{6};
-static constexpr month jul{7};
-static constexpr month aug{8};
-static constexpr month sep{9};
-static constexpr month oct{10};
-static constexpr month nov{11};
-static constexpr month dec{12};
-
-namespace detail
-{
-
-struct day_month_spec {
- constexpr day_month_spec(day d, month m);
-
-private:
- day d_;
- month m_;
-
- friend struct gregorian::date;
-};
-
-inline constexpr
-day_month_spec::day_month_spec(day d, month m)
- : d_{d}
- , m_{m}
- {
-}
-
-struct month_year_spec
-{
- constexpr month_year_spec(month m, year y);
-
-private:
- month m_;
- year y_;
-
- friend struct gregorian::date;
-};
-
-inline constexpr
-month_year_spec::month_year_spec(month m, year y)
- : m_{m}
- , y_{y}
- {
-}
-
-} // detail
-
-date operator+(date const &, month);
-date operator+(date const &, year);
-
-struct date {
- date();
- date(detail::day_month_spec dm, gregorian::year y);
- date(gregorian::day d, detail::month_year_spec my);
-
- constexpr int day() const noexcept {return day_ & 0x1F;}
- constexpr int month() const noexcept {return month_ & 0x0F;}
- constexpr int year() const noexcept {return year_;}
- constexpr int day_of_week() const noexcept {return static_cast((jdate_+3) % 7);}
- bool is_leap() const noexcept;
-
- date& operator+=(int d);
- date& operator++() {return *this += 1;}
- date operator++(int) {date tmp(*this); *this += 1; return tmp;}
- date& operator-=(int d) {return *this += -d;}
- date& operator--() {return *this -= 1;}
- date operator--(int) {date tmp(*this); *this -= 1; return tmp;}
- friend date operator+(const date& x, int y) {date r(x); r += y; return r;}
- friend date operator+(int x, const date& y) {return y + x;}
- friend date operator-(const date& x, int y) {date r(x); r += -y; return r;}
-
- date& operator+=(gregorian::month m) {*this = *this + m; return *this;}
- date& operator-=(gregorian::month m) {return *this += gregorian::month(-m.value);}
- friend date operator+(gregorian::month m, const date& y) {return y + m;}
- friend date operator-(const date& x, gregorian::month m) {date r(x); r -= m; return r;}
-
- date& operator+=(gregorian::year y) {*this = *this + y; return *this;}
- date& operator-=(gregorian::year y) {return *this += gregorian::year(-y.value);}
- friend date operator+(gregorian::year y, const date& x) {return x + y;}
- friend date operator-(const date& x, gregorian::year y) {date r(x); r -= y; return r;}
-
- friend constexpr long operator- (const date& x, const date& y) noexcept {return (long)(x.jdate_ - y.jdate_);}
- friend constexpr bool operator==(const date& x, const date& y) noexcept {return x.jdate_ == y.jdate_;}
- friend constexpr bool operator!=(const date& x, const date& y) noexcept {return x.jdate_ != y.jdate_;}
- friend constexpr bool operator< (const date& x, const date& y) noexcept {return x.jdate_ < y.jdate_;}
- friend constexpr bool operator<=(const date& x, const date& y) noexcept {return x.jdate_ <= y.jdate_;}
- friend constexpr bool operator> (const date& x, const date& y) noexcept {return x.jdate_ > y.jdate_;}
- friend constexpr bool operator>=(const date& x, const date& y) noexcept {return x.jdate_ >= y.jdate_;}
-
-private:
-
- constexpr date(int y, int m, int d)
- : jdate_{}
- , year_{(unsigned short)y}
- , month_{(unsigned char)m}
- , day_{(unsigned char)d}
- {
- }
-
- void init();
- void fix_from_ymd();
- void fix_from_jdate();
- void decode(int& dow, int& n) const noexcept;
- void encode(int dow, int n) noexcept;
-
- friend date operator+(const date&, gregorian::month);
- friend date operator+(const date&, gregorian::year);
-
-private:
- unsigned long jdate_;
- unsigned short year_;
- unsigned char month_;
- unsigned char day_;
-
-// static const unsigned char lastDay_s[12];
-};
-
-//constexpr unsigned char date::lastDay_s[12] { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-
-auto operator*(detail::spec s, week_day wd) -> day;
-auto operator*(int n, week_day wd) -> day;
-
-
-inline constexpr
-auto operator/(day d, month m) -> detail::day_month_spec {
- return detail::day_month_spec{d, m};
-}
-
-inline constexpr
-auto operator/(month m, day d) -> detail::day_month_spec {
- return detail::day_month_spec{d, m};
-}
-
-inline constexpr
-auto operator/(year y, month m) -> detail::month_year_spec {
- return detail::month_year_spec{m, y};
-}
-
-inline
-auto operator/(detail::day_month_spec dm, year y) -> date {
- return date{dm, y};
-}
-
-inline
-auto operator/(detail::month_year_spec my, day d) -> date {
- return date{d, my};
-}
-
-
-namespace detail
-{
-
-inline
-auto operator/(spec d, int m) -> detail::day_month_spec {
- return day{d} / month{m};
-}
-
-inline
-auto operator/(int m, spec d) -> detail::day_month_spec {
- return day{d} / month{m};
-}
-
-inline
-auto operator/(detail::day_month_spec dm, int y) -> date {
- return date{dm, year{y}};
-}
-
-inline
-auto operator/(detail::month_year_spec my, int d) -> date {
- return date{day{d}, my};
-}
-
-} // detail
-
-template
-auto operator >>(std::basic_istream & is, date & item) -> std::basic_istream & {
- typename std::basic_istream::sentry ok(is);
- if (ok) {
- std::ios_base::iostate err = std::ios_base::goodbit;
- try {
- std::time_get const & tg = std::use_facet >(is.getloc());
- std::tm t;
- tg.get_date(is, 0, is, err, &t);
- if (!(err & std::ios_base::failbit)) {
- item = date(month(t.tm_mon+1) / day(t.tm_mday) / year(t.tm_year+1900));
- }
- }
- catch (...) {
- err |= std::ios_base::badbit | std::ios_base::failbit;
- }
- is.setstate(err);
- }
- return is;
-}
-
-template
-auto operator <<(std::basic_ostream & os, date const & item) -> std::basic_ostream & {
- typename std::basic_ostream::sentry ok{os};
- if (ok) {
- bool failed;
- try {
- std::time_put const & tp = std::use_facet >(os.getloc());
- std::tm t;
- t.tm_mday = item.day();
- t.tm_mon = item.month() - 1;
- t.tm_year = item.year() - 1900;
- t.tm_wday = item.day_of_week();
- charT pattern[2] = {'%', 'x'};
- failed = tp.put(os, os, os.fill(), &t, pattern, pattern+2).failed();
- }
- catch (...) {
- failed = true;
- }
-
- if (failed) {
- os.setstate(std::ios_base::failbit | std::ios_base::badbit);
- }
- }
- return os;
-}
-
-} // gregorian
-
-#endif // DATE_H
diff --git a/src/issues.cpp b/src/issues.cpp
index 550901a410..dbeb7904cf 100644
--- a/src/issues.cpp
+++ b/src/issues.cpp
@@ -26,25 +26,13 @@
namespace fs = std::filesystem;
namespace {
-// date utilites may factor out again
-auto parse_month(std::string const & m) -> gregorian::month {
- // This could be turned into an efficient map lookup with a suitable indexed container
- return (m == "Jan") ? gregorian::jan
- : (m == "Feb") ? gregorian::feb
- : (m == "Mar") ? gregorian::mar
- : (m == "Apr") ? gregorian::apr
- : (m == "May") ? gregorian::may
- : (m == "Jun") ? gregorian::jun
- : (m == "Jul") ? gregorian::jul
- : (m == "Aug") ? gregorian::aug
- : (m == "Sep") ? gregorian::sep
- : (m == "Oct") ? gregorian::oct
- : (m == "Nov") ? gregorian::nov
- : (m == "Dec") ? gregorian::dec
- : throw std::runtime_error{"unknown month abbreviation " + m};
-}
-
-auto parse_date(std::istream & temp) -> gregorian::date {
+auto parse_date(std::istream & temp) -> std::chrono::year_month_day {
+#if __cpp_lib_chrono >= 201803L
+ std::chrono::year_month_day date{};
+ if (temp >> std::chrono::parse(" %d %b %Y", date))
+ return date;
+ throw std::runtime_error{"date format error"};
+#else
int d;
temp >> d;
if (temp.fail()) {
@@ -54,29 +42,34 @@ auto parse_date(std::istream & temp) -> gregorian::date {
std::string month;
temp >> month;
- auto m = parse_month(month);
+ std::map months{
+ {"Jan", 1}, {"Feb", 2}, {"Mar", 3}, {"Apr", 4}, {"May", 5}, {"Jun", 6},
+ {"Jul", 7}, {"Aug", 8}, {"Sep", 9}, {"Oct",10}, {"Nov",11}, {"Dec",12}
+ };
+
int y{ 0 };
temp >> y;
- return m/gregorian::day{d}/y;
-}
-
-auto make_date(std::tm const & mod) -> gregorian::date {
- return gregorian::year((unsigned short)(mod.tm_year+1900)) / (mod.tm_mon+1) / mod.tm_mday;
+ return std::chrono::year{y}/months[month]/d;
+#endif
}
-auto report_date_file_last_modified(std::filesystem::path const & filename, lwg::metadata const& meta) -> gregorian::date {
- std::time_t mtime;
+auto report_date_file_last_modified(std::filesystem::path const & filename, lwg::metadata const& meta) -> std::chrono::year_month_day {
+ using namespace std::chrono;
+ system_clock::time_point t;
int id = std::stoi(filename.filename().stem().native().substr(5));
if (auto it = meta.git_commit_times.find(id); it != meta.git_commit_times.end())
- mtime = it->second;
- else
- {
- auto file_mtime = fs::last_write_time(filename);
- auto sys_mtime = std::chrono::system_clock::now() - (fs::file_time_type::clock::now() - file_mtime);
- mtime = std::chrono::duration_cast(sys_mtime.time_since_epoch()).count();
+ t = system_clock::from_time_t(it->second);
+ else {
+ auto mtime = fs::last_write_time(filename);
+#if __cpp_lib_chrono >= 201803L
+ t = clock_cast(mtime);
+#else
+ auto fnow = fs::file_time_type::clock::now();
+ t = system_clock::now() - round(fnow - mtime);
+#endif
}
- return make_date(*std::gmtime(&mtime));
+ return year_month_day(floor(t));
}
// Replace '<' and '>' and '&' with HTML character references.
@@ -246,14 +239,14 @@ auto lwg::parse_issue_from_file(std::string tx, std::string const & filename,
try {
std::istringstream temp{tx.substr(k, l-k)};
is.date = parse_date(temp);
-
- // Get modification date
- is.mod_date = report_date_file_last_modified(filename, meta);
}
catch(std::exception const & ex) {
- throw bad_issue_file{filename, ex.what()};
+ throw bad_issue_file{filename, "date format error"};
}
+ // Get modification date
+ is.mod_date = report_date_file_last_modified(filename, meta);
+
// Get priority - this element is optional
k = tx.find("", l);
if (k != std::string::npos) {
diff --git a/src/issues.h b/src/issues.h
index 0bead73792..8981b8f995 100644
--- a/src/issues.h
+++ b/src/issues.h
@@ -2,18 +2,19 @@
#define INCLUDE_LWG_ISSUES_H
// standard headers
+#include
#include
\n";
+ << " Opened: " << iss.date
+ << " Last modified: " << iss.mod_date
+ << "\n";
// priority
out << "Priority: ";
@@ -459,7 +434,7 @@ R"(
Date: |
- )" << format_time("%Y-%m-%d", utc_timestamp()) << R"( |
+ )" << build_date << R"( |
Project: |
From 9a5d45398e3f2064ee63050c6b6d34261f6d7668 Mon Sep 17 00:00:00 2001
From: Jonathan Wakely
Date: Mon, 4 Nov 2024 12:57:29 +0000
Subject: [PATCH 4/7] Update Prerequisites in how-to-docs
---
how-to-docs.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/how-to-docs.html b/how-to-docs.html
index 4f280e75db..d1f4807a71 100644
--- a/how-to-docs.html
+++ b/how-to-docs.html
@@ -25,7 +25,7 @@ How To Instructions
Prerequisites
- Git
- - A C++17 compiler. Clang 9 works. GCC 8.x works for unix-like systems, but GCC 9.3 is recommended (because its
std::filesystem
supports Windows, and no additional -lstdc++fs
linker option is needed).
+ - A C++20 compiler. GCC 13 works, as does Clang 16.
- Windows is a prerequisite to use the Windows
.bat
scripts;
a POSIX environment is a prerequisite to use the equivalent make
commands.
From 73af2394e20f77c826d9f668b6e0f849b5d3e0d3 Mon Sep 17 00:00:00 2001
From: Jonathan Wakely
Date: Mon, 4 Nov 2024 16:49:44 +0000
Subject: [PATCH 5/7] Replace 'order_by_priority' with std::ranges::sort with
projection
---
src/report_generator.cpp | 24 ++++--------------------
1 file changed, 4 insertions(+), 20 deletions(-)
diff --git a/src/report_generator.cpp b/src/report_generator.cpp
index 8f83727455..31f04b30a5 100644
--- a/src/report_generator.cpp
+++ b/src/report_generator.cpp
@@ -95,25 +95,6 @@ struct order_by_status {
};
-struct order_by_priority {
- explicit order_by_priority(lwg::section_map §ions)
- : section_db(sections)
- {
- }
-
- auto operator()(lwg::issue const & x, lwg::issue const & y) const -> bool {
- assert(!x.tags.empty());
- assert(!y.tags.empty());
- auto tie = [this](auto& i) {
- return std::tie(i.priority, section_db[i.tags.front()], i.num);
- };
- return tie(x) < tie(y);
- }
-
-private:
- lwg::section_map& section_db;
-};
-
// Replace spaces to make a string usable as an 'id' attribute,
// or as an URL fragment (#foo) that links to an 'id' attribute.
inline std::string spaces_to_underscores(std::string s) {
@@ -673,7 +654,10 @@ R"(