Skip to content

Add iterator to pini #4

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 3 commits into from
Jul 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
22 changes: 20 additions & 2 deletions include/pini/pini.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <cstddef>
#include <cstdint>
#include <filesystem>
#include <sstream>
Expand All @@ -16,6 +17,13 @@ class pini {
bool load_file(std::filesystem::path const& filename);
bool load_text(std::string_view text);

// iteration

using const_iterator = map_type::const_iterator;

const_iterator begin() const { return key_value_pairs.begin(); }
const_iterator end() const { return key_value_pairs.end(); }

// return double
double get_double(std::string const& key, double def = 0) const;
// return unsigned 64 bit integer - <unsigned long long>
Expand All @@ -31,11 +39,21 @@ class pini {
std::string_view get_string(std::string const& key) const;

enum class severity { error, warn, info };
using on_msg = void (*)(std::string_view, severity);
using on_msg_t = void (*)(std::string_view, severity);
static void default_callback(std::string_view msg, severity level);
inline static on_msg on_msg_t = &default_callback;
inline static on_msg_t on_msg = &default_callback;

bool is_empty() const { return key_value_pairs.empty(); }
std::size_t size() const { return key_value_pairs.size(); }
void clear();
const_iterator erase(const_iterator pos);
const_iterator erase(const_iterator first, const_iterator last);
std::size_t erase(std::string const& key);
bool contains(std::string const& key) const;

private:
map_type key_value_pairs;
};
// implementation starts here
inline bool pini::contains(std::string const& key) const { return key_value_pairs.find(key) != key_value_pairs.end(); }
} // namespace pn
7 changes: 4 additions & 3 deletions include/pini/util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
#include <unordered_map>
#include <vector>

namespace util {

namespace pn::util {
// return vector of strings containing each line of the given file
std::vector<std::string> get_lines(std::filesystem::path const& filename);

Expand All @@ -22,7 +23,7 @@ std::string_view trim_whitespace(std::string_view str);

// data conversions:

double string_to_double(std::string const& str, std::uint64_t def = 0);
double string_to_double(std::string const& str, double def = 0);

std::uint64_t string_to_uint64(std::string const& str, std::uint64_t def = 0);

Expand All @@ -32,4 +33,4 @@ std::uint32_t string_to_uint32(std::string const& str, std::uint64_t def = 0);

std::int32_t string_to_int32(std::string const& str, std::uint64_t def = 0);

} // namespace util
} // namespace pn::util
21 changes: 13 additions & 8 deletions src/pini.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ bool pini::load_text(std::string_view text) {
double pini::get_double(std::string const& key, double def) const {
auto it = key_value_pairs.find(key);
if (it == key_value_pairs.end()) {
if (pn::pini::on_msg_t) {
if (pn::pini::on_msg) {
std::stringstream str;
str << "Key \"" << key << "\" not found.\n";
(*pn::pini::on_msg_t)(str.str(), pn::pini::severity::warn);
(*pn::pini::on_msg)(str.str(), pn::pini::severity::warn);
}
return def;
}
Expand All @@ -49,20 +49,20 @@ double pini::get_double(std::string const& key, double def) const {

std::uint64_t pini::get_uint64(std::string const& key, std::uint64_t def) const {
if (auto it = key_value_pairs.find(key); it != key_value_pairs.end()) { return util::string_to_uint64(it->second); }
if (pn::pini::on_msg_t) {
if (pn::pini::on_msg) {
std::stringstream str;
str << "Key \"" << key << "\" not found.\n";
(*pn::pini::on_msg_t)(str.str(), pn::pini::severity::warn);
(*pn::pini::on_msg)(str.str(), pn::pini::severity::warn);
}
return def;
}

std::int64_t pini::get_int64(std::string const& key, std::int64_t def) const {
if (auto it = key_value_pairs.find(key); it != key_value_pairs.end()) { return util::string_to_int32(it->second); }
if (pn::pini::on_msg_t) {
if (pn::pini::on_msg) {
std::stringstream str;
str << "Key \"" << key << "\" not found.\n";
(*pn::pini::on_msg_t)(str.str(), pn::pini::severity::warn);
(*pn::pini::on_msg)(str.str(), pn::pini::severity::warn);
}
return def;
}
Expand All @@ -74,10 +74,10 @@ std::int32_t pini::get_int32(std::string const& key, std::uint32_t def) const {
std::string_view pini::get_string(std::string const& key) const {
auto it = key_value_pairs.find(key);
if (it == key_value_pairs.end()) {
if (pn::pini::on_msg_t) {
if (pn::pini::on_msg) {
std::stringstream str;
str << "Key \"" << key << "\" not found.\n";
(*pn::pini::on_msg_t)(str.str(), pn::pini::severity::warn);
(*pn::pini::on_msg)(str.str(), pn::pini::severity::warn);
}
return {};
}
Expand All @@ -89,4 +89,9 @@ void pini::default_callback(std::string_view msg, severity level) {
out << msg << '\n';
}

void pini::clear() { key_value_pairs.clear(); }
pini::const_iterator pini::erase(pini::const_iterator pos) { return key_value_pairs.erase(pos); }
pini::const_iterator pini::erase(pini::const_iterator first, pini::const_iterator last) { return key_value_pairs.erase(first, last); }
std::size_t pini::erase(std::string const& key) { return key_value_pairs.erase(key); }

} // namespace pn
61 changes: 35 additions & 26 deletions src/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,35 @@
#include <string_view>
#include <pini/pini.hpp>
#include <pini/util.hpp>

namespace util {

std::vector<std::string> get_lines(std::filesystem::path const& filename) {
namespace pn {
std::vector<std::string> util::get_lines(std::filesystem::path const& filename) {
std::vector<std::string> ret;
std::string temp_line;
if (auto file = std::ifstream(filename)) {
while (std::getline(file, temp_line)) { ret.push_back(temp_line); }
} else {
if (pn::pini::on_msg_t) {
if (pn::pini::on_msg) {
std::stringstream str;
str << "File \"" << filename << "\"failed to open \n";
(*pn::pini::on_msg_t)(str.str(), pn::pini::severity::error);
(*pn::pini::on_msg)(str.str(), pn::pini::severity::error);
}
}
return ret;
}

std::unordered_map<std::string, std::string> insert_pairs(std::vector<std::string> file_lines) {
std::unordered_map<std::string, std::string> util::insert_pairs(std::vector<std::string> file_lines) {
std::unordered_map<std::string, std::string> key_value_pairs;
std::size_t line_number = 0;
for (const auto& str : file_lines) {
++line_number;
if (auto delimeter_pos = str.find('='); delimeter_pos != std::string::npos) {
std::string_view const key = trim_whitespace(str.substr(0, delimeter_pos));
if (key.empty() && pn::pini::on_msg_t) {
std::stringstream str;
str << "Line number " << line_number << " is not valid because the key is empty.\n";
(*pn::pini::on_msg_t)(str.str(), pn::pini::severity::warn);
if (key.empty()) {
if (pn::pini::on_msg) {
std::stringstream str;
str << "Line number " << line_number << " is not valid because the key is empty.\n";
(*pn::pini::on_msg)(str.str(), pn::pini::severity::warn);
}
} else {
std::string_view const value = trim_whitespace(str.substr(delimeter_pos + 1));
if (key[0] != '#') { key_value_pairs.insert({std::string(key), std::string(value)}); }
Expand All @@ -42,35 +42,44 @@ std::unordered_map<std::string, std::string> insert_pairs(std::vector<std::strin
return key_value_pairs;
}

std::string_view trim_whitespace(std::string_view str) {
std::string_view util::trim_whitespace(std::string_view str) {
if (str.empty()) { return {}; }
std::size_t start = 0;
std::size_t end = str.size();
std::size_t finish = str.size();
while (std::isspace(str[start])) { ++start; }
while (std::isspace(str[end - 1])) { --end; }
if (end == start) { return str; }
return str.substr(start, end - start);
while (std::isspace(str[finish - 1])) { --finish; }
if (finish == start) { return str; }
return str.substr(start, finish - start);
}

double string_to_double(std::string const& str, std::uint64_t def) {
double ret = std::atof(str.c_str());
return (ret == 0.0) ? def : ret;
double util::string_to_double(std::string const& str, double def) {
try {
return stod(str);
} catch (std::exception const& e) {
if (pini::on_msg) { (*pini::on_msg)(e.what(), pini::severity::warn); }
}
return def;
}

std::uint64_t string_to_uint64(std::string const& str, std::uint64_t def) {
std::uint64_t util::string_to_uint64(std::string const& str, std::uint64_t def) {
try {
return stoull(str);
} catch (std::exception const& e) { std::cerr << e.what() << '\n'; }
} catch (std::exception const& e) {
if (pini::on_msg) { (*pini::on_msg)(e.what(), pini::severity::warn); }
}
return def;
}

std::int64_t string_to_int64(std::string const& str, std::uint64_t def) {
std::int64_t util::string_to_int64(std::string const& str, std::uint64_t def) {
try {
return stoll(str);
} catch (std::exception const& e) { std::cerr << e.what() << '\n'; }
} catch (std::exception const& e) {
if (pini::on_msg) { (*pini::on_msg)(e.what(), pini::severity::warn); }
}
return def;
}

std::uint32_t string_to_uint32(std::string const& str, std::uint64_t def) { return static_cast<std::uint32_t>(string_to_uint64(str, def)); }
std::uint32_t util::string_to_uint32(std::string const& str, std::uint64_t def) { return static_cast<std::uint32_t>(string_to_uint64(str, def)); }

std::int32_t string_to_int32(std::string const& str, std::uint64_t def) { return static_cast<std::int32_t>(string_to_int64(str, def)); }
} // namespace util
std::int32_t util::string_to_int32(std::string const& str, std::uint64_t def) { return static_cast<std::int32_t>(string_to_int64(str, def)); }
} // namespace pn
25 changes: 19 additions & 6 deletions test/pini_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,23 @@
int main() {
pn::pini pin;

std::string_view raw_input{"= 5\n#b=10\n c = 23"};
// std::filesystem::path filename{"/test/test.ini"};
if (!pin.load_text(raw_input)) { return 1; }
std::cout << pin.get_int32("a");
std::cout << pin.get_int32("b");
std::cout << pin.get_int32("c");
// std::string_view raw_input{"= 5\n#b=10\n c = 23"};
std::filesystem::path filename{"/home/nikolaj/projects/cpp/pini/test/test.pini"};
static int ret = 0;
pin.on_msg = [](std::string_view msg, pn::pini::severity level) {
auto& out = level == pn::pini::severity::error ? std::cerr : std::cout;
out << "Custom: || " << msg << '\n';
if (level == pn::pini::severity::error) { ret = 1; }
};
if (!pin.load_file(filename)) { return 1; }
if (pin.is_empty()) { return 1; }
if (pin.contains({})) { return 1; }
if (pin.contains("#comment")) { return 1; }
if (pin.get_int32("health") != 9) { return 1; }

for (auto& pair : pin) { std::cout << pair.first << " " << pair.second << '\n'; }
std::cout << pin.size() << " | " << pin.is_empty();
pin.erase("def");
Copy link
Member

Choose a reason for hiding this comment

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

This needs more failure cases. Like I said before, you aren't going to see any output in automated runs.

for (auto& pair : pin) { std::cout << pair.first << " " << pair.second << '\n'; }
return ret;
}
4 changes: 3 additions & 1 deletion test/test.ini → test/test.pini
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
health = 9
attack = 4.5
def = -9.2314g
= 32
#comment
def = -9.2314
skill points = 8