通过外部评估调度将标准兼容性与不透明数据相连接

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

我正在接收低级

{ void * data; uint stride, count; }
格式的托管数据。我可以读取、写入和交换数据项,但不能添加或删除/调整大小/重新分配。有足够的信息用于迭代和随机访问,但没有用于取消引用的类型信息。所有不透明的项目都可以轻松复制和移动。

在现代 C++ 中是否有可能促进这种数据格式的 std 兼容性,省略解引用接口,并将评估委托给外部上下文?比如:

std::sort(OpaqueFirst, OpaqueLast, [](Opaque a, Opaque b){ return handle(a, b); });
c++ algorithm iterator std opaque-pointers
1个回答
0
投票

基本思想是创建一个类型,引用到你的一个子数组,并定义

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
包裹在
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
要求能够将范围元素移动到临时变量中,而不仅仅是交换它们。这需要一个相当复杂的包装类型,它实际上可以暂时拥有数据,这反过来又需要动态分配,因为
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
是一个 proxy 类型,应该支持通过纯右值排序的必要条件。

编译器资源管理器上存在

具有完整buffer类型的

完整示例

© www.soinside.com 2019 - 2024. All rights reserved.