1251881Speter/* 2251881Speter * token.c : routines for doing diffs 3251881Speter * 4251881Speter * ==================================================================== 5251881Speter * Licensed to the Apache Software Foundation (ASF) under one 6251881Speter * or more contributor license agreements. See the NOTICE file 7251881Speter * distributed with this work for additional information 8251881Speter * regarding copyright ownership. The ASF licenses this file 9251881Speter * to you under the Apache License, Version 2.0 (the 10251881Speter * "License"); you may not use this file except in compliance 11251881Speter * with the License. You may obtain a copy of the License at 12251881Speter * 13251881Speter * http://www.apache.org/licenses/LICENSE-2.0 14251881Speter * 15251881Speter * Unless required by applicable law or agreed to in writing, 16251881Speter * software distributed under the License is distributed on an 17251881Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18251881Speter * KIND, either express or implied. See the License for the 19251881Speter * specific language governing permissions and limitations 20251881Speter * under the License. 21251881Speter * ==================================================================== 22251881Speter */ 23251881Speter 24251881Speter 25251881Speter#include <apr.h> 26251881Speter#include <apr_pools.h> 27251881Speter#include <apr_general.h> 28251881Speter 29251881Speter#include "svn_error.h" 30251881Speter#include "svn_diff.h" 31251881Speter#include "svn_types.h" 32251881Speter 33251881Speter#include "diff.h" 34251881Speter 35251881Speter 36251881Speter/* 37251881Speter * Prime number to use as the size of the hash table. This number was 38251881Speter * not selected by testing of any kind and may need tweaking. 39251881Speter */ 40251881Speter#define SVN_DIFF__HASH_SIZE 127 41251881Speter 42251881Speterstruct svn_diff__node_t 43251881Speter{ 44251881Speter svn_diff__node_t *parent; 45251881Speter svn_diff__node_t *left; 46251881Speter svn_diff__node_t *right; 47251881Speter 48251881Speter apr_uint32_t hash; 49251881Speter svn_diff__token_index_t index; 50251881Speter void *token; 51251881Speter}; 52251881Speter 53251881Speterstruct svn_diff__tree_t 54251881Speter{ 55251881Speter svn_diff__node_t *root[SVN_DIFF__HASH_SIZE]; 56251881Speter apr_pool_t *pool; 57251881Speter svn_diff__token_index_t node_count; 58251881Speter}; 59251881Speter 60251881Speter 61251881Speter/* 62251881Speter * Returns number of tokens in a tree 63251881Speter */ 64251881Spetersvn_diff__token_index_t 65251881Spetersvn_diff__get_node_count(svn_diff__tree_t *tree) 66251881Speter{ 67251881Speter return tree->node_count; 68251881Speter} 69251881Speter 70251881Speter/* 71251881Speter * Support functions to build a tree of token positions 72251881Speter */ 73251881Speter 74251881Spetervoid 75251881Spetersvn_diff__tree_create(svn_diff__tree_t **tree, apr_pool_t *pool) 76251881Speter{ 77251881Speter *tree = apr_pcalloc(pool, sizeof(**tree)); 78251881Speter (*tree)->pool = pool; 79251881Speter (*tree)->node_count = 0; 80251881Speter} 81251881Speter 82251881Speter 83251881Speterstatic svn_error_t * 84251881Spetertree_insert_token(svn_diff__node_t **node, svn_diff__tree_t *tree, 85251881Speter void *diff_baton, 86251881Speter const svn_diff_fns2_t *vtable, 87251881Speter apr_uint32_t hash, void *token) 88251881Speter{ 89251881Speter svn_diff__node_t *new_node; 90251881Speter svn_diff__node_t **node_ref; 91251881Speter svn_diff__node_t *parent; 92251881Speter int rv; 93251881Speter 94251881Speter SVN_ERR_ASSERT(token); 95251881Speter 96251881Speter parent = NULL; 97251881Speter node_ref = &tree->root[hash % SVN_DIFF__HASH_SIZE]; 98251881Speter 99251881Speter while (*node_ref != NULL) 100251881Speter { 101251881Speter parent = *node_ref; 102251881Speter 103251881Speter rv = hash - parent->hash; 104251881Speter if (!rv) 105251881Speter SVN_ERR(vtable->token_compare(diff_baton, parent->token, token, &rv)); 106251881Speter 107251881Speter if (rv == 0) 108251881Speter { 109251881Speter /* Discard the previous token. This helps in cases where 110251881Speter * only recently read tokens are still in memory. 111251881Speter */ 112251881Speter if (vtable->token_discard != NULL) 113251881Speter vtable->token_discard(diff_baton, parent->token); 114251881Speter 115251881Speter parent->token = token; 116251881Speter *node = parent; 117251881Speter 118251881Speter return SVN_NO_ERROR; 119251881Speter } 120251881Speter else if (rv > 0) 121251881Speter { 122251881Speter node_ref = &parent->left; 123251881Speter } 124251881Speter else 125251881Speter { 126251881Speter node_ref = &parent->right; 127251881Speter } 128251881Speter } 129251881Speter 130251881Speter /* Create a new node */ 131251881Speter new_node = apr_palloc(tree->pool, sizeof(*new_node)); 132251881Speter new_node->parent = parent; 133251881Speter new_node->left = NULL; 134251881Speter new_node->right = NULL; 135251881Speter new_node->hash = hash; 136251881Speter new_node->token = token; 137251881Speter new_node->index = tree->node_count++; 138251881Speter 139251881Speter *node = *node_ref = new_node; 140251881Speter 141251881Speter return SVN_NO_ERROR; 142251881Speter} 143251881Speter 144251881Speter 145251881Speter/* 146251881Speter * Get all tokens from a datasource. Return the 147251881Speter * last item in the (circular) list. 148251881Speter */ 149251881Spetersvn_error_t * 150251881Spetersvn_diff__get_tokens(svn_diff__position_t **position_list, 151251881Speter svn_diff__tree_t *tree, 152251881Speter void *diff_baton, 153251881Speter const svn_diff_fns2_t *vtable, 154251881Speter svn_diff_datasource_e datasource, 155251881Speter apr_off_t prefix_lines, 156251881Speter apr_pool_t *pool) 157251881Speter{ 158251881Speter svn_diff__position_t *start_position; 159251881Speter svn_diff__position_t *position = NULL; 160251881Speter svn_diff__position_t **position_ref; 161251881Speter svn_diff__node_t *node; 162251881Speter void *token; 163251881Speter apr_off_t offset; 164251881Speter apr_uint32_t hash; 165251881Speter 166251881Speter *position_list = NULL; 167251881Speter 168251881Speter position_ref = &start_position; 169251881Speter offset = prefix_lines; 170251881Speter hash = 0; /* The callback fn doesn't need to touch it per se */ 171251881Speter while (1) 172251881Speter { 173251881Speter SVN_ERR(vtable->datasource_get_next_token(&hash, &token, 174251881Speter diff_baton, datasource)); 175251881Speter if (token == NULL) 176251881Speter break; 177251881Speter 178251881Speter offset++; 179251881Speter SVN_ERR(tree_insert_token(&node, tree, diff_baton, vtable, hash, token)); 180251881Speter 181251881Speter /* Create a new position */ 182251881Speter position = apr_palloc(pool, sizeof(*position)); 183251881Speter position->next = NULL; 184251881Speter position->token_index = node->index; 185251881Speter position->offset = offset; 186251881Speter 187251881Speter *position_ref = position; 188251881Speter position_ref = &position->next; 189251881Speter } 190251881Speter 191251881Speter *position_ref = start_position; 192251881Speter 193251881Speter SVN_ERR(vtable->datasource_close(diff_baton, datasource)); 194251881Speter 195251881Speter *position_list = position; 196251881Speter 197251881Speter return SVN_NO_ERROR; 198251881Speter} 199