Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

break: c rewrite #1270

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
AllowShortFunctionsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
IndentCaseLabels: false
SortIncludes: false
ColumnLimit: 80
IndentWidth: 2
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ jobs:
git clone --depth 1 https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/vendor/start/plenary.nvim
git clone --depth 1 https://github.com/kyazdani42/nvim-web-devicons ~/.local/share/nvim/site/pack/vendor/start/nvim-web-devicons
ln -s $(pwd) ~/.local/share/nvim/site/pack/vendor/start
make

- name: Run tests
run: |
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ build/
doc/tags

.luacheckcache
.gdb_history
1 change: 1 addition & 0 deletions .luacheckrc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ globals = {
"_TelescopeConfigurationValues",
"_TelescopeConfigurationPickers",
"__TelescopeKeymapStore",
"__Telescope_FFI_DEFINED",
}

-- Global objects defined by the C code
Expand Down
31 changes: 31 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,34 @@
CFLAGS = -Wall -Werror -fpic -std=gnu99
MODE ?= -O3

ifeq ($(OS),Windows_NT)
MKD = -mkdir
RM = cmd /C rmdir /Q /S
CC = gcc
TARGET := libtelescope.dll
else
MKD = mkdir -p
RM = rm -rf
TARGET := libtelescope.so
endif

all: build/$(TARGET)

build/$(TARGET): src/telescope.c src/telescope.h
$(MKD) build
$(CC) $(MODE) $(CFLAGS) -shared src/telescope.c -o build/$(TARGET)

.PHONY: lint clangdhappy clean test docgen

ntest:
nvim --headless --noplugin -u test/minrc.vim -c "PlenaryBustedDirectory test/ { minimal_init = './test/minrc.vim' }"

clangdhappy:
compiledb make

clean:
$(RM) build

test:
nvim --headless --noplugin -u scripts/minimal_init.vim -c "PlenaryBustedDirectory lua/tests/automated/ { minimal_init = './scripts/minimal_init.vim' }"

Expand Down
103 changes: 103 additions & 0 deletions lua/telescope/c_entry_manager.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
local ffi = require "ffi"
local native = require "telescope.ffi"

local EntryManager = {}
EntryManager.__index = EntryManager

function EntryManager:new(max_results, set_entry)
return setmetatable({
manager = ffi.gc(native.tele_manager_create(max_results), native.tele_manager_free),
tbl = {},
idx = 0,
max_results = max_results,
set_entry = vim.F.if_nil(set_entry, function() end),
}, self)
end

function EntryManager:num_results()
return tonumber(self.manager.list.len)
end

function EntryManager:worst_acceptable_score()
return tonumber(self.manager.worst_acceptable_score)
end

local function __iter(self)
local current_node = self.manager.list.head
return function()
local node = current_node
if node == nil then
return nil
end

current_node = current_node.next
return self.tbl[node.item.idx], node.item.score
end
end

function EntryManager:get_container(index)
local k = 0
local current_node = self.manager.list.head

while true do
local node = current_node
if node == nil then
return nil
end
current_node = current_node.next
k = k + 1
if k == index then
return node.item
end
end
end

function EntryManager:get_entry(index)
local node = self:get_container(index)
if node then
return self.tbl[node.idx]
end
return {}
end

function EntryManager:get_score(index)
return self:get_container(index).score
end

function EntryManager:get_ordinal(index)
return self:get_entry(index).ordinal
end

function EntryManager:find_entry(entry)
local count = 0
for o_entry in __iter(self) do
count = count + 1

if o_entry == entry then
return count
end
end
end

function EntryManager:add_entry(picker, score, entry)
score = score or 0

self.idx = self.idx + 1
self.tbl[self.idx] = entry
local index = native.tele_manager_add(self.manager, self.idx, score)
if index > 0 then
self.set_entry(picker, index, entry, score, true)
end
end

function EntryManager:iter()
local iterator = __iter(self)
return function()
local val = iterator()
return val
end
end

function EntryManager:truncate() end

return EntryManager
4 changes: 4 additions & 0 deletions lua/telescope/entry_manager.lua
Original file line number Diff line number Diff line change
Expand Up @@ -186,4 +186,8 @@ function EntryManager:iter()
end
end

function EntryManager:truncate(...)
return self.linked_states:truncate(...)
end

return EntryManager
47 changes: 47 additions & 0 deletions lua/telescope/ffi.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
local ffi = require "ffi"

local library_path = (function()
local dirname = string.sub(debug.getinfo(1).source, 2, #"/ffi.lua" * -1)
if package.config:sub(1, 1) == "\\" then
return dirname .. "../../build/libtelescope.dll"
else
return dirname .. "../../build/libtelescope.so"
end
end)()
local native = ffi.load(library_path)

if not __Telescope_FFI_DEFINED then
__Telescope_FFI_DEFINED = true
ffi.cdef [[
typedef struct {
int32_t idx;
double score;
} tele_container;

typedef struct tele_node_s tele_node_t;
struct tele_node_s {
tele_node_t *next;
tele_node_t *prev;
tele_container item;
};
typedef struct {
tele_node_t *head;
tele_node_t *tail;
tele_node_t *_tracked_node;
size_t len;
size_t track_at;
} tele_linked_list_t;

typedef struct {
size_t max_results;
double worst_acceptable_score;
tele_linked_list_t *list;
} tele_manager_t;

tele_manager_t *tele_manager_create(size_t max_results);
void tele_manager_free(tele_manager_t *manager);
int32_t tele_manager_add(tele_manager_t *manager, int32_t item, double score);
]]
end

return native
4 changes: 2 additions & 2 deletions lua/telescope/pickers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ local p_highlighter = require "telescope.pickers.highlights"
local p_scroller = require "telescope.pickers.scroller"
local p_window = require "telescope.pickers.window"

local EntryManager = require "telescope.entry_manager"
local EntryManager = require "telescope.c_entry_manager"
local MultiSelect = require "telescope.pickers.multi"

local get_default = utils.get_default
Expand Down Expand Up @@ -1169,7 +1169,7 @@ function pickers.on_close_prompt(prompt_bufnr)
if picker.cache_picker.limit_entries > 0 then
-- edge case: starting in normal mode and not having run a search means having no manager instantiated
if picker.manager then
picker.manager.linked_states:truncate(picker.cache_picker.limit_entries)
picker.manager:truncate(picker.cache_picker.limit_entries)
else
picker.manager = EntryManager:new(picker.max_results, picker.entry_adder, picker.stats)
end
Expand Down
23 changes: 6 additions & 17 deletions lua/tests/automated/entry_manager_spec.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
local EntryManager = require "telescope.entry_manager"
local EntryManager = require "telescope.c_entry_manager"

local eq = assert.are.same

Expand All @@ -17,7 +17,7 @@ describe("process_result", function()
manager:add_entry(nil, 1, "hello")
manager:add_entry(nil, 2, "later")

eq(2, manager.linked_states.size)
eq(2, manager:num_results())

eq("hello", manager:get_entry(1))
eq("later", manager:get_entry(2))
Expand Down Expand Up @@ -103,28 +103,17 @@ describe("process_result", function()
end)

it("should not loop a bunch", function()
local info = {}
local manager = EntryManager:new(5, nil, info)
local manager = EntryManager:new(5, nil)
manager:add_entry(nil, 4, "better result")
manager:add_entry(nil, 3, "better result")
manager:add_entry(nil, 2, "better result")

-- Loops once to find 3 < 4
-- Loops again to find 2 < 3
eq(2, info.looped)
end)

it("should not loop a bunch, part 2", function()
local info = {}
local manager = EntryManager:new(5, nil, info)
local manager = EntryManager:new(5, nil)
manager:add_entry(nil, 4, "better result")
manager:add_entry(nil, 2, "better result")
manager:add_entry(nil, 3, "better result")

-- Loops again to find 2 < 4
-- Loops once to find 3 > 2
-- but less than 4
eq(3, info.looped)
end)

it("should update worst score in all append case", function()
Expand All @@ -133,7 +122,7 @@ describe("process_result", function()
manager:add_entry(nil, 3, "result 3")
manager:add_entry(nil, 4, "result 4")

eq(3, manager.worst_acceptable_score)
eq(3, manager:worst_acceptable_score())
end)

it("should update worst score in all prepend case", function()
Expand All @@ -151,6 +140,6 @@ describe("process_result", function()
eq(3, called_count)

eq("better result", manager:get_entry(1))
eq(4, manager.worst_acceptable_score)
eq(4, manager:worst_acceptable_score())
end)
end)
49 changes: 49 additions & 0 deletions scratch/benchmark.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
local bench = require "plenary.benchmark"
local fzf = require "fzf_lib"
local CEntryManager = require "telescope.c_entry_manager"
local EntryManager = require "telescope.entry_manager"

local function lines_from(file)
local lines = {}
for line in io.lines(file) do
lines[#lines + 1] = line
end
return lines
end

local function filter(manager, prompt, lines)
local slab = fzf.allocate_slab()
local p = fzf.parse_pattern(prompt, 0)
for _, line in ipairs(lines) do
manager:add_entry({}, fzf.get_score(line, p, slab), { value = line, display = line, ordinal = line })
end
fzf.free_pattern(p)
fzf.free_slab(slab)

return manager:num_results()
end

local lines = lines_from "../telescope-fzf-native.nvim/files"

local max = 10000

bench("lua vs c ffi", {
warmup = 3,
runs = 10,
fun = {
{
"c ffi",
function()
local c_manager = CEntryManager:new(max)
filter(c_manager, "fzf.c", lines)
end,
},
{
"lua",
function()
local manager = EntryManager:new(max)
filter(manager, "fzf.c", lines)
end,
},
},
})
Loading