# include/net/node.hpp
# Namespaces
Name |
---|
net |
# Classes
Name | |
---|---|
struct | net::half_edge 描述着(某条格点上的)半边的信息,包括这条半边与哪条格点的哪条半边相连 |
class | net::node 存储了网络中一个格点内的信息 |
# Source code
#ifndef NET_NODE_HPP
#define NET_NODE_HPP
#include "error.hpp"
#include "network.hpp"
#include "traits.hpp"
#include <functional>
#include <map>
#include <string>
#include <vector>
namespace net {
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
class node;
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
class network;
template <typename T>
std::string to_string(const T & m);
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
struct half_edge {
using EdgeItrType = typename std::map<EdgeKey, half_edge<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>, typename Trait::edgekey_less>::iterator ;
int nb_num;
NodeKey nbkey;
EdgeKey nbind;
typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode nbitr;
EdgeVal val;
EdgeItrType nbegitr;
half_edge() : nb_num(0) {};
half_edge(const EdgeVal & E) : val(E), nb_num(0) {};
half_edge(const NodeKey & s1, const EdgeKey & s2, typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode s) :
nbkey(s1), nbind(s2), nbitr(s), nb_num(1){};
half_edge(const NodeKey & s1, const EdgeKey & s2, typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode s, const EdgeVal & E) :
nbkey(s1), nbind(s2), nbitr(s), val(E), nb_num(1){};
half_edge(const NodeKey & s1, const EdgeKey & s2, const EdgeVal & E) : nbkey(s1), nbind(s2), val(E), nb_num(1){};
half_edge(const half_edge<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &) = default;
};
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
class node {
template <typename NodeVal1, typename EdgeVal1, typename NodeKey1, typename EdgeKey1, typename Trait1>
friend std::ostream & output_node_text(std::ostream &, const node<NodeVal1, EdgeVal1, NodeKey1, EdgeKey1, Trait1> &);
template <typename NodeVal1, typename EdgeVal1, typename NodeKey1, typename EdgeKey1, typename Trait1>
friend std::istream & input_node_text(std::istream &, node<NodeVal1, EdgeVal1, NodeKey1, EdgeKey1, Trait1> &);
template <typename NodeVal1, typename EdgeVal1, typename NodeKey1, typename EdgeKey1, typename Trait1>
friend std::ostream & output_node_bin(std::ostream &, const node<NodeVal1, EdgeVal1, NodeKey1, EdgeKey1, Trait1> &);
template <typename NodeVal1, typename EdgeVal1, typename NodeKey1, typename EdgeKey1, typename Trait1>
friend std::istream & input_node_bin(std::istream &, node<NodeVal1, EdgeVal1, NodeKey1, EdgeKey1, Trait1> &);
public:
// constructor
node() = default;
node(const NodeKey & k) : key(k){};
node(const NodeKey & k, const NodeVal & s) : key(k),val(s){};
// copy constructor
node(const node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &) = default;
// copy assignment
node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> & operator=(const node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &) = default;
// move constructor
node(node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &&) = default;
// move assignment
node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> & operator=(node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &&) = default;
using EdgeType = half_edge<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>;
using NodeKeyType = NodeKey;
using NodeValType = NodeVal;
using EdgeKeyType = EdgeKey;
using EdgeValType = EdgeVal;
using TraitType = Trait;
typename half_edge<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::EdgeItrType
add_half_edge(const EdgeKey & ind1, const EdgeVal & edgev) ;
void clean();
template <typename Condition>
void delete_half_edge(Condition &&);
template <typename Condition>
void break_edge(Condition &&);
template <typename Condition>
void delete_edge(Condition &&);
void delete_nbedge();
void reset_nbkey_of_nb(const NodeKey &);
template <typename absorb_type, typename contract_type>
void absorb_nb(const NodeKey &, const NodeVal &, const absorb_type &, const contract_type &);
template <typename absorb_type, typename Condition>
void
harmless_absorb_nb(NodeVal &, std::set<std::pair<EdgeKey, EdgeKey>, typename Trait::edge2key_less> &, const absorb_type &, Condition &&) const;
void transfer_edge(const typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode &);
template <typename Condition>
void transfer_edge(const typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode &, Condition &&);
template <typename Condition>
void transfer_edge(
const typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode &,
const typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode &,
Condition &&);
void relink(std::map<NodeKey, node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>, typename Trait::nodekey_less> &);
bool consistency(const std::map<NodeKey, node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>, typename Trait::nodekey_less> &, const NodeKey & t, std::ostream &)const;
void fope(std::function<NodeVal(const NodeVal &)> f1, std::function<EdgeVal(const EdgeVal &)> f2);
template <typename NodeType2>
NodeType2
fmap(const NodeKey & this_key,std::function<typename NodeType2::NodeValType(const NodeVal &)> f1,
std::function<typename NodeType2::EdgeValType(const EdgeVal &)> f2) const;
template <typename NodeType2>
NodeType2
fmap(const NodeKey & new_key, std::function<typename NodeType2::NodeValType(const NodeVal &)> f1,
std::function<typename NodeType2::EdgeValType(const EdgeVal &)> f2,
std::function<typename NodeType2::NodeKeyType(const NodeKey &)> f3,
std::function<typename NodeType2::EdgeKeyType(const EdgeKey &)> f4) const;
template <typename NodeVal2, typename EdgeVal2, typename Trait2>
node<NodeVal2, EdgeVal2, NodeKey, EdgeKey, Trait2>
gfmap(const NodeKey & this_key,std::function<NodeVal2(const node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &)> f1,
std::function<EdgeVal2(const node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &,const EdgeKey &)> f2) const;
void gfope(std::function<NodeVal(const node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &)> f1,
std::function<EdgeVal(const node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &,const EdgeKey &)> f2);
NodeKey key;
NodeVal val;
std::map<EdgeKey, half_edge<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>, typename Trait::edgekey_less> edges;
};
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
template <typename Condition>
void node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::delete_half_edge(Condition && cond) {
for (auto edge_itr = edges.begin(); edge_itr != edges.end();) {
if (cond(edge_itr)) {
if(edge_itr->second.nbnum!=0){
edge_itr->second.nbegitr->second.nbnum=0;
edge_itr->second.nbegitr->second.nbkey=edge_itr->second.nbkey;
edge_itr->second.nbegitr->second.nbind=edge_itr->second.nbind;
edge_itr->second.nbegitr->second.nbitr=edge_itr->second.nbitr;
edge_itr->second.nbegitr->second.nbegitr=edge_itr->second.nbegitr;
}
edge_itr = edges.erase(edge_itr);
} else {
++edge_itr;
}
}
}
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
template <typename Condition>
void node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::break_edge(Condition && cond) {
for (auto edge_itr = edges.begin(); edge_itr != edges.end();++edge_itr) {
if (cond(edge_itr)) {
if(edge_itr->second.nb_num!=0){
edge_itr->second.nbegitr->second.nb_num=0;
edge_itr->second.nbegitr->second.nbkey=edge_itr->second.nbkey;
edge_itr->second.nbegitr->second.nbind=edge_itr->second.nbind;
edge_itr->second.nbegitr->second.nbitr=edge_itr->second.nbitr;
edge_itr->second.nbegitr->second.nbegitr=edge_itr->second.nbegitr;
edge_itr->second.nb_num=0;
edge_itr->second.nbkey=this->key;
edge_itr->second.nbind=edge_itr->first;
edge_itr->second.nbitr=edge_itr;
edge_itr->second.nbegitr=edge_itr;
}
}
}
}
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
template <typename Condition>
void node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::delete_edge(Condition && cond) {
for (auto edge_itr = edges.begin(); edge_itr != edges.end();) {
if (cond(edge_itr)) {
if(edge_itr->second.nb_num!=0){
edge_itr->second.nbitr->second.edges.erase(edge_itr->second.nbegitr);
}
edge_itr = edges.erase(edge_itr);
} else {
++edge_itr;
}
}
}
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
void node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::delete_nbedge() {
for (auto & b : edges) {
if(b.second.nb_num!=0){
b.second.nbitr->second.edges.erase(b.second.nbegitr);
}
}
edges.clear();
}
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
void node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::reset_nbkey_of_nb(const NodeKey & newkey) {
for (auto & b : edges) {
if(b.second.nb_num!=0){
b.second.nbegitr->second.nbkey = newkey;
}
}
}
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
template <typename absorb_type, typename contract_type>
void node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::absorb_nb(
const NodeKey & nbkey,
const NodeVal & nbval,
const absorb_type & absorb_fun,
const contract_type & contract_fun) {
std::set<std::pair<EdgeKey, EdgeKey>, typename Trait::edge2key_less> ind_pairs;
// set ind_pairs and erase iterator in node1
for (auto iter = edges.begin(); iter != edges.end();) {
if (iter->second.nb_num!=0 && iter->second.nbkey == nbkey) {
ind_pairs.insert({iter->first, iter->second.nbind});
val = absorb_fun(val, iter->second.val, iter->first);
iter = edges.erase(iter);
} else {
++iter;
}
}
val = contract_fun(val, nbval, ind_pairs);
}
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
template <typename absorb_type, typename Condition>
void node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::harmless_absorb_nb(
NodeVal & thisval,
std::set<std::pair<EdgeKey, EdgeKey>, typename Trait::edge2key_less> & ind_pairs,
const absorb_type & absorb_fun,
Condition && cond) const {
for (auto & b : edges) {
// std::cout<<"edge"<<b.first<<' '<<b.second.nbkey<<'\n';
if (b.second.nb_num!=0 && cond(b)) {
// std::cout<<"edgehere"<<b.first<<' '<<b.second.nbkey<<'\n';
ind_pairs.insert({b.first, b.second.nbind});
thisval = absorb_fun(thisval, b.second.val, b.first);
}
}
}
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
void node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::transfer_edge(
const typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode & newit) {
while(edges.size()>0) {
auto nh = edges.extract(edges.begin());
auto status = newit->second.edges.insert(std::move(nh));
if(status.position->second.nb_num!=0){
status.position->second.nbegitr->second.nbkey = newit->first;
status.position->second.nbegitr->second.nbitr = newit;
status.position->second.nbegitr->second.nbegitr = status.position;
}
}
}
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
template <typename Condition>
void node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::transfer_edge(
const typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode & newit,
Condition && cond) {
for (auto iter = edges.begin(); iter != edges.end();) {
if (cond(iter)) {
auto nh = edges.extract(iter++);
auto status = newit->second.edges.insert(std::move(nh));
if(status.position->second.nb_num!=0){
status.position->second.nbegitr->second.nbkey = newit->first;
status.position->second.nbegitr->second.nbitr = newit;
status.position->second.nbegitr->second.nbegitr = status.position;
}
} else {
++iter;
}
}
}
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
template <typename Condition>
void node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::transfer_edge(
const typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode & newit,
const typename network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::IterNode & newit2,
Condition && cond) {
for (auto iter = edges.begin(); iter != edges.end();) {
auto nh = edges.extract(iter++);
if (cond(iter)) {
auto status = newit->second.edges.insert(std::move(nh));
if(status.position->second.nb_num!=0){
status.position->second.nbegitr->second.nbkey = newit->first;
status.position->second.nbegitr->second.nbitr = newit;
status.position->second.nbegitr->second.nbegitr = status.position;
}
} else {
auto status = newit2->second.edges.insert(std::move(nh));
if(status.position->second.nb_num!=0){
status.position->second.nbegitr->second.nbkey = newit2->first;
status.position->second.nbegitr->second.nbitr = newit2;
status.position->second.nbegitr->second.nbegitr = status.position;
}
}
}
}
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
typename half_edge<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::EdgeItrType
node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::add_half_edge(const EdgeKey & ind1, const EdgeVal & edgev) {
auto [egit1, succ1] = edges.insert({ind1, typename node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::EdgeType(edgev)});
if (!succ1)
throw key_exist_error("In node.add_edge_node, ind " + to_string(ind1) + " already exist!");
return egit1;
}
template <typename IterNode, typename EdgeKey, typename EdgeVal>
void add_edge_node(IterNode it1, IterNode it2, const EdgeKey & ind1,const EdgeKey & ind2, const EdgeVal & edgev) {
auto egit1 = it1->second.add_half_edge(ind1,edgev);
auto egit2 = it2->second.add_half_edge(ind2,edgev);
egit1->second.nb_num=1;
egit1->second.nbkey= it2->first;
egit1->second.nbind= ind2;
egit1->second.nbitr=it2;
egit1->second.nbegitr=egit2;
egit2->second.nb_num=1;
egit2->second.nbkey= it1->first;
egit2->second.nbind= ind1;
egit2->second.nbitr=it1;
egit2->second.nbegitr=egit1;
}
template <typename IterNode, typename EdgeKey, typename EdgeVal>
void connect_edge_node(IterNode it1, IterNode it2, const EdgeKey & ind1,const EdgeKey & ind2) {
auto egit1 = it1->second.edges.find(ind1);
if (egit1 == it1->second.edges.end())
throw key_unfound_error("In node.connect_edge_node, ind " + to_string(ind1) + " is not found!");
if(egit1->second.nb_num==1)
throw key_exist_error("In node.connect_edge_node, ind " + to_string(ind1) + " already linked!");
auto egit2 = it2->second.edges.find(ind2);
if (egit2 == it2->second.edges.end())
throw key_unfound_error("In node.connect_edge_node, ind " + to_string(ind2) + " is not found!");
if(egit2->second.nb_num==1)
throw key_exist_error("In node.connect_edge_node, ind " + to_string(ind2) + " already linked!");
egit1->second.nb_num=1;
egit1->second.nbkey=it2->first;
egit1->second.nbind=ind2;
egit1->second.nbitr=it2;
egit1->second.nbegitr=egit2;
egit2->second.nb_num=1;
egit2->second.nbkey=it1->first;
egit2->second.nbind=ind1;
egit2->second.nbitr=it1;
egit2->second.nbegitr=egit1;
}
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
void node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::relink(
std::map<NodeKey, node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>, typename Trait::nodekey_less> & nodes) {
for (auto & b : edges){
if(b.second.nb_num==1){
b.second.nbitr = nodes.find(b.second.nbkey);
b.second.nbegitr = b.second.nbitr->second.edges.find(b.second.nbind);
}
}
}
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
template <typename NodeVal2, typename EdgeVal2, typename Trait2>
node<NodeVal2, EdgeVal2, NodeKey, EdgeKey, Trait2> node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::gfmap( const NodeKey & this_key,
std::function<NodeVal2(const node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &)> f1,
std::function<EdgeVal2(const node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &,const EdgeKey &)> f2) const {
node<NodeVal2, EdgeVal2, NodeKey, EdgeKey, Trait2> result(this_key,f1(*this));
for (auto & b : edges)
if(b.second.nb_num==1){
result.edges[b.first] = half_edge<NodeVal2, EdgeVal2, NodeKey, EdgeKey, Trait2>(b.second.nbkey, b.second.nbind, f2(*this, b.first));
}else{
result.edges[b.first] = half_edge<NodeVal2, EdgeVal2, NodeKey, EdgeKey, Trait2>(f2(*this, b.first));
}
return result;
}
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
template <typename NodeType2>
NodeType2 node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::fmap( const NodeKey & this_key,
std::function<typename NodeType2::NodeValType(const NodeVal &)> f1,
std::function<typename NodeType2::EdgeValType(const EdgeVal &)> f2) const {
NodeType2 result(this_key, f1(val));
for (auto & b : edges)
if(b.second.nb_num==1){
result.edges[b.first] = typename NodeType2::EdgeType(b.second.nbkey, b.second.nbind, f2(b.second.val));
}else{
result.edges[b.first] = typename NodeType2::EdgeType(f2(b.second.val));
}
return result;
}
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
template <typename NodeType2>
NodeType2 node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::fmap( const NodeKey & new_key,
std::function<typename NodeType2::NodeValType(const NodeVal &)> f1,
std::function<typename NodeType2::EdgeValType(const EdgeVal &)> f2,
std::function<typename NodeType2::NodeKeyType(const NodeKey &)> f3,
std::function<typename NodeType2::EdgeKeyType(const EdgeKey &)> f4) const {
NodeType2 result(new_key,f1(val));
for (auto & b : edges)
if(b.second.nb_num==1){
result.edges[f4(b.first)] = typename NodeType2::EdgeType(f3(b.second.nbkey), f4(b.second.nbind), f2(b.second.val));
}else{
result.edges[f4(b.first)] = typename NodeType2::EdgeType(f2(b.second.val));
}
return result;
}
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
void
node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::fope(std::function<NodeVal(const NodeVal &)> f1, std::function<EdgeVal(const EdgeVal &)> f2) {
val = f1(val);
for (auto & b : edges)
b.second.val = f2(b.second.val);
}
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
void
node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::gfope(std::function<NodeVal(const node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &)> f1,
std::function<EdgeVal(const node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait> &,const EdgeKey &)> f2) {
auto temp = f1(*this);
for (auto & b : edges)
b.second.val = f2(*this,b.first);
val = temp;
}
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
bool node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::consistency(
const std::map<NodeKey, node<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>, typename Trait::nodekey_less> & nodes,
const NodeKey & this_key, std::ostream & diagnosis) const {
if(key!=this_key){
diagnosis << "Network is not consistent, node at " + to_string(this_key) + " has wrong key!\n";
return false;
}
for (auto & b : edges) { // check if b is consistent
if(b.second.nb_num!=0){
if (nodes.count(b.second.nbkey) == 0) {
diagnosis << "Network is not consistent, neighbor " + to_string(b.second.nbkey) + " is not found!\n";
return false;
} else if (nodes.at(b.second.nbkey).edges.count(b.second.nbind) == 0) {
diagnosis << "Network is not consistent, neighbor " + to_string(b.second.nbkey) + " has no index named " + to_string(b.second.nbind) +
" !\n";
return false;
} else if (b.second.nbitr != nodes.find(b.second.nbkey)) {
diagnosis << "Network is not consistent, pointer to neighbor " + to_string(b.second.nbkey) + " is not correctly pointed !\n";
return false;
} else if (b.second.nbegitr != b.second.nbitr->second.edges.find(b.second.nbind)) {
diagnosis << "Network is not consistent, pointer to neighbor edge " + to_string(b.second.nbind) + " is not correctly pointed !\n";
return false;
} else if (b.second.nbegitr->second.nb_num == 0) {
diagnosis << "Network is not consistent, neighboring half edge to " + to_string(b.second.nbind) + " is dangling !\n";
return false;
} else if (b.second.nbegitr->second.nbkey != this_key) {
diagnosis << "Network is not consistent, neighboring half edge to " + to_string(b.second.nbind) + " is not matching 0 !\n";
return false;
} else if (b.second.nbegitr->second.nbind != b.first) {
diagnosis << "Network is not consistent, neighboring half edge to " + to_string(b.second.nbind) + " is not matching 1 !\n";
return false;
}
}
}
return true;
}
} // namespace net
#endif
Updated on 15 June 2022 at 16:04:19 CST