Skip to content

Commit

Permalink
Implement more native API and remove legacy dependency (#22)
Browse files Browse the repository at this point in the history
* Implement match(), wrap() natively.
* Do not support prepareQuery(), since it only precomputes something for query which is not a major optimization.
* Remove fuzzaldrin-plus dependency for prod (still depends on for dev/tests).
  • Loading branch information
rajendrant authored Sep 4, 2020
1 parent cde1276 commit 204b0f4
Show file tree
Hide file tree
Showing 9 changed files with 368 additions and 43 deletions.
2 changes: 1 addition & 1 deletion binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"targets": [
{
"target_name": "fuzzaldrinplusfast",
"sources": [ "src/fuzzaldrin.cc", "src/scorer.cc", "src/path_scorer.cc", "src/filter.cc", "src/query.cc" ],
"sources": [ "src/fuzzaldrin.cc", "src/scorer.cc", "src/path_scorer.cc", "src/filter.cc", "src/query.cc", "src/matcher.cc" ],
"cflags!": [ "-fno-exceptions" ],
"cflags_cc!": [ "-fno-exceptions" ],
"include_dirs": [
Expand Down
18 changes: 5 additions & 13 deletions fuzzaldrin.coffee
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
binding = require('node-gyp-build')(__dirname);

# for missing API
matcher = require('fuzzaldrin-plus/lib/matcher')
Query = require('fuzzaldrin-plus/lib/query')

defaultPathSeparator = if process?.platform is "win32" then '\\' else '/'

preparedQueryCache = null
parseOptions = (options, query) ->
options.allowErrors ?= false
options.usePathScoring ?= true
Expand All @@ -15,10 +10,6 @@ parseOptions = (options, query) ->
options.optCharRegEx ?= null
options.wrap ?= null
options.maxResults ?= 0
options.preparedQuery ?=
if preparedQueryCache and preparedQueryCache.query is query
then preparedQueryCache
else (preparedQueryCache = new Query(query, options))
return options

class FuzzaldrinPlusFast
Expand Down Expand Up @@ -58,14 +49,15 @@ module.exports =
return [] unless query
return [0...string.length] if string is query
options = parseOptions(options, query)
return matcher.match(string, query, options)
return binding.match(string, query, options.pathSeparator)

wrap: (string, query, options = {}) ->
return [] unless string
return [] unless query
options = parseOptions(options, query)
return matcher.wrap(string, query, options)
return binding.wrap(string, query, options.pathSeparator)

prepareQuery: (query, options = {}) ->
options = parseOptions(options, query)
return options.preparedQuery
# This is no-op since there is no major benefit by precomputing something
# just for the query.
return {}
5 changes: 3 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@
"dependencies": {
"bindings": "~1.5.0",
"node-addon-api": "~3.0.0",
"node-gyp-build": "^4.2.3",
"fuzzaldrin-plus": "^0.6.0"
"node-gyp-build": "^4.2.3"
},
"devDependencies": {
"babel-preset-atomic": "^1.1.0",
"cross-env": "^7.0.2",
"fuzzaldrin-plus": "^0.6.0",
"growl": ">=1.10.5",
"jasmine-node": "^3.0.0",
"npm-check-updates": "8.0.3",
"npm-check-updates": "8.1.0",
"parcel": "^2.0.0-nightly.387",
"prebuildify": "^4.0.0",
"shx": "^0.3.2"
Expand All @@ -61,4 +61,4 @@
"url": "https://github.com/rajendrant/fuzzaldrin-plus-fast/issues"
},
"homepage": "https://github.com/rajendrant/fuzzaldrin-plus-fast"
}
}
23 changes: 23 additions & 0 deletions spec/wrap-spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const path = require('path')
const {
wrap
} = require('../fuzzaldrin-dist')
const legacy = require('fuzzaldrin-plus')

describe("wrap(string, query)", () => {
const candidates = [
"helloworld", "Helloworld", "HelloWorld",
"hello world", "Hello world", "Hello World",
path.join("hello", "world"),
]
const queries = [
"he", "hl", "hw", "el", "eo", "ll", "wo", "ld", "", "helloworld",
]
it("returns same for hello world", () => {
for (const c of candidates) {
for (const q of queries) {
expect(wrap(c, q)).toEqual(legacy.wrap(c, q))
}
}
})
})
17 changes: 17 additions & 0 deletions src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,26 @@ struct Options {
const PreparedQuery preparedQuery;

Options(const Element &query, size_t maxResults, bool usePathScoring, bool useExtensionBonus) : max_results(maxResults), usePathScoring(usePathScoring), useExtensionBonus(useExtensionBonus), preparedQuery(query, pathSeparator) {}
Options(const Element &query, char pathSeparator) : pathSeparator(pathSeparator), preparedQuery(query, pathSeparator) {}
};

struct AcronymResult {
Score score;
float pos;
int count;

AcronymResult(Score s, float p, int c) : score(s), pos(p), count(c) {}
};

extern Element ToLower(const Element &s);
extern Element ToUpper(const Element &s);

extern bool isMatch(const Candidate &subject, const Element &query_lw, const Element &query_up);
extern bool isWordStart(int pos, const Candidate &subject, const Candidate &subject_lw);
extern Score scoreCharacter(int i, int j, bool start, Score acro_score, Score csc_score);
extern Score scoreConsecutives(const Candidate &subject, const Candidate &subject_lw, const Element &query, const Element &query_lw, int i, int j, bool startOfWord);
extern AcronymResult scoreAcronyms(Candidate subject, Candidate subject_lw, Element query, Element query_lw);

extern Score computeScore(const Candidate &subject, const Candidate &subject_lw, const PreparedQuery &preparedQuery);

extern Score scorer_score(const Candidate &string, const Element &query, const Options &options);
Expand All @@ -83,3 +97,6 @@ extern int countDir(const Candidate &path, int end, char pathSeparator);
extern Candidate getExtension(const Candidate &str);

extern CandidateIndexes filter(const vector<Candidates> &candidates, const Element &query, const Options &options);

extern std::vector<size_t> matcher_match(const Candidate &string, const Element &query, const Options &options);
extern void get_wrap(const Candidate &string, const Element &query, const Options &options, std::string *out);
50 changes: 43 additions & 7 deletions src/fuzzaldrin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,6 @@ Napi::Value Fuzzaldrin::Filter(const Napi::CallbackInfo& info) {
Options options(query, maxResults, usePathScoring, useExtensionBonus);
const auto matches = filter(candidates_, query, options);

std::vector<size_t> counts;
size_t start = 0;
for(const auto &c : candidates_) {
counts.push_back(start);
start += c.size();
}

for(uint32_t i=0; i<matches.size(); i++) {
res[i] = Napi::Number::New(info.Env(), matches[i]);
}
Expand Down Expand Up @@ -70,6 +63,47 @@ Napi::Number score(const Napi::CallbackInfo& info) {
return Napi::Number::New(info.Env(), score);
}

Napi::Array match(const Napi::CallbackInfo& info) {
Napi::Array res = Napi::Array::New(info.Env());
if (info.Length() != 3 || !info[0].IsString() || !info[1].IsString() ||
!info[2].IsString()) {
Napi::TypeError::New(info.Env(), "Invalid arguments").ThrowAsJavaScriptException();
return res;
}
std::string candidate = info[0].As<Napi::String>();
std::string query = info[1].As<Napi::String>();
std::string pathSeparator = info[2].As<Napi::String>();
if (pathSeparator.size() != 1) {
Napi::TypeError::New(info.Env(), "Invalid arguments").ThrowAsJavaScriptException();
return res;
}
Options options(query, pathSeparator[0]);
auto matches = matcher_match(candidate, query, options);
for(uint32_t i=0; i<matches.size(); i++) {
res[i] = Napi::Number::New(info.Env(), matches[i]);
}
return res;
}

Napi::String wrap(const Napi::CallbackInfo& info) {
if (info.Length() != 3 || !info[0].IsString() || !info[1].IsString() ||
!info[2].IsString()) {
Napi::TypeError::New(info.Env(), "Invalid arguments").ThrowAsJavaScriptException();
return Napi::String::New(info.Env(), "");
}
std::string candidate = info[0].As<Napi::String>();
std::string query = info[1].As<Napi::String>();
std::string pathSeparator = info[2].As<Napi::String>();
if (pathSeparator.size() != 1) {
Napi::TypeError::New(info.Env(), "Invalid arguments").ThrowAsJavaScriptException();
return Napi::String::New(info.Env(), "");
}
Options options(query, pathSeparator[0]);
std::string res;
get_wrap(candidate, query, options, &res);
return Napi::String::New(info.Env(), res);
}

Napi::Object Fuzzaldrin::Init(Napi::Env env, Napi::Object exports) {
Napi::HandleScope scope(env);

Expand All @@ -80,6 +114,8 @@ Napi::Object Fuzzaldrin::Init(Napi::Env env, Napi::Object exports) {

exports.Set("Fuzzaldrin", func);
exports.Set("score", Napi::Function::New(env, score));
exports.Set("match", Napi::Function::New(env, match));
exports.Set("wrap", Napi::Function::New(env, wrap));
return exports;
}

Expand Down
Loading

0 comments on commit 204b0f4

Please sign in to comment.