From 619b578614ab6e2d697db9ec720b12c675a14f19 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Tue, 8 Jul 2025 18:19:45 -0400
Subject: [PATCH 04/41] json: add json::value::clone

gcc/ChangeLog:
	* json.cc (json::object::clone): New.
	(json::object::clone_as_object): New.
	(json::array::clone): New.
	(json::float_number::clone): New.
	(json::integer_number::clone): New.
	(json::string::clone): New.
	(json::literal::clone): New.
	(selftest::test_cloning): New test.
	(selftest::json_cc_tests): Call it.
	* json.h (json::value::clone): New vfunc.
	(json::object::clone): New decl.
	(json::object::clone_as_object): New decl.
	(json::array::clone): New decl.
	(json::float_number::clone): New decl.
	(json::integer_number::clone): New decl.
	(json::string::clone): New decl.
	(json::literal::clone): New decl.
---
 gcc/json.cc | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/json.h  |   9 +++++
 2 files changed, 118 insertions(+)

diff --git a/gcc/json.cc b/gcc/json.cc
index df0702f8e6c5..7153f087a001 100644
--- a/gcc/json.cc
+++ b/gcc/json.cc
@@ -289,6 +289,30 @@ object::print (pretty_printer *pp, bool formatted) const
   pp_character (pp, '}');
 }
 
+std::unique_ptr<value>
+object::clone () const
+{
+  return clone_as_object ();
+}
+
+std::unique_ptr<object>
+object::clone_as_object () const
+{
+  auto result = std::make_unique<object> ();
+
+  /* Iterate in the order that the keys were inserted.  */
+  unsigned i;
+  const char *key;
+  FOR_EACH_VEC_ELT (m_keys, i, key)
+    {
+      map_t &mut_map = const_cast<map_t &> (m_map);
+      value *value = *mut_map.get (key);
+      result->set (key, value->clone ());
+    }
+
+  return result;
+}
+
 /* Set the json::value * for KEY, taking ownership of V
    (and taking a copy of KEY if necessary).  */
 
@@ -443,6 +467,17 @@ array::print (pretty_printer *pp, bool formatted) const
   pp_character (pp, ']');
 }
 
+std::unique_ptr<value>
+array::clone () const
+{
+  auto result = std::make_unique<array> ();
+  unsigned i;
+  value *v;
+  FOR_EACH_VEC_ELT (m_elements, i, v)
+    result->append (v->clone ());
+  return result;
+}
+
 /* Append non-NULL value V to a json::array, taking ownership of V.  */
 
 void
@@ -473,6 +508,12 @@ float_number::print (pretty_printer *pp,
   pp_string (pp, tmp);
 }
 
+std::unique_ptr<value>
+float_number::clone () const
+{
+  return std::make_unique<float_number> (m_value);
+}
+
 /* class json::integer_number, a subclass of json::value, wrapping a long.  */
 
 /* Implementation of json::value::print for json::integer_number.  */
@@ -486,6 +527,11 @@ integer_number::print (pretty_printer *pp,
   pp_string (pp, tmp);
 }
 
+std::unique_ptr<value>
+integer_number::clone () const
+{
+  return std::make_unique<integer_number> (m_value);
+}
 
 /* class json::string, a subclass of json::value.  */
 
@@ -516,6 +562,12 @@ string::print (pretty_printer *pp,
   print_escaped_json_string (pp, m_utf8, m_len);
 }
 
+std::unique_ptr<value>
+string::clone () const
+{
+  return std::make_unique<string> (m_utf8, m_len);
+}
+
 /* class json::literal, a subclass of json::value.  */
 
 /* Implementation of json::value::print for json::literal.  */
@@ -540,6 +592,12 @@ literal::print (pretty_printer *pp,
     }
 }
 
+std::unique_ptr<value>
+literal::clone () const
+{
+  return std::make_unique<literal> (m_kind);
+}
+
 
 #if CHECKING_P
 
@@ -924,6 +982,56 @@ test_strcmp ()
   ASSERT_EQ (strcmp (str.get_string (), "foo"), 0);
 }
 
+static void
+test_cloning ()
+{
+  // Objects
+  {
+    object obj;
+    obj.set_string ("foo", "bar");
+
+    auto obj_clone = obj.clone ();
+    ASSERT_JSON_EQ (obj, *obj_clone);
+  }
+
+  // Arrays
+  {
+    array arr;
+    arr.append (std::make_unique<string> ("foo"));
+
+    auto arr_clone = arr.clone ();
+    ASSERT_JSON_EQ (arr, *arr_clone);
+  }
+
+  // float_number
+  {
+    float_number f_one (1.0);
+    auto f_clone = f_one.clone ();
+    ASSERT_JSON_EQ (f_one, *f_clone);
+  }
+
+  // integer_number
+  {
+    integer_number num (42);
+    auto num_clone = num.clone ();
+    ASSERT_JSON_EQ (num, *num_clone);
+  }
+
+  // string
+  {
+    string str ("foo");
+    auto str_clone = str.clone ();
+    ASSERT_JSON_EQ (str, *str_clone);
+  }
+
+  // literal
+  {
+    literal lit (JSON_TRUE);
+    auto lit_clone = lit.clone ();
+    ASSERT_JSON_EQ (lit, *lit_clone);
+  }
+}
+
 /* Run all of the selftests within this file.  */
 
 void
@@ -939,6 +1047,7 @@ json_cc_tests ()
   test_formatting ();
   test_comparisons ();
   test_strcmp ();
+  test_cloning ();
 }
 
 } // namespace selftest
diff --git a/gcc/json.h b/gcc/json.h
index da4da852a1ed..156c086d2cfd 100644
--- a/gcc/json.h
+++ b/gcc/json.h
@@ -124,6 +124,7 @@ class value
   virtual ~value () {}
   virtual enum kind get_kind () const = 0;
   virtual void print (pretty_printer *pp, bool formatted) const = 0;
+  virtual std::unique_ptr<value> clone () const = 0;
 
   void dump (FILE *, bool formatted) const;
   void DEBUG_FUNCTION dump () const;
@@ -150,6 +151,7 @@ class object : public value
 
   enum kind get_kind () const final override { return JSON_OBJECT; }
   void print (pretty_printer *pp, bool formatted) const final override;
+  std::unique_ptr<value> clone () const final override;
 
   object *dyn_cast_object () final override { return this; }
 
@@ -182,6 +184,8 @@ class object : public value
 
   static int compare (const json::object &obj_a, const json::object &obj_b);
 
+  std::unique_ptr<object> clone_as_object () const;
+
  private:
   typedef hash_map <char *, value *,
     simple_hashmap_traits<nofree_string_hash, value *> > map_t;
@@ -200,6 +204,7 @@ class array : public value
 
   enum kind get_kind () const final override { return JSON_ARRAY; }
   void print (pretty_printer *pp, bool formatted) const final override;
+  std::unique_ptr<value> clone () const final override;
 
   void append (value *v);
   void append_string (const char *utf8_value);
@@ -241,6 +246,7 @@ class float_number : public value
 
   enum kind get_kind () const final override { return JSON_FLOAT; }
   void print (pretty_printer *pp, bool formatted) const final override;
+  std::unique_ptr<value> clone () const final override;
 
   double get () const { return m_value; }
 
@@ -257,6 +263,7 @@ class integer_number : public value
 
   enum kind get_kind () const final override { return JSON_INTEGER; }
   void print (pretty_printer *pp, bool formatted) const final override;
+  std::unique_ptr<value> clone () const final override;
 
   long get () const { return m_value; }
 
@@ -276,6 +283,7 @@ class string : public value
 
   enum kind get_kind () const final override { return JSON_STRING; }
   void print (pretty_printer *pp, bool formatted) const final override;
+  std::unique_ptr<value> clone () const final override;
 
   const char *get_string () const { return m_utf8; }
   size_t get_length () const { return m_len; }
@@ -298,6 +306,7 @@ class literal : public value
 
   enum kind get_kind () const final override { return m_kind; }
   void print (pretty_printer *pp, bool formatted) const final override;
+  std::unique_ptr<value> clone () const final override;
 
  private:
   enum kind m_kind;
-- 
2.26.3

