This implementation is by no means elegant: it does not handle error well; it uses the same space for a forward table with a rule table; it uses hand-coded parsing, which is hard to read and modify...
But it has to comply with some constraints: it has to use ONLY the standard library, it must be completed in a short time.
Then I post it here, after some polishing, for a reference.
SimpleRouter.cpp:
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
using namespace std;
class SimpleRouter
{
public:
typedef unsigned short num_type;
typedef pair<num_type, num_type> range_type;
typedef vector<range_type> ip_type;
typedef vector<ip_type> forward_table_type;
typedef pair<string, ip_type> rule_type;
typedef vector<rule_type> rule_table_type;
// This method & its signature is required by the problem.
vector<string> route(vector<string> rules, vector<string> packets);
private:
string route(ip_type& packet);
bool range_any(const range_type& ip_seg);
bool match(const ip_type& rule_ip, const ip_type& packet);
range_type parse_ip_seg(string& seg);
ip_type parse_ip(const string& ip);
string ip_seg_to_string(const range_type& ip_seg);
string ip_to_string(const ip_type& ip, char port_seperator);
string get_forward(const ip_type& rule, ip_type packet);
private:
const static num_type min_num = 0;
const static num_type max_num = static_cast<num_type>(-1);
rule_table_type rule_table;
forward_table_type forward_table;
void build_table(vector<string>& rules);
public:
// For debug
void print_table();
void print_ip(const ip_type& ip);
};
void SimpleRouter::build_table(vector<string>& rules)
{
rule_table.reserve(rules.size());
forward_table.reserve(rules.size());
string action, ip_str, port_str;
for(vector<string>::const_iterator iter = rules.begin();
iter != rules.end(); ++iter)
{
string::size_type end_action = iter->find_first_of(' ');
action = iter->substr(0, end_action);
ip_str = iter->substr(end_action + 1);
if(action == "FORWARD")
{
// get position of forward target
string::size_type temp = ip_str.find_first_of(' ') + 1;
string::size_type start_fwdip = ip_str.find_first_of(' ', temp) + 1;
rule_table.push_back(make_pair(action, parse_ip(ip_str.substr(0, start_fwdip - 1))));
forward_table.push_back(parse_ip(ip_str.substr(start_fwdip)));
}
else
{
rule_table.push_back(make_pair(action, parse_ip(ip_str)));
// push a placeholder to forward table
forward_table.push_back(ip_type());
}
}
}
vector <string> SimpleRouter::route(vector<string> rules, vector<string> packets)
{
build_table(rules);
vector<string> ret;
for(vector<string>::iterator iter = packets.begin();
iter != packets.end(); ++iter)
{
ret.push_back(route(parse_ip(*iter)));
}
return ret;
}
string SimpleRouter::route(ip_type& packet)
{
// check rules one-by-one reversely, as the last matched rule counts
forward_table_type::const_reverse_iterator fwd_iter = forward_table.rbegin();
rule_table_type::const_reverse_iterator rule_iter = rule_table.rbegin();
// workaround for a VC7.1 bug
rule_table_type::const_reverse_iterator rule_rend = rule_table.rend();
for(; rule_iter != rule_rend; ++rule_iter, ++fwd_iter)
{
string action = rule_iter->first;
if(action == "FORWARD")
{
if(match(rule_iter->second, packet))
{
return get_forward(*fwd_iter, packet);
}
}
else
{
if(match(rule_iter->second, packet))
return action;
}
}
// match no rules
return "REJECT";
}
string SimpleRouter::get_forward(const ip_type& fwd, ip_type packet)
{
// if fwd port is specified, replace packet port with fwd port
if(fwd.size() > 4 && !range_any(fwd[4]))
packet[4] = fwd[4];
return ip_to_string(packet, ':');
}
bool inline SimpleRouter::range_any(const range_type& ip_seg)
{
return ip_seg.first == min_num && ip_seg.second == max_num;
}
bool SimpleRouter::match(const ip_type& rule_ip, const ip_type& packet)
{
ip_type::const_iterator rule_iter = rule_ip.begin();
ip_type::const_iterator pk_iter = packet.begin();
for( ; rule_iter != rule_ip.end(); ++rule_iter, ++pk_iter)
{
// see if packet ip is within the range of rule
if(!(rule_iter->first <= pk_iter->first) ||
!(rule_iter->second >= pk_iter->second))
return false;
}
return true;
}
string SimpleRouter::ip_seg_to_string(const range_type& ip_seg)
{
char ret[12] = "*"; //the longest possible segment is 11 chars:
//xxxxx-xxxxx
if(!range_any(ip_seg))
{
int len = sprintf(ret, "%d", ip_seg.first);
if(ip_seg.first != ip_seg.second)
{
ret[len] = '-';
sprintf(ret + len + 1, "%d", ip_seg.second);
}
}
return ret;
}
string SimpleRouter::ip_to_string(const ip_type& ip, char port_seperator)
{
string ret;
ret.reserve(44); //the longest possible ip string is 43 chars:
//xxx-xxx.xxx-xxx.xxx-xxx.xxx-xxx xxxxx-xxxxx
ip_type::const_iterator iter = ip.begin();
for(int i = 0; iter != ip.end(); ++iter, ++i)
{
ret.append(ip_seg_to_string(*iter));
if(i < 3)
ret.append(".");
else if(i == 3)
ret.append(1, port_seperator);
}
return ret;
}
SimpleRouter::range_type SimpleRouter::parse_ip_seg(string& seg)
{
if(seg == "*")
{
return make_pair(min_num, max_num);
}
else
{
string::size_type dash_pos = seg.find_first_of('-');
num_type start, end;
if(dash_pos == string::npos)
{
stringstream(seg) >> start;
end = start;
}
else
{
stringstream(seg.substr(0, dash_pos)) >> start;
stringstream(seg.substr(++dash_pos)) >> end;
}
return make_pair(start, end);
}
}
SimpleRouter::ip_type SimpleRouter::parse_ip(const string& ip)
{
ip_type ret;
// break string ip into ip & port
string::size_type end_ip, start_port;
end_ip = ip.find_first_of(' ');
start_port = (end_ip == string::npos) ? string::npos : end_ip + 1;
// parse the 4 segment of ip
string::size_type start_seg = 0, end_seg;
for(int i = 0; i < 4; ++i)
{
end_seg = (i == 3) ? end_ip : ip.find_first_of('.', start_seg);
ret.push_back(parse_ip_seg(ip.substr(start_seg, end_seg - start_seg)));
start_seg = end_seg + 1;
}
// parse port(optional)
if(start_port != string::npos)
ret.push_back(parse_ip_seg(ip.substr(start_port)));
return ret;
}
//===================== For debug ======================
void SimpleRouter::print_ip(const ip_type& ip)
{
cout << ip_to_string(ip, ' ');
}
void SimpleRouter::print_table()
{
rule_table_type::iterator rule_iter = rule_table.begin();
forward_table_type::iterator fwd_iter = forward_table.begin();
for(; rule_iter != rule_table.end(); ++rule_iter, ++fwd_iter)
{
cout << rule_iter->first << " ";
print_ip(rule_iter->second);
if(!fwd_iter->empty())
{
cout << " ";
print_ip(*fwd_iter);
}
cout << endl;
}
}
//========================== Test ===========================
#include <iostream>
#include <algorithm>
template <class T>
struct ArraySize
{};
template <class T, int D>
struct ArraySize<T[D]>
{
static const int value = D;
};
template <class ARY>
void InitWith(vector<string>& vect, const ARY& ary)
{
int size = ArraySize<ARY>::value;
vect.reserve(size);
vect.insert(vect.begin(), ary, ary + size);
}
int main()
{
string rule_ary[] =
{
"REJECT *.20-252.114-157.36-91 13171-54085",
"ACCEPT *.*.73-180.* *",
"FORWARD 55.63.173.239 * 168.154.33.25",
"REJECT *.72-73.*.48-191 *",
"REJECT 20.51.*.* 4579",
"ACCEPT 70-166.*.*.86-182 *",
"REJECT 88-190.*.119-157.* 3316-27844",
"FORWARD *.52-221.134-250.66-207 * 116.94.120.82"
};
string packet_ary[] =
{
"203.11.104.45 44072",
"154.92.128.87 30085",
"20.51.68.55 4579",
"177.73.138.69 14319",
"112.65.145.82 26287",
"55.63.173.239 45899"
};
vector<string> rules, packets;
InitWith(rules, rule_ary);
InitWith(packets, packet_ary);
SimpleRouter router;
vector<string> ret = router.route(rules, packets);
for(vector<string>::iterator i = ret.begin(); i != ret.end(); ++i)
cout << *i << endl;
//============ debug =============
cout << endl << "Rule table, with forwards: " << endl;
router.print_table();
//================================
}
=================================================================================
cl /EHsc SimpleRouter.cpp
SimpleRouter
OUTPUT:
ACCEPT
ACCEPT
REJECT
177.73.138.69:14319
112.65.145.82:26287
55.63.173.239:45899
Rule table, with forwards:
REJECT *.20-252.114-157.36-91 13171-54085
ACCEPT *.*.73-180.* *
FORWARD 55.63.173.239 * 168.154.33.25
REJECT *.72-73.*.48-191 *
REJECT 20.51.*.* 4579
ACCEPT 70-166.*.*.86-182 *
REJECT 88-190.*.119-157.* 3316-27844
FORWARD *.52-221.134-250.66-207 * 116.94.120.82
分享到:
相关推荐
用于topcoder的第3方编辑器插件。
TopCoper SmartWordToy problem 解决方法,C++源码。 Problem Statement The toy company "I Can't Believe It Works!...Form: http://community.topcoder.com/stat?c=problem_statement&pm=3935&rd=6532
【标题】"Topcoder:我提交的Topcoder单轮比赛" 在编程竞赛的世界里,Topcoder是一个备受瞩目的平台,它提供了多种类型的竞赛,包括单轮比赛(SRM)。这些比赛吸引了全球各地的程序员,他们在这里挑战自己的算法设计...
【标题】:“topcoder:topcoder问题” 在编程竞赛领域,TopCoder是一个广为人知的平台,它提供了各种算法挑战,旨在提升参赛者的编程技能,尤其是C++编程能力。TopCoder的问题涵盖了数据结构、算法、数学等多个方面...
【标题】: "TopCoder: 详解Topcoder平台上的编程挑战与Java技术应用" 在编程竞赛的世界里,TopCoder是一个非常知名的在线平台,它提供了一系列的算法竞赛、软件设计比赛以及编码挑战,吸引了全球众多程序员参与。这...
TopCoder 练习 一个 Eclipse 项目,它将包含我用 Java 编写的 TopCoder 的所有实践问题。 包命名约定 会话类型,后跟其 ID 号和分区。 类型###.DIV# Eclipse 版本信息 版本:Luna Service Release 1 (4.4.1) 版本...
标题 "topcoder:Topcoder解决方案" 指的是在Topcoder平台上进行的算法竞赛和解决方案。Topcoder是一个全球知名的在线编程竞赛平台,它为程序员提供了一个展示编程技能、学习算法和解决问题的场所。参赛者通常需要...
【标题】"topcoder-srm:Topcoder SRM竞赛解决方案" 这个标题暗示了这是一个与Topcoder平台上的Single Round Matches (SRM)竞赛相关的资源集合。Topcoder SRM是全球知名的在线编程竞赛,参赛者需要在限定时间内解决...
【标题】"topcoder-python:用 Python 编写的 TopCoder 解决方案" 是一个项目,其核心在于使用 Python 语言解决 TopCoder 平台上的算法竞赛问题。TopCoder 是一个著名的在线编程竞赛平台,它提供了丰富的算法挑战,...
《TopCoder:Java编程实战指南》 在编程竞赛领域,TopCoder无疑是一个备受瞩目的平台,它为全球的程序员提供了一个展示技术才华、提升编程能力的舞台。本篇将聚焦于如何利用Java语言来解决TopCoder上的问题,帮助你...
topcoder-dl :bookmark: 下载所有Topcoder数据科学教程,并另存为PDF 灵感来自这个很棒的东西,叫做 安装 要手动安装的依赖项 从源代码构建 git clone " https://github.com/tushar-rishav/topcoder-dl.git " cd ...
【标题】"TopCoder:TopCoder" 【描述】"TopCoder是一个全球知名的在线编程竞赛平台,它提供了大量的算法挑战,帮助程序员提升技能并与其他高手竞技。TopCoder练习问题解决方案通常涉及各种算法和数据结构,是学习和...
此外,TopCoder竞赛提供了丰富的奖金和机会,如TopCoder Open(TCO)、TopCoder Collegiate Challenge(TCCC)和TopCoder High School(TCHS)等,涵盖算法、设计、开发和组装等领域。TopCoder Studio则专注于网页...
顶级编码器因为我不喜欢解决 TopCoder 问题
topcoder Challenge API 最初是使用构建的。 路由是通过使用 api\swagger\swagger.yaml 中的 swagger 配置文件来处理的。 路由是使用和模块完成的。 构建状态 工匠 快速入门(本地运行) 启动 postgres 创建...
"Topcoder:该存储库用于 Topcoder 算法竞赛的问题解决方案" 指出这个项目是一个专门为参加 Topcoder 算法竞赛的选手准备的资源库,其中包含了各种算法问题的解决方案。Topcoder 是一个全球知名的在线编程竞赛平台,...
【TopCoder:备份我的游乐场】 TopCoder是一个著名的在线编程竞赛平台,吸引了众多程序员参与算法比赛,提升编程技能。"备份我的游乐场"这个标题暗示了这是一个个人在TopCoder平台上练习和学习的记录,可能包含了该...
《TopCoder-Arena:竞技场的各种挑战解析》 在编程界,TopCoder是一个备受瞩目的在线编程竞赛平台,其中的竞技场(Arena)是它的核心组成部分。本文将深入探讨TopCoder-Arena的各种挑战,以及如何利用Java语言进行...
C++、Haskell 和其他语言中 TopCoder 问题的解决方案。 所有解决方案均已使用进行了正确性测试,该工具可帮助您在没有官方在线领域的情况下运行 TopCoder 解决方案。 每个解决方案的问题陈述都可以在找到。 这些...
综上所述,通过本文的介绍,您不仅能够了解到如何注册成为TopCoder会员,还能了解如何参与TopCoder Tournament China 2008比赛,更重要的是,您将对算法设计有一个初步的认识。希望这些信息能帮助您更好地利用...