FBString分析与使用

2016-07-11  本文已影响593人  扫帚的影子

FBString简介

fbstring is a drop-in replacement for std::string. The main benefit of fbstring is significantly increased performance on virtually all important primitives. This is achieved by using a three-tiered storage strategy and by cooperating with the memory allocator. In particular, fbstring is designed to detect use of jemalloc and cooperate with it to achieve significant improvements in speed and memory usage.

简单来说,使用了三层存储策略+内存分配策略+大小端支持,特别是配合使用 jemalloc, 减少磁盘碎片,加快并发下的分配速度和性能。

存储策略

核心实现

fbstring_core

struct MediumLarge {
    Char * data_;
    size_t size_;
    size_t capacity_;
    size_t capacity() const {
      return kIsLittleEndian
        ? capacity_ & capacityExtractMask
        : capacity_ >> 2;
    }
    void setCapacity(size_t cap, Category cat) {
        capacity_ = kIsLittleEndian
          ? cap | static_cast<category_type>(cat)
          : (cap << 2) | static_cast<category_type>(cat);
    }
  };

  union {
    Char small_[sizeof(MediumLarge) / sizeof(Char)];
    MediumLarge ml_;
  };

使用了union,其中small_用于small状态时的字符串存储,MediumLarge用于mediumlarge状态时的字符串存储;
使用small_时,其最后一格存储 maxSmallSize - 当前字符串实现大小
这个看起来还是一目了然,很清楚的。

struct RefCounted {
    std::atomic<size_t> refCount_;
    Char data_[1];

    static RefCounted * fromData(Char * p) {
      return static_cast<RefCounted*>(
        static_cast<void*>(
          static_cast<unsigned char*>(static_cast<void*>(p))
          - sizeof(refCount_)));
    }

    static size_t refs(Char * p) {
      return fromData(p)->refCount_.load(std::memory_order_acquire);
    }

    static void incrementRefs(Char * p) {
      fromData(p)->refCount_.fetch_add(1, std::memory_order_acq_rel);
    }

    static void decrementRefs(Char * p) {
      auto const dis = fromData(p);
      size_t oldcnt = dis->refCount_.fetch_sub(1, std::memory_order_acq_rel);
      assert(oldcnt > 0);
      if (oldcnt == 1) {
        free(dis);
      }
    }

    static RefCounted * create(size_t * size) {
      // Don't forget to allocate one extra Char for the terminating
      // null. In this case, however, one Char is already part of the
      // struct.
      const size_t allocSize = goodMallocSize(
        sizeof(RefCounted) + *size * sizeof(Char));
      auto result = static_cast<RefCounted*>(checkedMalloc(allocSize));
      result->refCount_.store(1, std::memory_order_release);
      *size = (allocSize - sizeof(RefCounted)) / sizeof(Char);
      return result;
    }

    static RefCounted * create(const Char * data, size_t * size) {
      const size_t effectiveSize = *size;
      auto result = create(size);
      fbstring_detail::pod_copy(data, data + effectiveSize, result->data_);
      return result;
    }

    static RefCounted * reallocate(Char *const data,
                                   const size_t currentSize,
                                   const size_t currentCapacity,
                                   const size_t newCapacity) {
      assert(newCapacity > 0 && newCapacity > currentSize);
      auto const dis = fromData(data);
      assert(dis->refCount_.load(std::memory_order_acquire) == 1);
      // Don't forget to allocate one extra Char for the terminating
      // null. In this case, however, one Char is already part of the
      // struct.
      auto result = static_cast<RefCounted*>(
             smartRealloc(dis,
                          sizeof(RefCounted) + currentSize * sizeof(Char),
                          sizeof(RefCounted) + currentCapacity * sizeof(Char),
                          sizeof(RefCounted) + newCapacity * sizeof(Char)));
      assert(result->refCount_.load(std::memory_order_acquire) == 1);
      return result;
    }
  };

看着代码多,其实很简单。
large状态使用COW技术就需要引用计数的存在,这个RefCounted就实现了这个,利用了std::atomic作计数,data_指向需要作计数的实体。fromData(Char p)*函数从需作计数的实体指针得到其对应的RefCounted实体的指针。

构造函数

fbstring_core(fbstring_core&& goner) noexcept {
    // Take goner's guts
    ml_ = goner.ml_;
    // Clean goner's carcass
    goner.reset();
  }

交换函数

auto const t = ml_;
ml_ = rhs.ml_;
rhs.ml_ = t;

实现简单,用处多多

### 访问函数
- const Char * data() const
- const Char * c_str()
- Char * mutable_data()
large状态的,要作拷贝啦~~~COW

### 回缩函数
- void shrink(const size_t delta)
size减少delta. "得儿塔" 让我想起了中学的数学课~~~还有我同桌

### Reserve函数
- void reserve(size_t minCapacity, bool disableSSO)
让这个string的capacity至少有minCapacity这么大,这个函数完美诠释了三种状态的转换。

## basic_fbstring
- 这个其实没什么说的,用fbstring_core的接口把std::string的所有接口都实现了一遍。
- 最后还附赠了一个 **typedef basic_fbstring<char> fbstring** 外加一个**FOLLY_FBSTRING_HASH**

# FBString作者:[Andrei Alexandrescu](https://zh.wikipedia.org/wiki/%E5%AE%89%E5%BE%B7%E7%83%88%C2%B7%E4%BA%9E%E6%AD%B7%E5%B1%B1%E5%BE%B7%E9%9B%B7%E6%96%AF%E5%BA%AB) C++和D語言專家
上一篇 下一篇

猜你喜欢

热点阅读