+ void readFixedStringSlow(std::string* str, size_t len) {
+ for (size_t available; (available = length()) < len; ) {
+ str->append(reinterpret_cast<const char*>(data()), available);
+ if (UNLIKELY(!tryAdvanceBuffer())) {
+ throw std::out_of_range("string underflow");
+ }
+ len -= available;
+ }
+ str->append(reinterpret_cast<const char*>(data()), len);
+ offset_ += len;
+ advanceBufferIfEmpty();
+ }
+
+ size_t pullAtMostSlow(void* buf, size_t len) {
+ uint8_t* p = reinterpret_cast<uint8_t*>(buf);
+ size_t copied = 0;
+ for (size_t available; (available = length()) < len; ) {
+ memcpy(p, data(), available);
+ copied += available;
+ if (UNLIKELY(!tryAdvanceBuffer())) {
+ return copied;
+ }
+ p += available;
+ len -= available;
+ }
+ memcpy(p, data(), len);
+ offset_ += len;
+ advanceBufferIfEmpty();
+ return copied + len;
+ }
+
+ void pullSlow(void* buf, size_t len) {
+ if (UNLIKELY(pullAtMostSlow(buf, len) != len)) {
+ throw std::out_of_range("underflow");
+ }
+ }
+
+ size_t skipAtMostSlow(size_t len) {
+ size_t skipped = 0;
+ for (size_t available; (available = length()) < len; ) {
+ skipped += available;
+ if (UNLIKELY(!tryAdvanceBuffer())) {
+ return skipped;
+ }
+ len -= available;
+ }
+ offset_ += len;
+ advanceBufferIfEmpty();
+ return skipped + len;
+ }
+
+ void skipSlow(size_t len) {
+ if (UNLIKELY(skipAtMostSlow(len) != len)) {
+ throw std::out_of_range("underflow");
+ }
+ }
+