2 // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 // Official repository: https://github.com/boostorg/beast
10 #ifndef BOOST_BEAST_HTTP_IMPL_FIELDS_IPP
11 #define BOOST_BEAST_HTTP_IMPL_FIELDS_IPP
13 #include <boost/beast/core/buffers_cat.hpp>
14 #include <boost/beast/core/string.hpp>
15 #include <boost/beast/core/static_string.hpp>
16 #include <boost/beast/core/detail/buffers_ref.hpp>
17 #include <boost/beast/http/verb.hpp>
18 #include <boost/beast/http/rfc7230.hpp>
19 #include <boost/beast/http/status.hpp>
20 #include <boost/beast/http/chunk_encode.hpp>
21 #include <boost/throw_exception.hpp>
25 #if defined(BOOST_LIBSTDCXX_VERSION) && BOOST_LIBSTDCXX_VERSION < 60000
26 // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437
27 #ifndef BOOST_BEAST_HTTP_NO_FIELDS_BASIC_STRING_ALLOCATOR
28 #define BOOST_BEAST_HTTP_NO_FIELDS_BASIC_STRING_ALLOCATOR
36 template<class Allocator>
37 class basic_fields<Allocator>::writer
40 using iter_type = typename list_t::const_iterator;
46 using value_type = boost::asio::const_buffer;
47 using pointer = value_type const*;
48 using reference = value_type const;
49 using difference_type = std::ptrdiff_t;
50 using iterator_category =
51 std::bidirectional_iterator_tag;
53 field_iterator() = default;
54 field_iterator(field_iterator&& other) = default;
55 field_iterator(field_iterator const& other) = default;
56 field_iterator& operator=(field_iterator&& other) = default;
57 field_iterator& operator=(field_iterator const& other) = default;
60 field_iterator(iter_type it)
66 operator==(field_iterator const& other) const
68 return it_ == other.it_;
72 operator!=(field_iterator const& other) const
74 return !(*this == other);
116 field_iterator first_;
117 field_iterator last_;
120 using const_iterator =
124 typename const_iterator::value_type;
126 field_range(iter_type first, iter_type last)
145 using view_type = buffers_cat_view<
146 boost::asio::const_buffer,
147 boost::asio::const_buffer,
148 boost::asio::const_buffer,
152 basic_fields const& f_;
153 boost::optional<view_type> view_;
157 using const_buffers_type =
158 beast::detail::buffers_ref<view_type>;
160 writer(basic_fields const& f,
161 unsigned version, verb v);
163 writer(basic_fields const& f,
164 unsigned version, unsigned code);
166 writer(basic_fields const& f);
171 return const_buffers_type(*view_);
175 template<class Allocator>
176 basic_fields<Allocator>::writer::
177 writer(basic_fields const& f)
181 boost::asio::const_buffer{nullptr, 0},
182 boost::asio::const_buffer{nullptr, 0},
183 boost::asio::const_buffer{nullptr, 0},
184 field_range(f_.list_.begin(), f_.list_.end()),
188 template<class Allocator>
189 basic_fields<Allocator>::writer::
190 writer(basic_fields const& f,
191 unsigned version, verb v)
198 " HTTP/X.Y\r\n" (11 chars)
201 if(v == verb::unknown)
202 sv = f_.get_method_impl();
206 // target_or_reason_ has a leading SP
214 buf_[6] = '0' + static_cast<char>(version / 10);
216 buf_[8] = '0' + static_cast<char>(version % 10);
221 boost::asio::const_buffer{sv.data(), sv.size()},
222 boost::asio::const_buffer{
223 f_.target_or_reason_.data(),
224 f_.target_or_reason_.size()},
225 boost::asio::const_buffer{buf_, 11},
226 field_range(f_.list_.begin(), f_.list_.end()),
230 template<class Allocator>
231 basic_fields<Allocator>::writer::
232 writer(basic_fields const& f,
233 unsigned version, unsigned code)
238 "HTTP/X.Y ### " (13 chars)
247 buf_[5] = '0' + static_cast<char>(version / 10);
249 buf_[7] = '0' + static_cast<char>(version % 10);
251 buf_[9] = '0' + static_cast<char>(code / 100);
252 buf_[10]= '0' + static_cast<char>((code / 10) % 10);
253 buf_[11]= '0' + static_cast<char>(code % 10);
257 if(! f_.target_or_reason_.empty())
258 sv = f_.target_or_reason_;
260 sv = obsolete_reason(static_cast<status>(code));
263 boost::asio::const_buffer{buf_, 13},
264 boost::asio::const_buffer{sv.data(), sv.size()},
265 boost::asio::const_buffer{"\r\n", 2},
266 field_range(f_.list_.begin(), f_.list_.end()),
270 //------------------------------------------------------------------------------
272 template<class Allocator>
273 basic_fields<Allocator>::
275 value_type(field name,
276 string_view sname, string_view value)
277 : off_(static_cast<off_t>(sname.size() + 2))
278 , len_(static_cast<off_t>(value.size()))
281 //BOOST_ASSERT(name == field::unknown ||
282 // iequals(sname, to_string(name)));
283 char* p = reinterpret_cast<char*>(this + 1);
286 p[off_ + len_] = '\r';
287 p[off_ + len_ + 1] = '\n';
288 std::memcpy(p, sname.data(), sname.size());
289 std::memcpy(p + off_, value.data(), value.size());
292 template<class Allocator>
295 basic_fields<Allocator>::
302 template<class Allocator>
305 basic_fields<Allocator>::
309 return {reinterpret_cast<
310 char const*>(this + 1),
311 static_cast<std::size_t>(off_ - 2)};
314 template<class Allocator>
317 basic_fields<Allocator>::
321 return {reinterpret_cast<
322 char const*>(this + 1) + off_,
323 static_cast<std::size_t>(len_)};
326 template<class Allocator>
328 boost::asio::const_buffer
329 basic_fields<Allocator>::
333 return boost::asio::const_buffer{
334 reinterpret_cast<char const*>(this + 1),
335 static_cast<std::size_t>(off_) + len_ + 2};
338 //------------------------------------------------------------------------------
340 template<class Allocator>
341 basic_fields<Allocator>::
345 realloc_string(method_, {});
347 target_or_reason_, {});
350 template<class Allocator>
351 basic_fields<Allocator>::
352 basic_fields(Allocator const& alloc)
357 template<class Allocator>
358 basic_fields<Allocator>::
359 basic_fields(basic_fields&& other)
360 : alloc_(std::move(other.alloc_))
361 , set_(std::move(other.set_))
362 , list_(std::move(other.list_))
363 , method_(other.method_)
364 , target_or_reason_(other.target_or_reason_)
366 other.method_.clear();
367 other.target_or_reason_.clear();
370 template<class Allocator>
371 basic_fields<Allocator>::
372 basic_fields(basic_fields&& other, Allocator const& alloc)
375 if(alloc_ != other.alloc_)
382 set_ = std::move(other.set_);
383 list_ = std::move(other.list_);
384 method_ = other.method_;
385 target_or_reason_ = other.target_or_reason_;
389 template<class Allocator>
390 basic_fields<Allocator>::
391 basic_fields(basic_fields const& other)
392 : alloc_(alloc_traits::
393 select_on_container_copy_construction(other.alloc_))
398 template<class Allocator>
399 basic_fields<Allocator>::
400 basic_fields(basic_fields const& other,
401 Allocator const& alloc)
407 template<class Allocator>
408 template<class OtherAlloc>
409 basic_fields<Allocator>::
410 basic_fields(basic_fields<OtherAlloc> const& other)
415 template<class Allocator>
416 template<class OtherAlloc>
417 basic_fields<Allocator>::
418 basic_fields(basic_fields<OtherAlloc> const& other,
419 Allocator const& alloc)
425 template<class Allocator>
427 basic_fields<Allocator>::
428 operator=(basic_fields&& other) ->
433 move_assign(other, std::integral_constant<bool,
434 alloc_traits:: propagate_on_container_move_assignment::value>{});
438 template<class Allocator>
440 basic_fields<Allocator>::
441 operator=(basic_fields const& other) ->
444 copy_assign(other, std::integral_constant<bool,
445 alloc_traits::propagate_on_container_copy_assignment::value>{});
449 template<class Allocator>
450 template<class OtherAlloc>
452 basic_fields<Allocator>::
453 operator=(basic_fields<OtherAlloc> const& other) ->
461 //------------------------------------------------------------------------------
465 //------------------------------------------------------------------------------
467 template<class Allocator>
469 basic_fields<Allocator>::
472 BOOST_ASSERT(name != field::unknown);
473 auto const it = find(name);
475 BOOST_THROW_EXCEPTION(std::out_of_range{
480 template<class Allocator>
482 basic_fields<Allocator>::
483 at(string_view name) const
485 auto const it = find(name);
487 BOOST_THROW_EXCEPTION(std::out_of_range{
492 template<class Allocator>
494 basic_fields<Allocator>::
495 operator[](field name) const
497 BOOST_ASSERT(name != field::unknown);
498 auto const it = find(name);
504 template<class Allocator>
506 basic_fields<Allocator>::
507 operator[](string_view name) const
509 auto const it = find(name);
515 //------------------------------------------------------------------------------
519 //------------------------------------------------------------------------------
521 template<class Allocator>
523 basic_fields<Allocator>::
531 template<class Allocator>
534 basic_fields<Allocator>::
535 insert(field name, string_param const& value)
537 BOOST_ASSERT(name != field::unknown);
538 insert(name, to_string(name), value);
541 template<class Allocator>
543 basic_fields<Allocator>::
544 insert(string_view sname, string_param const& value)
547 string_to_field(sname);
548 insert(name, sname, value);
551 template<class Allocator>
553 basic_fields<Allocator>::
555 string_view sname, string_param const& value)
557 auto& e = new_element(name, sname,
558 static_cast<string_view>(value));
560 set_.upper_bound(sname, key_compare{});
561 if(before == set_.begin())
563 BOOST_ASSERT(count(sname) == 0);
564 set_.insert_before(before, e);
568 auto const last = std::prev(before);
569 // VFALCO is it worth comparing `field name` first?
570 if(! iequals(sname, last->name_string()))
572 BOOST_ASSERT(count(sname) == 0);
573 set_.insert_before(before, e);
577 // keep duplicate fields together in the list
578 set_.insert_before(before, e);
579 list_.insert(++list_.iterator_to(*last), e);
582 template<class Allocator>
584 basic_fields<Allocator>::
585 set(field name, string_param const& value)
587 BOOST_ASSERT(name != field::unknown);
588 set_element(new_element(name, to_string(name),
589 static_cast<string_view>(value)));
592 template<class Allocator>
594 basic_fields<Allocator>::
595 set(string_view sname, string_param const& value)
597 set_element(new_element(
598 string_to_field(sname), sname,
599 static_cast<string_view>(value)));
602 template<class Allocator>
604 basic_fields<Allocator>::
605 erase(const_iterator pos) ->
608 auto next = pos.iter();
616 template<class Allocator>
618 basic_fields<Allocator>::
621 BOOST_ASSERT(name != field::unknown);
622 return erase(to_string(name));
625 template<class Allocator>
627 basic_fields<Allocator>::
628 erase(string_view name)
631 set_.erase_and_dispose(name, key_compare{},
635 list_.erase(list_.iterator_to(*e));
641 template<class Allocator>
643 basic_fields<Allocator>::
644 swap(basic_fields<Allocator>& other)
646 swap(other, std::integral_constant<bool,
647 alloc_traits::propagate_on_container_swap::value>{});
650 template<class Allocator>
653 basic_fields<Allocator>& lhs,
654 basic_fields<Allocator>& rhs)
659 //------------------------------------------------------------------------------
663 //------------------------------------------------------------------------------
665 template<class Allocator>
668 basic_fields<Allocator>::
669 count(field name) const
671 BOOST_ASSERT(name != field::unknown);
672 return count(to_string(name));
675 template<class Allocator>
677 basic_fields<Allocator>::
678 count(string_view name) const
680 return set_.count(name, key_compare{});
683 template<class Allocator>
686 basic_fields<Allocator>::
687 find(field name) const ->
690 BOOST_ASSERT(name != field::unknown);
691 return find(to_string(name));
694 template<class Allocator>
696 basic_fields<Allocator>::
697 find(string_view name) const ->
700 auto const it = set_.find(
701 name, key_compare{});
704 return list_.iterator_to(*it);
707 template<class Allocator>
710 basic_fields<Allocator>::
711 equal_range(field name) const ->
712 std::pair<const_iterator, const_iterator>
714 BOOST_ASSERT(name != field::unknown);
715 return equal_range(to_string(name));
718 template<class Allocator>
720 basic_fields<Allocator>::
721 equal_range(string_view name) const ->
722 std::pair<const_iterator, const_iterator>
725 set_.equal_range(name, key_compare{});
726 if(result.first == result.second)
727 return {list_.end(), list_.end()};
729 list_.iterator_to(*result.first),
730 ++list_.iterator_to(*(--result.second))};
733 //------------------------------------------------------------------------------
737 // Filter a token list
739 template<class String, class Pred>
746 token_list te{value};
747 auto it = te.begin();
748 auto last = te.end();
754 s.append(it->data(), it->size());
760 s.append(it->data(), it->size());
765 // Filter the last item in a token list
766 template<class String, class Pred>
768 filter_token_list_last(
773 token_list te{value};
774 if(te.begin() != te.end())
776 auto it = te.begin();
777 auto next = std::next(it);
781 s.append(it->data(), it->size());
784 s.append(it->data(), it->size());
788 next = std::next(it);
794 s.append(it->data(), it->size());
799 s.append(it->data(), it->size());
804 template<class String>
807 String& s, string_view value,
808 unsigned version, bool keep_alive)
815 filter_token_list(s, value,
818 return iequals(s, "close");
822 s.append("keep-alive");
823 else if(! token_list{value}.exists("keep-alive"))
824 s.append(", keep-alive");
828 // remove close and keep-alive
829 filter_token_list(s, value,
833 iequals(s, "close") ||
834 iequals(s, "keep-alive");
842 // remove close and keep-alive
843 filter_token_list(s, value,
847 iequals(s, "close") ||
848 iequals(s, "keep-alive");
854 filter_token_list(s, value,
857 return iequals(s, "keep-alive");
862 else if(! token_list{value}.exists("close"))
870 //------------------------------------------------------------------------------
874 template<class Allocator>
877 basic_fields<Allocator>::
878 get_method_impl() const
883 template<class Allocator>
886 basic_fields<Allocator>::
887 get_target_impl() const
889 if(target_or_reason_.empty())
890 return target_or_reason_;
892 target_or_reason_.data() + 1,
893 target_or_reason_.size() - 1};
896 template<class Allocator>
899 basic_fields<Allocator>::
900 get_reason_impl() const
902 return target_or_reason_;
905 template<class Allocator>
907 basic_fields<Allocator>::
908 get_chunked_impl() const
910 auto const te = token_list{
911 (*this)[field::transfer_encoding]};
912 for(auto it = te.begin(); it != te.end();)
914 auto const next = std::next(it);
916 return iequals(*it, "chunked");
922 template<class Allocator>
924 basic_fields<Allocator>::
925 get_keep_alive_impl(unsigned version) const
927 auto const it = find(field::connection);
933 it->value()}.exists("keep-alive");
938 it->value()}.exists("close");
941 template<class Allocator>
943 basic_fields<Allocator>::
944 has_content_length_impl() const
946 return count(field::content_length) > 0;
949 template<class Allocator>
952 basic_fields<Allocator>::
953 set_method_impl(string_view s)
955 realloc_string(method_, s);
958 template<class Allocator>
961 basic_fields<Allocator>::
962 set_target_impl(string_view s)
965 target_or_reason_, s);
968 template<class Allocator>
971 basic_fields<Allocator>::
972 set_reason_impl(string_view s)
975 target_or_reason_, s);
978 template<class Allocator>
980 basic_fields<Allocator>::
981 set_chunked_impl(bool value)
983 auto it = find(field::transfer_encoding);
989 set(field::transfer_encoding, "chunked");
992 auto const te = token_list{it->value()};
993 for(auto itt = te.begin();;)
995 auto const next = std::next(itt);
998 if(iequals(*itt, "chunked"))
999 return; // already set
1004 static_string<max_static_buffer> buf;
1005 if(it->value().size() <= buf.size() + 9)
1007 buf.append(it->value().data(), it->value().size());
1008 buf.append(", chunked", 9);
1009 set(field::transfer_encoding, buf);
1013 #ifdef BOOST_BEAST_HTTP_NO_FIELDS_BASIC_STRING_ALLOCATOR
1014 // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437
1018 typename beast::detail::allocator_traits<
1019 Allocator>::template rebind_alloc<char>;
1022 std::char_traits<char>,
1023 rebind_type> s{rebind_type{alloc_}};
1025 s.reserve(it->value().size() + 9);
1026 s.append(it->value().data(), it->value().size());
1027 s.append(", chunked", 9);
1028 set(field::transfer_encoding, s);
1037 static_string<max_static_buffer> buf;
1038 detail::filter_token_list_last(buf, it->value(),
1041 return iequals(s, "chunked");
1044 set(field::transfer_encoding, buf);
1046 erase(field::transfer_encoding);
1048 catch(std::length_error const&)
1050 #ifdef BOOST_BEAST_HTTP_NO_FIELDS_BASIC_STRING_ALLOCATOR
1051 // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437
1055 typename beast::detail::allocator_traits<
1056 Allocator>::template rebind_alloc<char>;
1059 std::char_traits<char>,
1060 rebind_type> s{rebind_type{alloc_}};
1062 s.reserve(it->value().size());
1063 detail::filter_token_list_last(s, it->value(),
1066 return iequals(s, "chunked");
1069 set(field::transfer_encoding, s);
1071 erase(field::transfer_encoding);
1075 template<class Allocator>
1077 basic_fields<Allocator>::
1078 set_content_length_impl(
1079 boost::optional<std::uint64_t> const& value)
1082 erase(field::content_length);
1084 set(field::content_length, *value);
1087 template<class Allocator>
1089 basic_fields<Allocator>::
1090 set_keep_alive_impl(
1091 unsigned version, bool keep_alive)
1093 // VFALCO What about Proxy-Connection ?
1094 auto const value = (*this)[field::connection];
1097 static_string<max_static_buffer> buf;
1098 detail::keep_alive_impl(
1099 buf, value, version, keep_alive);
1101 erase(field::connection);
1103 set(field::connection, buf);
1105 catch(std::length_error const&)
1107 #ifdef BOOST_BEAST_HTTP_NO_FIELDS_BASIC_STRING_ALLOCATOR
1108 // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437
1112 typename beast::detail::allocator_traits<
1113 Allocator>::template rebind_alloc<char>;
1116 std::char_traits<char>,
1117 rebind_type> s{rebind_type{alloc_}};
1119 s.reserve(value.size());
1120 detail::keep_alive_impl(
1121 s, value, version, keep_alive);
1123 erase(field::connection);
1125 set(field::connection, s);
1129 //------------------------------------------------------------------------------
1131 template<class Allocator>
1133 basic_fields<Allocator>::
1134 new_element(field name,
1135 string_view sname, string_view value) ->
1138 if(sname.size() + 2 >
1139 (std::numeric_limits<off_t>::max)())
1140 BOOST_THROW_EXCEPTION(std::length_error{
1141 "field name too large"});
1142 if(value.size() + 2 >
1143 (std::numeric_limits<off_t>::max)())
1144 BOOST_THROW_EXCEPTION(std::length_error{
1145 "field value too large"});
1146 value = detail::trim(value);
1147 std::uint16_t const off =
1148 static_cast<off_t>(sname.size() + 2);
1149 std::uint16_t const len =
1150 static_cast<off_t>(value.size());
1151 auto const p = alloc_traits::allocate(alloc_,
1152 1 + (off + len + 2 + sizeof(value_type) - 1) /
1153 sizeof(value_type));
1154 // VFALCO allocator can't call the constructor because its private
1155 //alloc_traits::construct(alloc_, p, name, sname, value);
1156 new(p) value_type{name, sname, value};
1160 template<class Allocator>
1162 basic_fields<Allocator>::
1163 delete_element(value_type& e)
1165 auto const n = 1 + (e.off_ + e.len_ + 2 +
1166 sizeof(value_type) - 1) / sizeof(value_type);
1167 alloc_traits::destroy(alloc_, &e);
1168 alloc_traits::deallocate(alloc_, &e, n);
1171 template<class Allocator>
1173 basic_fields<Allocator>::
1174 set_element(value_type& e)
1176 auto it = set_.lower_bound(
1177 e.name_string(), key_compare{});
1178 if(it == set_.end() || ! iequals(
1179 e.name_string(), it->name_string()))
1181 set_.insert_before(it, e);
1190 list_.erase(list_.iterator_to(*it));
1191 delete_element(*it);
1193 if(it == set_.end() ||
1194 ! iequals(e.name_string(), it->name_string()))
1197 set_.insert_before(it, e);
1201 template<class Allocator>
1203 basic_fields<Allocator>::
1204 realloc_string(string_view& dest, string_view s)
1206 if(dest.empty() && s.empty())
1208 auto a = typename beast::detail::allocator_traits<
1209 Allocator>::template rebind_alloc<
1213 a.deallocate(const_cast<char*>(
1214 dest.data()), dest.size());
1219 auto const p = a.allocate(s.size());
1220 std::memcpy(p, s.data(), s.size());
1221 dest = {p, s.size()};
1225 template<class Allocator>
1227 basic_fields<Allocator>::
1229 string_view& dest, string_view s)
1231 // The target string are stored with an
1232 // extra space at the beginning to help
1233 // the writer class.
1234 if(dest.empty() && s.empty())
1236 auto a = typename beast::detail::allocator_traits<
1237 Allocator>::template rebind_alloc<
1241 a.deallocate(const_cast<char*>(
1242 dest.data()), dest.size());
1247 auto const p = a.allocate(1 + s.size());
1249 std::memcpy(p + 1, s.data(), s.size());
1250 dest = {p, 1 + s.size()};
1254 template<class Allocator>
1255 template<class OtherAlloc>
1257 basic_fields<Allocator>::
1258 copy_all(basic_fields<OtherAlloc> const& other)
1260 for(auto const& e : other.list_)
1261 insert(e.name(), e.name_string(), e.value());
1262 realloc_string(method_, other.method_);
1263 realloc_string(target_or_reason_,
1264 other.target_or_reason_);
1267 template<class Allocator>
1269 basic_fields<Allocator>::
1273 realloc_string(method_, {});
1274 realloc_string(target_or_reason_, {});
1277 template<class Allocator>
1279 basic_fields<Allocator>::
1282 for(auto it = list_.begin(); it != list_.end();)
1283 delete_element(*it++);
1286 //------------------------------------------------------------------------------
1288 template<class Allocator>
1291 basic_fields<Allocator>::
1292 move_assign(basic_fields& other, std::true_type)
1295 set_ = std::move(other.set_);
1296 list_ = std::move(other.list_);
1297 method_ = other.method_;
1298 target_or_reason_ = other.target_or_reason_;
1299 other.method_.clear();
1300 other.target_or_reason_.clear();
1301 alloc_ = other.alloc_;
1304 template<class Allocator>
1307 basic_fields<Allocator>::
1308 move_assign(basic_fields& other, std::false_type)
1311 if(alloc_ != other.alloc_)
1318 set_ = std::move(other.set_);
1319 list_ = std::move(other.list_);
1320 method_ = other.method_;
1321 target_or_reason_ = other.target_or_reason_;
1322 other.method_.clear();
1323 other.target_or_reason_.clear();
1327 template<class Allocator>
1330 basic_fields<Allocator>::
1331 copy_assign(basic_fields const& other, std::true_type)
1334 alloc_ = other.alloc_;
1338 template<class Allocator>
1341 basic_fields<Allocator>::
1342 copy_assign(basic_fields const& other, std::false_type)
1348 template<class Allocator>
1351 basic_fields<Allocator>::
1352 swap(basic_fields& other, std::true_type)
1355 swap(alloc_, other.alloc_);
1356 swap(set_, other.set_);
1357 swap(list_, other.list_);
1358 swap(method_, other.method_);
1359 swap(target_or_reason_, other.target_or_reason_);
1362 template<class Allocator>
1365 basic_fields<Allocator>::
1366 swap(basic_fields& other, std::false_type)
1368 BOOST_ASSERT(alloc_ == other.alloc_);
1370 swap(set_, other.set_);
1371 swap(list_, other.list_);
1372 swap(method_, other.method_);
1373 swap(target_or_reason_, other.target_or_reason_);