tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

graphcycles.h (5472B)


      1 // Copyright 2017 The Abseil Authors.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //      https://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 //
     15 
     16 #ifndef ABSL_SYNCHRONIZATION_INTERNAL_GRAPHCYCLES_H_
     17 #define ABSL_SYNCHRONIZATION_INTERNAL_GRAPHCYCLES_H_
     18 
     19 // GraphCycles detects the introduction of a cycle into a directed
     20 // graph that is being built up incrementally.
     21 //
     22 // Nodes are identified by small integers.  It is not possible to
     23 // record multiple edges with the same (source, destination) pair;
     24 // requests to add an edge where one already exists are silently
     25 // ignored.
     26 //
     27 // It is also not possible to introduce a cycle; an attempt to insert
     28 // an edge that would introduce a cycle fails and returns false.
     29 //
     30 // GraphCycles uses no internal locking; calls into it should be
     31 // serialized externally.
     32 
     33 // Performance considerations:
     34 //   Works well on sparse graphs, poorly on dense graphs.
     35 //   Extra information is maintained incrementally to detect cycles quickly.
     36 //   InsertEdge() is very fast when the edge already exists, and reasonably fast
     37 //   otherwise.
     38 //   FindPath() is linear in the size of the graph.
     39 // The current implementation uses O(|V|+|E|) space.
     40 
     41 #include <cstdint>
     42 
     43 #include "absl/base/config.h"
     44 
     45 namespace absl {
     46 ABSL_NAMESPACE_BEGIN
     47 namespace synchronization_internal {
     48 
     49 // Opaque identifier for a graph node.
     50 struct GraphId {
     51  uint64_t handle;
     52 
     53  bool operator==(const GraphId& x) const { return handle == x.handle; }
     54  bool operator!=(const GraphId& x) const { return handle != x.handle; }
     55 };
     56 
     57 // Return an invalid graph id that will never be assigned by GraphCycles.
     58 inline GraphId InvalidGraphId() {
     59  return GraphId{0};
     60 }
     61 
     62 class GraphCycles {
     63 public:
     64  GraphCycles();
     65  ~GraphCycles();
     66 
     67  // Return the id to use for ptr, assigning one if necessary.
     68  // Subsequent calls with the same ptr value will return the same id
     69  // until Remove().
     70  GraphId GetId(void* ptr);
     71 
     72  // Remove "ptr" from the graph.  Its corresponding node and all
     73  // edges to and from it are removed.
     74  void RemoveNode(void* ptr);
     75 
     76  // Return the pointer associated with id, or nullptr if id is not
     77  // currently in the graph.
     78  void* Ptr(GraphId id);
     79 
     80  // Attempt to insert an edge from source_node to dest_node.  If the
     81  // edge would introduce a cycle, return false without making any
     82  // changes. Otherwise add the edge and return true.
     83  bool InsertEdge(GraphId source_node, GraphId dest_node);
     84 
     85  // Remove any edge that exists from source_node to dest_node.
     86  void RemoveEdge(GraphId source_node, GraphId dest_node);
     87 
     88  // Return whether node exists in the graph.
     89  bool HasNode(GraphId node);
     90 
     91  // Return whether there is an edge directly from source_node to dest_node.
     92  bool HasEdge(GraphId source_node, GraphId dest_node) const;
     93 
     94  // Return whether dest_node is reachable from source_node
     95  // by following edges.
     96  bool IsReachable(GraphId source_node, GraphId dest_node) const;
     97 
     98  // Find a path from "source" to "dest".  If such a path exists,
     99  // place the nodes on the path in the array path[], and return
    100  // the number of nodes on the path.  If the path is longer than
    101  // max_path_len nodes, only the first max_path_len nodes are placed
    102  // in path[].  The client should compare the return value with
    103  // max_path_len" to see when this occurs.  If no path exists, return
    104  // 0.  Any valid path stored in path[] will start with "source" and
    105  // end with "dest".  There is no guarantee that the path is the
    106  // shortest, but no node will appear twice in the path, except the
    107  // source and destination node if they are identical; therefore, the
    108  // return value is at most one greater than the number of nodes in
    109  // the graph.
    110  int FindPath(GraphId source, GraphId dest, int max_path_len,
    111               GraphId path[]) const;
    112 
    113  // Update the stack trace recorded for id with the current stack
    114  // trace if the last time it was updated had a smaller priority
    115  // than the priority passed on this call.
    116  //
    117  // *get_stack_trace is called to get the stack trace.
    118  void UpdateStackTrace(GraphId id, int priority,
    119                        int (*get_stack_trace)(void**, int));
    120 
    121  // Set *ptr to the beginning of the array that holds the recorded
    122  // stack trace for id and return the depth of the stack trace.
    123  int GetStackTrace(GraphId id, void*** ptr);
    124 
    125  // Check internal invariants. Crashes on failure, returns true on success.
    126  // Expensive: should only be called from graphcycles_test.cc.
    127  bool CheckInvariants() const;
    128 
    129  // Test-only method to add more nodes. The nodes will not be valid, and this
    130  // method should only be used to test the behavior of the graph when it is
    131  // very full.
    132  void TestOnlyAddNodes(uint32_t n);
    133 
    134  // ----------------------------------------------------
    135  struct Rep;
    136 private:
    137  Rep *rep_;      // opaque representation
    138  GraphCycles(const GraphCycles&) = delete;
    139  GraphCycles& operator=(const GraphCycles&) = delete;
    140 };
    141 
    142 }  // namespace synchronization_internal
    143 ABSL_NAMESPACE_END
    144 }  // namespace absl
    145 
    146 #endif