Я пытаюсь написать очень дешевый фрагмент кода C++, чтобы выполнить следующую операцию в короткой нулевой завершаемой строке.
Вход представляет собой строку типа "ABC"
. Он имеет нулевой конец и имеет максимальную длину 4 (или 5 с нулевым терминатором).
Выход идет на char[4]
который не является нулевым, и должен иметь пробел справа. Поэтому в этом случае это будут {'A','B','C',' '}
Это нормально предположить, что входная строка правильно завершена нулем, поэтому нет необходимости читать второе слово ввода, чтобы убедиться. 4 байта - это самое длинное, что может быть.
Таким образом, код вокруг него выглядит так:
char* input = "AB";
char output[4];
// code snippet goes here
// afterward output will be populated with {'A','B',' ',' '}
Как дешево это можно сделать? Если это имеет значение: я работаю с:
Linux 2.6.32-358.11.1.el6.x86_64 #1 SMP x86_64 x86_64 x86_64 GNU/Linux
Наконец, вход выравнивается по слову.
Как насчет чего-то вроде этого:
typedef unsigned int word;
int spacePad(word input) {
static const word spaces = 0x20202020;
word mask =
!input ? 0 :
!(input & 0x00ffffff) ? 0xff:
!(input & 0x0000ffff) ? 0xffff :
!(input & 0x0000ff) ? 0xffffff :
0xffffffff;
// or without branches
word branchless_mask =
1u << (8 * (
bool(input & 0xff000000) +
bool(input & 0x00ff0000) +
bool(input & 0x0000ff00) +
bool(input & 0x000000ff)
));
return (spaces & mask) | (input & ~mask);
}
И если я не spacePad(0xaabb0000)
, spacePad(0xaabb0000)
будет 0xaabb2020
.
Вместо вычислений и масок вы можете использовать встроенные функции SSE, которые, вероятно, будут быстрее, так как вы получите маску в нескольких инструкциях, а затем замаскированное перемещение сделает все остальное, но компилятор, вероятно, переместит ваши переменные arround из SSE к стандартным регистрам, которые могут привести к снижению веса. Все зависит от того, сколько данных вам нужно обрабатывать, как оно упаковано в память и т.д.
Если вход в char*
а не int
, обычно необходим дополнительный код, так как кастинг может считываться в нераспределенную память. Но так как вы упоминаете, что все строки выравниваются по словам, достаточно сделать актерский процесс, даже если есть несколько нераспределенных байтов, они находятся на том же слове, что и по меньшей мере один выделенный байт. Поскольку вы только читаете, нет риска повреждения памяти и всех архитектур, о которых я знаю, защита аппаратной памяти имеет зернистость, большую, чем слово. Например, на x86 страница памяти часто выравнивается по 4k.
Теперь, когда все хорошо и взломано, но: прежде чем выбрать решение, сравните его, что единственный способ узнать, что лучше для вас (за исключением, конечно, теплого нечеткого чувства написания кода, подобного этому ^^)
'\0'
) будет 0?
Если скорость ваша проблема - используйте грубую силу.
Это не имеет доступа input
за ее пределами, и не разрушает его.
const char* input = TBD();
char output[4] = {' '};
if (input[0]) {
output[0] = input[0];
if (input[1]) {
output[1] = input[1];
if (input[2]) {
output[2] = input[2];
if (input[3]) {
output[3] = input[3];
}
}
}
}
char* input = "AB";
char output[4];
input += (output[0] = *input ? *input : ' ') != ' ';
input += (output[1] = *input ? *input : ' ') != ' ';
input += (output[2] = *input ? *input : ' ') != ' ';
output[3] = *input ? *input : ' ';
Обратите внимание, что это уничтожает исходный указатель input
, поэтому сделайте копию этого, если вам нужно его сохранить.
Для коротких строк, подобных этому, я не думаю, что вы можете сделать намного лучше, чем тривиальная реализация:
char buffer[4];
const char * input = "AB";
const char * in = input;
char * out = buffer;
char * end = buffer + sizeof buffer;
while (out < end)
{
*out = *in != 0 ? *in++ : ' ';
out++;
}
Если ваш ввод имеет нулевое завершение, достаточно простого strcpy
. Memcpy работает быстрее, но скопирует любой мусор, найденный после нулевого символа.
Вы ищете memcpy
:
char* input = "AB\0\0";
char output[4];
memcpy(output, input, 4);
Если ваш вход является переменным, сначала вам нужно рассчитать размер:
char* input = "AB";
std::size_t len = strlen(input);
char output[4] = {' ', ' ', ' ', ' '};
memcpy(output, input, std::min(4, len));
strlen
которая принимает максимальную длину (есть нестандартное расширение strnlen
которое делает именно это).