<commit_before>#include "sortedcache.h"

GIT__USE_STRMAP;

int git_sortedcache_new(
	git_sortedcache **out,
	size_t item_path_offset,
	git_sortedcache_free_item_fn free_item,
	void *free_item_payload,
	git_vector_cmp item_cmp,
	const char *path)
{
	git_sortedcache *sc;
	size_t pathlen;

	pathlen = path ? strlen(path) : 0;

	sc = git__calloc(sizeof(git_sortedcache) + pathlen + 1, 1);
	GITERR_CHECK_ALLOC(sc);

	if (git_pool_init(&sc->pool, 1, 0) < 0 ||
		git_vector_init(&sc->items, 4, item_cmp) < 0 ||
		(sc->map = git_strmap_alloc()) == NULL)
		goto fail;

	if (git_mutex_init(&sc->lock)) {
		giterr_set(GITERR_OS, "Failed to initialize mutex");
		goto fail;
	}

	sc->item_path_offset = item_path_offset;
	sc->free_item = free_item;
	sc->free_item_payload = free_item_payload;
	GIT_REFCOUNT_INC(sc);
	if (pathlen)
		memcpy(sc->path, path, pathlen);

	*out = sc;
	return 0;

fail:
	if (sc->map)
		git_strmap_free(sc->map);
	git_vector_free(&sc->items);
	git_pool_clear(&sc->pool);
	git__free(sc);
	return -1;
}

void git_sortedcache_incref(git_sortedcache *sc)
{
	GIT_REFCOUNT_INC(sc);
}

static void sortedcache_clear(git_sortedcache *sc)
{
	git_strmap_clear(sc->map);

	if (sc->free_item) {
		size_t i;
		void *item;

		git_vector_foreach(&sc->items, i, item) {
			sc->free_item(sc->free_item_payload, item);
		}
	}

	git_vector_clear(&sc->items);

	git_pool_clear(&sc->pool);
}

static void sortedcache_free(git_sortedcache *sc)
{
	if (git_mutex_lock(&sc->lock) < 0) {
		giterr_set(GITERR_OS, "Unable to acquire mutex lock for free");
		return;
	}

	sortedcache_clear(sc);

	git_vector_free(&sc->items);
	git_strmap_free(sc->map);

	git_mutex_unlock(&sc->lock);
	git_mutex_free(&sc->lock);

	git__free(sc);
}

void git_sortedcache_free(git_sortedcache *sc)
{
	if (!sc)
		return;
	GIT_REFCOUNT_DEC(sc, sortedcache_free);
}

static int sortedcache_copy_item(void *payload, void *tgt_item, void *src_item)
{
	git_sortedcache *sc = payload;
	/* path will already have been copied by upsert */
	memcpy(tgt_item, src_item, sc->item_path_offset);
	return 0;
}

/* copy a sorted cache */
int git_sortedcache_copy(
	git_sortedcache **out,
	git_sortedcache *src,
	int (*copy_item)(void *payload, void *tgt_item, void *src_item),
	void *payload)
{
	git_sortedcache *tgt;
	size_t i;
	void *src_item, *tgt_item;

	if (!copy_item) {
		copy_item = sortedcache_copy_item;
		payload   = src;
	}

	if (git_sortedcache_new(
			&tgt, src->item_path_offset,
			src->free_item, src->free_item_payload,
			src->items._cmp, src->path) < 0)
		return -1;

	if (git_sortedcache_lock(src) < 0) {
		git_sortedcache_free(tgt);
		return -1;
	}

	if (git_sortedcache_lock(tgt) < 0)
		goto fail;

	git_vector_foreach(&src->items, i, src_item) {
		if (git_sortedcache_upsert(
				&tgt_item, tgt, ((char *)src_item) + src->item_path_offset) < 0)
			goto fail;
		if (copy_item(payload, tgt_item, src_item) < 0)
			goto fail;
	}

	git_sortedcache_unlock(tgt);
	git_sortedcache_unlock(src);

	*out = tgt;
	return 0;

fail:
	git_sortedcache_unlock(src);
	git_sortedcache_free(tgt);
	return -1;
}

/* release all items in sorted cache */
void git_sortedcache_clear(git_sortedcache *sc, bool lock)
{
	if (lock && git_mutex_lock(&sc->lock) < 0) {
		giterr_set(GITERR_OS, "Unable to acquire mutex lock for clear");
		return;
	}

	sortedcache_clear(sc);<commit_msg>No need to lock newly created tgt in copy<commit_after>#include "sortedcache.h"

GIT__USE_STRMAP;

int git_sortedcache_new(
	git_sortedcache **out,
	size_t item_path_offset,
	git_sortedcache_free_item_fn free_item,
	void *free_item_payload,
	git_vector_cmp item_cmp,
	const char *path)
{
	git_sortedcache *sc;
	size_t pathlen;

	pathlen = path ? strlen(path) : 0;

	sc = git__calloc(sizeof(git_sortedcache) + pathlen + 1, 1);
	GITERR_CHECK_ALLOC(sc);

	if (git_pool_init(&sc->pool, 1, 0) < 0 ||
		git_vector_init(&sc->items, 4, item_cmp) < 0 ||
		(sc->map = git_strmap_alloc()) == NULL)
		goto fail;

	if (git_mutex_init(&sc->lock)) {
		giterr_set(GITERR_OS, "Failed to initialize mutex");
		goto fail;
	}

	sc->item_path_offset = item_path_offset;
	sc->free_item = free_item;
	sc->free_item_payload = free_item_payload;
	GIT_REFCOUNT_INC(sc);
	if (pathlen)
		memcpy(sc->path, path, pathlen);

	*out = sc;
	return 0;

fail:
	if (sc->map)
		git_strmap_free(sc->map);
	git_vector_free(&sc->items);
	git_pool_clear(&sc->pool);
	git__free(sc);
	return -1;
}

void git_sortedcache_incref(git_sortedcache *sc)
{
	GIT_REFCOUNT_INC(sc);
}

static void sortedcache_clear(git_sortedcache *sc)
{
	git_strmap_clear(sc->map);

	if (sc->free_item) {
		size_t i;
		void *item;

		git_vector_foreach(&sc->items, i, item) {
			sc->free_item(sc->free_item_payload, item);
		}
	}

	git_vector_clear(&sc->items);

	git_pool_clear(&sc->pool);
}

static void sortedcache_free(git_sortedcache *sc)
{
	if (git_mutex_lock(&sc->lock) < 0) {
		giterr_set(GITERR_OS, "Unable to acquire mutex lock for free");
		return;
	}

	sortedcache_clear(sc);

	git_vector_free(&sc->items);
	git_strmap_free(sc->map);

	git_mutex_unlock(&sc->lock);
	git_mutex_free(&sc->lock);

	git__free(sc);
}

void git_sortedcache_free(git_sortedcache *sc)
{
	if (!sc)
		return;
	GIT_REFCOUNT_DEC(sc, sortedcache_free);
}

static int sortedcache_copy_item(void *payload, void *tgt_item, void *src_item)
{
	git_sortedcache *sc = payload;
	/* path will already have been copied by upsert */
	memcpy(tgt_item, src_item, sc->item_path_offset);
	return 0;
}

/* copy a sorted cache */
int git_sortedcache_copy(
	git_sortedcache **out,
	git_sortedcache *src,
	int (*copy_item)(void *payload, void *tgt_item, void *src_item),
	void *payload)
{
	git_sortedcache *tgt;
	size_t i;
	void *src_item, *tgt_item;

	if (!copy_item) {
		copy_item = sortedcache_copy_item;
		payload   = src;
	}

	if (git_sortedcache_new(
			&tgt, src->item_path_offset,
			src->free_item, src->free_item_payload,
			src->items._cmp, src->path) < 0)
		return -1;

	if (git_sortedcache_lock(src) < 0) {
		git_sortedcache_free(tgt);
		return -1;
	}

	git_vector_foreach(&src->items, i, src_item) {
		if (git_sortedcache_upsert(
				&tgt_item, tgt, ((char *)src_item) + src->item_path_offset) < 0)
			goto fail;
		if (copy_item(payload, tgt_item, src_item) < 0)
			goto fail;
	}

	git_sortedcache_unlock(src);

	*out = tgt;
	return 0;

fail:
	git_sortedcache_unlock(src);
	git_sortedcache_free(tgt);
	return -1;
}

/* release all items in sorted cache */
void git_sortedcache_clear(git_sortedcache *sc, bool lock)
{
	if (lock && git_mutex_lock(&sc->lock) < 0) {
		giterr_set(GITERR_OS, "Unable to acquire mutex lock for clear");
		return;
	}

	sortedcache_clear(sc);
{'fraction_non_alphanumeric': 0.13677673432293244, 'fraction_numerical': 0.006513177824901545, 'mean_word_length': 4.997275204359673, 'pattern_counts': {'":': 0, '<': 20, '<?xml version=': 0, '>': 69, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6841527', 'n_tokens_mistral': 2911, 'n_tokens_neox': 2765, 'n_words': 533}