summaryrefslogtreecommitdiff
path: root/boost/iostreams/detail/buffer.hpp
blob: 72400f04ca1001f838adb5ee7d54eab2864a8c9b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
// (C) Copyright 2003-2007 Jonathan Turkanis
// 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.)

// See http://www.boost.org/libs/iostreams for documentation.

#ifndef BOOST_IOSTREAMS_DETAIL_BUFFERS_HPP_INCLUDED
#define BOOST_IOSTREAMS_DETAIL_BUFFERS_HPP_INCLUDED

#if defined(_MSC_VER)
# pragma once
#endif              

#include <algorithm>                           // swap.
#include <memory>                              // allocator.
#include <boost/config.hpp>                    // member templates.
#include <boost/iostreams/char_traits.hpp>
#include <boost/iostreams/detail/ios.hpp>      // streamsize.
#include <boost/iostreams/read.hpp>
#include <boost/iostreams/traits.hpp>          // int_type_of.
#include <boost/iostreams/checked_operations.hpp>
#include <boost/mpl/if.hpp>
#include <boost/type_traits/is_same.hpp>

namespace boost { namespace iostreams { namespace detail {

//----------------Buffers-----------------------------------------------------//

//
// Template name: buffer
// Description: Character buffer.
// Template parameters:
//     Ch - The character type.
//     Alloc - The Allocator type.
//
template< typename Ch,
          typename Alloc = std::allocator<Ch> >
class basic_buffer {
private:
#ifndef BOOST_NO_STD_ALLOCATOR
    typedef typename Alloc::template rebind<Ch>::other allocator_type;
#else
    typedef std::allocator<Ch> allocator_type;
#endif
public:
    basic_buffer();
    basic_buffer(std::streamsize buffer_size);
    ~basic_buffer();
    void resize(std::streamsize buffer_size);
    Ch* begin() const { return buf_; }
    Ch* end() const { return buf_ + size_; }
    Ch* data() const { return buf_; }
    std::streamsize size() const { return size_; }
    void swap(basic_buffer& rhs);
private:
    // Disallow copying and assignment.
    basic_buffer(const basic_buffer&);
    basic_buffer& operator=(const basic_buffer&);
    Ch*              buf_;
    std::streamsize  size_;
};

template<typename Ch, typename Alloc>
void swap(basic_buffer<Ch, Alloc>& lhs, basic_buffer<Ch, Alloc>& rhs)
{ lhs.swap(rhs); }

//
// Template name: buffer
// Description: Character buffer with two pointers accessible via ptr() and
//      eptr().
// Template parameters:
//     Ch - A character type.
//
template< typename Ch,
          typename Alloc = std::allocator<Ch> >
class buffer : public basic_buffer<Ch, Alloc> {
private:
    typedef basic_buffer<Ch, Alloc> base;
public:
    typedef iostreams::char_traits<Ch> traits_type;
    using base::resize; 
    using base::data; 
    using base::size;
    typedef Ch* const const_pointer;
    buffer(std::streamsize buffer_size);
    Ch* & ptr() { return ptr_; }
    const_pointer& ptr() const { return ptr_; }
    Ch* & eptr() { return eptr_; }
    const_pointer& eptr() const { return eptr_; }
    void set(std::streamsize ptr, std::streamsize end);
    void swap(buffer& rhs);

    // Returns an int_type as a status code.
    template<typename Source>
    typename int_type_of<Source>::type fill(Source& src) 
    {
        using namespace std;
        std::streamsize keep;
        if ((keep = static_cast<std::streamsize>(eptr_ - ptr_)) > 0)
            traits_type::move(
                this->data(),
                ptr_, 
                static_cast<size_t>(keep)
            );
        set(0, keep);
        std::streamsize result = 
            iostreams::read(src, this->data() + keep, this->size() - keep);
        if (result != -1)
            this->set(0, keep + result);
        return result == -1 ?
            traits_type::eof() :
                result == 0 ?
                    traits_type::would_block() :
                    traits_type::good();

    }

    // Returns true if one or more characters were written.
    template<typename Sink>
    bool flush(Sink& dest) 
    {
        using namespace std;
        std::streamsize amt = static_cast<std::streamsize>(eptr_ - ptr_);
        std::streamsize result = iostreams::write_if(dest, ptr_, amt);
        if (result < amt) {
            traits_type::move( this->data(), 
                               ptr_ + static_cast<size_t>(result), 
                               static_cast<size_t>(amt - result) );
        }
        this->set(0, amt - result);
        return result != 0;
    }
private:
    Ch *ptr_, *eptr_;
};

template<typename Ch, typename Alloc>
void swap(buffer<Ch, Alloc>& lhs, buffer<Ch, Alloc>& rhs)
{ lhs.swap(rhs); }

//--------------Implementation of basic_buffer--------------------------------//

template<typename Ch, typename Alloc>
basic_buffer<Ch, Alloc>::basic_buffer() : buf_(0), size_(0) { }

template<typename Ch, typename Alloc>
basic_buffer<Ch, Alloc>::basic_buffer(std::streamsize buffer_size)
    : buf_(static_cast<Ch*>(allocator_type().allocate(
           static_cast<BOOST_DEDUCED_TYPENAME Alloc::size_type>(buffer_size), 0))), 
      size_(buffer_size) // Cast for SunPro 5.3.
    { }

template<typename Ch, typename Alloc>
inline basic_buffer<Ch, Alloc>::~basic_buffer()
{
    if (buf_) {
        allocator_type().deallocate(buf_,
            static_cast<BOOST_DEDUCED_TYPENAME Alloc::size_type>(size_));
    }
}

template<typename Ch, typename Alloc>
inline void basic_buffer<Ch, Alloc>::resize(std::streamsize buffer_size)
{
    if (size_ != buffer_size) {
        basic_buffer<Ch, Alloc> temp(buffer_size);
        std::swap(size_, temp.size_);
        std::swap(buf_, temp.buf_);
    }
}

template<typename Ch, typename Alloc>
void basic_buffer<Ch, Alloc>::swap(basic_buffer& rhs) 
{ 
    std::swap(buf_, rhs.buf_); 
    std::swap(size_, rhs.size_); 
}

//--------------Implementation of buffer--------------------------------------//

template<typename Ch, typename Alloc>
buffer<Ch, Alloc>::buffer(std::streamsize buffer_size)
    : basic_buffer<Ch, Alloc>(buffer_size) { }

template<typename Ch, typename Alloc>
inline void buffer<Ch, Alloc>::set(std::streamsize ptr, std::streamsize end)
{ 
    ptr_ = data() + ptr; 
    eptr_ = data() + end; 
}

template<typename Ch, typename Alloc>
inline void buffer<Ch, Alloc>::swap(buffer& rhs) 
{ 
    base::swap(rhs); 
    std::swap(ptr_, rhs.ptr_); 
    std::swap(eptr_, rhs.eptr_); 
}

//----------------------------------------------------------------------------//

} } } // End namespaces detail, iostreams, boost.

#endif // #ifndef BOOST_IOSTREAMS_DETAIL_BUFFERS_HPP_INCLUDED