Skip to content

RR Graph Overlay Creation and Deploy new node_type() API of Overlay #1693

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
6a2eb50
[VPR] Add an overlay RRGraph object; Different from t_rr_graph_view, …
tangxifan Mar 24, 2021
cb55acc
[VPR] Update rr_graph overlay to enable its deployment in DeviceContext
tangxifan Mar 24, 2021
584f7fc
[VPR] Replace node type() API with overlay API in check_rr_graph.cpp
tangxifan Mar 24, 2021
b86c734
Merge branch 'master' of https://github.com/verilog-to-routing/vtr-ve…
tangxifan Mar 24, 2021
e927bb5
[VPR] add overlay initialization for rr_graph loading from external f…
tangxifan Mar 24, 2021
b25adaa
[VPR] Code format fix
tangxifan Mar 24, 2021
59b766c
[VPR] Code format fix
tangxifan Mar 24, 2021
0d697c0
[VPR] Add rr graph overlay to rr_graph reader and writer
tangxifan Mar 24, 2021
ea1c017
[VPR] Add a prototype of RRGraphView (read-only) and its builder exte…
tangxifan Mar 26, 2021
4c82389
[VPR] Bug fix in RRGraphView API and deploy to placer delay matrix co…
tangxifan Mar 26, 2021
dcdb036
[VPR] Code format fix
tangxifan Mar 26, 2021
387eba7
[VPR] Deploy mutator to rr_node_indice builder as an example
tangxifan Mar 26, 2021
6e1427b
Merge branch 'master' into rr_graph_node_type_overlay
tangxifan Apr 1, 2021
409e527
Merge branch 'master' into rr_graph_node_type_overlay
tangxifan Apr 7, 2021
32225c8
[VPR] Reworked rr_graph_view and rr_graph_builder; Created rr_spatial…
tangxifan Apr 7, 2021
6ae1016
[VPR] code format fix; add comments to API
tangxifan Apr 8, 2021
161d66d
Merge branch 'master' into rr_graph_node_type_overlay
tangxifan Apr 8, 2021
7c0169c
[VPR] Add comments to explain why references are currently used in RR…
tangxifan Apr 9, 2021
a758762
Merge branch 'rr_graph_node_type_overlay' of https://github.com/tangx…
tangxifan Apr 9, 2021
0ef68b2
Merge branch 'master' into rr_graph_node_type_overlay
tangxifan Apr 13, 2021
abb5041
Merge branch 'master' into rr_graph_node_type_overlay
tangxifan Apr 14, 2021
77f632e
[VPR] Add protection to RRGraphBuilder, RRGraphView and RRSpatial to …
tangxifan Apr 15, 2021
0410c26
[VPR] Code format fix
tangxifan Apr 15, 2021
baad504
[VPR] Compiler warning fix
tangxifan Apr 15, 2021
3b5aab5
[VPR] Add RRGraphBuilder to DeviceContext; Identify a critical limita…
tangxifan Apr 15, 2021
706a965
[VPR] Reworked comments to emphasize on confusing codes while delete …
tangxifan Apr 15, 2021
0297ce9
[VPR] Reworked the comment about avoid copy contructors for RRGraphBu…
tangxifan Apr 16, 2021
4916c1b
Merge branch 'master' into rr_graph_node_type_overlay
tangxifan Apr 19, 2021
4a8443b
Merge branch 'master' into rr_graph_node_type_overlay
tangxifan May 20, 2021
2fdabbd
Merge branch 'rr_graph_node_type_overlay' of https://github.com/tangx…
tangxifan May 21, 2021
e137b6d
[VPR] Update comments to avoid confusion and clarify
tangxifan May 21, 2021
49e3339
[VPR] Patch comments and remove the inproper assert (which should be …
tangxifan May 21, 2021
76b6f00
Merge branch 'master' into rr_graph_node_type_overlay
vaughnbetz May 25, 2021
82da2e0
Merge branch 'master' into rr_graph_node_type_overlay
vaughnbetz May 25, 2021
ffb4bca
Merge branch 'master' into rr_graph_node_type_overlay
vaughnbetz May 26, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions vpr/src/base/vpr_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "vtr_vector.h"
#include "atom_netlist.h"
#include "clustered_netlist.h"
#include "rr_graph_view.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest to always sort all headers alphabetically.

That way it is harder possible to create merge conflicts if everyone does the same.
(I realize that this is not how the practice was in this file, but I suggest to adopt that practice. It also sometimes helps finding hidden dependencies in which header files only work when included in a particular sequence)

So in emacs that would be: mark the block with all includes then M-x sort-lines; other editors have a similar feature.

In general it is adivsable to follow the practices like in this style guide: grouping blocks of c-headers, c++ headers and project headers.

(Might be worth-while to have a separate cleanup-run of this, not necessarily in this pull request. So consider this an FYI with future influence)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes sense to me. I will avoid modifying the vpr_context.h because it is not the focus of this PR. But I will force the alphabetical order of header files in newly created files in this PR.

#include "rr_graph_storage.h"
#include "rr_node.h"
#include "rr_rc_data.h"
Expand Down Expand Up @@ -145,6 +146,7 @@ struct DeviceContext : public Context {
/*
* Structures to define the routing architecture of the FPGA.
*/
RRGraphView rr_graph; // A read-only view of routing resource graph to be the ONLY database for client functions: GUI, placer, router, timing analyzer etc.

t_rr_graph_storage rr_nodes; // autogenerated in build_rr_graph

Expand Down
47 changes: 47 additions & 0 deletions vpr/src/device/rr_graph_builder_view.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/***************************************
* Methods for Object RRGraphBuilderView
***************************************/
#include "vtr_assert.h"
#include "rr_graph_builder_view.h"

/****************************
* Constructors
****************************/
RRGraphBuilderView::RRGraphBuilderView(t_rr_graph_storage* node_storage,
t_rr_node_indices* rr_node_indices) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Always use constructor initializer list for simple assigning of things wherelver possible. The constructor body should only really be used if we have some work that needs to be done (which, incidently, we want to avoid as much as possible in constructors, because we don't have a way to fail in a constructor - except exceptions of course, which we of course want to avoid).

So

RRGraphBuilderView::RRGraphBuilderView(t_rr_graph_storage* node_storage,
                                       t_rr_node_indices* rr_node_indices) 
    : node_storage(node_storage), rr_node_indices_(rr_node_indices) {
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, and I see, in this case you're actually initializing values from a base class. Never do that, only access the base class through its constructor.

So the base-class should have RRGraphView::RRGraphView(... these nodes ...) : node_storage(...), rr_node_indeices(...) {}.

And then here, you initialize it with

RRGraphBuilderView::RRGraphBuilderView(t_rr_graph_storage* node_storage,
                                       t_rr_node_indices* rr_node_indices) 
    : RRGraphView(node_storage, rr_node_indices) {
}

... but see also other comments about inheritance. This is probably not what you want anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the comment. I was looking for something like this and failed to find related tutorials. I have updated the codes.

node_storage_ = node_storage;
rr_node_indices_ = rr_node_indices;
}

/****************************
* Mutators
****************************/
void RRGraphBuilderView::add_node_to_fast_lookup(const RRNodeId& node,
const int& x,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using references for simple integer types is not very useful. Only use references when you have to.

(problem is not only that there is a pointer instead of a shorter immediate type to be passed (and thus not only have to transfer 64 bits instead of 32 in this case, but if you invoke it with a number, the compiler has to generate an intermediate object that has an address), but also, that the compiler needs to often generate special code to make sure not to run into aliasing issues, which you don't have if you just copy things).

So integral values (int, char, int64_t, size_t, ...) always should be passed by value if you just have it as an in-parameter. Also for things such as std::string_view things are faster and better by value not const reference.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. Updated the codes

const int& y,
const t_rr_type& type,
const int& ptc,
const e_side& side) {
VTR_ASSERT_SAFE(3 == (*rr_node_indices_)[type].ndims());

/* Expand the fast look-up if the new node is out-of-range
* This may seldom happen because the rr_graph building function
* should ensure the fast look-up well organized
*/
VTR_ASSERT(type < (*rr_node_indices_).size());

if ((size_t(x) >= (*rr_node_indices_)[type].dim_size(0))
|| (size_t(y) >= (*rr_node_indices_)[type].dim_size(1))
|| (size_t(side) >= (*rr_node_indices_)[type].dim_size(2))) {
(*rr_node_indices_)[type].resize({std::max((*rr_node_indices_)[type].dim_size(0), size_t(x) + 1),
std::max((*rr_node_indices_)[type].dim_size(1), size_t(y) + 1),
std::max((*rr_node_indices_)[type].dim_size(2), size_t(side) + 1)});
}

if (size_t(ptc) >= (*rr_node_indices_)[type][x][y][side].size()) {
(*rr_node_indices_)[type][x][y][side].resize(ptc + 1);
}

/* Resize on demand finished; Register the node */
(*rr_node_indices_)[type][x][y][side][ptc] = int(size_t(node));
}
53 changes: 53 additions & 0 deletions vpr/src/device/rr_graph_builder_view.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#ifndef _RR_GRAPH_BUILDER_VIEW_
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid leading undrescores in the include-guards as they are reserved for c/c++ compiler internals.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. Updated.

#define _RR_GRAPH_BUILDER_VIEW_

#include <exception>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you include <exception> ? I don't see that needed anywhere below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. Removed all the unused headers.


#include "rr_graph_fwd.h"
#include "rr_node_fwd.h"
#include "rr_graph2.h"
#include "vtr_log.h"
#include "vtr_memory.h"
#include "vpr_utils.h"
#include "vtr_strong_id_range.h"
#include "vtr_array_view.h"
#include "rr_graph_storage.h"
#include "rr_graph_view.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Below, the types rr_graph_storage, rr_node_indices, RRNodeId, t_rr_type and e_side are used. Do we have to include all the above to get access to these ?

IWYU, but not more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. Removed all the unused headers.


/* An builder of routing resource graph which extends
* the read-only frame view RRGraphView
*
* Note that the builder does not own the storage
* It serves a virtual protocol for
* - rr_graph builder, which requires both mutators and accessors
*
* Note:
* - This is the only data structre allowed to modify a routing resource graph
*
*/
class RRGraphBuilderView : public RRGraphView {
Copy link
Collaborator

@litghost litghost Apr 1, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No inheritance of classes with non-abstract methods.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Second that.

Inheritance is reaaaally rarely used in real world code as it has all kinds of issues (fragile base class, hard to figure out what is going on in a stack of classes.

In the early days of object oriented programming, everyone thought that was a good idea, but, turns out composition is what is mostly reflecting what we want and inheritance is only really useful to describe abstract things and their implementation (meaning: the concept of interface and implementation)).

Base classes are typically only done with interfaces; that is when the base class defines an API of sorts, but with all abstract virtual methods; then there are implementations that implement that (this is what Keith said with the comment above: unless we use the concept of implementing an interface, don't use inheritance).

/****************
* Constructors
****************/
public:
RRGraphBuilderView(t_rr_graph_storage* node_storage,
t_rr_node_indices* rr_node_indices);

/****************
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd avoid the comments such as /* constructors ... */ /*mutators ...*/ that don't provide additional useful information the reader wouldn't already notice: it just adds more vertical space someone has to scroll through to get to the interesting parts (also in other files in this pull request).

Instead, focus on comments on each constructor or method. What are the parameters for these, how are these important, what does or provide the method. These are the relevant parts for someone later using the API.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The organization was actually suggested when prototyping the data structure RRGraphObject. We want to guide developers quickly to the constructors and accessors, which the developers care most. I am open to discussion still. This is mainly due to the suggested organization is not clear to me yet. We can have more discussion.

* Accessors all come from RRGraph View
****************/

/****************
* Mutators
****************/
public:
/* Register a node in the fast look-up */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each of the parameters need to be explained. This is a public interface, so that is what users of this API will look at to know what to do. Use Doxygen-style commenting style, in which the paramter is in quotes.
Something like

Add "node" at position ("x","y"). The "type" is .. blabla whatever needs to be described here

The name of the function looks like it mixes intent ("add_node()") and implementation detail : to_fast_lookup - this is something that is up to the implementation in which way it will add the nodes (one would hope for always fast look-up I presume :)).

This is a good name for a private method name as there you have more of the implementation details that are important. The public interface should only contain names that describe what we expect from something this class should do.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed. I will see what comments to added.

void add_node_to_fast_lookup(const RRNodeId& node,
const int& x,
const int& y,
const t_rr_type& type,
const int& ptc,
const e_side& side);
};

#endif
87 changes: 87 additions & 0 deletions vpr/src/device/rr_graph_view.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/***************************************
* Methods for Object RRGraphView
***************************************/
#include "vtr_assert.h"
#include "rr_graph_view.h"

/****************************
* Constructors
****************************/
RRGraphView::RRGraphView() {
node_storage_ = nullptr;
rr_node_indices_ = nullptr;
}

/****************************
* Accessors
****************************/
t_rr_type RRGraphView::node_type(const RRNodeId& node) const {
return node_storage_->node_type(node);
}

RRNodeId RRGraphView::find_node(const int& x,
const int& y,
const t_rr_type& type,
const int& ptc,
const e_side& side) const {
/* Find actual side to be used */
e_side node_side = side;
if (type == IPIN || type == OPIN) {
VTR_ASSERT_MSG(side != NUM_SIDES, "IPIN/OPIN must specify desired side (can not be default NUM_SIDES)");
} else {
VTR_ASSERT(type != IPIN && type != OPIN);
node_side = SIDES[0];
}

/* Currently need to swap x and y for CHANX because of chan, seg convention */
size_t node_x = x;
size_t node_y = y;
if (CHANX == type) {
std::swap(node_x, node_y);
}

VTR_ASSERT_SAFE(3 == (*rr_node_indices_)[type].ndims());

/* Sanity check to ensure the x, y, side and ptc are in range
* Data type of rr_node_indice:
* typedef std::array<vtr::NdMatrix<std::vector<int>, 3>, NUM_RR_TYPES> t_rr_node_indices;
* Note that x, y and side are the 1st, 2nd and 3rd dimensions of the vtr::NdMatrix
* ptc is in the std::vector<int>
*/
if (size_t(type) >= (*rr_node_indices_).size()) {
/* Node type is out of range, return an invalid index */
return RRNodeId::INVALID();
}

if (node_x >= (*rr_node_indices_)[type].dim_size(0)) {
/* Node x is out of range, return an invalid index */
return RRNodeId::INVALID();
}

if (node_y >= (*rr_node_indices_)[type].dim_size(1)) {
/* Node y is out of range, return an invalid index */
return RRNodeId::INVALID();
}

if (node_side >= (*rr_node_indices_)[type].dim_size(2)) {
/* Node side is out of range, return an invalid index */
return RRNodeId::INVALID();
}

if (size_t(ptc) >= (*rr_node_indices_)[type][node_x][node_y][node_side].size()) {
/* Ptc is out of range, return an invalid index */
return RRNodeId::INVALID();
}

/* Reaching here, it means that node exists in the look-up, return the id */
return RRNodeId((*rr_node_indices_)[type][node_x][node_y][node_side][ptc]);
}

/****************************
* Mutators
****************************/
void RRGraphView::set_internal_data(t_rr_graph_storage* node_storage,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this something we want to allow ? It sounds like that is something that we want to have set once. After all, the RRGraphView is (at this point) merely a tuple of these pointers. And to make things easy to reason, we want to have data containers mostly immutable (common best practice).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. Removed

t_rr_node_indices* rr_node_indices) {
node_storage_ = node_storage;
rr_node_indices_ = rr_node_indices;
}
99 changes: 99 additions & 0 deletions vpr/src/device/rr_graph_view.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#ifndef _RR_GRAPH_OVERLAY_
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The class you define here is called RRGraphView. The header is calls rr_graph_view.h. so you want the include guard also be called something like RR_GRAPH_VIEW_H_

Also, avoid leading underscores, as any identifiers and in particular macros with leading underscores are reserved for internal use in C/C++.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. Updated.

#define _RR_GRAPH_OVERLAY_

#include <exception>

#include "rr_graph_fwd.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(like in the other place, keep the headers sorted. Since this is a new file, we can start right away using best practices here)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree

#include "rr_node_fwd.h"
#include "rr_graph2.h"
#include "vtr_log.h"
#include "vtr_memory.h"
#include "vpr_utils.h"
#include "vtr_strong_id_range.h"
#include "vtr_array_view.h"
#include "rr_graph_storage.h"

/* An read-only routing resource graph
* which is an unified object including pointors to
* - node storage
* - edge_storage
* - node_ptc_storage
* - node_fan_in_storage
* - rr_node_indices
*
* Note that the RRGraphView does not own the storage
* It serves a virtual read-only protocol for
* - placer
* - router
* - timing analyzer
* - GUI
*
* Note that each client of rr_graph may get a frame view of the object
* The RRGraphView is the complete frame view of the routing resource graph
* - This helps to reduce the memory footprint for each client
* - This avoids massive changes for each client on using the APIs
* as each frame view provides adhoc APIs for each client
*
* TODO: more compact frame views will be created, e.g.,
* - a mini frame view: contains only node and edges, representing the connectivity of the graph
* - a geometry frame view: an extended mini frame view with node-level attributes,
* in particular geometry information (type, x, y etc).
*
*/
class RRGraphView {
/****************
* Constructors
****************/
public:
RRGraphView();

/****************
* Accessors
****************/
public:
/* Get the type of a routing resource node */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably good to add a TODO comment saying that the goal is to have these accessors private at some point totally replaced with the 'questioin' kind of methods.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. The TODO comment is useful. But not every API will be converted to the questionin methods. But the questionin style is preferred.

t_rr_type node_type(const RRNodeId& node) const;

/* Returns the index of the specified routing resource node. (x,y) are
* the location within the FPGA, rr_type specifies the type of resource,
* and ptc gives the number of this resource. ptc is the class number,
* pin number or track number, depending on what type of resource this
* is. All ptcs start at 0 and go up to pins_per_clb-1 or the equivalent.
* There are class_inf size SOURCEs + SINKs, type->num_pins IPINs + OPINs,
* and max_chan_width CHANX and CHANY (each).
*
* Note that for segments (CHANX and CHANY) of length > 1, the segment is
* given an rr_index based on the (x,y) location at which it starts (i.e.
* lowest (x,y) location at which this segment exists).
* This routine also performs error checking to make sure the node in
* question exists.
*
* The 'side' argument only applies to IPIN/OPIN types, and specifies which
* side of the grid tile the node should be located on. The value is ignored
* for non-IPIN/OPIN types
*/
RRNodeId find_node(const int& x,
const int& y,
const t_rr_type& type,
const int& ptc,
const e_side& side = NUM_SIDES) const;

/****************
* Mutators
****************/
public:
/* The ONLY mutators allowed */
void set_internal_data(t_rr_graph_storage* node_storage,
t_rr_node_indices* rr_node_indices);

/****************
* internal data storage, can be accessed by parent class RRGraphBuilderView
****************/
protected:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

protected on data members is what we rarely should have to do. If the derived classes need to have access to the raw members, make protected getters, but keep the members private.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. Changed to private now.

/* node-level storage including edge storages */
t_rr_graph_storage* node_storage_;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strive for making members that are only set once in the constructor, const.

t_rr_graph_storage* const node_storage_;
t_rr_node_indices* const rr_node_indices_;

That way, it is immediately clear for someone reading the code that these values will never be assigned to again, and it helps make it easier to reason about the code.

this also means, that you will have to have a
RRGraphView(t_rr_graph_storage* , t_rr_node_indices*) constructor that initializes via the initializer list, because otherwise assignment will not be possible anymore aftewards: So e.g. this works

RRGraphView(t_rr_graph_storage* storage, t_rr_node_indices* indices) 
    : node_storage_(storage), rr_node_indices_(indices) {}

While the following won't, as it attempts to assign things after the initializer list:

RRGraphView(t_rr_graph_storage* storage, t_rr_node_indices* indices) {
  node_storage_ = storage;
  rr_node_indices_ = indices;
}

So using this technique of making as much const as can be (the stuff that will only be set once in the constructor) also lets us adopt the correct habit of initializing as much as possible in the constructor initializer list. And it is easy to find the one place where it happens -> overall improved code quality.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. Updated.

/* Fast look-up */
t_rr_node_indices* rr_node_indices_;
};

#endif
Loading