Fix PointerSet and BuilderRecordMap iterators under C++23

Adds explicit operator++() and operator++(int) overrides in
PointerSet::const_iterator, BuilderRecordMap::const_iterator, and the
unit test TestHashTable::const_iterator to satisfy weakly_incrementable
requirements. I've also updated documentation and sample custom iterator
implementations in src/gn/hash_table_base.h.

This fixes a compilation error that started with the update to C++23 in
88604adbcec2101f25b2e3ebd7f39b38163a6a33, which triggers the following
error (in my case: macOS 26.4.1 using Xcode 26.2) indicating that
PointerSet<const Target>::const_iterator fails to satisfy one of the
requirements of std::weakly_incrementable:

    ../src/gn/json_project_writer.cc:80:14: note: in instantiation of function template specialization 'std::vector<const Target *>::assign<PointerSet<const Target>::const_iterator, 0>' requested here
       80 |     targets->assign(target_set.begin(), target_set.end());
          |              ^
    /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__algorithm/ranges_copy_n.h:64:3: note: candidate template ignored: constraints not satisfied [with _Ip = __libcpp_remove_reference_t<const_iterator &>, _Op = pointer]
       64 |   operator()(_Ip __first, iter_difference_t<_Ip> __n, _Op __result) const {
          |   ^
    /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__algorithm/ranges_copy_n.h:61:13: note: because 'PointerSet<const Target>::const_iterator' does not satisfy 'input_iterator'
       61 |   template <input_iterator _Ip, weakly_incrementable _Op>
          |             ^
    /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__iterator/concepts.h:195:26: note: because 'PointerSet<const Target>::const_iterator' does not satisfy 'input_or_output_iterator'
      195 | concept input_iterator = input_or_output_iterator<_Ip> && indirectly_readable<_Ip> && requires {
          |                          ^
    /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__iterator/concepts.h:140:6: note: because 'PointerSet<const Target>::const_iterator' does not satisfy 'weakly_incrementable'
      140 | } && weakly_incrementable<_Ip>;
          |      ^
    /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__iterator/concepts.h:126:20: note: because type constraint 'same_as<HashTableBase<PointerSetNode>::NodeIterator &, PointerSet<const Target>::const_iterator &>' was not satisfied:
      126 |       { ++__i } -> same_as<_Ip&>; // not required to be equality-preserving
          |                    ^

It looks like the PointerSet<T> template class was originally introduced
in commit 0e7ed6358c5bdf4e2448f735d5d6cfa3b58af06a. Its custom
const_iterator subclasses NodeIterator directly without overriding
operator++ and operator++(int).

Specifically, when json_project_writer.cc calls
targets->assign(target_set.begin(), target_set.end()),
std::vector::asign() requires that its arguments staisfy
std::input_iterator, which in turn requires that it satisfy
std::input_or_output_iterator, which in turn requires
std::weakly_incrementable.

Looking at the requirements of std::weakly_incrementable, there are four
criteria (https://en.cppreference.com/cpp/iterator/weakly_incrementable):

  * std::movable<I>: must be moveable.
  * std::iter_difference<I>: must have a related signed integer type
    (such as std::ptrdiff_t) that represents the difference between two
    iterators.
  * { ++i } -> std::same_as<I&>: the pre-increment operator must exist
    and its return type must be I&. This is what we violated.
  * i++: The post-increment operator must exist. There's no requirement
    on return type, so no issue here.

Because PointerSet::const_iterator inherited operator++ from
NodeIterator, pre-incrementing returned NodeIterator& instead of
const_iterator&, it fails the concept check.

Change-Id: I425c4e153d7a087beaf37b10a2e519184b4801c3
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/22660
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Reviewed-by: David Turner <digit@google.com>
Commit-Queue: David Turner <digit@google.com>
diff --git a/src/gn/builder_record_map.h b/src/gn/builder_record_map.h
index 77f0695..41c6565 100644
--- a/src/gn/builder_record_map.h
+++ b/src/gn/builder_record_map.h
@@ -64,6 +64,16 @@
 
     const BuilderRecord* operator->() const { return node_->record; }
     BuilderRecord* operator->() { return node_->record; }
+
+    const_iterator& operator++() {
+      NodeIterator::operator++();
+      return *this;
+    }
+    const_iterator operator++(int) {
+      const_iterator result = *this;
+      NodeIterator::operator++();
+      return result;
+    }
   };
 
   const_iterator begin() const { return {NodeBegin()}; }
diff --git a/src/gn/hash_table_base.h b/src/gn/hash_table_base.h
index 7e5b34e..cfe194d 100644
--- a/src/gn/hash_table_base.h
+++ b/src/gn/hash_table_base.h
@@ -281,7 +281,16 @@
   //     // Iterators point to Foo instances, not table nodes.
   //     struct ConstIterator : NodeIterator {
   //       const Foo* operator->() { return node_->foo_ptr; }
-  //       const Foo& operator*)) { return *(node_->foo_ptr); }
+  //       const Foo& operator*() { return *(node_->foo_ptr); }
+  //       ConstIterator& operator++() {
+  //         NodeIterator::operator++();
+  //         return *this;
+  //       }
+  //       ConstIterator operator++(int) {
+  //         ConstIterator result = *this;
+  //         NodeIterator::operator++();
+  //         return result;
+  //       }
   //     };
   //
   //     ConstIterator begin() const { return { NodeBegin() }; }
@@ -371,7 +380,16 @@
   //     // Iterators point to Foo instances, not table nodes.
   //     struct ConstIterator : NodeIterator {
   //       const Foo* operator->() { return node_->foo_ptr; }
-  //       const Foo& operator*)) { return *(node_->foo_ptr); }
+  //       const Foo& operator*() { return *(node_->foo_ptr); }
+  //       ConstIterator& operator++() {
+  //         NodeIterator::operator++();
+  //         return *this;
+  //       }
+  //       ConstIterator operator++(int) {
+  //         ConstIterator result = *this;
+  //         NodeIterator::operator++();
+  //         return result;
+  //       }
   //     };
   //
   // and compare two ways to implement its begin() method:
diff --git a/src/gn/hash_table_base_unittest.cc b/src/gn/hash_table_base_unittest.cc
index 7acbfbe..17eaf98 100644
--- a/src/gn/hash_table_base_unittest.cc
+++ b/src/gn/hash_table_base_unittest.cc
@@ -182,6 +182,15 @@
       return (this->BaseType::NodeIterator::operator*()).int_ptr->x();
     }
     const int* operator->() const { return &(this->operator*()); }
+    const_iterator& operator++() {
+      BaseType::NodeIterator::operator++();
+      return *this;
+    }
+    const_iterator operator++(int) {
+      const_iterator result = *this;
+      BaseType::NodeIterator::operator++();
+      return result;
+    }
   };
 
   const_iterator begin() const { return {BaseType::NodeBegin()}; }
diff --git a/src/gn/pointer_set.h b/src/gn/pointer_set.h
index 6a4ec62..4c4da2f 100644
--- a/src/gn/pointer_set.h
+++ b/src/gn/pointer_set.h
@@ -161,6 +161,15 @@
     T* operator*() const {
       return const_cast<T*>(static_cast<const T*>(node_->ptr_));
     }
+    const_iterator& operator++() {
+      NodeIterator::operator++();
+      return *this;
+    }
+    const_iterator operator++(int) {
+      const_iterator result = *this;
+      NodeIterator::operator++();
+      return result;
+    }
 
     // The following allows:
     // std::vector<T*> vector(set.begin(), set.end());