[llvm-branch-commits] [libcxx] [libc++][docs] Convert documentation from reST to Markdown (batch 1) (PR #221513)

Louis Dionne via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Sep 25 09:03:39 PDT 2026


================
@@ -196,293 +182,285 @@ just the values they can represent. We need to consider the effects they will
 have on users and their code. For example, each of them breaks the following
 code in some way:
 
-.. code-block:: cpp
-
-  // Bug caused by an unexpected 'rep' type returned by count.
-  void print_time(path p) {
-    // __int128_t doesn't have streaming operators, and neither would our
-    // custom arithmetic types.
-    cout << last_write_time(p).time_since_epoch().count() << endl;
-  }
-
-  // Overflow during creation bug.
-  file_time_type timespec_to_file_time_type(struct timespec ts) {
-    // woops! chrono::seconds and chrono::nanoseconds use a 64-bit representation
-    // this may overflow before it's converted to a file_time_type.
-    auto dur = seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec);
-    return file_time_type(dur);
-  }
-
-  file_time_type correct_timespec_to_file_time_type(struct timespec ts) {
-    // This is the correct version of the above example, where we
-    // avoid using the chrono typedefs as they're not sufficient.
-    // Can we expect users to avoid this bug?
-    using fs_seconds = chrono::duration<file_time_type::rep>;
-    using fs_nanoseconds = chrono::duration<file_time_type::rep, nano>;
-    auto dur = fs_seconds(ts.tv_sec) + fs_nanoseconds(tv.tv_nsec);
-    return file_time_type(dur);
-  }
-
-  // Implicit truncation during conversion bug.
-  intmax_t get_time_in_seconds(path p) {
-    using fs_seconds = duration<file_time_type::rep, ratio<1, 1> >;
-    auto tp = last_write_time(p);
-
-    // This works with truncation for __int128_t, but what does it do for
-    // our custom arithmetic types.
-    return duration_cast<fs_seconds>().count();
-  }
-
+```cpp
+// Bug caused by an unexpected 'rep' type returned by count.
+void print_time(path p) {
+  // __int128_t doesn't have streaming operators, and neither would our
+  // custom arithmetic types.
+  cout << last_write_time(p).time_since_epoch().count() << endl;
+}
+
+// Overflow during creation bug.
+file_time_type timespec_to_file_time_type(struct timespec ts) {
+  // woops! chrono::seconds and chrono::nanoseconds use a 64-bit representation
+  // this may overflow before it's converted to a file_time_type.
+  auto dur = seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec);
+  return file_time_type(dur);
+}
+
+file_time_type correct_timespec_to_file_time_type(struct timespec ts) {
+  // This is the correct version of the above example, where we
+  // avoid using the chrono typedefs as they're not sufficient.
+  // Can we expect users to avoid this bug?
+  using fs_seconds = chrono::duration<file_time_type::rep>;
+  using fs_nanoseconds = chrono::duration<file_time_type::rep, nano>;
+  auto dur = fs_seconds(ts.tv_sec) + fs_nanoseconds(tv.tv_nsec);
+  return file_time_type(dur);
+}
+
+// Implicit truncation during conversion bug.
+intmax_t get_time_in_seconds(path p) {
+  using fs_seconds = duration<file_time_type::rep, ratio<1, 1> >;
+  auto tp = last_write_time(p);
+
+  // This works with truncation for __int128_t, but what does it do for
+  // our custom arithmetic types.
+  return duration_cast<fs_seconds>().count();
+}
+```
 
 Each of the above examples would require a user to adjust their filesystem code
 to the particular eccentricities of the representation, hopefully only in such
 a way that the code is still portable across implementations.
 
 At least some of the above issues are unavoidable, no matter what
 representation we choose. But some representations may be quirkier than others,
-and, as I'll argue later, using an actual arithmetic type (``__int128_t``)
+and, as I'll argue later, using an actual arithmetic type (`__int128_t`)
 provides the least aberrant behavior.
 
+### Chrono and `timespec` Emulation.
 
-Chrono and ``timespec`` Emulation.
-----------------------------------
-
-One of the options we've considered is using something akin to ``timespec``
-to represent the ``file_time_type``. It only seems natural seeing as that's
+One of the options we've considered is using something akin to `timespec`
+to represent the `file_time_type`. It only seems natural seeing as that's
 what the underlying system uses, and because it might allow us to match
 the range and resolution exactly. But would it work with chrono? And could
-it still act at all like a ``timespec`` struct?
+it still act at all like a `timespec` struct?
 
 For ease of consideration, let's consider what the implementation might
 look like.
 
-.. code-block:: cpp
-
-  struct fs_timespec_rep {
-    fs_timespec_rep(long long v)
-      : tv_sec(v / nano::den), tv_nsec(v % nano::den)
-    { }
-  private:
-    time_t tv_sec;
-    long tv_nsec;
-  };
-  bool operator==(fs_timespec_rep, fs_timespec_rep);
-  fs_int128_rep operator+(fs_timespec_rep, fs_timespec_rep);
-  // ... arithmetic operators ... //
-
-The first thing to notice is that we can't construct ``fs_timespec_rep`` like
-a ``timespec`` by passing ``{secs, nsecs}``. Instead we're limited to
+```cpp
+struct fs_timespec_rep {
+  fs_timespec_rep(long long v)
+    : tv_sec(v / nano::den), tv_nsec(v % nano::den)
+  { }
+private:
+  time_t tv_sec;
+  long tv_nsec;
+};
+bool operator==(fs_timespec_rep, fs_timespec_rep);
+fs_int128_rep operator+(fs_timespec_rep, fs_timespec_rep);
+// ... arithmetic operators ... //
+```
+
+The first thing to notice is that we can't construct `fs_timespec_rep` like
+a `timespec` by passing `{secs, nsecs}`. Instead we're limited to
 constructing it from a single 64-bit integer.
 
-We also can't allow the user to inspect the ``tv_sec`` or ``tv_nsec`` values
-directly. A ``chrono::duration`` represents its value as a tick period and a
-number of ticks stored using ``rep``. The representation is unaware of the
-tick period it is being used to represent, but ``timespec`` is setup to assume
-a nanosecond tick period; which is the only case where the names ``tv_sec``
-and ``tv_nsec`` match the values they store.
+We also can't allow the user to inspect the `tv_sec` or `tv_nsec` values
+directly. A `chrono::duration` represents its value as a tick period and a
+number of ticks stored using `rep`. The representation is unaware of the
+tick period it is being used to represent, but `timespec` is setup to assume
+a nanosecond tick period; which is the only case where the names `tv_sec`
+and `tv_nsec` match the values they store.
 
-When we convert a nanosecond duration to seconds, ``fs_timespec_rep`` will
-use ``tv_sec`` to represent the number of giga seconds, and ``tv_nsec`` the
+When we convert a nanosecond duration to seconds, `fs_timespec_rep` will
+use `tv_sec` to represent the number of giga seconds, and `tv_nsec` the
 remaining seconds. Let's consider how this might cause a bug were users allowed
 to manipulate the fields directly.
 
-.. code-block:: cpp
-
-  template <class Period>
-  timespec convert_to_timespec(duration<fs_time_rep, Period> dur) {
-    fs_timespec_rep rep = dur.count();
-    return {rep.tv_sec, rep.tv_nsec}; // Oops! Period may not be nanoseconds.
-  }
-
-  template <class Duration>
-  Duration convert_to_duration(timespec ts) {
-    Duration dur({ts.tv_sec, ts.tv_nsec}); // Oops! Period may not be nanoseconds.
-    return file_time_type(dur);
-    file_time_type tp = last_write_time(p);
-    auto dur =
-  }
-
-  time_t extract_seconds(file_time_type tp) {
-    // Converting to seconds is a silly bug, but I could see it happening.
-    using SecsT = chrono::duration<file_time_type::rep, ratio<1, 1>>;
-    auto secs = duration_cast<Secs>(tp.time_since_epoch());
-    // tv_sec is now representing gigaseconds.
-    return secs.count().tv_sec; // Oops!
-  }
-
-Despite ``fs_timespec_rep`` not being usable in any manner resembling
-``timespec``, it still might buy us our goal of matching its range exactly,
+```cpp
+template <class Period>
+timespec convert_to_timespec(duration<fs_time_rep, Period> dur) {
+  fs_timespec_rep rep = dur.count();
+  return {rep.tv_sec, rep.tv_nsec}; // Oops! Period may not be nanoseconds.
+}
+
+template <class Duration>
+Duration convert_to_duration(timespec ts) {
+  Duration dur({ts.tv_sec, ts.tv_nsec}); // Oops! Period may not be nanoseconds.
+  return file_time_type(dur);
+  file_time_type tp = last_write_time(p);
+  auto dur =
+}
+
+time_t extract_seconds(file_time_type tp) {
+  // Converting to seconds is a silly bug, but I could see it happening.
+  using SecsT = chrono::duration<file_time_type::rep, ratio<1, 1>>;
+  auto secs = duration_cast<Secs>(tp.time_since_epoch());
+  // tv_sec is now representing gigaseconds.
+  return secs.count().tv_sec; // Oops!
+}
+```
+
+Despite `fs_timespec_rep` not being usable in any manner resembling
+`timespec`, it still might buy us our goal of matching its range exactly,
 right?
 
 Sort of. Chrono provides a specialization point which specifies the minimum
 and maximum values for a custom representation. It looks like this:
 
-.. code-block:: cpp
-
-  template <>
-  struct duration_values<fs_timespec_rep> {
-    static fs_timespec_rep zero();
-    static fs_timespec_rep min();
-    static fs_timespec_rep max() { // assume friendship.
-      fs_timespec_rep val;
-      val.tv_sec = numeric_limits<time_t>::max();
-      val.tv_nsec = nano::den - 1;
-      return val;
-    }
-  };
+```cpp
+template <>
+struct duration_values<fs_timespec_rep> {
+  static fs_timespec_rep zero();
+  static fs_timespec_rep min();
+  static fs_timespec_rep max() { // assume friendship.
+    fs_timespec_rep val;
+    val.tv_sec = numeric_limits<time_t>::max();
+    val.tv_nsec = nano::den - 1;
+    return val;
+  }
+};
+```
 
-Notice that ``duration_values`` doesn't tell the representation what tick
+Notice that `duration_values` doesn't tell the representation what tick
 period it's actually representing. This would indeed correctly limit the range
-of ``duration<fs_timespec_rep, nano>`` to exactly that of ``timespec``. But
+of `duration<fs_timespec_rep, nano>` to exactly that of `timespec`. But
 nanoseconds isn't the only tick period it will be used to represent. For
 example:
 
-.. code-block:: cpp
-
-  void test() {
-    using rep = file_time_type::rep;
-    using fs_nsec = duration<rep, nano>;
-    using fs_sec = duration<rep>;
-    fs_nsec nsecs(fs_seconds::max()); // Truncates
-  }
+```cpp
+void test() {
+  using rep = file_time_type::rep;
+  using fs_nsec = duration<rep, nano>;
+  using fs_sec = duration<rep>;
+  fs_nsec nsecs(fs_seconds::max()); // Truncates
+}
+```
 
 Though the above example may appear silly, I think it follows from the incorrect
-notion that using a ``timespec`` rep in chrono actually makes it act as if it
-were an actual ``timespec``.
+notion that using a `timespec` rep in chrono actually makes it act as if it
+were an actual `timespec`.
 
-Interactions with 32-bit ``time_t``
------------------------------------
+### Interactions with 32-bit `time_t`
 
-Up until now we've only be considering cases where ``time_t`` is 64 bits, but what
-about 32-bit systems/builds where ``time_t`` is 32 bits? (this is the common case
+Up until now we've only be considering cases where `time_t` is 64 bits, but what
+about 32-bit systems/builds where `time_t` is 32 bits? (this is the common case
 for 32-bit builds).
 
-When ``time_t`` is 32 bits, we can implement ``file_time_type`` simply using 64-bit
-``long long``. There is no need to get either ``__int128_t`` or ``timespec`` emulation
+When `time_t` is 32 bits, we can implement `file_time_type` simply using 64-bit
+`long long`. There is no need to get either `__int128_t` or `timespec` emulation
 involved. And nor should we, as it would suffer from the numerous complications
 described by this paper.
 
 Obviously our implementation for 32-bit builds should act as similarly to the
 64-bit build as possible. Code which compiles in one, should compile in the other.
-This consideration is important when choosing between ``__int128_t`` and
-emulating ``timespec``. The solution which provides the most uniformity with
+This consideration is important when choosing between `__int128_t` and
+emulating `timespec`. The solution which provides the most uniformity with
 the least eccentricity is the preferable one.
 
-Summary
-=======
+## Summary
 
-The ``file_time_type`` time point is used to represent the write times for files.
+The `file_time_type` time point is used to represent the write times for files.
 Its job is to act as part of a C++ wrapper for less ideal system interfaces. The
-underlying filesystem uses the ``timespec`` struct for the same purpose.
+underlying filesystem uses the `timespec` struct for the same purpose.
 
-However, the initial implementation of ``file_time_type`` could not represent
-either the range or resolution of ``timespec``, making it unsuitable. Fixing
+However, the initial implementation of `file_time_type` could not represent
+either the range or resolution of `timespec`, making it unsuitable. Fixing
 this requires an implementation which uses more than 64 bits to store the
 time point.
 
-We primarily considered two solutions: Using ``__int128_t`` and using a
-arithmetic emulation of ``timespec``. Each has its pros and cons, and both
+We primarily considered two solutions: Using `__int128_t` and using a
+arithmetic emulation of `timespec`. Each has its pros and cons, and both
 come with more than one complication.
 
-The Potential Solutions
------------------------
+### The Potential Solutions
 
-``long long`` - The Status Quo
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#### `long long` - The Status Quo
 
 Pros:
 
-* As a type ``long long`` plays the nicest with others:
+- As a type `long long` plays the nicest with others:
 
-  * It works with streaming operators and other library entities which support
-    builtin integer types, but don't support ``__int128_t``.
-  * Its the representation used by chrono's ``nanosecond`` and ``second`` typedefs.
+  - It works with streaming operators and other library entities which support
+    builtin integer types, but don't support `__int128_t`.
+  - Its the representation used by chrono's `nanosecond` and `second` typedefs.
 
 Cons:
 
-* It cannot provide the same resolution as ``timespec`` unless we limit it
+- It cannot provide the same resolution as `timespec` unless we limit it
   to a range of +/- 300 years from the epoch.
-* It cannot provide the same range as ``timespec`` unless we limit its resolution
+- It cannot provide the same range as `timespec` unless we limit its resolution
   to seconds.
-* ``last_write_time`` has to report an error when the time reported by the filesystem
+- `last_write_time` has to report an error when the time reported by the filesystem
   is unrepresentable.
 
-__int128_t
-~~~~~~~~~~~
+#### \_\_int128_t
----------------
ldionne wrote:

```suggestion
#### `__int128_t`
```

https://github.com/llvm/llvm-project/pull/221513


More information about the llvm-branch-commits mailing list