Allow copy-assigning one Env object to the other.

This commit is contained in:
King_DuckZ 2020-04-13 19:04:15 +02:00
parent dfefed1516
commit 01e40d297e
9 changed files with 189 additions and 20 deletions

View file

@ -17,8 +17,56 @@
#include "env_base.hpp" #include "env_base.hpp"
#include "string_view_cat.hpp" #include "string_view_cat.hpp"
#include "safe_print.hpp"
#include <stdexcept>
#include <type_traits>
namespace duck { namespace duck {
namespace {
template <typename F, typename R=decltype(std::declval<F>()())>
R call_noexcept (F func, std::string_view err_location) noexcept {
typedef R return_type;
try {
return func();
}
catch (const std::runtime_error& err) {
safe_print_error("Unexpected exception in ");
safe_print_error(err_location);
safe_print_error(": ");
safe_print_error_ln(err.what());
}
catch (...) {
safe_print_error("Unknown exception in ");
safe_print_error_ln(err_location);
}
if constexpr (not std::is_same<void, return_type>::value)
return return_type{};
}
} //unnamed namespace
class StdMutex : public EnvBase::Mutex {
public:
StdMutex (std::mutex& m) noexcept :
m_mutex(m)
{
}
virtual void lock() override { m_mutex.lock(); }
virtual void try_lock() override {m_mutex.try_lock(); }
virtual void unlock() noexcept override {m_mutex.unlock(); }
private:
std::mutex& m_mutex;
};
class EmptyMutex : public EnvBase::Mutex {
public:
EmptyMutex() noexcept = default;
virtual void lock() override { }
virtual void try_lock() override { }
virtual void unlock() noexcept override { }
};
bool EnvBase::empty() const noexcept { bool EnvBase::empty() const noexcept {
return 0 == this->size(); return 0 == this->size();
} }
@ -38,4 +86,26 @@ detail::EnvVarProxy<std::string> EnvBase::operator[] (std::string&& name) noexce
detail::EnvVarProxy<std::string> EnvBase::operator[] (const std::string& name) noexcept { detail::EnvVarProxy<std::string> EnvBase::operator[] (const std::string& name) noexcept {
return {to_string(name), this}; return {to_string(name), this};
} }
void EnvBase::set (std::string_view name, std::string_view value) {
StdMutex m(this->mutex());
this->set_implem(name, value, m);
}
void EnvBase::set_nolock (EnvBase& obj, std::string_view name, std::string_view value) {
EmptyMutex m;
obj.set_implem(name, value, m);
}
void EnvBase::clear() noexcept {
StdMutex m(this->mutex());
call_noexcept([this,&m](){this->clear_implem(m);}, to_string_view(__func__));
return;
}
void EnvBase::clear_nolock (EnvBase& obj) noexcept {
EmptyMutex m;
call_noexcept([&](){obj.clear_implem(m);}, to_string_view(__func__));
return;
}
} //namespace duck } //namespace duck

View file

@ -20,6 +20,7 @@
#include <string_view> #include <string_view>
#include <optional> #include <optional>
#include <utility> #include <utility>
#include <mutex>
namespace duck { namespace duck {
class EnvBase; class EnvBase;
@ -47,6 +48,13 @@ namespace duck {
typedef std::size_t size_type; typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type; typedef std::ptrdiff_t difference_type;
struct Mutex {
virtual ~Mutex() noexcept = default;
virtual void lock() = 0;
virtual void try_lock() = 0;
virtual void unlock() noexcept = 0;
};
EnvBase() = default; EnvBase() = default;
EnvBase (const EnvBase&) = delete; EnvBase (const EnvBase&) = delete;
EnvBase (EnvBase&&) = delete; EnvBase (EnvBase&&) = delete;
@ -59,12 +67,22 @@ namespace duck {
virtual std::optional<std::string_view> get (std::string_view name) const noexcept = 0; virtual std::optional<std::string_view> get (std::string_view name) const noexcept = 0;
virtual std::string_view get (std::string_view name, std::string_view def) const noexcept = 0; virtual std::string_view get (std::string_view name, std::string_view def) const noexcept = 0;
virtual void set (std::string_view name, std::string_view value) = 0; void set (std::string_view name, std::string_view value);
virtual void unset (std::string_view name) noexcept = 0; virtual void unset (std::string_view name) noexcept = 0;
virtual bool is_set (std::string_view name) const noexcept = 0; virtual bool is_set (std::string_view name) const noexcept = 0;
virtual size_type size() const noexcept = 0; virtual size_type size() const noexcept = 0;
virtual bool empty() const noexcept; virtual bool empty() const noexcept;
virtual void clear() noexcept = 0; void clear() noexcept;
virtual std::mutex& mutex() noexcept = 0;
protected:
virtual void set_all_into (EnvBase& other) const = 0;
static void set_all_into (const EnvBase& obj, EnvBase& other) { obj.set_all_into(other); }
virtual void clear_implem(Mutex& m) = 0;
static void clear_nolock (EnvBase& obj) noexcept;
virtual void set_implem (std::string_view name, std::string_view value, Mutex& m) = 0;
static void set_nolock (EnvBase& obj, std::string_view name, std::string_view value);
}; };
namespace detail { namespace detail {

View file

@ -87,7 +87,7 @@ std::string_view EnvFake::get (std::string_view name, std::string_view def) cons
return maybe_ret; return maybe_ret;
} }
void EnvFake::set (std::string_view name, std::string_view value) { void EnvFake::set_implem (std::string_view name, std::string_view value, Mutex& m) {
assert(not name.empty()); assert(not name.empty());
if (name.empty()) if (name.empty())
return; return;
@ -102,10 +102,13 @@ void EnvFake::set (std::string_view name, std::string_view value) {
const std::string_view new_value(buff.get() + name.size(), value.size()); const std::string_view new_value(buff.get() + name.size(), value.size());
assert(new_value == value); assert(new_value == value);
m_map_strong_cpy.insert_or_assign(std::string_view(new_name), std::move(buff)); {
m_map.insert_or_assign(std::string_view(new_name), std::string_view(new_value)); std::lock_guard<Mutex> lock(m);
assert(m_map.at(name) == value); m_map_strong_cpy.insert_or_assign(std::string_view(new_name), std::move(buff));
assert(m_map.find(name)->first.data() == new_name.data()); m_map.insert_or_assign(std::string_view(new_name), std::string_view(new_value));
assert(m_map.at(name) == value);
assert(m_map.find(name)->first.data() == new_name.data());
}
} }
void EnvFake::unset (std::string_view name) noexcept { void EnvFake::unset (std::string_view name) noexcept {
@ -121,7 +124,8 @@ auto EnvFake::size() const noexcept -> size_type {
return m_map.size(); return m_map.size();
} }
void EnvFake::clear() noexcept { void EnvFake::clear_implem(Mutex& m) {
std::lock_guard<Mutex> lock(m);
m_map.clear(); m_map.clear();
m_map_strong_cpy.clear(); m_map_strong_cpy.clear();
} }
@ -141,4 +145,22 @@ auto EnvFake::end() const -> const_iterator {
auto EnvFake::cend() const -> const_iterator { auto EnvFake::cend() const -> const_iterator {
return m_map.cend(); return m_map.cend();
} }
std::mutex& EnvFake::mutex() noexcept {
return m_mutex;
}
void EnvFake::set_all_into (EnvBase& other) const {
std::scoped_lock lock(m_mutex, other.mutex());
EnvBase::clear_nolock(other);
for (const auto& keyval : *this) {
EnvBase::set_nolock(other, keyval.first, keyval.second);
}
}
EnvFake& EnvFake::operator= (const EnvBase& other) {
EnvBase::set_all_into(other, *this);
return *this;
}
} //namespace duck } //namespace duck

View file

@ -20,6 +20,7 @@
#include "env_base.hpp" #include "env_base.hpp"
#include <unordered_map> #include <unordered_map>
#include <memory> #include <memory>
#include <mutex>
namespace duck { namespace duck {
class EnvFake : public EnvBase { class EnvFake : public EnvBase {
@ -30,21 +31,29 @@ namespace duck {
explicit EnvFake (bool starts_empty=false); explicit EnvFake (bool starts_empty=false);
~EnvFake() noexcept = default; ~EnvFake() noexcept = default;
EnvFake& operator= (const EnvBase& other);
virtual std::optional<std::string_view> get (std::string_view name) const noexcept override; virtual std::optional<std::string_view> get (std::string_view name) const noexcept override;
virtual std::string_view get (std::string_view name, std::string_view def) const noexcept override; virtual std::string_view get (std::string_view name, std::string_view def) const noexcept override;
virtual void set (std::string_view name, std::string_view value) override;
virtual void unset (std::string_view name) noexcept override; virtual void unset (std::string_view name) noexcept override;
virtual bool is_set (std::string_view name) const noexcept override; virtual bool is_set (std::string_view name) const noexcept override;
virtual size_type size() const noexcept override; virtual size_type size() const noexcept override;
virtual void clear() noexcept override;
const_iterator begin() const; const_iterator begin() const;
const_iterator cbegin() const; const_iterator cbegin() const;
const_iterator end() const; const_iterator end() const;
const_iterator cend() const; const_iterator cend() const;
virtual std::mutex& mutex() noexcept override;
protected:
virtual void set_all_into (EnvBase& other) const override;
virtual void clear_implem(Mutex& m) override;
virtual void set_implem (std::string_view name, std::string_view value, Mutex& m) override;
private: private:
std::unordered_map<std::string_view, std::unique_ptr<char[]>> m_map_strong_cpy; std::unordered_map<std::string_view, std::unique_ptr<char[]>> m_map_strong_cpy;
map_type m_map; map_type m_map;
mutable std::mutex m_mutex;
}; };
} //namespace duck } //namespace duck

View file

@ -40,10 +40,10 @@ namespace {
const constexpr std::size_t g_name_buff_len = 128; const constexpr std::size_t g_name_buff_len = 128;
PointerMap& pointer_map(); PointerMap& pointer_map() noexcept;
class PointerMap { class PointerMap {
friend PointerMap& pointer_map(); friend PointerMap& pointer_map() noexcept;
public: public:
PointerMap (const PointerMap&) = delete; PointerMap (const PointerMap&) = delete;
PointerMap (PointerMap&&) = delete; PointerMap (PointerMap&&) = delete;
@ -70,7 +70,7 @@ namespace {
static void value() noexcept {} static void value() noexcept {}
}; };
PointerMap& pointer_map() { PointerMap& pointer_map() noexcept {
static PointerMap pm; static PointerMap pm;
return pm; return pm;
} }
@ -204,6 +204,11 @@ EnvReal::EnvReal() :
{ {
} }
EnvReal& EnvReal::operator= (const EnvBase& other) {
EnvBase::set_all_into(other, *this);
return *this;
}
std::optional<std::string_view> EnvReal::get (std::string_view name) const noexcept { std::optional<std::string_view> EnvReal::get (std::string_view name) const noexcept {
const char* const ret = this->raw_fetch_env(name); const char* const ret = this->raw_fetch_env(name);
if (ret) if (ret)
@ -220,7 +225,7 @@ std::string_view EnvReal::get (std::string_view name, std::string_view def) cons
return def; return def;
} }
void EnvReal::set (std::string_view name, std::string_view value) { void EnvReal::set_implem (std::string_view name, std::string_view value, Mutex& m) {
assert(not name.empty()); assert(not name.empty());
if (name.empty()) if (name.empty())
return; return;
@ -236,7 +241,7 @@ void EnvReal::set (std::string_view name, std::string_view value) {
{ {
auto& pm = pointer_map(); auto& pm = pointer_map();
std::lock_guard<std::mutex> lock(pm.env_mutex()); std::lock_guard<Mutex> lock(m);
putenv(pm.register_pointer(std::move(new_var))); putenv(pm.register_pointer(std::move(new_var)));
} }
} }
@ -272,9 +277,9 @@ auto EnvReal::size() const noexcept -> size_type {
return z; return z;
} }
void EnvReal::clear() noexcept { void EnvReal::clear_implem(Mutex& m) {
auto& pm = pointer_map(); auto& pm = pointer_map();
std::lock_guard<std::mutex> lock(pm.env_mutex()); std::lock_guard<Mutex> lock(m);
const int r = clearenv(); const int r = clearenv();
if (not r) { if (not r) {
pm.clear(); pm.clear();
@ -315,4 +320,18 @@ auto EnvReal::cend() const -> const_iterator {
assert(*(::environ + this->size()) == nullptr); assert(*(::environ + this->size()) == nullptr);
return {::environ + this->size()}; return {::environ + this->size()};
} }
std::mutex& EnvReal::mutex() noexcept {
return pointer_map().env_mutex();
}
void EnvReal::set_all_into (EnvBase& other) const {
auto& pm = pointer_map();
std::scoped_lock lock(pm.env_mutex(), other.mutex());
EnvBase::clear_nolock(other);
for (const auto& keyval : *this) {
EnvBase::set_nolock(other, keyval.first, keyval.second);
}
}
} //namespace duck } //namespace duck

View file

@ -52,19 +52,26 @@ namespace duck {
EnvReal(); EnvReal();
virtual ~EnvReal() noexcept = default; virtual ~EnvReal() noexcept = default;
EnvReal& operator= (const EnvBase& other);
virtual std::optional<std::string_view> get (std::string_view name) const noexcept override; virtual std::optional<std::string_view> get (std::string_view name) const noexcept override;
virtual std::string_view get (std::string_view name, std::string_view def) const noexcept override; virtual std::string_view get (std::string_view name, std::string_view def) const noexcept override;
virtual void set (std::string_view name, std::string_view value) override;
virtual void unset (std::string_view name) noexcept override; virtual void unset (std::string_view name) noexcept override;
virtual bool is_set (std::string_view name) const noexcept override; virtual bool is_set (std::string_view name) const noexcept override;
virtual size_type size() const noexcept override; virtual size_type size() const noexcept override;
virtual void clear() noexcept override;
const_iterator begin() const; const_iterator begin() const;
const_iterator cbegin() const; const_iterator cbegin() const;
const_iterator end() const; const_iterator end() const;
const_iterator cend() const; const_iterator cend() const;
virtual std::mutex& mutex() noexcept override;
protected:
virtual void set_all_into (EnvBase& other) const override;
virtual void clear_implem(Mutex& m) override;
virtual void set_implem (std::string_view name, std::string_view value, Mutex& m) override;
private: private:
const char* raw_fetch_env (std::string_view name) const noexcept; const char* raw_fetch_env (std::string_view name) const noexcept;

View file

@ -21,13 +21,29 @@
namespace duck { namespace duck {
void safe_print (std::string_view msg) noexcept { void safe_print (std::string_view msg) noexcept {
try { try {
std::cout << msg << std::endl; std::cout << msg;
} }
catch (...) { catch (...) {
} }
} }
void safe_print_error (std::string_view msg) noexcept { void safe_print_error (std::string_view msg) noexcept {
try {
std::cerr << msg;
}
catch (...) {
}
}
void safe_print_ln (std::string_view msg) noexcept {
try {
std::cout << msg << std::endl;
}
catch (...) {
}
}
void safe_print_error_ln (std::string_view msg) noexcept {
try { try {
std::cerr << msg << std::endl; std::cerr << msg << std::endl;
} }

View file

@ -22,4 +22,7 @@
namespace duck { namespace duck {
void safe_print (std::string_view msg) noexcept; void safe_print (std::string_view msg) noexcept;
void safe_print_error (std::string_view msg) noexcept; void safe_print_error (std::string_view msg) noexcept;
void safe_print_ln (std::string_view msg) noexcept;
void safe_print_error_ln (std::string_view msg) noexcept;
} //namespace duck } //namespace duck

View file

@ -37,6 +37,11 @@ namespace duck {
return (str ? std::string_view{str} : std::string_view{""}); return (str ? std::string_view{str} : std::string_view{""});
} }
template <std::size_t S>
inline std::string_view to_string_view (const char (&str)[S]) noexcept {
return std::string_view(str, S);
}
inline std::string operator+ (std::string_view a, std::string_view b) { inline std::string operator+ (std::string_view a, std::string_view b) {
std::string ret(to_string(a)); std::string ret(to_string(a));
ret += b; ret += b;