public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Lancelot SIX <lsix@lancelotsix.com>
To: gdb-patches@sourceware.org
Cc: Lancelot SIX <lsix@lancelotsix.com>
Subject: [PATCH 4/4] gdb: Param setter return a bool to tell if the value changed
Date: Wed, 28 Jul 2021 20:50:43 +0100	[thread overview]
Message-ID: <20210728195043.904136-5-lsix@lancelotsix.com> (raw)
In-Reply-To: <20210728195043.904136-1-lsix@lancelotsix.com>

GDB can notify observers when a parameter is changed.

To do that, do_set_command (in gdb/cli/cli-setshow.c) compares the new
value against the old one before updating it, and based on that notifies
observers.  This looks like something like:

    int valuechanged = 0;
    switch (cmd->var.type ())
    {
    case var_integer:
      {
        LONGEST new_val = parse_and_eval_long (arg)
        if (new_val != cmd->var.get<var_integer> ())
        {
          cmd->var.get<var_integer> (new_val);
          value_changes = 1;
        }
      }
      break;
    case var_string:
      {
        std::string val = std::string (arg);
        if (new_val != cmd->var.get<var_string> ())
        {
          cmd->var.get<var_string> (new_val);
          value_changes = 1;
        }
      }
      break;
    case...
      /* And so on for all possible var_types.  */
    }

The main problem is that do_set_command does this comparison
for each possible var_types it handles, which leads to a significant
amount of code duplication.

In this patch I propose to move all those checks in one place within the
param setter method.  This has two advantages:

- Code duplication is reduced and the logic is written once within the
  templated setter.
- User provided setter can return a flag to indicate if a changed has
  been made based on its internal logic.  This can be useful for any
  command on which the set operation might fail.  This use case is
  inspired by a comment by Simon Marchi[1]

There should be no user visible change introduced by this commit.

Tested on x86_64 GNU/Linux.

[1] https://review.lttng.org/c/binutils-gdb/+/5831/41
---
 gdb/cli/cli-setshow.c | 98 ++++++++++---------------------------------
 gdb/command.h         |  8 ++--
 2 files changed, 26 insertions(+), 80 deletions(-)

diff --git a/gdb/cli/cli-setshow.c b/gdb/cli/cli-setshow.c
index 76a0d70a553..7ffa4dfe1cc 100644
--- a/gdb/cli/cli-setshow.c
+++ b/gdb/cli/cli-setshow.c
@@ -31,17 +31,17 @@
 
 /* Return true if the change of command parameter should be notified.  */
 
-static int
-notify_command_param_changed_p (int param_changed, struct cmd_list_element *c)
+static bool
+notify_command_param_changed_p (bool param_changed, struct cmd_list_element *c)
 {
-  if (param_changed == 0)
-    return 0;
+  if (!param_changed)
+    return false;
 
   if (c->theclass == class_maintenance || c->theclass == class_deprecated
       || c->theclass == class_obscure)
-    return 0;
+    return false;
 
-  return 1;
+  return true;
 }
 
 \f
@@ -305,7 +305,7 @@ void
 do_set_command (const char *arg, int from_tty, struct cmd_list_element *c)
 {
   /* A flag to indicate the option is changed or not.  */
-  int option_changed = 0;
+  bool option_changed = false;
 
   gdb_assert (c->type == set_cmd);
 
@@ -353,26 +353,12 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c)
 	*q++ = '\0';
 	newobj = (char *) xrealloc (newobj, q - newobj);
 
-	auto const var = c->var.get<var_string> ();
-	if (var != std::string (newobj))
-	  {
-	    c->var.set<var_string> (std::string (newobj));
-
-	    option_changed = 1;
-	  }
+	option_changed = c->var.set<var_string> (std::string (newobj));
 	xfree (newobj);
       }
       break;
     case var_string_noescape:
-      {
-	auto const var = c->var.get<var_string_noescape> ();
-	if (var != arg)
-	  {
-	    c->var.set<var_string_noescape> (std::string (arg));
-
-	    option_changed = 1;
-	  }
-      }
+      option_changed = c->var.set<var_string_noescape> (std::string (arg));
       break;
     case var_filename:
       if (*arg == '\0')
@@ -398,14 +384,8 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c)
 	else
 	  val = xstrdup ("");
 
-	auto const var = c->var.get<var_filename, var_optional_filename> ();
-	if (var != std::string (val))
-	  {
-	    c->var.set<var_filename, var_optional_filename>
-	      (std::string (val));
-
-	    option_changed = 1;
-	  }
+	option_changed
+	  = c->var.set<var_filename, var_optional_filename> (std::string (val));
 	xfree (val);
       }
       break;
@@ -415,38 +395,19 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c)
 
 	if (val < 0)
 	  error (_("\"on\" or \"off\" expected."));
-	if (val != c->var.get<var_boolean> ())
-	  {
-	    c->var.set<var_boolean> (val);
 
-	    option_changed = 1;
-	  }
+	option_changed = c->var.set<var_boolean> (val);
       }
       break;
     case var_auto_boolean:
-      {
-	enum auto_boolean val = parse_auto_binary_operation (arg);
-
-	if (c->var.get<var_auto_boolean> () != val)
-	  {
-	    c->var.set<var_auto_boolean> (val);
-
-	    option_changed = 1;
-	  }
-      }
+      option_changed
+	= c->var.set<var_auto_boolean> (parse_auto_binary_operation (arg));
       break;
     case var_uinteger:
     case var_zuinteger:
-      {
-	unsigned int val = parse_cli_var_uinteger (c->var.type (), &arg, true);
-
-	if (c->var.get<var_uinteger, var_zuinteger> () != val)
-	  {
-	    c->var.set<var_uinteger, var_zuinteger> (val);
-
-	    option_changed = 1;
-	  }
-      }
+      option_changed
+	= c->var.set<var_uinteger, var_zuinteger>
+	(parse_cli_var_uinteger (c->var.type (), &arg, true));
       break;
     case var_integer:
     case var_zinteger:
@@ -476,12 +437,7 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c)
 		 || (c->var.type () == var_zinteger && val > INT_MAX))
 	  error (_("integer %s out of range"), plongest (val));
 
-	if (c->var.get<var_integer, var_zinteger> () != val)
-	  {
-	    c->var.set<var_integer, var_zinteger> (val);
-
-	    option_changed = 1;
-	  }
+	option_changed = c->var.set<var_integer, var_zinteger> (val);
       }
       break;
     case var_enum:
@@ -494,24 +450,12 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c)
 	if (*after != '\0')
 	  error (_("Junk after item \"%.*s\": %s"), len, arg, after);
 
-	if (c->var.get<var_enum> () != match)
-	  {
-	    c->var.set<var_enum> (match);
-
-	    option_changed = 1;
-	  }
+	option_changed = c->var.set<var_enum> (match);
       }
       break;
     case var_zuinteger_unlimited:
-      {
-	int val = parse_cli_var_zuinteger_unlimited (&arg, true);
-
-	if (c->var.get<var_zuinteger_unlimited> () != val)
-	  {
-	    c->var.set<var_zuinteger_unlimited> (val);
-	    option_changed = 1;
-	  }
-      }
+      option_changed = c->var.set<var_zuinteger_unlimited>
+	(parse_cli_var_zuinteger_unlimited (&arg, true));
       break;
     default:
       error (_("gdb internal error: bad var_type in do_setshow_command"));
diff --git a/gdb/command.h b/gdb/command.h
index c8510acdf19..3bc4c41e6ab 100644
--- a/gdb/command.h
+++ b/gdb/command.h
@@ -129,7 +129,7 @@ template<typename T>
 struct accessor_sigs
 {
   using getter = T (*) ();
-  using setter = void (*) (T);
+  using setter = bool (*) (T);
 };
 
 /* Contains a function to access a parameter.  */
@@ -471,7 +471,7 @@ struct base_param_ref
   template<var_types... Ts,
 	   typename = gdb::Requires<
              detail::var_types_have_same_storage<Ts...>>>
-  void set (typename detail::var_types_have_same_storage<Ts...>::type v)
+  bool set (typename detail::var_types_have_same_storage<Ts...>::type v)
   {
     /* Check that the current instance is of one of the supported types for
        this instantiating.  */
@@ -483,13 +483,15 @@ struct base_param_ref
       (this->m_setter);
 
     if (setter != nullptr)
-      (*setter) (v);
+      return (*setter) (v);
     else
       {
 	gdb_assert (!this->empty ());
+	bool changed = (this->get<Ts...> () != v);
 	*static_cast<
 	  typename detail::var_types_have_same_storage<Ts...>::type *>
 	  (this->m_var) = v;
+	return changed;
       }
   }
 
-- 
2.31.1


  parent reply	other threads:[~2021-07-28 19:51 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-07-28 19:50 [PATCH 0/4] gdb: Refactor cmd_list_element.var Lancelot SIX
2021-07-28 19:50 ` [PATCH 1/4] gdb: Add typesafe getter/setter for cmd_list_element.var Lancelot SIX
2021-07-29  1:10   ` Simon Marchi
2021-07-28 19:50 ` [PATCH 2/4] gdb: make string-like set show commands use std::string variable Lancelot SIX
2021-07-29  1:27   ` Simon Marchi
2021-07-28 19:50 ` [PATCH 3/4] gdb: Have setter and getter callbacks for params Lancelot SIX
2021-07-29  1:39   ` Simon Marchi
2021-07-28 19:50 ` Lancelot SIX [this message]
2021-07-29  1:55   ` [PATCH 4/4] gdb: Param setter return a bool to tell if the value changed Simon Marchi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210728195043.904136-5-lsix@lancelotsix.com \
    --to=lsix@lancelotsix.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).