c++ 通过外部评估分派将标准兼容性与不透明数据接口

3xiyfsfu  于 5个月前  发布在  其他
关注(0)|答案(1)|浏览(65)

我正在接收低级别{ void * data; uint stride, count; }的托管数据。我可以读取,写入和交换数据项,但不能添加或删除/调整大小/重新分配。有足够的信息来重新命名和随机访问,但没有类型信息来取消引用。所有不透明的项目都可以重新命名复制和移动。
在现代C++中,是否有可能促进这种数据格式的标准兼容性,省略解引用接口,并将评估委托给外部上下文?类似于:

std::sort(OpaqueFirst, OpaqueLast, [](Opaque a, Opaque b){ return handle(a, b); });

字符串

u1ehiz5o

u1ehiz5o1#

基本的想法是创建一个类型,引用你的一个子数组,并定义swap来实际交换它们的内容:

struct buffer {std::span<std::byte> s;};  // but see below

void swap(const buffer &a,const buffer &b) {
  assert(a.s.size()==b.s.size());
  auto i=b.s.begin();
  for(auto &x : a.s) std::swap(x,*i++);
}

字符串
然后我们只需要创建一个这样的对象的惰性范围,这很容易用std::views::transform Package std::views::iota,并从问题中编写平凡的比较器:

struct array { void * data; uint stride, count; };

void sort(const array &a,bool lt(const void*,const void*)) {
  std::ranges::sort
    (std::views::transform
     (std::views::iota(uint(),a.count),
      [&](uint i)
      {return buffer{{static_cast<std::byte*>(a.data)+a.stride*i,a.stride}};}),
     [&](const buffer &x,const buffer &y) {return lt(x.s.data(),y.s.data());});
}


不幸的是,sort要求能够将范围元素移动到临时变量中,而不仅仅是交换它们。这需要一个相当复杂的 Package 器类型,可以临时拥有**数据,这反过来又需要动态分配,因为array::stride不是常量:

struct buffer {
  std::unique_ptr<std::byte[]> u;
  std::span<std::byte> s;

  buffer(std::span<std::byte> s) : s(s) {}
  buffer(buffer &&b) noexcept {
    if(b.u) u=std::move(b.u);
    else {
      u=std::make_unique<std::byte[]>(b.s.size());
      std::ranges::copy(b.s,u.get());
      s={u.get(),b.s.size()};
    }
  }

  void operator=(const buffer &b) const noexcept;
  buffer& operator=(const buffer &b) noexcept {
    assert(s.size()==b.s.size());
    std::ranges::copy(b.s,s.begin());
    return *this;
  }
};


保留我们的自定义swap避免了对每个元素交换使用这样的分配,所以性能并不可怕。未实现的operator=(…) const是必要的,以说服库buffer是一个代理类型,应该支持通过纯右值排序。
具有完整buffer类型的complete example存在于浏览器资源管理器中。

相关问题