如何封装两个容器之间传输的字节
How to encapsulate transferring bytes between two containers
我有两个独立的类,每个都维护一个有限大小的缓冲区:
class A {
private:
std::deque<uint8_t> buffer;
size_t max_size;
};
class B {
private:
static const size_t MAX_SIZE = 1024;
uint8_t buffer[MAX_SIZE];
}
现在,我还有一个函数 C,它不是 A 或 B 的成员。这个函数需要从 开始[=24= 开始获取(即删除)尽可能多的字节] 的 A 并将其写入 B。Ofc 不允许缓冲区溢出。
问题:如何在确保封装 A 和 B 的同时高效地执行此操作? IE。 A、B、C不知道其他的是怎么实现的
我不想要的东西,原因很明显:
- A 公开了一个 public 方法,该方法 returns 一个非 const 迭代器到 deque
- B 公开了一个 public 方法,该方法 returns 一个指向数组的非常量指针
class A
returns 通过新的 public 方法的 const 迭代器。
class B
公开了一种复制这些字节的方法。
class A {
public:
const std::deque<uint8_t>& getBuffer() const
{
return buffer;
}
private:
std::deque<uint8_t> buffer;
size_t max_size;
size_t current_size;
};
class B {
public:
B() : max_size(MAX_SIZE), current_size(0)
{
}
void Transfer(const std::deque<uint8_t>& data)
{
size_t remaining = max_size - current_size;
size_t toCopy = data.size() > remaining ? remaining : data.size();
for (size_t i = 0; i < toCopy; i++)
{
buffer[i+current_size] = data[i];
}
current_size += toCopy;
}
private:
static const size_t MAX_SIZE = 1024;
uint8_t buffer[MAX_SIZE];
};
CopyAToB(const A& a, B& b)
{
b.Transfer(a.getBuffer());
}
模拟标准容器。使用 begin
和 end
。这是我为您的用例看到的最小界面:
class A {
private:
std::deque<uint8_t> buffer_;
size_t max_size_;
public:
using const_iterator = decltype(buffer_)::const_iterator;
auto begin() const -> const_iterator { return buffer_.begin(); }
auto end() const -> const_iterator { return buffer_.end(); }
};
class B {
private:
static const size_t MAX_SIZE = 1024;
std::array<uint8_t, MAX_SIZE> buffer_;
public:
/// fills the buffer with elements in [first, last)
/// excessive elements are ignored
/// returns the number of successfully filled elements
template <class It>
auto fill_as_much_as_possible(It first, It last) -> std::size_t
{
auto in_size = std::distance(first, last);
if (in_size > static_cast<decltype(in_size)>(MAX_SIZE))
{
last = first;
std::advance(last, MAX_SIZE);
}
auto out_last = std::copy(first, last, buffer_.begin());
return std::distance(buffer_.begin(), out_last);
}
};
auto foo(const A& a, B& b)
{
b.fill_as_much_as_possible(a.begin(), a.end());
}
我有两个独立的类,每个都维护一个有限大小的缓冲区:
class A {
private:
std::deque<uint8_t> buffer;
size_t max_size;
};
class B {
private:
static const size_t MAX_SIZE = 1024;
uint8_t buffer[MAX_SIZE];
}
现在,我还有一个函数 C,它不是 A 或 B 的成员。这个函数需要从 开始[=24= 开始获取(即删除)尽可能多的字节] 的 A 并将其写入 B。Ofc 不允许缓冲区溢出。
问题:如何在确保封装 A 和 B 的同时高效地执行此操作? IE。 A、B、C不知道其他的是怎么实现的
我不想要的东西,原因很明显:
- A 公开了一个 public 方法,该方法 returns 一个非 const 迭代器到 deque
- B 公开了一个 public 方法,该方法 returns 一个指向数组的非常量指针
class A
returns 通过新的 public 方法的 const 迭代器。
class B
公开了一种复制这些字节的方法。
class A {
public:
const std::deque<uint8_t>& getBuffer() const
{
return buffer;
}
private:
std::deque<uint8_t> buffer;
size_t max_size;
size_t current_size;
};
class B {
public:
B() : max_size(MAX_SIZE), current_size(0)
{
}
void Transfer(const std::deque<uint8_t>& data)
{
size_t remaining = max_size - current_size;
size_t toCopy = data.size() > remaining ? remaining : data.size();
for (size_t i = 0; i < toCopy; i++)
{
buffer[i+current_size] = data[i];
}
current_size += toCopy;
}
private:
static const size_t MAX_SIZE = 1024;
uint8_t buffer[MAX_SIZE];
};
CopyAToB(const A& a, B& b)
{
b.Transfer(a.getBuffer());
}
模拟标准容器。使用 begin
和 end
。这是我为您的用例看到的最小界面:
class A {
private:
std::deque<uint8_t> buffer_;
size_t max_size_;
public:
using const_iterator = decltype(buffer_)::const_iterator;
auto begin() const -> const_iterator { return buffer_.begin(); }
auto end() const -> const_iterator { return buffer_.end(); }
};
class B {
private:
static const size_t MAX_SIZE = 1024;
std::array<uint8_t, MAX_SIZE> buffer_;
public:
/// fills the buffer with elements in [first, last)
/// excessive elements are ignored
/// returns the number of successfully filled elements
template <class It>
auto fill_as_much_as_possible(It first, It last) -> std::size_t
{
auto in_size = std::distance(first, last);
if (in_size > static_cast<decltype(in_size)>(MAX_SIZE))
{
last = first;
std::advance(last, MAX_SIZE);
}
auto out_last = std::copy(first, last, buffer_.begin());
return std::distance(buffer_.begin(), out_last);
}
};
auto foo(const A& a, B& b)
{
b.fill_as_much_as_possible(a.begin(), a.end());
}