From 28a994e8cb504133fbfcc461beea23623b3b2a40 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Thu, 27 Apr 2017 17:38:50 -0700 Subject: [PATCH] Move everything in basic_fields.hpp to fields.hpp (API Change) fix #320 --- CHANGELOG.md | 1 + include/beast/http.hpp | 1 - include/beast/http/basic_fields.hpp | 307 ------------------ .../detail/{basic_fields.hpp => fields.hpp} | 4 +- include/beast/http/fields.hpp | 288 +++++++++++++++- .../impl/{basic_fields.ipp => fields.ipp} | 4 +- test/Jamfile | 1 - test/http/CMakeLists.txt | 1 - test/http/basic_fields.cpp | 96 ------ test/http/fields.cpp | 87 +++++ 10 files changed, 379 insertions(+), 411 deletions(-) delete mode 100644 include/beast/http/basic_fields.hpp rename include/beast/http/detail/{basic_fields.hpp => fields.hpp} (98%) rename include/beast/http/impl/{basic_fields.ipp => fields.ipp} (98%) delete mode 100644 test/http/basic_fields.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 35277846..1b8b4b4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ API Changes: * Provide websocket::stream accept() overloads * Refactor websocket decorators +* Move everything in basic_fields.hpp to fields.hpp -------------------------------------------------------------------------------- diff --git a/include/beast/http.hpp b/include/beast/http.hpp index 8a8c3ff3..e3b7ed2d 100644 --- a/include/beast/http.hpp +++ b/include/beast/http.hpp @@ -10,7 +10,6 @@ #include -#include #include #include #include diff --git a/include/beast/http/basic_fields.hpp b/include/beast/http/basic_fields.hpp deleted file mode 100644 index f4f73ba9..00000000 --- a/include/beast/http/basic_fields.hpp +++ /dev/null @@ -1,307 +0,0 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_HTTP_BASIC_FIELDS_HPP -#define BEAST_HTTP_BASIC_FIELDS_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace beast { -namespace http { - -/** A container for storing HTTP header fields. - - This container is designed to store the field value pairs that make - up the fields and trailers in a HTTP message. Objects of this type - are iterable, with each element holding the field name and field - value. - - Field names are stored as-is, but comparisons are case-insensitive. - When the container is iterated, the fields are presented in the order - of insertion. For fields with the same name, the container behaves - as a `std::multiset`; there will be a separate value for each occurrence - of the field name. - - @note Meets the requirements of @b FieldSequence. -*/ -template -class basic_fields : -#if ! BEAST_DOXYGEN - private beast::detail::empty_base_optimization< - typename std::allocator_traits:: - template rebind_alloc< - detail::basic_fields_base::element>>, -#endif - public detail::basic_fields_base -{ - using alloc_type = typename - std::allocator_traits:: - template rebind_alloc< - detail::basic_fields_base::element>; - - using alloc_traits = - std::allocator_traits; - - using size_type = - typename std::allocator_traits::size_type; - - void - delete_all(); - - void - move_assign(basic_fields&, std::false_type); - - void - move_assign(basic_fields&, std::true_type); - - void - copy_assign(basic_fields const&, std::false_type); - - void - copy_assign(basic_fields const&, std::true_type); - - template - void - copy_from(FieldSequence const& fs) - { - for(auto const& e : fs) - insert(e.first, e.second); - } - -public: - /// The type of allocator used. - using allocator_type = Allocator; - - /** The value type of the field sequence. - - Meets the requirements of @b Field. - */ -#if BEAST_DOXYGEN - using value_type = implementation_defined; -#endif - - /// A const iterator to the field sequence -#if BEAST_DOXYGEN - using iterator = implementation_defined; -#endif - - /// A const iterator to the field sequence -#if BEAST_DOXYGEN - using const_iterator = implementation_defined; -#endif - - /// Default constructor. - basic_fields() = default; - - /// Destructor - ~basic_fields(); - - /** Construct the fields. - - @param alloc The allocator to use. - */ - explicit - basic_fields(Allocator const& alloc); - - /** Move constructor. - - The moved-from object becomes an empty field sequence. - - @param other The object to move from. - */ - basic_fields(basic_fields&& other); - - /** Move assignment. - - The moved-from object becomes an empty field sequence. - - @param other The object to move from. - */ - basic_fields& operator=(basic_fields&& other); - - /// Copy constructor. - basic_fields(basic_fields const&); - - /// Copy assignment. - basic_fields& operator=(basic_fields const&); - - /// Copy constructor. - template - basic_fields(basic_fields const&); - - /// Copy assignment. - template - basic_fields& operator=(basic_fields const&); - - /// Construct from a field sequence. - template - basic_fields(FwdIt first, FwdIt last); - - /// Returns `true` if the field sequence contains no elements. - bool - empty() const - { - return set_.empty(); - } - - /// Returns the number of elements in the field sequence. - std::size_t - size() const - { - return set_.size(); - } - - /// Returns a const iterator to the beginning of the field sequence. - const_iterator - begin() const - { - return list_.cbegin(); - } - - /// Returns a const iterator to the end of the field sequence. - const_iterator - end() const - { - return list_.cend(); - } - - /// Returns a const iterator to the beginning of the field sequence. - const_iterator - cbegin() const - { - return list_.cbegin(); - } - - /// Returns a const iterator to the end of the field sequence. - const_iterator - cend() const - { - return list_.cend(); - } - - /// Returns `true` if the specified field exists. - bool - exists(boost::string_ref const& name) const - { - return set_.find(name, less{}) != set_.end(); - } - - /// Returns the number of values for the specified field. - std::size_t - count(boost::string_ref const& name) const; - - /** Returns an iterator to the case-insensitive matching field name. - - If more than one field with the specified name exists, the - first field defined by insertion order is returned. - */ - iterator - find(boost::string_ref const& name) const; - - /** Returns the value for a case-insensitive matching header, or `""`. - - If more than one field with the specified name exists, the - first field defined by insertion order is returned. - */ - boost::string_ref - operator[](boost::string_ref const& name) const; - - /// Clear the contents of the basic_fields. - void - clear() noexcept; - - /** Remove a field. - - If more than one field with the specified name exists, all - matching fields will be removed. - - @param name The name of the field(s) to remove. - - @return The number of fields removed. - */ - std::size_t - erase(boost::string_ref const& name); - - /** Insert a field value. - - If a field with the same name already exists, the - existing field is untouched and a new field value pair - is inserted into the container. - - @param name The name of the field. - - @param value A string holding the value of the field. - */ - void - insert(boost::string_ref const& name, boost::string_ref value); - - /** Insert a field value. - - If a field with the same name already exists, the - existing field is untouched and a new field value pair - is inserted into the container. - - @param name The name of the field - - @param value The value of the field. The object will be - converted to a string using `boost::lexical_cast`. - */ - template - typename std::enable_if< - ! std::is_constructible::value>::type - insert(boost::string_ref name, T const& value) - { - insert(name, boost::lexical_cast(value)); - } - - /** Replace a field value. - - First removes any values with matching field names, then - inserts the new field value. - - @param name The name of the field. - - @param value A string holding the value of the field. - */ - void - replace(boost::string_ref const& name, boost::string_ref value); - - /** Replace a field value. - - First removes any values with matching field names, then - inserts the new field value. - - @param name The name of the field - - @param value The value of the field. The object will be - converted to a string using `boost::lexical_cast`. - */ - template - typename std::enable_if< - ! std::is_constructible::value>::type - replace(boost::string_ref const& name, T const& value) - { - replace(name, - boost::lexical_cast(value)); - } -}; - -} // http -} // beast - -#include - -#endif diff --git a/include/beast/http/detail/basic_fields.hpp b/include/beast/http/detail/fields.hpp similarity index 98% rename from include/beast/http/detail/basic_fields.hpp rename to include/beast/http/detail/fields.hpp index 1b296df3..60af3872 100644 --- a/include/beast/http/detail/basic_fields.hpp +++ b/include/beast/http/detail/fields.hpp @@ -5,8 +5,8 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_HTTP_DETAIL_BASIC_FIELDS_HPP -#define BEAST_HTTP_DETAIL_BASIC_FIELDS_HPP +#ifndef BEAST_HTTP_DETAIL_FIELDS_HPP +#define BEAST_HTTP_DETAIL_FIELDS_HPP #include #include diff --git a/include/beast/http/fields.hpp b/include/beast/http/fields.hpp index 7c2ef2a5..c62105b1 100644 --- a/include/beast/http/fields.hpp +++ b/include/beast/http/fields.hpp @@ -9,12 +9,296 @@ #define BEAST_HTTP_FIELDS_HPP #include -#include +#include +#include +#include +#include +#include #include +#include +#include +#include namespace beast { namespace http { +/** A container for storing HTTP header fields. + + This container is designed to store the field value pairs that make + up the fields and trailers in a HTTP message. Objects of this type + are iterable, with each element holding the field name and field + value. + + Field names are stored as-is, but comparisons are case-insensitive. + When the container is iterated, the fields are presented in the order + of insertion. For fields with the same name, the container behaves + as a `std::multiset`; there will be a separate value for each occurrence + of the field name. + + @note Meets the requirements of @b FieldSequence. +*/ +template +class basic_fields : +#if ! BEAST_DOXYGEN + private beast::detail::empty_base_optimization< + typename std::allocator_traits:: + template rebind_alloc< + detail::basic_fields_base::element>>, +#endif + public detail::basic_fields_base +{ + using alloc_type = typename + std::allocator_traits:: + template rebind_alloc< + detail::basic_fields_base::element>; + + using alloc_traits = + std::allocator_traits; + + using size_type = + typename std::allocator_traits::size_type; + + void + delete_all(); + + void + move_assign(basic_fields&, std::false_type); + + void + move_assign(basic_fields&, std::true_type); + + void + copy_assign(basic_fields const&, std::false_type); + + void + copy_assign(basic_fields const&, std::true_type); + + template + void + copy_from(FieldSequence const& fs) + { + for(auto const& e : fs) + insert(e.first, e.second); + } + +public: + /// The type of allocator used. + using allocator_type = Allocator; + + /** The value type of the field sequence. + + Meets the requirements of @b Field. + */ +#if BEAST_DOXYGEN + using value_type = implementation_defined; +#endif + + /// A const iterator to the field sequence +#if BEAST_DOXYGEN + using iterator = implementation_defined; +#endif + + /// A const iterator to the field sequence +#if BEAST_DOXYGEN + using const_iterator = implementation_defined; +#endif + + /// Default constructor. + basic_fields() = default; + + /// Destructor + ~basic_fields(); + + /** Construct the fields. + + @param alloc The allocator to use. + */ + explicit + basic_fields(Allocator const& alloc); + + /** Move constructor. + + The moved-from object becomes an empty field sequence. + + @param other The object to move from. + */ + basic_fields(basic_fields&& other); + + /** Move assignment. + + The moved-from object becomes an empty field sequence. + + @param other The object to move from. + */ + basic_fields& operator=(basic_fields&& other); + + /// Copy constructor. + basic_fields(basic_fields const&); + + /// Copy assignment. + basic_fields& operator=(basic_fields const&); + + /// Copy constructor. + template + basic_fields(basic_fields const&); + + /// Copy assignment. + template + basic_fields& operator=(basic_fields const&); + + /// Construct from a field sequence. + template + basic_fields(FwdIt first, FwdIt last); + + /// Returns `true` if the field sequence contains no elements. + bool + empty() const + { + return set_.empty(); + } + + /// Returns the number of elements in the field sequence. + std::size_t + size() const + { + return set_.size(); + } + + /// Returns a const iterator to the beginning of the field sequence. + const_iterator + begin() const + { + return list_.cbegin(); + } + + /// Returns a const iterator to the end of the field sequence. + const_iterator + end() const + { + return list_.cend(); + } + + /// Returns a const iterator to the beginning of the field sequence. + const_iterator + cbegin() const + { + return list_.cbegin(); + } + + /// Returns a const iterator to the end of the field sequence. + const_iterator + cend() const + { + return list_.cend(); + } + + /// Returns `true` if the specified field exists. + bool + exists(boost::string_ref const& name) const + { + return set_.find(name, less{}) != set_.end(); + } + + /// Returns the number of values for the specified field. + std::size_t + count(boost::string_ref const& name) const; + + /** Returns an iterator to the case-insensitive matching field name. + + If more than one field with the specified name exists, the + first field defined by insertion order is returned. + */ + iterator + find(boost::string_ref const& name) const; + + /** Returns the value for a case-insensitive matching header, or `""`. + + If more than one field with the specified name exists, the + first field defined by insertion order is returned. + */ + boost::string_ref + operator[](boost::string_ref const& name) const; + + /// Clear the contents of the basic_fields. + void + clear() noexcept; + + /** Remove a field. + + If more than one field with the specified name exists, all + matching fields will be removed. + + @param name The name of the field(s) to remove. + + @return The number of fields removed. + */ + std::size_t + erase(boost::string_ref const& name); + + /** Insert a field value. + + If a field with the same name already exists, the + existing field is untouched and a new field value pair + is inserted into the container. + + @param name The name of the field. + + @param value A string holding the value of the field. + */ + void + insert(boost::string_ref const& name, boost::string_ref value); + + /** Insert a field value. + + If a field with the same name already exists, the + existing field is untouched and a new field value pair + is inserted into the container. + + @param name The name of the field + + @param value The value of the field. The object will be + converted to a string using `boost::lexical_cast`. + */ + template + typename std::enable_if< + ! std::is_constructible::value>::type + insert(boost::string_ref name, T const& value) + { + insert(name, boost::lexical_cast(value)); + } + + /** Replace a field value. + + First removes any values with matching field names, then + inserts the new field value. + + @param name The name of the field. + + @param value A string holding the value of the field. + */ + void + replace(boost::string_ref const& name, boost::string_ref value); + + /** Replace a field value. + + First removes any values with matching field names, then + inserts the new field value. + + @param name The name of the field + + @param value The value of the field. The object will be + converted to a string using `boost::lexical_cast`. + */ + template + typename std::enable_if< + ! std::is_constructible::value>::type + replace(boost::string_ref const& name, T const& value) + { + replace(name, + boost::lexical_cast(value)); + } +}; + /// A typical HTTP header fields container using fields = basic_fields>; @@ -22,4 +306,6 @@ using fields = } // http } // beast +#include + #endif diff --git a/include/beast/http/impl/basic_fields.ipp b/include/beast/http/impl/fields.ipp similarity index 98% rename from include/beast/http/impl/basic_fields.ipp rename to include/beast/http/impl/fields.ipp index 06908720..c4a7c9b6 100644 --- a/include/beast/http/impl/basic_fields.ipp +++ b/include/beast/http/impl/fields.ipp @@ -5,8 +5,8 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_HTTP_IMPL_BASIC_FIELDS_IPP -#define BEAST_HTTP_IMPL_BASIC_FIELDS_IPP +#ifndef BEAST_HTTP_IMPL_FIELDS_IPP +#define BEAST_HTTP_IMPL_FIELDS_IPP #include #include diff --git a/test/Jamfile b/test/Jamfile index c9f49370..0d0c0510 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -48,7 +48,6 @@ unit-test core-tests : unit-test http-tests : ../extras/beast/unit_test/main.cpp http/basic_dynabuf_body.cpp - http/basic_fields.cpp http/basic_parser.cpp http/concepts.cpp http/design.cpp diff --git a/test/http/CMakeLists.txt b/test/http/CMakeLists.txt index c262eddd..7baaf15f 100644 --- a/test/http/CMakeLists.txt +++ b/test/http/CMakeLists.txt @@ -11,7 +11,6 @@ add_executable (http-tests test_parser.hpp ../../extras/beast/unit_test/main.cpp basic_dynabuf_body.cpp - basic_fields.cpp basic_parser.cpp concepts.cpp design.cpp diff --git a/test/http/basic_fields.cpp b/test/http/basic_fields.cpp deleted file mode 100644 index 9948bd63..00000000 --- a/test/http/basic_fields.cpp +++ /dev/null @@ -1,96 +0,0 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -// Test that header file is self-contained. -#include - -#include -#include - -namespace beast { -namespace http { - -class basic_fields_test : public beast::unit_test::suite -{ -public: - template - using bha = basic_fields; - - using bh = basic_fields>; - - template - static - void - fill(std::size_t n, basic_fields& h) - { - for(std::size_t i = 1; i<= n; ++i) - h.insert(boost::lexical_cast(i), i); - } - - template - static - void - self_assign(U& u, V&& v) - { - u = std::forward(v); - } - - void testHeaders() - { - bh h1; - BEAST_EXPECT(h1.empty()); - fill(1, h1); - BEAST_EXPECT(h1.size() == 1); - bh h2; - h2 = h1; - BEAST_EXPECT(h2.size() == 1); - h2.insert("2", "2"); - BEAST_EXPECT(std::distance(h2.begin(), h2.end()) == 2); - h1 = std::move(h2); - BEAST_EXPECT(h1.size() == 2); - BEAST_EXPECT(h2.size() == 0); - bh h3(std::move(h1)); - BEAST_EXPECT(h3.size() == 2); - BEAST_EXPECT(h1.size() == 0); - self_assign(h3, std::move(h3)); - BEAST_EXPECT(h3.size() == 2); - BEAST_EXPECT(h2.erase("Not-Present") == 0); - } - - void testRFC2616() - { - bh h; - h.insert("a", "w"); - h.insert("a", "x"); - h.insert("aa", "y"); - h.insert("b", "z"); - BEAST_EXPECT(h.count("a") == 2); - } - - void testErase() - { - bh h; - h.insert("a", "w"); - h.insert("a", "x"); - h.insert("aa", "y"); - h.insert("b", "z"); - BEAST_EXPECT(h.size() == 4); - h.erase("a"); - BEAST_EXPECT(h.size() == 2); - } - - void run() override - { - testHeaders(); - testRFC2616(); - } -}; - -BEAST_DEFINE_TESTSUITE(basic_fields,http,beast); - -} // http -} // beast diff --git a/test/http/fields.cpp b/test/http/fields.cpp index 8ac52d5b..e16408e0 100644 --- a/test/http/fields.cpp +++ b/test/http/fields.cpp @@ -7,3 +7,90 @@ // Test that header file is self-contained. #include + +#include +#include + +namespace beast { +namespace http { + +class basic_fields_test : public beast::unit_test::suite +{ +public: + template + using bha = basic_fields; + + using bh = basic_fields>; + + template + static + void + fill(std::size_t n, basic_fields& h) + { + for(std::size_t i = 1; i<= n; ++i) + h.insert(boost::lexical_cast(i), i); + } + + template + static + void + self_assign(U& u, V&& v) + { + u = std::forward(v); + } + + void testHeaders() + { + bh h1; + BEAST_EXPECT(h1.empty()); + fill(1, h1); + BEAST_EXPECT(h1.size() == 1); + bh h2; + h2 = h1; + BEAST_EXPECT(h2.size() == 1); + h2.insert("2", "2"); + BEAST_EXPECT(std::distance(h2.begin(), h2.end()) == 2); + h1 = std::move(h2); + BEAST_EXPECT(h1.size() == 2); + BEAST_EXPECT(h2.size() == 0); + bh h3(std::move(h1)); + BEAST_EXPECT(h3.size() == 2); + BEAST_EXPECT(h1.size() == 0); + self_assign(h3, std::move(h3)); + BEAST_EXPECT(h3.size() == 2); + BEAST_EXPECT(h2.erase("Not-Present") == 0); + } + + void testRFC2616() + { + bh h; + h.insert("a", "w"); + h.insert("a", "x"); + h.insert("aa", "y"); + h.insert("b", "z"); + BEAST_EXPECT(h.count("a") == 2); + } + + void testErase() + { + bh h; + h.insert("a", "w"); + h.insert("a", "x"); + h.insert("aa", "y"); + h.insert("b", "z"); + BEAST_EXPECT(h.size() == 4); + h.erase("a"); + BEAST_EXPECT(h.size() == 2); + } + + void run() override + { + testHeaders(); + testRFC2616(); + } +}; + +BEAST_DEFINE_TESTSUITE(basic_fields,http,beast); + +} // http +} // beast