-
Notifications
You must be signed in to change notification settings - Fork 3
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
[Environment] Generic approach with process_env #63
Comments
It might be a better idea to make |
Version for a string list: template<typename R>
requires (
requires(ranges::range_value_t<R> r) {{r} -> convertible_to< string_view>;} ||
requires(ranges::range_value_t<R> r) {{r} -> convertible_to< wstring_view>;} ||
requires(ranges::range_value_t<R> r) {{r} -> convertible_to< u8string_view>;} ||
requires(ranges::range_value_t<R> r) {{r} -> convertible_to<u16string_view>;} ||
requires(ranges::range_value_t<R> r) {{r} -> convertible_to<u32string_view>;}
)
struct process_env {
process_env( const R & data);
process_env( const R & data, const std::locale & loc);
template<typename T>
process_env( initializer_list<T> data);// -> process_env<initializer_list<T>> ;
template<typename T>
process_env( initializer_list<T> data, const std::locale & loc);// -> process_env<initializer_list<T>>;
};
template<typename T>
process_env( initializer_list<T> data) -> process_env<initializer_list<T>> ;
template<typename T>
process_env( initializer_list<T> data, const locale & loc) -> process_env<initializer_list<T>>; |
The thing might work, but adding an |
Alright, made it readable, will adapt it for #67. It is turning out big: template<typename T>
concept convertible_to_string_view =
convertible_to<T, string_view> || convertible_to<T, wstring_view> || convertible_to<T, u8string_view> || convertible_to<T, u16string_view> || convertible_to<T, u32string_view> ;
template<typename T>
requires convertible_to_string_view<T> ||
(requires (T t)
{
{tuple_size<T>{}} -> convertible_to<integral_constant<size_t,2u>>;
{get<0>(t)} -> convertible_to_string_view;
{get<1>(t)} -> convertible_to_string_view;
} ||
requires (T t)
{
{tuple_size<T>{}} -> convertible_to<integral_constant<size_t,2u>>;
{get<0>(t)} -> convertible_to_string_view;
{get<1>(t)} -> ranges::range;
{*ranges::begin(get<1>(t))} -> convertible_to_string_view;
})
class process_env {
public:
process_env();
process_env(initializer_list<T> r);
process_env(initializer_list<T> r, const std::locale & loc);
template<ranges::range Range>
requires(convertible_to<ranges::range_value_t<Range>, T>)
process_env(Range r);
template<ranges::range Range>
requires(convertible_to<ranges::range_value_t<Range>, T>)
process_env(Range r, const std::locale & loc);
template<input_iterator InputIt>
requires(convertible_to<typename iterator_traits<InputIt>::value_type, T>)
process_env(InputIt first, InputIt last);
template<input_iterator InputIt>
requires(convertible_to<typename iterator_traits<InputIt>::value_type, T>)
process_env(InputIt first, InputIt last, const std::locale & loc);
};
template<ranges::range Range>
process_env(Range r) -> process_env<ranges::range_value_t<Range>>;
template<ranges::range Range>
process_env(Range && r, const std::locale & loc) -> process_env<ranges::range_value_t<Range>>;
template<input_iterator InputIt>
process_env(InputIt first, InputIt last) -> process_env<typename iterator_traits<InputIt>::value_type>;
template<input_iterator InputIt>
process_env(InputIt first, InputIt last, const std::locale & loc) -> process_env<typename iterator_traits<InputIt>::value_type>;
process_env(initializer_list<pair< string_view, string_view>> r) -> process_env<pair< string_view, string_view>>;
process_env(initializer_list<pair< wstring_view, wstring_view>> r) -> process_env<pair< wstring_view, wstring_view>>;
process_env(initializer_list<pair< u8string_view, u8string_view>> r) -> process_env<pair< u8string_view, u8string_view>>;
process_env(initializer_list<pair<u16string_view, u16string_view>> r) -> process_env<pair<u16string_view, u16string_view>>;
process_env(initializer_list<pair<u32string_view, u32string_view>> r) -> process_env<pair<u32string_view, u32string_view>>;
process_env(initializer_list<pair< string_view, initializer_list< string_view>>> r) -> process_env<pair< string_view, initializer_list< string_view>>>;
process_env(initializer_list<pair< wstring_view, initializer_list< wstring_view>>> r) -> process_env<pair< wstring_view, initializer_list< wstring_view>>>;
process_env(initializer_list<pair< u8string_view, initializer_list< u8string_view>>> r) -> process_env<pair< u8string_view, initializer_list< u8string_view>>>;
process_env(initializer_list<pair<u16string_view, initializer_list<u16string_view>>> r) -> process_env<pair<u16string_view, initializer_list<u16string_view>>>;
process_env(initializer_list<pair<u32string_view, initializer_list<u32string_view>>> r) -> process_env<pair<u32string_view, initializer_list<u32string_view>>>; |
I got a rudimentary implementation of this template<typename T>
concept convertible_to_string_view =
convertible_to<T, string_view> || convertible_to<T, wstring_view> || convertible_to<T, u8string_view> || convertible_to<T, u16string_view> || convertible_to<T, u32string_view> ;
class process_env {
public:
template<typename Char>
constexpr static Char list_seperator = implementation-defined;
template<convertible_to_string_view T>
process_env(initializer_list<T> r);
template<convertible_to_string_view T>
process_env(initializer_list<T> r, const std::locale & loc);
template<ranges::range Range>
requires(convertible_to_string_view<ranges::range_value_t<Range>>)
process_env(Range r);
template<ranges::range Range>
requires(convertible_to_string_view<ranges::range_value_t<Range>>)
process_env(Range r, const std::locale & loc);
template<input_iterator InputIt>
requires(convertible_to_string_view<typename iterator_traits<InputIt>::value_type>)
process_env(InputIt first, InputIt last);
template<input_iterator InputIt>
requires(convertible_to_string_view<typename iterator_traits<InputIt>::value_type>)
process_env(InputIt first, InputIt last, const std::locale & loc);
}; This is much simpler and should seamlessly work with a a third party |
apologies for being so far behind you on this. I think this is exactly the correct direction -- in particular the range based approach. Let me address a few points
|
|
Ok. I haven't followed in detail the discussions about filesystem::path on the committee level, but it seems like it is able to do some magic w.r.t. this -- but maybe that's in a proposed replacement, will have to check. The good news is that since Elias and I have already briefed this a couple times we can get SG16 to tell us what they'd like us to do with this stuff to be compatible with the upcoming unicode support directions. |
Right, whatever the current convention is works for me. We need to convert to |
comment 723703925 is a good insight, and the creation of a process_env should be possible in that manner. But what if the user wants to manipulate the environment variables definitions computationally before creating a child-process? I suspect that most users will at some point create containers to combine/manipulate the environment variables contents. That results in string operations like splitting (O(N)) e.g. the PATH variables paths. That might happen only once. But joining them again to a string (O(N)) might occur more often, frustrating the user. Another thing that comes in my mind is the question, what should happen if multiple definitions of the same environment variable are passed to the constructor? |
If you manipulate the environment you will need to rebuild the environment for the child process anyhow. In linux it's a This means that you can get away without copies on linux, by just taking the pointer from a I did simplifiy the actually proposed version to just take a range of string_views and not the other stuff, so there would be no splitting going on unless explicitly requested by the users. That is unless he wants to modify the strings. |
I would leave the handling of multiple keys up to the implementation. Could be an overwrite or a system_error I reckon. |
Reading all the comments I forgot what this issue was all about -> just the creation of a process env for the child...so you are right, the problem only occurs when the user accesses the environment of the current process and manipulates in some way. |
I don't think we can rely on
P1275R0
to be standardized (I think the globalstd::arguments
will not be accepted) I think we should have a more generic approach to passing environments into a process, than relying on once class. We could add aninitializer
, e.g.process_env
or have a full featuredenvironment
class.The big need of environment functions arises on the side of the child process, i.e. when a child queries it's own environment. For example, searching for an executable that emulates the shell behaviour would be quite common for starting processes, but is quite different between platforms:
On windows, a certain file name is search in the
PATH
(orPath
sometimes) variable with the addition of the extensions available inPATHEXT
. On posix no such extensions exist, thus a function likestd::vector<std::filesystem::path> std::this_process::env::find_executable(std::string & name)
.Similarly, one might want to get the default shell of the OS, which on posix is stored in
SHELL
while it's deducable throughwindir
on windows. This could be handled by astd::filesystem::path std::this_process::env::shell()
function.It is to now however, that this information is queried before process start and thus usually queried from the father environment. Thus adding those specialized functions to an environment that is used to initialize a child process, should be considered of little to no priority. If another paper does provide such a class, we should support it.
If we discount specific values in an environment, what are the semantics ?
=
=
is a unique key=
is the value, that is a:
(posix) or;
(windows) seperated list.With these three characteristics we can define what types are acceptable as an environment to be set by the
process_env
:range<convertible_to<string_view>>
range<convertible_to<pair<string_view, string_view>>
range<convertible_to<pair<string_view, range<string_view>>>
This this overloaded we can now use different containers, e.g.
vector<string>
,unordered_map<string, string>
andunordered_map<string, vector<string>>
.The environment class proposed in P1275R0 does fulfill the first constraint as well.
The text was updated successfully, but these errors were encountered: