从不与对象大小对齐的连续固定大小缓冲区解析对象的有效方法
Efficient approaches for parsing objects from consecutive fixed size buffers that don't align with object size
我想在 C++ 中实现一些东西,我有一个 API 从字节数组中读出对象,而我传入的数组被限制为固定大小。解析出一个完整的对象后,API就知道了它完成读取的指针位置(当前字节数组中下一个要读取但未完成的对象的开头)。
然后我只需要将剩余的字节数组附加到下一个相同的固定大小数组,并开始在指针位置读取一个新对象,就好像它是新数组的开头一样。
我是 C++ 的新手,我可以使用以下方法,但看起来相当麻烦且效率低下。它需要三个向量和大量的清理、保留和插入。我想知道是否有任何替代方案可能更有效,或者至少同样有效但代码看起来更简洁?我一直在阅读像 stringstream 这样的东西,但它们似乎不需要更少的内存复制(可能更多,因为我的 API 必须要求传入字节数组)。谢谢!
std::vector<char> checkBuffer;
std::vector<char> remainingBuffer;
std::vector<char> readBuffer(READ_BUFFER_SIZE);
//loop while I still have stuff to read from input stream
while (in.good()) {
in.read(readBuffer.data(), READ_BUFFER_SIZE);
//This is the holding buffer for the API to parse object from
checkBuffer.clear();
//concatenate what's remaining in remainingBuffer (initially empty)
//with what's newly read from input inside readBuffer
checkBuffer.reserve(remainingBuffer.size() + readBuffer.size());
checkBuffer.insert(checkBuffer.end(), remainingBuffer.begin(),
remainingBuffer.end());
checkBuffer.insert(checkBuffer.end(), readBuffer.begin(),
readBuffer.end());
//Call API here, and I will also get a pointerPosition back as to
//where I am inside the buffer when finishing reading the object
Object parsedObject = parse(checkBuffer, &pointerPosition)
//Then calculate the size of bytes not read in checkBuffer
int remainingBufSize = CheckBuffer.size() - pointerPosition;
remainingBuffer.clear();
remainingBuffer.reserve(remainingBufSize);
//Then just copy over whatever is remaining in the checkBuffer into
//remainingBuffer and make it be used in next iteration
remainingBuffer.insert(remainingBuffer.end(),
&checkBuffer[pointerPosition],&checkBuffer[checkBuffer.size()]);
}
如果我处于你的位置,我会只保留 readBuffer。我会保留 READ_BUFFER_SIZE +sizeof(LargestMessage)
。
解析后,您将返回一个指向 api 能够在向量中读取的最后一个内容的指针。然后我会将结束迭代器转换为指针 &*readbuffer.end()
并使用它来绑定我们必须复制到向量头部的数据。一旦您在向量的头部获得了该数据,您就可以使用相同的数据调用读取其余部分,除非您添加剩余的字节数。确实需要某种方法来确定剩余数组中有多少个字符,但这不应该是无法克服的。
写append_chunk_into(in,vect)
。它在 vect
的末尾附加了一大块数据。它会根据需要调整大小。顺便说一句,字符大小的非零内存标准布局结构可能是比 char
.
更好的选择
追加到结尾:
size_t old_size=vect.size();
vect.resize(vect.size()+new_bytes);
in.read(vect.data()+old_size, new_bytes);
或任何读 api 是什么。
要解析,请输入 vect.data()
。取回结束时的指针 ptr
.
然后`vect.erase(vect.begin(), vect.begin()+(ptr-vect.data())) 移除解析后的字节。 (只有在从缓冲区中解析完所有内容后才能执行此操作,以节省浪费的内存移动)。
一个向量。它将重用它的内存,并且永远不会大于读取大小+最大对象 1 的大小。所以你可以提前预定。
但实际上,通常大部分时间都花在了 io 上。因此,将优化重点放在保持数据顺畅流动上。
我想在 C++ 中实现一些东西,我有一个 API 从字节数组中读出对象,而我传入的数组被限制为固定大小。解析出一个完整的对象后,API就知道了它完成读取的指针位置(当前字节数组中下一个要读取但未完成的对象的开头)。
然后我只需要将剩余的字节数组附加到下一个相同的固定大小数组,并开始在指针位置读取一个新对象,就好像它是新数组的开头一样。
我是 C++ 的新手,我可以使用以下方法,但看起来相当麻烦且效率低下。它需要三个向量和大量的清理、保留和插入。我想知道是否有任何替代方案可能更有效,或者至少同样有效但代码看起来更简洁?我一直在阅读像 stringstream 这样的东西,但它们似乎不需要更少的内存复制(可能更多,因为我的 API 必须要求传入字节数组)。谢谢!
std::vector<char> checkBuffer;
std::vector<char> remainingBuffer;
std::vector<char> readBuffer(READ_BUFFER_SIZE);
//loop while I still have stuff to read from input stream
while (in.good()) {
in.read(readBuffer.data(), READ_BUFFER_SIZE);
//This is the holding buffer for the API to parse object from
checkBuffer.clear();
//concatenate what's remaining in remainingBuffer (initially empty)
//with what's newly read from input inside readBuffer
checkBuffer.reserve(remainingBuffer.size() + readBuffer.size());
checkBuffer.insert(checkBuffer.end(), remainingBuffer.begin(),
remainingBuffer.end());
checkBuffer.insert(checkBuffer.end(), readBuffer.begin(),
readBuffer.end());
//Call API here, and I will also get a pointerPosition back as to
//where I am inside the buffer when finishing reading the object
Object parsedObject = parse(checkBuffer, &pointerPosition)
//Then calculate the size of bytes not read in checkBuffer
int remainingBufSize = CheckBuffer.size() - pointerPosition;
remainingBuffer.clear();
remainingBuffer.reserve(remainingBufSize);
//Then just copy over whatever is remaining in the checkBuffer into
//remainingBuffer and make it be used in next iteration
remainingBuffer.insert(remainingBuffer.end(),
&checkBuffer[pointerPosition],&checkBuffer[checkBuffer.size()]);
}
如果我处于你的位置,我会只保留 readBuffer。我会保留 READ_BUFFER_SIZE +sizeof(LargestMessage)
。
解析后,您将返回一个指向 api 能够在向量中读取的最后一个内容的指针。然后我会将结束迭代器转换为指针 &*readbuffer.end()
并使用它来绑定我们必须复制到向量头部的数据。一旦您在向量的头部获得了该数据,您就可以使用相同的数据调用读取其余部分,除非您添加剩余的字节数。确实需要某种方法来确定剩余数组中有多少个字符,但这不应该是无法克服的。
写append_chunk_into(in,vect)
。它在 vect
的末尾附加了一大块数据。它会根据需要调整大小。顺便说一句,字符大小的非零内存标准布局结构可能是比 char
.
追加到结尾:
size_t old_size=vect.size();
vect.resize(vect.size()+new_bytes);
in.read(vect.data()+old_size, new_bytes);
或任何读 api 是什么。
要解析,请输入 vect.data()
。取回结束时的指针 ptr
.
然后`vect.erase(vect.begin(), vect.begin()+(ptr-vect.data())) 移除解析后的字节。 (只有在从缓冲区中解析完所有内容后才能执行此操作,以节省浪费的内存移动)。
一个向量。它将重用它的内存,并且永远不会大于读取大小+最大对象 1 的大小。所以你可以提前预定。
但实际上,通常大部分时间都花在了 io 上。因此,将优化重点放在保持数据顺畅流动上。