1 // Copyright (c) 2001-2011 Hartmut Kaiser 2 // 3 // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 6 #if !defined(BOOST_SPIRIT_KARMA_SYMBOLS_NOV_23_2009_1251PM) 7 #define BOOST_SPIRIT_KARMA_SYMBOLS_NOV_23_2009_1251PM 8 9 #include <boost/spirit/home/support/common_terminals.hpp> 10 #include <boost/spirit/home/support/info.hpp> 11 #include <boost/spirit/home/support/unused.hpp> 12 #include <boost/spirit/home/support/attributes_fwd.hpp> 13 #include <boost/spirit/home/support/detail/get_encoding.hpp> 14 #include <boost/spirit/home/karma/detail/attributes.hpp> 15 #include <boost/spirit/home/karma/detail/extract_from.hpp> 16 #include <boost/spirit/home/karma/domain.hpp> 17 #include <boost/spirit/home/karma/meta_compiler.hpp> 18 #include <boost/spirit/home/karma/reference.hpp> 19 #include <boost/spirit/home/karma/generate.hpp> 20 #include <boost/spirit/home/karma/delimit_out.hpp> 21 #include <boost/spirit/home/karma/detail/get_casetag.hpp> 22 #include <boost/spirit/home/karma/detail/string_generate.hpp> 23 #include <boost/config.hpp> 24 #include <boost/proto/extends.hpp> 25 #include <boost/proto/traits.hpp> 26 #include <boost/shared_ptr.hpp> 27 #include <boost/mpl/if.hpp> 28 #include <map> 29 #include <set> 30 31 #if defined(BOOST_MSVC) 32 # pragma warning(push) 33 # pragma warning(disable: 4355) // 'this' : used in base member initializer list warning 34 #endif 35 36 /////////////////////////////////////////////////////////////////////////////// 37 namespace boost { namespace spirit { namespace traits 38 { 39 template <typename T, typename Attribute, typename Enable> 40 struct symbols_lookup 41 { 42 typedef 43 mpl::eval_if<fusion::traits::is_sequence<T> 44 , traits::detail::value_at_c<T, 0> 45 , detail::add_const_ref<T> > sequence_type; 46 typedef typename 47 mpl::eval_if<traits::is_container<T> 48 , traits::container_value<T> 49 , sequence_type>::type type; 50 51 // fusion sequence 52 template <typename T_> callboost::spirit::traits::symbols_lookup53 static type call(T_ const& t, mpl::false_, mpl::true_) 54 { 55 return fusion::at_c<0>(t); 56 } 57 58 // container 59 template <typename T_, typename IsSequence> callboost::spirit::traits::symbols_lookup60 static type call(T_ const& t, mpl::true_, IsSequence) 61 { 62 return t[0]; 63 } 64 65 // not a container and not a fusion sequence 66 template <typename T_> callboost::spirit::traits::symbols_lookup67 static type call(T_ const& t, mpl::false_, mpl::false_) 68 { 69 return t; 70 } 71 callboost::spirit::traits::symbols_lookup72 static type call(T const& t) 73 { 74 typedef typename traits::is_container<T>::type is_container; 75 typedef typename fusion::traits::is_sequence<T>::type is_sequence; 76 77 return call(t, is_container(), is_sequence()); 78 } 79 }; 80 81 template <typename Attribute> 82 struct symbols_lookup<Attribute, Attribute> 83 { 84 typedef Attribute const& type; 85 callboost::spirit::traits::symbols_lookup86 static type call(Attribute const& t) 87 { 88 return t; 89 } 90 }; 91 92 template <typename Attribute, typename T, typename Enable> 93 struct symbols_value 94 { 95 typedef 96 mpl::eval_if<fusion::traits::is_sequence<T> 97 , traits::detail::value_at_c<T, 1> 98 , mpl::identity<unused_type> > sequence_type; 99 typedef typename 100 mpl::eval_if<traits::is_container<T> 101 , traits::container_value<T> 102 , sequence_type>::type type; 103 104 // fusion sequence 105 template <typename T_> callboost::spirit::traits::symbols_value106 static type call(T_ const& t, mpl::false_, mpl::true_) 107 { 108 return fusion::at_c<1>(t); 109 } 110 111 // container 112 template <typename T_, typename IsSequence> callboost::spirit::traits::symbols_value113 static type call(T_ const& t, mpl::true_, IsSequence) 114 { 115 return t[1]; 116 } 117 118 // not a container nor a fusion sequence 119 template <typename T_> callboost::spirit::traits::symbols_value120 static type call(T_ const&, mpl::false_, mpl::false_) 121 { 122 return unused; 123 } 124 callboost::spirit::traits::symbols_value125 static type call(T const& t) 126 { 127 typedef typename traits::is_container<T>::type is_container; 128 typedef typename fusion::traits::is_sequence<T>::type is_sequence; 129 130 return call(t, is_container(), is_sequence()); 131 } 132 }; 133 134 template <typename Attribute> 135 struct symbols_value<Attribute, Attribute> 136 { 137 typedef unused_type type; 138 callboost::spirit::traits::symbols_value139 static type call(Attribute const&) 140 { 141 return unused; 142 } 143 }; 144 }}} 145 146 /////////////////////////////////////////////////////////////////////////////// 147 namespace boost { namespace spirit { namespace karma 148 { 149 /////////////////////////////////////////////////////////////////////////// 150 template <typename T, typename Attribute> 151 struct symbols_lookup 152 : mpl::if_< 153 traits::not_is_unused<T> 154 , std::map<Attribute, T> 155 , std::set<Attribute> 156 > 157 {}; 158 159 /////////////////////////////////////////////////////////////////////////// 160 namespace detail 161 { 162 /////////////////////////////////////////////////////////////////////// 163 template <typename CharEncoding, typename Tag> 164 struct generate_encoded 165 { 166 typedef typename 167 proto::terminal<tag::char_code<Tag, CharEncoding> >::type 168 encoding_type; 169 170 template <typename OutputIterator, typename Expr, typename Attribute> callboost::spirit::karma::detail::generate_encoded171 static bool call(OutputIterator& sink, Expr const& expr 172 , Attribute const& attr) 173 { 174 encoding_type const encoding = encoding_type(); 175 return karma::generate(sink, encoding[expr], attr); 176 } 177 }; 178 179 template <> 180 struct generate_encoded<unused_type, unused_type> 181 { 182 template <typename OutputIterator, typename Expr, typename Attribute> callboost::spirit::karma::detail::generate_encoded183 static bool call(OutputIterator& sink, Expr const& expr 184 , Attribute const& attr) 185 { 186 return karma::generate(sink, expr, attr); 187 } 188 }; 189 } 190 191 template < 192 typename Attribute = char, typename T = unused_type 193 , typename Lookup = typename symbols_lookup<T, Attribute>::type 194 , typename CharEncoding = unused_type, typename Tag = unused_type> 195 struct symbols 196 : proto::extends< 197 typename proto::terminal< 198 reference<symbols<Attribute, T, Lookup, CharEncoding, Tag> > 199 >::type 200 , symbols<Attribute, T, Lookup, CharEncoding, Tag> > 201 , primitive_generator< 202 symbols<Attribute, T, Lookup, CharEncoding, Tag> > 203 { 204 typedef T value_type; // the value associated with each entry 205 206 typedef reference<symbols> reference_; 207 typedef typename proto::terminal<reference_>::type terminal; 208 typedef proto::extends<terminal, symbols> base_type; 209 210 template <typename Context, typename Unused> 211 struct attribute 212 { 213 typedef Attribute type; 214 }; 215 symbolsboost::spirit::karma::symbols216 symbols(std::string const& name = "symbols") 217 : base_type(terminal::make(reference_(*this))) 218 , add(*this) 219 , remove(*this) 220 , lookup(new Lookup()) 221 , name_(name) 222 {} 223 symbolsboost::spirit::karma::symbols224 symbols(symbols const& syms) 225 : base_type(terminal::make(reference_(*this))) 226 , add(*this) 227 , remove(*this) 228 , lookup(syms.lookup) 229 , name_(syms.name_) 230 {} 231 232 template <typename CharEncoding_, typename Tag_> symbolsboost::spirit::karma::symbols233 symbols(symbols<Attribute, T, Lookup, CharEncoding_, Tag_> const& syms) 234 : base_type(terminal::make(reference_(*this))) 235 , add(*this) 236 , remove(*this) 237 , lookup(syms.lookup) 238 , name_(syms.name_) 239 {} 240 241 template <typename Symbols, typename Data> symbolsboost::spirit::karma::symbols242 symbols(Symbols const& syms, Data const& data 243 , std::string const& name = "symbols") 244 : base_type(terminal::make(reference_(*this))) 245 , add(*this) 246 , remove(*this) 247 , lookup(new Lookup()) 248 , name_(name) 249 { 250 typename range_const_iterator<Symbols>::type si = boost::begin(syms); 251 typename range_const_iterator<Data>::type di = boost::begin(data); 252 while (si != boost::end(syms)) 253 add(*si++, *di++); 254 } 255 256 symbols& operator =boost::spirit::karma::symbols257 operator=(symbols const& rhs) 258 { 259 *lookup = *rhs.lookup; 260 name_ = rhs.name_; 261 return *this; 262 } 263 264 template <typename CharEncoding_, typename Tag_> 265 symbols& operator =boost::spirit::karma::symbols266 operator=(symbols<Attribute, T, Lookup, CharEncoding_, Tag_> const& rhs) 267 { 268 *lookup = *rhs.lookup; 269 name_ = rhs.name_; 270 return *this; 271 } 272 clearboost::spirit::karma::symbols273 void clear() 274 { 275 lookup->clear(); 276 } 277 278 struct adder; 279 struct remover; 280 281 template <typename Attr, typename T_> 282 adder const& operator =boost::spirit::karma::symbols283 operator=(std::pair<Attr, T_> const& p) 284 { 285 lookup->clear(); 286 return add(p.first, p.second); 287 } 288 289 template <typename Attr, typename T_> 290 friend adder const& operator +=(symbols & sym,std::pair<Attr,T_> const & p)291 operator+= (symbols& sym, std::pair<Attr, T_> const& p) 292 { 293 return sym.add(p.first, p.second); 294 } 295 296 template <typename Attr> 297 friend remover const& operator -=(symbols & sym,Attr const & attr)298 operator-= (symbols& sym, Attr const& attr) 299 { 300 return sym.remove(attr); 301 } 302 303 #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) 304 // non-const version needed to suppress proto's += kicking in 305 template <typename Attr, typename T_> 306 friend adder const& operator +=(symbols & sym,std::pair<Attr,T_> & p)307 operator+= (symbols& sym, std::pair<Attr, T_>& p) 308 { 309 return sym.add(p.first, p.second); 310 } 311 312 // non-const version needed to suppress proto's -= kicking in 313 template <typename Attr> 314 friend remover const& operator -=(symbols & sym,Attr & attr)315 operator-= (symbols& sym, Attr& attr) 316 { 317 return sym.remove(attr); 318 } 319 #else 320 // for rvalue references 321 template <typename Attr, typename T_> 322 friend adder const& operator +=(symbols & sym,std::pair<Attr,T_> && p)323 operator+= (symbols& sym, std::pair<Attr, T_>&& p) 324 { 325 return sym.add(p.first, p.second); 326 } 327 328 // for rvalue references 329 template <typename Attr> 330 friend remover const& operator -=(symbols & sym,Attr && attr)331 operator-= (symbols& sym, Attr&& attr) 332 { 333 return sym.remove(attr); 334 } 335 #endif 336 template <typename F> for_eachboost::spirit::karma::symbols337 void for_each(F f) const 338 { 339 std::for_each(lookup->begin(), lookup->end(), f); 340 } 341 342 template <typename Attr> findboost::spirit::karma::symbols343 value_type* find(Attr const& attr) 344 { 345 typename Lookup::iterator it = lookup->find(attr); 346 return (it != lookup->end()) ? &(*it).second : 0; 347 } 348 349 template <typename Attr> atboost::spirit::karma::symbols350 value_type& at(Attr const& attr) 351 { 352 return (*lookup)[attr]; 353 } 354 355 /////////////////////////////////////////////////////////////////////// 356 template <typename OutputIterator, typename Context, typename Delimiter 357 , typename Attr> generateboost::spirit::karma::symbols358 bool generate(OutputIterator& sink, Context&, Delimiter const& d 359 , Attr const& attr) const 360 { 361 typename Lookup::iterator it = lookup->find( 362 traits::symbols_lookup<Attr, Attribute>::call(attr)); 363 if (it == lookup->end()) 364 return false; 365 366 return karma::detail::generate_encoded<CharEncoding, Tag>::call( 367 sink, (*it).second 368 , traits::symbols_value<Attribute, Attr>::call(attr)) && 369 karma::delimit_out(sink, d); 370 } 371 372 template <typename Context> whatboost::spirit::karma::symbols373 info what(Context&) const 374 { 375 return info(name_); 376 } 377 nameboost::spirit::karma::symbols378 void name(std::string const &str) 379 { 380 name_ = str; 381 } nameboost::spirit::karma::symbols382 std::string const &name() const 383 { 384 return name_; 385 } 386 387 /////////////////////////////////////////////////////////////////////// 388 struct adder 389 { 390 template <typename, typename = unused_type> 391 struct result { typedef adder const& type; }; 392 adderboost::spirit::karma::symbols::adder393 adder(symbols& sym) 394 : sym(sym) 395 { 396 } 397 398 template <typename Attr> 399 adder const& operator ()boost::spirit::karma::symbols::adder400 operator()(Attr const& attr, T const& val = T()) const 401 { 402 sym.lookup->insert(typename Lookup::value_type(attr, val)); 403 return *this; 404 } 405 406 template <typename Attr> 407 adder const& operator ,boost::spirit::karma::symbols::adder408 operator, (Attr const& attr) const 409 { 410 sym.lookup->insert(typename Lookup::value_type(attr, T())); 411 return *this; 412 } 413 414 symbols& sym; 415 416 // silence MSVC warning C4512: assignment operator could not be generated 417 BOOST_DELETED_FUNCTION(adder& operator= (adder const&)) 418 }; 419 420 struct remover 421 { 422 template <typename> 423 struct result { typedef remover const& type; }; 424 removerboost::spirit::karma::symbols::remover425 remover(symbols& sym) 426 : sym(sym) 427 { 428 } 429 430 template <typename Attr> 431 remover const& operator ()boost::spirit::karma::symbols::remover432 operator()(Attr const& attr) const 433 { 434 sym.lookup->erase(attr); 435 return *this; 436 } 437 438 template <typename Attr> 439 remover const& operator ,boost::spirit::karma::symbols::remover440 operator, (Attr const& attr) const 441 { 442 sym.lookup->erase(attr); 443 return *this; 444 } 445 446 symbols& sym; 447 448 // silence MSVC warning C4512: assignment operator could not be generated 449 BOOST_DELETED_FUNCTION(remover& operator= (remover const&)) 450 }; 451 452 adder add; 453 remover remove; 454 shared_ptr<Lookup> lookup; 455 std::string name_; 456 }; 457 458 /////////////////////////////////////////////////////////////////////////// 459 // specialization for unused stored type 460 template < 461 typename Attribute, typename Lookup 462 , typename CharEncoding, typename Tag> 463 struct symbols<Attribute, unused_type, Lookup, CharEncoding, Tag> 464 : proto::extends< 465 typename proto::terminal< 466 spirit::karma::reference< 467 symbols<Attribute, unused_type, Lookup, CharEncoding, Tag> > 468 >::type 469 , symbols<Attribute, unused_type, Lookup, CharEncoding, Tag> 470 > 471 , spirit::karma::generator< 472 symbols<Attribute, unused_type, Lookup, CharEncoding, Tag> > 473 { 474 typedef unused_type value_type; // the value associated with each entry 475 476 typedef spirit::karma::reference<symbols> reference_; 477 typedef typename proto::terminal<reference_>::type terminal; 478 typedef proto::extends<terminal, symbols> base_type; 479 480 template <typename Context, typename Unused> 481 struct attribute 482 { 483 typedef Attribute type; 484 }; 485 symbolsboost::spirit::karma::symbols486 symbols(std::string const& name = "symbols") 487 : base_type(terminal::make(reference_(*this))) 488 , add(*this) 489 , remove(*this) 490 , lookup(new Lookup()) 491 , name_(name) 492 {} 493 symbolsboost::spirit::karma::symbols494 symbols(symbols const& syms) 495 : base_type(terminal::make(reference_(*this))) 496 , add(*this) 497 , remove(*this) 498 , lookup(syms.lookup) 499 , name_(syms.name_) 500 {} 501 502 template <typename CharEncoding_, typename Tag_> symbolsboost::spirit::karma::symbols503 symbols(symbols<Attribute, unused_type, Lookup, CharEncoding_, Tag_> const& syms) 504 : base_type(terminal::make(reference_(*this))) 505 , add(*this) 506 , remove(*this) 507 , lookup(syms.lookup) 508 , name_(syms.name_) 509 {} 510 511 template <typename Symbols, typename Data> symbolsboost::spirit::karma::symbols512 symbols(Symbols const& syms, Data const& data 513 , std::string const& name = "symbols") 514 : base_type(terminal::make(reference_(*this))) 515 , add(*this) 516 , remove(*this) 517 , lookup(new Lookup()) 518 , name_(name) 519 { 520 typename range_const_iterator<Symbols>::type si = boost::begin(syms); 521 typename range_const_iterator<Data>::type di = boost::begin(data); 522 while (si != boost::end(syms)) 523 add(*si++, *di++); 524 } 525 526 symbols& operator =boost::spirit::karma::symbols527 operator=(symbols const& rhs) 528 { 529 *lookup = *rhs.lookup; 530 name_ = rhs.name_; 531 return *this; 532 } 533 534 template <typename CharEncoding_, typename Tag_> 535 symbols& operator =boost::spirit::karma::symbols536 operator=(symbols<Attribute, unused_type, Lookup, CharEncoding_, Tag_> const& rhs) 537 { 538 *lookup = *rhs.lookup; 539 name_ = rhs.name_; 540 return *this; 541 } 542 clearboost::spirit::karma::symbols543 void clear() 544 { 545 lookup->clear(); 546 } 547 548 struct adder; 549 struct remover; 550 551 template <typename Attr> 552 adder const& operator =boost::spirit::karma::symbols553 operator=(Attr const& attr) 554 { 555 lookup->clear(); 556 return add(attr); 557 } 558 559 template <typename Attr> 560 friend adder const& operator +=(symbols & sym,Attr const & attr)561 operator+= (symbols& sym, Attr const& attr) 562 { 563 return sym.add(attr); 564 } 565 566 template <typename Attr> 567 friend remover const& operator -=(symbols & sym,Attr const & attr)568 operator-= (symbols& sym, Attr const& attr) 569 { 570 return sym.remove(attr); 571 } 572 573 // non-const version needed to suppress proto's += kicking in 574 template <typename Attr> 575 friend adder const& operator +=(symbols & sym,Attr & attr)576 operator+= (symbols& sym, Attr& attr) 577 { 578 return sym.add(attr); 579 } 580 581 // non-const version needed to suppress proto's -= kicking in 582 template <typename Attr> 583 friend remover const& operator -=(symbols & sym,Attr & attr)584 operator-= (symbols& sym, Attr& attr) 585 { 586 return sym.remove(attr); 587 } 588 589 template <typename F> for_eachboost::spirit::karma::symbols590 void for_each(F f) const 591 { 592 std::for_each(lookup->begin(), lookup->end(), f); 593 } 594 595 template <typename Attr> findboost::spirit::karma::symbols596 value_type const* find(Attr const& attr) 597 { 598 typename Lookup::iterator it = lookup->find(attr); 599 return (it != lookup->end()) ? &unused : 0; 600 } 601 602 template <typename Attr> atboost::spirit::karma::symbols603 value_type at(Attr const& attr) 604 { 605 typename Lookup::iterator it = lookup->find(attr); 606 if (it == lookup->end()) 607 add(attr); 608 return unused; 609 } 610 611 /////////////////////////////////////////////////////////////////////// 612 template <typename OutputIterator, typename Context, typename Delimiter 613 , typename Attr> generateboost::spirit::karma::symbols614 bool generate(OutputIterator& sink, Context&, Delimiter const& d 615 , Attr const& attr) const 616 { 617 typename Lookup::iterator it = lookup->find( 618 traits::symbols_lookup<Attr, Attribute>::call(attr)); 619 if (it == lookup->end()) 620 return false; 621 622 return karma::detail::generate_encoded<CharEncoding, Tag>:: 623 call(sink 624 , traits::symbols_lookup<Attr, Attribute>::call(attr) 625 , unused) && 626 karma::delimit_out(sink, d); 627 } 628 629 template <typename Context> whatboost::spirit::karma::symbols630 info what(Context&) const 631 { 632 return info(name_); 633 } 634 nameboost::spirit::karma::symbols635 void name(std::string const &str) 636 { 637 name_ = str; 638 } nameboost::spirit::karma::symbols639 std::string const &name() const 640 { 641 return name_; 642 } 643 644 /////////////////////////////////////////////////////////////////////// 645 struct adder 646 { 647 template <typename, typename = unused_type> 648 struct result { typedef adder const& type; }; 649 adderboost::spirit::karma::symbols::adder650 adder(symbols& sym) 651 : sym(sym) 652 { 653 } 654 655 template <typename Attr> 656 adder const& operator ()boost::spirit::karma::symbols::adder657 operator()(Attr const& attr) const 658 { 659 sym.lookup->insert(attr); 660 return *this; 661 } 662 663 template <typename Attr> 664 adder const& operator ,boost::spirit::karma::symbols::adder665 operator, (Attr const& attr) const 666 { 667 sym.lookup->insert(attr); 668 return *this; 669 } 670 671 symbols& sym; 672 673 // silence MSVC warning C4512: assignment operator could not be generated 674 BOOST_DELETED_FUNCTION(adder& operator= (adder const&)) 675 }; 676 677 struct remover 678 { 679 template <typename> 680 struct result { typedef remover const& type; }; 681 removerboost::spirit::karma::symbols::remover682 remover(symbols& sym) 683 : sym(sym) 684 { 685 } 686 687 template <typename Attr> 688 remover const& operator ()boost::spirit::karma::symbols::remover689 operator()(Attr const& attr) const 690 { 691 sym.lookup->erase(attr); 692 return *this; 693 } 694 695 template <typename Attr> 696 remover const& operator ,boost::spirit::karma::symbols::remover697 operator, (Attr const& attr) const 698 { 699 sym.lookup->erase(attr); 700 return *this; 701 } 702 703 symbols& sym; 704 705 // silence MSVC warning C4512: assignment operator could not be generated 706 BOOST_DELETED_FUNCTION(remover& operator= (remover const&)) 707 }; 708 709 adder add; 710 remover remove; 711 shared_ptr<Lookup> lookup; 712 std::string name_; 713 }; 714 715 /////////////////////////////////////////////////////////////////////////// 716 // Generator generators: make_xxx function (objects) 717 /////////////////////////////////////////////////////////////////////////// 718 template <typename Attribute, typename T, typename Lookup 719 , typename CharEnconding, typename Tag, typename Modifiers> 720 struct make_primitive< 721 reference<symbols<Attribute, T, Lookup, CharEnconding, Tag> > 722 , Modifiers> 723 { 724 static bool const lower = 725 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value; 726 static bool const upper = 727 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value; 728 729 typedef reference< 730 symbols<Attribute, T, Lookup, CharEnconding, Tag> 731 > reference_; 732 733 typedef typename mpl::if_c< 734 lower || upper 735 , symbols< 736 Attribute, T, Lookup 737 , typename spirit::detail::get_encoding_with_case< 738 Modifiers, unused_type, lower || upper>::type 739 , typename detail::get_casetag<Modifiers, lower || upper>::type> 740 , reference_>::type 741 result_type; 742 operator ()boost::spirit::karma::make_primitive743 result_type operator()(reference_ ref, unused_type) const 744 { 745 return result_type(ref.ref.get()); 746 } 747 }; 748 }}} 749 750 namespace boost { namespace spirit { namespace traits 751 { 752 /////////////////////////////////////////////////////////////////////////// 753 template <typename Attribute, typename T, typename Lookup 754 , typename CharEncoding, typename Tag 755 , typename Attr, typename Context, typename Iterator> 756 struct handles_container<karma::symbols<Attribute, T, Lookup, CharEncoding, Tag> 757 , Attr, Context, Iterator> 758 : traits::is_container<Attr> {}; 759 }}} 760 761 #if defined(BOOST_MSVC) 762 # pragma warning(pop) 763 #endif 764 765 #endif 766 767