|  | // Components for manipulating non-owning sequences of characters -*- C++ -*- | 
|  |  | 
|  |  | 
|  | #ifndef COMMON_GDB_STRING_VIEW_H | 
|  | #define COMMON_GDB_STRING_VIEW_H | 
|  |  | 
|  | // Note: This file has been stolen from the gcc repo | 
|  | // (libstdc++-v3/include/experimental/string_view) and has local modifications. | 
|  |  | 
|  | // Copyright (C) 2013-2023 Free Software Foundation, Inc. | 
|  | // | 
|  | // This file is part of the GNU ISO C++ Library.  This library 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, or (at your option) | 
|  | // any later version. | 
|  |  | 
|  | // This library 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. | 
|  |  | 
|  | // Under Section 7 of GPL version 3, you are granted additional | 
|  | // permissions described in the GCC Runtime Library Exception, version | 
|  | // 3.1, as published by the Free Software Foundation. | 
|  |  | 
|  | // You should have received a copy of the GNU General Public License and | 
|  | // a copy of the GCC Runtime Library Exception along with this program; | 
|  | // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see | 
|  | // <http://www.gnu.org/licenses/>. | 
|  |  | 
|  | // | 
|  | // N3762 basic_string_view library | 
|  | // | 
|  |  | 
|  |  | 
|  | #if __cplusplus >= 201703L | 
|  |  | 
|  | #include <string_view> | 
|  |  | 
|  | namespace gdb { | 
|  | using string_view = std::string_view; | 
|  | } /* namespace gdb */ | 
|  |  | 
|  | #else /* __cplusplus < 201703L */ | 
|  |  | 
|  | #include <string> | 
|  | #include <limits> | 
|  | #include "gdb_assert.h" | 
|  |  | 
|  | namespace gdb { | 
|  |  | 
|  | /** | 
|  | *  @class basic_string_view <experimental/string_view> | 
|  | *  @brief  A non-owning reference to a string. | 
|  | * | 
|  | *  @ingroup strings | 
|  | *  @ingroup sequences | 
|  | *  @ingroup experimental | 
|  | * | 
|  | *  @tparam _CharT  Type of character | 
|  | *  @tparam _Traits  Traits for character type, defaults to | 
|  | *                   char_traits<_CharT>. | 
|  | * | 
|  | *  A basic_string_view looks like this: | 
|  | * | 
|  | *  @code | 
|  | *    _CharT*    _M_str | 
|  | *    size_t     _M_len | 
|  | *  @endcode | 
|  | */ | 
|  | template<typename _CharT, typename _Traits = std::char_traits<_CharT>> | 
|  | class basic_string_view | 
|  | { | 
|  | public: | 
|  |  | 
|  | // types | 
|  | using traits_type = _Traits; | 
|  | using value_type = _CharT; | 
|  | using pointer = const _CharT*; | 
|  | using const_pointer = const _CharT*; | 
|  | using reference = const _CharT&; | 
|  | using const_reference = const _CharT&; | 
|  | using const_iterator = const _CharT*; | 
|  | using iterator = const_iterator; | 
|  | using const_reverse_iterator = std::reverse_iterator<const_iterator>; | 
|  | using reverse_iterator = const_reverse_iterator; | 
|  | using size_type = size_t; | 
|  | using difference_type = ptrdiff_t; | 
|  | static constexpr size_type npos = size_type(-1); | 
|  |  | 
|  | // [string.view.cons], construct/copy | 
|  |  | 
|  | constexpr | 
|  | basic_string_view() noexcept | 
|  | : _M_len{0}, _M_str{nullptr} | 
|  | { } | 
|  |  | 
|  | constexpr basic_string_view(const basic_string_view&) noexcept = default; | 
|  |  | 
|  | template<typename _Allocator> | 
|  | basic_string_view(const std::basic_string<_CharT, _Traits, | 
|  | _Allocator>& __str) noexcept | 
|  | : _M_len{__str.length()}, _M_str{__str.data()} | 
|  | { } | 
|  |  | 
|  | /*constexpr*/ basic_string_view(const _CharT* __str) | 
|  | : _M_len{__str == nullptr ? 0 : traits_type::length(__str)}, | 
|  | _M_str{__str} | 
|  | { } | 
|  |  | 
|  | constexpr basic_string_view(const _CharT* __str, size_type __len) | 
|  | : _M_len{__len}, | 
|  | _M_str{__str} | 
|  | { } | 
|  |  | 
|  | basic_string_view& | 
|  | operator=(const basic_string_view&) noexcept = default; | 
|  |  | 
|  | // [string.view.iterators], iterators | 
|  |  | 
|  | constexpr const_iterator | 
|  | begin() const noexcept | 
|  | { return this->_M_str; } | 
|  |  | 
|  | constexpr const_iterator | 
|  | end() const noexcept | 
|  | { return this->_M_str + this->_M_len; } | 
|  |  | 
|  | constexpr const_iterator | 
|  | cbegin() const noexcept | 
|  | { return this->_M_str; } | 
|  |  | 
|  | constexpr const_iterator | 
|  | cend() const noexcept | 
|  | { return this->_M_str + this->_M_len; } | 
|  |  | 
|  | const_reverse_iterator | 
|  | rbegin() const noexcept | 
|  | { return const_reverse_iterator(this->end()); } | 
|  |  | 
|  | const_reverse_iterator | 
|  | rend() const noexcept | 
|  | { return const_reverse_iterator(this->begin()); } | 
|  |  | 
|  | const_reverse_iterator | 
|  | crbegin() const noexcept | 
|  | { return const_reverse_iterator(this->end()); } | 
|  |  | 
|  | const_reverse_iterator | 
|  | crend() const noexcept | 
|  | { return const_reverse_iterator(this->begin()); } | 
|  |  | 
|  | // [string.view.capacity], capacity | 
|  |  | 
|  | constexpr size_type | 
|  | size() const noexcept | 
|  | { return this->_M_len; } | 
|  |  | 
|  | constexpr size_type | 
|  | length() const noexcept | 
|  | { return _M_len; } | 
|  |  | 
|  | constexpr size_type | 
|  | max_size() const noexcept | 
|  | { | 
|  | return (npos - sizeof(size_type) - sizeof(void*)) | 
|  | / sizeof(value_type) / 4; | 
|  | } | 
|  |  | 
|  | constexpr bool | 
|  | empty() const noexcept | 
|  | { return this->_M_len == 0; } | 
|  |  | 
|  | // [string.view.access], element access | 
|  |  | 
|  | constexpr const _CharT& | 
|  | operator[](size_type __pos) const | 
|  | { | 
|  | // TODO: Assert to restore in a way compatible with the constexpr. | 
|  | // __glibcxx_assert(__pos < this->_M_len); | 
|  | return *(this->_M_str + __pos); | 
|  | } | 
|  |  | 
|  | constexpr const _CharT& | 
|  | at(size_type __pos) const | 
|  | { | 
|  | return __pos < this->_M_len | 
|  | ? *(this->_M_str + __pos) | 
|  | : (error (_("basic_string_view::at: __pos " | 
|  | "(which is %zu) >= this->size() " | 
|  | "(which is %zu)"), | 
|  | __pos, this->size()), | 
|  | *this->_M_str); | 
|  | } | 
|  |  | 
|  | constexpr const _CharT& | 
|  | front() const | 
|  | { | 
|  | // TODO: Assert to restore in a way compatible with the constexpr. | 
|  | // __glibcxx_assert(this->_M_len > 0); | 
|  | return *this->_M_str; | 
|  | } | 
|  |  | 
|  | constexpr const _CharT& | 
|  | back() const | 
|  | { | 
|  | // TODO: Assert to restore in a way compatible with the constexpr. | 
|  | // __glibcxx_assert(this->_M_len > 0); | 
|  | return *(this->_M_str + this->_M_len - 1); | 
|  | } | 
|  |  | 
|  | constexpr const _CharT* | 
|  | data() const noexcept | 
|  | { return this->_M_str; } | 
|  |  | 
|  | // [string.view.modifiers], modifiers: | 
|  |  | 
|  | /*constexpr*/ void | 
|  | remove_prefix(size_type __n) | 
|  | { | 
|  | gdb_assert (this->_M_len >= __n); | 
|  | this->_M_str += __n; | 
|  | this->_M_len -= __n; | 
|  | } | 
|  |  | 
|  | /*constexpr*/ void | 
|  | remove_suffix(size_type __n) | 
|  | { this->_M_len -= __n; } | 
|  |  | 
|  | /*constexpr*/ void | 
|  | swap(basic_string_view& __sv) noexcept | 
|  | { | 
|  | auto __tmp = *this; | 
|  | *this = __sv; | 
|  | __sv = __tmp; | 
|  | } | 
|  |  | 
|  |  | 
|  | // [string.view.ops], string operations: | 
|  |  | 
|  | template<typename _Allocator> | 
|  | explicit operator std::basic_string<_CharT, _Traits, _Allocator>() const | 
|  | { | 
|  | return { this->_M_str, this->_M_len }; | 
|  | } | 
|  |  | 
|  | size_type | 
|  | copy(_CharT* __str, size_type __n, size_type __pos = 0) const | 
|  | { | 
|  | gdb_assert (__str != nullptr || __n == 0); | 
|  | if (__pos > this->_M_len) | 
|  | error (_("basic_string_view::copy: __pos " | 
|  | "(which is %zu) > this->size() " | 
|  | "(which is %zu)"), | 
|  | __pos, this->size()); | 
|  | size_type __rlen{std::min(__n, size_type{this->_M_len  - __pos})}; | 
|  | for (auto __begin = this->_M_str + __pos, | 
|  | __end = __begin + __rlen; __begin != __end;) | 
|  | *__str++ = *__begin++; | 
|  | return __rlen; | 
|  | } | 
|  |  | 
|  |  | 
|  | // [string.view.ops], string operations: | 
|  |  | 
|  | /*constexpr*/ basic_string_view | 
|  | substr(size_type __pos, size_type __n=npos) const | 
|  | { | 
|  | return __pos <= this->_M_len | 
|  | ? basic_string_view{this->_M_str + __pos, | 
|  | std::min(__n, size_type{this->_M_len  - __pos})} | 
|  | : (error (_("basic_string_view::substr: __pos " | 
|  | "(which is %zu) > this->size() " | 
|  | "(which is %zu)"), | 
|  | __pos, this->size()), basic_string_view{}); | 
|  | } | 
|  |  | 
|  | /*constexpr*/ int | 
|  | compare(basic_string_view __str) const noexcept | 
|  | { | 
|  | int __ret = traits_type::compare(this->_M_str, __str._M_str, | 
|  | std::min(this->_M_len, __str._M_len)); | 
|  | if (__ret == 0) | 
|  | __ret = _S_compare(this->_M_len, __str._M_len); | 
|  | return __ret; | 
|  | } | 
|  |  | 
|  | /*constexpr*/ int | 
|  | compare(size_type __pos1, size_type __n1, basic_string_view __str) const | 
|  | { return this->substr(__pos1, __n1).compare(__str); } | 
|  |  | 
|  | /*constexpr*/ int | 
|  | compare(size_type __pos1, size_type __n1, | 
|  | basic_string_view __str, size_type __pos2, size_type __n2) const | 
|  | { return this->substr(__pos1, __n1).compare(__str.substr(__pos2, __n2)); } | 
|  |  | 
|  | /*constexpr*/ int | 
|  | compare(const _CharT* __str) const noexcept | 
|  | { return this->compare(basic_string_view{__str}); } | 
|  |  | 
|  | /*constexpr*/ int | 
|  | compare(size_type __pos1, size_type __n1, const _CharT* __str) const | 
|  | { return this->substr(__pos1, __n1).compare(basic_string_view{__str}); } | 
|  |  | 
|  | /*constexpr*/ int | 
|  | compare(size_type __pos1, size_type __n1, | 
|  | const _CharT* __str, size_type __n2) const | 
|  | { | 
|  | return this->substr(__pos1, __n1) | 
|  | .compare(basic_string_view(__str, __n2)); | 
|  | } | 
|  |  | 
|  | /*constexpr*/ size_type | 
|  | find(basic_string_view __str, size_type __pos = 0) const noexcept | 
|  | { return this->find(__str._M_str, __pos, __str._M_len); } | 
|  |  | 
|  | /*constexpr*/ size_type | 
|  | find(_CharT __c, size_type __pos=0) const noexcept; | 
|  |  | 
|  | /*constexpr*/ size_type | 
|  | find(const _CharT* __str, size_type __pos, size_type __n) const noexcept; | 
|  |  | 
|  | /*constexpr*/ size_type | 
|  | find(const _CharT* __str, size_type __pos=0) const noexcept | 
|  | { return this->find(__str, __pos, traits_type::length(__str)); } | 
|  |  | 
|  | /*constexpr*/ size_type | 
|  | rfind(basic_string_view __str, size_type __pos = npos) const noexcept | 
|  | { return this->rfind(__str._M_str, __pos, __str._M_len); } | 
|  |  | 
|  | /*constexpr*/ size_type | 
|  | rfind(_CharT __c, size_type __pos = npos) const noexcept; | 
|  |  | 
|  | /*constexpr*/ size_type | 
|  | rfind(const _CharT* __str, size_type __pos, size_type __n) const noexcept; | 
|  |  | 
|  | /*constexpr*/ size_type | 
|  | rfind(const _CharT* __str, size_type __pos = npos) const noexcept | 
|  | { return this->rfind(__str, __pos, traits_type::length(__str)); } | 
|  |  | 
|  | /*constexpr*/ size_type | 
|  | find_first_of(basic_string_view __str, size_type __pos = 0) const noexcept | 
|  | { return this->find_first_of(__str._M_str, __pos, __str._M_len); } | 
|  |  | 
|  | /*constexpr*/ size_type | 
|  | find_first_of(_CharT __c, size_type __pos = 0) const noexcept | 
|  | { return this->find(__c, __pos); } | 
|  |  | 
|  | /*constexpr*/ size_type | 
|  | find_first_of(const _CharT* __str, size_type __pos, size_type __n) const; | 
|  |  | 
|  | /*constexpr*/ size_type | 
|  | find_first_of(const _CharT* __str, size_type __pos = 0) const noexcept | 
|  | { return this->find_first_of(__str, __pos, traits_type::length(__str)); } | 
|  |  | 
|  | /*constexpr*/ size_type | 
|  | find_last_of(basic_string_view __str, | 
|  | size_type __pos = npos) const noexcept | 
|  | { return this->find_last_of(__str._M_str, __pos, __str._M_len); } | 
|  |  | 
|  | size_type | 
|  | find_last_of(_CharT __c, size_type __pos=npos) const noexcept | 
|  | { return this->rfind(__c, __pos); } | 
|  |  | 
|  | /*constexpr*/ size_type | 
|  | find_last_of(const _CharT* __str, size_type __pos, size_type __n) const; | 
|  |  | 
|  | /*constexpr*/ size_type | 
|  | find_last_of(const _CharT* __str, size_type __pos = npos) const noexcept | 
|  | { return this->find_last_of(__str, __pos, traits_type::length(__str)); } | 
|  |  | 
|  | /*constexpr*/ size_type | 
|  | find_first_not_of(basic_string_view __str, | 
|  | size_type __pos = 0) const noexcept | 
|  | { return this->find_first_not_of(__str._M_str, __pos, __str._M_len); } | 
|  |  | 
|  | /*constexpr*/ size_type | 
|  | find_first_not_of(_CharT __c, size_type __pos = 0) const noexcept; | 
|  |  | 
|  | /*constexpr*/ size_type | 
|  | find_first_not_of(const _CharT* __str, | 
|  | size_type __pos, size_type __n) const; | 
|  |  | 
|  | /*constexpr*/ size_type | 
|  | find_first_not_of(const _CharT* __str, size_type __pos = 0) const noexcept | 
|  | { | 
|  | return this->find_first_not_of(__str, __pos, | 
|  | traits_type::length(__str)); | 
|  | } | 
|  |  | 
|  | /*constexpr*/ size_type | 
|  | find_last_not_of(basic_string_view __str, | 
|  | size_type __pos = npos) const noexcept | 
|  | { return this->find_last_not_of(__str._M_str, __pos, __str._M_len); } | 
|  |  | 
|  | /*constexpr*/ size_type | 
|  | find_last_not_of(_CharT __c, size_type __pos = npos) const noexcept; | 
|  |  | 
|  | /*constexpr*/ size_type | 
|  | find_last_not_of(const _CharT* __str, | 
|  | size_type __pos, size_type __n) const; | 
|  |  | 
|  | /*constexpr*/ size_type | 
|  | find_last_not_of(const _CharT* __str, | 
|  | size_type __pos = npos) const noexcept | 
|  | { | 
|  | return this->find_last_not_of(__str, __pos, | 
|  | traits_type::length(__str)); | 
|  | } | 
|  |  | 
|  | private: | 
|  |  | 
|  | static constexpr int | 
|  | _S_compare(size_type __n1, size_type __n2) noexcept | 
|  | { | 
|  | return difference_type(__n1 - __n2) > std::numeric_limits<int>::max() | 
|  | ? std::numeric_limits<int>::max() | 
|  | : difference_type(__n1 - __n2) < std::numeric_limits<int>::min() | 
|  | ? std::numeric_limits<int>::min() | 
|  | : static_cast<int>(difference_type(__n1 - __n2)); | 
|  | } | 
|  |  | 
|  | size_t	    _M_len; | 
|  | const _CharT* _M_str; | 
|  | }; | 
|  |  | 
|  | // [string.view.comparison], non-member basic_string_view comparison functions | 
|  |  | 
|  | namespace __detail | 
|  | { | 
|  | // Identity transform to create a non-deduced context, so that only one | 
|  | // argument participates in template argument deduction and the other | 
|  | // argument gets implicitly converted to the deduced type. See n3766.html. | 
|  | template<typename _Tp> | 
|  | using __idt = typename std::common_type<_Tp>::type; | 
|  | } | 
|  |  | 
|  | template<typename _CharT, typename _Traits> | 
|  | /*constexpr*/ bool | 
|  | operator==(basic_string_view<_CharT, _Traits> __x, | 
|  | basic_string_view<_CharT, _Traits> __y) noexcept | 
|  | { return __x.size() == __y.size() && __x.compare(__y) == 0; } | 
|  |  | 
|  | template<typename _CharT, typename _Traits> | 
|  | /*constexpr*/ bool | 
|  | operator==(basic_string_view<_CharT, _Traits> __x, | 
|  | __detail::__idt<basic_string_view<_CharT, _Traits>> __y) noexcept | 
|  | { return __x.size() == __y.size() && __x.compare(__y) == 0; } | 
|  |  | 
|  | template<typename _CharT, typename _Traits> | 
|  | /*constexpr*/ bool | 
|  | operator==(__detail::__idt<basic_string_view<_CharT, _Traits>> __x, | 
|  | basic_string_view<_CharT, _Traits> __y) noexcept | 
|  | { return __x.size() == __y.size() && __x.compare(__y) == 0; } | 
|  |  | 
|  | template<typename _CharT, typename _Traits> | 
|  | /*constexpr*/ bool | 
|  | operator!=(basic_string_view<_CharT, _Traits> __x, | 
|  | basic_string_view<_CharT, _Traits> __y) noexcept | 
|  | { return !(__x == __y); } | 
|  |  | 
|  | template<typename _CharT, typename _Traits> | 
|  | /*constexpr*/ bool | 
|  | operator!=(basic_string_view<_CharT, _Traits> __x, | 
|  | __detail::__idt<basic_string_view<_CharT, _Traits>> __y) noexcept | 
|  | { return !(__x == __y); } | 
|  |  | 
|  | template<typename _CharT, typename _Traits> | 
|  | /*constexpr*/ bool | 
|  | operator!=(__detail::__idt<basic_string_view<_CharT, _Traits>> __x, | 
|  | basic_string_view<_CharT, _Traits> __y) noexcept | 
|  | { return !(__x == __y); } | 
|  |  | 
|  | template<typename _CharT, typename _Traits> | 
|  | /*constexpr*/ bool | 
|  | operator< (basic_string_view<_CharT, _Traits> __x, | 
|  | basic_string_view<_CharT, _Traits> __y) noexcept | 
|  | { return __x.compare(__y) < 0; } | 
|  |  | 
|  | template<typename _CharT, typename _Traits> | 
|  | /*constexpr*/ bool | 
|  | operator< (basic_string_view<_CharT, _Traits> __x, | 
|  | __detail::__idt<basic_string_view<_CharT, _Traits>> __y) noexcept | 
|  | { return __x.compare(__y) < 0; } | 
|  |  | 
|  | template<typename _CharT, typename _Traits> | 
|  | /*constexpr*/ bool | 
|  | operator< (__detail::__idt<basic_string_view<_CharT, _Traits>> __x, | 
|  | basic_string_view<_CharT, _Traits> __y) noexcept | 
|  | { return __x.compare(__y) < 0; } | 
|  |  | 
|  | template<typename _CharT, typename _Traits> | 
|  | /*constexpr*/ bool | 
|  | operator> (basic_string_view<_CharT, _Traits> __x, | 
|  | basic_string_view<_CharT, _Traits> __y) noexcept | 
|  | { return __x.compare(__y) > 0; } | 
|  |  | 
|  | template<typename _CharT, typename _Traits> | 
|  | /*constexpr*/ bool | 
|  | operator> (basic_string_view<_CharT, _Traits> __x, | 
|  | __detail::__idt<basic_string_view<_CharT, _Traits>> __y) noexcept | 
|  | { return __x.compare(__y) > 0; } | 
|  |  | 
|  | template<typename _CharT, typename _Traits> | 
|  | /*constexpr*/ bool | 
|  | operator> (__detail::__idt<basic_string_view<_CharT, _Traits>> __x, | 
|  | basic_string_view<_CharT, _Traits> __y) noexcept | 
|  | { return __x.compare(__y) > 0; } | 
|  |  | 
|  | template<typename _CharT, typename _Traits> | 
|  | /*constexpr*/ bool | 
|  | operator<=(basic_string_view<_CharT, _Traits> __x, | 
|  | basic_string_view<_CharT, _Traits> __y) noexcept | 
|  | { return __x.compare(__y) <= 0; } | 
|  |  | 
|  | template<typename _CharT, typename _Traits> | 
|  | /*constexpr*/ bool | 
|  | operator<=(basic_string_view<_CharT, _Traits> __x, | 
|  | __detail::__idt<basic_string_view<_CharT, _Traits>> __y) noexcept | 
|  | { return __x.compare(__y) <= 0; } | 
|  |  | 
|  | template<typename _CharT, typename _Traits> | 
|  | /*constexpr*/ bool | 
|  | operator<=(__detail::__idt<basic_string_view<_CharT, _Traits>> __x, | 
|  | basic_string_view<_CharT, _Traits> __y) noexcept | 
|  | { return __x.compare(__y) <= 0; } | 
|  |  | 
|  | template<typename _CharT, typename _Traits> | 
|  | /*constexpr*/ bool | 
|  | operator>=(basic_string_view<_CharT, _Traits> __x, | 
|  | basic_string_view<_CharT, _Traits> __y) noexcept | 
|  | { return __x.compare(__y) >= 0; } | 
|  |  | 
|  | template<typename _CharT, typename _Traits> | 
|  | /*constexpr*/ bool | 
|  | operator>=(basic_string_view<_CharT, _Traits> __x, | 
|  | __detail::__idt<basic_string_view<_CharT, _Traits>> __y) noexcept | 
|  | { return __x.compare(__y) >= 0; } | 
|  |  | 
|  | template<typename _CharT, typename _Traits> | 
|  | /*constexpr*/ bool | 
|  | operator>=(__detail::__idt<basic_string_view<_CharT, _Traits>> __x, | 
|  | basic_string_view<_CharT, _Traits> __y) noexcept | 
|  | { return __x.compare(__y) >= 0; } | 
|  |  | 
|  | // basic_string_view typedef names | 
|  |  | 
|  | using string_view = basic_string_view<char>; | 
|  | } /* namespace gdb */ | 
|  |  | 
|  | #include "gdb_string_view.tcc" | 
|  |  | 
|  | #endif // __cplusplus < 201703L | 
|  |  | 
|  | namespace gdb { | 
|  |  | 
|  | static inline std::string | 
|  | to_string(const gdb::string_view &view) | 
|  | { | 
|  | return { view.data (), view.size () }; | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | #endif /* COMMON_GDB_STRING_VIEW_H */ |