Skip to content

Commit

Permalink
clipmenud: add option to deduplicate entries
Browse files Browse the repository at this point in the history
uses a linear search to find the duplicate and a memmove to move
it over to the end.

not perticularly efficient since each snip is 256 bytes while
we're only interested in the first 8. and so iterating over it
linearly like this isn't very cache friendly. the memmove worst
case can also be around 250KiB with the default config.

Closes: #224
  • Loading branch information
N-R-K committed Jun 11, 2024
1 parent 1113ca8 commit dda5a33
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/clipmenud.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ static uint64_t store_clip(char *text) {
dbg("Possible partial of last clip, replacing\n");
expect(cs_replace(&cs, CS_ITER_NEWEST_FIRST, 0, text, &hash) == 0);
} else {
expect(cs_add(&cs, text, &hash) == 0);
expect(cs_add(&cs, text, &hash, cfg.deduplicate) == 0);
}

if (last_text) {
Expand Down
1 change: 1 addition & 0 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ int config_setup_internal(FILE *file, struct config *cfg) {
{"max_clips_batch", "CM_MAX_CLIPS_BATCH", &cfg->max_clips_batch,
convert_positive_int, "100", 0},
{"oneshot", "CM_ONESHOT", &cfg->oneshot, convert_positive_int, "0", 0},
{"deduplicate", NULL, &cfg->deduplicate, convert_bool, "1", 0},
{"own_clipboard", "CM_OWN_CLIPBOARD", &cfg->own_clipboard, convert_bool,
"0", 0},
{"selections", "CM_SELECTIONS", &cfg->selections, convert_selections,
Expand Down
1 change: 1 addition & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ struct config {
int max_clips;
int max_clips_batch;
int oneshot;
bool deduplicate;
bool own_clipboard;
struct selection *owned_selections;
struct selection *selections;
Expand Down
34 changes: 27 additions & 7 deletions src/store.c
Original file line number Diff line number Diff line change
Expand Up @@ -397,14 +397,16 @@ static int _must_use_ _nonnull_ cs_snip_add(struct clip_store *cs,

/**
* Add content to the content directory using the hash as the filename.
* Returns 1 if the entry was duplicate and no new entry was inserted.
*
* @cs: The clip store to operate on
* @hash: The hash of the content to add
* @content: The content to add to the file
*/
static int _must_use_ _nonnull_ cs_content_add(struct clip_store *cs,
uint64_t hash,
const char *content) {
const char *content,
bool deduplicate) {
bool dupe = false;

char dir_path[CS_HASH_STR_MAX];
Expand All @@ -421,7 +423,7 @@ static int _must_use_ _nonnull_ cs_content_add(struct clip_store *cs,
char base_file_path[PATH_MAX];
snprintf(base_file_path, sizeof(base_file_path), "%s/1", dir_path);

if (dupe) {
if (dupe && !deduplicate) {
// This clip already exists, just create a link for refcounting
struct stat st;
if (fstatat(cs->content_dir_fd, base_file_path, &st, 0) < 0) {
Expand All @@ -437,6 +439,23 @@ static int _must_use_ _nonnull_ cs_content_add(struct clip_store *cs,
}

return 0;
} else if (dupe && deduplicate) {
_drop_(cs_unref) struct ref_guard guard = cs_ref(cs);
if (guard.status < 0) {
return guard.status;
}

for (int i = 0; i < (int)cs->local_nr_snips; ++i) {
if (cs->snips[i].hash == hash) {
// move cs->snips[i] to the end of the array
struct cs_snip tmp = cs->snips[i];
memmove(cs->snips + i, cs->snips + i + 1,
(cs->local_nr_snips - (i + 1)) * sizeof(*cs->snips));
cs->snips[cs->local_nr_snips - 1] = tmp;
return 1;
}
}
return -ENOENT;
}

// This is a new clip
Expand Down Expand Up @@ -532,12 +551,13 @@ int cs_content_get(struct clip_store *cs, uint64_t hash,
* @content: The content to add
* @out_hash: Output for the generated hash, or NULL
*/
int cs_add(struct clip_store *cs, const char *content, uint64_t *out_hash) {
int cs_add(struct clip_store *cs, const char *content, uint64_t *out_hash,
bool deduplicate) {
uint64_t hash = djb64_hash(content);
char line[CS_SNIP_LINE_SIZE];
size_t nr_lines = first_line(content, line);

int ret = cs_content_add(cs, hash, content);
int ret = cs_content_add(cs, hash, content, deduplicate);
if (ret < 0) {
return ret;
}
Expand All @@ -546,7 +566,7 @@ int cs_add(struct clip_store *cs, const char *content, uint64_t *out_hash) {
*out_hash = hash;
}

return cs_snip_add(cs, hash, line, nr_lines);
return (ret == 1) ? 0 : cs_snip_add(cs, hash, line, nr_lines);
}

/**
Expand Down Expand Up @@ -767,8 +787,8 @@ int cs_replace(struct clip_store *cs, enum cs_iter_direction direction,
size_t nr_lines = first_line(content, line);
uint64_t hash = djb64_hash(content);
cs_snip_update(snip, hash, line, nr_lines);
ret = cs_content_add(cs, hash, content);
if (ret) {
ret = cs_content_add(cs, hash, content, 0);
if (ret < 0) {
return ret;
}
if (out_hash) {
Expand Down
4 changes: 2 additions & 2 deletions src/store.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,8 @@ void drop_cs_content_unmap(struct cs_content *content);
void drop_cs_destroy(struct clip_store *cs);
int _must_use_ _nonnull_ cs_content_get(struct clip_store *cs, uint64_t hash,
struct cs_content *content);
int _must_use_ _nonnull_n_(1)
cs_add(struct clip_store *cs, const char *content, uint64_t *out_hash);
int _must_use_ _nonnull_n_(1) cs_add(struct clip_store *cs, const char *content,
uint64_t *out_hash, bool deduplicate);
bool _must_use_ _nonnull_ cs_snip_iter(struct ref_guard *guard,
enum cs_iter_direction direction,
struct cs_snip **snip);
Expand Down

0 comments on commit dda5a33

Please sign in to comment.