summaryrefslogtreecommitdiff
path: root/dwarflint/all-dies-it.hh
blob: fe30057d18434dc4b774c303ee3f8f7b41ceea9f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/* Pedantic checking of DWARF files.
   Copyright (C) 2009, 2010, 2011 Red Hat, Inc.
   This file is part of elfutils.

   This file 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.

   elfutils 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/>.  */

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <vector>
#include <stdexcept>

// Tree flattening iterator.  It pre-order iterates all CUs in given
// dwarf file.
template <class T>
class all_dies_iterator
  : public std::iterator<std::input_iterator_tag,
			 typename T::debug_info_entry>
{
  typedef typename T::debug_info_entry::children_type::const_iterator die_it_t;
  typedef std::vector <std::pair <die_it_t, die_it_t> > die_it_stack_t;

  typename T::compile_units_type::const_iterator _m_cu_it, _m_cu_it_end;
  die_it_t _m_die_it, _m_die_it_end;
  die_it_stack_t _m_die_it_stack;
  bool _m_atend;

  void start ()
  {
    if (_m_cu_it == _m_cu_it_end)
      _m_atend = true;
    else
      {
	_m_die_it = die_it_t (*_m_cu_it);
	_m_die_it_end = die_it_t ();
	++_m_cu_it;
	assert (_m_die_it != _m_die_it_end);
      }
  }

public:
  // An end iterator.
  all_dies_iterator ()
    : _m_atend (true)
  {}

  explicit all_dies_iterator (T const &dw)
    : _m_cu_it (dw.compile_units ().begin ())
    , _m_cu_it_end (dw.compile_units ().end ())
    , _m_atend (_m_cu_it == _m_cu_it_end)
  {
    if (!_m_atend)
      start ();
  }

  bool operator== (all_dies_iterator const &other)
  {
    return (_m_atend && other._m_atend)
      || (_m_cu_it == other._m_cu_it
	  && _m_die_it == other._m_die_it
	  && _m_die_it_stack == other._m_die_it_stack);
  }

  bool operator!= (all_dies_iterator const &other)
  {
    return !(*this == other);
  }

  all_dies_iterator operator++ () // prefix
  {
    if (!_m_atend)
      {
	if (_m_die_it->has_children ()
	    && _m_die_it->children ().begin () != _m_die_it->children ().end ())
	  {
	    _m_die_it_stack.push_back (std::make_pair (_m_die_it, _m_die_it_end));
	    _m_die_it_end = _m_die_it->children ().end ();
	    _m_die_it = _m_die_it->children ().begin ();
	  }
	else
	  while (++_m_die_it == _m_die_it_end)

	    {
	      if (_m_die_it_stack.size () == 0)
		{
		  start ();
		  break;
		}
	      _m_die_it = _m_die_it_stack.back ().first;
	      _m_die_it_end = _m_die_it_stack.back ().second;
	      _m_die_it_stack.pop_back ();
	    }
      }
    return *this;
  }

  all_dies_iterator operator++ (int) // postfix
  {
    all_dies_iterator prev = *this;
    ++*this;
    return prev;
  }

  typename T::debug_info_entry const &operator* () const
  {
    if (unlikely (_m_atend))
      throw std::runtime_error ("dereferencing end iterator");
    return *_m_die_it;
  }

  std::vector<typename T::debug_info_entry> stack () const
  {
    std::vector<typename T::debug_info_entry> ret;
    for (auto it = _m_die_it_stack.begin ();
	 it != _m_die_it_stack.end (); ++it)
      ret.push_back (*it->first);
    ret.push_back (*_m_die_it);
    return ret;
  }

  typename T::compile_unit cu () const
  {
    return *_m_cu_it;
  }

  typename T::debug_info_entry const *operator-> () const
  {
    return &**this;
  }
};