Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-11 08:25:12

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