/** * @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 #include #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); void 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 */