Eu preciso dividir o conteúdo de um buffer em uma lista de seqüências de caracteres. O caractere nulo é usado para separar os itens.
Os itens foram separados por caracteres de nova linha, então eu poderia usar a mesma abordagem que process-lines
:
(let (lines)
(while (not (eobp))
(setq lines (cons (buffer-substring-no-properties
(line-beginning-position)
(line-end-position))
lines))
(forward-line 1))
(nreverse lines))
Eu suponho que forward-line
é eficiente, mas o uso line-beginning-position
e line-end-position
é um pouco suspeito. Mas como o caractere nulo é usado, não posso fazer isso de qualquer maneira.
Uma maneira de fazer isso seria:
(split-string (buffer-string) "\0")
Eu também estava considerando essa variação:
(split-string (buffer-substring-no-properties (point-min)
(point-max))
"\0")
Isso é realmente mais eficiente? O texto no buffer não é propertizado, mas eu imaginaria que procurar as propriedades inexistentes ainda adicionaria uma sobrecarga.
Em vez de ler o buffer em uma string e depois dividi-la, eu gostaria de trabalhar diretamente no buffer - novamente assumindo que isso é realmente mais eficiente.
(let ((beg (point))
items)
(while (search-forward "\0" nil t)
(push (buffer-substring-no-properties beg (1- (point))) items)
(setq beg (point)))
(nreverse items))
Existe algo assim search-forward-char
e isso seria mais eficiente do que search-forward
?
Suponho que eu poderia usar:
(while (not (= (char-after) ?\0)) (forward-char))
Mas eu esperaria que isso estivesse disponível como uma função se fosse mais eficiente do que search-forward
.
fonte
(skip-chars-forward "^\0")
deve fazer o trabalho.(search-forward "\0" nil t)
na minha máquina.(split-string (buffer-substring-no-properties) "\0")
variante vença. Além disso, o desempenho pode depender da estrutura do texto. (Existem muitas provas curtas terminadas por nulo caracteres ou há grandes fichas com apenas alguns nulos-caracteres.)char-after
pode retornarnil
.0
é realmente o gargalo do seu aplicativo antes de aprofundar tanto?Respostas:
Eu executei os seguintes benchmarks em
sem personalizações, ou seja, iniciando o Emacs com a
-Q
bandeira.Como o @Tobias aponta corretamente em um comentário , é uma alternativa mais rápida para
search-forward
procurar um único caractereskip-chars-forward
. Alguns benchmarks a seguir.Caractere nulo no final do buffer
dá
Linhas longas terminadas em nulo
dá
Linhas curtas terminadas em nulo
dá
Observe que a menor diferença de tempo com linhas curtas provavelmente ocorre devido à maior complexidade do loop do teste (b). Além disso, invertendo o sentido de busca (ou seja, utilizando
point-max
,skip-chars-backward
,bobp
, ebackward-char
) não faz qualquer diferença perceptível.Vamos ver:
dá
portanto, não há diferença em um buffer não autorizado. Observe que eu tive que fazer a chamada
buffer-string
em uma função separada por compilação de bytes, caso contrário ela teria sido otimizada para uma constante abaixobenchmark-run-compiled
.Vamos checar. As três funções a seguir devem fornecer o mesmo resultado:
Caractere nulo no final do buffer
dá
Linhas longas terminadas em nulo
dá
Linhas curtas terminadas em nulo
dá
Portanto, você provavelmente pode obter uma aceleração de ~ 2x usando
skip-chars-{forward,backward}
, mas como o @Tobias aponta , vale a pena a complexidade extra?fonte