- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

glinebuffer.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2001-2013 Graeme Walker <graeme_walker@users.sourceforge.net>
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // ===
17 //
18 // glinebuffer.cpp
19 //
20
21 #include "gdef.h"
22 #include "glimits.h"
23 #include "gnet.h"
24 #include "glinebuffer.h"
25 #include "gdebug.h"
26 #include "gassert.h"
27
28 unsigned long GNet::LineBuffer::m_limit = G::limits::net_line_limit ; // denial-of-service line-length limit
29
30 GNet::LineBuffer::LineBuffer( const std::string & eol , bool do_throw ) :
31 m_eol(eol) ,
32 m_eol_length(eol.length()) ,
33 m_p(std::string::npos) ,
34 m_current_valid(false) ,
35 m_throw(do_throw) ,
36 m_locked(false)
37 {
38 G_ASSERT( !eol.empty() ) ;
39 }
40
41 void GNet::LineBuffer::lock()
42 {
43 m_locked = true ;
44 }
45
46 void GNet::LineBuffer::unlock( std::string::size_type n )
47 {
48 m_locked = false ;
49 m_current_valid = false ;
50 m_store.erase( 0U , n ) ;
51 if( m_p != std::string::npos )
52 m_p -= n ;
53 }
54
55 void GNet::LineBuffer::add( const char * p , std::string::size_type n )
56 {
57 G_ASSERT( p != NULL ) ;
58 check( n ) ;
59 m_store.append( p , n ) ;
60 fix( n ) ;
61 }
62
63 void GNet::LineBuffer::add( const std::string & s )
64 {
65 check( s.length() ) ;
66 m_store.append( s ) ;
67 fix( s.length() ) ;
68 }
69
70 void GNet::LineBuffer::check( std::string::size_type n )
71 {
72 G_ASSERT( !m_locked ) ;
73 if( (m_store.length()+n) > m_limit )
74 {
75 std::string::size_type total = m_store.size() + m_current.size() + n ;
76
77 m_p = std::string::npos ;
78 m_current.erase() ;
79 m_current_valid = false ;
80 m_store.erase() ;
81
82 if( m_throw )
83 throw Overflow() ;
84 else
85 G_ERROR( "GNet::LineBuffer::check: line too long: discarding " << total << " bytes" ) ;
86 }
87 }
88
89 void GNet::LineBuffer::fix( std::string::size_type n )
90 {
91 if( m_p == std::string::npos )
92 {
93 std::string::size_type start = m_store.length() - n ;
94 start = (start+1U) > m_eol_length ? (start+1U-m_eol_length) : 0U ;
95 m_p = m_store.find( m_eol , start ) ;
96 }
97 }
98
99 bool GNet::LineBuffer::more() const
100 {
101 return m_p != std::string::npos ;
102 }
103
104 const std::string & GNet::LineBuffer::current() const
105 {
106 G_ASSERT( m_p != std::string::npos ) ;
107 G_ASSERT( !m_locked ) ;
108
109 if( ! m_current_valid )
110 {
111 LineBuffer * this_ = const_cast<LineBuffer*>(this) ;
112 this_->m_current = std::string( m_store , 0U , m_p ) ;
113 this_->m_current_valid = true ;
114 }
115 return m_current ;
116 }
117
118 void GNet::LineBuffer::discard()
119 {
120 G_ASSERT( m_p != std::string::npos ) ;
121 G_ASSERT( !m_locked ) ;
122
123 m_current.erase() ;
124 m_current_valid = false ;
125 m_store.erase( 0U , m_p + m_eol_length ) ;
126 m_p = m_store.find( m_eol ) ;
127 }
128
129 std::string GNet::LineBuffer::line()
130 {
131 std::string s( current() ) ;
132 discard() ;
133 return s ;
134 }
135
136 // ==
137
138 bool GNet::LineBufferIterator::more() const
139 {
140 return m_b.m_p != std::string::npos ;
141 }
142
143 const std::string & GNet::LineBufferIterator::line()
144 {
145 // this is optimised code -- the optimisation applies in high-throughput
146 // situations when the network code dumps in more than one line of
147 // text from each network event -- the discard() above is effectively
148 // done once per add() rather than once per line
149 const std::string::size_type n = m_b.m_p - m_n ;
150 m_b.m_current.resize( n ) ;
151 m_b.m_current.replace( 0U , n , m_b.m_store.data() + m_n , n ) ;
152 m_n = m_b.m_p + m_b.m_eol_length ;
153 m_b.m_p = m_n == m_store_length ? std::string::npos : m_b.m_store.find(m_b.m_eol,m_n) ;
154 return m_b.m_current ;
155 }
156
GNet::LineBuffer::add
void add(const std::string &segment)
Adds a data segment.
Definition: glinebuffer.cpp:63
GNet::LineBuffer::current
const std::string & current() const
Returns the current line, without extracting it.
Definition: glinebuffer.cpp:104
md5::size_type
std::string::size_type size_type
A std::size_t type.
Definition: md5.h:43
GNet::LineBufferIterator::more
bool more() const
Returns true if there is a line() to be had.
Definition: glinebuffer.cpp:138
GNet::LineBuffer::LineBuffer
LineBuffer(const std::string &eol=std::string("\n"), bool do_throw_on_overflow=false)
Constructor.
Definition: glinebuffer.cpp:30
glinebuffer.h
glimits.h
G_ASSERT
#define G_ASSERT(test)
Definition: gassert.h:30
gassert.h
GNet::LineBufferIterator::line
const std::string & line()
Returns the current line and increments the iterator.
Definition: glinebuffer.cpp:143
G_ERROR
#define G_ERROR(expr)
Definition: glog.h:108
G::limits::net_line_limit
Definition: glimits.h:48
GNet::LineBuffer
A class which does line buffering.
Definition: glinebuffer.h:52
GNet::LineBuffer::line
std::string line()
Extracts a line and returns it as a string.
Definition: glinebuffer.cpp:129
GNet::LineBuffer::more
bool more() const
Returns true if there are complete line(s) to be extracted.
Definition: glinebuffer.cpp:99
gdebug.h
GNet::LineBuffer::discard
void discard()
Discards the current line.
Definition: glinebuffer.cpp:118