Анимация
JavaScript
|
Главная Библионтека Буфер вывода настроен так, что функция overflow() вызывается, когда еще остается место для одного символа. Если функция overflow() вызывается с аргументом, отличным от EOF, то соответствующий символ может быть помещен в текущую позицию записи, поскольку указатель на нее не выходит за пределы конечного указателя. После того как аргумент overflow() будет помещен в позицию записи, буфер можно очистить. Именно эта задача решается функцией flushBuffer(). Функция записывает символы в стандартный канал вывода (дескриптор 1) при помощи фзшкции writeQ. Функция pbumpO потокового буфера возвращает позицию записи к началу буфера. Функция overflowO вставляет в буфер символ, ставший причиной вызова overflowO, если он отличен от EOF. Затем функция pbunfip() смещает текущую позицию записи, чтобы она отражала новый конец блока буферизованных символов. Тем самым позиция записи временно смещается за конечную позицию (epptrO). lOiacc также содержит виртуальную функцию syncO, предназначенную для синхронизации текущего состояния потокового буфера с непосредственным носителем данных. Обычно синхронизация ограничивается простой очисткой буфера. Для небуферизованных версий переопределять эту функцию не обязательно, поскольку нет самого буфера, который можно было бы очистить. Виртуальный деструктор обеспечивает вывод данных, остающихся в буфере при его уничтожении. Эти функции переопределяются для большинства потоковых буферов. Если внешнее представление имеет особую структуру, возможно, придется переопределить дополнительные функции, например функции seekoff() и seekpos(), для управления позицией записи. Пользовательские буферы ввода в сущности, механизм ввода работает по тем же принципам, что и механизм вывода. Однако для ввода также существует возможность отмены последнего чтения. Функции sungetcO (вызывается функцией unget() входного потока данных) и sputbackcO (вызывается функцией putback() входного потока данных) используются для восстановления потокового буфера в состоянии перед последним чтением. Также существует возможность чтения следующего символа без перемещения позиции чтения. Следовательно, при реализации чтения из потокового буфера приходится переопределять больше функций, чем при реализации записи в потоковый буфер. Для буфера, используемого для записи символов, поддерживаются три указателя, которые могут быть получены функциями еЬаскО, gptrO и egptr() (рис. 13.5): О еЬаскО («база ввода») - определяет начало буфера ввода или конец области отката; О gptrO («указатель ввода») - определяет текущую позицию чтения; О egptrO («конец ввода») - определяет конец буфера ввода. •back о gptro •gptr() Рис. 13.5. Интерфейс чтения из потоковых буферов Символы, находящиеся между начальной и конечной позициями, были переданы из внешнего представления в память программы, но еще ожидают обработки. Одиночные символы читаются функциями sgetc() и sbumpc(). Отличие между этими функциями состоит в том, что функция sbumpcO увеличивает указатель текущей позиции ввода, а функция sgetc() этого не делает. Если буфер будет полностью прочитан (gptr()==egptr()), значит, доступных символов нет и буфер необходимо заполнять заново. Для этого вызывается виртуальная функция underflow(), отвечающая за чтение данных. С другой стороны, функция sbumpc() при отсутствии символов вызывает виртуальную функцию uflowO. По умолчанию uflowO просто вызывает underflowO, а затем увеличивает указатель. По умолчанию версия underflowO в базовом классе basic streambuf возвращает EOF, то есть признак невозможности дальнейшего чтения с использованием стандартной реализации. Функция sgetnO предназначена для чтения сразу нескольких символов. Она перепоручает работу виртуальной функции xsgetnO. В реализации по умолчанию xsgetnO просто читает символы, вызывая для каждого из них sbumpcO. По аналогии с функцией xsputnO при записи функция xsgetnO используется для оптимизации чтения нескольких символов. В отличие от вывода для ввода недостаточно переопределить одну функцию. Вам придется либо выполнить настройку буфера, либо, по крайней мере, реализовать функции underflowO и uflow(). Дело в том, что функция underflowO не перемещается за текущий символ, однако она может быть вызвана из sgetc(). Перемещение к следующему символу приходится выполнять путем манипуляций с буфером или вызовом uflow(). В любом случае функция underflow() должна быть реализована для любого потокового буфера, поддерживающего чтение символов. Если реализованы обе функции, underflowO и uflow(), в настройке буфера нет необходимости. Настройка буфера чтения осуществляется функцией setg(), получающей следующие три аргумента (именно в таком порядке): О указатель на начало буфера (еЬаскО); О указатель на текущую позицию чтения (gptrO); О указатель на конец буфера (egptrO). В отличие от setpO функция setgO вызывается с тремя аргументами. Это необходимо для того, чтобы вы могли зарезервировать память для символов, возвращаемых в поток данных. Таким образом, при настройке буфера ввода желательно, чтобы некоторые символы (по крайней мере один) уже были прочитаны, но еще не сохранены в буфере. Как упоминалось выше, символы можно вернуть в буфер чтения с помощью функций sputbackcO и sungetc(). Функция sputbackcO получает возвращаемый символ в аргументе и проверяет, что именно этот символ был прочитан последним. Обе функции уменьшают указатель текущей позиции чтения, если это возможно. Очевидно, это возможно только в том случае, если указатель чтения не находится в начале буфера. При попытке возврата символа в начале буфера вызывается виртуальная функция pbackfaii(). Переопределяя эту функцию, можно реализовать механизм восстановления прежней позиции чтения даже в этом случае. В базовом классе basic streambuf соответствующее поведение не определено. Таким образом, на практике возврат на произвольное количество символов невозможен. Для потоков данных, не использующих буферизацию, следует реализовать функцию pbackfaii(), потому что в общем случае предполагается, что хотя бы один символ может быть возвращен в поток. Когда буфер заполняется заново, возникает другая проблема: если прежние данные не были сохранены в буфере, возврат даже одного символа невозможен. По этой причине реализация underflowO часто перемещает несколько последних символов (например, четыре) в начало буфера и присоединяет читаемые символы после ннх. Это позволяет вернуть хотя бы несколько символов перед тем, как будет вызвана функция pbackfaii(). Следующий пример показывает, как может выглядеть подобная реализация. Класс inbuf реализует буфер ввода, рассчитанный на десять символов. Буфер условно делится на две части: «область возврата» из четырех символов и «нормальный» буфер ввода из шести символов. io/lnbufl.hpp finclude <cstd1o> linclude <cstring> linclude <streafiibuf> extern "C" { int read (int fd. char* buf. int num): class inbuf ; public std;;streambuf { protected: /* Буфер данных; * - до четырех символов в области возврата. * - до шести символов в обычной буфере ввода. */ static const int bufferSize = 10: Размер буфера данных char buffer[bufferSize]: Буфер public: /* Конструктор * - Инициализация пустого буфера * - без области возврата * «> принудительный вызов underflowO* */ 0 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 206 207 208 209 [ 210 ] 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |