1// -*- C++ -*-
2
3// Copyright (C) 2005-2022 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library.  This library is free
6// software; you can redistribute it and/or modify it under the terms
7// of the GNU General Public License as published by the Free Software
8// Foundation; either version 3, or (at your option) any later
9// version.
10
11// This library is distributed in the hope that it will be useful, but
12// WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14// General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23// <http://www.gnu.org/licenses/>.
24
25// Copyright (C) 2004 Ami Tavory and Vladimir Dreizin, IBM-HRL.
26
27// Permission to use, copy, modify, sell, and distribute this software
28// is hereby granted without fee, provided that the above copyright
29// notice appears in all copies, and that both that copyright notice
30// and this permission notice appear in supporting documentation. None
31// of the above authors, nor IBM Haifa Research Laboratories, make any
32// representation about the suitability of this software for any
33// purpose. It is provided "as is" without express or implied
34// warranty.
35
36/**
37 * @file detail/debug_map_base.hpp
38 * Contains a debug-mode base for all maps.
39 */
40
41#ifndef PB_DS_DEBUG_MAP_BASE_HPP
42#define PB_DS_DEBUG_MAP_BASE_HPP
43
44#ifdef _GLIBCXX_DEBUG
45
46#include <list>
47#include <utility>
48#include <cstdlib>
49#include <iostream>
50#include <ext/throw_allocator.h>
51#include <debug/debug.h>
52
53namespace __gnu_pbds
54{
55  namespace detail
56  {
57    // Need std::pair ostream extractor.
58    template<typename _CharT, typename _Traits, typename _Tp1, typename _Tp2>
59    inline std::basic_ostream<_CharT, _Traits>&
60    operator<<(std::basic_ostream<_CharT, _Traits>& __out,
61	       const std::pair<_Tp1, _Tp2>& p)
62    { return (__out << '(' << p.first << ',' << p.second << ')'); }
63
64#define PB_DS_CLASS_T_DEC \
65    template<typename Key, typename Eq_Fn, typename Const_Key_Reference>
66
67#define PB_DS_CLASS_C_DEC \
68    debug_map_base<Key, Eq_Fn, Const_Key_Reference>
69
70    /// Debug base class.
71    template<typename Key, typename Eq_Fn, typename Const_Key_Reference>
72    class debug_map_base
73    {
74    private:
75      typedef Const_Key_Reference 			key_const_reference;
76      typedef std::_GLIBCXX_STD_C::list<Key> 		key_repository;
77      typedef typename key_repository::size_type       	size_type;
78      typedef typename key_repository::iterator	       	iterator;
79      typedef typename key_repository::const_iterator  	const_iterator;
80
81    protected:
82      debug_map_base();
83
84      debug_map_base(const PB_DS_CLASS_C_DEC&);
85
86      ~debug_map_base();
87
88      inline void
89      insert_new(key_const_reference);
90
91      inline void
92      erase_existing(key_const_reference);
93
94      void
95      clear();
96
97      inline void
98      check_key_exists(key_const_reference, const char*, int) const;
99
100      inline void
101      check_key_does_not_exist(key_const_reference, const char*, int) const;
102
103      inline void
104      check_size(size_type, const char*, int) const;
105
106      void
107      swap(PB_DS_CLASS_C_DEC&);
108
109      template<typename Cmp_Fn>
110      void
111      split(key_const_reference, Cmp_Fn, PB_DS_CLASS_C_DEC&);
112
113      void
114      join(PB_DS_CLASS_C_DEC&, bool with_cleanup = true);
115
116    private:
117      void
118      assert_valid(const char*, int) const;
119
120      const_iterator
121      find(key_const_reference) const;
122
123      iterator
124      find(key_const_reference);
125
126      key_repository 	m_keys;
127      Eq_Fn 		m_eq;
128    };
129
130    PB_DS_CLASS_T_DEC
131    PB_DS_CLASS_C_DEC::
132    debug_map_base()
133    { PB_DS_ASSERT_VALID((*this)) }
134
135    PB_DS_CLASS_T_DEC
136    PB_DS_CLASS_C_DEC::
137    debug_map_base(const PB_DS_CLASS_C_DEC& other)
138    : m_keys(other.m_keys), m_eq(other.m_eq)
139    { PB_DS_ASSERT_VALID((*this)) }
140
141    PB_DS_CLASS_T_DEC
142    PB_DS_CLASS_C_DEC::
143    ~debug_map_base()
144    { PB_DS_ASSERT_VALID((*this)) }
145
146    PB_DS_CLASS_T_DEC
147    inline void
148    PB_DS_CLASS_C_DEC::
149    insert_new(key_const_reference r_key)
150    {
151      PB_DS_ASSERT_VALID((*this))
152
153      if (find(r_key) != m_keys.end())
154	{
155	  std::cerr << "insert_new key already present " << r_key << std::endl;
156	  std::abort();
157	}
158
159      __try
160	{
161	  m_keys.push_back(r_key);
162	}
163      __catch(...)
164	{
165	  std::cerr << "insert_new " << r_key << std::endl;
166	  std::abort();
167	}
168
169      PB_DS_ASSERT_VALID((*this))
170    }
171
172    PB_DS_CLASS_T_DEC
173    inline void
174    PB_DS_CLASS_C_DEC::
175    erase_existing(key_const_reference r_key)
176    {
177      PB_DS_ASSERT_VALID((*this))
178      iterator it = find(r_key);
179      if (it == m_keys.end())
180	{
181	  std::cerr << "erase_existing" << r_key << std::endl;
182	  std::abort();
183	}
184      m_keys.erase(it);
185      PB_DS_ASSERT_VALID((*this))
186    }
187
188    PB_DS_CLASS_T_DEC
189    void
190    PB_DS_CLASS_C_DEC::
191    clear()
192    {
193      PB_DS_ASSERT_VALID((*this))
194      m_keys.clear();
195      PB_DS_ASSERT_VALID((*this))
196    }
197
198    PB_DS_CLASS_T_DEC
199    inline void
200    PB_DS_CLASS_C_DEC::
201    check_key_exists(key_const_reference r_key,
202		     const char* __file, int __line) const
203    {
204      assert_valid(__file, __line);
205      if (find(r_key) == m_keys.end())
206	{
207	  std::cerr << __file << ':' << __line << ": check_key_exists "
208		    << r_key << std::endl;
209	  std::abort();
210	}
211    }
212
213    PB_DS_CLASS_T_DEC
214    inline void
215    PB_DS_CLASS_C_DEC::
216    check_key_does_not_exist(key_const_reference r_key,
217			     const char* __file, int __line) const
218    {
219      assert_valid(__file, __line);
220      if (find(r_key) != m_keys.end())
221	{
222	  using std::cerr;
223	  using std::endl;
224	  cerr << __file << ':' << __line << ": check_key_does_not_exist "
225	       << r_key << endl;
226	  std::abort();
227	}
228    }
229
230    PB_DS_CLASS_T_DEC
231    inline void
232    PB_DS_CLASS_C_DEC::
233    check_size(size_type size, const char* __file, int __line) const
234    {
235      assert_valid(__file, __line);
236      const size_type keys_size = m_keys.size();
237      if (size != keys_size)
238	{
239	  std::cerr << __file << ':' << __line << ": check_size "
240		    << size << " != " << keys_size << std::endl;
241	  std::abort();
242	}
243     }
244
245    PB_DS_CLASS_T_DEC
246    void
247    PB_DS_CLASS_C_DEC::
248    swap(PB_DS_CLASS_C_DEC& other)
249    {
250      PB_DS_ASSERT_VALID((*this))
251      m_keys.swap(other.m_keys);
252      std::swap(m_eq, other.m_eq);
253      PB_DS_ASSERT_VALID((*this))
254    }
255
256    PB_DS_CLASS_T_DEC
257    typename PB_DS_CLASS_C_DEC::const_iterator
258    PB_DS_CLASS_C_DEC::
259    find(key_const_reference r_key) const
260    {
261      PB_DS_ASSERT_VALID((*this))
262      typedef const_iterator iterator_type;
263      for (iterator_type it = m_keys.begin(); it != m_keys.end(); ++it)
264	if (m_eq(*it, r_key))
265	  return it;
266      return m_keys.end();
267    }
268
269    PB_DS_CLASS_T_DEC
270    typename PB_DS_CLASS_C_DEC::iterator
271    PB_DS_CLASS_C_DEC::
272    find(key_const_reference r_key)
273    {
274      PB_DS_ASSERT_VALID((*this))
275      iterator it = m_keys.begin();
276      while (it != m_keys.end())
277	{
278	  if (m_eq(*it, r_key))
279	    return it;
280	  ++it;
281	}
282      return it;
283     }
284
285    PB_DS_CLASS_T_DEC
286    void
287    PB_DS_CLASS_C_DEC::
288    assert_valid(const char* __file, int __line) const
289    {
290      const_iterator prime_it = m_keys.begin();
291      while (prime_it != m_keys.end())
292	{
293	  const_iterator sec_it = prime_it;
294	  ++sec_it;
295	  while (sec_it != m_keys.end())
296	    {
297	      PB_DS_DEBUG_VERIFY(!m_eq(*sec_it, *prime_it));
298	      PB_DS_DEBUG_VERIFY(!m_eq(*prime_it, *sec_it));
299	      ++sec_it;
300	    }
301	  ++prime_it;
302	}
303    }
304
305    PB_DS_CLASS_T_DEC
306    template<typename Cmp_Fn>
307    void
308    PB_DS_CLASS_C_DEC::
309    split(key_const_reference r_key, Cmp_Fn cmp_fn, PB_DS_CLASS_C_DEC& other)
310    {
311      other.clear();
312      iterator it = m_keys.begin();
313      while (it != m_keys.end())
314	if (cmp_fn(r_key, *it))
315	  {
316	    other.insert_new(*it);
317	    it = m_keys.erase(it);
318	  }
319	else
320	  ++it;
321    }
322
323    PB_DS_CLASS_T_DEC
324    void
325    PB_DS_CLASS_C_DEC::
326    join(PB_DS_CLASS_C_DEC& other, bool with_cleanup)
327    {
328      iterator it = other.m_keys.begin();
329      while (it != other.m_keys.end())
330	{
331	  insert_new(*it);
332	  if (with_cleanup)
333	    it = other.m_keys.erase(it);
334	  else
335	    ++it;
336	}
337      _GLIBCXX_DEBUG_ASSERT(!with_cleanup || other.m_keys.empty());
338    }
339
340#undef PB_DS_CLASS_T_DEC
341#undef PB_DS_CLASS_C_DEC
342
343} // namespace detail
344} // namespace __gnu_pbds
345
346
347#endif
348
349#endif
350