在平面缓冲区向量中添加间隙

问题描述 投票:0回答:2

Flatbuffers 向量中是否可能有间隙或空元素?

我需要传输一个(可变长度)项目列表,其中项目的位置是相关的。不过,项目可以省略,但现有项目仍必须位于正确的位置

假设

table Item {
  value:string;
}

table List {
  items:[Item];
}

root_type List;
void createBuffer()
{
  auto fbb = ::flatbuffers::FlatBufferBuilder{};
    
  auto vector = std::vector<::flatbuffers::Offset<Item>>{};
  vector.push_back(CreateItem(fbb, fbb.CreateString("Test")));
  // Adds "empty" item
  vector.push_back({});
    
  auto fVector = fbb.CreateVector(vector);
  auto list = CreateList(fbb, fVector);
  fbb.Finish(list);
}

这会在创建 FBB 向量的

fbb.CreateVector
方法中崩溃。

有没有办法在向量中添加“间隙”,而不修改

Item
表?

c++ flatbuffers
2个回答
1
投票

不,这是不可能的。虽然表字段允许不存在/为空,但所有向量元素必须具有指定的类型。

无法在模式中指定“可选”向量元素类型。

你最好的选择是联合类型的向量。联合将包含

Item
类型,并且每个联合还允许“none”值,相当于 null。不过,这需要更多的工作,因为您实际上将存储 2 个向量,一个类型和一个值。


0
投票

正如评论者和@Aardappel 提到的,无法将“空”元素添加到向量中。我最终使用了向量联合的(新的?)功能。

但是,我找不到如何在 C++ 中使用它的描述(只有 C# 教程),所以这里有一个示例实现,供参考。

基本上,FlatBuffers 将写入 2 个向量,一个用于元素的类型,另一个用于实际元素

table Item {
  value:string;
}

table Empty {
}

union OptionalItem {
  Item,
  Empty
}

table List {
  items:[OptionalItem];
}

root_type List;
std::vector<uint8_t> createBuffer()
{
  auto fbb = ::flatbuffers::FlatBufferBuilder{};

  auto itemVector = std::vector<::flatbuffers::Offset<>>{};
  auto typeVector = std::vector<OptionalItem>{};
  itemVector.push_back(CreateItem(fbb, fbb.CreateString("Test")).Union());
  typeVector.push_back(OptionalItem::Item);

  // Adds "empty" item
  itemVector.push_back(CreateEmpty(fbb).Union());
  typeVector.push_back(OptionalItem::Empty);

  auto fbbItems = fbb.CreateVector(itemVector);
  auto fbbTypes = fbb.CreateVector(typeVector);
  auto list = CreateList(fbb, fbbTypes, fbbItems);
  fbb.Finish(list);

  return std::vector<uint8_t>(fbb.GetBufferPointer(), fbb.GetBufferPointer() + fbb.GetSize());
}

void readBuffer(std::vector<uint8_t> buffer)
{
  auto list = GetList(buffer.data());
  for (int i = 0; i < list->items()->size(); ++i) {
    if (list->items_type()->Get(i) == OptionalItem::Item) {
      auto item = reinterpret_cast<const Item*>(list->items()->Get(i));
      std::cout << i << ": " << item->value()->c_str() << std::endl;
    }
    else if (list->items_type()->Get(i) == OptionalItem::Empty) {
      std::cout << i << " is empty" << std::endl;
    }
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.