]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
refactor: Use std::chrono instead of custom classes
authorJoel Rosdahl <joel@rosdahl.net>
Sun, 5 Oct 2025 13:24:17 +0000 (15:24 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Sun, 5 Oct 2025 19:03:43 +0000 (21:03 +0200)
33 files changed:
src/ccache/ccache.cpp
src/ccache/context.cpp
src/ccache/context.hpp
src/ccache/core/cacheentry.cpp
src/ccache/core/manifest.cpp
src/ccache/core/manifest.hpp
src/ccache/core/statistics.cpp
src/ccache/core/statistics.hpp
src/ccache/inodecache.cpp
src/ccache/inodecache.hpp
src/ccache/storage/local/localstorage.cpp
src/ccache/storage/local/localstorage.hpp
src/ccache/util/CMakeLists.txt
src/ccache/util/direntry.hpp
src/ccache/util/duration.hpp [deleted file]
src/ccache/util/file.cpp
src/ccache/util/file.hpp
src/ccache/util/lockfile.cpp
src/ccache/util/lockfile.hpp
src/ccache/util/logging.cpp
src/ccache/util/string.cpp
src/ccache/util/string.hpp
src/ccache/util/time.cpp
src/ccache/util/time.hpp
src/ccache/util/timepoint.cpp [deleted file]
src/ccache/util/timepoint.hpp [deleted file]
unittest/CMakeLists.txt
unittest/test_inodecache.cpp
unittest/test_util_direntry.cpp
unittest/test_util_duration.cpp [deleted file]
unittest/test_util_lockfile.cpp
unittest/test_util_string.cpp
unittest/test_util_timepoint.cpp [deleted file]

index b672332164c73735427aa446a71f7b63a3ee826d..e95ac6b7ebbfb18d3a5e11d5b05074d519e6b6c5 100644 (file)
@@ -50,7 +50,6 @@
 #include <ccache/util/conversion.hpp>
 #include <ccache/util/defer.hpp>
 #include <ccache/util/direntry.hpp>
-#include <ccache/util/duration.hpp>
 #include <ccache/util/environment.hpp>
 #include <ccache/util/exec.hpp>
 #include <ccache/util/expected.hpp>
@@ -65,7 +64,6 @@
 #include <ccache/util/string.hpp>
 #include <ccache/util/temporaryfile.hpp>
 #include <ccache/util/time.hpp>
-#include <ccache/util/timepoint.hpp>
 #include <ccache/util/tokenizer.hpp>
 #include <ccache/util/umaskscope.hpp>
 #include <ccache/util/wincompat.hpp>
@@ -96,6 +94,8 @@
 
 namespace fs = util::filesystem;
 
+using namespace std::literals::chrono_literals;
+
 using core::Statistic;
 using util::DirEntry;
 
@@ -223,21 +223,19 @@ prepare_debug_path(const fs::path& cwd,
   // trying to open the path for writing.
   std::ignore = fs::create_directories(prefix.parent_path());
 
-  char timestamp[100];
+  std::string timestamp;
   const auto tm = util::localtime(time_of_invocation);
   if (tm) {
-    (void)strftime(timestamp, sizeof(timestamp), "%Y%m%d_%H%M%S", &*tm);
+    char t[100];
+    (void)strftime(t, sizeof(t), "%Y%m%d_%H%M%S", &*tm);
+    timestamp = t;
   } else {
-    (void)snprintf(
-      timestamp,
-      sizeof(timestamp),
-      "%llu",
-      static_cast<long long unsigned int>(time_of_invocation.sec()));
+    timestamp = std::to_string(util::sec(time_of_invocation));
   }
   return FMT("{}.{}_{:06}.ccache-{}",
              prefix,
              timestamp,
-             time_of_invocation.nsec_decimal_part() / 1000,
+             util::nsec_part(time_of_invocation) / 1000,
              suffix);
 }
 
@@ -1124,7 +1122,7 @@ rewrite_stdout_from_compiler(const Context& ctx, util::Bytes&& stdout_data)
 static std::string
 format_epoch_time(const util::TimePoint& tp)
 {
-  return FMT("{}.{:09}", tp.sec(), tp.nsec_decimal_part());
+  return FMT("{}.{:09}", util::sec(tp), util::nsec_part(tp));
 }
 
 static bool
@@ -1146,8 +1144,7 @@ source_file_is_too_new(const Context& ctx, const fs::path& path)
   // A relatively small safety margin is used in this case to make things safe
   // on common filesystems while also not bailing out when creating a source
   // file reasonably close in time before the compilation.
-  const util::Duration min_age(0, 100'000'000); // 0.1 s
-  util::TimePoint deadline = ctx.time_of_invocation + min_age;
+  util::TimePoint deadline = ctx.time_of_invocation + 100ms;
 
   DirEntry dir_entry(path);
 
@@ -1495,7 +1492,7 @@ hash_compiler(const Context& ctx,
   } else if (ctx.config.compiler_check() == "mtime") {
     hash.hash_delimiter("cc_mtime");
     hash.hash(dir_entry.size());
-    hash.hash(dir_entry.mtime().nsec());
+    hash.hash(util::nsec_tot(dir_entry.mtime()));
   } else if (util::starts_with(ctx.config.compiler_check(), "string:")) {
     hash.hash_delimiter("cc_hash");
     hash.hash(&ctx.config.compiler_check()[7]);
@@ -1769,7 +1766,8 @@ hash_common_info(const Context& ctx, const util::Args& args, Hash& hash)
     // added to the hash to prevent false positive cache hits if the
     // mtime of the file changes.
     hash.hash_delimiter("-fbuild-session-file mtime");
-    hash.hash(DirEntry(ctx.args_info.build_session_file).mtime().nsec());
+    hash.hash(
+      util::nsec_tot(DirEntry(ctx.args_info.build_session_file).mtime()));
   }
 
   if (!ctx.config.extra_files_to_hash().empty()) {
index 64ada878d82142754504a02e90591e1f609f65c8..ec82d17d1e931075d8938b4c484168b3809251f7 100644 (file)
@@ -26,7 +26,7 @@
 #include <ccache/util/path.hpp>
 #include <ccache/util/process.hpp>
 #include <ccache/util/string.hpp>
-#include <ccache/util/timepoint.hpp>
+#include <ccache/util/time.hpp>
 #include <ccache/util/wincompat.hpp>
 
 #ifdef HAVE_UNISTD_H
@@ -46,7 +46,7 @@ Context::Context()
 #ifdef INODE_CACHE_SUPPORTED
     inode_cache(config),
 #endif
-    time_of_invocation(util::TimePoint::now())
+    time_of_invocation(util::now())
 {
 }
 
index e8b688df6892f40025a511200ce178ed0f8ec73a..be9b8e9dd2766784a81958ad635056a034205e71 100644 (file)
@@ -27,7 +27,7 @@
 #include <ccache/util/bytes.hpp>
 #include <ccache/util/filestream.hpp>
 #include <ccache/util/noncopyable.hpp>
-#include <ccache/util/timepoint.hpp>
+#include <ccache/util/time.hpp>
 
 #ifdef INODE_CACHE_SUPPORTED
 #  include <ccache/inodecache.hpp>
index 224e07195f06f17a16f7040b1ad50deedfd95f08..fff72625db77281d9256539e05e4941342fd7db8 100644 (file)
@@ -29,7 +29,7 @@
 #include <ccache/util/filesystem.hpp>
 #include <ccache/util/format.hpp>
 #include <ccache/util/logging.hpp>
-#include <ccache/util/timepoint.hpp>
+#include <ccache/util/time.hpp>
 #include <ccache/util/xxh3_128.hpp>
 #include <ccache/util/zstd.hpp>
 
@@ -92,7 +92,7 @@ CacheEntry::Header::Header(const Config& config,
     compression_level(compression_level_from_config(config)),
     self_contained(entry_type != CacheEntryType::result
                    || !core::result::Serializer::use_raw_files(config)),
-    creation_time(util::TimePoint::now().sec()),
+    creation_time(util::sec(util::now())),
     ccache_version(CCACHE_VERSION),
     namespace_(config.namespace_()),
     entry_size(0)
index 2a3a0af5bd56308c5019a4b0fe4d4d36d707dfe6..12c7bf10c03ec998e424f1d2e16ae479ee2f577a 100644 (file)
@@ -115,8 +115,10 @@ Manifest::read(nonstd::span<const uint8_t> data)
     reader.read_int(entry.index);
     reader.read_and_copy_bytes(entry.digest);
     reader.read_int(entry.fsize);
-    entry.mtime.set_nsec(reader.read_int<int64_t>());
-    entry.ctime.set_nsec(reader.read_int<int64_t>());
+    entry.mtime =
+      util::TimePoint(std::chrono::nanoseconds(reader.read_int<int64_t>()));
+    entry.ctime =
+      util::TimePoint(std::chrono::nanoseconds(reader.read_int<int64_t>()));
   }
 
   const auto result_count = reader.read_int<uint32_t>();
@@ -282,8 +284,8 @@ Manifest::serialize(util::Bytes& output)
     writer.write_int<uint32_t>(file_info.index);
     writer.write_bytes(file_info.digest);
     writer.write_int(file_info.fsize);
-    writer.write_int(file_info.mtime.nsec());
-    writer.write_int(file_info.ctime.nsec());
+    writer.write_int(util::nsec_tot(file_info.mtime));
+    writer.write_int(util::nsec_tot(file_info.ctime));
   }
 
   writer.write_int(static_cast<uint32_t>(m_results.size()));
@@ -467,16 +469,16 @@ Manifest::inspect(FILE* const stream) const
     } else {
       PRINT(stream,
             "    Mtime: {}.{:09}\n",
-            m_file_infos[i].mtime.sec(),
-            m_file_infos[i].mtime.nsec_decimal_part());
+            util::sec(m_file_infos[i].mtime),
+            util::nsec_part(m_file_infos[i].mtime));
     }
     if (m_file_infos[i].ctime == util::TimePoint()) {
       PRINT_RAW(stream, "    Ctime: -\n");
     } else {
       PRINT(stream,
             "    Ctime: {}.{:09}\n",
-            m_file_infos[i].ctime.sec(),
-            m_file_infos[i].ctime.nsec_decimal_part());
+            util::sec(m_file_infos[i].ctime),
+            util::nsec_part(m_file_infos[i].ctime));
     }
   }
 
index b45b39192518c86e8eb4f488155828d8fe73628e..10753c0edd8936b7ab1bed3ca41bcf2ead575331 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2009-2024 Joel Rosdahl and other contributors
+// Copyright (C) 2009-2025 Joel Rosdahl and other contributors
 //
 // See doc/authors.adoc for a complete list of contributors.
 //
@@ -21,7 +21,7 @@
 #include <ccache/core/serializer.hpp>
 #include <ccache/hash.hpp>
 #include <ccache/util/bytes.hpp>
-#include <ccache/util/timepoint.hpp>
+#include <ccache/util/time.hpp>
 
 #include <nonstd/span.hpp>
 
index 6324f0702c31c3330015a3b107a869632551dae1..2ea938d64365732c62c8a0c45d87b9585e541071 100644 (file)
@@ -274,7 +274,7 @@ static_assert(std::size(k_statistics_fields)
 static std::string
 format_timestamp(const util::TimePoint& value)
 {
-  if (value.sec() == 0) {
+  if (util::sec(value) == 0) {
     return "never";
   } else {
     const auto tm = util::localtime(value);
@@ -404,7 +404,8 @@ Statistics::format_human_readable(const Config& config,
     table.add_row(
       {"Stats updated:", C(format_timestamp(last_updated)).colspan(4)});
     if (verbosity > 1) {
-      const util::TimePoint last_zeroed(S(stats_zeroed_timestamp));
+      const util::TimePoint last_zeroed(
+        std::chrono::seconds(S(stats_zeroed_timestamp)));
       table.add_row(
         {"Stats zeroed:", C(format_timestamp(last_zeroed)).colspan(4)});
     }
@@ -545,7 +546,7 @@ Statistics::prepare_statistics_entries(
 
   result.emplace_back("max_cache_size_kibibyte", config.max_size() / 1024);
   result.emplace_back("max_files_in_cache", config.max_files());
-  result.emplace_back("stats_updated_timestamp", last_updated.sec());
+  result.emplace_back("stats_updated_timestamp", util::sec(last_updated));
 
   std::sort(result.begin(), result.end());
   return result;
index 05a7fd569965028688f7101d6e2daf5574c6c15f..c82b2e06bdf17f1276316e5d7754da126b57609a 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2020-2024 Joel Rosdahl and other contributors
+// Copyright (C) 2020-2025 Joel Rosdahl and other contributors
 //
 // See doc/authors.adoc for a complete list of contributors.
 //
@@ -20,7 +20,7 @@
 
 #include <ccache/core/statistic.hpp>
 #include <ccache/core/statisticscounters.hpp>
-#include <ccache/util/timepoint.hpp>
+#include <ccache/util/time.hpp>
 
 #include <cstdint>
 #include <string>
index 29d67e6421a2db4833fbfdbb921719b54782b445..82452c7d9650ae91ef826fb708da2f996ae744bf 100644 (file)
@@ -54,6 +54,8 @@
 
 namespace fs = util::filesystem;
 
+using namespace std::literals::chrono_literals;
+
 // The inode cache resides on a file that is mapped into shared memory by
 // running processes. It is implemented as a two level structure, where the top
 // level is a hash table consisting of buckets. Each bucket contains entries
@@ -309,7 +311,7 @@ InodeCache::hash_inode(const fs::path& path,
   }
 
   // See comment for InodeCache::InodeCache why this check is done.
-  auto now = util::TimePoint::now();
+  auto now = util::now();
   if (now - de.ctime() < m_min_age || now - de.mtime() < m_min_age) {
     LOG("Too new ctime or mtime of {}, not considering for inode cache", path);
     return false;
@@ -323,10 +325,10 @@ InodeCache::hash_inode(const fs::path& path,
   key.st_mode = de.mode();
   // Note: Manually copying sec and nsec of mtime and ctime to prevent copying
   // the padding bytes.
-  auto mtime = de.mtime().to_timespec();
+  auto mtime = util::to_timespec(de.mtime());
   key.st_mtim.tv_sec = mtime.tv_sec;
   key.st_mtim.tv_nsec = mtime.tv_nsec;
-  auto ctime = de.ctime().to_timespec();
+  auto ctime = util::to_timespec(de.ctime());
   key.st_ctim.tv_sec = ctime.tv_sec;
   key.st_ctim.tv_nsec = ctime.tv_nsec;
   key.st_size = de.size();
@@ -505,12 +507,11 @@ InodeCache::initialize()
   return false;
 }
 
-InodeCache::InodeCache(const Config& config, util::Duration min_age)
+InodeCache::InodeCache(const Config& config, std::chrono::nanoseconds min_age)
   : m_config(config),
     // CCACHE_DISABLE_INODE_CACHE_MIN_AGE is only for testing purposes; see
     // test/suites/inode_cache.bash.
-    m_min_age(getenv("CCACHE_DISABLE_INODE_CACHE_MIN_AGE") ? util::Duration(0)
-                                                           : min_age),
+    m_min_age(getenv("CCACHE_DISABLE_INODE_CACHE_MIN_AGE") ? 0ns : min_age),
     m_self_pid(getpid())
 {
 }
index 79efe78fb261848d283765e53733f75f18064200..21e3431a0b053124187a527555b57842ff3ce402 100644 (file)
 
 #include <ccache/hash.hpp>
 #include <ccache/hashutil.hpp>
-#include <ccache/util/duration.hpp>
 #include <ccache/util/fd.hpp>
 #include <ccache/util/memorymap.hpp>
-#include <ccache/util/timepoint.hpp>
 
 #include <sys/types.h>
 
@@ -71,7 +69,8 @@ public:
   // timestamp was updated more than `min_age` ago. The default value is a
   // conservative 2 seconds since not all file systems have subsecond
   // resolution.
-  InodeCache(const Config& config, util::Duration min_age = util::Duration(2));
+  InodeCache(const Config& config,
+             std::chrono::nanoseconds min_age = std::chrono::seconds(2));
   ~InodeCache();
 
   // Return whether it's possible to use the inode cache on the filesystem
@@ -139,7 +138,7 @@ private:
   bool initialize();
 
   const Config& m_config;
-  util::Duration m_min_age;
+  std::chrono::nanoseconds m_min_age;
   util::Fd m_fd;
   struct SharedRegion* m_sr = nullptr;
   bool m_failed = false;
index fcdeb3cc1bb695c6f5117c3ede57532384974416..09dba0955dce1bbe682272c075a441e8b7a43ad0 100644 (file)
@@ -28,7 +28,6 @@
 #include <ccache/core/manifest.hpp>
 #include <ccache/core/statistics.hpp>
 #include <ccache/util/assertions.hpp>
-#include <ccache/util/duration.hpp>
 #include <ccache/util/expected.hpp>
 #include <ccache/util/file.hpp>
 #include <ccache/util/filestream.hpp>
@@ -42,6 +41,7 @@
 #include <ccache/util/temporaryfile.hpp>
 #include <ccache/util/texttable.hpp>
 #include <ccache/util/threadpool.hpp>
+#include <ccache/util/time.hpp>
 #include <ccache/util/wincompat.hpp>
 
 #ifdef INODE_CACHE_SUPPORTED
@@ -85,6 +85,8 @@
 
 namespace fs = util::filesystem;
 
+using namespace std::literals::chrono_literals;
+
 using core::AtomicFile;
 using core::Statistic;
 using core::StatisticsCounters;
@@ -94,7 +96,7 @@ namespace storage::local {
 
 // How often (in seconds) to scan $CCACHE_DIR/tmp for left-over temporary
 // files.
-const util::Duration k_tempdir_cleanup_interval(2 * 24 * 60 * 60); // 2 days
+const auto k_tempdir_cleanup_interval = 2 * 24 * 60 * 60s; // C++20: 2d
 
 // Maximum files per cache directory. This constant is somewhat arbitrarily
 // chosen to be large enough to avoid unnecessary cache levels but small enough
@@ -329,7 +331,7 @@ clean_dir(
 
   uint64_t cache_size = 0;
   uint64_t files_in_cache = 0;
-  auto current_time = util::TimePoint::now();
+  auto current_time = util::now();
   std::unordered_map<std::string /*result_file*/,
                      std::vector<fs::path> /*associated_raw_files*/>
     raw_files_map;
@@ -344,7 +346,7 @@ clean_dir(
     }
 
     // Delete any tmp files older than 1 hour right away.
-    if (file.mtime() + util::Duration(3600) < current_time
+    if (file.mtime() + 1h < current_time
         && util::TemporaryFile::is_tmp_file(file.path())) {
       std::ignore = util::remove(file.path());
       continue;
@@ -383,7 +385,7 @@ clean_dir(
     if ((max_size == 0 || cache_size <= max_size)
         && (max_files == 0 || files_in_cache <= max_files)
         && (!max_age
-            || file.mtime() > (current_time - util::Duration(*max_age)))
+            || file.mtime() > (current_time - std::chrono::seconds(*max_age)))
         && (!namespace_ || max_age)) {
       break;
     }
@@ -746,7 +748,7 @@ LocalStorage::increment_statistics(const StatisticsCounters& statistics)
 void
 LocalStorage::zero_all_statistics()
 {
-  const auto now = util::TimePoint::now();
+  const auto now = util::now();
   const auto zeroable_fields = core::Statistics::get_zeroable_fields();
 
   for_each_level_1_and_2_stats_file(
@@ -755,7 +757,7 @@ LocalStorage::zero_all_statistics()
         for (const auto statistic : zeroable_fields) {
           cs.set(statistic, 0);
         }
-        cs.set(Statistic::stats_zeroed_timestamp, now.sec());
+        cs.set(Statistic::stats_zeroed_timestamp, util::sec(now));
       });
     });
 }
@@ -1451,7 +1453,7 @@ LocalStorage::acquire_all_level_2_content_locks(
 void
 LocalStorage::clean_internal_tempdir()
 {
-  const auto now = util::TimePoint::now();
+  const auto now = util::now();
   const auto cleaned_stamp = FMT("{}/.cleaned", m_config.temporary_dir());
   DirEntry cleaned_dir_entry(cleaned_stamp);
   if (cleaned_dir_entry.is_regular_file()
index 6b31d93ba0aa238c67af41009c244cdd5e04ed16..5ce7c7935982425c4a77d0216eafeb358310dc10 100644 (file)
@@ -30,7 +30,7 @@
 #include <ccache/util/direntry.hpp>
 #include <ccache/util/lockfile.hpp>
 #include <ccache/util/longlivedlockfilemanager.hpp>
-#include <ccache/util/timepoint.hpp>
+#include <ccache/util/time.hpp>
 
 #include <nonstd/span.hpp>
 
index b06df0b602144d3bdb4731f87b3628c4cfffb3c8..f4a03656ff53e2a81e424e88e7cf0ab1f65b7bf7 100644 (file)
@@ -23,7 +23,6 @@ set(
   texttable.cpp
   threadpool.cpp
   time.cpp
-  timepoint.cpp
   tokenizer.cpp
   umaskscope.cpp
   zstd.cpp
index 9b4f4ed5f38f47e5803d2db83ea3fcab79223854..270cc74756062f615bdcccdd256b27a4749855b1 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2019-2024 Joel Rosdahl and other contributors
+// Copyright (C) 2019-2025 Joel Rosdahl and other contributors
 //
 // See doc/authors.adoc for a complete list of contributors.
 //
@@ -18,7 +18,7 @@
 
 #pragma once
 
-#include <ccache/util/timepoint.hpp>
+#include <ccache/util/time.hpp>
 #include <ccache/util/wincompat.hpp>
 
 #include <sys/stat.h>
@@ -212,13 +212,14 @@ inline util::TimePoint
 DirEntry::atime() const
 {
 #if defined(_WIN32) || defined(HAVE_STRUCT_STAT_ST_ATIM)
-  return util::TimePoint(do_stat().st_atim);
+  return util::timepoint_from_timespec(do_stat().st_atim);
 #elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
-  return util::TimePoint(do_stat().st_atimespec);
+  return util::timepoint_from_timespec(do_stat().st_atimespec);
 #elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
-  return util::TimePoint(do_stat().st_atime, do_stat().st_atimensec);
+  return util::timepoint_from_sec_nsec(do_stat().st_atime,
+                                       do_stat().st_atimensec);
 #else
-  return util::TimePoint(do_stat().st_atime, 0);
+  return util::timepoint_from_sec_nsec(do_stat().st_atime, 0);
 #endif
 }
 
@@ -226,13 +227,14 @@ inline util::TimePoint
 DirEntry::ctime() const
 {
 #if defined(_WIN32) || defined(HAVE_STRUCT_STAT_ST_CTIM)
-  return util::TimePoint(do_stat().st_ctim);
+  return util::timepoint_from_timespec(do_stat().st_ctim);
 #elif defined(HAVE_STRUCT_STAT_ST_CTIMESPEC)
-  return util::TimePoint(do_stat().st_ctimespec);
+  return util::timepoint_from_timespec(do_stat().st_ctimespec);
 #elif defined(HAVE_STRUCT_STAT_ST_CTIMENSEC)
-  return util::TimePoint(do_stat().st_ctime, do_stat().st_ctimensec);
+  return util::timepoint_from_sec_nsec(do_stat().st_ctime,
+                                       do_stat().st_ctimensec);
 #else
-  return util::TimePoint(do_stat().st_ctime, 0);
+  return util::timepoint_from_sec_nsec(do_stat().st_ctime, 0);
 #endif
 }
 
@@ -240,13 +242,14 @@ inline util::TimePoint
 DirEntry::mtime() const
 {
 #if defined(_WIN32) || defined(HAVE_STRUCT_STAT_ST_MTIM)
-  return util::TimePoint(do_stat().st_mtim);
+  return util::timepoint_from_timespec(do_stat().st_mtim);
 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
-  return util::TimePoint(do_stat().st_mtimespec);
+  return util::timepoint_from_timespec(do_stat().st_mtimespec);
 #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
-  return util::TimePoint(do_stat().st_mtime, do_stat().st_mtimensec);
+  return util::timepoint_from_sec_nsec(do_stat().st_mtime,
+                                       do_stat().st_mtimensec);
 #else
-  return util::TimePoint(do_stat().st_mtime, 0);
+  return util::timepoint_from_sec_nsec(do_stat().st_mtime, 0);
 #endif
 }
 
diff --git a/src/ccache/util/duration.hpp b/src/ccache/util/duration.hpp
deleted file mode 100644 (file)
index 33590df..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright (C) 2022-2023 Joel Rosdahl and other contributors
-//
-// See doc/authors.adoc for a complete list of contributors.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License as published by the Free
-// Software Foundation; either version 3 of the License, or (at your option)
-// any later version.
-//
-// This program is distributed in the hope that it will be useful, but WITHOUT
-// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-// more details.
-//
-// You should have received a copy of the GNU General Public License along with
-// this program; if not, write to the Free Software Foundation, Inc., 51
-// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-#pragma once
-
-#include <cstdint>
-
-namespace util {
-
-class Duration
-{
-public:
-  explicit Duration(int64_t sec = 0, int64_t nsec = 0);
-
-  bool operator==(const Duration& other) const;
-  bool operator!=(const Duration& other) const;
-  bool operator<(const Duration& other) const;
-  bool operator>(const Duration& other) const;
-  bool operator<=(const Duration& other) const;
-  bool operator>=(const Duration& other) const;
-
-  Duration operator+(const Duration& other) const;
-  Duration operator-(const Duration& other) const;
-  Duration operator*(double factor) const;
-  Duration operator/(double factor) const;
-
-  Duration operator-() const;
-
-  int64_t sec() const;
-  int64_t nsec() const;
-  int32_t nsec_decimal_part() const;
-
-private:
-  int64_t m_ns = 0;
-};
-
-inline Duration::Duration(int64_t sec, int64_t nsec)
-  : m_ns(1'000'000'000 * sec + nsec)
-{
-}
-
-inline bool
-Duration::operator==(const Duration& other) const
-{
-  return m_ns == other.m_ns;
-}
-
-inline bool
-Duration::operator!=(const Duration& other) const
-{
-  return m_ns != other.m_ns;
-}
-
-inline bool
-Duration::operator<(const Duration& other) const
-{
-  return m_ns < other.m_ns;
-}
-
-inline bool
-Duration::operator>(const Duration& other) const
-{
-  return m_ns > other.m_ns;
-}
-
-inline bool
-Duration::operator<=(const Duration& other) const
-{
-  return m_ns <= other.m_ns;
-}
-
-inline bool
-Duration::operator>=(const Duration& other) const
-{
-  return m_ns >= other.m_ns;
-}
-
-inline Duration
-Duration::operator+(const Duration& other) const
-{
-  return Duration(0, m_ns + other.m_ns);
-}
-
-inline Duration
-Duration::operator-(const Duration& other) const
-{
-  return Duration(0, m_ns - other.m_ns);
-}
-
-inline Duration
-Duration::operator*(double factor) const
-{
-  return Duration(0, static_cast<int64_t>(factor * static_cast<double>(m_ns)));
-}
-
-inline Duration
-Duration::operator/(double factor) const
-{
-  return Duration(0, static_cast<int64_t>(static_cast<double>(m_ns) / factor));
-}
-
-inline int64_t
-Duration::sec() const
-{
-  return m_ns / 1'000'000'000;
-}
-
-inline int64_t
-Duration::nsec() const
-{
-  return m_ns;
-}
-
-inline int32_t
-Duration::nsec_decimal_part() const
-{
-  return static_cast<int32_t>(m_ns % 1'000'000'000);
-}
-
-} // namespace util
index 686a7028dc5aebd9cfe1300f4da492d27f91ffe2..4631eb3315e5f582661d5068a33e3bffe10b0faf 100644 (file)
@@ -540,26 +540,26 @@ set_timestamps(const fs::path& path,
 #ifdef HAVE_UTIMENSAT
   timespec atime_mtime[2];
   if (mtime) {
-    atime_mtime[0] = (atime ? *atime : *mtime).to_timespec();
-    atime_mtime[1] = mtime->to_timespec();
+    atime_mtime[0] = util::to_timespec(atime ? *atime : *mtime);
+    atime_mtime[1] = util::to_timespec(*mtime);
   }
   utimensat(
     AT_FDCWD, util::pstr(path).c_str(), mtime ? atime_mtime : nullptr, 0);
 #elif defined(HAVE_UTIMES)
   timeval atime_mtime[2];
   if (mtime) {
-    atime_mtime[0].tv_sec = atime ? atime->sec() : mtime->sec();
+    atime_mtime[0].tv_sec = atime ? util::sec(*atime) : util::sec(*mtime);
     atime_mtime[0].tv_usec =
       (atime ? atime->nsec_decimal_part() : mtime->nsec_decimal_part()) / 1000;
-    atime_mtime[1].tv_sec = mtime->sec();
+    atime_mtime[1].tv_sec = util::sec(*mtime);
     atime_mtime[1].tv_usec = mtime->nsec_decimal_part() / 1000;
   }
   utimes(util::pstr(path).c_str(), mtime ? atime_mtime : nullptr);
 #else
   utimbuf atime_mtime;
   if (mtime) {
-    atime_mtime.actime = atime ? atime->sec() : mtime->sec();
-    atime_mtime.modtime = mtime->sec();
+    atime_mtime.actime = atime ? util::sec(*atime) : util::sec(*mtime);
+    atime_mtime.modtime = util::sec(*mtime);
     utime(util::pstr(path).c_str(), &atime_mtime);
   } else {
     utime(util::pstr(path).c_str(), nullptr);
index 783df5e97c9e616010f06caf694afedab14dcaea..107420df9d48ed763ae26f78513264d559336dea 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2021-2024 Joel Rosdahl and other contributors
+// Copyright (C) 2021-2025 Joel Rosdahl and other contributors
 //
 // See doc/authors.adoc for a complete list of contributors.
 //
@@ -20,7 +20,7 @@
 
 #include <ccache/util/bytes.hpp>
 #include <ccache/util/direntry.hpp>
-#include <ccache/util/timepoint.hpp>
+#include <ccache/util/time.hpp>
 #include <ccache/util/types.hpp>
 
 #include <nonstd/span.hpp>
index aa8f84b797462eb00d195ed42654f1da7461dc40..3c91309f13a0b76f1b88e58f8e6948bbd643f36f 100644 (file)
 #include <random>
 #include <sstream>
 
+using namespace std::literals::chrono_literals;
+
+namespace fs = util::filesystem;
+
 const uint32_t k_min_sleep_time_ms = 10;
 const uint32_t k_max_sleep_time_ms = 50;
 #ifndef _WIN32
-const util::Duration k_staleness_limit(2);
+const auto k_staleness_limit = 2s;
 #endif
 
-namespace fs = util::filesystem;
-
 namespace {
 
 class RandomNumberGenerator
@@ -230,7 +232,7 @@ LockFile::do_acquire(const bool blocking)
 
   TimePoint last_seen_activity = [this] {
     const auto last_lock_update = get_last_lock_update();
-    return last_lock_update ? *last_lock_update : TimePoint::now();
+    return last_lock_update ? *last_lock_update : util::now();
   }();
 
   std::string initial_content;
@@ -238,9 +240,9 @@ LockFile::do_acquire(const bool blocking)
                                            k_max_sleep_time_ms);
 
   while (true) {
-    const auto now = TimePoint::now();
+    const auto now = util::now();
     const auto my_content =
-      FMT("{}-{}.{}", content_prefix, now.sec(), now.nsec_decimal_part());
+      FMT("{}-{}.{}", content_prefix, util::sec(now), util::nsec_part(now));
 #  ifdef __CYGWIN__
     // Cygwin/MSYS2 does not support allow a symlink to have a nonexistent
     // target, so use plain files instead.
@@ -326,19 +328,19 @@ LockFile::do_acquire(const bool blocking)
       last_seen_activity = *last_lock_update;
     }
 
-    const Duration inactive_duration = TimePoint::now() - last_seen_activity;
+    const auto inactive_duration = util::now() - last_seen_activity;
 
     if (inactive_duration < k_staleness_limit) {
       LOG("Lock {} held by another process active {}.{:03} seconds ago",
           m_lock_file,
-          inactive_duration.sec(),
-          inactive_duration.nsec_decimal_part() / 1'000'000);
+          util::sec(inactive_duration),
+          util::nsec_part(inactive_duration) / 1'000'000);
     } else if (content == initial_content) {
       // The lock seems to be stale -- break it and try again.
       LOG("Breaking {} since it has been inactive for {}.{:03} seconds",
           m_lock_file,
-          inactive_duration.sec(),
-          inactive_duration.nsec_decimal_part() / 1'000'000);
+          util::sec(inactive_duration),
+          util::nsec_part(inactive_duration) / 1'000'000);
       if (auto r = fs::remove(m_alive_file);
           !r && r.error() != std::errc::no_such_file_or_directory) {
         return false;
index 169fffe13224bed7f5607ee4c4e95e5a78ffc6bd..ef472c362d30253a4d188024f8e60daaea09e0c1 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2020-2024 Joel Rosdahl and other contributors
+// Copyright (C) 2020-2025 Joel Rosdahl and other contributors
 //
 // See doc/authors.adoc for a complete list of contributors.
 //
@@ -20,7 +20,7 @@
 
 #include <ccache/util/longlivedlockfilemanager.hpp>
 #include <ccache/util/noncopyable.hpp>
-#include <ccache/util/timepoint.hpp>
+#include <ccache/util/time.hpp>
 
 #include <filesystem>
 #include <optional>
index 5d1d3ae93b864f17f472a1fc2cee22fd689a3aca..ec7a6440e8cd38c086477b30f3677050e929866b 100644 (file)
@@ -82,12 +82,12 @@ do_log(std::string_view message, bool bulk)
   static char prefix[200];
 
   if (!bulk || prefix[0] == '\0') {
-    const auto now = util::TimePoint::now();
+    const auto now = util::now();
     (void)snprintf(prefix,
                    sizeof(prefix),
                    "[%s.%06u %-5d] ",
                    util::format_iso8601_timestamp(now).c_str(),
-                   static_cast<unsigned int>(now.nsec_decimal_part() / 1000),
+                   static_cast<unsigned int>(util::nsec_part(now) / 1000),
                    static_cast<int>(getpid()));
   }
 
index c3729701148134ca6e252cb8e377a157a3b704a0..b82d699571ecfdc8d71d53f968953ff784ce2931 100644 (file)
@@ -203,18 +203,15 @@ format_human_readable_size(uint64_t size, SizeUnitPrefixType prefix_type)
 std::string
 format_iso8601_timestamp(const TimePoint& time, TimeZone time_zone)
 {
-  char timestamp[100];
   const auto tm =
     (time_zone == TimeZone::local ? util::localtime : util::gmtime)(time);
   if (tm) {
+    char timestamp[100];
     (void)strftime(timestamp, sizeof(timestamp), "%Y-%m-%dT%H:%M:%S", &*tm);
+    return timestamp;
   } else {
-    (void)snprintf(timestamp,
-                   sizeof(timestamp),
-                   "%llu",
-                   static_cast<long long unsigned int>(time.sec()));
+    return std::to_string(util::sec(time));
   }
-  return timestamp;
 }
 
 std::string
index dff3571fca23875e88d3a868846f8f21624c19c3..13d7fd40cddc7818dba0b4fd90bf949a751700a6 100644 (file)
@@ -19,7 +19,7 @@
 #pragma once
 
 #include <ccache/util/conversion.hpp>
-#include <ccache/util/timepoint.hpp>
+#include <ccache/util/time.hpp>
 #include <ccache/util/tokenizer.hpp>
 
 #include <nonstd/span.hpp>
@@ -27,6 +27,7 @@
 
 #include <sys/stat.h> // for mode_t
 
+#include <chrono>
 #include <cstdint>
 #include <cstring>
 #include <filesystem>
index 8630d2677b65138fab5771822cda5047d9ed37d9..30591eda257ac83fd816606ad54cca8676ed7816 100644 (file)
@@ -23,7 +23,7 @@ namespace util {
 std::optional<tm>
 gmtime(std::optional<TimePoint> time)
 {
-  time_t timestamp = time ? time->sec() : TimePoint::now().sec();
+  time_t timestamp = time ? sec(*time) : sec(now());
 #ifdef HAVE_GMTIME_R
   struct tm result;
   if (gmtime_r(&timestamp, &result)) {
@@ -41,7 +41,7 @@ gmtime(std::optional<TimePoint> time)
 std::optional<tm>
 localtime(std::optional<TimePoint> time)
 {
-  time_t timestamp = time ? time->sec() : TimePoint::now().sec();
+  time_t timestamp = time ? sec(*time) : sec(now());
 #ifdef HAVE_LOCALTIME_R
   struct tm result;
   if (localtime_r(&timestamp, &result)) {
index 16d90af6def0f2b164ce5f2c75e12dc91eb8469a..458f646dd474dea12505cdfe3e1a1c13250ef28f 100644 (file)
 
 #pragma once
 
-#include <ccache/util/timepoint.hpp>
-
+#include <chrono>
 #include <ctime>
 #include <optional>
 
 namespace util {
 
+// --- Interface ---
+
+using TimePoint =
+  std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>;
+
 // Thread-safe version of `gmtime(3)`. If `time` is not specified the current
 // time of day is used.
 std::optional<tm> gmtime(std::optional<TimePoint> time = {});
@@ -33,4 +37,93 @@ std::optional<tm> gmtime(std::optional<TimePoint> time = {});
 // time of day is used.
 std::optional<tm> localtime(std::optional<TimePoint> time = {});
 
+TimePoint now();
+
+template<typename Rep, typename Period>
+int32_t nsec_part(std::chrono::duration<Rep, Period> d);
+
+int32_t nsec_part(TimePoint tp);
+
+template<typename Rep, typename Period>
+int64_t nsec_tot(std::chrono::duration<Rep, Period> d);
+
+int64_t nsec_tot(TimePoint tp);
+
+template<typename Rep, typename Period>
+int64_t sec(std::chrono::duration<Rep, Period> d);
+
+int64_t sec(TimePoint tp);
+
+TimePoint timepoint_from_sec_nsec(int64_t sec, int64_t nsec);
+
+TimePoint timepoint_from_timespec(const timespec& ts);
+
+timespec to_timespec(TimePoint tp);
+
+// --- Inline implementations ---
+
+inline TimePoint
+timepoint_from_sec_nsec(int64_t sec, int64_t nsec)
+{
+  return TimePoint(std::chrono::seconds(sec) + std::chrono::nanoseconds(nsec));
+}
+
+inline TimePoint
+timepoint_from_timespec(const timespec& ts)
+{
+  return TimePoint(std::chrono::seconds(ts.tv_sec)
+                   + std::chrono::nanoseconds(ts.tv_nsec));
+}
+
+inline TimePoint
+now()
+{
+  return std::chrono::system_clock::now();
+}
+
+template<typename Rep, typename Period>
+inline int64_t
+nsec_tot(std::chrono::duration<Rep, Period> d)
+{
+  return std::chrono::duration_cast<std::chrono::nanoseconds>(d).count();
+}
+
+inline int64_t
+nsec_tot(TimePoint tp)
+{
+  return tp.time_since_epoch().count();
+}
+
+template<typename Rep, typename Period>
+inline int64_t
+sec(std::chrono::duration<Rep, Period> d)
+{
+  return nsec_tot(d) / 1'000'000'000;
+}
+
+inline int64_t
+sec(TimePoint tp)
+{
+  return nsec_tot(tp) / 1'000'000'000;
+}
+
+template<typename Rep, typename Period>
+inline int32_t
+nsec_part(std::chrono::duration<Rep, Period> d)
+{
+  return nsec_tot(d) % 1'000'000'000;
+}
+
+inline int32_t
+nsec_part(TimePoint tp)
+{
+  return nsec_tot(tp) % 1'000'000'000;
+}
+
+inline timespec
+to_timespec(TimePoint tp)
+{
+  return {static_cast<time_t>(util::sec(tp)), util::nsec_part(tp)};
+}
+
 } // namespace util
diff --git a/src/ccache/util/timepoint.cpp b/src/ccache/util/timepoint.cpp
deleted file mode 100644 (file)
index d22432c..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (C) 2022-2024 Joel Rosdahl and other contributors
-//
-// See doc/authors.adoc for a complete list of contributors.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License as published by the Free
-// Software Foundation; either version 3 of the License, or (at your option)
-// any later version.
-//
-// This program is distributed in the hope that it will be useful, but WITHOUT
-// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-// more details.
-//
-// You should have received a copy of the GNU General Public License along with
-// this program; if not, write to the Free Software Foundation, Inc., 51
-// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-#include "timepoint.hpp"
-
-#include <chrono>
-
-namespace util {
-
-TimePoint
-TimePoint::now()
-{
-  return TimePoint(0,
-                   std::chrono::time_point_cast<std::chrono::nanoseconds>(
-                     std::chrono::system_clock::now())
-                     .time_since_epoch()
-                     .count());
-}
-
-} // namespace util
diff --git a/src/ccache/util/timepoint.hpp b/src/ccache/util/timepoint.hpp
deleted file mode 100644 (file)
index 65e0c36..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright (C) 2022-2024 Joel Rosdahl and other contributors
-//
-// See doc/authors.adoc for a complete list of contributors.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License as published by the Free
-// Software Foundation; either version 3 of the License, or (at your option)
-// any later version.
-//
-// This program is distributed in the hope that it will be useful, but WITHOUT
-// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-// more details.
-//
-// You should have received a copy of the GNU General Public License along with
-// this program; if not, write to the Free Software Foundation, Inc., 51
-// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-#pragma once
-
-#include <ccache/util/duration.hpp>
-
-#include <cstdint>
-#include <ctime>
-
-namespace util {
-
-class TimePoint
-{
-public:
-  explicit TimePoint(int64_t sec = 0, int64_t nsec = 0);
-  TimePoint(const TimePoint& other);
-  explicit TimePoint(const timespec& timespec);
-
-  TimePoint& operator=(const TimePoint& other);
-
-  static TimePoint now();
-
-  timespec to_timespec() const;
-
-  int64_t sec() const;
-  int64_t nsec() const;
-  int32_t nsec_decimal_part() const;
-
-  void set_sec(int64_t sec, uint32_t nsec = 0);
-  void set_nsec(int64_t nsec);
-
-  bool operator==(const TimePoint& other) const;
-  bool operator!=(const TimePoint& other) const;
-  bool operator<(const TimePoint& other) const;
-  bool operator>(const TimePoint& other) const;
-  bool operator<=(const TimePoint& other) const;
-  bool operator>=(const TimePoint& other) const;
-
-  TimePoint operator+(const Duration& duration) const;
-  TimePoint operator-(const Duration& duration) const;
-
-  Duration operator-(const TimePoint& other) const;
-
-private:
-  int64_t m_ns = 0;
-};
-
-inline TimePoint::TimePoint(int64_t sec, int64_t nsec)
-  : m_ns(1'000'000'000 * sec + nsec)
-{
-}
-
-inline TimePoint::TimePoint(const TimePoint& other)
-  : m_ns(other.m_ns)
-{
-}
-
-inline TimePoint::TimePoint(const timespec& timespec)
-  : TimePoint(timespec.tv_sec, timespec.tv_nsec)
-{
-}
-
-inline TimePoint&
-TimePoint::operator=(const TimePoint& other)
-{
-  m_ns = other.m_ns;
-  return *this;
-}
-
-inline timespec
-TimePoint::to_timespec() const
-{
-  return {static_cast<time_t>(sec()), nsec_decimal_part()};
-}
-
-inline int64_t
-TimePoint::sec() const
-{
-  return m_ns / 1'000'000'000;
-}
-
-inline int64_t
-TimePoint::nsec() const
-{
-  return m_ns;
-}
-
-inline int32_t
-TimePoint::nsec_decimal_part() const
-{
-  return static_cast<int32_t>(m_ns % 1'000'000'000);
-}
-
-inline void
-TimePoint::set_sec(int64_t sec, uint32_t nsec)
-{
-  m_ns = 1'000'000'000 * sec + nsec;
-}
-
-inline void
-TimePoint::set_nsec(int64_t nsec)
-{
-  m_ns = nsec;
-}
-
-inline bool
-TimePoint::operator==(const TimePoint& other) const
-{
-  return m_ns == other.m_ns;
-}
-
-inline bool
-TimePoint::operator!=(const TimePoint& other) const
-{
-  return m_ns != other.m_ns;
-}
-
-inline bool
-TimePoint::operator<(const TimePoint& other) const
-{
-  return m_ns < other.m_ns;
-}
-
-inline bool
-TimePoint::operator>(const TimePoint& other) const
-{
-  return m_ns > other.m_ns;
-}
-
-inline bool
-TimePoint::operator<=(const TimePoint& other) const
-{
-  return m_ns <= other.m_ns;
-}
-
-inline bool
-TimePoint::operator>=(const TimePoint& other) const
-{
-  return m_ns >= other.m_ns;
-}
-
-inline TimePoint
-TimePoint::operator+(const Duration& duration) const
-{
-  return TimePoint(0, nsec() + duration.nsec());
-}
-
-inline TimePoint
-TimePoint::operator-(const Duration& duration) const
-{
-  return TimePoint(0, nsec() - duration.nsec());
-}
-
-inline Duration
-TimePoint::operator-(const TimePoint& other) const
-{
-  return Duration(0, nsec() - other.nsec());
-}
-
-} // namespace util
index 369ec9c55ab5aadceddbded0eadf4cfb456240b6..f333b3d91762385ac9dba011bf99d9223e7465c1 100644 (file)
@@ -23,7 +23,6 @@ set(
   test_util_clang.cpp
   test_util_conversion.cpp
   test_util_direntry.cpp
-  test_util_duration.cpp
   test_util_environment.cpp
   test_util_exec.cpp
   test_util_expected.cpp
@@ -32,7 +31,6 @@ set(
   test_util_path.cpp
   test_util_string.cpp
   test_util_texttable.cpp
-  test_util_timepoint.cpp
   test_util_tokenizer.cpp
   test_util_xxh3_128.cpp
   test_util_xxh3_64.cpp
index f0a6cedb90e9351c45b9d705f160345075869bb6..7e60ca926edc345887b76f01c0324f5f52ab3d69 100644 (file)
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include <chrono>
+
 namespace fs = util::filesystem;
 
+using namespace std::literals::chrono_literals;
+
 using TestUtil::TestContext;
 
 namespace {
@@ -84,7 +88,7 @@ TEST_CASE("Test disabled")
   Config config;
   init(config);
   config.set_inode_cache(false);
-  InodeCache inode_cache(config, util::Duration(0));
+  InodeCache inode_cache(config, 0ns);
 
   CHECK(!inode_cache.get("a",
                          InodeCache::ContentType::checked_for_temporal_macros));
@@ -104,7 +108,7 @@ TEST_CASE("Test lookup nonexistent")
   Config config;
   init(config);
 
-  InodeCache inode_cache(config, util::Duration(0));
+  InodeCache inode_cache(config, 0ns);
   REQUIRE(util::write_file("a", ""));
 
   CHECK(!inode_cache.get("a",
@@ -121,7 +125,7 @@ TEST_CASE("Test put and lookup")
   Config config;
   init(config);
 
-  InodeCache inode_cache(config, util::Duration(0));
+  InodeCache inode_cache(config, 0ns);
   REQUIRE(util::write_file("a", "a text"));
 
   HashSourceCodeResult result;
@@ -169,7 +173,7 @@ TEST_CASE("Drop file")
   Config config;
   init(config);
 
-  InodeCache inode_cache(config, util::Duration(0));
+  InodeCache inode_cache(config, 0ns);
 
   inode_cache.get("a", InodeCache::ContentType::raw);
   CHECK(util::DirEntry(inode_cache.get_path()));
@@ -185,7 +189,7 @@ TEST_CASE("Test content type")
   Config config;
   init(config);
 
-  InodeCache inode_cache(config, util::Duration(0));
+  InodeCache inode_cache(config, 0ns);
   REQUIRE(util::write_file("a", "a text"));
   auto binary_digest = Hash().hash("binary").digest();
   auto code_digest = Hash().hash("code").digest();
index 411300fe6fd4f64a7cf16d973b9bce11b8f73882..5af7ee1267b0204578f06cc6b1a2a549d3f21465 100644 (file)
@@ -162,10 +162,10 @@ TEST_CASE("Default constructor")
   CHECK(entry.device() == 0);
   CHECK(entry.inode() == 0);
   CHECK(entry.mode() == 0);
-  CHECK(entry.ctime().sec() == 0);
-  CHECK(entry.ctime().nsec() == 0);
-  CHECK(entry.mtime().sec() == 0);
-  CHECK(entry.mtime().nsec() == 0);
+  CHECK(util::sec(entry.ctime()) == 0);
+  CHECK(util::nsec_part(entry.ctime()) == 0);
+  CHECK(util::sec(entry.mtime()) == 0);
+  CHECK(util::nsec_part(entry.mtime()) == 0);
   CHECK(entry.size() == 0);
   CHECK(entry.size_on_disk() == 0);
   CHECK(!entry.is_directory());
@@ -188,10 +188,10 @@ TEST_CASE("Construction for missing entry")
   CHECK(entry.device() == 0);
   CHECK(entry.inode() == 0);
   CHECK(entry.mode() == 0);
-  CHECK(entry.ctime().sec() == 0);
-  CHECK(entry.ctime().nsec() == 0);
-  CHECK(entry.mtime().sec() == 0);
-  CHECK(entry.mtime().nsec() == 0);
+  CHECK(util::sec(entry.ctime()) == 0);
+  CHECK(util::nsec_part(entry.ctime()) == 0);
+  CHECK(util::sec(entry.mtime()) == 0);
+  CHECK(util::nsec_part(entry.mtime()) == 0);
   CHECK(entry.size() == 0);
   CHECK(entry.size_on_disk() == 0);
   CHECK(!entry.is_directory());
@@ -294,10 +294,10 @@ TEST_CASE("Return values when file exists")
   struct timespec last_write_time =
     win32_filetime_to_timespec(info.ftLastWriteTime);
 
-  CHECK(de.ctime().sec() == creation_time.tv_sec);
-  CHECK(de.ctime().nsec_decimal_part() == creation_time.tv_nsec);
-  CHECK(de.mtime().sec() == last_write_time.tv_sec);
-  CHECK(de.mtime().nsec_decimal_part() == last_write_time.tv_nsec);
+  CHECK(util::sec(de.ctime()) == creation_time.tv_sec);
+  CHECK(util::nsec_part(de.ctime()) == creation_time.tv_nsec);
+  CHECK(util::sec(de.mtime()) == last_write_time.tv_sec);
+  CHECK(util::nsec_part(de.mtime()) == last_write_time.tv_nsec);
 
   CHECK(de.size_on_disk() == ((de.size() + 4095) & ~4095));
   CHECK(de.file_attributes() == info.dwFileAttributes);
@@ -313,25 +313,25 @@ TEST_CASE("Return values when file exists")
   CHECK(de.size_on_disk() == util::likely_size_on_disk(st.st_size));
 
 #  ifdef HAVE_STRUCT_STAT_ST_CTIM
-  CHECK(de.ctime().sec() == st.st_ctim.tv_sec);
-  CHECK(de.ctime().nsec_decimal_part() == st.st_ctim.tv_nsec);
+  CHECK(util::sec(de.ctime()) == st.st_ctim.tv_sec);
+  CHECK(util::nsec_part(de.ctime()) == st.st_ctim.tv_nsec);
 #  elif defined(HAVE_STRUCT_STAT_ST_CTIMESPEC)
-  CHECK(de.ctime().sec() == st.st_ctimespec.tv_sec);
-  CHECK(de.ctime().nsec_decimal_part() == st.st_ctimespec.tv_nsec);
+  CHECK(util::sec(de.ctime()) == st.st_ctimespec.tv_sec);
+  CHECK(util::nsec_part(de.ctime()) == st.st_ctimespec.tv_nsec);
 #  else
-  CHECK(de.ctime().sec() == st.st_ctime);
-  CHECK(de.ctime().nsec_decimal_part() == 0);
+  CHECK(util::sec(de.ctime()) == st.st_ctime);
+  CHECK(util::nsec_part(de.ctime()) == 0);
 #  endif
 
 #  ifdef HAVE_STRUCT_STAT_ST_MTIM
-  CHECK(de.mtime().sec() == st.st_mtim.tv_sec);
-  CHECK(de.mtime().nsec_decimal_part() == st.st_mtim.tv_nsec);
+  CHECK(util::sec(de.mtime()) == st.st_mtim.tv_sec);
+  CHECK(util::nsec_part(de.mtime()) == st.st_mtim.tv_nsec);
 #  elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
-  CHECK(de.mtime().sec() == st.st_mtimespec.tv_sec);
-  CHECK(de.mtime().nsec_decimal_part() == st.st_mtimespec.tv_nsec);
+  CHECK(util::sec(de.mtime()) == st.st_mtimespec.tv_sec);
+  CHECK(util::nsec_part(de.mtime()) == st.st_mtimespec.tv_nsec);
 #  else
-  CHECK(de.mtime().sec() == st.st_mtime);
-  CHECK(de.mtime().nsec_decimal_part() == 0);
+  CHECK(util::sec(de.mtime()) == st.st_mtime);
+  CHECK(util::nsec_part(de.mtime()) == 0);
 #  endif
 #endif
 }
diff --git a/unittest/test_util_duration.cpp b/unittest/test_util_duration.cpp
deleted file mode 100644 (file)
index c420be1..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright (C) 2022-2024 Joel Rosdahl and other contributors
-//
-// See doc/authors.adoc for a complete list of contributors.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License as published by the Free
-// Software Foundation; either version 3 of the License, or (at your option)
-// any later version.
-//
-// This program is distributed in the hope that it will be useful, but WITHOUT
-// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-// more details.
-//
-// You should have received a copy of the GNU General Public License along with
-// this program; if not, write to the Free Software Foundation, Inc., 51
-// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-#include <ccache/util/duration.hpp>
-
-#include <doctest/doctest.h>
-
-TEST_SUITE_BEGIN("util::Duration");
-
-using util::Duration;
-
-TEST_CASE("Basics")
-{
-  Duration d0(4711, 2042);
-
-  CHECK(d0.sec() == 4711);
-  CHECK(d0.nsec() == 4711000002042);
-  CHECK(d0.nsec_decimal_part() == 2042);
-}
-
-TEST_CASE("Comparison operators")
-{
-  Duration d0(1000, 0);
-  Duration d1(1000, 42);
-  Duration d2(1001, 0);
-
-  SUBCASE("operator==")
-  {
-    CHECK(d0 == d0);
-    CHECK(!(d0 == d1));
-    CHECK(!(d1 == d0));
-    CHECK(!(d0 == d2));
-    CHECK(!(d2 == d0));
-  }
-
-  SUBCASE("operator!=")
-  {
-    CHECK(!(d0 != d0));
-    CHECK(d0 != d1);
-    CHECK(d1 != d0);
-  }
-
-  SUBCASE("operator<")
-  {
-    CHECK(d0 < d1);
-    CHECK(d0 < d2);
-    CHECK(d1 < d2);
-    CHECK(!(d1 < d0));
-    CHECK(!(d2 < d0));
-    CHECK(!(d2 < d1));
-  }
-
-  SUBCASE("operator>")
-  {
-    CHECK(d2 > d1);
-    CHECK(d2 > d0);
-    CHECK(d1 > d0);
-    CHECK(!(d1 > d2));
-    CHECK(!(d0 > d2));
-    CHECK(!(d0 > d1));
-  }
-
-  SUBCASE("operator<=")
-  {
-    CHECK(d0 <= d0);
-    CHECK(d0 <= d1);
-    CHECK(d0 <= d2);
-    CHECK(!(d1 <= d0));
-    CHECK(!(d2 <= d0));
-  }
-
-  SUBCASE("operator>=")
-  {
-    CHECK(d2 >= d1);
-    CHECK(d2 >= d0);
-    CHECK(d1 >= d0);
-    CHECK(!(d1 >= d2));
-    CHECK(!(d0 >= d2));
-  }
-}
-
-TEST_CASE("Arithmetic operators")
-{
-  Duration d0(1, 2);
-  Duration d1(3, 9);
-
-  SUBCASE("operator+")
-  {
-    Duration d = d0 + d1;
-    CHECK(d.sec() == 4);
-    CHECK(d.nsec_decimal_part() == 11);
-  }
-
-  SUBCASE("operator-")
-  {
-    Duration d = d0 - d1;
-    CHECK(d.sec() == -2);
-    CHECK(d.nsec_decimal_part() == -7);
-  }
-
-  SUBCASE("operator*")
-  {
-    Duration d = d1 * 4;
-    CHECK(d.sec() == 12);
-    CHECK(d.nsec_decimal_part() == 36);
-  }
-
-  SUBCASE("operator/")
-  {
-    Duration d = d1 / 0.8;
-    CHECK(d.sec() == 3);
-    CHECK(d.nsec_decimal_part() == 750'000'011);
-  }
-}
-
-TEST_SUITE_END();
index 8652c3a25f7130a6b3898c1a5fc31e4672ad6bc6..acc0a37af7b6b37cd905a92c7d351afb5c733094 100644 (file)
@@ -21,6 +21,7 @@
 #include <ccache/util/direntry.hpp>
 #include <ccache/util/file.hpp>
 #include <ccache/util/lockfile.hpp>
+#include <ccache/util/time.hpp>
 #include <ccache/util/wincompat.hpp>
 
 #include <doctest/doctest.h>
@@ -116,7 +117,7 @@ TEST_CASE("Break stale lock, blocking")
   TestContext test_context;
 
   REQUIRE(util::write_file("test.alive", ""));
-  const util::TimePoint long_time_ago(0, 0);
+  const util::TimePoint long_time_ago(0s);
   util::set_timestamps("test.alive", long_time_ago);
   CHECK(symlink("foo", "test.lock") == 0);
 
@@ -131,7 +132,7 @@ TEST_CASE("Break stale lock, non-blocking")
   TestContext test_context;
 
   REQUIRE(util::write_file("test.alive", ""));
-  const util::TimePoint long_time_ago(0, 0);
+  const util::TimePoint long_time_ago(0s);
   util::set_timestamps("test.alive", long_time_ago);
   CHECK(symlink("foo", "test.lock") == 0);
 
index 8a6138bc3c9abc87058f12f2d2af01c92e2d11b3..2859ba34015a570c78d3765c572125e53a01d19f 100644 (file)
 
 #include <doctest/doctest.h>
 
+#include <chrono>
 #include <ostream> // https://github.com/doctest/doctest/issues/618
 #include <vector>
 
+using namespace std::literals::chrono_literals;
+
 TEST_SUITE_BEGIN("util");
 
 TEST_CASE("util::format_argv_as_win32_command_string")
@@ -265,9 +268,9 @@ TEST_CASE("util::format_iso8601_timestamp")
   using util::TimePoint;
   using util::TimeZone;
 
-  CHECK(util::format_iso8601_timestamp(TimePoint(0), TimeZone::utc)
+  CHECK(util::format_iso8601_timestamp(TimePoint(0s), TimeZone::utc)
         == "1970-01-01T00:00:00");
-  CHECK(util::format_iso8601_timestamp(TimePoint(1234567890), TimeZone::utc)
+  CHECK(util::format_iso8601_timestamp(TimePoint(1234567890s), TimeZone::utc)
         == "2009-02-13T23:31:30");
 }
 
diff --git a/unittest/test_util_timepoint.cpp b/unittest/test_util_timepoint.cpp
deleted file mode 100644 (file)
index 44acb7b..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright (C) 2022-2024 Joel Rosdahl and other contributors
-//
-// See doc/authors.adoc for a complete list of contributors.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License as published by the Free
-// Software Foundation; either version 3 of the License, or (at your option)
-// any later version.
-//
-// This program is distributed in the hope that it will be useful, but WITHOUT
-// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-// more details.
-//
-// You should have received a copy of the GNU General Public License along with
-// this program; if not, write to the Free Software Foundation, Inc., 51
-// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-#include <ccache/util/timepoint.hpp>
-
-#include <doctest/doctest.h>
-
-TEST_SUITE_BEGIN("util::TimePoint");
-
-using util::TimePoint;
-
-TEST_CASE("Basics")
-{
-  TimePoint t0(4711, 2042);
-
-  CHECK(t0.sec() == 4711);
-  CHECK(t0.nsec() == 4711000002042);
-  CHECK(t0.nsec_decimal_part() == 2042);
-}
-
-TEST_CASE("Conversions")
-{
-  TimePoint t0(4711, 2042);
-
-  SUBCASE("to_timespec")
-  {
-    timespec ts = t0.to_timespec();
-    CHECK(ts.tv_sec == 4711);
-    CHECK(ts.tv_nsec == 2042);
-  }
-}
-
-TEST_CASE("Comparison operators")
-{
-  TimePoint t0(1000, 0);
-  TimePoint t1(1000, 42);
-  TimePoint t2(1001, 0);
-
-  SUBCASE("operator==")
-  {
-    CHECK(t0 == t0);
-    CHECK(!(t0 == t1));
-    CHECK(!(t1 == t0));
-    CHECK(!(t0 == t2));
-    CHECK(!(t2 == t0));
-  }
-
-  SUBCASE("operator!=")
-  {
-    CHECK(!(t0 != t0));
-    CHECK(t0 != t1);
-    CHECK(t1 != t0);
-  }
-
-  SUBCASE("operator<")
-  {
-    CHECK(t0 < t1);
-    CHECK(t0 < t2);
-    CHECK(t1 < t2);
-    CHECK(!(t1 < t0));
-    CHECK(!(t2 < t0));
-    CHECK(!(t2 < t1));
-  }
-
-  SUBCASE("operator>")
-  {
-    CHECK(t2 > t1);
-    CHECK(t2 > t0);
-    CHECK(t1 > t0);
-    CHECK(!(t1 > t2));
-    CHECK(!(t0 > t2));
-    CHECK(!(t0 > t1));
-  }
-
-  SUBCASE("operator<=")
-  {
-    CHECK(t0 <= t0);
-    CHECK(t0 <= t1);
-    CHECK(t0 <= t2);
-    CHECK(!(t1 <= t0));
-    CHECK(!(t2 <= t0));
-  }
-
-  SUBCASE("operator>=")
-  {
-    CHECK(t2 >= t1);
-    CHECK(t2 >= t0);
-    CHECK(t1 >= t0);
-    CHECK(!(t1 >= t2));
-    CHECK(!(t0 >= t2));
-  }
-}
-
-TEST_CASE("Operations with duration")
-{
-  TimePoint t0(1, 2);
-  TimePoint t1(3, 17);
-
-  SUBCASE("operator-(TimePoint)")
-  {
-    CHECK(t1 - t0 == util::Duration(2, 15));
-    CHECK(t0 - t1 == util::Duration(-2, -15));
-  }
-
-  SUBCASE("operator+(Duration)")
-  {
-    CHECK(t0 + util::Duration(4, 999999999) == util::TimePoint(6, 1));
-  }
-
-  SUBCASE("operator-(Duration))")
-  {
-    auto t = t0 - util::Duration(4, 999999999);
-    CHECK(t.sec() == -3);
-    CHECK(t.nsec_decimal_part() == -999999997);
-  }
-}
-
-TEST_SUITE_END();