#include "commit.h"
#include "revwalk.h"
#include "git/odb.h"
+#include "git/repository.h"
#define COMMIT_PRINT(commit) {\
char oid[41]; oid[40] = 0;\
printf("Oid: %s | In degree: %d | Time: %u\n", oid, commit->in_degree, commit->commit_time);\
}
+static void clear_parents(git_commit *commit)
+{
+ git_commit_parents *node, *next_node;
+
+ node = commit->parents;
+ while (node) {
+ next_node = node->next;
+ free(node);
+ node = next_node;
+ }
+
+ commit->parents = NULL;
+}
+
void git_commit__free(git_commit *commit)
{
- git_commit_list_clear(&commit->parents, 0);
+ clear_parents(commit);
if (commit->odb_open)
git_obj_close(&commit->odb_object);
return &c->object.id;
}
-void git_commit__mark_uninteresting(git_commit *commit)
-{
- git_commit_node *parents;
-
- if (commit == NULL)
- return;
-
- parents = commit->parents.head;
-
- commit->uninteresting = 1;
-
- while (parents) {
- parents->commit->uninteresting = 1;
- parents = parents->next;
- }
-}
-
-git_commit *git_commit_parse(git_revpool *pool, const git_oid *id)
-{
- git_commit *commit = NULL;
-
- if ((commit = git_commit_lookup(pool, id)) == NULL)
- return NULL;
-
- if (git_commit__parse_basic(commit) < 0)
- goto error_cleanup;
-
- return commit;
-
-error_cleanup:
- /* FIXME: do not free; the commit is owned by the revpool */
- free(commit);
- return NULL;
-}
-
int git_commit__parse(git_commit *commit, unsigned int parse_flags, int close_db_object)
{
int error = 0;
if (!commit->odb_open) {
- error = git_odb_read(&commit->odb_object, commit->object.pool->db, &commit->object.id);
+ error = git_odb_read(&commit->odb_object, commit->object.repo->db, &commit->object.id);
if (error < 0)
return error;
return 0;
}
-git_commit *git_commit_lookup(git_revpool *pool, const git_oid *id)
+git_commit *git_commit_lookup(git_repository *repo, const git_oid *id)
{
- git_commit *commit = NULL;
-
- if (pool == NULL)
- return NULL;
-
- commit = (git_commit *)git_revpool_table_lookup(pool->objects, id);
- if (commit != NULL)
- return commit;
-
- commit = git__malloc(sizeof(git_commit));
-
- if (commit == NULL)
- return NULL;
-
- memset(commit, 0x0, sizeof(git_commit));
-
- /* Initialize parent object */
- git_oid_cpy(&commit->object.id, id);
- commit->object.pool = pool;
- commit->object.type = GIT_OBJ_COMMIT;
-
- git_revpool_table_insert(pool->objects, (git_revpool_object *)commit);
-
- return commit;
+ return (git_commit *)git_repository_lookup(repo, id, GIT_OBJ_COMMIT);
}
int git__parse_person(git_person *person, char **buffer_out,
return GIT_EOBJCORRUPTED;
if (parse_flags & GIT_COMMIT_TREE)
- commit->tree = git_tree_lookup(commit->object.pool, &oid);
+ commit->tree = git_tree_lookup(commit->object.repo, &oid);
/*
* TODO: commit grafts!
*/
if (parse_flags & GIT_COMMIT_PARENTS)
- git_commit_list_clear(&commit->parents, 0);
+ clear_parents(commit);
while (git__parse_oid(&oid, &buffer, buffer_end, "parent ") == 0) {
git_commit *parent;
+ git_commit_parents *node;
if ((parse_flags & GIT_COMMIT_PARENTS) == 0)
continue;
- if ((parent = git_commit_lookup(commit->object.pool, &oid)) == NULL)
+ if ((parent = git_commit_lookup(commit->object.repo, &oid)) == NULL)
return GIT_ENOTFOUND;
- /* Inherit uninteresting flag */
- if (commit->uninteresting)
- parent->uninteresting = 1;
-
- if (git_commit_list_push_back(&commit->parents, parent) < 0)
+ if ((node = git__malloc(sizeof(git_commit_parents))) == NULL)
return GIT_ENOMEM;
+
+ node->commit = parent;
+ node->next = commit->parents;
+ commit->parents = node;
}
if (git__parse_person(&person, &buffer, buffer_end, "author ") < 0)
git_commit__parse(commit, GIT_COMMIT_MESSAGE_SHORT, 0);
return commit->message_short;
}
-
-
-
-int git_commit_list_push_back(git_commit_list *list, git_commit *commit)
-{
- git_commit_node *node = NULL;
-
- node = git__malloc(sizeof(git_commit_list));
-
- if (node == NULL)
- return GIT_ENOMEM;
-
- node->commit = commit;
- node->next = NULL;
- node->prev = list->tail;
-
- if (list->tail == NULL) {
- list->head = list->tail = node;
- } else {
- list->tail->next = node;
- list->tail = node;
- }
-
- list->size++;
- return 0;
-}
-
-int git_commit_list_push_front(git_commit_list *list, git_commit *commit)
-{
- git_commit_node *node = NULL;
-
- node = git__malloc(sizeof(git_commit_list));
-
- if (node == NULL)
- return GIT_ENOMEM;
-
- node->commit = commit;
- node->next = list->head;
- node->prev = NULL;
-
- if (list->head == NULL) {
- list->head = list->tail = node;
- } else {
- list->head->prev = node;
- list->head = node;
- }
-
- list->size++;
- return 0;
-}
-
-
-git_commit *git_commit_list_pop_back(git_commit_list *list)
-{
- git_commit_node *node;
- git_commit *commit;
-
- if (list->tail == NULL)
- return NULL;
-
- node = list->tail;
- list->tail = list->tail->prev;
- if (list->tail == NULL)
- list->head = NULL;
-
- commit = node->commit;
- free(node);
-
- list->size--;
-
- return commit;
-}
-
-git_commit *git_commit_list_pop_front(git_commit_list *list)
-{
- git_commit_node *node;
- git_commit *commit;
-
- if (list->head == NULL)
- return NULL;
-
- node = list->head;
- list->head = list->head->next;
- if (list->head == NULL)
- list->tail = NULL;
-
- commit = node->commit;
- free(node);
-
- list->size--;
-
- return commit;
-}
-
-void git_commit_list_clear(git_commit_list *list, int free_commits)
-{
- git_commit_node *node, *next_node;
-
- node = list->head;
- while (node) {
- if (free_commits)
- free(node->commit);
-
- next_node = node->next;
- free(node);
- node = next_node;
- }
-
- list->head = list->tail = NULL;
- list->size = 0;
-}
-
-void git_commit_list_timesort(git_commit_list *list)
-{
- git_commit_node *p, *q, *e;
- int in_size, p_size, q_size, merge_count, i;
-
- if (list->head == NULL)
- return;
-
- in_size = 1;
-
- do {
- p = list->head;
- list->tail = NULL;
- merge_count = 0;
-
- while (p != NULL) {
- merge_count++;
- q = p;
- p_size = 0;
- q_size = in_size;
-
- for (i = 0; i < in_size && q; ++i, q = q->next)
- p_size++;
-
- while (p_size > 0 || (q_size > 0 && q)) {
-
- if (p_size == 0)
- e = q, q = q->next, q_size--;
-
- else if (q_size == 0 || q == NULL ||
- p->commit->commit_time >= q->commit->commit_time)
- e = p, p = p->next, p_size--;
-
- else
- e = q, q = q->next, q_size--;
-
- if (list->tail != NULL)
- list->tail->next = e;
- else
- list->head = e;
-
- e->prev = list->tail;
- list->tail = e;
- }
-
- p = q;
- }
-
- list->tail->next = NULL;
- in_size *= 2;
-
- } while (merge_count > 1);
-}
-
-void git_commit_list_toposort(git_commit_list *list)
-{
- git_commit *commit;
- git_commit_list topo;
- memset(&topo, 0x0, sizeof(git_commit_list));
-
- while ((commit = git_commit_list_pop_back(list)) != NULL) {
- git_commit_node *p;
-
- if (commit->in_degree > 0) {
- commit->topo_delay = 1;
- continue;
- }
-
- for (p = commit->parents.head; p != NULL; p = p->next) {
- p->commit->in_degree--;
-
- if (p->commit->in_degree == 0 && p->commit->topo_delay) {
- p->commit->topo_delay = 0;
- git_commit_list_push_back(list, p->commit);
- }
- }
-
- git_commit_list_push_back(&topo, commit);
- }
-
- list->head = topo.head;
- list->tail = topo.tail;
- list->size = topo.size;
-}
-
#include "git/commit.h"
#include "tree.h"
-#include "revobject.h"
+#include "repository.h"
#include <time.h>
-struct git_commit_node {
- struct git_commit *commit;
-
- struct git_commit_node *next;
- struct git_commit_node *prev;
-};
-
-struct git_commit_list {
- struct git_commit_node *head;
- struct git_commit_node *tail;
- size_t size;
-};
-
-typedef struct git_commit_list git_commit_list;
-typedef struct git_commit_node git_commit_node;
-
#define GIT_COMMIT_TREE (1 << 1)
#define GIT_COMMIT_PARENTS (1 << 2)
#define GIT_COMMIT_AUTHOR (1 << 3)
#define GIT_COMMIT_MESSAGE_SHORT (1 << 7)
#define GIT_COMMIT_FOOTERS (1 << 8)
+typedef struct git_commit_parents {
+ git_commit *commit;
+ struct git_commit_parents *next;
+} git_commit_parents;
+
struct git_commit {
- git_revpool_object object;
+ git_repository_object object;
git_obj odb_object;
time_t commit_time;
- git_commit_list parents;
+ git_commit_parents *parents;
git_tree *tree;
git_person *author;
char *message;
char *message_short;
- unsigned short in_degree;
unsigned basic_parse:1,
- odb_open:1,
- seen:1,
- uninteresting:1,
- topo_delay:1,
- flags:25;
+ odb_open:1;
};
void git_commit__free(git_commit *c);
int git__parse_oid(git_oid *oid, char **buffer_out, const char *buffer_end, const char *header);
int git__parse_person(git_person *person, char **buffer_out, const char *buffer_end, const char *header);
-int git_commit_list_push_back(git_commit_list *list, git_commit *commit);
-int git_commit_list_push_front(git_commit_list *list, git_commit *commit);
-
-git_commit *git_commit_list_pop_back(git_commit_list *list);
-git_commit *git_commit_list_pop_front(git_commit_list *list);
-
-void git_commit_list_clear(git_commit_list *list, int free_commits);
-
-void git_commit_list_timesort(git_commit_list *list);
-void git_commit_list_toposort(git_commit_list *list);
#endif
#include "common.h"
#include "oid.h"
#include "tree.h"
+#include "repository.h"
/**
* @file git/commit.h
typedef struct git_commit git_commit;
/**
- * Locate a reference to a commit without loading it.
+ * Lookup a commit object from a repository.
* The generated commit object is owned by the revision
- * pool and shall not be freed by the user.
+ * repo and shall not be freed by the user.
*
- * @param pool the pool to use when locating the commit.
+ * @param repo the repo to use when locating the commit.
* @param id identity of the commit to locate. If the object is
* an annotated tag it will be peeled back to the commit.
* @return the commit; NULL if the commit could not be created
*/
-GIT_EXTERN(git_commit *) git_commit_lookup(git_revpool *pool, const git_oid *id);
-
-/**
- * Locate a reference to a commit, and try to load and parse it it from
- * the commit cache or the object database.
- * The generated commit object is owned by the revision
- * pool and shall not be freed by the user.
- *
- * @param pool the pool to use when parsing/caching the commit.
- * @param id identity of the commit to locate. If the object is
- * an annotated tag it will be peeled back to the commit.
- * @return the commit; NULL if the commit does not exist in the
- * pool's git_odb, or if the commit is present but is
- * too malformed to be parsed successfully.
- */
-GIT_EXTERN(git_commit *) git_commit_parse(git_revpool *pool, const git_oid *id);
+GIT_EXTERN(git_commit *) git_commit_lookup(git_repository *repo, const git_oid *id);
/**
* Get the id of a commit.
GIT_BEGIN_DECL
-/** A revision traversal pool. */
-typedef struct git_revpool git_revpool;
+/**
+ * Representation of an existing git repository,
+ * including all its object contents
+ */
+typedef struct git_repository git_repository;
+
+/* Representation of a generic object in a repository */
+typedef struct git_repository_object git_repository_object;
/** Parsed representation of a person */
typedef struct git_person {
/** Basic type (loose or packed) of any Git object. */
typedef enum {
+ GIT_OBJ_ANY = -2, /**< Object can be any of the following */
GIT_OBJ_BAD = -1, /**< Object is invalid. */
GIT_OBJ__EXT1 = 0, /**< Reserved for future use. */
GIT_OBJ_COMMIT = 1, /**< A commit object. */
--- /dev/null
+#ifndef INCLUDE_git_repository_h__
+#define INCLUDE_git_repository_h__
+
+#include "common.h"
+#include "odb.h"
+#include "commit.h"
+
+/**
+ * @file git/repository.h
+ * @brief Git revision object management routines
+ * @defgroup git_repository Git revision object management routines
+ * @ingroup Git
+ * @{
+ */
+GIT_BEGIN_DECL
+
+/**
+ * Allocate a new repository object.
+ *
+ * TODO: specify the repository's path instead
+ * of its object database
+ *
+ * @param odb an existing object database to back the repo
+ * @return the new repository handle; NULL on error
+ */
+GIT_EXTERN(git_repository *) git_repository_alloc(git_odb *odb);
+
+
+/**
+ * Lookup a reference to one of the objects in the repostory.
+ *
+ * The generated reference is owned by the repository and
+ * should not be freed by the user.
+ * The generated reference should be cast back to the
+ * expected type; e.g.
+ *
+ * git_commit *c = (git_commit *)
+ * git_repository_lookup(repo, id, GIT_OBJ_COMMIT);
+ *
+ * The 'type' parameter must match the type of the object
+ * in the odb; the method will fail otherwise.
+ * The special value 'GIT_OBJ_ANY' may be passed to let
+ * the method guess the object's type.
+ *
+ * @param repo the repository to look up the object
+ * @param id the unique identifier for the object
+ * @param type the type of the object
+ * @return a reference to the object
+ */
+GIT_EXTERN(git_repository_object *) git_repository_lookup(git_repository *repo, const git_oid *id, git_otype type);
+
+/**
+ * Free a previously allocated repository
+ * @param repo repository handle to close. If NULL nothing occurs.
+ */
+GIT_EXTERN(void) git_repository_free(git_repository *repo);
+
+/** @} */
+GIT_END_DECL
+#endif
GIT_BEGIN_DECL
/**
- * Sort the revpool contents in no particular ordering;
+ * Sort the repository contents in no particular ordering;
* this sorting is arbritary, implementation-specific
* and subject to change at any time.
- * This is the default sorting for new revision pools.
+ * This is the default sorting for new walkers.
*/
-#define GIT_RPSORT_NONE (0)
+#define GIT_SORT_NONE (0)
/**
- * Sort the revpool contents in topological order
+ * Sort the repository contents in topological order
* (parents before children); this sorting mode
* can be combined with time sorting.
*/
-#define GIT_RPSORT_TOPOLOGICAL (1 << 0)
+#define GIT_SORT_TOPOLOGICAL (1 << 0)
/**
- * Sort the revpool contents by commit time;
+ * Sort the repository contents by commit time;
* this sorting mode can be combined with
* topological sorting.
*/
-#define GIT_RPSORT_TIME (1 << 1)
+#define GIT_SORT_TIME (1 << 1)
/**
- * Iterate through the revpool contents in reverse
+ * Iterate through the repository contents in reverse
* order; this sorting mode can be combined with
* any of the above.
*/
-#define GIT_RPSORT_REVERSE (1 << 2)
+#define GIT_SORT_REVERSE (1 << 2)
+
+typedef struct git_revwalk git_revwalk;
/**
- * Allocate a new revision traversal pool.
- *
- * The configuration is copied during allocation. Changes
- * to the configuration after allocation do not affect the pool
- * returned by this function. Callers may safely free the
- * passed configuration after the function completes.
+ * Allocate a new revision walker to iterate through a repo.
*
- * @param db the database objects are read from.
- * @return the new traversal handle; NULL if memory is exhausted.
+ * @param repo the repo to walk through
+ * @return the new walker handle; NULL if memory is exhausted.
*/
-GIT_EXTERN(git_revpool *) gitrp_alloc(git_odb *db);
+GIT_EXTERN(git_revwalk *) git_revwalk_alloc(git_repository *repo);
/**
- * Reset the traversal machinary for reuse.
- * @param pool traversal handle to reset.
+ * Reset the walking machinary for reuse.
+ * @param walker handle to reset.
*/
-GIT_EXTERN(void) gitrp_reset(git_revpool *pool);
+GIT_EXTERN(void) git_revwalk_reset(git_revwalk *walker);
/**
- * Mark an object to start traversal from.
- * @param pool the pool being used for the traversal.
+ * Mark a commit to start traversal from.
+ * The commit object must belong to the repo which is being walked through.
+ *
+ * @param walker the walker being used for the traversal.
* @param commit the commit to start from.
*/
-GIT_EXTERN(int) gitrp_push(git_revpool *pool, git_commit *commit);
+GIT_EXTERN(int) git_revwalk_push(git_revwalk *walk, git_commit *commit);
/**
* Mark a commit (and its ancestors) uninteresting for the output.
- * @param pool the pool being used for the traversal.
+ * @param walker the walker being used for the traversal.
* @param commit the commit that will be ignored during the traversal
*/
-GIT_EXTERN(int) gitrp_hide(git_revpool *pool, git_commit *commit);
+GIT_EXTERN(int) git_revwalk_hide(git_revwalk *walk, git_commit *commit);
/**
* Get the next commit from the revision traversal.
- * @param pool the pool to pop the commit from.
+ * @param walk the walker to pop the commit from.
* @return next commit; NULL if there is no more output.
*/
-GIT_EXTERN(git_commit *) gitrp_next(git_revpool *pool);
+GIT_EXTERN(git_commit *) git_revwalk_next(git_revwalk *walk);
/**
* Change the sorting mode when iterating through the
- * revision pool's contents.
- * @param pool the pool being used for the traversal.
+ * repository's contents.
+ * Changing the sorting mode resets the walker.
+ * @param walk the walker being used for the traversal.
* @param sort_mode combination of GIT_RPSORT_XXX flags
*/
-GIT_EXTERN(void) gitrp_sorting(git_revpool *pool, unsigned int sort_mode);
+GIT_EXTERN(void) git_revwalk_sorting(git_revwalk *walk, unsigned int sort_mode);
/**
* Free a revwalk previously allocated.
- * @param pool traversal handle to close. If NULL nothing occurs.
+ * @param walk traversal handle to close. If NULL nothing occurs.
*/
-GIT_EXTERN(void) gitrp_free(git_revpool *pool);
+GIT_EXTERN(void) git_revwalk_free(git_revwalk *walk);
/** @} */
GIT_END_DECL
#include "common.h"
#include "oid.h"
#include "tree.h"
+#include "repository.h"
/**
* @file git/tag.h
typedef struct git_tag git_tag;
/**
- * Locate a reference to a tag without loading it.
+ * Lookup a tag object from the repository.
* The generated tag object is owned by the revision
- * pool and shall not be freed by the user.
+ * repo and shall not be freed by the user.
*
- * @param pool the pool to use when locating the tag.
+ * @param repo the repo to use when locating the tag.
* @param id identity of the tag to locate.
* @return the tag; NULL if the tag could not be created
*/
-GIT_EXTERN(git_tag *) git_tag_lookup(git_revpool *pool, const git_oid *id);
-
-/**
- * Locate a reference to a tag, and try to load and parse it it from
- * the object cache or the object database.
- * The generated tag object is owned by the revision
- * pool and shall not be freed by the user.
- *
- * @param pool the pool to use when parsing/caching the tag.
- * @param id identity of the tag to locate.
- * @return the tag; NULL if the tag does not exist in the
- * pool's git_odb, or if the tag is present but is
- * too malformed to be parsed successfully.
- */
-GIT_EXTERN(git_tag *) git_tag_parse(git_revpool *pool, const git_oid *id);
+GIT_EXTERN(git_tag *) git_tag_lookup(git_repository *repo, const git_oid *id);
/**
* Get the id of a tag.
#include "common.h"
#include "oid.h"
+#include "repository.h"
/**
* @file git/tree.h
typedef struct git_tree git_tree;
/**
- * Locate a reference to a tree without loading it.
+ * Lookup a tree object from the repository.
* The generated tree object is owned by the revision
- * pool and shall not be freed by the user.
+ * repo and shall not be freed by the user.
*
- * @param pool the pool to use when locating the tree.
+ * @param repo the repo to use when locating the tree.
* @param id identity of the tree to locate.
* @return the tree; NULL if the tree could not be created
*/
-GIT_EXTERN(git_tree *) git_tree_lookup(git_revpool *pool, const git_oid *id);
-
-/**
- * Locate a reference to a tree object and parse its
- * contents.
- * The generated tree object is owned by the revision
- * pool and shall not be freed by the user.
- *
- * @param pool the pool to use when locating the tree.
- * @param id identity of the tree to locate.
- * @return the tree; NULL if the tree could not be created
- */
-GIT_EXTERN(git_tree *) git_tree_parse(git_revpool *pool, const git_oid *id);
+GIT_EXTERN(git_tree *) git_tree_lookup(git_repository *repo, const git_oid *id);
/**
* Get the id of a tree.
--- /dev/null
+/*
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2,
+ * as published by the Free Software Foundation.
+ *
+ * In addition to the permissions in the GNU General Public License,
+ * the authors give you unlimited permission to link the compiled
+ * version of this file into combinations with other programs,
+ * and to distribute those combinations without any restriction
+ * coming from the use of this file. (The General Public License
+ * restrictions do apply in other respects; for example, they cover
+ * modification of the file, and distribution when not linked into
+ * a combined executable.)
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "common.h"
+#include "repository.h"
+#include "commit.h"
+
+static const int default_table_size = 32;
+static const double max_load_factor = 0.65;
+
+static void hashtable_resize(git_hashtable *table)
+{
+ git_hashtable_node **new_nodes;
+ unsigned int new_size, i;
+
+ assert(table);
+
+ new_size = (table->size_mask + 1) * 2;
+
+ new_nodes = git__malloc(new_size * sizeof(git_hashtable_node *));
+ if (new_nodes == NULL)
+ return;
+
+ memset(new_nodes, 0x0, new_size * sizeof(git_hashtable_node *));
+
+ for (i = 0; i <= table->size_mask; ++i) {
+ git_hashtable_node *n;
+ unsigned int index;
+
+ while ((n = table->nodes[i]) != NULL) {
+ table->nodes[i] = n->next;
+ index = n->hash & (new_size - 1);
+ n->next = new_nodes[index];
+ new_nodes[index] = n;
+ }
+ }
+
+ free(table->nodes);
+ table->nodes = new_nodes;
+ table->size_mask = (new_size - 1);
+ table->max_count = (unsigned int)(new_size * max_load_factor);
+}
+
+git_hashtable *git_hashtable_alloc(unsigned int min_size,
+ git_hash_ptr hash,
+ git_hash_keyeq_ptr key_eq)
+{
+ unsigned int i;
+ git_hashtable *table;
+
+ assert(hash && key_eq);
+
+ if ((table = git__malloc(sizeof(git_hashtable))) == NULL)
+ return NULL;
+
+ /* round up size to closest power of 2 */
+ min_size--;
+ min_size |= min_size >> 1;
+ min_size |= min_size >> 2;
+ min_size |= min_size >> 4;
+ min_size |= min_size >> 8;
+ min_size |= min_size >> 16;
+
+ table->size_mask = min_size;
+ table->count = 0;
+ table->max_count = (unsigned int)((min_size + 1) * max_load_factor);
+
+ table->hash = hash;
+ table->key_equal = key_eq;
+
+ table->nodes = git__malloc((min_size + 1) * sizeof(git_hashtable_node *));
+
+ if (table->nodes == NULL) {
+ free(table);
+ return NULL;
+ }
+
+ for (i = 0; i <= min_size; ++i)
+ table->nodes[i] = NULL;
+
+ return table;
+}
+
+void git_hashtable_clear(git_hashtable *table)
+{
+ unsigned int index;
+
+ assert(table);
+
+ for (index = 0; index <= table->size_mask; ++index) {
+ git_hashtable_node *node, *next_node;
+
+ node = table->nodes[index];
+ while (node != NULL) {
+ next_node = node->next;
+ free(node);
+ node = next_node;
+ }
+
+ table->nodes[index] = NULL;
+ }
+
+ table->count = 0;
+}
+
+void git_hashtable_free(git_hashtable *table)
+{
+ assert(table);
+
+ git_hashtable_clear(table);
+ free(table->nodes);
+ free(table);
+}
+
+
+int git_hashtable_insert(git_hashtable *table, const void *key, void *value)
+{
+ git_hashtable_node *node;
+ uint32_t index, hash;
+
+ assert(table);
+
+ if (table->count + 1 > table->max_count)
+ hashtable_resize(table);
+
+ node = git__malloc(sizeof(git_hashtable_node));
+ if (node == NULL)
+ return GIT_ENOMEM;
+
+ hash = table->hash(key);
+ index = (hash & table->size_mask);
+
+ node->object = value;
+ node->hash = hash;
+ node->next = table->nodes[index];
+
+ table->nodes[index] = node;
+ table->count++;
+
+ return GIT_SUCCESS;
+}
+
+void *git_hashtable_lookup(git_hashtable *table, const void *key)
+{
+ git_hashtable_node *node;
+ uint32_t index, hash;
+
+ assert(table);
+
+ hash = table->hash(key);
+ index = (hash & table->size_mask);
+ node = table->nodes[index];
+
+ while (node != NULL) {
+ if (node->hash == hash && table->key_equal(node->object, key))
+ return node->object;
+
+ node = node->next;
+ }
+
+ return NULL;
+}
+
+
+
+void git_hashtable_iterator_init(git_hashtable *table, git_hashtable_iterator *it)
+{
+ assert(table && it);
+
+ memset(it, 0x0, sizeof(git_hashtable_iterator));
+
+ it->nodes = table->nodes;
+ it->current_node = NULL;
+ it->current_pos = 0;
+ it->size = table->size_mask + 1;
+}
+
+void *git_hashtable_iterator_next(git_hashtable_iterator *it)
+{
+ git_hashtable_node *next = NULL;
+
+ assert(it);
+
+ while (it->current_node == NULL) {
+ if (it->current_pos >= it->size)
+ return NULL;
+
+ it->current_node = it->nodes[it->current_pos++];
+ }
+
+ next = it->current_node;
+ it->current_node = it->current_node->next;
+
+ return next->object;
+}
+
--- /dev/null
+#ifndef INCLUDE_hashtable_h__
+#define INCLUDE_hashtable_h__
+
+#include "git/common.h"
+#include "git/oid.h"
+#include "git/odb.h"
+
+
+typedef uint32_t (*git_hash_ptr)(const void *);
+typedef int (*git_hash_keyeq_ptr)(void *obj, const void *obj_key);
+
+struct git_hashtable_node {
+ void *object;
+ uint32_t hash;
+ struct git_hashtable_node *next;
+};
+
+struct git_hashtable {
+ struct git_hashtable_node **nodes;
+
+ unsigned int size_mask;
+ unsigned int count;
+ unsigned int max_count;
+
+ git_hash_ptr hash;
+ git_hash_keyeq_ptr key_equal;
+};
+
+struct git_hashtable_iterator {
+ struct git_hashtable_node **nodes;
+ struct git_hashtable_node *current_node;
+ unsigned int current_pos;
+ unsigned int size;
+};
+
+typedef struct git_hashtable_node git_hashtable_node;
+typedef struct git_hashtable git_hashtable;
+typedef struct git_hashtable_iterator git_hashtable_iterator;
+
+git_hashtable *git_hashtable_alloc(unsigned int min_size,
+ git_hash_ptr hash,
+ git_hash_keyeq_ptr key_eq);
+int git_hashtable_insert(git_hashtable *h, const void *key, void *value);
+void *git_hashtable_lookup(git_hashtable *h, const void *key);
+void git_hashtable_free(git_hashtable *h);
+void git_hashtable_clear(git_hashtable *h);
+
+void *git_hashtable_iterator_next(git_hashtable_iterator *it);
+void git_hashtable_iterator_init(git_hashtable *h, git_hashtable_iterator *it);
+
+#endif
--- /dev/null
+/*
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2,
+ * as published by the Free Software Foundation.
+ *
+ * In addition to the permissions in the GNU General Public License,
+ * the authors give you unlimited permission to link the compiled
+ * version of this file into combinations with other programs,
+ * and to distribute those combinations without any restriction
+ * coming from the use of this file. (The General Public License
+ * restrictions do apply in other respects; for example, they cover
+ * modification of the file, and distribution when not linked into
+ * a combined executable.)
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "common.h"
+#include "repository.h"
+#include "commit.h"
+#include "tag.h"
+
+static const int default_table_size = 32;
+static const double max_load_factor = 0.65;
+
+uint32_t git_repository_object_hash(const void *key)
+{
+ uint32_t r;
+ git_oid *id;
+
+ id = (git_oid *)key;
+ memcpy(&r, id->id, sizeof(r));
+ return r;
+}
+
+int git_repository_object_haskey(void *object, const void *key)
+{
+ git_repository_object *obj;
+ git_oid *oid;
+
+ obj = (git_repository_object *)object;
+ oid = (git_oid *)key;
+
+ return (git_oid_cmp(oid, &obj->id) == 0);
+}
+
+git_repository *git_repository_alloc(git_odb *odb)
+{
+ git_repository *repo = git__malloc(sizeof(git_repository));
+ if (!repo)
+ return NULL;
+
+ memset(repo, 0x0, sizeof(git_repository));
+
+ repo->objects = git_hashtable_alloc(
+ default_table_size,
+ git_repository_object_hash,
+ git_repository_object_haskey);
+
+ if (repo->objects == NULL) {
+ free(repo);
+ return NULL;
+ }
+
+ repo->db = odb; /* TODO: create ODB manually! */
+
+ return repo;
+}
+
+void git_repository_free(git_repository *repo)
+{
+ git_hashtable_iterator it;
+ git_repository_object *object;
+
+ git_hashtable_iterator_init(repo->objects, &it);
+
+ while ((object = (git_repository_object *)
+ git_hashtable_iterator_next(&it)) != NULL) {
+
+ switch (object->type) {
+ case GIT_OBJ_COMMIT:
+ git_commit__free((git_commit *)object);
+ break;
+
+ case GIT_OBJ_TREE:
+ git_tree__free((git_tree *)object);
+ break;
+
+ case GIT_OBJ_TAG:
+ git_tag__free((git_tag *)object);
+ break;
+
+ default:
+ free(object);
+ break;
+ }
+ }
+
+ git_hashtable_free(repo->objects);
+ /* TODO: free odb */
+ free(repo);
+}
+
+git_repository_object *git_repository_lookup(git_repository *repo, const git_oid *id, git_otype type)
+{
+ git_repository_object *object = NULL;
+ git_obj obj_file;
+
+ assert(repo);
+
+ object = git_hashtable_lookup(repo->objects, id);
+ if (object != NULL)
+ return object;
+
+ if (git_odb_read(&obj_file, repo->db, id) < 0 ||
+ (type != GIT_OBJ_ANY && type != obj_file.type))
+ return NULL;
+
+ object = git__malloc(sizeof(git_commit));
+
+ if (object == NULL)
+ return NULL;
+
+ memset(object, 0x0, sizeof(git_commit));
+
+ /* Initialize parent object */
+ git_oid_cpy(&object->id, id);
+ object->repo = repo;
+ object->type = obj_file.type;
+
+ git_hashtable_insert(repo->objects, &object->id, object);
+ git_obj_close(&obj_file);
+
+ return object;
+}
--- /dev/null
+#ifndef INCLUDE_repository_h__
+#define INCLUDE_repository_h__
+
+#include "git/common.h"
+#include "git/oid.h"
+#include "git/odb.h"
+#include "git/repository.h"
+
+#include "hashtable.h"
+
+struct git_repository_object {
+ git_oid id;
+ git_repository *repo;
+ git_otype type;
+};
+
+struct git_repository {
+ git_odb *db;
+ git_hashtable *objects;
+};
+
+int git_repository__insert(git_repository *repo, git_repository_object *obj);
+git_repository_object *git_repository__lookup(git_repository *repo, const git_oid *id);
+
+#endif
+++ /dev/null
-/*
- * This file is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2,
- * as published by the Free Software Foundation.
- *
- * In addition to the permissions in the GNU General Public License,
- * the authors give you unlimited permission to link the compiled
- * version of this file into combinations with other programs,
- * and to distribute those combinations without any restriction
- * coming from the use of this file. (The General Public License
- * restrictions do apply in other respects; for example, they cover
- * modification of the file, and distribution when not linked into
- * a combined executable.)
- *
- * This file is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "common.h"
-#include "revobject.h"
-
-static const double max_load_factor = 0.65;
-
-static unsigned int git_revpool_table__hash(const git_oid *id)
-{
- unsigned int r;
- memcpy(&r, id->id, sizeof(r));
- return r;
-}
-
-git_revpool_table *git_revpool_table_create(unsigned int min_size)
-{
- git_revpool_table *table;
- unsigned int i;
-
- table = git__malloc(sizeof(*table));
-
- if (table == NULL)
- return NULL;
-
- /* round up size to closest power of 2 */
- min_size--;
- min_size |= min_size >> 1;
- min_size |= min_size >> 2;
- min_size |= min_size >> 4;
- min_size |= min_size >> 8;
- min_size |= min_size >> 16;
-
- table->size_mask = min_size;
- table->count = 0;
- table->max_count = (unsigned int)((min_size + 1) * max_load_factor);
-
- table->nodes = git__malloc((min_size + 1) * sizeof(git_revpool_node *));
-
- if (table->nodes == NULL) {
- free(table);
- return NULL;
- }
-
- for (i = 0; i <= min_size; ++i)
- table->nodes[i] = NULL;
-
- return table;
-}
-
-int git_revpool_table_insert(git_revpool_table *table, git_revpool_object *object)
-{
- git_revpool_node *node;
- unsigned int index, hash;
-
- if (table == NULL)
- return GIT_ERROR;
-
- if (table->count + 1 > table->max_count)
- git_revpool_table_resize(table);
-
- node = git__malloc(sizeof(git_revpool_node));
- if (node == NULL)
- return GIT_ENOMEM;
-
- hash = git_revpool_table__hash(&object->id);
- index = (hash & table->size_mask);
-
- node->object = object;
- node->hash = hash;
- node->next = table->nodes[index];
-
- table->nodes[index] = node;
- table->count++;
-
- return 0;
-}
-
-git_revpool_object *git_revpool_table_lookup(git_revpool_table *table, const git_oid *id)
-{
- git_revpool_node *node;
- unsigned int index, hash;
-
- if (table == NULL)
- return NULL;
-
- hash = git_revpool_table__hash(id);
- index = (hash & table->size_mask);
- node = table->nodes[index];
-
- while (node != NULL) {
- if (node->hash == hash && git_oid_cmp(id, &node->object->id) == 0)
- return node->object;
-
- node = node->next;
- }
-
- return NULL;
-}
-
-void git_revpool_table_resize(git_revpool_table *table)
-{
- git_revpool_node **new_nodes;
- unsigned int new_size, i;
-
- new_size = (table->size_mask + 1) * 2;
-
- new_nodes = git__malloc(new_size * sizeof(git_revpool_node *));
- if (new_nodes == NULL)
- return;
-
- memset(new_nodes, 0x0, new_size * sizeof(git_revpool_node *));
-
- for (i = 0; i <= table->size_mask; ++i) {
- git_revpool_node *n;
- unsigned int index;
-
- while ((n = table->nodes[i]) != NULL) {
- table->nodes[i] = n->next;
- index = n->hash & (new_size - 1);
- n->next = new_nodes[index];
- new_nodes[index] = n;
- }
- }
-
- free(table->nodes);
- table->nodes = new_nodes;
- table->size_mask = (new_size - 1);
- table->max_count = (unsigned int)(new_size * max_load_factor);
-}
-
-
-void git_revpool_table_free(git_revpool_table *table)
-{
- unsigned int index;
-
- for (index = 0; index <= table->size_mask; ++index) {
- git_revpool_node *node, *next_node;
-
- node = table->nodes[index];
- while (node != NULL) {
- next_node = node->next;
- free(node);
- node = next_node;
- }
- }
-
- free(table->nodes);
- free(table);
-}
-
-void git_revpool_tableit_init(git_revpool_table *table, git_revpool_tableit *it)
-{
- memset(it, 0x0, sizeof(git_revpool_tableit));
-
- it->nodes = table->nodes;
- it->current_node = NULL;
- it->current_pos = 0;
- it->size = table->size_mask + 1;
-}
-
-git_revpool_object *git_revpool_tableit_next(git_revpool_tableit *it)
-{
- git_revpool_node *next = NULL;
-
- while (it->current_node == NULL) {
- if (it->current_pos >= it->size)
- return NULL;
-
- it->current_node = it->nodes[it->current_pos++];
- }
-
- next = it->current_node;
- it->current_node = it->current_node->next;
-
- return next->object;
-}
-
-git_revpool_object *git_revpool_tableit_nextfilter(git_revpool_tableit *it, git_otype type)
-{
- git_revpool_object *obj;
-
- do {
- obj = git_revpool_tableit_next(it);
- } while (obj != NULL && obj->type != type);
-
- return obj;
-}
+++ /dev/null
-#ifndef INCLUDE_objecttable_h__
-#define INCLUDE_objecttable_h__
-
-#include "git/common.h"
-#include "git/oid.h"
-#include "git/odb.h"
-
-struct git_revpool_object {
- git_oid id;
- git_revpool *pool;
- git_otype type;
-};
-
-struct git_revpool_node {
- struct git_revpool_object *object;
- unsigned int hash;
- struct git_revpool_node *next;
-};
-
-struct git_revpool_table {
- struct git_revpool_node **nodes;
-
- unsigned int size_mask;
- unsigned int count;
- unsigned int max_count;
-};
-
-struct git_revpool_tableit {
- struct git_revpool_node **nodes;
- struct git_revpool_node *current_node;
- unsigned int current_pos;
- unsigned int size;
-};
-
-
-typedef struct git_revpool_node git_revpool_node;
-typedef struct git_revpool_object git_revpool_object;
-typedef struct git_revpool_table git_revpool_table;
-typedef struct git_revpool_tableit git_revpool_tableit;
-
-git_revpool_table *git_revpool_table_create(unsigned int min_size);
-int git_revpool_table_insert(git_revpool_table *table, git_revpool_object *object);
-git_revpool_object *git_revpool_table_lookup(git_revpool_table *table, const git_oid *id);
-void git_revpool_table_resize(git_revpool_table *table);
-void git_revpool_table_free(git_revpool_table *table);
-
-
-git_revpool_object *git_revpool_tableit_next(git_revpool_tableit *it);
-git_revpool_object *git_revpool_tableit_nextfilter(git_revpool_tableit *it, git_otype type);
-void git_revpool_tableit_init(git_revpool_table *table, git_revpool_tableit *it);
-
-#endif
#include "common.h"
#include "commit.h"
#include "revwalk.h"
+#include "hashtable.h"
-static const int default_table_size = 32;
+uint32_t git_revwalk_commit_hash(const void *key)
+{
+ uint32_t r;
+ git_commit *commit;
-git_revpool *gitrp_alloc(git_odb *db)
+ commit = (git_commit *)key;
+ memcpy(&r, commit->object.id.id, sizeof(r));
+ return r;
+}
+
+int git_revwalk_commit_haskey(void *object, const void *key)
{
- git_revpool *walk = git__malloc(sizeof(*walk));
- if (!walk)
+ git_revwalk_commit *walk_commit;
+ git_commit *commit_object;
+
+ walk_commit = (git_revwalk_commit *)object;
+ commit_object = (git_commit *)key;
+
+ return (walk_commit->commit_object == commit_object);
+}
+
+
+git_revwalk *git_revwalk_alloc(git_repository *repo)
+{
+ git_revwalk *walk;
+
+ walk = git__malloc(sizeof(git_revwalk));
+ if (walk == NULL)
return NULL;
- memset(walk, 0x0, sizeof(git_revpool));
+ memset(walk, 0x0, sizeof(git_revwalk));
- walk->objects = git_revpool_table_create(default_table_size);
+ walk->commits = git_hashtable_alloc(64,
+ git_revwalk_commit_hash,
+ git_revwalk_commit_haskey);
+
+ if (walk->commits == NULL) {
+ free(walk);
+ return NULL;
+ }
- walk->db = db;
+ walk->repo = repo;
return walk;
}
-void gitrp_free(git_revpool *walk)
+void git_revwalk_free(git_revwalk *walk)
{
- git_revpool_object *obj;
- git_revpool_tableit it;
+ git_revwalk_reset(walk);
+ git_hashtable_free(walk->commits);
+ free(walk);
+}
- git_commit_list_clear(&(walk->iterator), 0);
- git_commit_list_clear(&(walk->roots), 0);
+void git_revwalk_sorting(git_revwalk *walk, unsigned int sort_mode)
+{
+ if (walk->walking)
+ return;
- git_revpool_tableit_init(walk->objects, &it);
+ walk->sorting = sort_mode;
+ git_revwalk_reset(walk);
+}
- while ((obj = git_revpool_tableit_next(&it)) != NULL) {
- switch (obj->type) {
+static git_revwalk_commit *commit_to_walkcommit(git_revwalk *walk, git_commit *commit_object)
+{
+ git_revwalk_commit *commit;
- case GIT_OBJ_COMMIT:
- git_commit__free((git_commit *)obj);
- break;
+ commit = (git_revwalk_commit *)git_hashtable_lookup(walk->commits, commit_object);
- case GIT_OBJ_TREE:
- git_tree__free((git_tree *)obj);
- break;
+ if (commit != NULL)
+ return commit;
- default:
- free(obj);
- break;
- }
+ if (!commit_object->basic_parse) {
+ if (git_commit__parse_basic(commit_object) < 0)
+ return NULL;
}
- git_revpool_table_free(walk->objects);
+ commit = git__malloc(sizeof(git_revwalk_commit));
+ if (commit == NULL)
+ return NULL;
- free(walk);
+ memset(commit, 0x0, sizeof(git_revwalk_commit));
+
+ commit->commit_object = commit_object;
+
+ git_hashtable_insert(walk->commits, commit_object, commit);
+
+ return commit;
}
-void gitrp_sorting(git_revpool *pool, unsigned int sort_mode)
+static git_revwalk_commit *insert_commit(git_revwalk *walk, git_commit *commit_object)
{
- if (pool->walking)
- return;
+ git_revwalk_commit *commit;
+ git_commit_parents *parents;
+
+ assert(walk && commit_object);
+
+ if (commit_object->object.repo != walk->repo || walk->walking)
+ return NULL;
+
+ commit = commit_to_walkcommit(walk, commit_object);
+ if (commit == NULL)
+ return NULL;
- pool->sorting = sort_mode;
- gitrp_reset(pool);
+ if (commit->seen)
+ return commit;
+
+ commit->seen = 1;
+
+ assert(commit->commit_object->basic_parse);
+
+ for (parents = commit->commit_object->parents; parents != NULL; parents = parents->next) {
+ git_revwalk_commit *parent;
+
+ if ((parent = commit_to_walkcommit(walk, parents->commit)) == NULL)
+ return NULL;
+
+ parent = insert_commit(walk, parents->commit);
+ if (parent == NULL)
+ return NULL;
+
+ parent->in_degree++;
+
+ git_revwalk_list_push_back(&commit->parents, parent);
+ }
+
+ if (git_revwalk_list_push_back(&walk->iterator, commit))
+ return NULL;
+
+ return commit;
}
-int gitrp_push(git_revpool *pool, git_commit *commit)
+int git_revwalk_push(git_revwalk *walk, git_commit *commit)
{
- if (commit == NULL || commit->seen)
- return GIT_ENOTFOUND;
+ return insert_commit(walk, commit) ? GIT_SUCCESS : GIT_ERROR;
+}
- if (commit->object.pool != pool || pool->walking)
- return GIT_ERROR;
+static void mark_uninteresting(git_revwalk_commit *commit)
+{
+ git_revwalk_listnode *parent;
+
+ if (commit == NULL)
+ return;
- if (!commit->basic_parse) {
- int error = git_commit__parse_basic(commit);
+ commit->uninteresting = 1;
+ parent = commit->parents.head;
- if (error < 0)
- return error;
+ while (parent) {
+ mark_uninteresting(parent->walk_commit);
+ parent = parent->next;
}
+}
+
+int git_revwalk_hide(git_revwalk *walk, git_commit *commit)
+{
+ git_revwalk_commit *hide;
+
+ hide = insert_commit(walk, commit);
+ if (hide == NULL)
+ return GIT_ERROR;
- /*
- * Sanity check: make sure that if the commit
- * has been manually marked as uninteresting,
- * all the parent commits are too.
- */
- if (commit->uninteresting)
- git_commit__mark_uninteresting(commit);
+ mark_uninteresting(hide);
+ return GIT_SUCCESS;
+}
- if (git_commit_list_push_back(&pool->roots, commit) < 0)
- return GIT_ENOMEM;
- return 0;
+static void prepare_walk(git_revwalk *walk)
+{
+ if (walk->sorting & GIT_SORT_TIME)
+ git_revwalk_list_timesort(&walk->iterator);
+
+ if (walk->sorting & GIT_SORT_TOPOLOGICAL)
+ git_revwalk_list_toposort(&walk->iterator);
+
+ if (walk->sorting & GIT_SORT_REVERSE)
+ walk->next = &git_revwalk_list_pop_back;
+ else
+ walk->next = &git_revwalk_list_pop_front;
+
+ walk->walking = 1;
}
-int gitrp_hide(git_revpool *pool, git_commit *commit)
+git_commit *git_revwalk_next(git_revwalk *walk)
{
- if (pool->walking)
- return GIT_ERROR;
+ git_revwalk_commit *next;
- git_commit__mark_uninteresting(commit);
- return gitrp_push(pool, commit);
+ if (!walk->walking)
+ prepare_walk(walk);
+
+ while ((next = walk->next(&walk->iterator)) != NULL) {
+ if (!next->uninteresting)
+ return next->commit_object;
+ }
+
+ /* No commits left to iterate */
+ git_revwalk_reset(walk);
+ return NULL;
}
-int gitrp__enroot(git_revpool *pool, git_commit *commit)
+void git_revwalk_reset(git_revwalk *walk)
{
- int error;
- git_commit_node *parents;
+ git_hashtable_iterator it;
+ git_revwalk_commit *commit;
- if (commit->seen)
- return 0;
+ git_hashtable_iterator_init(walk->commits, &it);
- if (!commit->basic_parse) {
- error = git_commit__parse_basic(commit);
- if (error < 0)
- return error;
+ while ((commit = (git_revwalk_commit *)
+ git_hashtable_iterator_next(&it)) != NULL) {
+ git_revwalk_list_clear(&commit->parents);
+ free(commit);
}
- commit->seen = 1;
+ git_hashtable_clear(walk->commits);
+ git_revwalk_list_clear(&walk->iterator);
+ walk->walking = 0;
+}
+
+
+
+
+
+
+int git_revwalk_list_push_back(git_revwalk_list *list, git_revwalk_commit *commit)
+{
+ git_revwalk_listnode *node = NULL;
+
+ node = git__malloc(sizeof(git_revwalk_listnode));
+
+ if (node == NULL)
+ return GIT_ENOMEM;
- for (parents = commit->parents.head; parents != NULL; parents = parents->next) {
- parents->commit->in_degree++;
+ node->walk_commit = commit;
+ node->next = NULL;
+ node->prev = list->tail;
- error = gitrp__enroot(pool, parents->commit);
- if (error < 0)
- return error;
+ if (list->tail == NULL) {
+ list->head = list->tail = node;
+ } else {
+ list->tail->next = node;
+ list->tail = node;
}
- if (git_commit_list_push_back(&pool->iterator, commit))
+ list->size++;
+ return 0;
+}
+
+int git_revwalk_list_push_front(git_revwalk_list *list, git_revwalk_commit *commit)
+{
+ git_revwalk_listnode *node = NULL;
+
+ node = git__malloc(sizeof(git_revwalk_listnode));
+
+ if (node == NULL)
return GIT_ENOMEM;
+ node->walk_commit = commit;
+ node->next = list->head;
+ node->prev = NULL;
+
+ if (list->head == NULL) {
+ list->head = list->tail = node;
+ } else {
+ list->head->prev = node;
+ list->head = node;
+ }
+
+ list->size++;
return 0;
}
-void gitrp__prepare_walk(git_revpool *pool)
+
+git_revwalk_commit *git_revwalk_list_pop_back(git_revwalk_list *list)
{
- git_commit_node *it;
+ git_revwalk_listnode *node;
+ git_revwalk_commit *commit;
- for (it = pool->roots.head; it != NULL; it = it->next)
- gitrp__enroot(pool, it->commit);
+ if (list->tail == NULL)
+ return NULL;
- if (pool->sorting & GIT_RPSORT_TIME)
- git_commit_list_timesort(&pool->iterator);
+ node = list->tail;
+ list->tail = list->tail->prev;
+ if (list->tail == NULL)
+ list->head = NULL;
- if (pool->sorting & GIT_RPSORT_TOPOLOGICAL)
- git_commit_list_toposort(&pool->iterator);
+ commit = node->walk_commit;
+ free(node);
- if (pool->sorting & GIT_RPSORT_REVERSE)
- pool->next_commit = &git_commit_list_pop_back;
- else
- pool->next_commit = &git_commit_list_pop_front;
+ list->size--;
- pool->walking = 1;
+ return commit;
}
-git_commit *gitrp_next(git_revpool *pool)
+git_revwalk_commit *git_revwalk_list_pop_front(git_revwalk_list *list)
{
- git_commit *next;
+ git_revwalk_listnode *node;
+ git_revwalk_commit *commit;
+
+ if (list->head == NULL)
+ return NULL;
- if (!pool->walking)
- gitrp__prepare_walk(pool);
+ node = list->head;
+ list->head = list->head->next;
+ if (list->head == NULL)
+ list->tail = NULL;
- while ((next = pool->next_commit(&pool->iterator)) != NULL) {
- if (!next->uninteresting)
- return next;
+ commit = node->walk_commit;
+ free(node);
+
+ list->size--;
+
+ return commit;
+}
+
+void git_revwalk_list_clear(git_revwalk_list *list)
+{
+ git_revwalk_listnode *node, *next_node;
+
+ node = list->head;
+ while (node) {
+ next_node = node->next;
+ free(node);
+ node = next_node;
}
- /* No commits left to iterate */
- gitrp_reset(pool);
- return NULL;
+ list->head = list->tail = NULL;
+ list->size = 0;
}
-void gitrp_reset(git_revpool *pool)
+void git_revwalk_list_timesort(git_revwalk_list *list)
{
- git_commit *commit;
- git_revpool_tableit it;
+ git_revwalk_listnode *p, *q, *e;
+ int in_size, p_size, q_size, merge_count, i;
+
+ if (list->head == NULL)
+ return;
+
+ in_size = 1;
+
+ do {
+ p = list->head;
+ list->tail = NULL;
+ merge_count = 0;
+
+ while (p != NULL) {
+ merge_count++;
+ q = p;
+ p_size = 0;
+ q_size = in_size;
+
+ for (i = 0; i < in_size && q; ++i, q = q->next)
+ p_size++;
+
+ while (p_size > 0 || (q_size > 0 && q)) {
- git_revpool_tableit_init(pool->objects, &it);
+ if (p_size == 0)
+ e = q, q = q->next, q_size--;
- while ((commit =
- (git_commit *)git_revpool_tableit_nextfilter(
- &it, GIT_OBJ_COMMIT)) != NULL) {
+ else if (q_size == 0 || q == NULL ||
+ p->walk_commit->commit_object->commit_time >=
+ q->walk_commit->commit_object->commit_time)
+ e = p, p = p->next, p_size--;
+
+ else
+ e = q, q = q->next, q_size--;
+
+ if (list->tail != NULL)
+ list->tail->next = e;
+ else
+ list->head = e;
+
+ e->prev = list->tail;
+ list->tail = e;
+ }
+
+ p = q;
+ }
+
+ list->tail->next = NULL;
+ in_size *= 2;
+
+ } while (merge_count > 1);
+}
+
+void git_revwalk_list_toposort(git_revwalk_list *list)
+{
+ git_revwalk_commit *commit;
+ git_revwalk_list topo;
+ memset(&topo, 0x0, sizeof(git_revwalk_list));
+
+ while ((commit = git_revwalk_list_pop_back(list)) != NULL) {
+ git_revwalk_listnode *p;
+
+ if (commit->in_degree > 0) {
+ commit->topo_delay = 1;
+ continue;
+ }
+
+ for (p = commit->parents.head; p != NULL; p = p->next) {
+ p->walk_commit->in_degree--;
+
+ if (p->walk_commit->in_degree == 0 && p->walk_commit->topo_delay) {
+ p->walk_commit->topo_delay = 0;
+ git_revwalk_list_push_back(list, p->walk_commit);
+ }
+ }
- commit->seen = 0;
- commit->topo_delay = 0;
- commit->in_degree = 0;
+ git_revwalk_list_push_back(&topo, commit);
}
- git_commit_list_clear(&pool->iterator, 0);
- pool->walking = 0;
+ list->head = topo.head;
+ list->tail = topo.tail;
+ list->size = topo.size;
}
#include "git/revwalk.h"
#include "commit.h"
+#include "repository.h"
+#include "hashtable.h"
-struct git_revpool {
- git_odb *db;
+struct git_revwalk_commit;
- git_commit_list iterator;
- git_commit *(*next_commit)(git_commit_list *);
+typedef struct git_revwalk_listnode {
+ struct git_revwalk_commit *walk_commit;
+ struct git_revwalk_listnode *next;
+ struct git_revwalk_listnode *prev;
+} git_revwalk_listnode;
- git_commit_list roots;
- git_revpool_table *objects;
+typedef struct git_revwalk_list {
+ struct git_revwalk_listnode *head;
+ struct git_revwalk_listnode *tail;
+ size_t size;
+} git_revwalk_list;
+
+
+struct git_revwalk_commit {
+
+ git_commit *commit_object;
+ git_revwalk_list parents;
+
+ unsigned short in_degree;
+ unsigned seen:1,
+ uninteresting:1,
+ topo_delay:1,
+ flags:25;
+};
+
+typedef struct git_revwalk_commit git_revwalk_commit;
+
+struct git_revwalk {
+ git_repository *repo;
+
+ git_hashtable *commits;
+ git_revwalk_list iterator;
+
+ git_revwalk_commit *(*next)(git_revwalk_list *);
unsigned walking:1;
unsigned int sorting;
};
-void gitrp__prepare_walk(git_revpool *pool);
-int gitrp__enroot(git_revpool *pool, git_commit *commit);
+
+void git_revwalk__prepare_walk(git_revwalk *walk);
+int git_revwalk__enroot(git_revwalk *walk, git_commit *commit);
+
+int git_revwalk_list_push_back(git_revwalk_list *list, git_revwalk_commit *commit);
+int git_revwalk_list_push_front(git_revwalk_list *list, git_revwalk_commit *obj);
+
+git_revwalk_commit *git_revwalk_list_pop_back(git_revwalk_list *list);
+git_revwalk_commit *git_revwalk_list_pop_front(git_revwalk_list *list);
+
+void git_revwalk_list_clear(git_revwalk_list *list);
+
+void git_revwalk_list_timesort(git_revwalk_list *list);
+void git_revwalk_list_toposort(git_revwalk_list *list);
#endif /* INCLUDE_revwalk_h__ */
#include "tag.h"
#include "revwalk.h"
#include "git/odb.h"
-
+#include "git/repository.h"
void git_tag__free(git_tag *tag)
{
return &t->object.id;
}
-const git_revpool_object *git_tag_target(git_tag *t)
+const git_repository_object *git_tag_target(git_tag *t)
{
if (t->target)
return t->target;
int error = 0;
git_obj odb_object;
- error = git_odb_read(&odb_object, tag->object.pool->db, &tag->object.id);
+ error = git_odb_read(&odb_object, tag->object.repo->db, &tag->object.id);
if (error < 0)
return error;
return error;
}
-git_tag *git_tag_lookup(git_revpool *pool, const git_oid *id)
+git_tag *git_tag_lookup(git_repository *repo, const git_oid *id)
{
- git_tag *tag = NULL;
-
- if (pool == NULL)
- return NULL;
-
- tag = (git_tag *)git_revpool_table_lookup(pool->objects, id);
- if (tag != NULL)
- return tag;
-
- tag = git__malloc(sizeof(git_tag));
-
- if (tag == NULL)
- return NULL;
-
- memset(tag, 0x0, sizeof(git_tag));
-
- /* Initialize parent object */
- git_oid_cpy(&tag->object.id, id);
- tag->object.pool = pool;
- tag->object.type = GIT_OBJ_TAG;
-
- git_revpool_table_insert(pool->objects, (git_revpool_object *)tag);
-
- return tag;
+ return (git_tag *)git_repository_lookup(repo, id, GIT_OBJ_TAG);
}
#define INCLUDE_tag_h__
#include "git/tag.h"
-#include "revobject.h"
+#include "repository.h"
struct git_tag {
- git_revpool_object object;
+ git_repository_object object;
- git_revpool_object *target;
+ git_repository_object *target;
git_otype type;
char *tag_name;
git_person *tagger;
#include "commit.h"
#include "revwalk.h"
#include "tree.h"
+#include "git/repository.h"
void git_tree__free(git_tree *tree)
{
return &tree->object.id;
}
-git_tree *git_tree_lookup(git_revpool *pool, const git_oid *id)
+git_tree *git_tree_lookup(git_repository *repo, const git_oid *id)
{
- git_tree *tree = NULL;
-
- if (pool == NULL)
- return NULL;
-
- tree = (git_tree *)git_revpool_table_lookup(pool->objects, id);
- if (tree != NULL)
- return tree;
-
- tree = git__malloc(sizeof(git_tree));
-
- if (tree == NULL)
- return NULL;
-
- memset(tree, 0x0, sizeof(git_tree));
-
- /* Initialize parent object */
- git_oid_cpy(&tree->object.id, id);
- tree->object.pool = pool;
- tree->object.type = GIT_OBJ_TREE;
-
- git_revpool_table_insert(pool->objects, (git_revpool_object *)tree);
-
- return tree;
-}
-
-
-git_tree *git_tree_parse(git_revpool *pool, const git_oid *id)
-{
- git_tree *tree = NULL;
-
- if ((tree = git_tree_lookup(pool, id)) == NULL)
- return NULL;
-
- if (git_tree__parse(tree) < 0)
- goto error_cleanup;
-
- return tree;
-
-error_cleanup:
- /* FIXME: do not free; the tree is owned by the revpool */
- free(tree);
- return NULL;
+ return (git_tree *)git_repository_lookup(repo, id, GIT_OBJ_TREE);
}
int git_tree__parse(git_tree *tree)
git_obj odb_object;
char *buffer, *buffer_end;
- error = git_odb_read(&odb_object, tree->object.pool->db, &tree->object.id);
+ error = git_odb_read(&odb_object, tree->object.repo->db, &tree->object.id);
if (error < 0)
return error;
#define INCLUDE_tree_h__
#include <git/tree.h>
-#include "revobject.h"
+#include "repository.h"
struct git_tree_entry {
typedef struct git_tree_entry git_tree_entry;
struct git_tree {
- git_revpool_object object;
+ git_repository_object object;
size_t byte_size;
git_tree_entry *entries;
/* simple commit, 1 parents */
"tree f6c0dad3c7b3481caa9d73db21f91964894a945b\n\
-parent 05452d6349abcd67aa396dfb28660d765d8b2a36\n\
+parent a4a7dce85cf63874e984719f4fdd239f5145052f\n\
author Vicent Marti <tanoku@gmail.com> 1273848544 +0200\n\
committer Vicent Marti <tanoku@gmail.com> 1273848544 +0200\n\
\n\
const int broken_commit_count = sizeof(test_commits_broken) / sizeof(*test_commits_broken);
const int working_commit_count = sizeof(test_commits_working) / sizeof(*test_commits_working);
- const unsigned int default_flags = 0xFF; /* parse everything */
+ const unsigned int default_flags =
+ GIT_COMMIT_AUTHOR |
+ GIT_COMMIT_COMMITTER |
+ GIT_COMMIT_TIME |
+ GIT_COMMIT_MESSAGE |
+ GIT_COMMIT_MESSAGE_SHORT; /* parse everything */
int i;
+ git_repository *repo = git_repository_alloc(NULL);
- git_revpool *pool = gitrp_alloc(NULL);
+ must_be_true(repo != NULL);
for (i = 0; i < broken_commit_count; ++i) {
git_commit *commit;
commit = git__malloc(sizeof(git_commit));
memset(commit, 0x0, sizeof(git_commit));
- commit->object.pool = pool;
+ commit->object.repo = repo;
must_fail(git_commit__parse_buffer(
commit,
git_commit *commit;
commit = git__malloc(sizeof(git_commit));
memset(commit, 0x0, sizeof(git_commit));
- commit->object.pool = pool;
+ commit->object.repo = repo;
must_pass(git_commit__parse_buffer(
commit,
git_commit__free(commit);
}
- gitrp_free(pool);
+ git_repository_free(repo);
END_TEST
unsigned int i;
git_odb *db;
- git_revpool *pool;
+ git_repository *repo;
must_pass(git_odb_open(&db, odb_dir));
- pool = gitrp_alloc(db);
- must_be_true(pool != NULL);
+ repo = git_repository_alloc(db);
+ must_be_true(repo != NULL);
for (i = 0; i < commit_count; ++i) {
git_oid id;
git_oid_mkstr(&id, commit_ids[i]);
- commit = git_commit_parse(pool, &id);
+ commit = git_commit_lookup(repo, &id);
must_be_true(commit != NULL);
message = git_commit_message(commit);
must_be_true(commit_time > 0);
}
- gitrp_free(pool);
+ git_repository_free(repo);
git_odb_close(db);
END_TEST
+++ /dev/null
-#include "test_lib.h"
-#include "test_helpers.h"
-#include "commit.h"
-#include <git/odb.h>
-#include <git/commit.h>
-
-BEGIN_TEST(list_timesort_test)
-
- git_commit_list list;
- git_commit_node *n;
- int i, t;
- time_t previous_time;
-
-#define TEST_SORTED() \
- previous_time = INT_MAX;\
- for (n = list.head; n != NULL; n = n->next) {\
- must_be_true(n->commit->commit_time <= previous_time);\
- previous_time = n->commit->commit_time;\
- }
-
- memset(&list, 0x0, sizeof(git_commit_list));
- srand((unsigned int)time(NULL));
-
- for (t = 0; t < 20; ++t) {
- const int test_size = rand() % 500 + 500;
-
- /* Purely random sorting test */
- for (i = 0; i < test_size; ++i) {
- git_commit *c = git__malloc(sizeof(git_commit));
- c->commit_time = (time_t)rand();
-
- git_commit_list_push_back(&list, c);
- }
-
- git_commit_list_timesort(&list);
- TEST_SORTED();
- git_commit_list_clear(&list, 1);
- }
-
- /* Try to sort list with all dates equal. */
- for (i = 0; i < 200; ++i) {
- git_commit *c = git__malloc(sizeof(git_commit));
- c->commit_time = 0;
-
- git_commit_list_push_back(&list, c);
- }
-
- git_commit_list_timesort(&list);
- TEST_SORTED();
- git_commit_list_clear(&list, 1);
-
- /* Try to sort empty list */
- git_commit_list_timesort(&list);
- TEST_SORTED();
-
-END_TEST
"5b5b025afb0b4c913b4c338a42934a3863bf3644", /* 5 */
};
-static const int commit_sorting_topo[] = {0, 1, 2, 3, 5, 4};
-static const int commit_sorting_time[] = {0, 3, 1, 2, 5, 4};
-static const int commit_sorting_topo_reverse[] = {4, 5, 3, 2, 1, 0};
-static const int commit_sorting_time_reverse[] = {4, 5, 2, 1, 3, 0};
-static const int commit_sorting_topo_time[] = {0};
+/* Careful: there are two possible topological sorts */
+static const int commit_sorting_topo[][6] = {
+ {0, 1, 2, 3, 5, 4}, {0, 3, 1, 2, 5, 4}
+};
+
+static const int commit_sorting_time[][6] = {
+ {0, 3, 1, 2, 5, 4}
+};
+
+static const int commit_sorting_topo_reverse[][6] = {
+ {4, 5, 3, 2, 1, 0}, {4, 5, 2, 1, 3, 0}
+};
+
+static const int commit_sorting_time_reverse[][6] = {
+ {4, 5, 2, 1, 3, 0}
+};
+
+static const int commit_count = 6;
+static const int result_bytes = 24;
+
+
+static int get_commit_index(git_commit *commit)
+{
+ int i;
+ char oid[40];
+
+ git_oid_fmt(oid, &commit->object.id);
+
+ for (i = 0; i < commit_count; ++i)
+ if (memcmp(oid, commit_ids[i], 40) == 0)
+ return i;
+
+ return -1;
+}
+
+static int test_walk(git_revwalk *walk, git_commit *start_from,
+ int flags, const int possible_results[][6], int results_count)
+{
+ git_commit *commit = NULL;
+
+ int i;
+ int result_array[commit_count];
+
+ git_revwalk_sorting(walk, flags);
+ git_revwalk_push(walk, start_from);
+
+ for (i = 0; i < commit_count; ++i)
+ result_array[i] = -1;
+
+ i = 0;
+ while ((commit = git_revwalk_next(walk)) != NULL)
+ result_array[i++] = get_commit_index(commit);
+
+ for (i = 0; i < results_count; ++i)
+ if (memcmp(possible_results[i],
+ result_array, result_bytes) == 0)
+ return GIT_SUCCESS;
+
+ return GIT_ERROR;
+}
BEGIN_TEST(simple_walk_test)
git_odb *db;
git_oid id;
- git_revpool *pool;
+ git_repository *repo;
+ git_revwalk *walk;
git_commit *head = NULL;
must_pass(git_odb_open(&db, odb_dir));
- pool = gitrp_alloc(db);
- must_be_true(pool != NULL);
+ repo = git_repository_alloc(db);
+ must_be_true(repo != NULL);
+
+ walk = git_revwalk_alloc(repo);
+ must_be_true(walk != NULL);
git_oid_mkstr(&id, commit_head);
- head = git_commit_parse(pool, &id);
+ head = git_commit_lookup(repo, &id);
must_be_true(head != NULL);
- gitrp_push(pool, head);
-
-#define TEST_WALK(sort_flags, result_array) {\
- char oid[40]; int i = 0;\
- git_commit *commit = NULL;\
- gitrp_sorting(pool, sort_flags);\
- while ((commit = gitrp_next(pool)) != NULL) {\
- git_oid_fmt(oid, &commit->object.id);\
- must_be_true(memcmp(oid, commit_ids[result_array[i++]], 40) == 0);\
- }\
- must_be_true(i == sizeof(result_array)/sizeof(int));\
- gitrp_reset(pool);\
-}
- TEST_WALK(GIT_RPSORT_TIME, commit_sorting_time);
- TEST_WALK(GIT_RPSORT_TOPOLOGICAL, commit_sorting_topo);
- TEST_WALK(GIT_RPSORT_TIME | GIT_RPSORT_REVERSE, commit_sorting_time_reverse);
- TEST_WALK(GIT_RPSORT_TOPOLOGICAL | GIT_RPSORT_REVERSE, commit_sorting_topo_reverse);
+ must_pass(test_walk(walk, head,
+ GIT_SORT_TIME,
+ commit_sorting_time, 1));
+
+ must_pass(test_walk(walk, head,
+ GIT_SORT_TOPOLOGICAL,
+ commit_sorting_topo, 2));
+
+ must_pass(test_walk(walk, head,
+ GIT_SORT_TIME | GIT_SORT_REVERSE,
+ commit_sorting_time_reverse, 1));
+
+ must_pass(test_walk(walk, head,
+ GIT_SORT_TOPOLOGICAL | GIT_SORT_REVERSE,
+ commit_sorting_topo_reverse, 2));
-#undef TEST_WALK
- gitrp_free(pool);
+ git_revwalk_free(walk);
+ git_repository_free(repo);
git_odb_close(db);
END_TEST
--- /dev/null
+#include "test_lib.h"
+#include "test_helpers.h"
+#include "commit.h"
+#include "revwalk.h"
+#include <git/odb.h>
+#include <git/commit.h>
+
+BEGIN_TEST(list_timesort_test)
+
+ git_revwalk_list list;
+ git_revwalk_listnode *n;
+ int i, t;
+ time_t previous_time;
+
+#define TEST_SORTED() \
+ previous_time = INT_MAX;\
+ for (n = list.head; n != NULL; n = n->next) {\
+ must_be_true(n->walk_commit->commit_object->commit_time <= previous_time);\
+ previous_time = n->walk_commit->commit_object->commit_time;\
+ }
+
+#define CLEAR_LIST() \
+ for (n = list.head; n != NULL; n = n->next) {\
+ free(n->walk_commit->commit_object);\
+ free(n->walk_commit);\
+ }\
+ git_revwalk_list_clear(&list);
+
+ memset(&list, 0x0, sizeof(git_revwalk_list));
+ srand((unsigned int)time(NULL));
+
+ for (t = 0; t < 20; ++t) {
+ const int test_size = rand() % 500 + 500;
+
+ /* Purely random sorting test */
+ for (i = 0; i < test_size; ++i) {
+ git_commit *c = git__malloc(sizeof(git_commit));
+ git_revwalk_commit *rc = git__malloc(sizeof(git_revwalk_commit));
+
+ c->commit_time = (time_t)rand();
+ rc->commit_object = c;
+
+ git_revwalk_list_push_back(&list, rc);
+ }
+
+ git_revwalk_list_timesort(&list);
+ TEST_SORTED();
+ CLEAR_LIST();
+ }
+
+ /* Try to sort list with all dates equal. */
+ for (i = 0; i < 200; ++i) {
+ git_commit *c = git__malloc(sizeof(git_commit));
+ git_revwalk_commit *rc = git__malloc(sizeof(git_revwalk_commit));
+
+ c->commit_time = 0;
+ rc->commit_object = c;
+
+ git_revwalk_list_push_back(&list, rc);
+ }
+
+ git_revwalk_list_timesort(&list);
+ TEST_SORTED();
+ CLEAR_LIST();
+
+ /* Try to sort empty list */
+ git_revwalk_list_timesort(&list);
+ TEST_SORTED();
+
+END_TEST
+++ /dev/null
-#include "test_lib.h"
-#include "test_helpers.h"
-#include "commit.h"
-#include "revobject.h"
-#include "hash.h"
-
-
-BEGIN_TEST(table_create)
-
- git_revpool_table *table = NULL;
-
- table = git_revpool_table_create(55);
- must_be_true(table != NULL);
- must_be_true(table->size_mask + 1 == 64);
-
- git_revpool_table_free(table);
-
-END_TEST
-
-BEGIN_TEST(table_populate)
-
- const int objects_n = 32;
- int i;
- git_revpool_object *objects;
- git_revpool_table *table = NULL;
-
- table = git_revpool_table_create(objects_n * 2);
- must_be_true(table != NULL);
-
- objects = git__malloc(objects_n * sizeof(git_revpool_object));
- memset(objects, 0x0, objects_n * sizeof(git_revpool_object));
-
- /* populate the hash table */
- for (i = 0; i < objects_n; ++i) {
- git_hash_buf(&(objects[i].id), &i, sizeof(int));
- must_pass(git_revpool_table_insert(table, &(objects[i])));
- }
-
- /* make sure all the inserted objects can be found */
- for (i = 0; i < objects_n; ++i) {
- git_oid id;
- git_revpool_object *ob;
-
- git_hash_buf(&id, &i, sizeof(int));
- ob = git_revpool_table_lookup(table, &id);
-
- must_be_true(ob != NULL);
- must_be_true(ob == &(objects[i]));
- }
-
- /* make sure we cannot find inexisting objects */
- for (i = 0; i < 50; ++i) {
- int hash_id;
- git_oid id;
-
- hash_id = (rand() % 50000) + objects_n;
- git_hash_buf(&id, &hash_id, sizeof(int));
- must_be_true(git_revpool_table_lookup(table, &id) == NULL);
- }
-
- git_revpool_table_free(table);
- free(objects);
-
-END_TEST
-
-
-BEGIN_TEST(table_resize)
-
- const int objects_n = 64;
- int i;
- unsigned int old_size;
- git_revpool_object *objects;
- git_revpool_table *table = NULL;
-
- table = git_revpool_table_create(objects_n);
- must_be_true(table != NULL);
-
- objects = git__malloc(objects_n * sizeof(git_revpool_object));
- memset(objects, 0x0, objects_n * sizeof(git_revpool_object));
-
- old_size = table->size_mask + 1;
-
- /* populate the hash table -- should be automatically resized */
- for (i = 0; i < objects_n; ++i) {
- git_hash_buf(&(objects[i].id), &i, sizeof(int));
- must_pass(git_revpool_table_insert(table, &(objects[i])));
- }
-
- must_be_true(table->size_mask > old_size);
-
- /* make sure all the inserted objects can be found */
- for (i = 0; i < objects_n; ++i) {
- git_oid id;
- git_revpool_object *ob;
-
- git_hash_buf(&id, &i, sizeof(int));
- ob = git_revpool_table_lookup(table, &id);
-
- must_be_true(ob != NULL);
- must_be_true(ob == &(objects[i]));
- }
-
- /* force another resize */
- old_size = table->size_mask + 1;
- git_revpool_table_resize(table);
- must_be_true(table->size_mask > old_size);
-
- /* make sure all the inserted objects can be found */
- for (i = 0; i < objects_n; ++i) {
- git_oid id;
- git_revpool_object *ob;
-
- git_hash_buf(&id, &i, sizeof(int));
- ob = git_revpool_table_lookup(table, &id);
-
- must_be_true(ob != NULL);
- must_be_true(ob == &(objects[i]));
- }
-
- git_revpool_table_free(table);
- free(objects);
-
-END_TEST
+++ /dev/null
-#include "test_lib.h"
-#include "test_helpers.h"
-#include "commit.h"
-#include "revobject.h"
-#include "hash.h"
-
-typedef struct _aux_object {
- git_revpool_object object;
- int visited;
-} aux_object;
-
-
-BEGIN_TEST(table_iterator)
-
- const int objects_n = 32;
- int i;
- aux_object *objects, *ob;
-
- git_revpool_table *table = NULL;
- git_revpool_tableit iterator;
-
- table = git_revpool_table_create(objects_n * 2);
- must_be_true(table != NULL);
-
- objects = git__malloc(objects_n * sizeof(aux_object));
- memset(objects, 0x0, objects_n * sizeof(aux_object));
-
- /* populate the hash table */
- for (i = 0; i < objects_n; ++i) {
- git_hash_buf(&(objects[i].object.id), &i, sizeof(int));
- must_pass(git_revpool_table_insert(table, (git_revpool_object *)&(objects[i])));
- }
-
- git_revpool_tableit_init(table, &iterator);
-
- /* iterate through all nodes, mark as visited */
- while ((ob = (aux_object *)git_revpool_tableit_next(&iterator)) != NULL)
- ob->visited = 1;
-
- /* make sure all nodes have been visited */
- for (i = 0; i < objects_n; ++i)
- must_be_true(objects[i].visited);
-
- git_revpool_table_free(table);
- free(objects);
-
-END_TEST
--- /dev/null
+#include "test_lib.h"
+#include "test_helpers.h"
+#include "commit.h"
+#include "hash.h"
+#include "hashtable.h"
+
+typedef struct table_item
+{
+ int __bulk;
+ git_oid id;
+} table_item;
+
+
+uint32_t hash_func(const void *key)
+{
+ uint32_t r;
+ git_oid *id;
+
+ id = (git_oid *)key;
+ memcpy(&r, id->id, sizeof(r));
+ return r;
+}
+
+int hash_haskey(void *item, const void *key)
+{
+ table_item *obj;
+ git_oid *oid;
+
+ obj = (table_item *)item;
+ oid = (git_oid *)key;
+
+ return (git_oid_cmp(oid, &obj->id) == 0);
+}
+
+BEGIN_TEST(table_create)
+
+ git_hashtable *table = NULL;
+
+ table = git_hashtable_alloc(55, hash_func, hash_haskey);
+ must_be_true(table != NULL);
+ must_be_true(table->size_mask + 1 == 64);
+
+ git_hashtable_free(table);
+
+END_TEST
+
+BEGIN_TEST(table_populate)
+
+ const int objects_n = 32;
+ int i;
+
+ table_item *objects;
+ git_hashtable *table = NULL;
+
+ table = git_hashtable_alloc(objects_n * 2, hash_func, hash_haskey);
+ must_be_true(table != NULL);
+
+ objects = git__malloc(objects_n * sizeof(table_item));
+ memset(objects, 0x0, objects_n * sizeof(table_item));
+
+ /* populate the hash table */
+ for (i = 0; i < objects_n; ++i) {
+ git_hash_buf(&(objects[i].id), &i, sizeof(int));
+ must_pass(git_hashtable_insert(table, &(objects[i].id), &(objects[i])));
+ }
+
+ /* make sure all the inserted objects can be found */
+ for (i = 0; i < objects_n; ++i) {
+ git_oid id;
+ table_item *ob;
+
+ git_hash_buf(&id, &i, sizeof(int));
+ ob = (table_item *)git_hashtable_lookup(table, &id);
+
+ must_be_true(ob != NULL);
+ must_be_true(ob == &(objects[i]));
+ }
+
+ /* make sure we cannot find inexisting objects */
+ for (i = 0; i < 50; ++i) {
+ int hash_id;
+ git_oid id;
+
+ hash_id = (rand() % 50000) + objects_n;
+ git_hash_buf(&id, &hash_id, sizeof(int));
+ must_be_true(git_hashtable_lookup(table, &id) == NULL);
+ }
+
+ git_hashtable_free(table);
+ free(objects);
+
+END_TEST
+
+
+BEGIN_TEST(table_resize)
+
+ const int objects_n = 64;
+ int i;
+ unsigned int old_size;
+ table_item *objects;
+ git_hashtable *table = NULL;
+
+ table = git_hashtable_alloc(objects_n, hash_func, hash_haskey);
+ must_be_true(table != NULL);
+
+ objects = git__malloc(objects_n * sizeof(table_item));
+ memset(objects, 0x0, objects_n * sizeof(table_item));
+
+ old_size = table->size_mask + 1;
+
+ /* populate the hash table -- should be automatically resized */
+ for (i = 0; i < objects_n; ++i) {
+ git_hash_buf(&(objects[i].id), &i, sizeof(int));
+ must_pass(git_hashtable_insert(table, &(objects[i].id), &(objects[i])));
+ }
+
+ must_be_true(table->size_mask > old_size);
+
+ /* make sure all the inserted objects can be found */
+ for (i = 0; i < objects_n; ++i) {
+ git_oid id;
+ table_item *ob;
+
+ git_hash_buf(&id, &i, sizeof(int));
+ ob = (table_item *)git_hashtable_lookup(table, &id);
+
+ must_be_true(ob != NULL);
+ must_be_true(ob == &(objects[i]));
+ }
+
+ git_hashtable_free(table);
+ free(objects);
+
+END_TEST
--- /dev/null
+#include "test_lib.h"
+#include "test_helpers.h"
+#include "commit.h"
+#include "hashtable.h"
+#include "hash.h"
+
+typedef struct _aux_object {
+ int __bulk;
+ git_oid id;
+ int visited;
+} table_item;
+
+uint32_t hash_func(const void *key)
+{
+ uint32_t r;
+ git_oid *id;
+
+ id = (git_oid *)key;
+ memcpy(&r, id->id, sizeof(r));
+ return r;
+}
+
+int hash_haskey(void *item, const void *key)
+{
+ table_item *obj;
+ git_oid *oid;
+
+ obj = (table_item *)item;
+ oid = (git_oid *)key;
+
+ return (git_oid_cmp(oid, &obj->id) == 0);
+}
+
+
+BEGIN_TEST(table_iterator)
+
+ const int objects_n = 32;
+ int i;
+ table_item *objects, *ob;
+
+ git_hashtable *table = NULL;
+ git_hashtable_iterator iterator;
+
+ table = git_hashtable_alloc(objects_n * 2, hash_func, hash_haskey);
+ must_be_true(table != NULL);
+
+ objects = git__malloc(objects_n * sizeof(table_item));
+ memset(objects, 0x0, objects_n * sizeof(table_item));
+
+ /* populate the hash table */
+ for (i = 0; i < objects_n; ++i) {
+ git_hash_buf(&(objects[i].id), &i, sizeof(int));
+ must_pass(git_hashtable_insert(table, &(objects[i].id), &(objects[i])));
+ }
+
+ git_hashtable_iterator_init(table, &iterator);
+
+ /* iterate through all nodes, mark as visited */
+ while ((ob = (table_item *)git_hashtable_iterator_next(&iterator)) != NULL)
+ ob->visited = 1;
+
+ /* make sure all nodes have been visited */
+ for (i = 0; i < objects_n; ++i)
+ must_be_true(objects[i].visited);
+
+ git_hashtable_free(table);
+ free(objects);
+
+END_TEST