Tak na szybko:
(Przypomnienie: używany mock socketa)
#pragma once
#include <iostream>
#include <vector>
#include <string>
template<typename Socket>
auto fetch_next(Socket &sock) {
return sock.fetch_next();
}
namespace mock {
class socket {
public:
using data_type = std::string;
using send_calls_type = std::vector<data_type>;
socket(send_calls_type &&scalls):
send_calls(std::rbegin(scalls), std::rend(scalls)) {}
data_type fetch_next() {
return send_calls.size()?
pop() : data_type{};
}
private:
data_type pop() {
auto result = send_calls.back();
send_calls.pop_back();
return result;
}
send_calls_type send_calls;
};
}
Pakowanie danych do komunikacji (communication.hpp
):
#pragma once
#include <vector>
#include <string>
#include <boost/type_index.hpp>
namespace communication {
using strings = std::vector<std::string>;
struct package {
std::string identifier;
strings data;
};
std::string to_csv(package const &pkg) {
std::string result = pkg.identifier;
for(auto &&el: pkg.data) {
result += ",\""+el+"\"";
}
return result;
}
template<typename T>
package make_package(std::string const &id, T const &msg) {
return package {
id, msg.as_strings()
};
}
template<typename T>
package to_package(T const &msg) {
return make_package(
boost::typeindex::type_id<T>().pretty_name(), msg);
}
}
main.cpp
:
#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <functional>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/classification.hpp>
#include "socket.hpp"
#include "communication.hpp"
namespace command {
struct unit {
std::string who, what, details;
static unit from(communication::strings const strings) {
return { strings[0], strings[1], strings[2] };
}
communication::strings as_strings() const {
return { who, what, details };
}
};
struct system {
std::string function, input;
static system from(communication::strings const strings) {
return { strings[0], strings[1] };
}
communication::strings as_strings() const {
return { function, input };
}
};
}
std::vector<std::string> split_csv(std::string const &csv) {
std::vector<std::string> result;
boost::split(result, csv, boost::is_any_of(","), boost::token_compress_on);
return result;
}
std::string without_quotes(std::string const &str) {
return str.at(0) == '\"'?
std::string(std::begin(str)+1, std::end(str)-1) : str;
}
void inspect(std::string const &data) {
std::cout << "##INSPECTION: BEGIN\n" << "(raw data:)\n" << data << "\n";
auto splitted = split_csv(data);
std::cout << "(splitted:)\n";
for(auto el: split_csv(data)) {
std::cout << without_quotes(el) << "\n";
}
std::cout << "##INSPECTION: END\n";
}
using handler = std::function<void(communication::strings const &)>;
using handlers_map = std::unordered_map<std::string, handler>;
void handle(handlers_map const &handlers, std::string const &data) {
auto strings = split_csv(data);
handlers.at(strings[0])
(communication::strings(std::begin(strings)+1, std::end(strings)));
}
int main() {
using namespace communication;
mock::socket socket {{
to_csv(to_package(command::unit {
"piekarz", "wstaw 9", "bulki janka"
})),
to_csv(to_package(command::unit {
"piekarz", "wyjmij 27", "bagietki z pieca"
})),
to_csv(to_package(command::system {
"print", "Hello World!"
}))
}};
handlers_map handlers {
{{"command::unit"}, [](communication::strings const &strings) {
auto cmd = command::unit::from(strings);
std::cout << "\n>> todo: recognize and launch unit command\n";
}},
{{"command::system"}, [](communication::strings const &strings) {
auto cmd = command::system::from(strings);
std::cout << "\n>> todo: recognize and launch system command\n";
}}
};
std::string data;
while((data = fetch_next(socket)).size()){
inspect(data);
handle(handlers, data);
std::cout << std::endl;
}
return 0;
}
link: http://melpon.org/wandbox/permlink/g1hdapMODrPrN9cA
output:
##INSPECTION: BEGIN
(raw data:)
command::unit,"piekarz","wstaw 9","bulki janka"
(splitted:)
command::unit
piekarz
wstaw 9
bulki janka
##INSPECTION: END
>> todo: recognize and launch unit command
##INSPECTION: BEGIN
(raw data:)
command::unit,"piekarz","wyjmij 27","bagietki z pieca"
(splitted:)
command::unit
piekarz
wyjmij 27
bagietki z pieca
##INSPECTION: END
>> todo: recognize and launch unit command
##INSPECTION: BEGIN
(raw data:)
command::system,"print","Hello World!"
(splitted:)
command::system
print
Hello World!
##INSPECTION: END
>> todo: recognize and launch system command
To, co powinieneś teraz zrobić, to napisać obsługę rozpoznanych komend (operując na gotowych command::unit i command::system lub na czymkolwiek co sobie dorzucisz)
PS. wstaw 9
możesz przetrawić przy pomocy stringstream
PPS. Jestem dopiero w połowie 3 sezonu :P