+ template <class T>
+ FOLLY_NOINLINE T readSlow() {
+ T val;
+ pullSlow(&val, sizeof(T));
+ return val;
+ }
+
+ 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())) {
+ std::__throw_out_of_range("string underflow");
+ }
+ len -= available;
+ }
+ str->append(reinterpret_cast<const char*>(data()), len);
+ crtPos_ += 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);
+ crtPos_ += len;
+ advanceBufferIfEmpty();
+ return copied + len;
+ }
+
+ void pullSlow(void* buf, size_t len) {
+ if (UNLIKELY(pullAtMostSlow(buf, len) != len)) {
+ std::__throw_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;
+ }
+ crtPos_ += len;
+ advanceBufferIfEmpty();
+ return skipped + len;
+ }
+
+ void skipSlow(size_t len) {
+ if (UNLIKELY(skipAtMostSlow(len) != len)) {
+ std::__throw_out_of_range("underflow");
+ }
+ }
+
+ size_t retreatAtMostSlow(size_t len) {
+ size_t retreated = 0;
+ for (size_t available; (available = crtPos_ - crtBegin_) < len;) {
+ retreated += available;
+ if (UNLIKELY(!tryRetreatBuffer())) {
+ return retreated;
+ }
+ len -= available;
+ }
+ crtPos_ -= len;
+ return retreated + len;
+ }
+
+ void retreatSlow(size_t len) {
+ if (UNLIKELY(retreatAtMostSlow(len) != len)) {
+ std::__throw_out_of_range("underflow");
+ }
+ }
+