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 "string_view_cat.hpp"
#include "safe_print.hpp"
#include <stdexcept>
#include <type_traits>
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 {
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 {
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

View file

@ -20,6 +20,7 @@
#include <string_view>
#include <optional>
#include <utility>
#include <mutex>
namespace duck {
class EnvBase;
@ -47,6 +48,13 @@ namespace duck {
typedef std::size_t size_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 (const 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::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 bool is_set (std::string_view name) const noexcept = 0;
virtual size_type size() const noexcept = 0;
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 {

View file

@ -87,7 +87,7 @@ std::string_view EnvFake::get (std::string_view name, std::string_view def) cons
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());
if (name.empty())
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());
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));
assert(m_map.at(name) == value);
assert(m_map.find(name)->first.data() == new_name.data());
{
std::lock_guard<Mutex> lock(m);
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));
assert(m_map.at(name) == value);
assert(m_map.find(name)->first.data() == new_name.data());
}
}
void EnvFake::unset (std::string_view name) noexcept {
@ -121,7 +124,8 @@ auto EnvFake::size() const noexcept -> size_type {
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_strong_cpy.clear();
}
@ -141,4 +145,22 @@ auto EnvFake::end() const -> const_iterator {
auto EnvFake::cend() const -> const_iterator {
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

View file

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

View file

@ -40,10 +40,10 @@ namespace {
const constexpr std::size_t g_name_buff_len = 128;
PointerMap& pointer_map();
PointerMap& pointer_map() noexcept;
class PointerMap {
friend PointerMap& pointer_map();
friend PointerMap& pointer_map() noexcept;
public:
PointerMap (const PointerMap&) = delete;
PointerMap (PointerMap&&) = delete;
@ -70,7 +70,7 @@ namespace {
static void value() noexcept {}
};
PointerMap& pointer_map() {
PointerMap& pointer_map() noexcept {
static PointerMap 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 {
const char* const ret = this->raw_fetch_env(name);
if (ret)
@ -220,7 +225,7 @@ std::string_view EnvReal::get (std::string_view name, std::string_view def) cons
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());
if (name.empty())
return;
@ -236,7 +241,7 @@ void EnvReal::set (std::string_view name, std::string_view value) {
{
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)));
}
}
@ -272,9 +277,9 @@ auto EnvReal::size() const noexcept -> size_type {
return z;
}
void EnvReal::clear() noexcept {
void EnvReal::clear_implem(Mutex& m) {
auto& pm = pointer_map();
std::lock_guard<std::mutex> lock(pm.env_mutex());
std::lock_guard<Mutex> lock(m);
const int r = clearenv();
if (not r) {
pm.clear();
@ -315,4 +320,18 @@ auto EnvReal::cend() const -> const_iterator {
assert(*(::environ + this->size()) == nullptr);
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

View file

@ -52,19 +52,26 @@ namespace duck {
EnvReal();
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::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 bool is_set (std::string_view name) const noexcept override;
virtual size_type size() const noexcept override;
virtual void clear() noexcept override;
const_iterator begin() const;
const_iterator cbegin() const;
const_iterator end() 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:
const char* raw_fetch_env (std::string_view name) const noexcept;

View file

@ -21,13 +21,29 @@
namespace duck {
void safe_print (std::string_view msg) noexcept {
try {
std::cout << msg << std::endl;
std::cout << msg;
}
catch (...) {
}
}
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 {
std::cerr << msg << std::endl;
}

View file

@ -22,4 +22,7 @@
namespace duck {
void safe_print (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

View file

@ -37,6 +37,11 @@ namespace duck {
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) {
std::string ret(to_string(a));
ret += b;