Compare commits

...

8 Commits

Author SHA1 Message Date
seb
fb8f61f868 Fix node-gyp compatibility: move to dependencies for proper version control
- Move node-gyp from devDependencies to dependencies
- Ensures v11.2.0 is used when installed as dependency
- Fixes Visual Studio detection issues in consuming projects
- Resolves shopApi build failures with old node-gyp v8.4.1
2025-06-27 03:37:33 +02:00
seb
091c258d41 Update package.json to include Node.js engine requirement and enhance build scripts. Add new keywords for better package discoverability, define repository information, and specify supported operating systems and CPU architectures. Introduce devDependencies for node-gyp to streamline native module compilation. 2025-06-27 03:32:24 +02:00
seb
8474c77163 Enhance search index handling by returning an empty array for no results instead of throwing an error. Improve memory management in free_words function by checking for NULL before freeing. Update search_index to properly return NULL when no results are found. 2025-06-27 03:15:45 +02:00
seb
21f527ba46 Update .gitignore to ignore npm lock file and tidy entry
Add package-lock.json to prevent accidental commits of npm’s lock
file. While here, remove the stray trailing space from the Thumbs.db
entry for a cleaner diff.
2025-06-23 07:09:30 +02:00
seb
462041654d Optimize search result finalization by reallocating in place
Replace the malloc/copy/free sequence with a single realloc that
shrinks temp_results to its exact size and returns it directly.  This

* eliminates an extra allocation and memory copy
* simplifies cleanup logic
* retains correct failure handling (temp_results unchanged on realloc
  failure)

Also drop the superfluous trailing space at EOF and add package-lock.json
to version control to lock Node.js dependencies.
2025-06-23 04:16:18 +02:00
seb
60d609dd6a Fix Windows compilation issue by adding malloc.h include 2025-06-21 21:14:20 +02:00
seb
ccbd833361 package.json aktualisiert 2025-04-22 04:39:00 +00:00
seb
24895fc1bc similarity_search.c aktualisiert
3 -> 2 (min word length)
2025-04-22 04:35:04 +00:00
4 changed files with 69 additions and 25 deletions

2
.gitignore vendored
View File

@@ -23,3 +23,5 @@ build/
.Trashes
ehthumbs.db
Thumbs.db
package-lock.json

View File

@@ -1,23 +1,59 @@
{
"name": "similarity-search",
"version": "1.0.1",
"version": "1.0.2",
"description": "A Node.js module for word order independent string similarity search",
"main": "index.js",
"engines": {
"node": ">=14.0.0"
},
"scripts": {
"install": "node-gyp rebuild",
"test": "node test.js"
"rebuild": "node-gyp rebuild",
"build": "node-gyp rebuild",
"clean": "node-gyp clean",
"configure": "node-gyp configure",
"test": "node test.js",
"pretest": "npm run build"
},
"keywords": [
"search",
"similarity",
"string",
"fuzzy"
"fuzzy",
"native",
"addon",
"c++",
"performance"
],
"author": "",
"license": "MIT",
"dependencies": {
"nan": "^2.22.2",
"node-addon-api": "^6.0.0"
"node-addon-api": "^6.0.0",
"node-gyp": "^11.2.0"
},
"gypfile": true
"devDependencies": {
},
"repository": {
"type": "git",
"url": ""
},
"files": [
"index.js",
"binding.gyp",
"similarity_search.c",
"similarity_search.h",
"similarity_search_addon.cc",
"README.md"
],
"gypfile": true,
"os": [
"win32",
"darwin",
"linux"
],
"cpu": [
"x64",
"arm64"
]
}

View File

@@ -5,6 +5,11 @@
#include <ctype.h>
#include <math.h>
#include <stdbool.h>
#ifdef _WIN32
#include <malloc.h> // For alloca on Windows
#else
#include <alloca.h> // For alloca on Unix-like systems
#endif
#include "similarity_search.h"
// Case insensitive string comparison
@@ -43,7 +48,9 @@ int split_into_words(const char *s,
// Free memory allocated for words
void free_words(char *storage) { /* simplified */
free(storage); /* single free, if any */
if (storage) { /* check for NULL */
free(storage); /* single free, if any */
}
}
// Calculate Levenshtein distance between two strings
@@ -77,8 +84,8 @@ float word_similarity(const char *word1, const char *word2) {
int len1 = strlen(word1);
int len2 = strlen(word2);
// For very short words (3 chars or less), require exact match
if (len1 <= 3 || len2 <= 3) {
// For very short words (2 chars or less), require exact match
if (len1 <= 2 || len2 <= 2) {
return str_case_cmp(word1, word2) == 0 ? 1.0f : 0.0f;
}
@@ -100,7 +107,7 @@ float word_similarity(const char *word1, const char *word2) {
// Calculate similarity between query and target string
float calculate_similarity(const char *query, const char *target, float cutoff) {
// Split strings into words
char *query_buf, *target_buf;
char *query_buf = NULL, *target_buf = NULL;
char *query_words[MAX_WORDS], *target_words[MAX_WORDS];
int query_word_count = split_into_words(query, query_words, &query_buf);
@@ -299,27 +306,26 @@ SearchResult* search_index(SearchIndex* index, const char* query, float cutoff,
}
}
// If no results found, return NULL properly
if (*num_results == 0) {
free(temp_results);
return NULL;
}
// Sort results by similarity
qsort(temp_results, *num_results, sizeof(SearchResult), compare_results);
// Allocate final result array with exact size
SearchResult* results = (SearchResult*)malloc(*num_results * sizeof(SearchResult));
// Shrink temp_results to exact size and return it directly
SearchResult* results = (SearchResult*)realloc(
temp_results, *num_results * sizeof(SearchResult));
if (!results) {
// Free all strings in temp_results
// realloc failure temp_results unchanged, clean up
for (int i = 0; i < *num_results; i++) {
free(temp_results[i].string);
}
free(temp_results);
return NULL;
}
// Copy results to final array
for (int i = 0; i < *num_results; i++) {
results[i].string = temp_results[i].string;
results[i].similarity = temp_results[i].similarity;
}
free(temp_results);
return results;
}

View File

@@ -129,9 +129,9 @@ Napi::Value SearchIndexWrapper::Search(const Napi::CallbackInfo& info) {
int num_results = 0;
SearchResult* results = search_index(this->index_, query.c_str(), cutoff, &num_results);
if (!results) {
Napi::Error::New(env, "Search failed").ThrowAsJavaScriptException();
return env.Null();
// If no results found, return empty array instead of throwing error
if (!results || num_results == 0) {
return Napi::Array::New(env, 0);
}
Napi::Array result_array = Napi::Array::New(env, num_results);