diff --git a/src/env_fake.cpp b/src/env_fake.cpp new file mode 100644 index 0000000..d859629 --- /dev/null +++ b/src/env_fake.cpp @@ -0,0 +1,129 @@ +/* Copyright 2020, Michele Santullo + * This file is part of user-gcc. + * + * User-gcc is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * User-gcc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with user-gcc. If not, see . + */ + +#include "env_fake.hpp" +#include "to_var_map.hpp" +#include "safe_print.hpp" +#include "string_view_cat.hpp" +#include +#include +#include +#include +#include +#include + +namespace duck { +namespace { + template < + typename M, + typename I, + typename F, + typename R=decltype(std::declval()(std::declval().find(std::declval()))&>())), + //not supposed to be altered by the caller + bool FIsNoex=noexcept(std::declval()(std::declval().find(std::declval()))&>())) and noexcept(R()) + > + R run_if_found (M& map, const I& item, F func) noexcept(FIsNoex) { + typedef decltype(map.find(item)) iterator_type; + + iterator_type it_found; + if constexpr (FIsNoex) { + try { + it_found = map.find(item); + } + catch (...) { + safe_print_error("Unexpected exception in run_if_found() will be ignored"); + } + } + else { + it_found = map.find(item); + } + + if constexpr (std::is_same::value) { + if (map.end() != it_found) { + func(it_found); + } + } + else { + if (map.end() != it_found) { + return func(it_found); + } + else { + return R{}; + } + } + } +} //unnamed namespace + +EnvFake::EnvFake (bool starts_empty) : + m_map_strong_cpy(), + m_map(starts_empty ? map_type() : to_var_map_ignore_ownership(environ)) +{ +} + +std::optional EnvFake::get (std::string_view name) const noexcept { + return run_if_found(m_map, name, [](auto& it)noexcept{return std::make_optional(it->second);}); +} + +std::string_view EnvFake::get (std::string_view name, std::string_view def) const noexcept { + bool ret_def{true}; + std::string_view maybe_ret(run_if_found(m_map, name, [&ret_def](auto& it)noexcept{ret_def=false; return it->second;})); + if (ret_def) + return def; + else + return maybe_ret; +} + +void EnvFake::set (std::string_view name, std::string_view value) { + assert(not name.empty()); + if (name.empty()) + return; + + const std::size_t size = name.size() + value.size(); + std::unique_ptr buff = std::make_unique(size); + std::copy(name.begin(), name.end(), buff.get()); + std::copy(value.begin(), value.end(), buff.get() + name.size()); + + const std::string_view new_name(buff.get(), name.size()); + assert(new_name == name); + 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()); +} + +void EnvFake::unset (std::string_view name) noexcept { + run_if_found(m_map, name, [&](auto& it)noexcept{m_map.erase(it);}); + run_if_found(m_map_strong_cpy, name, [&](auto& it)noexcept{m_map_strong_cpy.erase(it);}); +} + +bool EnvFake::is_set (std::string_view name) const noexcept { + return run_if_found(m_map, name, [](auto&)noexcept{return true;}); +} + +auto EnvFake::size() const noexcept -> size_type { + return m_map.size(); +} + +void EnvFake::clear() noexcept { + m_map.clear(); + m_map_strong_cpy.clear(); +} + +} //namespace duck diff --git a/src/env_fake.hpp b/src/env_fake.hpp new file mode 100644 index 0000000..75fd1f8 --- /dev/null +++ b/src/env_fake.hpp @@ -0,0 +1,43 @@ +/* Copyright 2020, Michele Santullo + * This file is part of user-gcc. + * + * User-gcc is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * User-gcc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with user-gcc. If not, see . + */ + +#pragma once + +#include "env_base.hpp" +#include +#include + +namespace duck { + class EnvFake : public EnvBase { + typedef std::unordered_map map_type; + public: + explicit EnvFake (bool starts_empty=false); + ~EnvFake() noexcept = default; + + virtual std::optional 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; + + private: + std::unordered_map> m_map_strong_cpy; + map_type m_map; + }; +} //namespace duck diff --git a/src/meson.build b/src/meson.build index 8a762d8..2f547ed 100644 --- a/src/meson.build +++ b/src/meson.build @@ -21,6 +21,7 @@ executable(meson.project_name(), 'var_map.cpp', 'env_base.cpp', 'env_real.cpp', + 'env_fake.cpp', 'safe_print.cpp', install: true, dependencies: [fslib_dep],