--- /dev/null
+//
+// reader::StringReaderの実装を提供します。
+//
+// StringReaderは、単純な文字列から、バイト単位の読み出しをサポートするための
+// 実装です。
+// StringReaderでは、渡された文字列のエンコーディングを考慮しません。
+// そのため、マルチバイト文字列を渡した場合、マルチバイトの解釈は行わず、
+// その場合でも単純なバイト列として扱います。
+//
+// StringReaderにおける読み出し位置は、先頭が0であるとされます。
+// 4文字渡して、2文字読出した時点で2となります。
+//
+#include "src/string_reader.h"
+
+namespace reader = utakata::reader;
+
+// 保持している文字列の現在の読み出し位置から1バイト読み出して返します。
+// この関数では、読み出し位置を更新します。
+//
+// IsEofがtrueを返す場合に実行すると、reader::EndOfDeviceExceptionが送出
+// されます。
+// コンストラクタに空文字列が渡されている場合、常に例外を返します。
+unsigned char reader::StringReader::Read()
+{
+ if (iterator_ == buffer_.end()) {
+ throw reader::EndOfDeviceException("end of String `" + buffer_ + "`");
+ }
+
+ unsigned char byte = *iterator_++;
+ ++pos_;
+ return byte;
+}
+
+// 保持している文字列の現在の読み出し位置から指定されたバイト数だけ
+// 読み出して返します。この関数では、読み出し位置を更新します。
+// 指定されたバイト数未満で末尾に到達した場合、読出したデータだけが返されます。
+//
+// IsEofがtrueを返す場合に実行すると、reader::EndOfDeviceExceptionが送出
+// されます。
+// コンストラクタに空文字列が渡されている場合、常に例外を返します。
+//
+// 引数としてゼロ以下の数値が渡された場合、返されるバイト列のサイズは0になります。
+std::vector<unsigned char> reader::StringReader::Read(size_t num) {
+ if (num <= 0)
+ {
+ return std::vector<unsigned char>();
+ }
+
+ if (iterator_ == buffer_.end()) {
+ throw reader::EndOfDeviceException("end of String `" + buffer_ + "`");
+ }
+
+ std::vector<unsigned char> ret;
+ for (size_t i = 0; i < num && iterator_ != buffer_.end(); ++i) {
+ ret.push_back(*iterator_++);
+ }
+
+ pos_ += num;
+
+ return ret;
+}
+
+// 保持している文字列の現在の読み出し位置から、1バイトだけ
+// 読み出して返します。この関数では、読み出し位置は更新されません。
+// 指定されたバイト数未満で末尾に到達した場合、読出したデータだけが返されます。
+//
+// IsEofがtrueを返す場合に実行すると、reader::EndOfDeviceExceptionが送出
+// されます。
+// コンストラクタに空文字列が渡されている場合、常に例外を返します。
+unsigned char reader::StringReader::Peek() {
+ if (iterator_ == buffer_.end()) {
+ throw reader::EndOfDeviceException("end of String `" + buffer_ + "`");
+ }
+
+ return *iterator_;
+}
+
+// 保持している文字列の現在の読み出し位置から、指定されたバイト数だけ
+// 読み出して返します。この関数では、読み出し位置は更新されません。
+// 指定されたバイト数未満で末尾に到達した場合、読出したデータだけが返されます。
+//
+// IsEofがtrueを返す場合に実行すると、reader::EndOfDeviceExceptionが送出
+// されます。
+// コンストラクタに空文字列が渡されている場合、常に例外を返します。
+//
+// 引数としてゼロ以下の値が渡された場合、返り値のサイズは0となります。
+std::vector<unsigned char> reader::StringReader::Peek(size_t num) {
+ if (num <= 0) {
+ return std::vector<unsigned char>();
+ }
+
+ if (iterator_ == buffer_.end()) {
+ throw reader::EndOfDeviceException("end of String `" + buffer_ + "`");
+ }
+
+ reader::StringReader::internal_iterator peeker = iterator_;
+ std::vector<unsigned char> ret;
+ for (size_t i = 0; i < num && peeker != buffer_.end(); ++i) {
+ ret.push_back(*peeker++);
+ }
+
+ return ret;
+}
+
+// 現在の読み出し位置を返します。PeekではGetPosの値は更新されません。
+size_t reader::StringReader::GetPos() const {
+ return pos_;
+}
+
+// 読み出し位置を1バイト分だけ戻します。
+// 先頭で実行された場合には何も行いません。
+void reader::StringReader::Unget() {
+ if (iterator_ != buffer_.begin()) {
+ --iterator_;
+ --pos_;
+ }
+}
+
+// 読み出し位置を、指定された方向に指定された量だけ移動します。
+// 移動量が、先頭、または末尾を超えた場合、それぞれ先頭、末尾に
+// 位置します。
+// seekpos以下の値で、移動した量を返します。
+//
+// seekposにゼロ以下の値が渡された場合、何も行いません。
+size_t reader::StringReader::Seek(
+ size_t seekpos, reader::StringReader::SeekDirection direction) {
+ if (seekpos <= 0) {
+ return 0;
+ }
+
+ int count = 0;
+ if (direction == reader::IReader::kForward) {
+ for (size_t i = 0; i < seekpos && iterator_ != buffer_.end();
+ ++i, ++pos_, ++iterator_, ++count) {}
+ if (pos_ > buffer_.size()) {
+ pos_ = buffer_.size();
+ }
+
+ } else {
+ for (size_t i = 0; i < seekpos && iterator_ != buffer_.begin();
+ ++i, --pos_, --iterator_, ++count) {}
+ if (pos_ < 0) {
+ pos_ = 0;
+ }
+ }
+
+ return count;
+}
+
+// 読み出し位置を先頭に戻します。
+void reader::StringReader::Begin() {
+ pos_ = 0;
+ iterator_ = buffer_.begin();
+}
+
+// 現在保持している読出し対象のサイズを返します。
+size_t reader::StringReader::GetSize() const {
+ return buffer_.size();
+}
+
+// 現在の読み出し位置が末尾である場合、trueを返します。
+bool reader::StringReader::IsEof() const {
+ return iterator_ == buffer_.end();
+}