⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 compose_delta.c

📁 subversion-1.4.3-1.tar.gz 配置svn的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * compose_delta.c:  Delta window composition. * * ==================================================================== * Copyright (c) 2000-2004 CollabNet.  All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution.  The terms * are also available at http://subversion.tigris.org/license-1.html. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * * This software consists of voluntary contributions made by many * individuals.  For exact contribution history, see the revision * history and logs, available at http://subversion.tigris.org/. * ==================================================================== */#include <assert.h>#include <apr_general.h>        /* For APR_INLINE */#include "svn_delta.h"#include "svn_pools.h"#include "delta.h"/* Define a MIN macro if this platform doesn't already have one. */#ifndef MIN#define MIN(a, b) ((a) < (b) ? (a) : (b))#endif/* ==================================================================== *//* Support for efficient small-block allocation from pools. *//* The following structs will be allocated and freed often: *//* A node in the range index tree. */typedef struct range_index_node_t range_index_node_t;struct range_index_node_t{  /* 'offset' and 'limit' define the range in the source window. */  apr_size_t offset;  apr_size_t limit;  /* 'target_offset' is where that range is represented in the target. */  apr_size_t target_offset;  /* 'left' and 'right' link the node into a splay tree. */  range_index_node_t *left, *right;  /* 'prev' and 'next' link it into an ordered, doubly-linked list. */  range_index_node_t *prev, *next;};/* A node in a list of ranges for source and target op copies. */enum range_kind  {    range_from_source,    range_from_target  };typedef struct range_list_node_t range_list_node_t;struct range_list_node_t{  /* Where does the range come from?     'offset' and 'limit' always refer to the "virtual" source data     for the second delta window. For a target range, the actual     offset to use for generating the target op is 'target_offset';     that field isn't used by source ranges. */  enum range_kind kind;  /* 'offset' and 'limit' define the range. */  apr_size_t offset;  apr_size_t limit;  /* 'target_offset' is the start of the range in the target. */  apr_size_t target_offset;  /* 'prev' and 'next' link the node into an ordered, doubly-linked list. */  range_list_node_t *prev, *next;};/* This is what will be allocated: */typedef union alloc_block_t alloc_block_t;union alloc_block_t{  range_index_node_t index_node;  range_list_node_t list_node;  /* Links free blocks into a freelist. */  alloc_block_t *next_free;};/* Allocate a block. */static APR_INLINE void *alloc_block(apr_pool_t *pool, alloc_block_t **free_list){  alloc_block_t *block;  if (*free_list == NULL)    block = apr_palloc(pool, sizeof(*block));  else    {      block = *free_list;      *free_list = block->next_free;    }  return block;}/* Return the block back to the free list. */static APR_INLINE voidfree_block(void *ptr, alloc_block_t **free_list){  /* Wrapper functions take care of type safety. */  alloc_block_t *const block = ptr;  block->next_free = *free_list;  *free_list = block;}/* ==================================================================== *//* Mapping offsets in the target streem to txdelta ops. */typedef struct offset_index_t{  int length;  apr_size_t *offs;} offset_index_t;/* Create an index mapping target stream offsets to delta ops in   WINDOW. Allocate from POOL. */static offset_index_t *create_offset_index(const svn_txdelta_window_t *window, apr_pool_t *pool){  offset_index_t *ndx = apr_palloc(pool, sizeof(*ndx));  apr_size_t offset = 0;  int i;  ndx->length = window->num_ops;  ndx->offs = apr_palloc(pool, (ndx->length + 1) * sizeof(*ndx->offs));  for (i = 0; i < ndx->length; ++i)    {      ndx->offs[i] = offset;      offset += window->ops[i].length;    }  ndx->offs[ndx->length] = offset;  return ndx;}/* Find the index of the delta op thet defines that data at OFFSET in   NDX. */static intsearch_offset_index(const offset_index_t *ndx, apr_size_t offset){  int lo, hi, op;  assert(offset < ndx->offs[ndx->length]);  for (lo = 0, hi = ndx->length, op = (lo + hi)/2;       lo < hi;       op = (lo + hi)/2)    {      const apr_size_t this_offset = ndx->offs[op];      const apr_size_t next_offset = ndx->offs[op + 1];      if (offset < this_offset)        hi = op;      else if (offset > next_offset)        lo = op;      else        {          /* this_offset <= offset <= next_offset */          if (offset == next_offset)            ++op;          break;        }    }  assert(ndx->offs[op] <= offset && offset < ndx->offs[op + 1]);  return op;}/* ==================================================================== *//* Mapping ranges in the source stream to ranges in the composed delta. *//* The range index tree. */typedef struct range_index_t{  range_index_node_t *tree;  alloc_block_t *free_list;  apr_pool_t *pool;} range_index_t;/* Create a range index tree. Allocate from POOL. */static range_index_t *create_range_index(apr_pool_t *pool){  range_index_t *ndx = apr_palloc(pool, sizeof(*ndx));  ndx->tree = NULL;  ndx->pool = pool;  ndx->free_list = NULL;  return ndx;}/* Allocate a node for the range index tree. */static range_index_node_t *alloc_range_index_node(range_index_t *ndx,                       apr_size_t offset,                       apr_size_t limit,                       apr_size_t target_offset){  range_index_node_t *const node = alloc_block(ndx->pool, &ndx->free_list);  node->offset = offset;  node->limit = limit;  node->target_offset = target_offset;  node->left = node->right = NULL;  node->prev = node->next = NULL;  return node;}/* Free a node from the range index tree. */static voidfree_range_index_node(range_index_t *ndx, range_index_node_t *node){  if (node->next)    node->next->prev = node->prev;  if (node->prev)    node->prev->next = node->next;  free_block(node, &ndx->free_list);}/* Splay the index tree, using OFFSET as the key. */static voidsplay_range_index(apr_size_t offset, range_index_t *ndx){  range_index_node_t *tree = ndx->tree;  range_index_node_t scratch_node;  range_index_node_t *left, *right;  if (tree == NULL)    return;  scratch_node.left = scratch_node.right = NULL;  left = right = &scratch_node;  for (;;)    {      if (offset < tree->offset)        {          if (tree->left != NULL              && offset < tree->left->offset)            {              /* Right rotation */              range_index_node_t *const node = tree->left;              tree->left = node->right;              node->right = tree;              tree = node;            }          if (tree->left == NULL)            break;          /* Remember the right subtree */          right->left = tree;          right = tree;          tree = tree->left;        }      else if (offset > tree->offset)        {          if (tree->right != NULL              && offset > tree->right->offset)            {              /* Left rotation */              range_index_node_t *const node = tree->right;              tree->right = node->left;              node->left = tree;              tree = node;            }          if (tree->right == NULL)            break;          /* Remember the left subtree */          left->right = tree;          left = tree;          tree = tree->right;        }      else        break;    }  /* Link in the left and right subtrees */  left->right = tree->left;  right->left = tree->right;  tree->left  = scratch_node.right;  tree->right = scratch_node.left;  /* The basic top-down splay is finished, but we may still need to     turn the tree around. What we want is to put the node with the     largest offset where node->offset <= offset at the top of the     tree, so that we can insert the new data (or search for existing     ranges) to the right of the root. This makes cleaning up the     tree after an insert much simpler, and -- incidentally -- makes     the whole range index magic work. */  if (offset < tree->offset && tree->left != NULL)    {      if (tree->left->right == NULL)        {          /* A single right rotation is enough. */          range_index_node_t *const node = tree->left;          tree->left = node->right; /* Which is always NULL. */          node->right = tree;          tree = node;        }      else        {          /* Slide down to the rightmost node in the left subtree. */          range_index_node_t **nodep = &tree->left;          while ((*nodep)->right != NULL)            nodep = &(*nodep)->right;          /* Now move this node to root in one giant promotion. */          right = tree;          left = tree->left;          tree = *nodep;          *nodep = tree->left;          right->left = tree->right; /* Which is always NULL, too. */          tree->left = left;          tree->right = right;        }    }  /* Sanity check ... */  assert((offset >= tree->offset)         || ((tree->left == NULL)             && (tree->prev == NULL)));  ndx->tree = tree;}/* Remove all ranges from NDX that fall into the root's range.  To   keep the range index as small as possible, we must also remove   nodes that don't fall into the new range, but have become redundant   because the new range overlaps the beginning of the next range.   Like this:       new-range: |-----------------|         range-1:         |-----------------|         range-2:                |--------------------|   Before new-range was inserted, range-1 and range-2 were both   necessary. Now the union of new-range and range-2 completely covers   range-1, which has become redundant now.   FIXME: But, of course, there's a catch. range-1 must still remain   in the tree if we want to optimize the number of target copy ops in   the case were a copy falls within range-1, but starts before   range-2 and ends after new-range. */static voiddelete_subtree(range_index_t *ndx, range_index_node_t *node){  if (node != NULL)    {      delete_subtree(ndx, node->left);      delete_subtree(ndx, node->right);      free_range_index_node(ndx, node);    }}static voidclean_tree(range_index_t *ndx, apr_size_t limit){  apr_size_t top_offset = limit + 1;  range_index_node_t **nodep = &ndx->tree->right;  while (*nodep != NULL)    {      range_index_node_t *const node = *nodep;      apr_size_t const offset =        (node->right != NULL && node->right->offset < top_offset         ? node->right->offset         : top_offset);      if (node->limit <= limit          || (node->offset < limit && offset < limit))        {          *nodep = node->right;          node->right = NULL;          delete_subtree(ndx, node);        }      else        {          top_offset = node->offset;          nodep = &node->left;        }    }}/* Add a range [OFFSET, LIMIT) into NDX. If NDX already contains a   range that encloses [OFFSET, LIMIT), do nothing. Otherwise, remove   all ranges from NDX that are superseded by the new range.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -