Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:31:55

0001 // Copyright 2017 The Abseil Authors.
0002 //
0003 // Licensed under the Apache License, Version 2.0 (the "License");
0004 // you may not use this file except in compliance with the License.
0005 // You may obtain a copy of the License at
0006 //
0007 //      https://www.apache.org/licenses/LICENSE-2.0
0008 //
0009 // Unless required by applicable law or agreed to in writing, software
0010 // distributed under the License is distributed on an "AS IS" BASIS,
0011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0012 // See the License for the specific language governing permissions and
0013 // limitations under the License.
0014 //
0015 
0016 #ifndef ABSL_SYNCHRONIZATION_INTERNAL_GRAPHCYCLES_H_
0017 #define ABSL_SYNCHRONIZATION_INTERNAL_GRAPHCYCLES_H_
0018 
0019 // GraphCycles detects the introduction of a cycle into a directed
0020 // graph that is being built up incrementally.
0021 //
0022 // Nodes are identified by small integers.  It is not possible to
0023 // record multiple edges with the same (source, destination) pair;
0024 // requests to add an edge where one already exists are silently
0025 // ignored.
0026 //
0027 // It is also not possible to introduce a cycle; an attempt to insert
0028 // an edge that would introduce a cycle fails and returns false.
0029 //
0030 // GraphCycles uses no internal locking; calls into it should be
0031 // serialized externally.
0032 
0033 // Performance considerations:
0034 //   Works well on sparse graphs, poorly on dense graphs.
0035 //   Extra information is maintained incrementally to detect cycles quickly.
0036 //   InsertEdge() is very fast when the edge already exists, and reasonably fast
0037 //   otherwise.
0038 //   FindPath() is linear in the size of the graph.
0039 // The current implementation uses O(|V|+|E|) space.
0040 
0041 #include <cstdint>
0042 
0043 #include "absl/base/config.h"
0044 
0045 namespace absl {
0046 ABSL_NAMESPACE_BEGIN
0047 namespace synchronization_internal {
0048 
0049 // Opaque identifier for a graph node.
0050 struct GraphId {
0051   uint64_t handle;
0052 
0053   bool operator==(const GraphId& x) const { return handle == x.handle; }
0054   bool operator!=(const GraphId& x) const { return handle != x.handle; }
0055 };
0056 
0057 // Return an invalid graph id that will never be assigned by GraphCycles.
0058 inline GraphId InvalidGraphId() {
0059   return GraphId{0};
0060 }
0061 
0062 class GraphCycles {
0063  public:
0064   GraphCycles();
0065   ~GraphCycles();
0066 
0067   // Return the id to use for ptr, assigning one if necessary.
0068   // Subsequent calls with the same ptr value will return the same id
0069   // until Remove().
0070   GraphId GetId(void* ptr);
0071 
0072   // Remove "ptr" from the graph.  Its corresponding node and all
0073   // edges to and from it are removed.
0074   void RemoveNode(void* ptr);
0075 
0076   // Return the pointer associated with id, or nullptr if id is not
0077   // currently in the graph.
0078   void* Ptr(GraphId id);
0079 
0080   // Attempt to insert an edge from source_node to dest_node.  If the
0081   // edge would introduce a cycle, return false without making any
0082   // changes. Otherwise add the edge and return true.
0083   bool InsertEdge(GraphId source_node, GraphId dest_node);
0084 
0085   // Remove any edge that exists from source_node to dest_node.
0086   void RemoveEdge(GraphId source_node, GraphId dest_node);
0087 
0088   // Return whether node exists in the graph.
0089   bool HasNode(GraphId node);
0090 
0091   // Return whether there is an edge directly from source_node to dest_node.
0092   bool HasEdge(GraphId source_node, GraphId dest_node) const;
0093 
0094   // Return whether dest_node is reachable from source_node
0095   // by following edges.
0096   bool IsReachable(GraphId source_node, GraphId dest_node) const;
0097 
0098   // Find a path from "source" to "dest".  If such a path exists,
0099   // place the nodes on the path in the array path[], and return
0100   // the number of nodes on the path.  If the path is longer than
0101   // max_path_len nodes, only the first max_path_len nodes are placed
0102   // in path[].  The client should compare the return value with
0103   // max_path_len" to see when this occurs.  If no path exists, return
0104   // 0.  Any valid path stored in path[] will start with "source" and
0105   // end with "dest".  There is no guarantee that the path is the
0106   // shortest, but no node will appear twice in the path, except the
0107   // source and destination node if they are identical; therefore, the
0108   // return value is at most one greater than the number of nodes in
0109   // the graph.
0110   int FindPath(GraphId source, GraphId dest, int max_path_len,
0111                GraphId path[]) const;
0112 
0113   // Update the stack trace recorded for id with the current stack
0114   // trace if the last time it was updated had a smaller priority
0115   // than the priority passed on this call.
0116   //
0117   // *get_stack_trace is called to get the stack trace.
0118   void UpdateStackTrace(GraphId id, int priority,
0119                         int (*get_stack_trace)(void**, int));
0120 
0121   // Set *ptr to the beginning of the array that holds the recorded
0122   // stack trace for id and return the depth of the stack trace.
0123   int GetStackTrace(GraphId id, void*** ptr);
0124 
0125   // Check internal invariants. Crashes on failure, returns true on success.
0126   // Expensive: should only be called from graphcycles_test.cc.
0127   bool CheckInvariants() const;
0128 
0129   // Test-only method to add more nodes. The nodes will not be valid, and this
0130   // method should only be used to test the behavior of the graph when it is
0131   // very full.
0132   void TestOnlyAddNodes(uint32_t n);
0133 
0134   // ----------------------------------------------------
0135   struct Rep;
0136  private:
0137   Rep *rep_;      // opaque representation
0138   GraphCycles(const GraphCycles&) = delete;
0139   GraphCycles& operator=(const GraphCycles&) = delete;
0140 };
0141 
0142 }  // namespace synchronization_internal
0143 ABSL_NAMESPACE_END
0144 }  // namespace absl
0145 
0146 #endif