可変長配列データベース

では、可変長配列データベースを作成します。ここでの「可変長」とは配列の各要素のサイズが可変であることを意味します。もちろん要素数も可変です。前にも書いたように可変長データを固定長データに分割して固定長データーベースに保存します。分割した固定長データをたどるためのポインタは圧縮して持ちます。可変長配列データベースを1から作成するのは結構大変ですが、既に可変長配列を構成する部品は揃っているので、純粋な可変長配列データベースの実装部分は結構少ないです。

class VariableArray {
public:
  static const size_t headSize = 128;
  static const size_t bodySize = 256;

  // Format:|size(encoded)|body index(encoded)|data...|
  class Head {
  public:
    Head() {
      *record = 0;
    }
    unsigned char record[headSize];
  };
  // Format:|next index(encoded)|data...|
  class Body {
  public:
    unsigned char record[bodySize];
  };

  VariableArray(const std::string &f) {
    initialize(f);
  }

  void initialize(const std::string &f) {
    std::string str = f;
    str.append("_h");
    head.initialize(str);
    str = f;
    str.append("_t");
    body.initialize(str);
  }

  void set(size_t idx, std::vector<unsigned char> &val) {
    set(idx, &val[0], val.size());
  }

  void set(size_t idx, unsigned char *val, size_t size) {
    erase(idx);
    if (idx >= head.getSize()) {
      head.resize(idx + 1);
    }
    unsigned char *ptr = (unsigned char*)&head.at(idx);
    int sizeSize = Codec::encode(size, ptr);
    size_t bodyIndexSize = 1;
    size_t totalSize = size + sizeSize + bodyIndexSize;
    ptr += sizeSize;

    size_t bodyIndex;
    int len;
    if (totalSize > headSize) {
      bodyIndex = body.insert();
      bodyIndexSize = Codec::encode(bodyIndex, ptr);
      len = headSize - sizeSize - bodyIndexSize;
    } else {
      bodyIndex = 0;
      //bodyIndexSize = Codec::encode(bodyIndex, ptr);
      bodyIndexSize = 1;
      len = size;
    }

    ptr += bodyIndexSize;
    memcpy(ptr, val, len);
    while (bodyIndex != 0) {
      size -= len;
      val += len;

      bodyIndexSize = 1;
      totalSize = size + bodyIndexSize;
      if (totalSize > bodySize) {
        size_t ti = body.insert();
        ptr = (unsigned char*)&body.at(bodyIndex);
        bodyIndex = ti;
        bodyIndexSize = Codec::encode(bodyIndex, ptr);
        len = bodySize - bodyIndexSize;
      } else {
        ptr = (unsigned char*)&body.at(bodyIndex);
        bodyIndex = 0;
        *ptr = 0;
        len = size;
      }

      ptr += bodyIndexSize;
      memcpy(ptr, val, len);

    }
  }

  unsigned char *get(size_t idx, size_t &size) {
    unsigned char *ptr = (unsigned char*)&head.at(idx);

    size_t sizeSize;
    size = Codec::decode(ptr, sizeSize);
    if (size == 0) {
      throw Exception("The specified element is empty");
    }
    unsigned char *buf = new unsigned char[size];
    unsigned char *bufptr = buf;
    ptr += sizeSize;
    size_t bodyIndexSize;
    size_t bodyIndex = Codec::decode(ptr, bodyIndexSize);
    ptr += bodyIndexSize;
    int len = headSize - sizeSize - bodyIndexSize;
    len = size > len ? len : size;
    memcpy(bufptr, ptr, len);
    while (bodyIndex != 0) {
      size -= len;
      assert(size > 0);
      bufptr += len;
      ptr = (unsigned char*)&body.at(bodyIndex);
      bodyIndex = Codec::decode(ptr, bodyIndexSize);
      ptr += bodyIndexSize;
      len = bodySize - bodyIndexSize;
      len = size > len ? len : size;;
      memcpy(bufptr, ptr, len);
    }

    return buf;
  }

  void erase(size_t idx) {
    if (idx >= head.getSize()) {
      return;
    }
    unsigned char *headPtr  = (unsigned char*)&head.at(idx);
    unsigned char *ptr = headPtr;
    size_t sizeSize;
    size_t size = Codec::decode(ptr, sizeSize);
    if (size == 0) {
      // already cleared
      return;
    }
    ptr += sizeSize;
    size_t bodyIndexSize;
    size_t bodyIndex = Codec::decode(ptr, bodyIndexSize);
    headPtr[0] = 0;  // size <- 0
    headPtr[1] = 0;  // index <- 0 invalid index
    while (bodyIndex != 0) {
      ptr = (unsigned char*)&body.at(bodyIndex);
      size_t nextIndex = Codec::decode(ptr, bodyIndexSize);
      body.remove(bodyIndex);
      bodyIndex = nextIndex;
    }
    return;
  }

  Array<Head>   head;
  Pool<Body>    body;

};

ということで、ソースを書きなぐってきた感じですので、ちょっと使ってみたいと思っても、かなり使いにくい状態になっていますね。時間を見つけてライブラリにでもしないと。

前:ポインタのエンコード

次:可変長データベースのまとめ