Skip to content

Commit

Permalink
Value Semantics for request_storage_base.
Browse files Browse the repository at this point in the history
Here we make sure that copies of types deriving from
request_storage_base will properly copy the data (not copy-on-write)
that is in the buffers of the original object.
  • Loading branch information
deanberris committed Mar 14, 2012
1 parent 43f56f3 commit ddf1765
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 12 deletions.
4 changes: 0 additions & 4 deletions boost/network/protocol/http/request/request.hpp
Expand Up @@ -88,10 +88,6 @@ inline void swap(request &l, request &r) {

} // namespace boost

#ifdef BOOST_NETWORK_NO_LIB
#include <boost/network/protocol/http/request/request.ipp>
#endif

#include <boost/network/message/modifiers.hpp>
#include <boost/network/message/wrappers.hpp>
#include <boost/network/message/directives.hpp>
Expand Down
5 changes: 1 addition & 4 deletions boost/network/protocol/http/request/request_base.hpp
Expand Up @@ -26,6 +26,7 @@ struct request_storage_base_pimpl;
struct request_storage_base {
protected:
request_storage_base(size_t chunk_size = BOOST_NETWORK_BUFFER_CHUNK);
request_storage_base(request_storage_base const &other);
virtual void append(char const *data, size_t size);
virtual size_t read(char *destination, size_t offset, size_t size) const;
virtual void flatten(std::string &destination) const;
Expand Down Expand Up @@ -62,8 +63,4 @@ struct request_base : message_base, request_storage_base {

} /* boost */

#ifdef BOOST_NETWORK_NO_LIB
#include <boost/network/protocol/http/request/request_base.ipp>
#endif

#endif /* BOOST_NETWORK_PROTOCOL_HTTP_REQUEST_BASE_HPP_20111008 */
30 changes: 28 additions & 2 deletions boost/network/protocol/http/request/request_base.ipp
Expand Up @@ -18,25 +18,31 @@ request_base::~request_base() {
}

struct request_storage_base_pimpl {
request_storage_base_pimpl(size_t chunk_size);
explicit request_storage_base_pimpl(size_t chunk_size);
request_storage_base_pimpl *clone() const;
void append(char const *data, size_t size);
size_t read(char *destination, size_t offset, size_t size) const;
void flatten(std::string &destination) const;
void clear();
request_storage_base_pimpl clone() const;
~request_storage_base_pimpl();

private:
size_t chunk_size_;
typedef std::vector<std::pair<char *, size_t> > chunks_vector;
chunks_vector chunks_;
mutex chunk_mutex;

request_storage_base_pimpl(request_storage_base_pimpl const &other);
};

request_storage_base::request_storage_base(size_t chunk_size)
: pimpl_(new (std::nothrow) request_storage_base_pimpl(chunk_size))
{}

request_storage_base::request_storage_base(request_storage_base const &other)
: pimpl_(other.pimpl_->clone())
{}

request_storage_base::~request_storage_base() {
delete pimpl_;
}
Expand Down Expand Up @@ -64,6 +70,25 @@ request_storage_base_pimpl::request_storage_base_pimpl(size_t chunk_size)
// do nothing here.
}

request_storage_base_pimpl::request_storage_base_pimpl(request_storage_base_pimpl const &other)
: chunk_size_(other.chunk_size_)
, chunks_(0) {
chunks_.reserve(other.chunks_.size());
chunks_vector::const_iterator it = other.chunks_.begin();
for (; it != other.chunks_.end(); ++it) {
chunks_vector::value_type pair =
std::make_pair(
new (std::nothrow) char[other.chunk_size_],
it->second);
std::memcpy(pair.first, it->first, it->second);
chunks_.push_back(pair);
}
}

request_storage_base_pimpl * request_storage_base_pimpl::clone() const {
return new(std::nothrow) request_storage_base_pimpl(*this);
}

void request_storage_base_pimpl::append(char const *data, size_t size) {
if (chunks_.empty()) {
chunks_.push_back(std::make_pair(
Expand Down Expand Up @@ -133,6 +158,7 @@ request_storage_base_pimpl::~request_storage_base_pimpl() {
clear();
}


} /* http */

} /* network */
Expand Down
1 change: 0 additions & 1 deletion libs/network/test/http/CMakeLists.txt
Expand Up @@ -78,7 +78,6 @@ if (Boost_FOUND)
PROPERTIES COMPILE_FLAGS "-Wall")
endif()
add_executable(cpp-netlib-http-${test} ${test}.cpp)
add_dependencies(cpp-netlib-http-${test} cppnetlib-server-parsers)
target_link_libraries(cpp-netlib-http-${test} ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} cppnetlib-server-parsers)
set_target_properties(cpp-netlib-http-${test}
PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CPP-NETLIB_BINARY_DIR}/tests)
Expand Down
25 changes: 24 additions & 1 deletion libs/network/test/http/request_base_test.cpp
Expand Up @@ -23,10 +23,14 @@ struct request_test : http::request_storage_base {
using base_type::flatten;
using base_type::clear;

request_test(size_t chunk_size)
explicit request_test(size_t chunk_size)
: base_type(chunk_size)
{}

request_test(request_test const &other)
: base_type(other)
{}

~request_test() {
// do nothing here.
}
Expand All @@ -47,3 +51,22 @@ BOOST_AUTO_TEST_CASE(request_storage_flow) {
BOOST_CHECK_EQUAL(std::string(data, sizeof(data)), std::string(output, sizeof(data)));
simple.clear();
}

BOOST_AUTO_TEST_CASE(request_storage_copy) {
// Use a few byt chunks just to make it manageable.
request_test original(64);
static char quick_brown[] = "The quick brown fox jumps over the lazy dog.";
original.append(quick_brown, sizeof(quick_brown));
char output[sizeof(quick_brown)];
request_test copy(original);
size_t bytes_read = copy.read(output, 0, sizeof(quick_brown));
BOOST_CHECK_EQUAL(bytes_read, sizeof(quick_brown));
std::string flattened;
copy.flatten(flattened);
BOOST_CHECK_EQUAL(flattened, std::string(output, sizeof(quick_brown)));
BOOST_CHECK_EQUAL(std::string(quick_brown, sizeof(quick_brown)), std::string(output, sizeof(quick_brown)));
copy.clear();
flattened.clear();
original.flatten(flattened);
BOOST_CHECK_EQUAL(flattened, std::string(quick_brown, sizeof(quick_brown)));
}

0 comments on commit ddf1765

Please sign in to comment.