Merge/concatenate 未知数量的字节数组
Merge/concatenate unknown amount of byte arrays
我可以 merge/combine/concatenate 两个具有以下函数的数组,但我如何修改它以支持未知数量的数组。换句话说,可变函数 Args...
?
char* concat(char* a, size_t a_size,
char* b, size_t b_size) {
char* c = realloc(a, a_size + b_size);
memcpy(c + a_size, b, b_size); // dest is after "a" data, source is b with b_size
free(b);
return c;
}
使用 span
s 和 vector
s,你可以这样写:
std::vector<std::byte> Concat(std::span<std::byte> a)
{
return std::vector<std::byte>(a.data(), a.data() + a.size());
}
template<typename... Args>
std::vector<std::byte> Concat(std::span<std::byte> a, Args... args)
{
auto vec = std::vector<std::byte>(a.data(), a.data() + a.size());
auto concat = Concat(args...);
vec.insert(vec.end(), concat.begin(), concat.end());
return vec;
}
请注意,您需要一个兼容 C++20 的编译器才能使用 span
。支持最新版本的 GCC、Clang 和 MSVC。
我不确定这样的事情是否适合你?我认为这也应该适用于 C++11,并且我相信如果需要可以针对 std::span
进行调整。它只分配一次内存,然后将提供给 concat
的每个内存块复制到这个分配的块中,消除了任何重新分配的需要。
#include <cassert>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <utility>
template <typename T>
size_t concatSize(T* arr, size_t len) {
return len;
}
template <typename T, typename... Args>
size_t concatSize(T* arr, size_t len, Args... args) {
return len + concatSize(args...);
}
template <typename T>
void copyMem(T* res, T* arr, size_t len) {
memcpy(res, arr, len);
}
template <typename T, typename... Args>
void copyMem(T* res, T* arr, size_t len, Args... args) {
memcpy(res, arr, len);
copyMem((T*)((char*)res + len), args...);
}
template <typename T, typename... Args>
std::pair<T*, size_t> concat(T* arr, size_t len, Args... args) {
static_assert(sizeof... (Args)%2 == 0, "Not even number of arguments!");
auto size = concatSize(arr, len, args...);
T* result = (T*)malloc(size);
copyMem(result, arr, len, args...);
return std::make_pair(result, size);
}
int main() {
{
char a[] = {'a', 'b', 'c'};
char b[] = {'d', 'e', 'f'};
char c[] = {'g', 'h', 'i'};
auto result = concat(a, sizeof a, b, sizeof b, c, sizeof c);
//Don't use regular printf %s since it's not a C-string!
for(int i = 0; i < result.second; ++i) {
std::printf("%c ", result.first[i]);
}
std::printf("\n");
free(result.first);
}
{
int a[] = {'1', '2', '3'};
int b[] = {'4', '5', '6'};
int c[] = {'7', '8', '9'};
auto result = concat(a, sizeof( a), b, sizeof( b), c, sizeof( c));
char* x = (char*)result.first;
for(int i = 0; i < result.second; ++i) {
std::printf("%c ", x[i]);
}
std::printf("\n");
free(result.first);
}
}
a b c d e f g h i
1 2 3 4 5 6 7 8 9
我可以 merge/combine/concatenate 两个具有以下函数的数组,但我如何修改它以支持未知数量的数组。换句话说,可变函数 Args...
?
char* concat(char* a, size_t a_size,
char* b, size_t b_size) {
char* c = realloc(a, a_size + b_size);
memcpy(c + a_size, b, b_size); // dest is after "a" data, source is b with b_size
free(b);
return c;
}
使用 span
s 和 vector
s,你可以这样写:
std::vector<std::byte> Concat(std::span<std::byte> a)
{
return std::vector<std::byte>(a.data(), a.data() + a.size());
}
template<typename... Args>
std::vector<std::byte> Concat(std::span<std::byte> a, Args... args)
{
auto vec = std::vector<std::byte>(a.data(), a.data() + a.size());
auto concat = Concat(args...);
vec.insert(vec.end(), concat.begin(), concat.end());
return vec;
}
请注意,您需要一个兼容 C++20 的编译器才能使用 span
。支持最新版本的 GCC、Clang 和 MSVC。
我不确定这样的事情是否适合你?我认为这也应该适用于 C++11,并且我相信如果需要可以针对 std::span
进行调整。它只分配一次内存,然后将提供给 concat
的每个内存块复制到这个分配的块中,消除了任何重新分配的需要。
#include <cassert>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <utility>
template <typename T>
size_t concatSize(T* arr, size_t len) {
return len;
}
template <typename T, typename... Args>
size_t concatSize(T* arr, size_t len, Args... args) {
return len + concatSize(args...);
}
template <typename T>
void copyMem(T* res, T* arr, size_t len) {
memcpy(res, arr, len);
}
template <typename T, typename... Args>
void copyMem(T* res, T* arr, size_t len, Args... args) {
memcpy(res, arr, len);
copyMem((T*)((char*)res + len), args...);
}
template <typename T, typename... Args>
std::pair<T*, size_t> concat(T* arr, size_t len, Args... args) {
static_assert(sizeof... (Args)%2 == 0, "Not even number of arguments!");
auto size = concatSize(arr, len, args...);
T* result = (T*)malloc(size);
copyMem(result, arr, len, args...);
return std::make_pair(result, size);
}
int main() {
{
char a[] = {'a', 'b', 'c'};
char b[] = {'d', 'e', 'f'};
char c[] = {'g', 'h', 'i'};
auto result = concat(a, sizeof a, b, sizeof b, c, sizeof c);
//Don't use regular printf %s since it's not a C-string!
for(int i = 0; i < result.second; ++i) {
std::printf("%c ", result.first[i]);
}
std::printf("\n");
free(result.first);
}
{
int a[] = {'1', '2', '3'};
int b[] = {'4', '5', '6'};
int c[] = {'7', '8', '9'};
auto result = concat(a, sizeof( a), b, sizeof( b), c, sizeof( c));
char* x = (char*)result.first;
for(int i = 0; i < result.second; ++i) {
std::printf("%c ", x[i]);
}
std::printf("\n");
free(result.first);
}
}
a b c d e f g h i
1 2 3 4 5 6 7 8 9