Files
binutils-gdb/gdb/thread-iter.h
Simon Marchi 9be259865c gdb: introduce iterator_range, remove next_adapter
I was always a bit confused by next_adapter, because it kind of mixes
the element type and the iterator type.  In reality, it is not much more
than a class that wraps two iterators (begin and end).  However, it
assumes that:

 - you can construct the begin iterator by passing a pointer to the
   first element of the iterable
 - you can default-construct iterator to make the end iterator

I think that by generalizing it a little bit, we can re-use it at more
places.

Rename it to "iterator_range".  I think it describes a bit better: it's
a range made by wrapping a begin and end iterator.  Move it to its own
file, since it's not related to next_iterator anymore.

iterator_range has two constructors.  The variadic one, where arguments
are forwarded to construct the underlying begin iterator.  The end
iterator is constructed through default construction.  This is a
generalization of what we have today.

There is another constructor which receives already constructed begin
and end iterators, useful if the end iterator can't be obtained by
default-construction.  Or, if you wanted to make a range that does not
end at the end of the container, you could pass any iterator as the
"end".

This generalization allows removing some "range" classes, like
all_inferiors_range.  These classes existed only to pass some arguments
when constructing the begin iterator.  With iterator_range, those same
arguments are passed to the iterator_range constructed and then
forwarded to the constructed begin iterator.

There is a small functional difference in how iterator_range works
compared to next_adapter.  next_adapter stored the pointer it received
as argument and constructeur an iterator in the `begin` method.
iterator_range constructs the begin iterator and stores it as a member.
Its `begin` method returns a copy of that iterator.

With just iterator_range, uses of next_adapter<foo> would be replaced
with:

  using foo_iterator = next_iterator<foo>;
  using foo_range = iterator_range<foo_iterator>;

However, I added a `next_range` wrapper as a direct replacement for
next_adapter<foo>.  IMO, next_range is a slightly better name than
next_adapter.

The rest of the changes are applications of this new class.

gdbsupport/ChangeLog:

	* next-iterator.h (class next_adapter): Remove.
	* iterator-range.h: New.

gdb/ChangeLog:

	* breakpoint.h (bp_locations_range): Remove.
	(bp_location_range): New.
	(struct breakpoint) <locations>: Adjust type.
	(breakpoint_range): Use iterator_range.
	(tracepoint_range): Use iterator_range.
	* breakpoint.c (breakpoint::locations): Adjust return type.
	* gdb_bfd.h (gdb_bfd_section_range): Use iterator_range.
	* gdbthread.h (all_threads_safe): Pass argument to
	all_threads_safe_range.
	* inferior-iter.h (all_inferiors_range): Use iterator_range.
	(all_inferiors_safe_range): Use iterator_range.
	(all_non_exited_inferiors_range): Use iterator_range.
	* inferior.h (all_inferiors, all_non_exited_inferiors): Pass
	inferior_list as argument.
	* objfiles.h (struct objfile) <compunits_range>: Remove.
	<compunits>: Return compunit_symtab_range.
	* progspace.h (unwrapping_objfile_iterator)
	<unwrapping_objfile_iterator>: Take parameter by value.
	(unwrapping_objfile_range): Use iterator_range.
	(struct program_space) <objfiles_range>: Define with "using".
	<objfiles>: Adjust.
	<objfiles_safe_range>: Define with "using".
	<objfiles_safe>: Adjust.
	<solibs>: Return so_list_range, define here.
	* progspace.c (program_space::solibs): Remove.
	* psymtab.h (class psymtab_storage) <partial_symtab_iterator>:
	New.
	<partial_symtab_range>: Use iterator_range.
	* solist.h (so_list_range): New.
	* symtab.h (compunit_symtab_range):
	New.
	(symtab_range): New.
	(compunit_filetabs): Change to a function.
	* thread-iter.h (inf_threads_range,
	inf_non_exited_threads_range, safe_inf_threads_range,
	all_threads_safe_range): Use iterator_range.
	* top.h (ui_range): New.
	(all_uis): Use ui_range.

Change-Id: Ib7a9d2a3547f45f01aa1c6b24536ba159db9b854
2021-07-06 15:02:05 -04:00

245 lines
6.9 KiB
C++

/* Thread iterators and ranges for GDB, the GNU debugger.
Copyright (C) 2018-2021 Free Software Foundation, Inc.
This file is part of GDB.
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, see <http://www.gnu.org/licenses/>. */
#ifndef THREAD_ITER_H
#define THREAD_ITER_H
#include "gdbsupport/filtered-iterator.h"
#include "gdbsupport/next-iterator.h"
#include "gdbsupport/safe-iterator.h"
/* A forward iterator that iterates over a given inferior's
threads. */
using inf_threads_iterator = next_iterator<thread_info>;
/* A forward iterator that iterates over all threads of all
inferiors. */
class all_threads_iterator
{
public:
typedef all_threads_iterator self_type;
typedef struct thread_info *value_type;
typedef struct thread_info *&reference;
typedef struct thread_info **pointer;
typedef std::forward_iterator_tag iterator_category;
typedef int difference_type;
/* Tag type. */
struct begin_t {};
/* Create an iterator that points to the first thread of the first
inferior. */
explicit all_threads_iterator (begin_t);
/* Create a one-past-end iterator. */
all_threads_iterator ()
: m_thr (nullptr)
{}
thread_info *operator* () const { return m_thr; }
all_threads_iterator &operator++ ()
{
advance ();
return *this;
}
bool operator== (const all_threads_iterator &other) const
{ return m_thr == other.m_thr; }
bool operator!= (const all_threads_iterator &other) const
{ return m_thr != other.m_thr; }
private:
/* Advance to the next thread. */
void advance ();
private:
/* The current inferior and thread. M_THR is NULL if we reached the
end of the threads list of the last inferior. */
inferior *m_inf;
thread_info *m_thr;
};
/* Iterate over all threads that match a given PTID. */
class all_matching_threads_iterator
{
public:
typedef all_matching_threads_iterator self_type;
typedef struct thread_info *value_type;
typedef struct thread_info *&reference;
typedef struct thread_info **pointer;
typedef std::forward_iterator_tag iterator_category;
typedef int difference_type;
/* Creates an iterator that iterates over all threads that match
FILTER_PTID. */
all_matching_threads_iterator (process_stratum_target *filter_target,
ptid_t filter_ptid);
/* Create a one-past-end iterator. */
all_matching_threads_iterator ()
: m_inf (nullptr),
m_thr (nullptr),
m_filter_target (nullptr),
m_filter_ptid (minus_one_ptid)
{}
thread_info *operator* () const { return m_thr; }
all_matching_threads_iterator &operator++ ()
{
advance ();
return *this;
}
bool operator== (const all_matching_threads_iterator &other) const
{ return m_thr == other.m_thr; }
bool operator!= (const all_matching_threads_iterator &other) const
{ return m_thr != other.m_thr; }
private:
/* Advance to next thread, skipping filtered threads. */
void advance ();
/* True if M_INF matches the process identified by
M_FILTER_PTID. */
bool m_inf_matches ();
private:
/* The current inferior. */
inferior *m_inf;
/* The current thread. */
thread_info *m_thr;
/* The filter. */
process_stratum_target *m_filter_target;
ptid_t m_filter_ptid;
};
/* Filter for filtered_iterator. Filters out exited threads. */
struct non_exited_thread_filter
{
bool operator() (struct thread_info *thr) const
{
return thr->state != THREAD_EXITED;
}
};
/* Iterate over all non-exited threads that match a given PTID. */
using all_non_exited_threads_iterator
= filtered_iterator<all_matching_threads_iterator, non_exited_thread_filter>;
/* Iterate over all non-exited threads of an inferior. */
using inf_non_exited_threads_iterator
= filtered_iterator<inf_threads_iterator, non_exited_thread_filter>;
/* Iterate over all threads of all inferiors, safely. */
using all_threads_safe_iterator
= basic_safe_iterator<all_threads_iterator>;
/* Iterate over all threads of an inferior, safely. */
using safe_inf_threads_iterator
= basic_safe_iterator<inf_threads_iterator>;
/* A range adapter that makes it possible to iterate over all threads
of an inferior with range-for. */
using inf_threads_range = iterator_range<inf_threads_iterator>;
/* A range adapter that makes it possible to iterate over all
non-exited threads of an inferior with range-for. */
using inf_non_exited_threads_range
= iterator_range<inf_non_exited_threads_iterator>;
/* A range adapter that makes it possible to iterate over all threads
of an inferior with range-for, safely. */
using safe_inf_threads_range = iterator_range<safe_inf_threads_iterator>;
/* A range adapter that makes it possible to iterate over all threads
with range-for "safely". I.e., it is safe to delete the
currently-iterated thread. */
using all_threads_safe_range = iterator_range<all_threads_safe_iterator>;
/* A range adapter that makes it possible to iterate over all threads
that match a PTID filter with range-for. */
struct all_matching_threads_range
{
public:
all_matching_threads_range (process_stratum_target *filter_target,
ptid_t filter_ptid)
: m_filter_target (filter_target), m_filter_ptid (filter_ptid)
{}
all_matching_threads_range ()
: m_filter_target (nullptr), m_filter_ptid (minus_one_ptid)
{}
all_matching_threads_iterator begin () const
{ return all_matching_threads_iterator (m_filter_target, m_filter_ptid); }
all_matching_threads_iterator end () const
{ return all_matching_threads_iterator (); }
private:
/* The filter. */
process_stratum_target *m_filter_target;
ptid_t m_filter_ptid;
};
/* A range adapter that makes it possible to iterate over all
non-exited threads of all inferiors, with range-for.
Threads/inferiors that do not match FILTER_PTID are filtered
out. */
class all_non_exited_threads_range
{
public:
all_non_exited_threads_range (process_stratum_target *filter_target,
ptid_t filter_ptid)
: m_filter_target (filter_target), m_filter_ptid (filter_ptid)
{}
all_non_exited_threads_range ()
: m_filter_target (nullptr), m_filter_ptid (minus_one_ptid)
{}
all_non_exited_threads_iterator begin () const
{ return all_non_exited_threads_iterator (m_filter_target, m_filter_ptid); }
all_non_exited_threads_iterator end () const
{ return all_non_exited_threads_iterator (); }
private:
process_stratum_target *m_filter_target;
ptid_t m_filter_ptid;
};
#endif /* THREAD_ITER_H */