fbstring IOBuf::moveToFbString() {
  // we need to save useHeapFullStorage and the observerListHead since
  // sharedInfo() may not be valid after fbstring str
  bool useHeapFullStorage = false;
  SharedInfoObserverEntryBase* observerListHead = nullptr;
  // malloc-allocated buffers are just fine, everything else needs
  // to be turned into one.
  if (!sharedInfo() || // user owned, not ours to give up
      sharedInfo()->freeFn || // not malloc()-ed
      headroom() != 0 || // malloc()-ed block doesn't start at beginning
      tailroom() == 0 || // no room for NUL terminator
      isShared() || // shared
      isChained()) { // chained
    // We might as well get rid of all head and tailroom if we're going
    // to reallocate; we need 1 byte for NUL terminator.
    coalesceAndReallocate(0, computeChainDataLength(), this, 1);
  } else {
    auto info = sharedInfo();
    if (info) {
      // if we do not call coalesceAndReallocate
      // we might need to call SharedInfo::releaseStorage()
      // and/or SharedInfo::invokeAndDeleteEachObserver()
      useHeapFullStorage = info->useHeapFullStorage;
      // save the observerListHead
      // the coalesceAndReallocate path will call
      // decrementRefcount and freeExtBuffer if needed
      // so the observer lis notification is needed here
      observerListHead = info->observerListHead;
      info->observerListHead = nullptr;
    }
  }

  // Ensure NUL terminated
  *writableTail() = 0;
  fbstring str(
      reinterpret_cast<char*>(writableData()),
      length(),
      capacity(),
      AcquireMallocatedString());

  if (io_buf_free_cb && sharedInfo() && sharedInfo()->userData) {
    io_buf_free_cb(
        writableData(), reinterpret_cast<size_t>(sharedInfo()->userData));
  }

  SharedInfo::invokeAndDeleteEachObserver(
      observerListHead, [](auto& entry) { entry.afterReleaseExtBuffer(); });

  if (flags() & kFlagFreeSharedInfo) {
    delete sharedInfo();
  } else {
    if (useHeapFullStorage) {
      SharedInfo::releaseStorage(sharedInfo());
    }
  }

  // Reset to a state where we can be deleted cleanly
  flagsAndSharedInfo_ = 0;
  buf_ = nullptr;
  clear();
  return str;
}
fbstring IOBuf::moveToFbString() {
   
   
  bool useHeapFullStorage = false;
  SharedInfoObserverEntryBase* observerListHead = nullptr;
   
   
  if (!sharedInfo() ||  
      sharedInfo()->freeFn ||  
      headroom() != 0 ||  
      tailroom() == 0 ||  
      isShared() ||  
      isChained()) {  
     
     
    coalesceAndReallocate(0, computeChainDataLength(), this, 1);
  } else {
    auto info = sharedInfo();
    if (info) {
       
       
       
      useHeapFullStorage = info->useHeapFullStorage;
       
       
       
       
      observerListHead = info->observerListHead;
      info->observerListHead = nullptr;
    }
  }

   
  *writableTail() = 0;
  fbstring str(
      reinterpret_cast<char*>(writableData()),
      length(),
      capacity(),
      AcquireMallocatedString());

  if (io_buf_free_cb && sharedInfo() && sharedInfo()->userData) {
    io_buf_free_cb(
        writableData(), reinterpret_cast<size_t>(sharedInfo()->userData));
  }

  SharedInfo::invokeAndDeleteEachObserver(
      observerListHead, [](auto& entry) { entry.afterReleaseExtBuffer(); });

  if (flags() & kFlagFreeSharedInfo) {
    delete sharedInfo();
  } else {
    if (useHeapFullStorage) {
      SharedInfo::releaseStorage(sharedInfo());
    }
  }

   
  flagsAndSharedInfo_ = 0;
  buf_ = nullptr;
  clear();
  return str;
}