Allow copy-assigning one Env object to the other.
This commit is contained in:
parent
dfefed1516
commit
01e40d297e
9 changed files with 189 additions and 20 deletions
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue