//////////////////////////////////////////////////////////////////////////////////////////////// // sequence_buffer.h #pragma once #include #include #include #include #include #include #include #include #include #include #include #include //////////////////////////////////////////////////////////////////////////////////////////////// #pragma warning(push) #pragma warning(disable: 4511; disable: 4512; disable: 4706) //////////////////////////////////////////////////////////////////////////////////////////////// namespace sequence_buffer { //////////////////////////////////////////////////////////////////////////////////////////////// // synopsis // adaptable sequence concepts template class input_sequence_concept; template class output_sequence_concept; // examples of sequence models template class stl_input_sequence; template class stl_output_sequence; template class push_back_sequence; // named optional parameters for buffer adapters template struct allocator_is; template struct element_is; template struct element_traits_is; template struct buffer_size_is; namespace detail { struct default_parameter; } // buffer adapters template< // mandatory parameters class sequence_model // optional parameters , class P1 = detail::default_parameter , class P2 = detail::default_parameter , class P3 = detail::default_parameter , class P4 = detail::default_parameter > class input_buffer; template< // mandatory parameters class sequence_model // optional parameters , class P1 = detail::default_parameter , class P2 = detail::default_parameter , class P3 = detail::default_parameter , class P4 = detail::default_parameter > class output_buffer; //////////////////////////////////////////////////////////////////////////////////////////////// namespace detail { //////////////////////////////////////////////////////////////////////////////////////////////// namespace mpl = boost::mpl; namespace tt = boost; // type traits struct sequence_model_tag {}; struct allocator_tag {}; struct element_tag {}; struct element_traits_tag {}; struct buffer_size_tag {}; template struct define_parameter { typedef tag name; typedef T type; }; struct default_parameter_tag {}; struct default_parameter : detail::define_parameter {}; //////////////////////////////////////////////////////////////////////////////////////////////// template class optional_parameters; //////////////////////////////////////////////////////////////////////////////////////////////// template struct superior_of { derived& self() { return static_cast(*this); } }; //////////////////////////////////////////////////////////////////////////////////////////////// } // namespace detail //////////////////////////////////////////////////////////////////////////////////////////////// // sequence concepts template class input_sequence_concept : private detail::superior_of { public: typedef input_sequence_concept concept; size_t read(void* buffer, size_t size) // byte buffer[size] { return self().read_impl(buffer, size); } }; template class output_sequence_concept : private detail::superior_of { public: typedef output_sequence_concept concept; void write(const void* buffer, size_t size) // byte buffer[size] { return self().write_impl(buffer, size); } }; //////////////////////////////////////////////////////////////////////////////////////////////// // examples of sequence models template class stl_input_sequence : public input_sequence_concept > { private: typedef typename std::iterator_traits::value_type element; public: stl_input_sequence(iterator begin, iterator end) // [begin, end) : begin_(begin) , end_(end) {} size_t read_impl(void* buffer, size_t size) { if (size % sizeof(element)) throw std::runtime_error("read_impl() failed."); size = std::min(size / sizeof(element), end_ - begin_); std::copy(begin_, begin_ + size, static_cast(buffer)); begin_ += size; return size * sizeof(element); } private: iterator begin_; iterator end_; }; template class stl_output_sequence : public output_sequence_concept > { private: typedef typename std::iterator_traits::value_type element; public: stl_output_sequence(iterator begin, iterator end) // [begin, end) : begin_(begin) , end_(end) {} void write_impl(const void* buffer, size_t size) { if (size % sizeof(element) || size / sizeof(element) > size_t(end_ - begin_)) throw std::runtime_error("write_impl() failed."); size /= sizeof(element); std::copy(static_cast(buffer), static_cast(buffer) + size, begin_); begin_ += size; } private: iterator begin_; iterator end_; }; template class push_back_sequence : public output_sequence_concept > { private: typedef typename container::value_type element; public: push_back_sequence(container& c) : container_(c) {} void write_impl(const void* buffer, size_t size) { if (size % sizeof(element)) throw std::runtime_error("write_impl() failed."); std::copy(static_cast(buffer), static_cast(buffer) + size / sizeof(element), std::back_inserter(container_)); } private: container& container_; }; //////////////////////////////////////////////////////////////////////////////////////////////// // named optional parameters template struct allocator_is : detail::define_parameter {}; template struct element_is : detail::define_parameter {}; template struct element_traits_is : detail::define_parameter {}; template struct buffer_size_is : detail::define_parameter > {}; //////////////////////////////////////////////////////////////////////////////////////////////// namespace detail { //////////////////////////////////////////////////////////////////////////////////////////////// template< class sequence_concept , class P1 , class P2 , class P3 , class P4 > class buffer_base : public std::basic_streambuf< typename detail::optional_parameters >::element , typename detail::optional_parameters >::element_traits > , private detail::optional_parameters >::allocator // allow EBO { protected: typedef detail::optional_parameters parameters; typedef typename parameters::element element; typedef typename parameters::element_traits element_traits; typedef typename parameters::allocator allocator; static const size_t buffer_size = parameters::buffer_size::value; buffer_base(sequence_concept& sequence) : sequence_(sequence) { initialize(); } ~buffer_base() { release_buffer(); } protected: sequence_concept& get_sequence() { return sequence_; } void pre_underflow() { if (!eback()) { element* buffer = allocate_buffer(); setg(buffer, buffer + buffer_size, buffer + buffer_size); } } void pre_overflow() { if (!pbase()) { element* buffer = allocate_buffer(); setp(buffer, buffer + buffer_size); } } private: element* allocate_buffer() { return this->allocator::allocate(buffer_size); } void release_buffer() { this->allocator::deallocate(eback(), buffer_size); setg(0, 0, 0); this->allocator::deallocate(pbase(), buffer_size); setp(0, 0); } void initialize() { setg(0, 0, 0); setp(0, 0); } sequence_concept& sequence_; }; //////////////////////////////////////////////////////////////////////////////////////////////// } // namespace detail //////////////////////////////////////////////////////////////////////////////////////////////// template< class sequence_model , class P1 , class P2 , class P3 , class P4 > class input_buffer : public detail::buffer_base { private: typedef detail::buffer_base base; typedef typename base::element element; typedef typename base::element_traits element_traits; static const size_t buffer_size = base::buffer_size; typedef typename sequence_model::concept sequence_concept; typedef typename element_traits::int_type int_type; public: input_buffer(sequence_concept& sequence) : base(sequence) {} private: int_type underflow() { base::pre_underflow(); size_t read; if ((read = get_sequence().read(eback(), buffer_size * sizeof(element))) && !(read % sizeof(element))) { setg(eback(), eback(), eback() + read / sizeof(element)); return element_traits::to_int_type(*eback()); } else { return element_traits::eof(); } } }; //////////////////////////////////////////////////////////////////////////////////////////////// template< class sequence_model , class P1 , class P2 , class P3 , class P4 > class output_buffer : public detail::buffer_base { private: typedef detail::buffer_base base; typedef typename base::element element; typedef typename base::element_traits element_traits; static const size_t buffer_size = base::buffer_size; typedef typename element_traits::int_type int_type; typedef typename sequence_model::concept sequence_concept; public: output_buffer(sequence_concept& sequence) : base(sequence) {} private: int sync() { overflow(element_traits::eof()); return 0; } int_type overflow(int_type c) { base::pre_overflow(); get_sequence().write(pbase(), (pptr() - pbase()) * sizeof(element)); setp(pbase(), epptr()); if (!element_traits::eq_int_type(c, element_traits::eof())) { element e = element_traits::to_char_type(c); get_sequence().write(&e, sizeof(element)); } return !element_traits::eof(); } }; //////////////////////////////////////////////////////////////////////////////////////////////// namespace detail { //////////////////////////////////////////////////////////////////////////////////////////////// template class find_parameter { private: struct equal_name { template struct apply { typedef typename tt::is_same::type type; }; }; typedef typename mpl::find_if::type result_iterator; public: typedef typename mpl::if_< typename tt::is_same< typename mpl::end::type, result_iterator >::type, default_parameter, typename result_iterator::type >::type type; }; //////////////////////////////////////////////////////////////////////////////////////////////// template class optional_parameters > { private: typedef mpl::vector parameters; typedef typename find_parameter< element_tag, parameters >::type provided_element; typedef typename find_parameter< element_traits_tag, parameters >::type provided_element_traits; typedef typename find_parameter< allocator_tag, parameters >::type provided_allocator; typedef typename find_parameter< buffer_size_tag, parameters >::type provided_buffer_size; public: // default element is char typedef typename mpl::if_< typename tt::is_same< provided_element, default_parameter >::type, char, typename provided_element::type >::type element; // default element_traits is std::char_traits typedef typename mpl::if_< typename tt::is_same< provided_element_traits, default_parameter >::type, std::char_traits, typename provided_element_traits::type >::type element_traits; // default allocator is std::allocator typedef typename mpl::if_< typename tt::is_same< provided_allocator, default_parameter >::type, std::allocator, typename provided_allocator::type >::type allocator; // default buffer_size is 0x100 elements typedef typename mpl::if_< typename tt::is_same< provided_buffer_size, default_parameter >::type, mpl::integral_c, typename provided_buffer_size::type >::type buffer_size; }; //////////////////////////////////////////////////////////////////////////////////////////////// } // namespace detail //////////////////////////////////////////////////////////////////////////////////////////////// } // namespace sequence_buffer //////////////////////////////////////////////////////////////////////////////////////////////// #pragma warning(pop) ////////////////////////////////////////////////////////////////////////////////////////////////