diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b0394f4..0a4697b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Version 54: * flat_buffer coverage * multi_buffer coverage * consuming_buffers members and coverage +* basic_fields members and coverage -------------------------------------------------------------------------------- diff --git a/include/beast/http/fields.hpp b/include/beast/http/fields.hpp index 1d3343ea..6dc5e2f6 100644 --- a/include/beast/http/fields.hpp +++ b/include/beast/http/fields.hpp @@ -73,15 +73,12 @@ public: }; protected: - // - // These are for `header` - // - friend class fields_test; + friend class fields_test; // for `header` /// Destructor ~basic_fields(); - /// Default constructor. + /// Constructor. basic_fields() = default; /** Constructor. @@ -97,6 +94,14 @@ protected: */ basic_fields(basic_fields&&); + /** Move constructor. + + The moved-from object behaves as if by call to @ref clear. + + @param alloc The allocator to use. + */ + basic_fields(basic_fields&&, Allocator const& alloc); + /// Copy constructor. basic_fields(basic_fields const&); @@ -107,26 +112,14 @@ protected: basic_fields(basic_fields const&, Allocator const& alloc); /// Copy constructor. -#if BEAST_DOXYGEN template -#else - template::value>::type> -#endif basic_fields(basic_fields const&); /** Copy constructor. @param alloc The allocator to use. */ -#if BEAST_DOXYGEN template -#else - template::value>::type> -#endif basic_fields(basic_fields const&, Allocator const& alloc); @@ -140,13 +133,7 @@ protected: basic_fields& operator=(basic_fields const&); /// Copy assignment. -#if BEAST_DOXYGEN template -#else - template::value>::type> -#endif basic_fields& operator=(basic_fields const&); public: @@ -213,6 +200,13 @@ public: return set_.find(name, less{}) != set_.end(); } + /// Return the number of values for the specified field. + std::size_t + count(field name) const + { + return count(to_string(name)); + } + /// Return the number of values for the specified field. std::size_t count(string_view name) const; @@ -444,6 +438,9 @@ protected: void set_chunked_impl(bool v); private: + template + friend class basic_fields; + class element : public boost::intrusive::set_base_hook < boost::intrusive::link_mode < @@ -549,16 +546,15 @@ private: void swap(basic_fields& other, std::false_type); + alloc_type alloc_; set_t set_; list_t list_; string_view method_; string_view target_or_reason_; - alloc_type alloc_; }; /// A typical HTTP header fields container -using fields = - basic_fields>; +using fields = basic_fields>; } // http } // beast diff --git a/include/beast/http/impl/fields.ipp b/include/beast/http/impl/fields.ipp index 7daa88ed..5f14f753 100644 --- a/include/beast/http/impl/fields.ipp +++ b/include/beast/http/impl/fields.ipp @@ -359,20 +359,39 @@ basic_fields(Allocator const& alloc) template basic_fields:: basic_fields(basic_fields&& other) - : set_(std::move(other.set_)) + : alloc_(std::move(other.alloc_)) + , set_(std::move(other.set_)) , list_(std::move(other.list_)) , method_(other.method_) , target_or_reason_(other.target_or_reason_) - , alloc_(std::move(other.alloc_)) { other.method_.clear(); other.target_or_reason_.clear(); } +template +basic_fields:: +basic_fields(basic_fields&& other, Allocator const& alloc) + : alloc_(alloc) +{ + if(alloc_ != other.alloc_) + { + copy_all(other); + other.clear_all(); + } + else + { + set_ = std::move(other.set_); + list_ = std::move(other.list_); + method_ = other.method_; + target_or_reason_ = other.target_or_reason_; + } +} + template basic_fields:: basic_fields(basic_fields const& other) - : basic_fields(alloc_traits:: + : alloc_(alloc_traits:: select_on_container_copy_construction(other.alloc_)) { copy_all(other); @@ -388,7 +407,7 @@ basic_fields(basic_fields const& other, } template -template +template basic_fields:: basic_fields(basic_fields const& other) { @@ -396,7 +415,7 @@ basic_fields(basic_fields const& other) } template -template +template basic_fields:: basic_fields(basic_fields const& other, Allocator const& alloc) @@ -430,7 +449,7 @@ operator=(basic_fields const& other) -> } template -template +template auto basic_fields:: operator=(basic_fields const& other) -> diff --git a/test/http/fields.cpp b/test/http/fields.cpp index 0f204006..20d1e987 100644 --- a/test/http/fields.cpp +++ b/test/http/fields.cpp @@ -8,6 +8,7 @@ // Test that header file is self-contained. #include +#include #include #include @@ -55,6 +56,232 @@ public: return std::distance(f.begin(), f.end()); } + void + testMembers() + { + using namespace test; + + // compare equal + using equal_t = test::test_allocator; + + // compare not equal + using unequal_t = test::test_allocator; + + // construction + { + { + fields f; + BEAST_EXPECT(f.begin() == f.end()); + } + { + unequal_t a1; + basic_fields f{a1}; + BEAST_EXPECT(f.get_allocator() == a1); + BEAST_EXPECT(f.get_allocator() != unequal_t{}); + } + } + + // move construction + { + { + basic_fields f1; + BEAST_EXPECT(f1.get_allocator()->nmove == 0); + f1.insert("1", "1"); + BEAST_EXPECT(f1["1"] == "1"); + basic_fields f2{std::move(f1)}; + BEAST_EXPECT(f2.get_allocator()->nmove == 1); + BEAST_EXPECT(f2["1"] == "1"); + BEAST_EXPECT(f1["1"] == ""); + } + // allocators equal + { + basic_fields f1; + f1.insert("1", "1"); + equal_t a; + basic_fields f2{std::move(f1), a}; + BEAST_EXPECT(f2["1"] == "1"); + BEAST_EXPECT(f1["1"] == ""); + } + { + // allocators unequal + basic_fields f1; + f1.insert("1", "1"); + unequal_t a; + basic_fields f2{std::move(f1), a}; + BEAST_EXPECT(f2["1"] == "1"); + } + } + + // copy construction + { + { + basic_fields f1; + f1.insert("1", "1"); + basic_fields f2{f1}; + BEAST_EXPECT(f1.get_allocator() == f2.get_allocator()); + BEAST_EXPECT(f1["1"] == "1"); + BEAST_EXPECT(f2["1"] == "1"); + } + { + basic_fields f1; + f1.insert("1", "1"); + unequal_t a; + basic_fields f2(f1, a); + BEAST_EXPECT(f1.get_allocator() != f2.get_allocator()); + BEAST_EXPECT(f1["1"] == "1"); + BEAST_EXPECT(f2["1"] == "1"); + } + { + basic_fields f1; + f1.insert("1", "1"); + basic_fields f2(f1); + BEAST_EXPECT(f1["1"] == "1"); + BEAST_EXPECT(f2["1"] == "1"); + } + { + basic_fields f1; + f1.insert("1", "1"); + equal_t a; + basic_fields f2(f1, a); + BEAST_EXPECT(f2.get_allocator() == a); + BEAST_EXPECT(f1["1"] == "1"); + BEAST_EXPECT(f2["1"] == "1"); + } + } + + // move assignment + { + { + fields f1; + f1.insert("1", "1"); + fields f2; + f2 = std::move(f1); + BEAST_EXPECT(f1.begin() == f1.end()); + BEAST_EXPECT(f2["1"] == "1"); + } + { + // propagate_on_container_move_assignment : true + using pocma_t = test::test_allocator; + basic_fields f1; + f1.insert("1", "1"); + basic_fields f2; + f2 = std::move(f1); + BEAST_EXPECT(f1.begin() == f1.end()); + BEAST_EXPECT(f2["1"] == "1"); + } + { + // propagate_on_container_move_assignment : false + using pocma_t = test::test_allocator; + basic_fields f1; + f1.insert("1", "1"); + basic_fields f2; + f2 = std::move(f1); + BEAST_EXPECT(f1.begin() == f1.end()); + BEAST_EXPECT(f2["1"] == "1"); + } + } + + // copy assignment + { + { + fields f1; + f1.insert("1", "1"); + fields f2; + f2 = f1; + BEAST_EXPECT(f1["1"] == "1"); + BEAST_EXPECT(f2["1"] == "1"); + basic_fields f3; + f3 = f2; + BEAST_EXPECT(f3["1"] == "1"); + } + { + // propagate_on_container_copy_assignment : true + using pocca_t = test::test_allocator; + basic_fields f1; + f1.insert("1", "1"); + basic_fields f2; + f2 = f1; + BEAST_EXPECT(f2["1"] == "1"); + } + { + // propagate_on_container_copy_assignment : false + using pocca_t = test::test_allocator; + basic_fields f1; + f1.insert("1", "1"); + basic_fields f2; + f2 = f1; + BEAST_EXPECT(f2["1"] == "1"); + } + } + + // swap + { + { + // propagate_on_container_swap : true + using pocs_t = test::test_allocator; + pocs_t a1, a2; + BEAST_EXPECT(a1 != a2); + basic_fields f1{a1}; + f1.insert("1", "1"); + basic_fields f2{a2}; + BEAST_EXPECT(f1.get_allocator() == a1); + BEAST_EXPECT(f2.get_allocator() == a2); + swap(f1, f2); + BEAST_EXPECT(f1.get_allocator() == a2); + BEAST_EXPECT(f2.get_allocator() == a1); + BEAST_EXPECT(f1.begin() == f1.end()); + BEAST_EXPECT(f2["1"] == "1"); + swap(f1, f2); + BEAST_EXPECT(f1.get_allocator() == a1); + BEAST_EXPECT(f2.get_allocator() == a2); + BEAST_EXPECT(f1["1"] == "1"); + BEAST_EXPECT(f2.begin() == f2.end()); + } + { + // propagate_on_container_swap : false + using pocs_t = test::test_allocator; + pocs_t a1, a2; + BEAST_EXPECT(a1 == a2); + BEAST_EXPECT(a1.id() != a2.id()); + basic_fields f1{a1}; + f1.insert("1", "1"); + basic_fields f2{a2}; + BEAST_EXPECT(f1.get_allocator() == a1); + BEAST_EXPECT(f2.get_allocator() == a2); + swap(f1, f2); + BEAST_EXPECT(f1.get_allocator().id() == a1.id()); + BEAST_EXPECT(f2.get_allocator().id() == a2.id()); + BEAST_EXPECT(f1.begin() == f1.end()); + BEAST_EXPECT(f2["1"] == "1"); + swap(f1, f2); + BEAST_EXPECT(f1.get_allocator().id() == a1.id()); + BEAST_EXPECT(f2.get_allocator().id() == a2.id()); + BEAST_EXPECT(f1["1"] == "1"); + BEAST_EXPECT(f2.begin() == f2.end()); + } + } + + // operations + { + fields f; + f.insert(field::user_agent, "x"); + BEAST_EXPECT(f.exists(field::user_agent)); + BEAST_EXPECT(f.exists(to_string(field::user_agent))); + BEAST_EXPECT(f.count(field::user_agent) == 1); + BEAST_EXPECT(f.count(to_string(field::user_agent)) == 1); + f.insert(field::user_agent, "y"); + BEAST_EXPECT(f.count(field::user_agent) == 2); + } + } + void testHeaders() { f_t f1; @@ -83,7 +310,7 @@ public: f.insert("a", "w"); f.insert("a", "x"); f.insert("aa", "y"); - f.insert("b", "z"); + f.insert("f", "z"); BEAST_EXPECT(f.count("a") == 2); } @@ -93,7 +320,7 @@ public: f.insert("a", "w"); f.insert("a", "x"); f.insert("aa", "y"); - f.insert("b", "z"); + f.insert("f", "z"); BEAST_EXPECT(size(f) == 4); f.erase("a"); BEAST_EXPECT(size(f) == 2); @@ -101,6 +328,7 @@ public: void run() override { + testMembers(); testHeaders(); testRFC2616(); testErase();