1 // Debugging multimap implementation -*- C++ -*-
2 
3 // Copyright (C) 2003-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
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
10 
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU 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 /** @file debug/multimap.h
26  *  This file is a GNU debug extension to the Standard C++ Library.
27  */
28 
29 #ifndef _GLIBCXX_DEBUG_MULTIMAP_H
30 #define _GLIBCXX_DEBUG_MULTIMAP_H 1
31 
32 #include <debug/safe_sequence.h>
33 #include <debug/safe_container.h>
34 #include <debug/safe_iterator.h>
35 #include <bits/stl_pair.h>
36 
_GLIBCXX_VISIBILITY(default)37 namespace std _GLIBCXX_VISIBILITY(default)
38 {
39 namespace __debug
40 {
41   /// Class std::multimap with safety/checking/debug instrumentation.
42   template<typename _Key, typename _Tp, typename _Compare = std::less<_Key>,
43              typename _Allocator = std::allocator<std::pair<const _Key, _Tp> > >
44     class multimap
45       : public __gnu_debug::_Safe_container<
46           multimap<_Key, _Tp, _Compare, _Allocator>, _Allocator,
47           __gnu_debug::_Safe_node_sequence>,
48           public _GLIBCXX_STD_C::multimap<_Key, _Tp, _Compare, _Allocator>
49     {
50       typedef _GLIBCXX_STD_C::multimap<
51           _Key, _Tp, _Compare, _Allocator>                            _Base;
52       typedef __gnu_debug::_Safe_container<
53           multimap, _Allocator, __gnu_debug::_Safe_node_sequence>     _Safe;
54 
55       typedef typename _Base::const_iterator      _Base_const_iterator;
56       typedef typename _Base::iterator            _Base_iterator;
57       typedef __gnu_debug::_Equal_to<_Base_const_iterator> _Equal;
58 
59       template<typename _ItT, typename _SeqT, typename _CatT>
60           friend class ::__gnu_debug::_Safe_iterator;
61 
62       // Reference wrapper for base class. Disambiguates multimap(const _Base&)
63       // from copy constructor by requiring a user-defined conversion.
64       // See PR libstdc++/90102.
65       struct _Base_ref
66       {
67           _Base_ref(const _Base& __r) : _M_ref(__r) { }
68 
69           const _Base& _M_ref;
70       };
71 
72     public:
73       // types:
74       typedef _Key                                          key_type;
75       typedef _Tp                                           mapped_type;
76       typedef std::pair<const _Key, _Tp>                    value_type;
77       typedef _Compare                                                key_compare;
78       typedef _Allocator                                    allocator_type;
79       typedef typename _Base::reference                     reference;
80       typedef typename _Base::const_reference               const_reference;
81 
82       typedef __gnu_debug::_Safe_iterator<_Base_iterator, multimap>
83                                                                       iterator;
84       typedef __gnu_debug::_Safe_iterator<_Base_const_iterator,
85                                                     multimap>         const_iterator;
86 
87       typedef typename _Base::size_type                     size_type;
88       typedef typename _Base::difference_type               difference_type;
89       typedef typename _Base::pointer                       pointer;
90       typedef typename _Base::const_pointer                 const_pointer;
91       typedef std::reverse_iterator<iterator>               reverse_iterator;
92       typedef std::reverse_iterator<const_iterator>         const_reverse_iterator;
93 
94       // 23.3.1.1 construct/copy/destroy:
95 
96 #if __cplusplus < 201103L
97       multimap() : _Base() { }
98 
99       multimap(const multimap& __x)
100       : _Base(__x) { }
101 
102       ~multimap() { }
103 #else
104       multimap() = default;
105       multimap(const multimap&) = default;
106       multimap(multimap&&) = default;
107 
108       multimap(initializer_list<value_type> __l,
109                  const _Compare& __c = _Compare(),
110                  const allocator_type& __a = allocator_type())
111       : _Base(__l, __c, __a) { }
112 
113       explicit
114       multimap(const allocator_type& __a)
115       : _Base(__a) { }
116 
117       multimap(const multimap& __m,
118                  const __type_identity_t<allocator_type>& __a)
119       : _Base(__m, __a) { }
120 
121       multimap(multimap&& __m, const __type_identity_t<allocator_type>& __a)
122       noexcept( noexcept(_Base(std::move(__m), __a)) )
123       : _Safe(std::move(__m), __a),
124           _Base(std::move(__m), __a) { }
125 
126       multimap(initializer_list<value_type> __l, const allocator_type& __a)
127       : _Base(__l, __a) { }
128 
129       template<typename _InputIterator>
130           multimap(_InputIterator __first, _InputIterator __last,
131                      const allocator_type& __a)
132           : _Base(__gnu_debug::__base(
133                       __glibcxx_check_valid_constructor_range(__first, __last)),
134                     __gnu_debug::__base(__last), __a) { }
135 
136       ~multimap() = default;
137 #endif
138 
139       explicit multimap(const _Compare& __comp,
140                               const _Allocator& __a = _Allocator())
141       : _Base(__comp, __a) { }
142 
143       template<typename _InputIterator>
144       multimap(_InputIterator __first, _InputIterator __last,
145                  const _Compare& __comp = _Compare(),
146                  const _Allocator& __a = _Allocator())
147           : _Base(__gnu_debug::__base(
148                       __glibcxx_check_valid_constructor_range(__first, __last)),
149                     __gnu_debug::__base(__last),
150                 __comp, __a) { }
151 
152       multimap(_Base_ref __x)
153       : _Base(__x._M_ref) { }
154 
155 #if __cplusplus >= 201103L
156       multimap&
157       operator=(const multimap&) = default;
158 
159       multimap&
160       operator=(multimap&&) = default;
161 
162       multimap&
163       operator=(initializer_list<value_type> __l)
164       {
165           _Base::operator=(__l);
166           this->_M_invalidate_all();
167           return *this;
168       }
169 #endif
170 
171       using _Base::get_allocator;
172 
173       // iterators:
174       iterator
175       begin() _GLIBCXX_NOEXCEPT
176       { return iterator(_Base::begin(), this); }
177 
178       const_iterator
179       begin() const _GLIBCXX_NOEXCEPT
180       { return const_iterator(_Base::begin(), this); }
181 
182       iterator
183       end() _GLIBCXX_NOEXCEPT
184       { return iterator(_Base::end(), this); }
185 
186       const_iterator
187       end() const _GLIBCXX_NOEXCEPT
188       { return const_iterator(_Base::end(), this); }
189 
190       reverse_iterator
191       rbegin() _GLIBCXX_NOEXCEPT
192       { return reverse_iterator(end()); }
193 
194       const_reverse_iterator
195       rbegin() const _GLIBCXX_NOEXCEPT
196       { return const_reverse_iterator(end()); }
197 
198       reverse_iterator
199       rend() _GLIBCXX_NOEXCEPT
200       { return reverse_iterator(begin()); }
201 
202       const_reverse_iterator
203       rend() const _GLIBCXX_NOEXCEPT
204       { return const_reverse_iterator(begin()); }
205 
206 #if __cplusplus >= 201103L
207       const_iterator
208       cbegin() const noexcept
209       { return const_iterator(_Base::begin(), this); }
210 
211       const_iterator
212       cend() const noexcept
213       { return const_iterator(_Base::end(), this); }
214 
215       const_reverse_iterator
216       crbegin() const noexcept
217       { return const_reverse_iterator(end()); }
218 
219       const_reverse_iterator
220       crend() const noexcept
221       { return const_reverse_iterator(begin()); }
222 #endif
223 
224       // capacity:
225       using _Base::empty;
226       using _Base::size;
227       using _Base::max_size;
228 
229       // modifiers:
230 #if __cplusplus >= 201103L
231       template<typename... _Args>
232           iterator
233           emplace(_Args&&... __args)
234           { return { _Base::emplace(std::forward<_Args>(__args)...), this }; }
235 
236       template<typename... _Args>
237           iterator
238           emplace_hint(const_iterator __pos, _Args&&... __args)
239           {
240             __glibcxx_check_insert(__pos);
241             return
242               {
243                 _Base::emplace_hint(__pos.base(), std::forward<_Args>(__args)...),
244                 this
245               };
246           }
247 #endif
248 
249       iterator
250       insert(const value_type& __x)
251       { return iterator(_Base::insert(__x), this); }
252 
253 #if __cplusplus >= 201103L
254       // _GLIBCXX_RESOLVE_LIB_DEFECTS
255       // 2354. Unnecessary copying when inserting into maps with braced-init
256       iterator
257       insert(value_type&& __x)
258       { return { _Base::insert(std::move(__x)), this }; }
259 
260       template<typename _Pair, typename = typename
261                  std::enable_if<std::is_constructible<value_type,
262                                                                 _Pair&&>::value>::type>
263           iterator
264           insert(_Pair&& __x)
265           { return { _Base::insert(std::forward<_Pair>(__x)), this }; }
266 #endif
267 
268 #if __cplusplus >= 201103L
269       void
270       insert(std::initializer_list<value_type> __list)
271       { _Base::insert(__list); }
272 #endif
273 
274       iterator
275 #if __cplusplus >= 201103L
276       insert(const_iterator __position, const value_type& __x)
277 #else
278       insert(iterator __position, const value_type& __x)
279 #endif
280       {
281           __glibcxx_check_insert(__position);
282           return iterator(_Base::insert(__position.base(), __x), this);
283       }
284 
285 #if __cplusplus >= 201103L
286       // _GLIBCXX_RESOLVE_LIB_DEFECTS
287       // 2354. Unnecessary copying when inserting into maps with braced-init
288       iterator
289       insert(const_iterator __position, value_type&& __x)
290       {
291           __glibcxx_check_insert(__position);
292           return { _Base::insert(__position.base(), std::move(__x)), this };
293       }
294 
295       template<typename _Pair, typename = typename
296                  std::enable_if<std::is_constructible<value_type,
297                                                                 _Pair&&>::value>::type>
298           iterator
299           insert(const_iterator __position, _Pair&& __x)
300           {
301             __glibcxx_check_insert(__position);
302             return
303               {
304                 _Base::insert(__position.base(), std::forward<_Pair>(__x)),
305                 this
306               };
307           }
308 #endif
309 
310       template<typename _InputIterator>
311           void
312           insert(_InputIterator __first, _InputIterator __last)
313           {
314             typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
315             __glibcxx_check_valid_range2(__first, __last, __dist);
316 
317             if (__dist.second >= __gnu_debug::__dp_sign)
318               _Base::insert(__gnu_debug::__unsafe(__first),
319                                 __gnu_debug::__unsafe(__last));
320             else
321               _Base::insert(__first, __last);
322           }
323 
324 #if __cplusplus > 201402L
325       using node_type = typename _Base::node_type;
326 
327       node_type
328       extract(const_iterator __position)
329       {
330           __glibcxx_check_erase(__position);
331           this->_M_invalidate_if(_Equal(__position.base()));
332           return _Base::extract(__position.base());
333       }
334 
335       node_type
336       extract(const key_type& __key)
337       {
338           const auto __position = find(__key);
339           if (__position != end())
340             return extract(__position);
341           return {};
342       }
343 
344       iterator
345       insert(node_type&& __nh)
346       { return { _Base::insert(std::move(__nh)), this }; }
347 
348       iterator
349       insert(const_iterator __hint, node_type&& __nh)
350       {
351           __glibcxx_check_insert(__hint);
352           return { _Base::insert(__hint.base(), std::move(__nh)), this };
353       }
354 
355       using _Base::merge;
356 #endif // C++17
357 
358 #if __cplusplus >= 201103L
359       iterator
360       erase(const_iterator __position)
361       {
362           __glibcxx_check_erase(__position);
363           return { erase(__position.base()), this };
364       }
365 
366       _Base_iterator
367       erase(_Base_const_iterator __position)
368       {
369           __glibcxx_check_erase2(__position);
370           this->_M_invalidate_if(_Equal(__position));
371           return _Base::erase(__position);
372       }
373 
374       _GLIBCXX_ABI_TAG_CXX11
375       iterator
376       erase(iterator __position)
377       { return erase(const_iterator(__position)); }
378 #else
379       void
380       erase(iterator __position)
381       {
382           __glibcxx_check_erase(__position);
383           this->_M_invalidate_if(_Equal(__position.base()));
384           _Base::erase(__position.base());
385       }
386 #endif
387 
388       size_type
389       erase(const key_type& __x)
390       {
391           std::pair<_Base_iterator, _Base_iterator> __victims =
392             _Base::equal_range(__x);
393           size_type __count = 0;
394           _Base_iterator __victim = __victims.first;
395           while (__victim !=  __victims.second)
396             {
397               this->_M_invalidate_if(_Equal(__victim));
398               _Base::erase(__victim++);
399               ++__count;
400             }
401           return __count;
402       }
403 
404 #if __cplusplus >= 201103L
405       iterator
406       erase(const_iterator __first, const_iterator __last)
407       {
408           // _GLIBCXX_RESOLVE_LIB_DEFECTS
409           // 151. can't currently clear() empty container
410           __glibcxx_check_erase_range(__first, __last);
411           for (_Base_const_iterator __victim = __first.base();
412                __victim != __last.base(); ++__victim)
413             {
414               _GLIBCXX_DEBUG_VERIFY(__victim != _Base::cend(),
415                                           _M_message(__gnu_debug::__msg_valid_range)
416                                           ._M_iterator(__first, "first")
417                                           ._M_iterator(__last, "last"));
418               this->_M_invalidate_if(_Equal(__victim));
419             }
420 
421           return { _Base::erase(__first.base(), __last.base()), this };
422       }
423 #else
424       void
425       erase(iterator __first, iterator __last)
426       {
427           // _GLIBCXX_RESOLVE_LIB_DEFECTS
428           // 151. can't currently clear() empty container
429           __glibcxx_check_erase_range(__first, __last);
430           for (_Base_iterator __victim = __first.base();
431                __victim != __last.base(); ++__victim)
432             {
433               _GLIBCXX_DEBUG_VERIFY(__victim != _Base::end(),
434                                           _M_message(__gnu_debug::__msg_valid_range)
435                                           ._M_iterator(__first, "first")
436                                           ._M_iterator(__last, "last"));
437               this->_M_invalidate_if(_Equal(__victim));
438             }
439           _Base::erase(__first.base(), __last.base());
440       }
441 #endif
442 
443       void
444       swap(multimap& __x)
445       _GLIBCXX_NOEXCEPT_IF( noexcept(declval<_Base&>().swap(__x)) )
446       {
447           _Safe::_M_swap(__x);
448           _Base::swap(__x);
449       }
450 
451       void
452       clear() _GLIBCXX_NOEXCEPT
453       {
454           this->_M_invalidate_all();
455           _Base::clear();
456       }
457 
458       // observers:
459       using _Base::key_comp;
460       using _Base::value_comp;
461 
462       // 23.3.1.3 multimap operations:
463       iterator
464       find(const key_type& __x)
465       { return iterator(_Base::find(__x), this); }
466 
467 #if __cplusplus > 201103L
468       template<typename _Kt,
469                  typename _Req =
470                      typename __has_is_transparent<_Compare, _Kt>::type>
471           iterator
472           find(const _Kt& __x)
473           { return { _Base::find(__x), this }; }
474 #endif
475 
476       const_iterator
477       find(const key_type& __x) const
478       { return const_iterator(_Base::find(__x), this); }
479 
480 #if __cplusplus > 201103L
481       template<typename _Kt,
482                  typename _Req =
483                      typename __has_is_transparent<_Compare, _Kt>::type>
484           const_iterator
485           find(const _Kt& __x) const
486           { return { _Base::find(__x), this }; }
487 #endif
488 
489       using _Base::count;
490 
491       iterator
492       lower_bound(const key_type& __x)
493       { return iterator(_Base::lower_bound(__x), this); }
494 
495 #if __cplusplus > 201103L
496       template<typename _Kt,
497                  typename _Req =
498                      typename __has_is_transparent<_Compare, _Kt>::type>
499           iterator
500           lower_bound(const _Kt& __x)
501           { return { _Base::lower_bound(__x), this }; }
502 #endif
503 
504       const_iterator
505       lower_bound(const key_type& __x) const
506       { return const_iterator(_Base::lower_bound(__x), this); }
507 
508 #if __cplusplus > 201103L
509       template<typename _Kt,
510                  typename _Req =
511                      typename __has_is_transparent<_Compare, _Kt>::type>
512           const_iterator
513           lower_bound(const _Kt& __x) const
514           { return { _Base::lower_bound(__x), this }; }
515 #endif
516 
517       iterator
518       upper_bound(const key_type& __x)
519       { return iterator(_Base::upper_bound(__x), this); }
520 
521 #if __cplusplus > 201103L
522       template<typename _Kt,
523                  typename _Req =
524                      typename __has_is_transparent<_Compare, _Kt>::type>
525           iterator
526           upper_bound(const _Kt& __x)
527           { return { _Base::upper_bound(__x), this }; }
528 #endif
529 
530       const_iterator
531       upper_bound(const key_type& __x) const
532       { return const_iterator(_Base::upper_bound(__x), this); }
533 
534 #if __cplusplus > 201103L
535       template<typename _Kt,
536                  typename _Req =
537                      typename __has_is_transparent<_Compare, _Kt>::type>
538           const_iterator
539           upper_bound(const _Kt& __x) const
540           { return { _Base::upper_bound(__x), this }; }
541 #endif
542 
543       std::pair<iterator,iterator>
544       equal_range(const key_type& __x)
545       {
546           std::pair<_Base_iterator, _Base_iterator> __res =
547           _Base::equal_range(__x);
548           return std::make_pair(iterator(__res.first, this),
549                                     iterator(__res.second, this));
550       }
551 
552 #if __cplusplus > 201103L
553       template<typename _Kt,
554                  typename _Req =
555                      typename __has_is_transparent<_Compare, _Kt>::type>
556           std::pair<iterator, iterator>
557           equal_range(const _Kt& __x)
558           {
559             auto __res = _Base::equal_range(__x);
560             return { { __res.first, this }, { __res.second, this } };
561           }
562 #endif
563 
564       std::pair<const_iterator,const_iterator>
565       equal_range(const key_type& __x) const
566       {
567           std::pair<_Base_const_iterator, _Base_const_iterator> __res =
568             _Base::equal_range(__x);
569           return std::make_pair(const_iterator(__res.first, this),
570                                     const_iterator(__res.second, this));
571       }
572 
573 #if __cplusplus > 201103L
574       template<typename _Kt,
575                  typename _Req =
576                      typename __has_is_transparent<_Compare, _Kt>::type>
577           std::pair<const_iterator, const_iterator>
578           equal_range(const _Kt& __x) const
579           {
580             auto __res = _Base::equal_range(__x);
581             return { { __res.first, this }, { __res.second, this } };
582           }
583 #endif
584 
585       _Base&
586       _M_base() _GLIBCXX_NOEXCEPT { return *this; }
587 
588       const _Base&
589       _M_base() const _GLIBCXX_NOEXCEPT { return *this; }
590     };
591 
592 #if __cpp_deduction_guides >= 201606
593 
594   template<typename _InputIterator,
595              typename _Compare = less<__iter_key_t<_InputIterator>>,
596              typename _Allocator = allocator<__iter_to_alloc_t<_InputIterator>>,
597              typename = _RequireInputIter<_InputIterator>,
598              typename = _RequireNotAllocator<_Compare>,
599              typename = _RequireAllocator<_Allocator>>
600     multimap(_InputIterator, _InputIterator,
601                _Compare = _Compare(), _Allocator = _Allocator())
602     -> multimap<__iter_key_t<_InputIterator>, __iter_val_t<_InputIterator>,
603                     _Compare, _Allocator>;
604 
605   template<typename _Key, typename _Tp, typename _Compare = less<_Key>,
606              typename _Allocator = allocator<pair<const _Key, _Tp>>,
607              typename = _RequireNotAllocator<_Compare>,
608              typename = _RequireAllocator<_Allocator>>
609     multimap(initializer_list<pair<_Key, _Tp>>,
610                _Compare = _Compare(), _Allocator = _Allocator())
611     -> multimap<_Key, _Tp, _Compare, _Allocator>;
612 
613   template<typename _InputIterator, typename _Allocator,
614              typename = _RequireInputIter<_InputIterator>,
615              typename = _RequireAllocator<_Allocator>>
616     multimap(_InputIterator, _InputIterator, _Allocator)
617     -> multimap<__iter_key_t<_InputIterator>, __iter_val_t<_InputIterator>,
618     less<__iter_key_t<_InputIterator>>, _Allocator>;
619 
620   template<typename _Key, typename _Tp, typename _Allocator,
621              typename = _RequireAllocator<_Allocator>>
622     multimap(initializer_list<pair<_Key, _Tp>>, _Allocator)
623     -> multimap<_Key, _Tp, less<_Key>, _Allocator>;
624 
625 #endif
626 
627   template<typename _Key, typename _Tp,
628              typename _Compare, typename _Allocator>
629     inline bool
630     operator==(const multimap<_Key, _Tp, _Compare, _Allocator>& __lhs,
631                  const multimap<_Key, _Tp, _Compare, _Allocator>& __rhs)
632     { return __lhs._M_base() == __rhs._M_base(); }
633 
634 #if __cpp_lib_three_way_comparison
635   template<typename _Key, typename _Tp, typename _Compare, typename _Alloc>
636     inline __detail::__synth3way_t<pair<const _Key, _Tp>>
637     operator<=>(const multimap<_Key, _Tp, _Compare, _Alloc>& __lhs,
638                     const multimap<_Key, _Tp, _Compare, _Alloc>& __rhs)
639     { return __lhs._M_base() <=> __rhs._M_base(); }
640 #else
641   template<typename _Key, typename _Tp,
642              typename _Compare, typename _Allocator>
643     inline bool
644     operator!=(const multimap<_Key, _Tp, _Compare, _Allocator>& __lhs,
645                  const multimap<_Key, _Tp, _Compare, _Allocator>& __rhs)
646     { return __lhs._M_base() != __rhs._M_base(); }
647 
648   template<typename _Key, typename _Tp,
649              typename _Compare, typename _Allocator>
650     inline bool
651     operator<(const multimap<_Key, _Tp, _Compare, _Allocator>& __lhs,
652                 const multimap<_Key, _Tp, _Compare, _Allocator>& __rhs)
653     { return __lhs._M_base() < __rhs._M_base(); }
654 
655   template<typename _Key, typename _Tp,
656              typename _Compare, typename _Allocator>
657     inline bool
658     operator<=(const multimap<_Key, _Tp, _Compare, _Allocator>& __lhs,
659                  const multimap<_Key, _Tp, _Compare, _Allocator>& __rhs)
660     { return __lhs._M_base() <= __rhs._M_base(); }
661 
662   template<typename _Key, typename _Tp,
663              typename _Compare, typename _Allocator>
664     inline bool
665     operator>=(const multimap<_Key, _Tp, _Compare, _Allocator>& __lhs,
666                  const multimap<_Key, _Tp, _Compare, _Allocator>& __rhs)
667     { return __lhs._M_base() >= __rhs._M_base(); }
668 
669   template<typename _Key, typename _Tp,
670              typename _Compare, typename _Allocator>
671     inline bool
672     operator>(const multimap<_Key, _Tp, _Compare, _Allocator>& __lhs,
673                 const multimap<_Key, _Tp, _Compare, _Allocator>& __rhs)
674     { return __lhs._M_base() > __rhs._M_base(); }
675 #endif // three-way comparison
676 
677   template<typename _Key, typename _Tp,
678              typename _Compare, typename _Allocator>
679     inline void
680     swap(multimap<_Key, _Tp, _Compare, _Allocator>& __lhs,
681            multimap<_Key, _Tp, _Compare, _Allocator>& __rhs)
682     _GLIBCXX_NOEXCEPT_IF(noexcept(__lhs.swap(__rhs)))
683     { __lhs.swap(__rhs); }
684 
685 } // namespace __debug
686 } // namespace std
687 
688 #endif
689