Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:50:13

0001 //
0002 // process/environment.hpp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2021 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 
0010 #ifndef BOOST_PROCESS_V2_ENVIRONMENT_HPP
0011 #define BOOST_PROCESS_V2_ENVIRONMENT_HPP
0012 
0013 #include <boost/process/v2/detail/config.hpp>
0014 #include <boost/process/v2/cstring_ref.hpp>
0015 #include <boost/process/v2/detail/utf8.hpp>
0016 #include <boost/type_traits.hpp>
0017 #include <functional>
0018 #include <memory>
0019 #include <numeric>
0020 
0021 #if !defined(GENERATING_DOCUMENTATION)
0022 #if defined(BOOST_PROCESS_V2_WINDOWS)
0023 #include <boost/process/v2/detail/environment_win.hpp>
0024 #else
0025 #include <boost/process/v2/detail/environment_posix.hpp>
0026 #endif
0027 #endif
0028 
0029 BOOST_PROCESS_V2_BEGIN_NAMESPACE
0030 
0031 /// Namespace for information and functions regarding the calling process.
0032 namespace environment
0033 {
0034 
0035 #if defined(GENERATING_DOCUMENTATION)
0036 
0037 /// A char traits type that reflects the OS rules for string representing environment keys.
0038 /** Can be an alias of std::char_traits. May only be defined for `char` and `wchar_t`.
0039  * 
0040  * Windows treats keys as case-insensitive yet perserving. The char traits are made to reflect 
0041  * that behaviour.
0042 */
0043 tempalte<typename Char>
0044 using key_char_traits = implementation_defined ;
0045 
0046 /// A char traits type that reflects the OS rules for string representing environment values.
0047 /** Can be an alias of std::char_traits. May only be defined for `char` and `wchar_t`.
0048 */
0049 tempalte<typename Char>
0050 using value_char_traits = implementation_defined ;
0051 
0052 /// The character type used by the environment. Either `char` or `wchar_t`.
0053 using char_type = implementation_defined ;
0054 
0055 /// The equal character in an environment string used to separate key and value.
0056 constexpr char_type equality_sign = implementation_defined;
0057 
0058 /// The delimiter in environemtn lists. Commonly used by the `PATH` variable.
0059 constexpr char_type delimiter = implementation_defined;
0060 
0061 /// The native handle of an environment. Note that this can be an owning pointer and is generally not thread safe.
0062 using native_handle = implementation_defined;
0063 
0064 
0065 #endif
0066 
0067 
0068 /// The iterator used by a value or value_view to iterator through environments that are lists.
0069 struct value_iterator
0070 {
0071     using string_view_type  = basic_string_view<char_type, value_char_traits<char_type>>;
0072     using difference_type   = int;
0073     using reference         = string_view_type;
0074     using iterator_category = std::forward_iterator_tag;
0075 
0076     value_iterator & operator++()
0077     {
0078         const auto delim = view_.find(delimiter);
0079         if (delim != string_view_type::npos)
0080           view_ = view_.substr(delim + 1);
0081         else
0082           view_ = view_.substr(view_.size());
0083         return *this;
0084     }
0085 
0086     value_iterator operator++(int)
0087     {
0088         auto last = *this;
0089         ++(*this);
0090         return last;
0091     }
0092     string_view_type operator*() const
0093     {
0094       const auto delim = view_.find(delimiter);
0095       if (delim == string_view_type::npos)
0096         return view_;
0097       else
0098         return view_.substr(0, delim);
0099     }
0100 
0101     value_iterator() = default;
0102     value_iterator(const value_iterator & ) = default;
0103     value_iterator(string_view_type view, std::size_t offset = 0u) : view_(view.substr(offset))
0104     {
0105     }
0106 
0107     friend bool operator==(const value_iterator & l, const value_iterator & r) { return l.view_ == r.view_; }
0108     friend bool operator!=(const value_iterator & l, const value_iterator & r) { return l.view_ != r.view_; }
0109 
0110   private:
0111     string_view_type view_;
0112 };
0113 
0114 /// A view type for a key of an environment
0115 struct key_view
0116 {
0117     using value_type       = char_type;
0118     using traits_type      = key_char_traits<char_type>;
0119     using string_view_type = basic_string_view<char_type, traits_type>;
0120     using string_type      = std::basic_string<char_type, key_char_traits<char_type>>;
0121 
0122     key_view() noexcept = default;
0123     key_view( const key_view& p ) = default;
0124     key_view( key_view&& p ) noexcept = default;
0125     template<typename Source, 
0126              typename = typename std::enable_if<is_constructible<string_view_type, Source>::value>::type>
0127     key_view( const Source& source ) : value_(source) {}
0128     key_view( const char_type * p) : value_(p) {}
0129     key_view(       char_type * p) : value_(p) {}
0130 
0131     ~key_view() = default;
0132 
0133     key_view& operator=( const key_view& p ) = default;
0134     key_view& operator=( key_view&& p ) noexcept = default;
0135     key_view& operator=( string_view_type source )
0136     {
0137         value_ = source;
0138         return *this;
0139     }
0140 
0141     void swap( key_view& other ) noexcept
0142     {
0143         std::swap(value_, other.value_);
0144     }
0145 
0146     string_view_type native() const noexcept {return value_;}
0147 
0148     operator string_view_type() const {return native();}
0149 
0150     int compare( const key_view& p ) const noexcept {return value_.compare(p.value_);}
0151     int compare( string_view_type str ) const {return value_.compare(str);}
0152     int compare( const value_type* s ) const {return value_.compare(s);}
0153 
0154     template< class CharT, class Traits = std::char_traits<CharT>,
0155             class Alloc = std::allocator<CharT> >
0156     std::basic_string<CharT,Traits,Alloc>
0157     basic_string( const Alloc& alloc = Alloc()) const
0158     {
0159         return BOOST_PROCESS_V2_NAMESPACE::detail::conv_string<CharT, Traits>(
0160             value_.data(), value_.size(), alloc);
0161     }
0162 
0163     std::string       string() const {return basic_string<char>();}
0164     std::wstring     wstring() const {return basic_string<wchar_t>();}
0165 
0166     string_type native_string() const
0167     {
0168         return basic_string<char_type, key_char_traits<char_type>>();
0169     }
0170 
0171     friend bool operator==(key_view l, key_view r) { return l.value_ == r.value_; }
0172     friend bool operator!=(key_view l, key_view r) { return l.value_ != r.value_; }
0173     friend bool operator<=(key_view l, key_view r) { return l.value_ <= r.value_; }
0174     friend bool operator>=(key_view l, key_view r) { return l.value_ >= r.value_; }
0175     friend bool operator< (key_view l, key_view r) { return l.value_ <  r.value_; }
0176     friend bool operator> (key_view l, key_view r) { return l.value_ >  r.value_; }
0177 
0178     bool empty() const {return value_.empty(); }
0179 
0180     template< class CharT, class Traits >
0181     friend std::basic_ostream<CharT,Traits>&
0182     operator<<( std::basic_ostream<CharT,Traits>& os, const key_view& p )
0183     {
0184         os << BOOST_PROCESS_V2_NAMESPACE::quoted(p.basic_string<CharT,Traits>());
0185         return os;
0186     }
0187 
0188     template< class CharT, class Traits >
0189     friend std::basic_istream<CharT,Traits>&
0190     operator>>( std::basic_istream<CharT,Traits>& is, key_view& p )
0191     {
0192         std::basic_string<CharT, Traits> t;
0193         is >> BOOST_PROCESS_V2_NAMESPACE::quoted(t);
0194         p = t;
0195         return is;
0196     }
0197     const value_type * data() const {return value_.data(); }
0198     std::size_t size() const {return value_.size(); }
0199   private:
0200     string_view_type value_;
0201 };
0202 
0203 /// A view for a value in an environment
0204 struct value_view
0205 {
0206     using value_type       = char_type;
0207     using string_view_type = basic_cstring_ref<char_type, value_char_traits<char_type>>;
0208     using string_type      = std::basic_string<char_type, value_char_traits<char_type>>;
0209     using traits_type      = value_char_traits<char_type>;
0210 
0211     value_view() noexcept = default;
0212     value_view( const value_view& p ) = default;
0213     value_view( value_view&& p ) noexcept = default;
0214     template<typename Source, typename = typename std::enable_if<is_constructible<string_view_type, Source>::value>::type>
0215     value_view( const Source& source ) : value_(source) {}
0216     value_view( const char_type * p) : value_(p) {}
0217     value_view(       char_type * p) : value_(p) {}
0218 
0219     ~value_view() = default;
0220 
0221     value_view& operator=( const value_view& p ) = default;
0222     value_view& operator=( value_view&& p ) noexcept = default;
0223     value_view& operator=( string_view_type source )
0224     {
0225         value_ = source;
0226         return *this;
0227     }
0228 
0229     void swap( value_view& other ) noexcept
0230     {
0231         std::swap(value_, other.value_);
0232     }
0233 
0234     string_view_type native() const noexcept {return value_;}
0235 
0236     operator string_view_type() const {return native();}
0237     operator typename string_view_type::string_view_type() const {return value_; }
0238 
0239     int compare( const value_view& p ) const noexcept {return value_.compare(p.value_);}
0240     int compare( string_view_type str ) const {return value_.compare(str);}
0241     int compare( const value_type* s ) const {return value_.compare(s);}
0242 
0243     template< class CharT, class Traits = std::char_traits<CharT>,
0244             class Alloc = std::allocator<CharT> >
0245     std::basic_string<CharT,Traits,Alloc>
0246     basic_string( const Alloc& alloc = Alloc() ) const
0247     {
0248         return BOOST_PROCESS_V2_NAMESPACE::detail::conv_string<CharT, Traits>(
0249                 value_.data(), value_.size(),  alloc);
0250     }
0251 
0252     std::string string() const       {return basic_string<char>();}
0253     std::wstring wstring() const     {return basic_string<wchar_t>();}
0254 
0255     string_type native_string() const
0256     {
0257         return basic_string<char_type, value_char_traits<char_type>>();
0258     }
0259 
0260     bool empty() const {return value_.empty(); }
0261 
0262     friend bool operator==(value_view l, value_view r) { return l.value_ == r.value_; }
0263     friend bool operator!=(value_view l, value_view r) { return l.value_ != r.value_; }
0264     friend bool operator<=(value_view l, value_view r) { return l.value_ <= r.value_; }
0265     friend bool operator>=(value_view l, value_view r) { return l.value_ >= r.value_; }
0266     friend bool operator< (value_view l, value_view r) { return l.value_ <  r.value_; }
0267     friend bool operator> (value_view l, value_view r) { return l.value_ >  r.value_; }
0268 
0269 
0270     template< class CharT, class Traits >
0271     friend std::basic_ostream<CharT,Traits>&
0272     operator<<( std::basic_ostream<CharT,Traits>& os, const value_view& p )
0273     {
0274         os << BOOST_PROCESS_V2_NAMESPACE::quoted(p.basic_string<CharT,Traits>());
0275         return os;
0276     }
0277 
0278     template< class CharT, class Traits >
0279     friend std::basic_istream<CharT,Traits>&
0280     operator>>( std::basic_istream<CharT,Traits>& is, value_view& p )
0281     {
0282         std::basic_string<CharT, Traits> t;
0283         is >> BOOST_PROCESS_V2_NAMESPACE::quoted(t);
0284         p = t;
0285         return is;
0286     }
0287     value_iterator begin() const {return value_iterator(value_.data());}
0288     value_iterator   end() const {return value_iterator(value_.data() , value_.size());}
0289 
0290     const char_type * c_str() {return value_.c_str(); }
0291     const value_type * data() const {return value_.data(); }
0292     std::size_t size() const {return value_.size(); }
0293 
0294   private:
0295     string_view_type value_;
0296 };
0297 
0298 /// A view for a key value pair in an environment
0299 struct key_value_pair_view
0300 {
0301   using value_type       = char_type;
0302   using string_type      = std::basic_string<char_type>;
0303   using string_view_type = basic_cstring_ref<char_type>;
0304   using traits_type      = std::char_traits<char_type>;
0305 
0306   key_value_pair_view() noexcept = default;
0307   key_value_pair_view( const key_value_pair_view& p ) = default;
0308   key_value_pair_view( key_value_pair_view&& p ) noexcept = default;
0309   template<typename Source,
0310            typename = typename std::enable_if<is_constructible<string_view_type, Source>::value>::type>
0311   key_value_pair_view( const Source& source ) : value_(source) {}
0312 
0313   key_value_pair_view( const char_type * p) : value_(p) {}
0314   key_value_pair_view(       char_type * p) : value_(p) {}
0315 
0316 
0317   ~key_value_pair_view() = default;
0318 
0319   key_value_pair_view& operator=( const key_value_pair_view& p ) = default;
0320   key_value_pair_view& operator=( key_value_pair_view&& p ) noexcept = default;
0321 
0322   void swap( key_value_pair_view& other ) noexcept
0323   {
0324       std::swap(value_, other.value_);
0325   }
0326 
0327   string_view_type native() const noexcept {return value_;}
0328 
0329   operator string_view_type() const {return native();}
0330   operator typename string_view_type::string_view_type() const {return value_; }
0331 
0332   int compare( key_value_pair_view p ) const noexcept 
0333   {
0334       const auto c = key().compare(p.key());
0335       if (c != 0)
0336             return c;
0337       return value().compare(p.value());
0338   }
0339   int compare( const string_type& str ) const
0340   {
0341       return compare(key_value_pair_view(str));
0342   }
0343   int compare( string_view_type str ) const 
0344   {
0345       string_type st(str.data(), str.size());
0346       return compare(st);
0347   }
0348   int compare( const value_type* s ) const
0349   {
0350       return compare(key_value_pair_view(s));
0351   }
0352 
0353   template< class CharT, class Traits = std::char_traits<CharT>, class Alloc = std::allocator<CharT> >
0354   std::basic_string<CharT,Traits,Alloc>
0355   basic_string( const Alloc& alloc = Alloc()) const
0356   {
0357       return BOOST_PROCESS_V2_NAMESPACE::detail::conv_string<CharT, Traits>(value_.begin(), value_.size(), alloc);
0358   }
0359 
0360   std::string string() const       {return basic_string<char>();}
0361   std::wstring wstring() const     {return basic_string<wchar_t>();}
0362 
0363   string_type native_string() const
0364   {
0365     return basic_string<char_type>();
0366   }
0367 
0368   bool empty() const {return value_.empty(); }
0369 
0370   key_view key() const
0371   {
0372       auto eq = value_.find(equality_sign);
0373       if (eq == 0)
0374       {
0375           auto eq2 = value_.find(equality_sign, 1);
0376           if (eq2 != string_type::npos)
0377               eq = eq2;
0378       }
0379       const auto res = native().substr(0,  eq == string_view_type::npos ? value_.size() : eq);
0380       return key_view::string_view_type(res.data(), res.size());
0381   }
0382   value_view value() const
0383   {
0384       auto eq = value_.find(equality_sign);
0385       if (eq == 0)
0386       {
0387           auto eq2 = value_.find(equality_sign, 1);
0388           if (eq2 != string_type::npos)
0389               eq = eq2;
0390       }
0391       return environment::value_view(native().substr(eq + 1));
0392   }
0393 
0394   friend bool operator==(key_value_pair_view l, key_value_pair_view r) { return l.compare(r) == 0; }
0395   friend bool operator!=(key_value_pair_view l, key_value_pair_view r) { return l.compare(r) != 0; }
0396   friend bool operator<=(key_value_pair_view l, key_value_pair_view r) { return l.compare(r) <= 0; }
0397   friend bool operator>=(key_value_pair_view l, key_value_pair_view r) { return l.compare(r) >= 0; }
0398   friend bool operator< (key_value_pair_view l, key_value_pair_view r) { return l.compare(r) <  0; }
0399   friend bool operator> (key_value_pair_view l, key_value_pair_view r) { return l.compare(r) >  0; }
0400 
0401 
0402   template< class CharT, class Traits >
0403   friend std::basic_ostream<CharT,Traits>&
0404   operator<<( std::basic_ostream<CharT,Traits>& os, const key_value_pair_view& p )
0405   {
0406       os << BOOST_PROCESS_V2_NAMESPACE::quoted(p.basic_string<CharT,Traits>());
0407       return os;
0408   }
0409 
0410   template< class CharT, class Traits >
0411   friend std::basic_istream<CharT,Traits>&
0412   operator>>( std::basic_istream<CharT,Traits>& is, key_value_pair_view& p )
0413   {
0414       std::basic_string<CharT, Traits> t;
0415       is >> BOOST_PROCESS_V2_NAMESPACE::quoted(t);
0416       p = t;
0417       return is;
0418   }
0419 
0420   template<std::size_t Idx>
0421   inline auto get() const -> typename conditional<Idx == 0u, BOOST_PROCESS_V2_NAMESPACE::environment::key_view,
0422                                                              BOOST_PROCESS_V2_NAMESPACE::environment::value_view>::type;
0423   const value_type * c_str() const noexcept
0424   {
0425     return value_.data();
0426   }
0427   const value_type * data() const {return value_.data(); }
0428   std::size_t size() const {return value_.size(); }
0429 
0430  private:
0431 
0432   string_view_type value_;
0433 };
0434 
0435 template<>
0436 inline key_view key_value_pair_view::get<0u>() const
0437 {
0438     return key();
0439 }
0440 
0441 template<>
0442 inline value_view key_value_pair_view::get<1u>() const
0443 {
0444     return value();
0445 }
0446 
0447 namespace detail
0448 {
0449 
0450 template<typename Char>
0451 std::size_t hash_step(std::size_t prev, Char c, std::char_traits<Char>)
0452 {
0453     return prev ^ (c << 1);
0454 }
0455 
0456 }
0457 
0458 inline std::size_t hash_value(const key_view & value)
0459 {
0460     std::size_t hash = 0u;
0461     for (auto c = value.data(); *c != *v2::detail::null_char_(*c); c++)
0462         hash = detail::hash_step(hash, *c, key_view::traits_type{});
0463     return hash ;
0464 }
0465 
0466 
0467 inline std::size_t hash_value(const BOOST_PROCESS_V2_NAMESPACE::environment::value_view & value)
0468 {
0469     std::size_t hash = 0u;
0470     for (auto c = value.data(); *c != *v2::detail::null_char_(*c); c++)
0471         hash = detail::hash_step(hash, *c, value_view::traits_type{});
0472     return hash ;
0473 }
0474 
0475 
0476 inline std::size_t hash_value(const BOOST_PROCESS_V2_NAMESPACE::environment::key_value_pair_view & value)
0477 {
0478     std::size_t hash = 0u;
0479     for (auto c = value.data(); *c != *v2::detail::null_char_(*c); c++)
0480         hash = detail::hash_step(hash, *c, key_value_pair_view::traits_type{});
0481     return hash ;
0482 }
0483 
0484 /// A class representing a key within an environment.
0485 struct key
0486 {
0487     using value_type       = char_type;
0488     using traits_type      = key_char_traits<char_type>;
0489     using string_type      = std::basic_string<char_type, traits_type>;
0490     using string_view_type = basic_string_view<char_type, traits_type>;
0491 
0492     key() {}
0493     key( const key& p ) = default;
0494     key( key&& p ) noexcept = default;
0495     key( const string_type& source ) : value_(source) {}
0496     key( string_type&& source ) : value_(std::move(source)) {}
0497     key( const value_type * raw ) : value_(raw) {}
0498     key(       value_type * raw ) : value_(raw) {}
0499 
0500     explicit key(key_view kv) : value_(kv.native_string()) {}
0501 
0502 
0503     template< class Source >
0504     key( const Source& source,
0505         decltype(std::declval<Source>().data()) = nullptr,
0506         decltype(std::declval<Source>().size()) = 0u)
0507         : value_(
0508              BOOST_PROCESS_V2_NAMESPACE::detail::conv_string<char_type, traits_type>(
0509                 source.data(), source.size()))
0510     {
0511     }
0512 
0513     key(const typename conditional<is_same<value_type, char>::value, wchar_t, char>::type  * raw)
0514         : value_(BOOST_PROCESS_V2_NAMESPACE::detail::conv_string<char_type, traits_type>(
0515                 raw, std::char_traits<std::decay<std::remove_pointer<decltype(raw)>::type>::type>::length(raw)))
0516     {
0517     }
0518 
0519     template< class InputIt >
0520     key( InputIt first, InputIt last)
0521         : key(std::basic_string<typename std::iterator_traits<typename std::decay<InputIt>::type>::value_type>(first, last))
0522     {
0523     }
0524 
0525     ~key() = default;
0526 
0527     key& operator=( const key& p ) = default;
0528     key& operator=( key&& p )
0529     {
0530       value_ = std::move(p.value_);
0531       return *this;
0532     }
0533     key& operator=( string_type&& source )
0534     {
0535         value_ = std::move(source);
0536         return *this;
0537     }
0538     template< class Source >
0539     key& operator=( const Source& source )
0540     {
0541         value_ = BOOST_PROCESS_V2_NAMESPACE::detail::conv_string<char_type, traits_type>(source.data(), source.size());
0542         return *this;
0543     }
0544 
0545     key& assign( string_type&& source )
0546     {
0547         value_ = std::move(source);
0548         return *this;
0549     }
0550     template< class Source >
0551     key& assign( const Source& source )
0552     {
0553         value_ = BOOST_PROCESS_V2_NAMESPACE::detail::conv_string<char_type, traits_type>(source.data(), source.size());
0554         return *this;
0555     }
0556 
0557     template< class InputIt >
0558     key& assign( InputIt first, InputIt last )
0559     {
0560 
0561         return assign(std::basic_string<typename std::iterator_traits<typename std::decay<InputIt>::type>::value_type>(first, last));
0562     }
0563 
0564     void clear() {value_.clear();}
0565 
0566     void swap( key& other ) noexcept
0567     {
0568         std::swap(value_, other.value_);
0569     }
0570 
0571     const value_type* c_str() const noexcept {return value_.c_str();}
0572     const string_type& native() const noexcept {return value_;}
0573     string_view_type native_view() const noexcept {return value_;}
0574 
0575     operator string_type() const {return native();}
0576     operator string_view_type() const {return native_view();}
0577 
0578     int compare( const key& p ) const noexcept {return value_.compare(p.value_);}
0579     int compare( const string_type& str ) const {return value_.compare(str);}
0580     int compare( string_view_type str ) const {return -str.compare(value_);}
0581     int compare( const value_type* s ) const {return value_.compare(s);}
0582 
0583     template< class CharT, class Traits = std::char_traits<CharT>,
0584         class Alloc = std::allocator<CharT> >
0585     std::basic_string<CharT,Traits,Alloc>
0586     basic_string( const Alloc& alloc = Alloc()) const
0587     {
0588         return BOOST_PROCESS_V2_NAMESPACE::detail::conv_string<CharT, Traits>(
0589             value_.data(), value_.size(), alloc);
0590     }
0591 
0592 
0593     std::string string() const       {return basic_string<char>();}
0594     std::wstring wstring() const     {return basic_string<wchar_t>();}
0595 
0596     const string_type & native_string() const
0597     {
0598         return value_;
0599     }
0600 
0601     bool empty() const {return value_.empty(); }
0602 
0603     friend bool operator==(const key & l, const key & r) { return l.value_ == r.value_; }
0604     friend bool operator!=(const key & l, const key & r) { return l.value_ != r.value_; }
0605     friend bool operator<=(const key & l, const key & r) { return l.value_ <= r.value_; }
0606     friend bool operator>=(const key & l, const key & r) { return l.value_ >= r.value_; }
0607     friend bool operator< (const key & l, const key & r) { return l.value_ <  r.value_; }
0608     friend bool operator> (const key & l, const key & r) { return l.value_ >  r.value_; }
0609 
0610     template< class CharT, class Traits >
0611     friend std::basic_ostream<CharT,Traits>&
0612     operator<<( std::basic_ostream<CharT,Traits>& os, const key& p )
0613     {
0614         os << BOOST_PROCESS_V2_NAMESPACE::quoted(p.basic_string<CharT,Traits>());
0615         return os;
0616     }
0617 
0618     template< class CharT, class Traits >
0619     friend std::basic_istream<CharT,Traits>&
0620     operator>>( std::basic_istream<CharT,Traits>& is, key& p )
0621     {
0622         std::basic_string<CharT, Traits> t;
0623         is >> BOOST_PROCESS_V2_NAMESPACE::quoted(t);
0624         p = t;
0625         return is;
0626     }
0627     const value_type * data() const {return value_.data(); }
0628     std::size_t size() const {return value_.size(); }
0629 
0630   private:
0631     string_type value_;
0632 };
0633 
0634 #if !defined(GENERATING_DOCUMENTATION)
0635 
0636 template<typename T, typename U>
0637 typename std::enable_if<
0638         ((std::is_same<T, key>::value || std::is_same<T, key_view>::value) &&
0639          std::is_convertible<const U &, key_view>::value)
0640         ||
0641         ((std::is_same<U, key>::value || std::is_same<U, key_view>::value) &&
0642          std::is_convertible<const T & , key_view>::value),
0643         bool>::type
0644 operator==(const T  &l, const U & r) { return key_view(l) == key_view(r); }
0645 
0646 template<typename T, typename U>
0647 typename std::enable_if<
0648         ((std::is_same<T, key>::value || std::is_same<T, key_view>::value) &&
0649          std::is_convertible<const U &, key_view>::value)
0650         ||
0651         ((std::is_same<U, key>::value || std::is_same<U, key_view>::value) &&
0652          std::is_convertible<const T & , key_view>::value),
0653         bool>::type
0654 operator!=(const T  &l, const U & r) { return key_view(l) != key_view(r); }
0655 
0656 template<typename T, typename U>
0657 typename std::enable_if<
0658         ((std::is_same<T, key>::value || std::is_same<T, key_view>::value) &&
0659          std::is_convertible<const U &, key_view>::value)
0660         ||
0661         ((std::is_same<U, key>::value || std::is_same<U, key_view>::value) &&
0662          std::is_convertible<const T & , key_view>::value),
0663         bool>::type
0664 operator<=(const T  &l, const U & r) { return key_view(l) <= key_view(r); }
0665 
0666 template<typename T, typename U>
0667 typename std::enable_if<
0668         ((std::is_same<T, key>::value || std::is_same<T, key_view>::value) &&
0669          std::is_convertible<const U &, key_view>::value)
0670         ||
0671         ((std::is_same<U, key>::value || std::is_same<U, key_view>::value) &&
0672          std::is_convertible<const T & , key_view>::value),
0673         bool>::type
0674 operator <(const T  &l, const U & r) { return key_view(l)  < key_view(r); }
0675 
0676 template<typename T, typename U>
0677 typename std::enable_if<
0678         ((std::is_same<T, key>::value || std::is_same<T, key_view>::value) &&
0679          std::is_convertible<const U &, key_view>::value)
0680         ||
0681         ((std::is_same<U, key>::value || std::is_same<U, key_view>::value) &&
0682          std::is_convertible<const T & , key_view>::value),
0683         bool>::type
0684 operator>=(const T  &l, const U & r) { return key_view(l) >= key_view(r); }
0685 
0686 template<typename T, typename U>
0687 typename std::enable_if<
0688         ((std::is_same<T, key>::value || std::is_same<T, key_view>::value) &&
0689          std::is_convertible<const U &, key_view>::value)
0690         ||
0691         ((std::is_same<U, key>::value || std::is_same<U, key_view>::value) &&
0692          std::is_convertible<const T & , key_view>::value),
0693         bool>::type
0694 operator >(const T  &l, const U & r) { return key_view(l) >  key_view(r); }
0695 
0696 #else
0697 
0698 
0699 bool operator==(const value_view &, const value_view);
0700 bool operator!=(const value_view &, const value_view);
0701 bool operator<=(const value_view &, const value_view);
0702 bool operator< (const value_view &, const value_view);
0703 bool operator> (const value_view &, const value_view);
0704 bool operator>=(const value_view &, const value_view);
0705 
0706 #endif
0707 
0708 
0709 struct value
0710 {
0711     using value_type       = char_type;
0712     using traits_type      = value_char_traits<char_type>;
0713     using string_type      = std::basic_string<char_type, traits_type>;
0714     using string_view_type = basic_cstring_ref<char_type, traits_type>;
0715 
0716     value() {}
0717     value( const value& p ) = default;
0718 
0719     value( const string_type& source ) : value_(source) {}
0720     value( string_type&& source ) : value_(std::move(source)) {}
0721     value( const value_type * raw ) : value_(raw) {}
0722     value(       value_type * raw ) : value_(raw) {}
0723 
0724     explicit value(value_view kv) : value_(kv.c_str()) {}
0725 
0726     template< class Source >
0727     value( const Source& source,
0728            decltype(std::declval<Source>().data()) = nullptr,
0729     decltype(std::declval<Source>().size()) = 0u)
0730     : value_(BOOST_PROCESS_V2_NAMESPACE::detail::conv_string<char_type, traits_type>(
0731         source.data(), source.size()))
0732     {
0733     }
0734 
0735     value(const typename conditional<is_same<value_type, char>::value, wchar_t, char>::type  * raw)
0736             : value_(BOOST_PROCESS_V2_NAMESPACE::detail::conv_string<char_type, traits_type>(
0737             raw, std::char_traits<std::decay<std::remove_pointer<decltype(raw)>::type>::type>::length(raw)))
0738     {
0739     }
0740 
0741     template< class InputIt >
0742     value( InputIt first, InputIt last)
0743             : value(std::basic_string<typename std::iterator_traits<typename std::decay<InputIt>::type>::value_type>(first, last))
0744     {
0745     }
0746 
0747     ~value() = default;
0748 
0749     value& operator=( const value& p ) = default;
0750     value& operator=( value&& p )
0751     {
0752       value_ = std::move(p.value_);
0753       return *this;
0754     }
0755     value& operator=( string_type&& source )
0756     {
0757         value_ = std::move(source);
0758         return *this;
0759     }
0760     template< class Source >
0761     value& operator=( const Source& source )
0762     {
0763         value_ = BOOST_PROCESS_V2_NAMESPACE::detail::conv_string<char_type, traits_type>(
0764             source.data(), source.size);
0765         return *this;
0766     }
0767 
0768     value& assign( string_type&& source )
0769     {
0770         value_ = std::move(source);
0771         return *this;
0772     }
0773     template< class Source >
0774     value& assign( const Source& source )
0775     {
0776       value_ = BOOST_PROCESS_V2_NAMESPACE::detail::conv_string<char_type, traits_type>(
0777           source.data(), source.size());
0778       return *this;
0779     }
0780 
0781     template< class InputIt >
0782     value& assign( InputIt first, InputIt last )
0783     {
0784         return assign(std::basic_string<typename std::iterator_traits<typename std::decay<InputIt>::type>::value_type>(first, last));
0785     }
0786 
0787     void push_back(const value & sv)
0788     {
0789         (value_ += delimiter) += sv;
0790     }
0791 
0792     void clear() {value_.clear();}
0793 
0794     void swap( value& other ) noexcept
0795     {
0796         std::swap(value_, other.value_);
0797     }
0798 
0799     const value_type* c_str() const noexcept {return value_.c_str();}
0800     const string_type& native() const noexcept {return value_;}
0801     string_view_type native_view() const noexcept {return value_;}
0802 
0803     operator string_type() const {return native();}
0804     operator string_view_type() const {return native_view();}
0805     operator typename string_view_type::string_view_type() const {return value_; }
0806 
0807     int compare( const value& p ) const noexcept {return value_.compare(p.value_);}
0808     int compare( const string_type& str ) const {return value_.compare(str);}
0809     int compare( string_view_type str ) const {return -str.compare(value_);}
0810     int compare( const value_type* s ) const {return value_.compare(s);}
0811 
0812     template< class CharT, class Traits = std::char_traits<CharT>,
0813             class Alloc = std::allocator<CharT> >
0814     std::basic_string<CharT,Traits,Alloc>
0815     basic_string( const Alloc& alloc = Alloc()) const
0816     {
0817         return BOOST_PROCESS_V2_NAMESPACE::detail::conv_string<CharT, Traits>(
0818             value_.data(), value_.size(),alloc);
0819     }
0820 
0821     std::string string() const       {return basic_string<char>();}
0822     std::wstring wstring() const     {return basic_string<wchar_t>();}
0823 
0824 
0825     const string_type & native_string() const
0826     {
0827         return value_;
0828     }
0829 
0830     bool empty() const {return value_.empty(); }
0831 
0832     friend bool operator==(const value & l, const value & r) { return l.value_ == r.value_; }
0833     friend bool operator!=(const value & l, const value & r) { return l.value_ != r.value_; }
0834     friend bool operator<=(const value & l, const value & r) { return l.value_ <= r.value_; }
0835     friend bool operator>=(const value & l, const value & r) { return l.value_ >= r.value_; }
0836     friend bool operator< (const value & l, const value & r) { return l.value_ <  r.value_; }
0837     friend bool operator> (const value & l, const value & r) { return l.value_ >  r.value_; }
0838 
0839     template< class CharT, class Traits >
0840     friend std::basic_ostream<CharT,Traits>&
0841     operator<<( std::basic_ostream<CharT,Traits>& os, const value& p )
0842     {
0843         os << BOOST_PROCESS_V2_NAMESPACE::quoted(p.basic_string<CharT,Traits>());
0844         return os;
0845     }
0846 
0847     template< class CharT, class Traits >
0848     friend std::basic_istream<CharT,Traits>&
0849     operator>>( std::basic_istream<CharT,Traits>& is, value& p )
0850     {
0851         std::basic_string<CharT, Traits> t;
0852         is >> BOOST_PROCESS_V2_NAMESPACE::quoted(t);
0853         p = t;
0854         return is;
0855     }
0856 
0857     value_iterator begin() const {return value_iterator(value_.data());}
0858     value_iterator   end() const {return value_iterator(value_.data(), value_.size());}
0859     const value_type * data() const {return value_.data(); }
0860     std::size_t size() const {return value_.size(); }
0861 
0862   private:
0863     string_type value_;
0864 };
0865 
0866 
0867 #if !defined(GENERATING_DOCUMENTATION)
0868 
0869 template<typename T, typename U>
0870 typename std::enable_if<
0871         ((std::is_same<T, value>::value || std::is_same<T, value_view>::value) &&
0872          std::is_convertible<const U &, value_view>::value)
0873         ||
0874         ((std::is_same<U, value>::value || std::is_same<U, value_view>::value) &&
0875          std::is_convertible<const T & , value_view>::value),
0876         bool>::type
0877 operator==(const T  &l, const U & r) { return value_view(l) == value_view(r); }
0878 
0879 template<typename T, typename U>
0880 typename std::enable_if<
0881         ((std::is_same<T, value>::value || std::is_same<T, value_view>::value) &&
0882          std::is_convertible<const U &, value_view>::value)
0883         ||
0884         ((std::is_same<U, value>::value || std::is_same<U, value_view>::value) &&
0885          std::is_convertible<const T & , value_view>::value),
0886         bool>::type
0887 operator!=(const T  &l, const U & r) { return value_view(l) != value_view(r); }
0888 
0889 template<typename T, typename U>
0890 typename std::enable_if<
0891         ((std::is_same<T, value>::value || std::is_same<T, value_view>::value) &&
0892          std::is_convertible<const U &, value_view>::value)
0893         ||
0894         ((std::is_same<U, value>::value || std::is_same<U, value_view>::value) &&
0895          std::is_convertible<const T & , value_view>::value),
0896         bool>::type
0897 operator<=(const T  &l, const U & r) { return value_view(l) <= value_view(r); }
0898 
0899 template<typename T, typename U>
0900 typename std::enable_if<
0901         ((std::is_same<T, value>::value || std::is_same<T, value_view>::value) &&
0902          std::is_convertible<const U &, value_view>::value)
0903         ||
0904         ((std::is_same<U, value>::value || std::is_same<U, value_view>::value) &&
0905          std::is_convertible<const T & , value_view>::value),
0906         bool>::type
0907 operator <(const T  &l, const U & r) { return value_view(l)  < value_view(r); }
0908 
0909 template<typename T, typename U>
0910 typename std::enable_if<
0911         ((std::is_same<T, value>::value || std::is_same<T, value_view>::value) &&
0912          std::is_convertible<const U &, value_view>::value)
0913         ||
0914         ((std::is_same<U, value>::value || std::is_same<U, value_view>::value) &&
0915          std::is_convertible<const T & , value_view>::value),
0916         bool>::type
0917 operator>=(const T  &l, const U & r) { return value_view(l) >= value_view(r); }
0918 
0919 template<typename T, typename U>
0920 typename std::enable_if<
0921         ((std::is_same<T, value>::value || std::is_same<T, value_view>::value) &&
0922          std::is_convertible<const U &, value_view>::value)
0923         ||
0924         ((std::is_same<U, value>::value || std::is_same<U, value_view>::value) &&
0925          std::is_convertible<const T & , value_view>::value),
0926         bool>::type
0927 operator >(const T  &l, const U & r) { return value_view(l) >  value_view(r); }
0928 
0929 #else
0930 
0931 bool operator==(const value_view &, const value_view);
0932 bool operator!=(const value_view &, const value_view);
0933 bool operator<=(const value_view &, const value_view);
0934 bool operator< (const value_view &, const value_view);
0935 bool operator> (const value_view &, const value_view);
0936 bool operator>=(const value_view &, const value_view);
0937 
0938 #endif
0939 
0940 struct key_value_pair
0941 {
0942     using value_type       = char_type;
0943     using traits_type      = std::char_traits<char_type>;
0944     using string_type      = std::basic_string<char_type>;
0945     using string_view_type = basic_cstring_ref<char_type>;
0946 
0947     key_value_pair() {}
0948     key_value_pair( const key_value_pair& p ) = default;
0949     key_value_pair( key_value_pair&& p ) noexcept = default;
0950     key_value_pair(key_view key, value_view value) : value_(key.basic_string<char_type, traits_type>() + equality_sign + 
0951                                                             value.basic_string<char_type, traits_type>()) {}
0952 
0953     key_value_pair(key_view key, std::initializer_list<basic_string_view<char_type>> values)
0954     {
0955         const auto sz = std::accumulate(values.begin(), values.end(),
0956                                         key.size(), [](std::size_t sz, const basic_string_view<char_type> & str) { return sz + str.size() + 1;});
0957 
0958         value_.reserve(sz);
0959         value_.append(key.data(), key.size());
0960         value_ += equality_sign;
0961         for (auto & value : values)
0962         {
0963             if (value_.back() != equality_sign)
0964                 value_ += delimiter;
0965             value_.append(value.data(), value.size());
0966         }
0967     }
0968 
0969     key_value_pair( const string_type& source ) : value_(source) {}
0970     key_value_pair( string_type&& source ) : value_(std::move(source)) {}
0971     key_value_pair( const value_type * raw ) : value_(raw) {}
0972     key_value_pair(       value_type * raw ) : value_(raw) {}
0973 
0974     explicit key_value_pair(key_value_pair_view kv) : value_(kv.c_str()) {}
0975 
0976     template< class Source >
0977     key_value_pair( const Source& source,
0978            decltype(std::declval<Source>().data()) = nullptr,
0979            decltype(std::declval<Source>().size()) = 0u)
0980             : value_(BOOST_PROCESS_V2_NAMESPACE::detail::conv_string<char_type, traits_type>(
0981                 source.data(), source.size()))
0982     {
0983     }
0984 
0985     template< typename Key, 
0986               typename Value >
0987     key_value_pair(
0988          const std::pair<Key, Value> & kv/*,
0989          typename std::enable_if<std::is_constructible<struct key,   Key >::value && 
0990                                  std::is_constructible<struct value, Value>::value
0991                 >::type = 0*/) : value_(((struct key)(kv.first)).basic_string<char_type, traits_type>() + equality_sign 
0992                                       + ((struct value)(kv.second)).basic_string<char_type, traits_type>())
0993     {}
0994 
0995     key_value_pair(const typename conditional<is_same<value_type, char>::value, wchar_t, char>::type  * raw)
0996             : value_(BOOST_PROCESS_V2_NAMESPACE::detail::conv_string<char_type, traits_type>(
0997                      raw,
0998                      std::char_traits<std::decay<std::remove_pointer<decltype(raw)>::type>::type>::length(raw)))
0999     {
1000     }
1001 
1002     template< class InputIt , typename std::iterator_traits<InputIt>::iterator_category>
1003     key_value_pair( InputIt first, InputIt last )
1004             : key_value_pair(std::basic_string<typename std::iterator_traits<typename std::decay<InputIt>::type>::value_type>(first, last))
1005     {
1006     }
1007 
1008     ~key_value_pair() = default;
1009 
1010     key_value_pair& operator=( const key_value_pair& p ) = default;
1011     key_value_pair& operator=( key_value_pair&& p )
1012     {
1013       value_ = std::move(p.value_);
1014       return *this;
1015     }
1016     key_value_pair& operator=( string_type&& source )
1017     {
1018         value_ = std::move(source);
1019         return *this;
1020     }
1021     template< class Source >
1022     key_value_pair& operator=( const Source& source )
1023     {
1024         value_ = BOOST_PROCESS_V2_NAMESPACE::detail::conv_string<char_type, traits_type>(
1025             source.data(), source.size());
1026         return *this;
1027     }
1028 
1029     key_value_pair& assign( string_type&& source )
1030     {
1031         value_ = std::move(source);
1032         return *this;
1033     }
1034     template< class Source >
1035     key_value_pair& assign( const Source& source )
1036     {
1037         value_ = BOOST_PROCESS_V2_NAMESPACE::detail::conv_string<char_type, traits_type>(
1038             source.data(), source.size());
1039         return *this;
1040     }
1041 
1042 
1043     template< class InputIt >
1044     key_value_pair& assign( InputIt first, InputIt last )
1045     {
1046         return assign(std::basic_string<typename std::iterator_traits<typename std::decay<InputIt>::type>::value_type>(first, last));
1047     }
1048 
1049     void clear() {value_.clear();}
1050 
1051     void swap( key_value_pair& other ) noexcept
1052     {
1053         std::swap(value_, other.value_);
1054     }
1055 
1056     const value_type* c_str() const noexcept {return value_.c_str();}
1057     const string_type& native() const noexcept {return value_;}
1058     string_view_type native_view() const noexcept {return value_;}
1059 
1060     operator string_type() const {return native();}
1061     operator string_view_type() const {return native_view();}
1062     operator typename string_view_type::string_view_type() const {return native_view();}
1063     operator key_value_pair_view() const {return native_view();}
1064 
1065     int compare( const key_value_pair& p ) const noexcept 
1066     {
1067         return key_value_pair_view(*this).compare(key_value_pair_view(p));
1068     }
1069     
1070     int compare( const string_type& str ) const 
1071     {
1072         return key_value_pair_view(*this).compare(str);
1073     }
1074     int compare( string_view_type str ) const   
1075     {
1076         return key_value_pair_view(*this).compare(str);
1077     }
1078     int compare( const value_type* s ) const
1079     {
1080         return key_value_pair_view(*this).compare(s);
1081     }
1082 
1083     template< class CharT, class Traits = std::char_traits<CharT>, class Alloc = std::allocator<CharT> >
1084     std::basic_string<CharT,Traits,Alloc>
1085     basic_string( const Alloc& alloc = Alloc() ) const
1086     {
1087         return BOOST_PROCESS_V2_NAMESPACE::detail::conv_string<CharT, Traits>(value_.data(), value_.size(), alloc);
1088     }
1089 
1090     std::string string() const       {return basic_string<char>();}
1091     std::wstring wstring() const     {return basic_string<wchar_t>();}
1092 
1093     const string_type & native_string() const
1094     {
1095         return value_;
1096     }
1097 
1098     friend bool operator==(const key_value_pair & l, const key_value_pair & r) { return l.compare(r) == 0; }
1099     friend bool operator!=(const key_value_pair & l, const key_value_pair & r) { return l.compare(r) != 0; }
1100     friend bool operator<=(const key_value_pair & l, const key_value_pair & r) { return l.compare(r) <= 0; }
1101     friend bool operator>=(const key_value_pair & l, const key_value_pair & r) { return l.compare(r) >= 0; }
1102     friend bool operator< (const key_value_pair & l, const key_value_pair & r) { return l.compare(r) <  0; }
1103     friend bool operator> (const key_value_pair & l, const key_value_pair & r) { return l.compare(r) >  0; }
1104 
1105     bool empty() const {return value_.empty(); }
1106 
1107     struct key_view key() const
1108     {
1109         auto eq = value_.find(equality_sign);
1110         if (eq == 0)
1111         {
1112             auto eq2 = value_.find(equality_sign, 1);
1113             if (eq2 != string_type::npos)
1114               eq = eq2;
1115         }
1116         const auto k = native_view().substr(0, eq);
1117 
1118         return BOOST_PROCESS_V2_NAMESPACE::environment::key_view::string_view_type (k.data(), k.size());
1119     }
1120     struct value_view value() const
1121     {
1122         auto eq = value_.find(equality_sign);
1123         if (eq == 0)
1124         {
1125             auto eq2 = value_.find(equality_sign, 1);
1126             if (eq2 != string_type::npos)
1127                eq = eq2;
1128         }
1129         return value_view::string_view_type(native_view().substr(eq + 1));
1130     }
1131 
1132     template< class CharT, class Traits >
1133     friend std::basic_ostream<CharT,Traits>&
1134     operator<<( std::basic_ostream<CharT,Traits>& os, const key_value_pair& p )
1135     {
1136         os << BOOST_PROCESS_V2_NAMESPACE::quoted(p.basic_string<CharT,Traits>());
1137         return os;
1138     }
1139 
1140     template< class CharT, class Traits >
1141     friend std::basic_istream<CharT,Traits>&
1142     operator>>( std::basic_istream<CharT,Traits>& is, key_value_pair& p )
1143     {
1144         is >> BOOST_PROCESS_V2_NAMESPACE::quoted(p.value_);
1145         return is;
1146     }
1147 
1148     const value_type * data() const {return value_.data(); }
1149     std::size_t size() const {return value_.size(); }
1150 
1151     template<std::size_t Idx>
1152     inline auto get() const 
1153             -> typename conditional<Idx == 0u, BOOST_PROCESS_V2_NAMESPACE::environment::key_view,
1154                                             BOOST_PROCESS_V2_NAMESPACE::environment::value_view>::type;
1155 
1156 private:
1157     string_type value_;
1158 };
1159 
1160 #if !defined(GENERATING_DOCUMENTATION)
1161 
1162 template<typename T, typename U>
1163 typename std::enable_if<
1164         ((std::is_same<T, key_value_pair>::value || std::is_same<T, key_value_pair_view>::value) &&
1165          std::is_convertible<const U &, key_value_pair_view>::value)
1166         ||
1167         ((std::is_same<U, key_value_pair>::value || std::is_same<U, key_value_pair_view>::value) &&
1168          std::is_convertible<const T & , key_value_pair_view>::value),
1169         bool>::type
1170 operator==(const T  &l, const U & r) { return key_value_pair_view(l) == key_value_pair_view(r); }
1171 
1172 template<typename T, typename U>
1173 typename std::enable_if<
1174         ((std::is_same<T, key_value_pair>::value || std::is_same<T, key_value_pair_view>::value) &&
1175          std::is_convertible<const U &, key_value_pair_view>::value)
1176         ||
1177         ((std::is_same<U, key_value_pair>::value || std::is_same<U, key_value_pair_view>::value) &&
1178          std::is_convertible<const T & , key_value_pair_view>::value),
1179         bool>::type
1180 operator!=(const T  &l, const U & r) { return key_value_pair_view(l) != key_value_pair_view(r); }
1181 
1182 template<typename T, typename U>
1183 typename std::enable_if<
1184         ((std::is_same<T, key_value_pair>::value || std::is_same<T, key_value_pair_view>::value) &&
1185          std::is_convertible<const U &, key_value_pair_view>::value)
1186         ||
1187         ((std::is_same<U, key_value_pair>::value || std::is_same<U, key_value_pair_view>::value) &&
1188          std::is_convertible<const T & , key_value_pair_view>::value),
1189         bool>::type
1190 operator<=(const T  &l, const U & r) { return key_value_pair_view(l) <= key_value_pair_view(r); }
1191 
1192 template<typename T, typename U>
1193 typename std::enable_if<
1194         ((std::is_same<T, key_value_pair>::value || std::is_same<T, key_value_pair_view>::value) &&
1195          std::is_convertible<const U &, key_value_pair_view>::value)
1196         ||
1197         ((std::is_same<U, key_value_pair>::value || std::is_same<U, key_value_pair_view>::value) &&
1198          std::is_convertible<const T & , key_value_pair_view>::value),
1199         bool>::type
1200 operator <(const T  &l, const U & r) { return key_value_pair_view(l)  < key_value_pair_view(r); }
1201 
1202 template<typename T, typename U>
1203 typename std::enable_if<
1204         ((std::is_same<T, key_value_pair>::value || std::is_same<T, key_value_pair_view>::value) &&
1205          std::is_convertible<const U &, key_value_pair_view>::value)
1206         ||
1207         ((std::is_same<U, key_value_pair>::value || std::is_same<U, key_value_pair_view>::value) &&
1208          std::is_convertible<const T & , key_value_pair_view>::value),
1209         bool>::type
1210 operator>=(const T  &l, const U & r) { return key_value_pair_view(l) >= key_value_pair_view(r); }
1211 
1212 template<typename T, typename U>
1213 typename std::enable_if<
1214         ((std::is_same<T, key_value_pair>::value || std::is_same<T, key_value_pair_view>::value) &&
1215          std::is_convertible<const U &, key_value_pair_view>::value)
1216         ||
1217         ((std::is_same<U, key_value_pair>::value || std::is_same<U, key_value_pair_view>::value) &&
1218          std::is_convertible<const T & , key_value_pair_view>::value),
1219         bool>::type
1220 operator >(const T  &l, const U & r) { return key_value_pair_view(l) >  key_value_pair_view(r); }
1221 
1222 #else
1223 
1224 bool operator==(const key_value_pair_view &, const key_value_pair_view);
1225 bool operator!=(const key_value_pair_view &, const key_value_pair_view);
1226 bool operator<=(const key_value_pair_view &, const key_value_pair_view);
1227 bool operator< (const key_value_pair_view &, const key_value_pair_view);
1228 bool operator> (const key_value_pair_view &, const key_value_pair_view);
1229 bool operator>=(const key_value_pair_view &, const key_value_pair_view);
1230 
1231 #endif
1232 
1233 
1234 template<>
1235 inline key_view key_value_pair::get<0u>() const
1236 {
1237     return key();
1238 }
1239 
1240 template<>
1241 inline value_view key_value_pair::get<1u>() const
1242 {
1243     return value();
1244 }
1245 
1246 }
1247 BOOST_PROCESS_V2_END_NAMESPACE
1248 
1249 namespace std
1250 {
1251 
1252 template<>
1253 class tuple_size<BOOST_PROCESS_V2_NAMESPACE::environment::key_value_pair> : integral_constant<std::size_t, 2u> {};
1254 
1255 template<>
1256 class tuple_element<0u, BOOST_PROCESS_V2_NAMESPACE::environment::key_value_pair> 
1257 {
1258   public: 
1259     using type = BOOST_PROCESS_V2_NAMESPACE::environment::key_view;
1260 };
1261 
1262 template<>
1263 class tuple_element<1u, BOOST_PROCESS_V2_NAMESPACE::environment::key_value_pair> 
1264 {
1265   public: 
1266     using type = BOOST_PROCESS_V2_NAMESPACE::environment::value_view;
1267 };
1268 
1269 template<std::size_t Idx>
1270 inline auto get(const BOOST_PROCESS_V2_NAMESPACE::environment::key_value_pair & kvp) 
1271         -> typename std::tuple_element<Idx, BOOST_PROCESS_V2_NAMESPACE::environment::key_value_pair>::type
1272 {
1273     return kvp.get<Idx>();
1274 }
1275 
1276 template<>
1277 class tuple_size<BOOST_PROCESS_V2_NAMESPACE::environment::key_value_pair_view> : integral_constant<std::size_t, 2u> {};
1278 
1279 template<>
1280 class tuple_element<0u, BOOST_PROCESS_V2_NAMESPACE::environment::key_value_pair_view>
1281 {
1282   public:
1283     using type = BOOST_PROCESS_V2_NAMESPACE::environment::key_view;
1284 };
1285 
1286 template<>
1287 class tuple_element<1u, BOOST_PROCESS_V2_NAMESPACE::environment::key_value_pair_view>
1288 {
1289   public:
1290     using type = BOOST_PROCESS_V2_NAMESPACE::environment::value_view;
1291 };
1292 
1293 template<std::size_t Idx>
1294 inline auto get(BOOST_PROCESS_V2_NAMESPACE::environment::key_value_pair_view kvp) 
1295         -> typename std::tuple_element<Idx, BOOST_PROCESS_V2_NAMESPACE::environment::key_value_pair_view>::type
1296 {
1297     return kvp.get<Idx>();
1298 }
1299 
1300 }
1301 
1302 BOOST_PROCESS_V2_BEGIN_NAMESPACE
1303 namespace environment 
1304 {
1305 
1306 
1307 /// A view object for the current environment of this process.
1308 /**
1309  * The view might (windows) or might not (posix) be owning;
1310  * if it owns it will deallocate the on destruction, like a unique_ptr.
1311  * 
1312  * Note that accessing the environment in this way is not thread-safe.
1313  * 
1314  * @code
1315  * 
1316  * void dump_my_env(current_view env = current())
1317  * {
1318  *    for (auto  & [k, v] : env)
1319  *        std::cout << k.string() << " = "  << v.string() << std::endl;
1320  * }
1321  * 
1322  * @endcode
1323  * 
1324  * 
1325  */ 
1326 struct current_view
1327 {
1328     using native_handle_type = environment::native_handle_type;
1329     using value_type = key_value_pair_view;
1330 
1331     current_view() = default;
1332     current_view(current_view && nt) = default;
1333 
1334     native_handle_type  native_handle() { return handle_.get(); }
1335 
1336     struct iterator
1337     {
1338         using value_type        = key_value_pair_view;
1339         using difference_type   = int;
1340         using reference         = key_value_pair_view;
1341         using pointer           = key_value_pair_view;
1342         using iterator_category = std::forward_iterator_tag;
1343 
1344         iterator() = default;
1345         iterator(const iterator & ) = default;
1346         iterator(const native_iterator &native_handle) : iterator_(native_handle) {}
1347 
1348         iterator & operator++()
1349         {
1350             iterator_ = detail::next(iterator_);
1351             return *this;
1352         }
1353 
1354         iterator operator++(int)
1355         {
1356             auto last = *this;
1357             iterator_ = detail::next(iterator_);
1358             return last;
1359         }
1360         key_value_pair_view operator*() const
1361         {
1362             return detail::dereference(iterator_);
1363         }
1364 
1365         friend bool operator==(const iterator & l, const iterator & r) {return l.iterator_ == r.iterator_;}
1366         friend bool operator!=(const iterator & l, const iterator & r) {return l.iterator_ != r.iterator_;}
1367 
1368       private:
1369         environment::native_iterator iterator_;
1370     };
1371 
1372     iterator begin() const {return iterator(handle_.get());}
1373     iterator   end() const {return iterator(detail::find_end(handle_.get()));}
1374 
1375  private:
1376 
1377   std::unique_ptr<typename remove_pointer<native_handle_type>::type,
1378                     detail::native_handle_deleter> handle_{environment::detail::load_native_handle()};
1379 };
1380 
1381 /// Obtain a handle to the current environment
1382 inline current_view current() {return current_view();}
1383 
1384 namespace detail
1385 {
1386 
1387 template<typename Environment>
1388 auto find_key(Environment & env, key_view ky) 
1389     -> typename std::enable_if<std::is_convertible<decltype(*std::begin(env)), key_value_pair_view>::value, value_view>::type
1390 {
1391     const auto itr = std::find_if(std::begin(env), std::end(env),
1392                                   [&](key_value_pair_view vp)
1393                                   {
1394                                     auto tmp = std::get<0>(vp) == ky;
1395                                     if (tmp)
1396                                       return true;
1397                                     else
1398                                       return false;
1399                                   });
1400     
1401     if (itr != std::end(env))
1402       return key_value_pair_view(*itr).value();
1403     else
1404       return {};
1405 }
1406 
1407 template<typename Environment>
1408 auto find_key(Environment & env, key_view ky) 
1409     -> typename std::enable_if<
1410     !std::is_convertible<decltype(*std::begin(env)), key_value_pair_view>::value && 
1411      std::is_convertible<decltype(*std::begin(env)), key_value_pair>::value, 
1412     value>::type
1413 {
1414     const auto itr = std::find_if(std::begin(env), std::end(env),
1415                                   [&](key_value_pair vp)
1416                                   {
1417                                     auto tmp = std::get<0>(vp) == ky;
1418                                     if (tmp)
1419                                       return true;
1420                                     else
1421                                       return false;
1422                                   });
1423     if (itr != std::end(env))
1424       return key_value_pair(*itr).value();
1425     else
1426       return {};
1427 }
1428 
1429 
1430 }
1431 
1432 
1433 /// Find the home folder in an environment-like type.
1434 /** 
1435  * @param env The environment to search. Defaults to the current environment of this process
1436  * 
1437  * The environment type passed in must be a range with value T that fulfills the following requirements:
1438  * 
1439  *  For `T value`
1440  *
1441  *  - std::get<0>(value) must return a type comparable to `key_view`.
1442  *  - std::get<1>(value) must return a type convertible to filesystem::path.
1443  * 
1444  * @return A filesystem::path to the home directory or an empty path if it cannot be found.
1445  * 
1446  */
1447 template<typename Environment = current_view>
1448 inline filesystem::path home(Environment && env = current())
1449 {
1450 #if defined(BOOST_PROCESS_V2_WINDOWS)
1451   return detail::find_key(env, L"HOMEDRIVE").native_string() 
1452        + detail::find_key(env, L"HOMEPATH").native_string();
1453 #else
1454   return detail::find_key(env, "HOME").native_string();
1455 #endif
1456 }
1457 
1458 /// Find the executable `name` in an environment-like type.
1459 /** 
1460  * @param env The environment to search. Defaults to the current environment of this process
1461  * 
1462  * The environment type passed in must be a range with value T that fulfills the following requirements:
1463  * 
1464  *  For `T value`
1465  *
1466  *  - std::get<0>(value) must return a type comparable to `key_view`.
1467  *  - std::get<1>(value) must return a type convertible to `value_view`.
1468  * 
1469  * 
1470  * @return A filesystem::path to the executable or an empty path if it cannot be found.
1471  * 
1472  */
1473 template<typename Environment = current_view>
1474 inline BOOST_PROCESS_V2_NAMESPACE::filesystem::path find_executable(
1475                                              BOOST_PROCESS_V2_NAMESPACE::filesystem::path name,
1476                                              Environment && env = current())
1477 {
1478 
1479 #if defined(BOOST_PROCESS_V2_WINDOWS)
1480     auto path = detail::find_key(env, L"PATH");
1481     auto pathext = detail::find_key(env, L"PATHEXT");
1482     for (auto pp_view : path)
1483     {
1484         // first check if it has the extension already
1485         BOOST_PROCESS_V2_NAMESPACE::filesystem::path full_nm(name);
1486         BOOST_PROCESS_V2_NAMESPACE::filesystem::path pp(pp_view.begin(), pp_view.end());
1487         auto p = pp / full_nm;
1488         error_code ec;
1489 
1490         if (detail::is_executable(p, ec) && !ec)
1491             return p;
1492 
1493         for (auto ext : pathext)
1494         {
1495             ec.clear();
1496             BOOST_PROCESS_V2_NAMESPACE::filesystem::path nm(name);
1497             nm.concat(ext.begin(), ext.end());
1498 
1499             auto p = pp / nm;
1500 
1501             if (detail::is_executable(p, ec) && !ec)
1502                 return p;
1503         }
1504     }
1505 #else
1506     for (auto pp_view : detail::find_key(env, "PATH"))
1507     {
1508         auto p = BOOST_PROCESS_V2_NAMESPACE::filesystem::path(pp_view.begin(), pp_view.end()) / name;
1509         error_code ec;
1510         bool is_exec = detail::is_executable(p, ec);
1511         if (!ec && is_exec)
1512             return p;
1513     }
1514 #endif
1515     return {};
1516 }
1517 
1518 /// Get an environment variable from the current process.
1519 inline value get(const key & k, error_code & ec) { return detail::get(k.c_str(), ec);}
1520 /// Throwing @overload value get(const key & k, error_code & ec)
1521 inline value get(const key & k)
1522 {
1523   error_code ec;
1524   auto tmp = detail::get(k.c_str(), ec);
1525   BOOST_PROCESS_V2_NAMESPACE::detail::throw_error(ec, "environment::get");
1526   return tmp;
1527 }
1528 
1529 /// Disambiguating @overload value get(const key & k, error_code & ec)
1530 inline value get(basic_cstring_ref<char_type, key_char_traits<char_type>> k, error_code & ec)
1531 {
1532   return detail::get(k, ec);
1533 }
1534 /// Disambiguating @overload value get(const key & k)
1535 inline value get(basic_cstring_ref<char_type, key_char_traits<char_type>> k)
1536 {
1537   error_code ec;
1538   auto tmp = detail::get(k, ec);
1539   BOOST_PROCESS_V2_NAMESPACE::detail::throw_error(ec, "environment::get");
1540   return tmp;
1541 }
1542 
1543 
1544 /// Disambiguating @overload value get(const key & k, error_code & ec)
1545 inline value get(const char_type * c, error_code & ec) { return detail::get(c, ec);}
1546 /// Disambiguating @overload value get(const key & k)
1547 inline value get(const char_type * c)
1548 {
1549   error_code ec;
1550   auto tmp = detail::get(c, ec);
1551   BOOST_PROCESS_V2_NAMESPACE::detail::throw_error(ec, "environment::get");
1552   return tmp;
1553 }
1554 
1555 /// Set an environment variable for the current process.
1556 inline void set(const key & k, value_view vw, error_code & ec) { detail::set(k, vw, ec);}
1557 /// Throwing @overload void set(const key & k, value_view vw, error_code & ec)
1558 inline void set(const key & k, value_view vw)
1559 {
1560   error_code ec;
1561   detail::set(k, vw, ec);
1562   BOOST_PROCESS_V2_NAMESPACE::detail::throw_error(ec, "environment::set");
1563 }
1564 
1565 /// Disambiguating @overload void set(const key & k, value_view vw, error_code & ec)
1566 inline void set(basic_cstring_ref<char_type, key_char_traits<char_type>> k, value_view vw, error_code & ec) { detail::set(k, vw, ec);}
1567 /// Disambiguating @overload void set(const key & k, value_view vw, error_code & ec)
1568 inline void set(basic_cstring_ref<char_type, key_char_traits<char_type>> k, value_view vw)
1569 {
1570   error_code ec;
1571   detail::set(k, vw, ec);
1572   BOOST_PROCESS_V2_NAMESPACE::detail::throw_error(ec, "environment::set");
1573 }
1574 
1575 
1576 /// Disambiguating @overload void set(const key & k, value_view vw, error_code & ec)
1577 inline void set(const char_type * k, value_view vw, error_code & ec) { detail::set(k, vw, ec);}
1578 /// Disambiguating @overload void set(const key & k, value_view vw, error_code & ec)
1579 inline void set(const char_type * k, value_view vw)
1580 {
1581   error_code ec;
1582   detail::set(k, vw, ec);
1583   BOOST_PROCESS_V2_NAMESPACE::detail::throw_error(ec, "environment::set");
1584 }
1585 
1586 /// Disambiguating @overload void set(const key & k, value_view vw, error_code & ec)
1587 template<typename Char, typename = typename std::enable_if<!std::is_same<Char, char_type>::value>::type>
1588 inline void set(const key & k, const Char * vw, error_code & ec)
1589 {
1590     value val{vw};
1591     detail::set(k, val, ec);
1592 }
1593 /// Disambiguating @overload void set(const key & k, value_view vw, error_code & ec)
1594 template<typename Char, typename = typename std::enable_if<!std::is_same<Char, char_type>::value>::type>
1595 inline void set(const key & k, const Char * vw)
1596 {
1597     error_code ec;
1598     value val{vw};
1599     detail::set(k, val, ec);
1600     BOOST_PROCESS_V2_NAMESPACE::detail::throw_error(ec, "environment::set");
1601 }
1602 
1603 /// Disambiguating @overload void set(const key & k, value_view vw, error_code & ec)
1604 template<typename Char, typename = typename std::enable_if<!std::is_same<Char, char_type>::value>::type>
1605 inline void set(basic_cstring_ref<char_type, key_char_traits<char_type>> k, const Char * vw, error_code & ec)
1606 {
1607     value val{vw};
1608     detail::set(k, val, ec);
1609 }
1610 
1611 /// Disambiguating @overload void set(const key & k, value_view vw, error_code & ec)
1612 template<typename Char, typename = typename std::enable_if<!std::is_same<Char, char_type>::value>::type>
1613 inline void set(basic_cstring_ref<char_type, key_char_traits<char_type>> k, const Char * vw)
1614 {
1615     error_code ec;
1616     value val{vw};
1617     detail::set(k, val, ec);
1618     BOOST_PROCESS_V2_NAMESPACE::detail::throw_error(ec, "environment::set");
1619 }
1620 
1621 /// Disambiguating @overload void set(const key & k, value_view vw, error_code & ec)
1622 template<typename Char, typename = typename std::enable_if<!std::is_same<Char, char_type>::value>::type>
1623 inline void set(const char_type * k, const Char * vw, error_code & ec)
1624 {
1625     value val{vw};
1626     detail::set(k, val, ec);
1627 }
1628 
1629 /// Disambiguating @overload void set(const key & k, value_view vw, error_code & ec)
1630 template<typename Char, typename = typename std::enable_if<!std::is_same<Char, char_type>::value>::type>
1631 inline void set(const char_type * k, const Char * vw)
1632 {
1633     error_code ec;
1634     value val{vw};
1635     detail::set(k, val, ec);
1636     BOOST_PROCESS_V2_NAMESPACE::detail::throw_error(ec, "environment::set");
1637 }
1638 
1639 
1640 /// Remove an environment variable from the current process.
1641 inline void unset(const key & k, error_code & ec) { detail::unset(k, ec);}
1642 /// Throwing @overload void unset(const key & k, error_code & ec)
1643 inline void unset(const key & k)
1644 {
1645   error_code ec;
1646   detail::unset(k, ec);
1647   BOOST_PROCESS_V2_NAMESPACE::detail::throw_error(ec, "environment::unset");
1648 }
1649 
1650 /// Disambiguating @overload void unset(const key & k, error_code & ec)
1651 inline void unset(basic_cstring_ref<char_type, key_char_traits<char_type>> k, error_code & ec)
1652 {
1653   detail::unset(k, ec);
1654 }
1655 
1656 /// Disambiguating @overload void unset(const key & k, error_code & ec)
1657 inline void unset(basic_cstring_ref<char_type, key_char_traits<char_type>> k)
1658 {
1659   error_code ec;
1660   detail::unset(k, ec);
1661   BOOST_PROCESS_V2_NAMESPACE::detail::throw_error(ec, "environment::unset");
1662 }
1663 
1664 /// Disambiguating @overload void unset(const key & k, error_code & ec)
1665 inline void unset(const char_type * c, error_code & ec) { detail::unset(c, ec);}
1666 
1667 /// Disambiguating @overload void unset(const key & k, error_code & ec)
1668 inline void unset(const char_type * c)
1669 {
1670   error_code ec;
1671   detail::unset(c, ec);
1672   BOOST_PROCESS_V2_NAMESPACE::detail::throw_error(ec, "environment::unset");
1673 }
1674 }
1675 
1676 // sub process environment stuff
1677 
1678 #if defined(BOOST_PROCESS_V2_WINDOWS)
1679 namespace windows { struct default_launcher ;}
1680 #else
1681 namespace posix { struct default_launcher ;}
1682 #endif 
1683 
1684 /// Initializer for the environment of sub process.
1685 /**
1686  * This will set the environment in a subprocess:
1687  * 
1688  * @code {.cpp}
1689  * 
1690  * process proc{executor, find_executable("printenv"), {"foo"}, process_environment{"foo=bar"}};
1691  * @endcode
1692  * 
1693  * The environment initializer will persist it's state, so that it can
1694  * be used multiple times. Do however note the the Operating System is
1695  * allowed to modify the internal state.
1696  * 
1697  * @code {.cpp}
1698  * auto exe = find_executable("printenv");
1699  * process_environment env = {"FOO=BAR", "BAR=FOO"};
1700  * 
1701  * process proc1(executor, exe, {"FOO"}, env);
1702  * process proc2(executor, exe, {"BAR"}, env);
1703  * @endcode
1704  * 
1705  * 
1706  */
1707 struct process_environment
1708 {
1709 
1710 #if defined(BOOST_PROCESS_V2_WINDOWS)
1711 
1712 
1713   template<typename Args>
1714   static
1715   std::vector<wchar_t> build_env(Args && args,
1716                                       typename std::enable_if<
1717                                               std::is_convertible<
1718                                                       decltype(*std::begin(std::declval<Args>())),
1719                                                       wcstring_ref>::value>::type * = nullptr)
1720   {
1721     std::vector<wchar_t> res;
1722     std::size_t sz = 1;
1723     for (wcstring_ref cs : std::forward<Args>(args))
1724         sz =+ cs.size() + 1;
1725     res.reserve(sz);
1726     
1727     for (wcstring_ref cs : std::forward<Args>(args))
1728         res.insert(res.end(), cs.begin(), std::next(cs.end()));
1729         
1730 
1731     res.push_back(L'\0');
1732     return res;
1733   }
1734 
1735   template<typename Args>
1736   std::vector<wchar_t> build_env(Args && args,
1737                                       typename std::enable_if<
1738                                               !std::is_convertible<
1739                                                       decltype(*std::begin(std::declval<Args>())),
1740                                                       wcstring_ref>::value>::type * = nullptr)
1741   {
1742     for (auto && arg: std::forward<Args>(args))
1743       env_buffer.emplace_back(arg);
1744     return build_env(env_buffer);
1745   }
1746 
1747   process_environment(std::initializer_list<string_view> sv)  : unicode_env{build_env(sv)} {}
1748   process_environment(std::initializer_list<wstring_view> sv) : unicode_env{build_env(sv)} {}
1749 
1750   template<typename Args>
1751   process_environment(Args && args) : unicode_env{build_env(std::forward<Args>(args))}
1752   {
1753   }
1754 
1755   error_code error() {return ec;}
1756   error_code ec;
1757   std::vector<environment::key_value_pair> env_buffer;
1758   std::vector<wchar_t> unicode_env;
1759 
1760   BOOST_PROCESS_V2_DECL
1761   error_code on_setup(windows::default_launcher & launcher,
1762                       const filesystem::path &, const std::wstring &);
1763 
1764 #else
1765 
1766   template<typename Args>
1767   static
1768   std::vector<const char *> build_env(Args && args,
1769                                       typename std::enable_if<
1770                                               std::is_convertible<
1771                                                       decltype(*std::begin(std::declval<Args>())),
1772                                                       cstring_ref>::value>::type * = nullptr)
1773   {
1774     std::vector<const char *> env;
1775     for (auto && e : args)
1776       env.push_back(e.c_str());
1777 
1778     env.push_back(nullptr);
1779     return env;
1780   }
1781 
1782   template<typename Args>
1783   std::vector<const char *> build_env(Args && args,
1784                                       typename std::enable_if<
1785                                               !std::is_convertible<
1786                                                       decltype(*std::begin(std::declval<Args>())),
1787                                                       cstring_ref>::value>::type * = nullptr)
1788   {
1789     std::vector<const char *> env;
1790 
1791     for (auto && arg: std::forward<Args>(args))
1792       env_buffer.emplace_back(arg);
1793 
1794     for (auto && e : env_buffer)
1795       env.push_back(e.c_str());
1796     env.push_back(nullptr);
1797     return env;
1798   }
1799 
1800 
1801   process_environment(std::initializer_list<string_view> sv) : env{build_env(sv)}  {  }
1802 
1803   template<typename Args>
1804   process_environment(Args && args) : env(build_env(std::forward<Args>(args)))
1805   {
1806   }
1807 
1808 
1809   BOOST_PROCESS_V2_DECL
1810   error_code on_setup(posix::default_launcher & launcher, 
1811                       const filesystem::path &, const char * const *);
1812 
1813   std::vector<environment::key_value_pair> env_buffer;
1814   std::vector<const char *> env;
1815 
1816 #endif
1817 
1818 };
1819 
1820 
1821 
1822 BOOST_PROCESS_V2_END_NAMESPACE
1823 
1824 
1825 namespace std
1826 {
1827 
1828 template<>
1829 struct hash<BOOST_PROCESS_V2_NAMESPACE::environment::key_view>
1830 {
1831     std::size_t operator()( BOOST_PROCESS_V2_NAMESPACE::environment::key_view kv) const noexcept
1832     {
1833         return BOOST_PROCESS_V2_NAMESPACE::environment::hash_value(kv);
1834     }
1835 };
1836 
1837 
1838 template<>
1839 struct hash<BOOST_PROCESS_V2_NAMESPACE::environment::value_view>
1840 {
1841     std::size_t operator()( BOOST_PROCESS_V2_NAMESPACE::environment::value_view kv) const noexcept
1842     {
1843         return BOOST_PROCESS_V2_NAMESPACE::environment::hash_value(kv);
1844     }
1845 };
1846 
1847 template<>
1848 struct hash<BOOST_PROCESS_V2_NAMESPACE::environment::key_value_pair_view>
1849 {
1850     std::size_t operator()( BOOST_PROCESS_V2_NAMESPACE::environment::key_value_pair_view kv) const noexcept
1851     {
1852         return BOOST_PROCESS_V2_NAMESPACE::environment::hash_value(kv);
1853     }
1854 };
1855 
1856 
1857 template<>
1858 struct hash<BOOST_PROCESS_V2_NAMESPACE::environment::key>
1859 {
1860     std::size_t operator()( BOOST_PROCESS_V2_NAMESPACE::environment::key_view kv) const noexcept
1861     {
1862         return BOOST_PROCESS_V2_NAMESPACE::environment::hash_value(kv);
1863     }
1864 };
1865 
1866 
1867 template<>
1868 struct hash<BOOST_PROCESS_V2_NAMESPACE::environment::value>
1869 {
1870     std::size_t operator()( BOOST_PROCESS_V2_NAMESPACE::environment::value_view kv) const noexcept
1871     {
1872         return BOOST_PROCESS_V2_NAMESPACE::environment::hash_value(kv);
1873     }
1874 };
1875 
1876 template<>
1877 struct hash<BOOST_PROCESS_V2_NAMESPACE::environment::key_value_pair>
1878 {
1879     std::size_t operator()( BOOST_PROCESS_V2_NAMESPACE::environment::key_value_pair_view kv) const noexcept
1880     {
1881         return BOOST_PROCESS_V2_NAMESPACE::environment::hash_value(kv);
1882     }
1883 };
1884 
1885 }
1886 
1887 
1888 
1889 #if defined(BOOST_PROCESS_V2_HEADER_ONLY)
1890 
1891 #include <boost/process/v2/impl/environment.ipp>
1892 #include <boost/process/v2/detail/impl/environment.ipp>
1893 
1894 #endif
1895 
1896 #endif //BOOST_PROCESS_V2_ENVIRONMENT_HPP