diff --git a/ridlbe/c++11/config/cxx_type.rb b/ridlbe/c++11/config/cxx_type.rb index 2a0c85ad..ce581182 100644 --- a/ridlbe/c++11/config/cxx_type.rb +++ b/ridlbe/c++11/config/cxx_type.rb @@ -60,12 +60,10 @@ def cxx_member_type_name self.respond_to?(:node) ? cxx_type(node.enclosure) : cxx_type end - def cdr_to_type(scope = nil) - #cxx_type(scope) + def cdr_to_helper_type end - def cdr_from_type(scope = nil) - cxx_type(scope) + def cdr_from_helper_type end def resolved_cxx_type(scope = nil) @@ -232,20 +230,20 @@ def idltype_name(_scope = nil) 'int8' end - def cdr_to_type(_scope = nil) + def cdr_to_helper_type 'ACE_InputCDR::to_int8' end - def cdr_from_type(_scope = nil) + def cdr_from_helper_type 'ACE_OutputCDR::from_int8' end def cdr_to_fmt - "#{cdr_to_type} (#{super})" + "#{cdr_to_helper_type} (#{super})" end def cdr_from_fmt - "#{cdr_from_type} (#{super})" + "#{cdr_from_helper_type} (#{super})" end end @@ -275,20 +273,20 @@ def idltype_name(_scope = nil) 'uint8' end - def cdr_to_type(_scope = nil) + def cdr_to_helper_type 'ACE_InputCDR::to_uint8' end - def cdr_from_type(_scope = nil) + def cdr_from_helper_type 'ACE_OutputCDR::from_uint8' end def cdr_to_fmt - "#{cdr_to_type} (#{super})" + "#{cdr_to_helper_type} (#{super})" end def cdr_from_fmt - "#{cdr_from_type} (#{super})" + "#{cdr_from_helper_type} (#{super})" end end @@ -355,20 +353,20 @@ def cxx_arg_type(_scope = nil) 'ACE_InputCDR::to_boolean' end - def cdr_to_type(_scope = nil) + def cdr_to_helper_type 'ACE_InputCDR::to_boolean' end - def cdr_from_type(_scope = nil) + def cdr_from_helper_type 'ACE_OutputCDR::from_boolean' end def cdr_to_fmt - "#{cdr_to_type} (#{super})" + "#{cdr_to_helper_type} (#{super})" end def cdr_from_fmt - "#{cdr_from_type} (#{super})" + "#{cdr_from_helper_type} (#{super})" end def is_pod? @@ -399,20 +397,20 @@ def value_to_s(v, _scope = nil) end end - def cdr_to_type(_scope = nil) + def cdr_to_helper_type 'ACE_InputCDR::to_char' end - def cdr_from_type(_scope = nil) + def cdr_from_helper_type 'ACE_OutputCDR::from_char' end def cdr_to_fmt - "#{cdr_to_type} (#{super})" + "#{cdr_to_helper_type} (#{super})" end def cdr_from_fmt - "#{cdr_from_type} (#{super})" + "#{cdr_from_helper_type} (#{super})" end def is_pod? @@ -447,20 +445,20 @@ def value_to_s(v, _scope = nil) end end - def cdr_to_type(_scope = nil) + def cdr_to_helper_type 'ACE_InputCDR::to_wchar' end - def cdr_from_type(_scope = nil) + def cdr_from_helper_type 'ACE_OutputCDR::from_wchar' end def cdr_to_fmt - "#{cdr_to_type} (#{super})" + "#{cdr_to_helper_type} (#{super})" end def cdr_from_fmt - "#{cdr_from_type} (#{super})" + "#{cdr_from_helper_type} (#{super})" end def is_pod? @@ -473,20 +471,20 @@ def cxx_arg_type(_scope = nil) 'ACE_InputCDR::to_octet' end - def cdr_to_type(_scope = nil) + def cdr_to_helper_type 'ACE_InputCDR::to_octet' end - def cdr_from_type(_scope = nil) + def cdr_from_helper_type 'ACE_OutputCDR::from_octet' end def cdr_to_fmt - "#{cdr_to_type} (#{super})" + "#{cdr_to_helper_type} (#{super})" end def cdr_from_fmt - "#{cdr_from_type} (#{super})" + "#{cdr_from_helper_type} (#{super})" end def os_fmt @@ -830,12 +828,12 @@ def cxx_arg_type(_scope = nil) resolved_type.cxx_arg_type end - def cdr_to_type(scope = nil) - resolved_type.cdr_to_type(scope) + def cdr_to_helper_type + resolved_type.cdr_to_helper_type end - def cdr_from_type(scope = nil) - resolved_type.cdr_from_type(scope) + def cdr_from_helper_type + resolved_type.cdr_from_helper_type end def cdr_to_fmt diff --git a/ridlbe/c++11/templates/cli/hdr/struct_idl_traits_def.erb b/ridlbe/c++11/templates/cli/hdr/struct_idl_traits_def.erb index 87a27231..fc044550 100644 --- a/ridlbe/c++11/templates/cli/hdr/struct_idl_traits_def.erb +++ b/ridlbe/c++11/templates/cli/hdr/struct_idl_traits_def.erb @@ -35,7 +35,7 @@ struct formatter<<%= scoped_cxxtype %>, OStrm_> % end % else % if _m.optional? - << "<%= _sep %><%= _m.cxxname %>="; if (val_.<%= _m.cxxname() %> ().has_value ()) { os_ << IDL::traits<<%= _m.scoped_cxxtype %>>::write(val_.<%= _m.cxxname %> ().value ()); } else { os_ << "std::nullopt"; } os_ + << "<%= _sep %><%= _m.cxxname %>=" << val_.<%= _m.cxxname %> () % elsif _m.external? %# TODO % else diff --git a/ridlbe/c++11/templates/cli/hdr/union_idl_traits_def.erb b/ridlbe/c++11/templates/cli/hdr/union_idl_traits_def.erb index bc9c48c4..bcff0845 100644 --- a/ridlbe/c++11/templates/cli/hdr/union_idl_traits_def.erb +++ b/ridlbe/c++11/templates/cli/hdr/union_idl_traits_def.erb @@ -13,7 +13,7 @@ struct formatter<<%= scoped_cxxtype %>, OStrm_> % # in these cases there is only a single member mapping all labels % _m = _defmem || _ndefmem.shift % if _m.optional? - os_ << "<%= _m.cxxname %>="; if (val_.<%= _m.cxxname() %> ().has_value ()) { os_ << IDL::traits<<%= _m.scoped_cxxtype %>>::write (val_.<%= _m.cxxname %> ().value ());} else { os_ << "std::nullopt"; } + os_ << "<%= _m.cxxname %>=" << val_.<%= _m.cxxname %> (); % else os_ << "<%= _m.cxxname %>=" << IDL::traits<<%= _m.scoped_cxxtype %>>::write (val_.<%= _m.cxxname %> ()); % end @@ -24,7 +24,7 @@ struct formatter<<%= scoped_cxxtype %>, OStrm_> if (<%= _lbl == 'false' ? '!' : '' %>val_._d ()) { % if _m.optional? - os_ << "<%= _m.cxxname %>="; if (val_.<%= _m.cxxname() %> ().has_value ()) { os_ << IDL::traits<<%= _m.scoped_cxxtype %>>::write (val_.<%= _m.cxxname %> ().value ());} else { os_ << "std::nullopt"; } + os_ << "<%= _m.cxxname %>=" << val_.<%= _m.cxxname %> (); % else os_ << "<%= _m.cxxname %>=" << IDL::traits<<%= _m.scoped_cxxtype %>>::write (val_.<%= _m.cxxname %> ()); % end @@ -34,7 +34,7 @@ struct formatter<<%= scoped_cxxtype %>, OStrm_> { % _m = _defmem || _ndefmem.shift # get other (non-)default member % if _m.optional? - os_ << "<%= _m.cxxname %>="; if (val_.<%= _m.cxxname() %> ().has_value ()) { os_ << IDL::traits<<%= _m.scoped_cxxtype %>>::write (val_.<%= _m.cxxname %> ().value ());} else { os_ << "std::nullopt"; } + os_ << "<%= _m.cxxname %>=" << val_.<%= _m.cxxname %> (); % else os_ << "<%= _m.cxxname %>=" << IDL::traits<<%= _m.scoped_cxxtype %>>::write (val_.<%= _m.cxxname %> ()); % end @@ -51,7 +51,7 @@ struct formatter<<%= scoped_cxxtype %>, OStrm_> % end { % if _m.optional? - os_ << "<%= _m.cxxname %>="; if (val_.<%= _m.cxxname() %> ().has_value ()) { os_ << IDL::traits<<%= _m.scoped_cxxtype %>>::write (val_.<%= _m.cxxname %> ().value ());} else { os_ << "std::nullopt"; } + os_ << "<%= _m.cxxname %>=" << val_.<%= _m.cxxname %> (); % elsif _m.external? %# TODO % else @@ -67,7 +67,7 @@ struct formatter<<%= scoped_cxxtype %>, OStrm_> % _m_def = default_member { % if _m_def.optional? - os_ << "<%= _m_def.cxxname %>="; if (val_.<%= _m_def.cxxname() %> ().has_value ()) { os_ << IDL::traits<<%= _m_def.scoped_cxxtype %>>::write (val_.<%= _m_def.cxxname %> ().value ());} else { os_ << "std::nullopt"; } + os_ << "<%= _m_def.cxxname %>=" << val_.<%= _m_def.cxxname %> (); % elsif _m_def.external? %# TODO % else diff --git a/ridlbe/c++11/templates/cli/src/except_cdr.erb b/ridlbe/c++11/templates/cli/src/except_cdr.erb index eef857f3..9dae9820 100644 --- a/ridlbe/c++11/templates/cli/src/except_cdr.erb +++ b/ridlbe/c++11/templates/cli/src/except_cdr.erb @@ -8,7 +8,7 @@ TAO_CORBA::Boolean operator<< (TAO_OutputCDR &strm, const <%= scoped_cxxname %> % _n = member_count-1 % members.each_with_index do |_m, _i| % if _m.optional? - (taox11_optional_cdr_in<<%= _m.cxx_member_type%>, <%= _m.cdr_from_type %>>::insert (strm, _tao_aggregate.<%= _m.cxxname %> ()))<%= ((_i < _n ) ? ' &&' : ';') %> + (taox11_optional_cdr_in<<%= _m.cxx_member_type%><%= !_m.cdr_from_helper_type.nil? ? ', ' : '' %><%= _m.cdr_from_helper_type %>>::insert (strm, _tao_aggregate.<%= _m.cxxname %> ()))<%= ((_i < _n ) ? ' &&' : ';') %> % else (strm <<<%= _m.cdr_from_fmt % "_tao_aggregate.#{_m.cxxname} ()" %>)<%= ((_i < _n ) ? ' &&' : ';') %> % end @@ -25,7 +25,7 @@ TAO_CORBA::Boolean operator>> ( return % members.each_with_index do |_m, _i| % if _m.optional? - (taox11_optional_cdr_out<<%= _m.cxx_member_type%><%= !_m.cdr_to_type.nil? ? ', ' : '' %><%= _m.cdr_to_type %>>::extract (strm, _tao_aggregate.<%= _m.cxxname %> ()))<%= ((_i < _n ) ? ' &&' : ';') %> + (taox11_optional_cdr_out<<%= _m.cxx_member_type%><%= !_m.cdr_to_helper_type.nil? ? ', ' : '' %><%= _m.cdr_to_helper_type %>>::extract (strm, _tao_aggregate.<%= _m.cxxname %> ()))<%= ((_i < _n ) ? ' &&' : ';') %> % else (strm >> <%= _m.cdr_to_fmt % "_tao_aggregate.#{_m.cxxname} ()" %>)<%= ((_i < _n) ? ' &&' : ';') %> % end diff --git a/ridlbe/c++11/templates/cli/src/struct_cdr.erb b/ridlbe/c++11/templates/cli/src/struct_cdr.erb index 15d1bc8c..ccdafe2a 100644 --- a/ridlbe/c++11/templates/cli/src/struct_cdr.erb +++ b/ridlbe/c++11/templates/cli/src/struct_cdr.erb @@ -10,7 +10,7 @@ TAO_CORBA::Boolean operator<< (TAO_OutputCDR &<% if member_count > 0 || !base.ni % _n = member_count-1 % members.each_with_index do |_m, _i| % if _m.optional? - (taox11_optional_cdr_in<<%= _m.cxx_member_type%>, <%= _m.cdr_from_type %>>::insert (strm, _tao_aggregate.<%= _m.cxxname %> ()))<%= ((_i < _n ) ? ' &&' : ';') %> + (taox11_optional_cdr_in<<%= _m.cxx_member_type%><%= !_m.cdr_from_helper_type.nil? ? ', ' : '' %><%= _m.cdr_from_helper_type %>>::insert (strm, _tao_aggregate.<%= _m.cxxname %> ()))<%= ((_i < _n ) ? ' &&' : ';') %> % else (strm << <%= _m.cdr_from_fmt % "_tao_aggregate.#{_m.cxxname} ()" %>)<%= ((_i < _n ) ? ' &&' : ';') %> % end @@ -30,7 +30,7 @@ TAO_CORBA::Boolean operator>> (TAO_InputCDR &<% if member_count > 0 || !base.nil % members.each_with_index do |_m, _i| %# <%= _m.cdr_to_fmt % "_tao_aggregate.#{_m.cxxname} ()" %> % if _m.optional? - (taox11_optional_cdr_out<<%= _m.cxx_member_type%><%= !_m.cdr_to_type.nil? ? ', ' : '' %><%= _m.cdr_to_type %>>::extract (strm, _tao_aggregate.<%= _m.cxxname %> ()))<%= ((_i < _n ) ? ' &&' : ';') %> + (taox11_optional_cdr_out<<%= _m.cxx_member_type%><%= !_m.cdr_to_helper_type.nil? ? ', ' : '' %><%= _m.cdr_to_helper_type %>>::extract (strm, _tao_aggregate.<%= _m.cxxname %> ()))<%= ((_i < _n ) ? ' &&' : ';') %> % else (strm >> <%= _m.cdr_to_fmt % "_tao_aggregate.#{_m.cxxname} ()" %>)<%= ((_i < _n) ? ' &&' : ';') %> % end diff --git a/ridlbe/c++11/templates/cli/src/union_cdr.erb b/ridlbe/c++11/templates/cli/src/union_cdr.erb index 3487c84e..26c1b2c4 100644 --- a/ridlbe/c++11/templates/cli/src/union_cdr.erb +++ b/ridlbe/c++11/templates/cli/src/union_cdr.erb @@ -15,7 +15,7 @@ TAO_CORBA::Boolean operator<< (TAO_OutputCDR &strm, const <%= scoped_cxxname %> % # in these cases there is only a single member mapping all labels % _m = _defmem || _ndefmem.shift % if _m.optional? - result = (taox11_optional_cdr_in<<%= _m.cxx_member_type%>, <%= _m.cdr_from_type %>>::insert (strm, _tao_union.<%= _m.cxxname %> ())); + result = (taox11_optional_cdr_in<<%= _m.cxx_member_type%><%= !_m.cdr_from_helper_type.nil? ? ', ' : '' %><%= _m.cdr_from_helper_type %>>::insert (strm, _tao_union.<%= _m.cxxname %> ())); % else result = strm << <%= _m.cdr_from_fmt % "_tao_union.#{_m.cxxname} ()" %>; % end @@ -26,7 +26,7 @@ TAO_CORBA::Boolean operator<< (TAO_OutputCDR &strm, const <%= scoped_cxxname %> if (<%= _lbl == 'false' ? '!' : '' %>_tao_union._d ()) { % if _m.optional? - result = (taox11_optional_cdr_in<<%= _m.cxx_member_type%>, <%= _m.cdr_from_type %>>::insert (strm, _tao_union.<%= _m.cxxname %> ())); + result = (taox11_optional_cdr_in<<%= _m.cxx_member_type%><%= !_m.cdr_from_helper_type.nil? ? ', ' : '' %><%= _m.cdr_from_helper_type %>>::insert (strm, _tao_union.<%= _m.cxxname %> ())); % else result = strm << <%= _m.cdr_from_fmt % "_tao_union.#{_m.cxxname} ()" %>; % end @@ -36,7 +36,7 @@ TAO_CORBA::Boolean operator<< (TAO_OutputCDR &strm, const <%= scoped_cxxname %> { % _m = _defmem || _ndefmem.shift # get other (non-)default member % if _m.optional? - result = (taox11_optional_cdr_in<<%= _m.cxx_member_type%>, <%= _m.cdr_from_type %>>::insert (strm, _tao_union.<%= _m.cxxname %> ())); + result = (taox11_optional_cdr_in<<%= _m.cxx_member_type%><%= !_m.cdr_from_helper_type.nil? ? ', ' : '' %><%= _m.cdr_from_helper_type %>>::insert (strm, _tao_union.<%= _m.cxxname %> ())); % else result = strm << <%= _m.cdr_from_fmt % "_tao_union.#{_m.cxxname} ()" %>; % end @@ -53,7 +53,7 @@ TAO_CORBA::Boolean operator<< (TAO_OutputCDR &strm, const <%= scoped_cxxname %> % end { % if _m.optional? - result = (taox11_optional_cdr_in<<%= _m.cxx_member_type%>, <%= _m.cdr_from_type %>>::insert (strm, _tao_union.<%= _m.cxxname %> ())); + result = (taox11_optional_cdr_in<<%= _m.cxx_member_type%><%= !_m.cdr_from_helper_type.nil? ? ', ' : '' %><%= _m.cdr_from_helper_type %>>::insert (strm, _tao_union.<%= _m.cxxname %> ())); % else result = strm << <%= _m.cdr_from_fmt % "_tao_union.#{_m.cxxname} ()" %>; % end @@ -67,7 +67,7 @@ TAO_CORBA::Boolean operator<< (TAO_OutputCDR &strm, const <%= scoped_cxxname %> % _m_def = default_member { % if _m_def.optional? - result = (taox11_optional_cdr_in<<%= _m_def.cxx_member_type%>, <%= _m_def.cdr_from_type %>>::insert (strm, _tao_union.<%= _m_def.cxxname %> ())); + result = (taox11_optional_cdr_in<<%= _m_def.cxx_member_type%><%= !_m_def.cdr_from_helper_type.nil? ? ', ' : '' %><%= _m_def.cdr_from_helper_type %>>::insert (strm, _tao_union.<%= _m_def.cxxname %> ())); % else result = strm << <%= _m_def.cdr_from_fmt % "_tao_union.#{_m_def.cxxname} ()" %>; % end @@ -113,7 +113,7 @@ TAO_CORBA::Boolean operator>> (TAO_InputCDR &strm, <%= scoped_cxxname %> &_tao_u <%= _m.cxx_member_type %> temp_val<%= _m.value_initializer %>; // extract % if _m.optional? - if (taox11_optional_cdr_out<<%= _m.cxx_member_type%><%= !_m.cdr_to_type.nil? ? ', ' : '' %><%= _m.cdr_to_type %>>::extract (strm, temp_val)) + if (taox11_optional_cdr_out<<%= _m.cxx_member_type%><%= !_m.cdr_to_helper_type.nil? ? ', ' : '' %><%= _m.cdr_to_helper_type %>>::extract (strm, temp_val)) % else if (strm >> <%= _m.cdr_to_fmt % "temp_val" %>) % end @@ -131,7 +131,7 @@ TAO_CORBA::Boolean operator>> (TAO_InputCDR &strm, <%= scoped_cxxname %> &_tao_u <%= _m.cxx_member_type %> temp_val<%= _m.value_initializer %>; // extract % if _m.optional? - if (taox11_optional_cdr_out<<%= _m.cxx_member_type%><%= !_m.cdr_to_type.nil? ? ', ' : '' %><%= _m.cdr_to_type %>>::extract (strm, temp_val)) + if (taox11_optional_cdr_out<<%= _m.cxx_member_type%><%= !_m.cdr_to_helper_type.nil? ? ', ' : '' %><%= _m.cdr_to_helper_type %>>::extract (strm, temp_val)) % else if (strm >> <%= _m.cdr_to_fmt % "temp_val" %>) % end @@ -156,7 +156,7 @@ TAO_CORBA::Boolean operator>> (TAO_InputCDR &strm, <%= scoped_cxxname %> &_tao_u <%= _m.cxx_member_type %> temp_val<%= _m.value_initializer %>; // extract % if _m.optional? - if (taox11_optional_cdr_out<<%= _m.cxx_member_type%><%= !_m.cdr_to_type.nil? ? ', ' : '' %><%= _m.cdr_to_type %>>::extract (strm, temp_val)) + if (taox11_optional_cdr_out<<%= _m.cxx_member_type%><%= !_m.cdr_to_helper_type.nil? ? ', ' : '' %><%= _m.cdr_to_helper_type %>>::extract (strm, temp_val)) % else if (strm >> <%= _m.cdr_to_fmt % "temp_val" %>) % end @@ -178,7 +178,7 @@ TAO_CORBA::Boolean operator>> (TAO_InputCDR &strm, <%= scoped_cxxname %> &_tao_u <%= _m_def.cxx_member_type %> temp_val<%= _m_def.value_initializer %>; // extract % if _m_def.optional? - if (taox11_optional_cdr_out<<%= _m_def.cxx_member_type%><%= !_m_def.cdr_to_type.nil? ? ', ' : '' %><%= _m_def.cdr_to_type %>>::extract (strm, temp_val)) + if (taox11_optional_cdr_out<<%= _m_def.cxx_member_type%><%= !_m_def.cdr_to_helper_type.nil? ? ', ' : '' %><%= _m_def.cdr_to_helper_type %>>::extract (strm, temp_val)) % else if (strm >> <%= _m_def.cdr_to_fmt % "temp_val" %>) % end diff --git a/ridlbe/c++11/visitorbase.rb b/ridlbe/c++11/visitorbase.rb index 4d8d7a21..bedae155 100644 --- a/ridlbe/c++11/visitorbase.rb +++ b/ridlbe/c++11/visitorbase.rb @@ -473,12 +473,12 @@ def implementation_member_type self._idltype.is_a?(IDL::Type::Any) ? 'CORBA::Any' : scoped_cxx_member_type end - def cdr_to_type - self._idltype.cdr_to_type(cur_scope) + def cdr_to_helper_type + self._idltype.cdr_to_helper_type end - def cdr_from_type - self._idltype.cdr_from_type(cur_scope) + def cdr_from_helper_type + self._idltype.cdr_from_helper_type end def cdr_from_fmt diff --git a/tao/x11/optional_cdr_t.h b/tao/x11/optional_cdr_t.h index 116f01ea..d08ab0b1 100644 --- a/tao/x11/optional_cdr_t.h +++ b/tao/x11/optional_cdr_t.h @@ -15,8 +15,32 @@ TAO_BEGIN_VERSIONED_NAMESPACE_DECL /// Generic sequence CDR streaming helper template - template - struct taox11_optional_cdr_in + template + struct taox11_optional_cdr_in; + + template + struct taox11_optional_cdr_in<_Tp> + { + /// Unbounded insert + template + static bool insert (_Stream& _strm, const _Tp& _optional) + { + if (!(_strm << ACE_OutputCDR::from_boolean (_optional.has_value ()))) + { + return false; + } + + bool result { true }; + if (_optional.has_value ()) + { + result = _strm << _optional.value (); + } + return result; + } + }; + + template + struct taox11_optional_cdr_in<_Tp, _Thelper> { /// Unbounded insert template @@ -30,7 +54,7 @@ TAO_BEGIN_VERSIONED_NAMESPACE_DECL bool result { true }; if (_optional.has_value ()) { - result = _strm << _T (_optional.value ()); + result = _strm << _Thelper(_optional.value ()); } return result; } @@ -76,8 +100,8 @@ TAO_BEGIN_VERSIONED_NAMESPACE_DECL }; /// Generic sequence CDR streaming helper template - template - struct taox11_optional_cdr_out<_Tp, _T> + template + struct taox11_optional_cdr_out<_Tp, _Thelper> { /// Unbounded extract template @@ -94,7 +118,7 @@ TAO_BEGIN_VERSIONED_NAMESPACE_DECL // If the optional doesn't contain a value initialize it if (!_optional) _optional.emplace(); // extract - if (_strm >> _T(_optional.value ())) + if (_strm >> _Thelper(_optional.value ())) { return true; } diff --git a/tao/x11/optional_t.h b/tao/x11/optional_t.h index be47fd21..1214b617 100644 --- a/tao/x11/optional_t.h +++ b/tao/x11/optional_t.h @@ -20,6 +20,20 @@ namespace TAOX11_NAMESPACE { template using optional = std::optional; + + template + std::ostream& operator <<(std::ostream& stream, const optional& optional) + { + if (optional.has_value()) + { + stream << IDL::traits::write(optional.value ()); + } + else + { + stream << "std::nullopt"; + } + return stream; + } } // namespace IDL } // namespace TAOX11_NAMESPACE