StrIdx 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CMakeLists.txt +27 -0
- data/Gemfile +5 -0
- data/README.md +39 -2
- data/exe/stridx.rb +16 -0
- data/gem_install +4 -0
- data/py_example.py +18 -0
- data/py_interf.cpp +182 -0
- data/runserver.rb +7 -0
- data/server.rb +103 -0
- data/setup.py +32 -0
- data/stridx-screencast.mp4 +0 -0
- data/stridx-tty.rb +122 -0
- data/stridx.gemspec +37 -0
- data/stridx.hpp +38 -31
- data/test.rb +7 -2
- data/unit_tests.sh +4 -0
- data/unittest.cpp +147 -0
- metadata +105 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f7655b6bd71bca58c86ad607fd197933fc19b97b3ae1c76e322ec0432025dad7
|
4
|
+
data.tar.gz: 2421892aa6fe750213d08e2254019d87ce7abb10496cdf1635a61815b8b8b0d7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0a0ed3f51b95b72a553cf97e1a852f63e8b6d1cbbba56fdab55ed5037ef4d658b8649f2cf92d35b5eea4e6657a18a3a1460a3a57069cda0889a1987f5d1611ee
|
7
|
+
data.tar.gz: f0d4753ee43cb205fa86468dad92a66644e12cf889d8018283cb421e4a5d670386b8666af64b89d4d475a59f10701de2223c31d03ac5d366f2ee255c77190cf8
|
data/CMakeLists.txt
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
cmake_minimum_required(VERSION 3.14)
|
2
|
+
|
3
|
+
project(my_project)
|
4
|
+
# https://github.com/google/googletest/issues/4000
|
5
|
+
include(FetchContent)
|
6
|
+
FetchContent_Declare(
|
7
|
+
googletest
|
8
|
+
URL https://github.com/google/googletest/archive/58d77fa8070e8cec2dc1ed015d66b454c8d78850.zip # release-1.12.1
|
9
|
+
)
|
10
|
+
|
11
|
+
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
12
|
+
FetchContent_MakeAvailable(googletest)
|
13
|
+
|
14
|
+
enable_testing()
|
15
|
+
|
16
|
+
add_executable(
|
17
|
+
stridx_test
|
18
|
+
unittest.cpp
|
19
|
+
)
|
20
|
+
target_link_libraries(
|
21
|
+
stridx_test
|
22
|
+
GTest::gtest_main
|
23
|
+
)
|
24
|
+
|
25
|
+
include(GoogleTest)
|
26
|
+
gtest_discover_tests(stridx_test)
|
27
|
+
|
data/README.md
CHANGED
@@ -37,9 +37,46 @@ and candidate is "./drivers/char/hw_random/nomadik-rng.c", then scores are calcu
|
|
37
37
|
score = score1/(11*11)*0.97 + score1/(11*38)*0.03 = 0.342944
|
38
38
|
```
|
39
39
|
|
40
|
-
#
|
40
|
+
# Interfaces
|
41
|
+
|
42
|
+
## Commandline
|
43
|
+
Install instructions (for Ubuntu Linux):
|
44
|
+
```
|
45
|
+
apt update
|
46
|
+
apt install ruby ruby-dev build-essential
|
47
|
+
gem install StrIdx
|
48
|
+
```
|
49
|
+
|
50
|
+
Start indexing server (on background):
|
51
|
+
```
|
52
|
+
stridx.rb start -- ~/Documents/ ~/Pictures/
|
53
|
+
```
|
54
|
+
|
55
|
+
Add bash keybindings (Ctrl-t):
|
56
|
+
```
|
57
|
+
eval "$(stridx.rb bash)"
|
58
|
+
```
|
59
|
+
|
60
|
+
Search by pressing <kbd>ctrl</kbd>+<kbd>t</kbd>. Keys: <kbd>up</kbd>, <kbd>down</kbd>, select with <kbd>enter</kbd>
|
61
|
+
|
62
|
+
![screencast](https://github.com/SamiSieranoja/stridx/assets/46612258/b2fd4fa2-37ad-4423-bd5f-d54b24ff6df5)
|
63
|
+
|
64
|
+
|
65
|
+
Stop server:
|
66
|
+
```
|
67
|
+
stridx.rb stop
|
68
|
+
```
|
69
|
+
|
70
|
+
Start indexing server (on foreground, to debug):
|
71
|
+
```
|
72
|
+
stridx.rb run -- ~/Documents/ ~/Pictures/
|
73
|
+
```
|
74
|
+
|
75
|
+
|
76
|
+
## Ruby
|
41
77
|
Install:
|
42
78
|
```
|
79
|
+
apt install ruby ruby-dev build-essential
|
43
80
|
gem install StrIdx
|
44
81
|
```
|
45
82
|
|
@@ -114,7 +151,7 @@ Search time: 0.0488 seconds
|
|
114
151
|
```
|
115
152
|
|
116
153
|
|
117
|
-
|
154
|
+
## C++
|
118
155
|
See demo.cpp
|
119
156
|
```cpp
|
120
157
|
#include "stridx.hpp"
|
data/exe/stridx.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.dirname(__FILE__) + "/.."
|
4
|
+
|
5
|
+
if ARGV[0] == "tty"
|
6
|
+
require "stridx-tty.rb"
|
7
|
+
StrIdxTTY.run
|
8
|
+
elsif ARGV[0] == "bash"
|
9
|
+
puts %q/
|
10
|
+
bind -m emacs-standard '"\er": redraw-current-line';
|
11
|
+
bind -m emacs-standard '"\C-t": " \C-b\C-k \C-u`stridx.rb tty`\e\C-e\er\C-a\C-y\C-h\C-e\e \C-y\ey\C-x\C-x\C-f"'
|
12
|
+
/
|
13
|
+
else
|
14
|
+
require "daemons"
|
15
|
+
Daemons.run(File.dirname(__FILE__) + "/../runserver.rb")
|
16
|
+
end
|
data/gem_install
ADDED
data/py_example.py
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
|
3
|
+
from stridx import StringIndex
|
4
|
+
e=StringIndex()
|
5
|
+
e.set_value(3)
|
6
|
+
e.add("./rust/alloc/vec/spec_extend.rs",0)
|
7
|
+
e.add("./virt/kvm/dirty_ring.c",1)
|
8
|
+
e.add("./Documentation/staging/static-keys.rst",2)
|
9
|
+
e.add("./Documentation/staging/lzo.rst",3)
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
results = e.find("rstalloc")
|
14
|
+
for x in results:
|
15
|
+
print(x)
|
16
|
+
|
17
|
+
# print(e.get_value())
|
18
|
+
|
data/py_interf.cpp
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+
|
2
|
+
#include <stdio.h>
|
3
|
+
#include <limits.h>
|
4
|
+
#include <cstring>
|
5
|
+
#include <pthread.h>
|
6
|
+
|
7
|
+
#include <stdio.h>
|
8
|
+
#include <iostream>
|
9
|
+
#include <string>
|
10
|
+
#include <vector>
|
11
|
+
#include <cfloat>
|
12
|
+
#include <cmath>
|
13
|
+
#include <bits/stdc++.h>
|
14
|
+
|
15
|
+
using std::ios;
|
16
|
+
using std::sort;
|
17
|
+
using std::string;
|
18
|
+
using std::vector;
|
19
|
+
|
20
|
+
#include <Python.h>
|
21
|
+
#include <cstring>
|
22
|
+
|
23
|
+
#include "stridx.hpp"
|
24
|
+
|
25
|
+
extern "C" {
|
26
|
+
|
27
|
+
// Define a structure for the custom object
|
28
|
+
typedef struct {
|
29
|
+
PyObject_HEAD int value;
|
30
|
+
StrIdx::StringIndex *idx;
|
31
|
+
} StrIdxObject;
|
32
|
+
|
33
|
+
// Method to allocate memory for the object
|
34
|
+
static PyObject *StrIdxObject_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
|
35
|
+
StrIdxObject *self;
|
36
|
+
|
37
|
+
self = (StrIdxObject *)type->tp_alloc(type, 0);
|
38
|
+
if (self != NULL) {
|
39
|
+
self->value = 0;
|
40
|
+
self->idx = new StrIdx::StringIndex();
|
41
|
+
}
|
42
|
+
|
43
|
+
return (PyObject *)self;
|
44
|
+
}
|
45
|
+
|
46
|
+
// Method to deallocate memory for the object
|
47
|
+
static void StrIdxObject_dealloc(StrIdxObject *self) { Py_TYPE(self)->tp_free((PyObject *)self); }
|
48
|
+
|
49
|
+
// Method to set the value of the object
|
50
|
+
static PyObject *StrIdxObject_set_value(StrIdxObject *self, PyObject *args) {
|
51
|
+
int value;
|
52
|
+
|
53
|
+
if (!PyArg_ParseTuple(args, "i", &value)) {
|
54
|
+
return NULL;
|
55
|
+
}
|
56
|
+
|
57
|
+
self->value = value;
|
58
|
+
|
59
|
+
Py_INCREF(Py_None);
|
60
|
+
return Py_None;
|
61
|
+
}
|
62
|
+
|
63
|
+
static PyObject *StrIdxObject_add(StrIdxObject *self, PyObject *args) {
|
64
|
+
char *value;
|
65
|
+
int file_id;
|
66
|
+
std::string str;
|
67
|
+
if (!PyArg_ParseTuple(args, "si", &value, &file_id)) {
|
68
|
+
return NULL;
|
69
|
+
}
|
70
|
+
str = value;
|
71
|
+
|
72
|
+
printf("char[]*: %s %i\n", value, file_id);
|
73
|
+
self->idx->addStrToIndex(str, file_id);
|
74
|
+
// self->idx->addStrToIndexThreaded(str, file_id);
|
75
|
+
Py_INCREF(Py_None);
|
76
|
+
return Py_None;
|
77
|
+
}
|
78
|
+
|
79
|
+
static PyObject *StrIdxObject_find(StrIdxObject *self, PyObject *args) {
|
80
|
+
char *value;
|
81
|
+
std::string str;
|
82
|
+
if (!PyArg_ParseTuple(args, "s", &value)) {
|
83
|
+
return NULL;
|
84
|
+
}
|
85
|
+
str = value;
|
86
|
+
|
87
|
+
printf("char*: %s\n", value);
|
88
|
+
const std::vector<std::pair<float, int>> &results = self->idx->findSimilar(str, 2);
|
89
|
+
|
90
|
+
int limit = 15;
|
91
|
+
int i = 0;
|
92
|
+
|
93
|
+
printf("res=%d\n", results.size());
|
94
|
+
if (results.size() < limit) {
|
95
|
+
limit = results.size();
|
96
|
+
}
|
97
|
+
PyObject *pyarr = PyList_New(limit);
|
98
|
+
|
99
|
+
for (const auto &[score,fileId] : results) {
|
100
|
+
PyObject *arr2 = PyList_New(2);
|
101
|
+
// PyList_SetItem(arr2, 0, Py_BuildValue("i", res.second));
|
102
|
+
// PyList_SetItem(arr2, 1, Py_BuildValue("d", res.first));
|
103
|
+
PyList_SetItem(arr2, 0, Py_BuildValue("i", fileId));
|
104
|
+
PyList_SetItem(arr2, 1, Py_BuildValue("d", score));
|
105
|
+
PyList_SetItem(pyarr, i, arr2);
|
106
|
+
i++;
|
107
|
+
if (i >= limit) {
|
108
|
+
break;
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
112
|
+
// Py_INCREF(Py_None);
|
113
|
+
return pyarr;
|
114
|
+
}
|
115
|
+
|
116
|
+
// Method to get the value of the object
|
117
|
+
static PyObject *StrIdxObject_get_value(StrIdxObject *self) {
|
118
|
+
return PyLong_FromLong(self->value);
|
119
|
+
}
|
120
|
+
|
121
|
+
// Define methods of the class
|
122
|
+
static PyMethodDef StrIdxObject_methods[] = {
|
123
|
+
{"set_value", (PyCFunction)StrIdxObject_set_value, METH_VARARGS,
|
124
|
+
"Set the value of the object"},
|
125
|
+
{"add", (PyCFunction)StrIdxObject_add, METH_VARARGS, "Set the value of the object"},
|
126
|
+
{"find", (PyCFunction)StrIdxObject_find, METH_VARARGS, "Find similar strings"},
|
127
|
+
{"get_value", (PyCFunction)StrIdxObject_get_value, METH_NOARGS, "Get the value of the object"},
|
128
|
+
{NULL} /* Sentinel */
|
129
|
+
};
|
130
|
+
|
131
|
+
// Define the type object for the class
|
132
|
+
static PyTypeObject StrIdxType = {
|
133
|
+
PyVarObject_HEAD_INIT(NULL, 0).tp_name = "stridx.StrIdx",
|
134
|
+
.tp_basicsize = sizeof(StrIdxObject),
|
135
|
+
.tp_dealloc = (destructor)StrIdxObject_dealloc,
|
136
|
+
.tp_doc = PyDoc_STR("Fuzzy string index"),
|
137
|
+
.tp_methods = StrIdxObject_methods,
|
138
|
+
.tp_new = StrIdxObject_new,
|
139
|
+
// .tp_repr = (reprfunc)myobj_repr,
|
140
|
+
};
|
141
|
+
|
142
|
+
// PyVarObject_HEAD_INIT(NULL, 0)
|
143
|
+
// .tp_name = "stridx.StrIdx",
|
144
|
+
// .tp_doc = "StrIdx class",
|
145
|
+
// .tp_basicsize = sizeof(StrIdxObject),
|
146
|
+
// .tp_itemsize = 0,
|
147
|
+
// .tp_flags = Py_TPFLAGS_DEFAULT,
|
148
|
+
// .tp_new = StrIdxObject_new,
|
149
|
+
// .tp_dealloc = (destructor)StrIdxObject_dealloc,
|
150
|
+
// .tp_methods = StrIdxObject_methods,
|
151
|
+
// };
|
152
|
+
|
153
|
+
|
154
|
+
// Define python accessible methods
|
155
|
+
static PyMethodDef StrIdxMethods[] = {
|
156
|
+
{NULL, NULL, 0, NULL}};
|
157
|
+
|
158
|
+
static struct PyModuleDef moduledef = {
|
159
|
+
PyModuleDef_HEAD_INIT, "stridx", NULL, -1, StrIdxMethods, NULL, NULL, NULL, NULL};
|
160
|
+
|
161
|
+
PyMODINIT_FUNC PyInit_stridx(void) {
|
162
|
+
PyObject *m;
|
163
|
+
m = PyModule_Create(&moduledef);
|
164
|
+
|
165
|
+
// Initialize the type object
|
166
|
+
if (PyType_Ready(&StrIdxType) < 0) {
|
167
|
+
return NULL;
|
168
|
+
}
|
169
|
+
|
170
|
+
Py_INCREF(&StrIdxType);
|
171
|
+
if (PyModule_AddObject(m, "StringIndex", (PyObject *)&StrIdxType) < 0) {
|
172
|
+
Py_DECREF(&StrIdxType);
|
173
|
+
Py_DECREF(m);
|
174
|
+
return NULL;
|
175
|
+
}
|
176
|
+
|
177
|
+
if (!m) {
|
178
|
+
return NULL;
|
179
|
+
}
|
180
|
+
return m;
|
181
|
+
}
|
182
|
+
} // END extern "C"
|
data/runserver.rb
ADDED
data/server.rb
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "socket"
|
4
|
+
require "stridx"
|
5
|
+
|
6
|
+
module StrIdx
|
7
|
+
class Server
|
8
|
+
def recursively_find_files(directories)
|
9
|
+
filelist = []
|
10
|
+
|
11
|
+
for d in directories
|
12
|
+
filelist = filelist + Dir.glob("#{d}/**/*").select { |e|
|
13
|
+
File.file?(e)
|
14
|
+
# File.file?(e) or File.directory?(e)
|
15
|
+
}
|
16
|
+
end
|
17
|
+
return filelist
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.start(dir_list, daemonize: false)
|
21
|
+
Server.new(dir_list, daemonize: daemonize)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.stop
|
25
|
+
sock_dir = File.expand_path("~/.stridx")
|
26
|
+
sockfn = "#{sock_dir}/sock"
|
27
|
+
client = UNIXSocket.new(sockfn)
|
28
|
+
client.puts "stop"
|
29
|
+
response = client.recv(200 * 200)
|
30
|
+
client.close
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(dir_list, daemonize: false)
|
34
|
+
idx = StrIdx::StringIndex.new
|
35
|
+
idx.setDirSeparator("/")
|
36
|
+
|
37
|
+
t = Time.new
|
38
|
+
|
39
|
+
dirs = dir_list.select { |x| File.directory?(x) }
|
40
|
+
puts "Scanning files in directories:#{dirs.join(",")}"
|
41
|
+
flist = recursively_find_files(dirs)
|
42
|
+
|
43
|
+
i = 0
|
44
|
+
for x in flist
|
45
|
+
idx.add(x, i)
|
46
|
+
i += 1
|
47
|
+
end
|
48
|
+
|
49
|
+
idx.waitUntilDone()
|
50
|
+
idx_time = Time.new
|
51
|
+
puts "\nIndexing time (#{flist.size} files): #{(idx_time - t).round(4)} seconds"
|
52
|
+
|
53
|
+
sock_dir = File.expand_path("~/.stridx")
|
54
|
+
Dir.mkdir(sock_dir) if !Dir.exist?(sock_dir)
|
55
|
+
sockfn = "#{sock_dir}/sock"
|
56
|
+
File.unlink(sockfn) if File.exist?(sockfn)
|
57
|
+
|
58
|
+
puts "Indexing done, starting server"
|
59
|
+
if (daemonize)
|
60
|
+
require "daemons"
|
61
|
+
Daemons.daemonize
|
62
|
+
# exit if fork() # Daemonize
|
63
|
+
end
|
64
|
+
|
65
|
+
# exit if fork() # Daemonize
|
66
|
+
# $PROGRAM_NAME = "stridx-daemon"
|
67
|
+
|
68
|
+
t = Thread.new {
|
69
|
+
serv = UNIXServer.new(sockfn)
|
70
|
+
|
71
|
+
loop do
|
72
|
+
# Accept a new client connection
|
73
|
+
client = serv.accept
|
74
|
+
|
75
|
+
# puts "Client connected!"
|
76
|
+
|
77
|
+
# Read data from the client
|
78
|
+
data = client.recv(1024)
|
79
|
+
|
80
|
+
if data.match(/^stop$/)
|
81
|
+
puts "Got stop signal. Shutting down server."
|
82
|
+
client.close
|
83
|
+
break
|
84
|
+
end
|
85
|
+
|
86
|
+
# puts "Received from client: #{data}"
|
87
|
+
if data.match(/^find:(.*)/)
|
88
|
+
query = Regexp.last_match(1)
|
89
|
+
res = idx.find(query)
|
90
|
+
response = res.collect { |x| flist[x[0]] }.join("\n")
|
91
|
+
|
92
|
+
# Send a response back to the client
|
93
|
+
client.puts response
|
94
|
+
end
|
95
|
+
# Close the client connection
|
96
|
+
client.close
|
97
|
+
end
|
98
|
+
}
|
99
|
+
|
100
|
+
t.join
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/setup.py
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
import numpy
|
3
|
+
|
4
|
+
import setuptools
|
5
|
+
from setuptools import setup, Extension
|
6
|
+
|
7
|
+
__version__ = "0.1"
|
8
|
+
|
9
|
+
cargs = ['-fpermissive']
|
10
|
+
|
11
|
+
|
12
|
+
with open('README.md', 'r', encoding='utf-8') as f:
|
13
|
+
long_description = f.read()
|
14
|
+
|
15
|
+
module1 = Extension('stridx', sources=['py_interf.cpp'], include_dirs=['.'], extra_compile_args=cargs,
|
16
|
+
language="c++",
|
17
|
+
)
|
18
|
+
|
19
|
+
ext_modules = [module1]
|
20
|
+
|
21
|
+
setup(
|
22
|
+
name='stridx',
|
23
|
+
version='1.0',
|
24
|
+
setup_requires=['wheel'],
|
25
|
+
python_requires='>=3',
|
26
|
+
provides=['stridx'],
|
27
|
+
description='Fast fuzzy string similarity search and indexing (for filenames) ',
|
28
|
+
long_description=long_description,
|
29
|
+
long_description_content_type='text/markdown',
|
30
|
+
ext_modules=[module1]
|
31
|
+
)
|
32
|
+
|
Binary file
|
data/stridx-tty.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "tty-prompt"
|
4
|
+
require "tty-cursor"
|
5
|
+
require "tty-reader"
|
6
|
+
require "pastel"
|
7
|
+
|
8
|
+
require "socket"
|
9
|
+
|
10
|
+
class StrIdxTTY
|
11
|
+
def self.run
|
12
|
+
stty = StrIdxTTY.new
|
13
|
+
selected = stty.search
|
14
|
+
STDOUT.write selected
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize()
|
18
|
+
@lines = []
|
19
|
+
@selected = ""
|
20
|
+
@idx = 0
|
21
|
+
|
22
|
+
@reader = TTY::Reader.new(output: STDERR)
|
23
|
+
@pastel = Pastel.new()
|
24
|
+
@cursor = TTY::Cursor
|
25
|
+
|
26
|
+
sock_dir = File.expand_path("~/.stridx")
|
27
|
+
sockfn = "#{sock_dir}/sock"
|
28
|
+
|
29
|
+
error = true
|
30
|
+
while error
|
31
|
+
begin
|
32
|
+
# Create a new UNIXSocket
|
33
|
+
client = UNIXSocket.new(sockfn)
|
34
|
+
rescue Errno::ECONNREFUSED => e
|
35
|
+
out "Waiting for server to start\n"
|
36
|
+
sleep 2
|
37
|
+
error = true
|
38
|
+
else
|
39
|
+
error = false
|
40
|
+
client.close
|
41
|
+
#... executes when no error
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def out(x)
|
47
|
+
STDERR.write x
|
48
|
+
end
|
49
|
+
|
50
|
+
def search
|
51
|
+
out "\n" * 20
|
52
|
+
out @cursor.clear_screen
|
53
|
+
out "\n" * 20
|
54
|
+
@cursor.move_to(0, 0)
|
55
|
+
@reader.on(:keypress) { |event|
|
56
|
+
handle_event(event)
|
57
|
+
}
|
58
|
+
@reader.read_line(">> ")
|
59
|
+
|
60
|
+
out @cursor.clear_screen
|
61
|
+
return @selected.strip
|
62
|
+
end
|
63
|
+
|
64
|
+
def get_res_from_server(query)
|
65
|
+
# Define the socket file path
|
66
|
+
sock_dir = File.expand_path("~/.stridx")
|
67
|
+
sockfn = "#{sock_dir}/sock"
|
68
|
+
|
69
|
+
# Create a new UNIXSocket
|
70
|
+
client = UNIXSocket.new(sockfn)
|
71
|
+
|
72
|
+
# Send data to the server
|
73
|
+
client.puts "find:#{query}"
|
74
|
+
|
75
|
+
# Read response from the server
|
76
|
+
response = client.recv(200 * 200)
|
77
|
+
|
78
|
+
# Close the client connection
|
79
|
+
client.close
|
80
|
+
return response.lines
|
81
|
+
end
|
82
|
+
|
83
|
+
def draw_list()
|
84
|
+
@selected = @list[@idx]
|
85
|
+
i = 0
|
86
|
+
for x in @list
|
87
|
+
out @cursor.up(1)
|
88
|
+
out @cursor.clear_line
|
89
|
+
if i == @idx
|
90
|
+
out @pastel.lookup(:bold)
|
91
|
+
end
|
92
|
+
out x.strip
|
93
|
+
out @pastel.lookup(:reset)
|
94
|
+
i += 1
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def update_search(event)
|
99
|
+
query = event.line[3..-1]
|
100
|
+
if query.size > 2
|
101
|
+
@list = get_res_from_server(query)
|
102
|
+
draw_list
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def handle_event(event)
|
107
|
+
out @cursor.save
|
108
|
+
if event.key.name == :alpha
|
109
|
+
update_search(event)
|
110
|
+
elsif event.key.name == :up
|
111
|
+
@idx += 1 if @idx < @list.size - 1
|
112
|
+
draw_list
|
113
|
+
elsif event.key.name == :down
|
114
|
+
@idx -= 1 if @idx > 0
|
115
|
+
draw_list
|
116
|
+
elsif event.key.name == :backspace
|
117
|
+
update_search(event)
|
118
|
+
end
|
119
|
+
|
120
|
+
out @cursor.restore
|
121
|
+
end
|
122
|
+
end
|
data/stridx.gemspec
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
Gem::Specification.new do |spec|
|
2
|
+
spec.name = "StrIdx"
|
3
|
+
spec.version = "0.1.4"
|
4
|
+
spec.authors = ["Sami Sieranoja"]
|
5
|
+
spec.email = ["sami.sieranoja@gmail.com"]
|
6
|
+
|
7
|
+
spec.summary = %q{StrIdx}
|
8
|
+
spec.description = %q{ Fast fuzzy string similarity search and indexing (for filenames)}
|
9
|
+
spec.homepage = "https://github.com/SamiSieranoja/stridx"
|
10
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
11
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
12
|
+
|
13
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
14
|
+
f.match(%r{^(refcode|spec|features)/})
|
15
|
+
end
|
16
|
+
# spec.files << "thread_pool.hpp"
|
17
|
+
# spec.files << "exe/stridx.rb"
|
18
|
+
# spec.files << "server.rb"
|
19
|
+
# spec.files << "stridx-tty.rb"
|
20
|
+
|
21
|
+
spec.bindir = "exe"
|
22
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
|
+
spec.require_paths = ["lib", "ext"]
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 2.4.21"
|
26
|
+
spec.add_development_dependency "rake", "~> 13.1.0"
|
27
|
+
|
28
|
+
spec.add_runtime_dependency "tty-cursor", "~> 0.7.1"
|
29
|
+
spec.add_runtime_dependency "tty-prompt", "~> 0.23.1"
|
30
|
+
spec.add_runtime_dependency "tty-reader", "~> 0.9.0"
|
31
|
+
spec.add_runtime_dependency "tty-screen", "~> 0.8.2"
|
32
|
+
spec.add_runtime_dependency "pastel", "~> 0.8.0"
|
33
|
+
spec.add_runtime_dependency "daemons", "~> 1.4.1"
|
34
|
+
|
35
|
+
spec.extensions = ["rubyext/extconf.rb"]
|
36
|
+
spec.licenses = ["LGPL-2.0+"]
|
37
|
+
end
|
data/stridx.hpp
CHANGED
@@ -33,16 +33,16 @@ public:
|
|
33
33
|
Output(int verb) : verboseLevel(verb) {}
|
34
34
|
Output() : Output(3) {}
|
35
35
|
~Output() = default;
|
36
|
-
void print() {}
|
36
|
+
static void print() {}
|
37
37
|
|
38
38
|
// When calling as print("xxx ",3, " yyy") outputs "xxx 3 yyy"
|
39
|
-
template <typename T, typename... Types> void print(T var1, Types... var2) {
|
39
|
+
template <typename T, typename... Types> static void print(T var1, Types... var2) {
|
40
40
|
std::cout << var1;
|
41
41
|
print(var2...);
|
42
42
|
}
|
43
43
|
|
44
44
|
// When calling as printl("xxx ",3, " yyy") outputs "xxx 3 yyy\n"
|
45
|
-
template <typename... Types> void printl(Types... var2) {
|
45
|
+
template <typename... Types> static void printl(Types... var2) {
|
46
46
|
print(var2...);
|
47
47
|
print("\n");
|
48
48
|
}
|
@@ -79,7 +79,7 @@ std::vector<std::string> splitString(const std::string &input, const char &separ
|
|
79
79
|
}
|
80
80
|
|
81
81
|
// Convert int64_t to binary string
|
82
|
-
[[nodiscard]] std::string int64ToBinaryString(int64_t num) {
|
82
|
+
[[nodiscard]] std::string int64ToBinaryString(const int64_t &num) {
|
83
83
|
std::string result;
|
84
84
|
for (int i = 63; i >= 0; --i) {
|
85
85
|
result += ((num >> i) & 1) ? '1' : '0';
|
@@ -88,7 +88,7 @@ std::vector<std::string> splitString(const std::string &input, const char &separ
|
|
88
88
|
}
|
89
89
|
|
90
90
|
// Debug. Convert a (8 char) string represented as int64_t to std::string
|
91
|
-
[[nodiscard]] std::string int64ToStr(int64_t key) {
|
91
|
+
[[nodiscard]] std::string int64ToStr(const int64_t &key) {
|
92
92
|
int nchars = 8;
|
93
93
|
std::string str;
|
94
94
|
int multip = nchars * 8;
|
@@ -108,7 +108,7 @@ void printVector(const std::vector<int> &vec) {
|
|
108
108
|
}
|
109
109
|
|
110
110
|
// Debug
|
111
|
-
[[nodiscard]] std::string charToBinaryString(char chr) {
|
111
|
+
[[nodiscard]] std::string charToBinaryString(const char &chr) {
|
112
112
|
std::string result;
|
113
113
|
for (int i = 7; i >= 0; --i) {
|
114
114
|
result += ((chr >> i) & 1) ? '1' : '0';
|
@@ -122,8 +122,7 @@ enum class segmentType { Dir, File };
|
|
122
122
|
// A segment of a file path
|
123
123
|
// e.g. if path is /foo/bar/baz.txt
|
124
124
|
// segments are [{root}, foo, bar, baz.txt]
|
125
|
-
|
126
|
-
public:
|
125
|
+
struct PathSegment {
|
127
126
|
std::string str;
|
128
127
|
int fileId; // (if FILE)
|
129
128
|
Candidate *cand;
|
@@ -135,7 +134,7 @@ public:
|
|
135
134
|
PathSegment(std::string _str) : str(_str), parent(nullptr) {}
|
136
135
|
PathSegment(std::string _str, int _fileId)
|
137
136
|
: str(_str), fileId(_fileId), cand(nullptr), parent(nullptr) {}
|
138
|
-
[[nodiscard]] int size() {
|
137
|
+
[[nodiscard]] int size() const {
|
139
138
|
int sz = str.size();
|
140
139
|
PathSegment *cur = parent;
|
141
140
|
// Sum up length of parent segments (+1 for divisors)
|
@@ -148,8 +147,7 @@ public:
|
|
148
147
|
};
|
149
148
|
|
150
149
|
// Candidate for result in string (filename) search
|
151
|
-
|
152
|
-
public:
|
150
|
+
struct Candidate {
|
153
151
|
std::vector<float> v_charscore;
|
154
152
|
PathSegment *seg;
|
155
153
|
int fileId;
|
@@ -162,25 +160,17 @@ public:
|
|
162
160
|
int candLen; // Length of candidate
|
163
161
|
|
164
162
|
Candidate(){};
|
165
|
-
Candidate(int _fileId, std::string _str, int _len) : fileId(_fileId), str(_str), len(_len) {
|
166
|
-
// Initialize v_charscores with zeros
|
167
|
-
v_charscore.resize(len, 0);
|
168
|
-
candLen = str.size();
|
169
|
-
seg = nullptr;
|
170
|
-
}
|
171
|
-
|
172
163
|
Candidate(PathSegment *_seg, int _len) : seg(_seg), len(_len) {
|
173
164
|
// Initialize v_charscores with zeros
|
174
165
|
v_charscore.resize(len, 0);
|
175
166
|
candLen = seg->size();
|
176
167
|
}
|
177
168
|
|
178
|
-
[[nodiscard]] float getScore() {
|
169
|
+
[[nodiscard]] float getScore() const {
|
179
170
|
int i = 0;
|
180
171
|
float score = 0.0;
|
181
|
-
candLen = seg->size();
|
182
172
|
|
183
|
-
for (float &charscore : v_charscore) {
|
173
|
+
for (const float &charscore : v_charscore) {
|
184
174
|
score += charscore;
|
185
175
|
i++;
|
186
176
|
}
|
@@ -193,7 +183,7 @@ public:
|
|
193
183
|
return score;
|
194
184
|
}
|
195
185
|
|
196
|
-
[[nodiscard]] float operator[](int idx) { return v_charscore[idx]; }
|
186
|
+
[[nodiscard]] float operator[](int idx) const { return v_charscore[idx]; }
|
197
187
|
};
|
198
188
|
|
199
189
|
// This seems to give 10x speed improvement over std::unordered_map
|
@@ -210,19 +200,17 @@ private:
|
|
210
200
|
int numStrings = 0;
|
211
201
|
|
212
202
|
std::vector<SegMap *> dirmaps;
|
203
|
+
std::array<std::mutex, 9> mts_d; // for dirmaps
|
213
204
|
std::vector<SegMap *> filemaps;
|
205
|
+
std::array<std::mutex, 9> mts_f; // for filemaps
|
214
206
|
|
215
207
|
std::vector<PathSegment *> segsToClean;
|
216
208
|
|
217
|
-
std::unordered_map<int, std::string> strlist;
|
218
209
|
std::unordered_map<int, PathSegment *> seglist;
|
219
210
|
PathSegment *root;
|
220
211
|
int dirId = 0;
|
221
212
|
float dirWeight = 0.7; // Give only 70% of score if match is for a directory
|
222
213
|
|
223
|
-
std::array<std::mutex, 9> mts_f;
|
224
|
-
std::array<std::mutex, 9> mts_d;
|
225
|
-
|
226
214
|
std::unique_ptr<ThreadPool> pool;
|
227
215
|
Output out{1}; // verbose level = 1
|
228
216
|
|
@@ -279,9 +267,11 @@ public:
|
|
279
267
|
void addStrToIndexThreaded(std::string filePath, int fileId) {
|
280
268
|
pool->enqueue([=] { addStrToIndex(filePath, fileId, dirSeparator); });
|
281
269
|
}
|
282
|
-
void waitUntilReady() { pool->waitUntilDone(); }
|
270
|
+
void waitUntilReady() const { pool->waitUntilDone(); }
|
283
271
|
|
284
|
-
void waitUntilDone() { pool->waitUntilDone(); }
|
272
|
+
void waitUntilDone() const { pool->waitUntilDone(); }
|
273
|
+
|
274
|
+
int size() const { return seglist.size(); }
|
285
275
|
|
286
276
|
/**
|
287
277
|
* Add a string to the index to be searched for afterwards
|
@@ -291,8 +281,14 @@ public:
|
|
291
281
|
* @param separator Can be used to split filePath to components (e.g. 'home','user'...). Usually
|
292
282
|
* one of {'\\', '/', '\0' (no separation)}.
|
293
283
|
*/
|
284
|
+
|
294
285
|
void addStrToIndex(std::string filePath, int fileId, const char &separator) {
|
295
|
-
out.printv(3, "Add file:", filePath, ",", fileId, ",", separator);
|
286
|
+
out.printv(3, "Add file:", filePath, ",", fileId, ",", separator, ",",dirSeparator);
|
287
|
+
|
288
|
+
// If a string with this index has beeen added already
|
289
|
+
if (seglist.find(fileId) != seglist.end()) {
|
290
|
+
return;
|
291
|
+
}
|
296
292
|
|
297
293
|
std::vector<std::string> segs;
|
298
294
|
numStrings += 1;
|
@@ -345,6 +341,17 @@ public:
|
|
345
341
|
}
|
346
342
|
}
|
347
343
|
|
344
|
+
std::string getString(int id) {
|
345
|
+
std::string s = "";
|
346
|
+
PathSegment *seg = seglist[id];
|
347
|
+
s += seg->str;
|
348
|
+
while (seg->parent->parent != nullptr) {
|
349
|
+
seg = seg->parent;
|
350
|
+
s = seg->str + dirSeparator + s;
|
351
|
+
}
|
352
|
+
return s;
|
353
|
+
}
|
354
|
+
|
348
355
|
/**
|
349
356
|
The search will find filepaths similar to the input string
|
350
357
|
|
@@ -423,7 +430,7 @@ public:
|
|
423
430
|
}
|
424
431
|
|
425
432
|
// Return int64_t representation of the first nchars in str, starting from index i
|
426
|
-
[[nodiscard]] int64_t getKeyAtIdx(std::string str, int i, int nchars) {
|
433
|
+
[[nodiscard]] int64_t getKeyAtIdx(const std::string &str, int i, int nchars) const {
|
427
434
|
int64_t key = 0;
|
428
435
|
for (int i_char = 0; i_char < nchars; i_char++) {
|
429
436
|
key = key | static_cast<int64_t>(str[i + i_char]);
|
@@ -519,7 +526,7 @@ private:
|
|
519
526
|
// Find pathsegments from <map> that include the substring of <str> which starts at index <i> and
|
520
527
|
// is of length <nchars>.
|
521
528
|
[[nodiscard]] std::vector<PathSegment *> findSimilarForNgram(std::string str, int i, int nchars,
|
522
|
-
SegMap &map) {
|
529
|
+
SegMap &map) const {
|
523
530
|
|
524
531
|
assert(i + nchars <= static_cast<int>(str.size()));
|
525
532
|
std::vector<PathSegment *> res;
|
data/test.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
+
$:.unshift File.dirname(__FILE__)
|
4
|
+
|
3
5
|
require "stridx"
|
4
6
|
idx = StrIdx::StringIndex.new
|
5
7
|
|
8
|
+
# "/" for unix-style file paths
|
9
|
+
idx.setDirSeparator("/") #(comment out if not file paths)
|
10
|
+
|
6
11
|
t = Time.new
|
7
12
|
fn = File.expand_path("flist.txt")
|
8
13
|
lines = IO.read(fn).lines.collect { |x| x.strip }
|
@@ -14,12 +19,12 @@ end
|
|
14
19
|
|
15
20
|
idx_time = Time.new
|
16
21
|
# Time to start the threadpool to process indexing
|
17
|
-
puts "\nIndexing launch time (#{lines.size} files
|
22
|
+
puts "\nIndexing launch time (#{lines.size} files): #{(idx_time - t).round(4)} seconds"
|
18
23
|
|
19
24
|
idx.waitUntilDone() # Not necessary, will be called by idx.find
|
20
25
|
idx_time = Time.new
|
21
26
|
# Time when all threads have completed
|
22
|
-
puts "\nIndexing completed time (#{lines.size} files
|
27
|
+
puts "\nIndexing completed time (#{lines.size} files): #{(idx_time - t).round(4)} seconds"
|
23
28
|
|
24
29
|
query = "rngnomadriv"
|
25
30
|
res = idx.find(query)
|
data/unit_tests.sh
ADDED
data/unittest.cpp
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
|
2
|
+
#include <gtest/gtest.h>
|
3
|
+
#include "stridx.hpp"
|
4
|
+
#include <cmath>
|
5
|
+
#include <memory>
|
6
|
+
|
7
|
+
TEST(SplitString, MatchSize) {
|
8
|
+
std::vector<std::string> svec = StrIdx::splitString("foo/bar/test1.txt", '/');
|
9
|
+
EXPECT_EQ(svec.size(), 3);
|
10
|
+
if (svec.size() == 3) {
|
11
|
+
EXPECT_EQ(svec[0].size(), 3);
|
12
|
+
EXPECT_EQ(svec[2].size(), 9);
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
std::vector<std::string> flist{"./drivers/char/hw_random/nomadik-rng.c",
|
17
|
+
"./drivers/pinctrl/nomadik",
|
18
|
+
"./drivers/clk/clk-nomadik.c",
|
19
|
+
"./drivers/gpio/gpio-nomadik.c",
|
20
|
+
"./drivers/i2c/busses/i2c-nomadik.c",
|
21
|
+
"./drivers/clocksource/nomadik-mtu.c",
|
22
|
+
"./drivers/gpu/drm/pl111/pl111_nomadik.h",
|
23
|
+
"./drivers/gpu/drm/pl111/pl111_nomadik.c",
|
24
|
+
"./drivers/pinctrl/nomadik/pinctrl-nomadik.c",
|
25
|
+
"./drivers/input/keyboard/nomadik-ske-keypad.c",
|
26
|
+
"./drivers/pinctrl/nomadik/pinctrl-nomadik-db8500.c",
|
27
|
+
"./drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c",
|
28
|
+
"./drivers/char/hw_random/omap-rng.c",
|
29
|
+
"./drivers/char/hw_random/omap3-rom-rng.c",
|
30
|
+
"./include/dt-bindings/pinctrl/nomadik.h",
|
31
|
+
"./Documentation/devicetree/bindings/arm/ste-nomadik.txt"};
|
32
|
+
|
33
|
+
std::vector<float> target_scores{0.342944, 0.271396, 0.271126, 0.270893, 0.270431, 0.270355,
|
34
|
+
0.270088, 0.270088, 0.26987, 0.269776, 0.269574, 0.269538,
|
35
|
+
0.236358, 0.236074, 0.224804, 0.224238};
|
36
|
+
|
37
|
+
void scoreTest(bool threaded) {
|
38
|
+
|
39
|
+
StrIdx::StringIndex idx('/'); // Separate directories using unix style "/" char
|
40
|
+
std::string query = "rngnomadriv";
|
41
|
+
|
42
|
+
int i = 1;
|
43
|
+
for (const auto &str : flist) {
|
44
|
+
if (threaded) {
|
45
|
+
idx.addStrToIndexThreaded(str, i);
|
46
|
+
} else {
|
47
|
+
idx.addStrToIndex(str, i);
|
48
|
+
}
|
49
|
+
i++;
|
50
|
+
}
|
51
|
+
const std::vector<std::pair<float, int>> &results = idx.findSimilar(query);
|
52
|
+
|
53
|
+
std::cout << results[0].first;
|
54
|
+
EXPECT_EQ(results[0].second, 1);
|
55
|
+
if (results.size() == 16) {
|
56
|
+
int i = 0;
|
57
|
+
for (const auto &res : results) {
|
58
|
+
// Check if first five digits of the scores match
|
59
|
+
EXPECT_EQ(std::floor(res.first * 1e5), std::floor(1e5 * target_scores[i]));
|
60
|
+
i++;
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
TEST(IndexSearch, MatchingScoresSingleThread) { scoreTest(false); }
|
66
|
+
TEST(IndexSearch, MatchingScoresThreaded) { scoreTest(true); }
|
67
|
+
|
68
|
+
class IndexTest : public testing::Test {
|
69
|
+
protected:
|
70
|
+
std::unique_ptr<StrIdx::StringIndex> idx = std::make_unique<StrIdx::StringIndex>('/');
|
71
|
+
|
72
|
+
IndexTest() {}
|
73
|
+
|
74
|
+
void SetUp() override {
|
75
|
+
// Code here will be called immediately after the constructor (right
|
76
|
+
// before each test).
|
77
|
+
idx = std::make_unique<StrIdx::StringIndex>('/');
|
78
|
+
}
|
79
|
+
|
80
|
+
void TearDown() override {
|
81
|
+
// Code here will be called immediately after each test (right
|
82
|
+
// before the destructor).
|
83
|
+
}
|
84
|
+
};
|
85
|
+
|
86
|
+
TEST_F(IndexTest, BinaryRepresentation1) {
|
87
|
+
int64_t num = idx->getKeyAtIdx("abcdefgh", 0, 8);
|
88
|
+
std::string s = StrIdx::int64ToBinaryString(num);
|
89
|
+
// a b c d ...
|
90
|
+
EXPECT_TRUE(s == "0110000101100010011000110110010001100101011001100110011101101000");
|
91
|
+
}
|
92
|
+
|
93
|
+
TEST_F(IndexTest, BinaryRepresentation2) {
|
94
|
+
int64_t num = idx->getKeyAtIdx("abcdefgh", 0, 1);
|
95
|
+
std::string s = StrIdx::int64ToBinaryString(num);
|
96
|
+
EXPECT_TRUE(
|
97
|
+
s == "0000000000000000000000000000000000000000000000000000000001100001"); // 01100001 == "a"
|
98
|
+
}
|
99
|
+
TEST_F(IndexTest, BinaryRepresentation3) {
|
100
|
+
int64_t num = idx->getKeyAtIdx("abcdefgh", 7, 1);
|
101
|
+
std::string s = StrIdx::int64ToBinaryString(num);
|
102
|
+
EXPECT_TRUE(
|
103
|
+
s == "0000000000000000000000000000000000000000000000000000000001101000"); // 01101000 == "h"
|
104
|
+
}
|
105
|
+
|
106
|
+
TEST_F(IndexTest, AccessString) {
|
107
|
+
idx->addStrToIndex("./drivers/i2c/busses/i2c-nomadik.c", 0);
|
108
|
+
idx->addStrToIndex("./drivers/i2c/busses/i2c-nomadiksdf.c", 2);
|
109
|
+
idx->addStrToIndex("./drivers//i2c///busses////aa-i2c-nomadiksdf.c", 3);
|
110
|
+
idx->addStrToIndex("/test/foo/bar.txt", 4);
|
111
|
+
idx->addStrToIndex("bar.txt", 5);
|
112
|
+
|
113
|
+
EXPECT_EQ(idx->size(), 5);
|
114
|
+
EXPECT_STREQ(idx->getString(0).c_str(), "./drivers/i2c/busses/i2c-nomadik.c");
|
115
|
+
|
116
|
+
// TODO: does not work yet
|
117
|
+
// EXPECT_STREQ(idx->getString(3).c_str(), "./drivers//i2c///busses////aa-i2c-nomadiksdf.c");
|
118
|
+
|
119
|
+
// TODO: does not work yet
|
120
|
+
// EXPECT_STREQ(idx->getString(4).c_str(), "/test/foo/bar.txt");
|
121
|
+
EXPECT_STREQ(idx->getString(5).c_str(), "bar.txt");
|
122
|
+
}
|
123
|
+
|
124
|
+
TEST_F(IndexTest, Size1) {
|
125
|
+
// Should not add different files with same id
|
126
|
+
idx->addStrToIndex("./drivers/i2c/busses/i2c-nomadik.c", 0);
|
127
|
+
idx->addStrToIndex("./drivers/i2c/busses/i2c-nomadiksdf.c", 0);
|
128
|
+
|
129
|
+
// Should not be added because essentially same as 0:
|
130
|
+
idx->addStrToIndex("./drivers//i2c///busses////i2c-nomadik.c", 44);
|
131
|
+
|
132
|
+
// Should not add same file with different id
|
133
|
+
idx->addStrToIndex("./drivers/i2c/busses/i2c-nomadik.c", 1);
|
134
|
+
idx->addStrToIndex("./drivers/i2c/busses/i2c-nomadik.c", 2);
|
135
|
+
|
136
|
+
EXPECT_EQ(idx->size(), 1);
|
137
|
+
|
138
|
+
// Test no-overwriting
|
139
|
+
EXPECT_STREQ(idx->getString(0).c_str(), "./drivers/i2c/busses/i2c-nomadik.c");
|
140
|
+
}
|
141
|
+
|
142
|
+
TEST_F(IndexTest, Size2) {
|
143
|
+
idx->addStrToIndex("./drivers/i2c/busses/i2c-nomadik.c", 22);
|
144
|
+
idx->addStrToIndex("./Documentation/devicetree/bindings/arm/ste-nomadik.txt", 1);
|
145
|
+
idx->addStrToIndex("./Documentation/devicetree/bindings/arm/ste-nomadik33.txt", 3);
|
146
|
+
EXPECT_EQ(idx->size(), 3);
|
147
|
+
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: StrIdx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sami Sieranoja
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-06-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -38,24 +38,123 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 13.1.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: tty-cursor
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.7.1
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.7.1
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: tty-prompt
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.23.1
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.23.1
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: tty-reader
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.9.0
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.9.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: tty-screen
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.8.2
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.8.2
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: pastel
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.8.0
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.8.0
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: daemons
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 1.4.1
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 1.4.1
|
41
125
|
description: " Fast fuzzy string similarity search and indexing (for filenames)"
|
42
126
|
email:
|
43
127
|
- sami.sieranoja@gmail.com
|
44
|
-
executables:
|
128
|
+
executables:
|
129
|
+
- stridx.rb
|
45
130
|
extensions:
|
46
131
|
- rubyext/extconf.rb
|
47
132
|
extra_rdoc_files: []
|
48
133
|
files:
|
134
|
+
- CMakeLists.txt
|
135
|
+
- Gemfile
|
49
136
|
- LICENSE
|
50
137
|
- Makefile
|
51
138
|
- README.md
|
52
139
|
- demo.cpp
|
140
|
+
- exe/stridx.rb
|
53
141
|
- flist.txt
|
142
|
+
- gem_install
|
143
|
+
- py_example.py
|
144
|
+
- py_interf.cpp
|
54
145
|
- rubyext/extconf.rb
|
55
146
|
- rubyext/ruby_interf.cpp
|
147
|
+
- runserver.rb
|
148
|
+
- server.rb
|
149
|
+
- setup.py
|
150
|
+
- stridx-screencast.mp4
|
151
|
+
- stridx-tty.rb
|
152
|
+
- stridx.gemspec
|
56
153
|
- stridx.hpp
|
57
154
|
- test.rb
|
58
155
|
- thread_pool.hpp
|
156
|
+
- unit_tests.sh
|
157
|
+
- unittest.cpp
|
59
158
|
- unordered_dense.h
|
60
159
|
homepage: https://github.com/SamiSieranoja/stridx
|
61
160
|
licenses:
|
@@ -63,7 +162,7 @@ licenses:
|
|
63
162
|
metadata:
|
64
163
|
source_code_uri: https://github.com/SamiSieranoja/stridx
|
65
164
|
homepage_uri: https://github.com/SamiSieranoja/stridx
|
66
|
-
post_install_message:
|
165
|
+
post_install_message:
|
67
166
|
rdoc_options: []
|
68
167
|
require_paths:
|
69
168
|
- lib
|
@@ -80,7 +179,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
80
179
|
version: '0'
|
81
180
|
requirements: []
|
82
181
|
rubygems_version: 3.3.26
|
83
|
-
signing_key:
|
182
|
+
signing_key:
|
84
183
|
specification_version: 4
|
85
184
|
summary: StrIdx
|
86
185
|
test_files: []
|