2 * token.c : routines for doing diffs
\r
4 * ====================================================================
\r
5 * Copyright (c) 2000-2004 CollabNet. All rights reserved.
\r
7 * This software is licensed as described in the file COPYING, which
\r
8 * you should have received as part of this distribution. The terms
\r
9 * are also available at http://subversion.tigris.org/license-1.html.
\r
10 * If newer versions of this license are posted there, you may use a
\r
11 * newer version instead, at your option.
\r
13 * This software consists of voluntary contributions made by many
\r
14 * individuals. For exact contribution history, see the revision
\r
15 * history and logs, available at http://subversion.tigris.org/.
\r
16 * ====================================================================
\r
21 #include <apr_pools.h>
\r
22 #include <apr_general.h>
\r
24 #include "svn_error.h"
\r
25 #include "svn_diff.h"
\r
26 #include "svn_types.h"
\r
32 * Prime number to use as the size of the hash table. This number was
\r
33 * not selected by testing of any kind and may need tweaking.
\r
35 #define SVN_DIFF__HASH_SIZE 127
\r
37 struct svn_diff__node_t
\r
39 svn_diff__node_t *parent;
\r
40 svn_diff__node_t *left;
\r
41 svn_diff__node_t *right;
\r
47 struct svn_diff__tree_t
\r
49 svn_diff__node_t *root[SVN_DIFF__HASH_SIZE];
\r
55 * Support functions to build a tree of token positions
\r
59 svn_diff__tree_create(svn_diff__tree_t **tree, apr_pool_t *pool)
\r
61 *tree = apr_pcalloc(pool, sizeof(**tree));
\r
62 (*tree)->pool = pool;
\r
66 static svn_error_t *
\r
67 svn_diff__tree_insert_token(svn_diff__node_t **node, svn_diff__tree_t *tree,
\r
69 const svn_diff_fns_t *vtable,
\r
70 apr_uint32_t hash, void *token)
\r
72 svn_diff__node_t *new_node;
\r
73 svn_diff__node_t **node_ref;
\r
74 svn_diff__node_t *parent;
\r
77 SVN_ERR_ASSERT(token);
\r
80 node_ref = &tree->root[hash % SVN_DIFF__HASH_SIZE];
\r
82 while (*node_ref != NULL)
\r
86 rv = hash - parent->hash;
\r
88 SVN_ERR(vtable->token_compare(diff_baton, parent->token, token, &rv));
\r
92 /* Discard the previous token. This helps in cases where
\r
93 * only recently read tokens are still in memory.
\r
95 if (vtable->token_discard != NULL)
\r
96 vtable->token_discard(diff_baton, parent->token);
\r
98 parent->token = token;
\r
101 return SVN_NO_ERROR;
\r
105 node_ref = &parent->left;
\r
109 node_ref = &parent->right;
\r
113 /* Create a new node */
\r
114 new_node = apr_palloc(tree->pool, sizeof(*new_node));
\r
115 new_node->parent = parent;
\r
116 new_node->left = NULL;
\r
117 new_node->right = NULL;
\r
118 new_node->hash = hash;
\r
119 new_node->token = token;
\r
121 *node = *node_ref = new_node;
\r
123 return SVN_NO_ERROR;
\r
128 * Get all tokens from a datasource. Return the
\r
129 * last item in the (circular) list.
\r
132 svn_diff__get_tokens(svn_diff__position_t **position_list,
\r
133 svn_diff__tree_t *tree,
\r
135 const svn_diff_fns_t *vtable,
\r
136 svn_diff_datasource_e datasource,
\r
139 svn_diff__position_t *start_position;
\r
140 svn_diff__position_t *position = NULL;
\r
141 svn_diff__position_t **position_ref;
\r
142 svn_diff__node_t *node;
\r
147 *position_list = NULL;
\r
150 SVN_ERR(vtable->datasource_open(diff_baton, datasource));
\r
152 position_ref = &start_position;
\r
154 hash = 0; /* The callback fn doesn't need to touch it per se */
\r
157 SVN_ERR(vtable->datasource_get_next_token(&hash, &token,
\r
158 diff_baton, datasource));
\r
163 SVN_ERR(svn_diff__tree_insert_token(&node, tree,
\r
164 diff_baton, vtable,
\r
167 /* Create a new position */
\r
168 position = apr_palloc(pool, sizeof(*position));
\r
169 position->next = NULL;
\r
170 position->node = node;
\r
171 position->offset = offset;
\r
173 *position_ref = position;
\r
174 position_ref = &position->next;
\r
177 *position_ref = start_position;
\r
179 SVN_ERR(vtable->datasource_close(diff_baton, datasource));
\r
181 *position_list = position;
\r
183 return SVN_NO_ERROR;
\r