blob: c467175c748eb7dd031d10349c67ddbe53f1f80d [file] [log] [blame]
/**
* @copyright
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
* @endcopyright
*
* @file svn_element.h
* @brief Tree elements
*
* @since New in ???.
*/
#ifndef SVN_BRANCH_ELEMENT_H
#define SVN_BRANCH_ELEMENT_H
#include <apr_pools.h>
#include <apr_tables.h>
#include "svn_types.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* ====================================================================== */
/** Like apr_hash_get() but the hash key is an integer. */
void *
svn_eid__hash_get(apr_hash_t *ht,
int key);
/** Like apr_hash_set() but the hash key is an integer. */
void
svn_eid__hash_set(apr_hash_t *ht,
int key,
const void *val);
/** Like apr_hash_this_key() but the hash key is an integer. */
int
svn_eid__hash_this_key(apr_hash_index_t *hi);
struct svn_sort__item_t;
/** A hash iterator for iterating over an array or a hash table in
* its natural order or in sorted order.
*
* For an array, the @a i and @a val members provide the index and value
* of the current item.
*/
typedef struct svn_eid__hash_iter_t
{
/* private: an array of (svn_sort__item_t) hash items for sorted iteration */
const apr_array_header_t *array;
/* current element: iteration order index */
int i;
/* current element: key */
int eid;
/* current element: value */
void *val;
} svn_eid__hash_iter_t;
svn_eid__hash_iter_t *
svn_eid__hash_sorted_first(apr_pool_t *pool,
apr_hash_t *ht,
int (*comparison_func)(const struct svn_sort__item_t *,
const struct svn_sort__item_t *));
svn_eid__hash_iter_t *
svn_eid__hash_sorted_next(svn_eid__hash_iter_t *hi);
/** A sort ordering callback function that returns an indication whether
* A sorts before or after or equal to B, by comparing their keys as EIDs.
*/
int
svn_eid__hash_sort_compare_items_by_eid(const struct svn_sort__item_t *a,
const struct svn_sort__item_t *b);
#define SVN_EID__HASH_ITER_SORTED(i, ht, comparison_func, pool) \
i = (void *)svn_eid__hash_sorted_first(pool, ht, comparison_func); \
i; \
i = (void *)svn_eid__hash_sorted_next((void *)i)
#define SVN_EID__HASH_ITER_SORTED_BY_EID(i, ht, pool) \
SVN_EID__HASH_ITER_SORTED(i, ht, svn_eid__hash_sort_compare_items_by_eid, pool)
/* ====================================================================== */
/**
*/
typedef struct svn_element__branch_ref_t
{
svn_revnum_t rev;
const char *branch_id;
int eid;
} svn_element__branch_ref_t;
/** Versioned payload of an element, excluding tree structure information.
*
* This specifies the properties and the text of a file or target of a
* symlink, directly, or by reference to an existing committed element, or
* by a delta against such a reference payload.
*
* ### An idea: If the sender and receiver agree, the payload for an element
* may be specified as "null" to designate that the payload is not
* available. For example, when a client performing a WC update has
* no read authorization for a given path, the server may send null
* payload and the client may record an 'absent' WC node. (This
* would not make sense in a commit.)
*/
typedef struct svn_element__payload_t svn_element__payload_t;
/*
* ========================================================================
* Element Payload Interface
* ========================================================================
*
* @defgroup svn_element_payload Element payload interface
* @{
*/
/** Versioned payload of a node, excluding tree structure information.
*
* Payload is described by setting fields in one of the following ways.
* Other fields SHOULD be null (or equivalent).
*
* by reference: (kind=unknown, ref)
* dir: (kind=dir, props)
* file: (kind=file, props, text)
* symlink: (kind=symlink, props, target)
*
* ### Idea for the future: Specify payload as an (optional) reference
* plus (optional) overrides or deltas against the reference?
*/
struct svn_element__payload_t
{
/* Is this a subbranch-root element, in other words a link to a nested
* branch? If so, all other fields are irrelevant. */
svn_boolean_t is_subbranch_root;
/* The node kind for this payload: dir, file, symlink, or unknown. */
svn_node_kind_t kind;
/* Reference an existing, committed payload. (Use with kind=unknown if
* there is no content in props/text/targe fields.)
* The 'null' value is (SVN_INVALID_REVNUM, NULL, *). */
svn_element__branch_ref_t branch_ref;
/* The pool in which the payload's content is allocated. Used when
* resolving (populating the props/text/target in) a payload that was
* originally defined by reference. */
apr_pool_t *pool;
/* Properties (for kind != unknown).
* Maps (const char *) name -> (svn_string_t) value.
* An empty hash means no properties. (SHOULD NOT be NULL.)
* ### Presently NULL means 'no change' in some contexts. */
apr_hash_t *props;
/* File text (for kind=file; otherwise SHOULD be NULL). */
svn_stringbuf_t *text;
/* Symlink target (for kind=symlink; otherwise SHOULD be NULL). */
const char *target;
};
/* Return true iff PAYLOAD satisfies all its invariants.
*/
svn_boolean_t
svn_element__payload_invariants(const svn_element__payload_t *payload);
/** Duplicate a node-payload @a old into @a result_pool.
*/
svn_element__payload_t *
svn_element__payload_dup(const svn_element__payload_t *old,
apr_pool_t *result_pool);
/* Return true iff the payload of LEFT is identical to that of RIGHT.
* References are not supported. Node kind 'unknown' is not supported.
*/
svn_boolean_t
svn_element__payload_equal(const svn_element__payload_t *left,
const svn_element__payload_t *right,
apr_pool_t *scratch_pool);
/** Create a new node-payload object for a subbranch-root (link to a
* nested branch).
*
* Allocate the result in @a result_pool.
*/
svn_element__payload_t *
svn_element__payload_create_subbranch(apr_pool_t *result_pool);
/** Create a new node-payload object by reference to an existing payload.
*
* Set the node kind to 'unknown'.
*
* Allocate the result in @a result_pool.
*/
svn_element__payload_t *
svn_element__payload_create_ref(svn_revnum_t rev,
const char *branch_id,
int eid,
apr_pool_t *result_pool);
/** Create a new node-payload object for a directory node.
*
* Allocate the result in @a result_pool.
*/
svn_element__payload_t *
svn_element__payload_create_dir(apr_hash_t *props,
apr_pool_t *result_pool);
/** Create a new node-payload object for a file node.
*
* Allocate the result in @a result_pool.
*/
svn_element__payload_t *
svn_element__payload_create_file(apr_hash_t *props,
svn_stringbuf_t *text,
apr_pool_t *result_pool);
/** Create a new node-payload object for a symlink node.
*
* Allocate the result in @a result_pool.
*/
svn_element__payload_t *
svn_element__payload_create_symlink(apr_hash_t *props,
const char *target,
apr_pool_t *result_pool);
/** @} */
/*
* ========================================================================
* Element-Revision Content
* ========================================================================
*
* @defgroup svn_el_rev_content Element-Revision Content
* @{
*/
/* The content (parent, name and payload) of an element-revision.
* In other words, an el-rev node in a (mixed-rev) directory-tree.
*/
typedef struct svn_element__content_t
{
/* eid of the parent element, or -1 if this is the root element */
int parent_eid;
/* element name, or "" for root element; never null */
const char *name;
/* payload (kind, props, text, ...) */
svn_element__payload_t *payload;
} svn_element__content_t;
/* Return a new content object constructed with deep copies of PARENT_EID,
* NAME and PAYLOAD, allocated in RESULT_POOL.
*/
svn_element__content_t *
svn_element__content_create(int parent_eid,
const char *name,
const svn_element__payload_t *payload,
apr_pool_t *result_pool);
/* Return a deep copy of OLD, allocated in RESULT_POOL.
*/
svn_element__content_t *
svn_element__content_dup(const svn_element__content_t *old,
apr_pool_t *result_pool);
/* Return TRUE iff CONTENT_LEFT is the same as CONTENT_RIGHT. */
svn_boolean_t
svn_element__content_equal(const svn_element__content_t *content_left,
const svn_element__content_t *content_right,
apr_pool_t *scratch_pool);
/** @} */
/*
* ========================================================================
* Element Tree
* ========================================================================
*
* The elements in an Element Tree do not necessarily form a single,
* complete tree at all times.
*
* @defgroup svn_element_tree Element Tree
* @{
*/
/* A (sub)tree of elements.
*
* An element tree is described by the content of element ROOT_EID in E_MAP,
* and its children (as determined by their parent links) and their names
* and their content recursively. For the element ROOT_EID itself, only
* its content is relevant; its parent and name are to be ignored.
*
* E_MAP may also contain entries that are not part of the subtree. Thus,
* to select a sub-subtree, it is only necessary to change ROOT_EID.
*
* The EIDs used in here may be considered either as global EIDs (known to
* the repo), or as local stand-alone EIDs (in their own local name-space),
* according to the context.
*/
typedef struct svn_element__tree_t
{
/* EID -> svn_element__content_t mapping. */
apr_hash_t *e_map;
/* Subtree root EID. (ROOT_EID must be an existing key in E_MAP.) */
int root_eid;
} svn_element__tree_t;
/* Create an element tree object.
*
* The result contains a *shallow* copy of E_MAP, or a new empty mapping
* if E_MAP is null.
*/
svn_element__tree_t *
svn_element__tree_create(apr_hash_t *e_map,
int root_eid,
apr_pool_t *result_pool);
svn_element__content_t *
svn_element__tree_get(const svn_element__tree_t *tree,
int eid);
svn_error_t *
svn_element__tree_set(svn_element__tree_t *tree,
int eid,
const svn_element__content_t *element);
/* Purge entries from E_MAP that don't connect, via parent directory hierarchy,
* to ROOT_EID. In other words, remove elements that have been implicitly
* deleted.
*
* ROOT_EID must be present in E_MAP.
*
* ### Does not detect cycles: current implementation will not purge a cycle
* that is disconnected from ROOT_EID. This could be a problem.
*/
void
svn_element__tree_purge_orphans(apr_hash_t *e_map,
int root_eid,
apr_pool_t *scratch_pool);
/* Return the subtree-relative path of element EID in TREE.
*
* If the element EID does not currently exist in TREE, return NULL.
*
* ### TODO: Clarify sequencing requirements.
*/
const char *
svn_element__tree_get_path_by_eid(const svn_element__tree_t *tree,
int eid,
apr_pool_t *result_pool);
/* Return the subtree rooted at EID within ELEMENT_TREE.
*
* The result is limited by the lifetime of ELEMENT_TREE. It includes a
* shallow copy of the mapping in ELEMENT_TREE: the hash table is
* duplicated but the keys and values (element content data) are not.
*/
svn_element__tree_t *
svn_element__tree_get_subtree_at_eid(svn_element__tree_t *element_tree,
int eid,
apr_pool_t *result_pool);
/** @} */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SVN_BRANCH_ELEMENT_H */