<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkFollower.hh
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
// .NAME vtkFollower - a subclass of actor that always faces the camera
// .SECTION Description
// vtkFollowr is a subclass of vtkActor that always follows its specified
// camera.

#ifndef __vtkFollower_hh
#define __vtkFollower_hh

#include "vtkActor.hh"
class vtkCamera;

class vtkFollower : public vtkActor
{
 public:
  vtkFollower();
  ~vtkFollower();
  char *GetClassName() {return "vtkFollower";};
  void PrintSelf(ostream& os, vtkIndent indent);

  virtual void GetMatrix(vtkMatrix4x4& m);

  // Description:
  // Sets the Camera to follow
  vtkSetObjectMacro(Camera,vtkCamera);
  // Description:
  // Returns the Camera it is following
  vtkGetObjectMacro(Camera,vtkCamera);

protected:
  vtkCamera *Camera;
};

#endif

<commit_msg>updated comments<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkFollower.hh
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
// .NAME vtkFollower - a subclass of actor that always faces the camera
// .SECTION Description
// vtkFollowr is a subclass of vtkActor that always follows its specified
// camera. More specifically it will not change its position or scale,
// but it will continually update its orientation so that it is right side
// up and facing the camera. This is typically used for text labels in a
// scene. All of the adjustments that can be made to an actor will also
// take effect with a follwer.  So if you change the orientation of the
// follower by 90 degrees then it will follow the camera, but be off by
// 90 degrees.

// .SECTION see also
// vtkActor vtkCamera

#ifndef __vtkFollower_hh
#define __vtkFollower_hh

#include "vtkActor.hh"
class vtkCamera;

class vtkFollower : public vtkActor
{
 public:
  vtkFollower();
  ~vtkFollower();
  char *GetClassName() {return "vtkFollower";};
  void PrintSelf(ostream& os, vtkIndent indent);

  virtual void GetMatrix(vtkMatrix4x4& m);

  // Description:
  // Set/Get the Camera to follow. If this is not set then the follower
  // won't know who to follow.
  vtkSetObjectMacro(Camera,vtkCamera);
  vtkGetObjectMacro(Camera,vtkCamera);

protected:
  vtkCamera *Camera;
};

#endif

<|endoftext|>


<commit_before>/*
 * This file is part of otf2xx (https://github.com/tud-zih-energy/otf2xx)
 * otf2xx - A wrapper for the Open Trace Format 2 library
 *
 * Copyright (c) 2013-2016, Technische Universität Dresden, Germany
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * * Neither the name of the copyright holder nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#ifndef INCLUDE_OTF2XX_DEFINITIONS_PROPERTY_HPP
#define INCLUDE_OTF2XX_DEFINITIONS_PROPERTY_HPP

#include <otf2xx/common.hpp>
#include <otf2xx/fwd.hpp>
#include <otf2xx/reference.hpp>

#include <otf2xx/definition/string.hpp>

#include <otf2xx/definition/detail/base.hpp>
#include <otf2xx/definition/detail/property_impl.hpp>

namespace otf2
{
namespace definition
{

    /**
     * \brief class for representing property definitions
     */
    template <class Definition>
    class property : public detail::base<property<Definition>>
    {
        typedef typename detail::base<property<Definition>> base;
        typedef typename otf2::traits::definition_impl_type<property<Definition>>::type impl_type;

        using base::base;

        static_assert(otf2::traits::is_definition<Definition>::value,
                      "The Definition has to be a otf2::definition.");

    public:
        using type_type = typename impl_type::type_type;
        using value_type = typename impl_type::value_type;

        property(Definition def, string name, type_type type, value_type value)
        : base(new impl_type(def, name, type, value))
        {
        }

        property() = default;

        /**
         * \brief returns the name of the property
         *
         * \returns a \ref string definiton containing the name
         *
         */
        const otf2::definition::string& name() const
        {
            assert(this->is_valid());
            return this->data_->name();
        }

        /**
         * \brief returns the type of the property
         *
         */
        type_type type() const
        {
            assert(this->is_valid());
            return this->data_->type();
        }

        /**
         * \brief returns the value of the property
         *
         */
        value_type value() const
        {
            assert(this->is_valid());
            return this->data_->value();
        }

        /**
         * \brief returns the referenced definition record
         *
         */
        Definition def() const
        {
            assert(this->is_valid());
            return this->data_->def();
        }
    };
}
} // namespace otf2::definition

#endif // INCLUDE_OTF2XX_DEFINITIONS_PROPERTY_HPP
<commit_msg>Fixes missing pass-by-ref for Definition object<commit_after>/*
 * This file is part of otf2xx (https://github.com/tud-zih-energy/otf2xx)
 * otf2xx - A wrapper for the Open Trace Format 2 library
 *
 * Copyright (c) 2013-2016, Technische Universität Dresden, Germany
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * * Neither the name of the copyright holder nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#ifndef INCLUDE_OTF2XX_DEFINITIONS_PROPERTY_HPP
#define INCLUDE_OTF2XX_DEFINITIONS_PROPERTY_HPP

#include <otf2xx/common.hpp>
#include <otf2xx/fwd.hpp>
#include <otf2xx/reference.hpp>

#include <otf2xx/definition/string.hpp>

#include <otf2xx/definition/detail/base.hpp>
#include <otf2xx/definition/detail/property_impl.hpp>

namespace otf2
{
namespace definition
{

    /**
     * \brief class for representing property definitions
     */
    template <class Definition>
    class property : public detail::base<property<Definition>>
    {
        typedef typename detail::base<property<Definition>> base;
        typedef typename otf2::traits::definition_impl_type<property<Definition>>::type impl_type;

        using base::base;

        static_assert(otf2::traits::is_definition<Definition>::value,
                      "The Definition has to be a otf2::definition.");

    public:
        using type_type = typename impl_type::type_type;
        using value_type = typename impl_type::value_type;

        property(const Definition& def, string name, type_type type, value_type value)
        : base(new impl_type(def, name, type, value))
        {
        }

        property() = default;

        /**
         * \brief returns the name of the property
         *
         * \returns a \ref string definiton containing the name
         *
         */
        const otf2::definition::string& name() const
        {
            assert(this->is_valid());
            return this->data_->name();
        }

        /**
         * \brief returns the type of the property
         *
         */
        type_type type() const
        {
            assert(this->is_valid());
            return this->data_->type();
        }

        /**
         * \brief returns the value of the property
         *
         */
        value_type value() const
        {
            assert(this->is_valid());
            return this->data_->value();
        }

        /**
         * \brief returns the referenced definition record
         *
         */
        Definition def() const
        {
            assert(this->is_valid());
            return this->data_->def();
        }
    };
}
} // namespace otf2::definition

#endif // INCLUDE_OTF2XX_DEFINITIONS_PROPERTY_HPP
<|endoftext|>


<commit_before>//===- Util/TemplateSequence.hpp ------------------------------------ C++ -===//
//
//
//
//===----------------------------------------------------------------------===//
//
//
//
//===----------------------------------------------------------------------===//

#ifndef SEEC_UTIL_TEMPLATESEQUENCE_HPP
#define SEEC_UTIL_TEMPLATESEQUENCE_HPP

namespace seec {

namespace compile_time {

/// \brief A compile-time sequence of ints.
template<int ...>
struct sequence_int {};

/// \brief Build a compile-time sequence of ints to cover a range.
/// Builds a sequence [Start, End) by recursively instantiating itself and
/// accumulating in the Sequence parameter pack.
template<int Start, int End, int ...Sequence>
struct generate_sequence_int
: public generate_sequence_int<Start, End - 1, End - 1, Sequence...> {};

/// \brief Build a compile-time sequence of ints to cover a range.
/// Base case of the recursion, create a sequence using all values that have
/// accumulated in the Sequence parameter pack.
template<int StartEnd, int ...Sequence>
struct generate_sequence_int<StartEnd, StartEnd, Sequence...> {
  typedef sequence_int<Sequence...> type;
};

} // namespace compile_time

} // namespace seec

#endif // SEEC_UTIL_TEMPLATESEQUENCE_HPP
<commit_msg>Rename seec::compile_time to seec::ct.<commit_after>//===- Util/TemplateSequence.hpp ------------------------------------ C++ -===//
//
//
//
//===----------------------------------------------------------------------===//
//
//
//
//===----------------------------------------------------------------------===//

#ifndef SEEC_UTIL_TEMPLATESEQUENCE_HPP
#define SEEC_UTIL_TEMPLATESEQUENCE_HPP

namespace seec {

/// Compile-time utilities.
namespace ct {

/// \brief A compile-time sequence of ints.
template<int ...>
struct sequence_int {};

/// \brief Build a compile-time sequence of ints to cover a range.
/// Builds a sequence [Start, End) by recursively instantiating itself and
/// accumulating in the Sequence parameter pack.
template<int Start, int End, int ...Sequence>
struct generate_sequence_int
: public generate_sequence_int<Start, End - 1, End - 1, Sequence...> {};

/// \brief Build a compile-time sequence of ints to cover a range.
/// Base case of the recursion, create a sequence using all values that have
/// accumulated in the Sequence parameter pack.
template<int StartEnd, int ...Sequence>
struct generate_sequence_int<StartEnd, StartEnd, Sequence...> {
  typedef sequence_int<Sequence...> type;
};

} // namespace ct

} // namespace seec

#endif // SEEC_UTIL_TEMPLATESEQUENCE_HPP
<|endoftext|>


<commit_before>// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#ifndef TAO_PEGTL_CONTRIB_COVERAGE_HPP
#define TAO_PEGTL_CONTRIB_COVERAGE_HPP

#include <cstddef>
#include <iostream>
#include <map>
#include <string_view>

#include "../config.hpp"
#include "../normal.hpp"
#include "../nothing.hpp"
#include "../parse.hpp"
#include "../type_list.hpp"
#include "../visit.hpp"

#include "../internal/demangle.hpp"

namespace TAO_PEGTL_NAMESPACE
{
   struct coverage_info
   {
      std::size_t start = 0;
      std::size_t success = 0;
      std::size_t failure = 0;
      std::size_t raise = 0;
   };

   struct coverage_entry
      : coverage_info
   {
      std::map< std::string_view, coverage_info > branches;
   };

   struct coverage_state
   {
      std::vector< std::string_view > stack;
      std::map< std::string_view, coverage_entry > map;
   };

   template< typename Rule >
   struct coverage_insert
   {
      static void visit( coverage_state& state )
      {
         visit_branches( state.map.try_emplace( internal::demangle< Rule >() ).first->second.branches, typename Rule::subs_t() );
      }

      template< typename... Ts >
      static void visit_branches( std::map< std::string_view, coverage_info >& branches, type_list< Ts... > /*unused*/ )
      {
         ( branches.try_emplace( internal::demangle< Ts >() ), ... );
      }
   };

   template< typename Rule, template< typename... > class Control >
   struct basic_coverage_control
      : Control< Rule >
   {
      static constexpr bool enable = true;

      template< typename ParseInput >
      static void start( const ParseInput& in, coverage_state& state )
      {
         auto name = internal::demangle< Rule >();
         if( !state.stack.empty() ) {
            ++state.map.at( state.stack.back() ).branches.at( name ).start;
         }
         state.stack.push_back( name );
         ++state.map.at( name ).start;
         Control< Rule >::start( in, state );
      }

      template< typename ParseInput >
      static void success( const ParseInput& in, coverage_state& state )
      {
         auto name = internal::demangle< Rule >();
         ++state.map.at( name ).success;
         state.stack.pop_back();
         if( !state.stack.empty() ) {
            ++state.map.at( state.stack.back() ).branches.at( name ).success;
         }
         Control< Rule >::success( in, state );
      }

      template< typename ParseInput >
      static void failure( const ParseInput& in, coverage_state& state )
      {
         auto name = internal::demangle< Rule >();
         ++state.map.at( name ).failure;
         state.stack.pop_back();
         if( !state.stack.empty() ) {
            ++state.map.at( state.stack.back() ).branches.at( name ).failure;
         }
         Control< Rule >::failure( in, state );
      }

      template< typename ParseInput >
      [[noreturn]] static void raise( const ParseInput& in, coverage_state& state )
      {
         auto name = internal::demangle< Rule >();
         ++state.map.at( name ).raise;
         state.stack.pop_back();
         if( !state.stack.empty() ) {
            ++state.map.at( state.stack.back() ).branches.at( name ).raise;
         }
         Control< Rule >::raise( in, state );
      }
   };

   template< typename Rule >
   using coverage_control = basic_coverage_control< Rule, normal >;

   template< typename Grammar, typename ParseInput >
   bool coverage( ParseInput&& in )
   {
      coverage_state state;
      visit< Grammar, coverage_insert >( state );
      const auto result = parse< Grammar, nothing, coverage_control >( in, state );
      std::cout << "{\n"
                << "  \"grammar\": \"" << internal::demangle< Grammar >() << "\",\n"
                << "  \"source\": \"" << in.source() << "\",\n"
                << "  \"result\": " << ( result ? "true" : "false" ) << ",\n"
                << "  \"coverage\":\n"
                << "  [\n";
      bool f = true;
      for( const auto& [ k, v ] : state.map ) {
         if( f ) {
            f = false;
         }
         else {
            std::cout << ",\n";
         }
         std::cout << "    {\n"
                   << "      \"rule\": \"" << k << "\",\n"
                   << "      \"start\": " << v.start << ", \"success\": " << v.success << ", \"failure\": " << v.failure << ", \"raise\": " << v.raise << ",\n";
         if( v.branches.empty() ) {
            std::cout << "      \"branches\": []\n";
         }
         else {
            std::cout << "      \"branches\": [\n";
            bool f2 = true;
            for( const auto& [ k2, v2 ] : v.branches ) {
               if( f2 ) {
                  f2 = false;
               }
               else {
                  std::cout << ",\n";
               }
               std::cout << "        { \"branch\": \"" << k2 << "\" start\": " << v2.start << ", \"success\": " << v2.success << ", \"failure\": " << v2.failure << ", \"raise\": " << v2.raise << " }";
            }
            std::cout << "\n      ]\n";
         }
         std::cout << "    }";
      }
      std::cout << "\n"
                << "  ]\n"
                << "}" << std::endl;
      return result;
   }

}  // namespace TAO_PEGTL_NAMESPACE

#endif
<commit_msg>Add include.<commit_after>// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#ifndef TAO_PEGTL_CONTRIB_COVERAGE_HPP
#define TAO_PEGTL_CONTRIB_COVERAGE_HPP

#include <cstddef>
#include <iostream>
#include <map>
#include <string_view>
#include <vector>

#include "../config.hpp"
#include "../normal.hpp"
#include "../nothing.hpp"
#include "../parse.hpp"
#include "../type_list.hpp"
#include "../visit.hpp"

#include "../internal/demangle.hpp"

namespace TAO_PEGTL_NAMESPACE
{
   struct coverage_info
   {
      std::size_t start = 0;
      std::size_t success = 0;
      std::size_t failure = 0;
      std::size_t raise = 0;
   };

   struct coverage_entry
      : coverage_info
   {
      std::map< std::string_view, coverage_info > branches;
   };

   struct coverage_state
   {
      std::vector< std::string_view > stack;
      std::map< std::string_view, coverage_entry > map;
   };

   template< typename Rule >
   struct coverage_insert
   {
      static void visit( coverage_state& state )
      {
         visit_branches( state.map.try_emplace( internal::demangle< Rule >() ).first->second.branches, typename Rule::subs_t() );
      }

      template< typename... Ts >
      static void visit_branches( std::map< std::string_view, coverage_info >& branches, type_list< Ts... > /*unused*/ )
      {
         ( branches.try_emplace( internal::demangle< Ts >() ), ... );
      }
   };

   template< typename Rule, template< typename... > class Control >
   struct basic_coverage_control
      : Control< Rule >
   {
      static constexpr bool enable = true;

      template< typename ParseInput >
      static void start( const ParseInput& in, coverage_state& state )
      {
         auto name = internal::demangle< Rule >();
         if( !state.stack.empty() ) {
            ++state.map.at( state.stack.back() ).branches.at( name ).start;
         }
         state.stack.push_back( name );
         ++state.map.at( name ).start;
         Control< Rule >::start( in, state );
      }

      template< typename ParseInput >
      static void success( const ParseInput& in, coverage_state& state )
      {
         auto name = internal::demangle< Rule >();
         ++state.map.at( name ).success;
         state.stack.pop_back();
         if( !state.stack.empty() ) {
            ++state.map.at( state.stack.back() ).branches.at( name ).success;
         }
         Control< Rule >::success( in, state );
      }

      template< typename ParseInput >
      static void failure( const ParseInput& in, coverage_state& state )
      {
         auto name = internal::demangle< Rule >();
         ++state.map.at( name ).failure;
         state.stack.pop_back();
         if( !state.stack.empty() ) {
            ++state.map.at( state.stack.back() ).branches.at( name ).failure;
         }
         Control< Rule >::failure( in, state );
      }

      template< typename ParseInput >
      [[noreturn]] static void raise( const ParseInput& in, coverage_state& state )
      {
         auto name = internal::demangle< Rule >();
         ++state.map.at( name ).raise;
         state.stack.pop_back();
         if( !state.stack.empty() ) {
            ++state.map.at( state.stack.back() ).branches.at( name ).raise;
         }
         Control< Rule >::raise( in, state );
      }
   };

   template< typename Rule >
   using coverage_control = basic_coverage_control< Rule, normal >;

   template< typename Grammar, typename ParseInput >
   bool coverage( ParseInput&& in )
   {
      coverage_state state;
      visit< Grammar, coverage_insert >( state );
      const auto result = parse< Grammar, nothing, coverage_control >( in, state );
      std::cout << "{\n"
                << "  \"grammar\": \"" << internal::demangle< Grammar >() << "\",\n"
                << "  \"source\": \"" << in.source() << "\",\n"
                << "  \"result\": " << ( result ? "true" : "false" ) << ",\n"
                << "  \"coverage\":\n"
                << "  [\n";
      bool f = true;
      for( const auto& [ k, v ] : state.map ) {
         if( f ) {
            f = false;
         }
         else {
            std::cout << ",\n";
         }
         std::cout << "    {\n"
                   << "      \"rule\": \"" << k << "\",\n"
                   << "      \"start\": " << v.start << ", \"success\": " << v.success << ", \"failure\": " << v.failure << ", \"raise\": " << v.raise << ",\n";
         if( v.branches.empty() ) {
            std::cout << "      \"branches\": []\n";
         }
         else {
            std::cout << "      \"branches\": [\n";
            bool f2 = true;
            for( const auto& [ k2, v2 ] : v.branches ) {
               if( f2 ) {
                  f2 = false;
               }
               else {
                  std::cout << ",\n";
               }
               std::cout << "        { \"branch\": \"" << k2 << "\" start\": " << v2.start << ", \"success\": " << v2.success << ", \"failure\": " << v2.failure << ", \"raise\": " << v2.raise << " }";
            }
            std::cout << "\n      ]\n";
         }
         std::cout << "    }";
      }
      std::cout << "\n"
                << "  ]\n"
                << "}" << std::endl;
      return result;
   }

}  // namespace TAO_PEGTL_NAMESPACE

#endif
<|endoftext|>


<commit_before>/*
 * xmlprofile.cpp
 *
 *  Created on: 2015. 6. 22.
 *      Author: hwang-linux
 */

#include "xmlprofile.hpp"

namespace cossb {
namespace profile {

xmlprofile::xmlprofile() {
	// TODO Auto-generated constructor stub

}

xmlprofile::~xmlprofile() {
	// TODO Auto-generated destructor stub
}

bool xmlprofile::load(const char* filepath)
{
	int result = _doc.LoadFile(filepath);

	if(result==XML_SUCCESS)
		_loaded = true;
	else
	{
		//this->error(result);
		_loaded = false;
	}
	return _loaded;
}

const char* xmlprofile::get_error_str(int error) const
{
	switch(error)
	{
	case	XML_NO_ATTRIBUTE: 						return "No Attribute"; 		break;
	case	XML_WRONG_ATTRIBUTE_TYPE: 				return "Wrong attribute type";	break;
	case	XML_ERROR_FILE_NOT_FOUND: 				return "Cannot found profile";	break;
	case	XML_ERROR_FILE_COULD_NOT_BE_OPENED: 	return "Profile could not be loaded";	break;
	case	XML_ERROR_ELEMENT_MISMATCH: 			return "Element mismatch";	break;
	case	XML_ERROR_PARSING_ELEMENT: 				return "Parsing element";	break;
	case	XML_ERROR_PARSING_ATTRIBUTE: 			return "Parsing attribute";	break;
	case	XML_ERROR_IDENTIFYING_TAG: 				return "Identifying tag";	break;
	case	XML_ERROR_PARSING_TEXT: 					return "Parsing text";	break;
	case	XML_ERROR_PARSING_CDATA: 				return "Parsing CDATA";	break;
	case	XML_ERROR_PARSING_COMMENT: 				return "Parsing comment";	break;
	case	XML_ERROR_PARSING_DECLARATION: 			return "Parsing declaration";	break;
	case	XML_ERROR_PARSING_UNKNOWN: 				return "Parsing unknown";	break;
	case	XML_ERROR_EMPTY_DOCUMENT: 				return "Empty document";	break;
	case	XML_ERROR_MISMATCHED_ELEMENT: 			return "Mismatched element";	break;
	case	XML_ERROR_PARSING: 						return "Parsing Error";	break;
	}

	return "";
}

profile::type xmlprofile::get(profile::section section, const char* element)
{
	profile::type result;
	string section_name = "";
	bool exist = false;

	switch(section)
	{
	case profile::section::info:		section_name = "info"; exist = true;	break;
	case profile::section::property: section_name = "property";	exist = true;	break;
	case profile::section::resource: section_name = "resource";	exist = true;	break;
	default:	{ section_name = "unknown"; exist = false; }
	}

	if(_loaded && exist && _doc.FirstChildElement(section_name.c_str())!=0)
	{
		if(_doc.FirstChildElement(section_name.c_str())->FirstChildElement(element)!=0)
		{
			XMLNode* _node = _doc.FirstChildElement(section_name.c_str())->FirstChildElement(element)->FirstChild();
			if(_node)
				set(result, _node->ToText()->Value());
			/*else
				spdlog::get("main_thread")->error("Does not exist element value");*/
		}
		/*else
			spdlog::get("main_thread")->error("{} element in {} does not exist.", element, section_name);*/
	}
	/*else
		spdlog::get("main_thread")->error("Cannot find {} in the profile", section_name);*/

	return result;
}

bool xmlprofile::save()
{
	if(_loaded) {
		_doc.SaveFile(_filepath.c_str());
		return true;
	}

	return false;
}

} /* namespace profile */
} /* namespace cossb */
<commit_msg>add check code for debugging<commit_after>/*
 * xmlprofile.cpp
 *
 *  Created on: 2015. 6. 22.
 *      Author: hwang-linux
 */

#include "xmlprofile.hpp"
#include <iostream>

using namespace std;

namespace cossb {
namespace profile {

xmlprofile::xmlprofile() {
	// TODO Auto-generated constructor stub

}

xmlprofile::~xmlprofile() {
	// TODO Auto-generated destructor stub
}

bool xmlprofile::load(const char* filepath)
{
	int result = _doc.LoadFile(filepath);

	if(result==XML_SUCCESS)
		_loaded = true;
	else
	{
		cout << filepath << "profile error : " << this->get_error_str(result) << endl;
		_loaded = false;
	}
	return _loaded;
}

const char* xmlprofile::get_error_str(int error) const
{
	switch(error)
	{
	case	XML_NO_ATTRIBUTE: 						return "No Attribute"; 		break;
	case	XML_WRONG_ATTRIBUTE_TYPE: 				return "Wrong attribute type";	break;
	case	XML_ERROR_FILE_NOT_FOUND: 				return "Cannot found profile";	break;
	case	XML_ERROR_FILE_COULD_NOT_BE_OPENED: 	return "Profile could not be loaded";	break;
	case	XML_ERROR_ELEMENT_MISMATCH: 			return "Element mismatch";	break;
	case	XML_ERROR_PARSING_ELEMENT: 				return "Parsing element";	break;
	case	XML_ERROR_PARSING_ATTRIBUTE: 			return "Parsing attribute";	break;
	case	XML_ERROR_IDENTIFYING_TAG: 				return "Identifying tag";	break;
	case	XML_ERROR_PARSING_TEXT: 					return "Parsing text";	break;
	case	XML_ERROR_PARSING_CDATA: 				return "Parsing CDATA";	break;
	case	XML_ERROR_PARSING_COMMENT: 				return "Parsing comment";	break;
	case	XML_ERROR_PARSING_DECLARATION: 			return "Parsing declaration";	break;
	case	XML_ERROR_PARSING_UNKNOWN: 				return "Parsing unknown";	break;
	case	XML_ERROR_EMPTY_DOCUMENT: 				return "Empty document";	break;
	case	XML_ERROR_MISMATCHED_ELEMENT: 			return "Mismatched element";	break;
	case	XML_ERROR_PARSING: 						return "Parsing Error";	break;
	}

	return "";
}

profile::type xmlprofile::get(profile::section section, const char* element)
{
	profile::type result;
	string section_name = "";
	bool exist = false;

	switch(section)
	{
	case profile::section::info:		section_name = "info"; exist = true;	break;
	case profile::section::property: section_name = "property";	exist = true;	break;
	case profile::section::resource: section_name = "resource";	exist = true;	break;
	default:	{ section_name = "unknown"; exist = false; }
	}

	if(_loaded && exist && _doc.FirstChildElement(section_name.c_str())!=0)
	{
		if(_doc.FirstChildElement(section_name.c_str())->FirstChildElement(element)!=0)
		{
			XMLNode* _node = _doc.FirstChildElement(section_name.c_str())->FirstChildElement(element)->FirstChild();
			if(_node)
				set(result, _node->ToText()->Value());
			/*else
				spdlog::get("main_thread")->error("Does not exist element value");*/
		}
		/*else
			spdlog::get("main_thread")->error("{} element in {} does not exist.", element, section_name);*/
	}
	/*else
		spdlog::get("main_thread")->error("Cannot find {} in the profile", section_name);*/

	return result;
}

bool xmlprofile::save()
{
	if(_loaded) {
		_doc.SaveFile(_filepath.c_str());
		return true;
	}

	return false;
}

} /* namespace profile */
} /* namespace cossb */
<|endoftext|>


<commit_before>/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

// See docs in ../ops/sparse_ops.cc.

#define EIGEN_USE_THREADS

#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/register_types.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/framework/tensor_util.h"
#include "tensorflow/core/framework/types.h"
#include "tensorflow/core/util/sparse/sparse_tensor.h"

// TODO(b/31496047): Fix non-standard include order.
#include <numeric>  // clang-format off

using tensorflow::sparse::SparseTensor;
using tensorflow::gtl::ArraySlice;

namespace tensorflow {

struct ReduceDetails {
  // The dimensions to call Reorder() with.
  std::vector<int64> reorder_dims;

  // The dimensions to call group() with after Reorder().
  std::vector<int64> group_by_dims;

  // The shape after reduction.
  TensorShape reduced_shape;
};

// Compute common reduce parameters that'll be used for SparseTensor
// reductions. Usage:
// ReduceDetails reduction = SparseTensorReduceHelper(sp, axes, keep_dims);
// sp.Reorder(reduction.reorder_dims);
// for (const auto& g : sp.group(reduction.group_by_dims)) {
//   ...
// }
// // Set output shape to reduction.reduced_shape.
ReduceDetails SparseTensorReduceHelper(const SparseTensor &sp,
                                       gtl::ArraySlice<int32> axes_slice,
                                       bool keep_dims) {
  ReduceDetails reduction;

  std::vector<int32> reduction_axes(axes_slice.begin(), axes_slice.end());
  int ndims = sp.dims();
  for (int64 i = 0; i < reduction_axes.size(); ++i) {
    reduction_axes[i] = (reduction_axes[i] + ndims) % ndims;
  }
  std::sort(reduction_axes.begin(), reduction_axes.end());

  // (0) Calculate the grouping dimensions:
  // group_by_dims == {0, .., NDIMS-1} \ reduction_axes.
  std::vector<int64> perm(ndims);
  std::iota(perm.begin(), perm.end(), 0);

  // Requires perm and reduction_axes_ be sorted; group_by_dims will be
  // sorted as well.
  std::set_difference(
      perm.begin(), perm.end(), reduction_axes.begin(), reduction_axes.end(),
      std::inserter(reduction.group_by_dims, reduction.group_by_dims.begin()));

  // Now append the rest of the axes (the complement of group_by_dims_);
  // result is used by Reorder().
  reduction.reorder_dims = reduction.group_by_dims;
  std::set_difference(perm.begin(), perm.end(), reduction.group_by_dims.begin(),
                      reduction.group_by_dims.end(),
                      std::back_inserter(reduction.reorder_dims));

  // (1) Calculate the shape after reduction.
  auto sp_shape = sp.shape();
  std::vector<int64> out_dim_sizes;
  if (keep_dims) {
    out_dim_sizes.reserve(ndims);
    auto beg = reduction.group_by_dims.begin();
    auto end = reduction.group_by_dims.end();
    for (int d = 0; d < ndims; ++d) {
      if (std::find(beg, end, d) == end) {
        out_dim_sizes.push_back(1);  // A reduced axis.
      } else {
        out_dim_sizes.push_back(sp_shape[d]);
      }
    }
  } else {
    out_dim_sizes = sp.PickDims(reduction.group_by_dims);
  }

  reduction.reduced_shape = TensorShape(out_dim_sizes);
  return reduction;
}

Status ValidateInputs(const Tensor *shape_t, const Tensor *reduction_axes_t) {
  // indices and values are validated in SparseTensor ctor.
  if (!TensorShapeUtils::IsVector(shape_t->shape())) {
    return errors::InvalidArgument(
        "Expected input_shape to be a vector; got shape: ",
        shape_t->shape().DebugString());
  }
  if (!TensorShapeUtils::IsScalar(reduction_axes_t->shape()) &&
      !TensorShapeUtils::IsVector(reduction_axes_t->shape())) {
    return errors::InvalidArgument(
        "Expected reduction_axes to be a scalar or a vector; got shape: ",
        reduction_axes_t->shape().DebugString());
  }

  const auto reduction_axes_flat = reduction_axes_t->flat<int32>();
  for (int64 i = 0; i < reduction_axes_flat.size(); i++) {
    int32 axis = reduction_axes_flat(i);
    if (axis < -shape_t->NumElements() || axis >= shape_t->NumElements()) {
      return errors::InvalidArgument("Invalid reduction dimension ", axis,
                                     ", for input with ",
                                     shape_t->NumElements(), " dimensions.");
    }
  }

  return Status::OK();
}

struct SumOp {
  template <typename T>
  static void Run(OpKernelContext *ctx, typename TTypes<T>::Scalar &s, const typename TTypes<T>::UnalignedVec &v) {
      s.device(ctx->eigen_cpu_device()) = v.sum();
  }
  static StringPiece Name() {
      return "sum";
  }
};

struct MaxOp {
  template <typename T>
  static void Run(OpKernelContext *ctx, typename TTypes<T>::Scalar &s, const typename TTypes<T>::UnalignedVec &v) {
      s.device(ctx->eigen_cpu_device()) = v.maximum();
  }
  static StringPiece Name() {
      return "max";
  }
};

template <typename T, typename Op>
class SparseReduceOp : public OpKernel {
 public:
  explicit SparseReduceOp(OpKernelConstruction *ctx) : OpKernel(ctx) {
    OP_REQUIRES_OK(ctx, ctx->GetAttr("keep_dims", &keep_dims_));
  }

  void Compute(OpKernelContext *ctx) override {
    const Tensor *indices_t, *values_t, *shape_t, *reduction_axes_t;
    OP_REQUIRES_OK(ctx, ctx->input("input_indices", &indices_t));
    OP_REQUIRES_OK(ctx, ctx->input("input_values", &values_t));
    OP_REQUIRES_OK(ctx, ctx->input("input_shape", &shape_t));
    OP_REQUIRES_OK(ctx, ctx->input("reduction_axes", &reduction_axes_t));

    OP_REQUIRES_OK(ctx, ValidateInputs(shape_t, reduction_axes_t));

    // TODO(zongheng): we will call Reorder() below, which will modify
    // in-place the underlying indices and values buffers.  To avoid
    // surprises of this kernel being stateful, we work around the above by
    // making deep copies here.  Remove this if/when we change Reorder()'s
    // semantics.
    const auto shape_vec = shape_t->vec<int64>();
    SparseTensor sp;
    OP_REQUIRES_OK(ctx, SparseTensor::Create(
        tensor::DeepCopy(*indices_t), tensor::DeepCopy(*values_t),
                    TensorShape(shape_vec), &sp));
    ReduceDetails reduction = SparseTensorReduceHelper(
        sp, reduction_axes_t->flat<int32>(), keep_dims_);

    Tensor *out_values;
    OP_REQUIRES_OK(
        ctx, ctx->allocate_output(0, reduction.reduced_shape, &out_values));
    auto out_flat = out_values->flat<T>();
    out_flat.setZero();

    Tensor tmp_reduced_val;
    OP_REQUIRES_OK(ctx, ctx->allocate_temp(DataTypeToEnum<T>::value,
                                           TensorShape({}), &tmp_reduced_val));
    auto reduced_val = tmp_reduced_val.scalar<T>();

    // Compute strides, and use it to convert coords to flat index.  The
    // coordinates returned by .group() have the same ndims as group_by_dims.
    gtl::InlinedVector<int64, 8> output_strides(reduction.group_by_dims.size());
    if (!output_strides.empty()) {  // Do this iff we don't reduce all.
      output_strides.back() = 1;
      for (int d = output_strides.size() - 2; d >= 0; --d) {
        output_strides[d] =
            output_strides[d + 1] * shape_vec(reduction.group_by_dims[d + 1]);
      }
    }

    auto CoordinatesToFlatIndex = [](ArraySlice<int64> coords,
                                     ArraySlice<int64> strides) -> int64 {
      if (strides.empty()) {  // Reduce all.
        return 0;
      }
      CHECK_EQ(coords.size(), strides.size());
      int64 idx = 0;
      for (int i = 0; i < coords.size(); ++i) {
        idx += coords[i] * strides[i];
      }
      return idx;
    };

    // Each group maps one-on-one onto a value in the reduced tensor.
    // g.group() provides the coordinates of a particular reduced value.
    sp.Reorder<T>(reduction.reorder_dims);
    OP_REQUIRES_OK(ctx, sp.IndicesValid());
    for (const auto &g : sp.group(reduction.group_by_dims)) {
      Op::template Run<T>(ctx, reduced_val, g.template values<T>());
      const int64 idx = CoordinatesToFlatIndex(g.group(), output_strides);
      out_flat(idx) = reduced_val();
      VLOG(2) << "coords: " << absl::StrJoin(g.group(), ",")
              << "; idx: " << idx << "; group " << Op::Name() << ": "
              << reduced_val();
    }
  }

 private:
  // True if the number of dimensions should be maintained.
  bool keep_dims_;
};

#define REGISTER_KERNELS(T)                                              \
  REGISTER_KERNEL_BUILDER(                                               \
      Name("SparseReduceSum").Device(DEVICE_CPU).TypeConstraint<T>("T"), \
      SparseReduceOp<T, SumOp>)
TF_CALL_NUMBER_TYPES(REGISTER_KERNELS);
#undef REGISTER_KERNELS

#define REGISTER_KERNELS(T)                                              \
  REGISTER_KERNEL_BUILDER(                                               \
      Name("SparseReduceMax").Device(DEVICE_CPU).TypeConstraint<T>("T"), \
      SparseReduceOp<T, MaxOp>)
TF_CALL_REAL_NUMBER_TYPES(REGISTER_KERNELS);
#undef REGISTER_KERNELS

template <typename T, typename Op>
class SparseReduceSparseOp : public OpKernel {
 public:
  explicit SparseReduceSparseOp(OpKernelConstruction *ctx) : OpKernel(ctx) {
    OP_REQUIRES_OK(ctx, ctx->GetAttr("keep_dims", &keep_dims_));
  }

  void Compute(OpKernelContext *ctx) override {
    const Tensor *indices_t, *values_t, *shape_t, *reduction_axes_t;
    OP_REQUIRES_OK(ctx, ctx->input("input_indices", &indices_t));
    OP_REQUIRES_OK(ctx, ctx->input("input_values", &values_t));
    OP_REQUIRES_OK(ctx, ctx->input("input_shape", &shape_t));
    OP_REQUIRES_OK(ctx, ctx->input("reduction_axes", &reduction_axes_t));

    OP_REQUIRES_OK(ctx, ValidateInputs(shape_t, reduction_axes_t));

    SparseTensor sp;
    OP_REQUIRES_OK(ctx, SparseTensor::Create(tensor::DeepCopy(*indices_t),
                                         tensor::DeepCopy(*values_t),
                    TensorShape(shape_t->vec<int64>()), &sp));
    ReduceDetails reduction = SparseTensorReduceHelper(
        sp, reduction_axes_t->flat<int32>(), keep_dims_);

    sp.Reorder<T>(reduction.reorder_dims);
    // Count nnzs in the output SparseTensor.
    int64 nnz = 0;
    auto iter = sp.group(reduction.group_by_dims);
    for (auto it = iter.begin(); it != iter.end(); ++it) {
      nnz++;
    }

    Tensor *out_indices_t;
    OP_REQUIRES_OK(ctx,
                   ctx->allocate_output(
                       0, TensorShape({nnz, reduction.reduced_shape.dims()}),
                       &out_indices_t));
    typename TTypes<int64>::Matrix out_indices_mat =
        out_indices_t->matrix<int64>();
    // For keep_dims. We don't explicitly set dim fields for reduced dims below.
    out_indices_mat.setZero();

    Tensor *out_values_t;
    OP_REQUIRES_OK(ctx,
                   ctx->allocate_output(1, TensorShape({nnz}), &out_values_t));
    auto out_flat = out_values_t->flat<T>();

    Tensor tmp_reduced_val;
    OP_REQUIRES_OK(ctx, ctx->allocate_temp(DataTypeToEnum<T>::value,
                                           TensorShape({}), &tmp_reduced_val));
    auto reduced_val = tmp_reduced_val.scalar<T>();
    int64 i = 0;
    for (const auto &g : sp.group(reduction.group_by_dims)) {
      Op::template Run<T>(ctx, reduced_val, g.template values<T>());
      std::vector<int64> group = g.group();
      for (int64 j = 0; j < group.size(); j++) {
        if (keep_dims_) {
          out_indices_mat(i, reduction.group_by_dims[j]) = group[j];
        } else {
          out_indices_mat(i, j) = group[j];
        }
      }
      out_flat(i) = reduced_val();
      i++;
      VLOG(2) << "coords: " << absl::StrJoin(g.group(), ",")
              << "; group " << Op::Name() << ": "
              << reduced_val();
    }

    Tensor *out_shape_t;
    OP_REQUIRES_OK(ctx, ctx->allocate_output(
                            2, TensorShape({reduction.reduced_shape.dims()}),
                            &out_shape_t));
    auto out_shape_flat = out_shape_t->flat<int64>();
    auto out_dim_sizes = reduction.reduced_shape.dim_sizes();
    if (!out_dim_sizes.empty()) {
      std::copy(out_dim_sizes.begin(), out_dim_sizes.end(), &out_shape_flat(0));
    }
  }

 private:
  // True if the number of dimensions should be maintained.
  bool keep_dims_;
};

#define REGISTER_KERNELS(T)                                                    \
  REGISTER_KERNEL_BUILDER(                                                     \
      Name("SparseReduceSumSparse").Device(DEVICE_CPU).TypeConstraint<T>("T"), \
      SparseReduceSparseOp<T, SumOp>)
TF_CALL_NUMBER_TYPES(REGISTER_KERNELS);
#undef REGISTER_KERNELS

#define REGISTER_KERNELS(T)                                                    \
  REGISTER_KERNEL_BUILDER(                                                     \
      Name("SparseReduceMaxSparse").Device(DEVICE_CPU).TypeConstraint<T>("T"), \
      SparseReduceSparseOp<T, MaxOp>)
TF_CALL_REAL_NUMBER_TYPES(REGISTER_KERNELS);
#undef REGISTER_KERNELS

}  // namespace tensorflow
<commit_msg>Validate indices for tf.sparse.reduce_sum and tf.sparse_reduce_max, fixing heap out of bounds.<commit_after>/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

// See docs in ../ops/sparse_ops.cc.

#define EIGEN_USE_THREADS

#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/register_types.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/framework/tensor_util.h"
#include "tensorflow/core/framework/types.h"
#include "tensorflow/core/util/sparse/sparse_tensor.h"

// TODO(b/31496047): Fix non-standard include order.
#include <numeric>  // clang-format off

using tensorflow::sparse::SparseTensor;
using tensorflow::gtl::ArraySlice;

namespace tensorflow {

struct ReduceDetails {
  // The dimensions to call Reorder() with.
  std::vector<int64> reorder_dims;

  // The dimensions to call group() with after Reorder().
  std::vector<int64> group_by_dims;

  // The shape after reduction.
  TensorShape reduced_shape;
};

// Compute common reduce parameters that'll be used for SparseTensor
// reductions. Usage:
// ReduceDetails reduction = SparseTensorReduceHelper(sp, axes, keep_dims);
// sp.Reorder(reduction.reorder_dims);
// for (const auto& g : sp.group(reduction.group_by_dims)) {
//   ...
// }
// // Set output shape to reduction.reduced_shape.
ReduceDetails SparseTensorReduceHelper(const SparseTensor &sp,
                                       gtl::ArraySlice<int32> axes_slice,
                                       bool keep_dims) {
  ReduceDetails reduction;

  std::vector<int32> reduction_axes(axes_slice.begin(), axes_slice.end());
  int ndims = sp.dims();
  for (int64 i = 0; i < reduction_axes.size(); ++i) {
    reduction_axes[i] = (reduction_axes[i] + ndims) % ndims;
  }
  std::sort(reduction_axes.begin(), reduction_axes.end());

  // (0) Calculate the grouping dimensions:
  // group_by_dims == {0, .., NDIMS-1} \ reduction_axes.
  std::vector<int64> perm(ndims);
  std::iota(perm.begin(), perm.end(), 0);

  // Requires perm and reduction_axes_ be sorted; group_by_dims will be
  // sorted as well.
  std::set_difference(
      perm.begin(), perm.end(), reduction_axes.begin(), reduction_axes.end(),
      std::inserter(reduction.group_by_dims, reduction.group_by_dims.begin()));

  // Now append the rest of the axes (the complement of group_by_dims_);
  // result is used by Reorder().
  reduction.reorder_dims = reduction.group_by_dims;
  std::set_difference(perm.begin(), perm.end(), reduction.group_by_dims.begin(),
                      reduction.group_by_dims.end(),
                      std::back_inserter(reduction.reorder_dims));

  // (1) Calculate the shape after reduction.
  auto sp_shape = sp.shape();
  std::vector<int64> out_dim_sizes;
  if (keep_dims) {
    out_dim_sizes.reserve(ndims);
    auto beg = reduction.group_by_dims.begin();
    auto end = reduction.group_by_dims.end();
    for (int d = 0; d < ndims; ++d) {
      if (std::find(beg, end, d) == end) {
        out_dim_sizes.push_back(1);  // A reduced axis.
      } else {
        out_dim_sizes.push_back(sp_shape[d]);
      }
    }
  } else {
    out_dim_sizes = sp.PickDims(reduction.group_by_dims);
  }

  reduction.reduced_shape = TensorShape(out_dim_sizes);
  return reduction;
}

Status ValidateInputs(const Tensor *shape_t, const Tensor *reduction_axes_t) {
  // indices and values are validated in SparseTensor ctor.
  if (!TensorShapeUtils::IsVector(shape_t->shape())) {
    return errors::InvalidArgument(
        "Expected input_shape to be a vector; got shape: ",
        shape_t->shape().DebugString());
  }
  if (!TensorShapeUtils::IsScalar(reduction_axes_t->shape()) &&
      !TensorShapeUtils::IsVector(reduction_axes_t->shape())) {
    return errors::InvalidArgument(
        "Expected reduction_axes to be a scalar or a vector; got shape: ",
        reduction_axes_t->shape().DebugString());
  }

  const auto reduction_axes_flat = reduction_axes_t->flat<int32>();
  for (int64 i = 0; i < reduction_axes_flat.size(); i++) {
    int32 axis = reduction_axes_flat(i);
    if (axis < -shape_t->NumElements() || axis >= shape_t->NumElements()) {
      return errors::InvalidArgument("Invalid reduction dimension ", axis,
                                     ", for input with ",
                                     shape_t->NumElements(), " dimensions.");
    }
  }

  return Status::OK();
}

struct SumOp {
  template <typename T>
  static void Run(OpKernelContext *ctx, typename TTypes<T>::Scalar &s, const typename TTypes<T>::UnalignedVec &v) {
      s.device(ctx->eigen_cpu_device()) = v.sum();
  }
  static StringPiece Name() {
      return "sum";
  }
};

struct MaxOp {
  template <typename T>
  static void Run(OpKernelContext *ctx, typename TTypes<T>::Scalar &s, const typename TTypes<T>::UnalignedVec &v) {
      s.device(ctx->eigen_cpu_device()) = v.maximum();
  }
  static StringPiece Name() {
      return "max";
  }
};

template <typename T, typename Op>
class SparseReduceOp : public OpKernel {
 public:
  explicit SparseReduceOp(OpKernelConstruction *ctx) : OpKernel(ctx) {
    OP_REQUIRES_OK(ctx, ctx->GetAttr("keep_dims", &keep_dims_));
  }

  void Compute(OpKernelContext *ctx) override {
    const Tensor *indices_t, *values_t, *shape_t, *reduction_axes_t;
    OP_REQUIRES_OK(ctx, ctx->input("input_indices", &indices_t));
    OP_REQUIRES_OK(ctx, ctx->input("input_values", &values_t));
    OP_REQUIRES_OK(ctx, ctx->input("input_shape", &shape_t));
    OP_REQUIRES_OK(ctx, ctx->input("reduction_axes", &reduction_axes_t));

    OP_REQUIRES_OK(ctx, ValidateInputs(shape_t, reduction_axes_t));

    // TODO(zongheng): we will call Reorder() below, which will modify
    // in-place the underlying indices and values buffers.  To avoid
    // surprises of this kernel being stateful, we work around the above by
    // making deep copies here.  Remove this if/when we change Reorder()'s
    // semantics.
    const auto shape_vec = shape_t->vec<int64>();
    SparseTensor sp;
    OP_REQUIRES_OK(ctx, SparseTensor::Create(
        tensor::DeepCopy(*indices_t), tensor::DeepCopy(*values_t),
                    TensorShape(shape_vec), &sp));
    ReduceDetails reduction = SparseTensorReduceHelper(
        sp, reduction_axes_t->flat<int32>(), keep_dims_);

    Tensor *out_values;
    OP_REQUIRES_OK(
        ctx, ctx->allocate_output(0, reduction.reduced_shape, &out_values));
    auto out_flat = out_values->flat<T>();
    out_flat.setZero();

    Tensor tmp_reduced_val;
    OP_REQUIRES_OK(ctx, ctx->allocate_temp(DataTypeToEnum<T>::value,
                                           TensorShape({}), &tmp_reduced_val));
    auto reduced_val = tmp_reduced_val.scalar<T>();

    // Compute strides, and use it to convert coords to flat index.  The
    // coordinates returned by .group() have the same ndims as group_by_dims.
    gtl::InlinedVector<int64, 8> output_strides(reduction.group_by_dims.size());
    if (!output_strides.empty()) {  // Do this iff we don't reduce all.
      output_strides.back() = 1;
      for (int d = output_strides.size() - 2; d >= 0; --d) {
        output_strides[d] =
            output_strides[d + 1] * shape_vec(reduction.group_by_dims[d + 1]);
      }
    }

    auto CoordinatesToFlatIndex = [](ArraySlice<int64> coords,
                                     ArraySlice<int64> strides) -> int64 {
      if (strides.empty()) {  // Reduce all.
        return 0;
      }
      CHECK_EQ(coords.size(), strides.size());
      int64 idx = 0;
      for (int i = 0; i < coords.size(); ++i) {
        idx += coords[i] * strides[i];
      }
      return idx;
    };

    // Each group maps one-on-one onto a value in the reduced tensor.
    // g.group() provides the coordinates of a particular reduced value.
    sp.Reorder<T>(reduction.reorder_dims);
    for (const auto &g : sp.group(reduction.group_by_dims)) {
      Op::template Run<T>(ctx, reduced_val, g.template values<T>());
      const int64 idx = CoordinatesToFlatIndex(g.group(), output_strides);
      out_flat(idx) = reduced_val();
      VLOG(2) << "coords: " << absl::StrJoin(g.group(), ",")
              << "; idx: " << idx << "; group " << Op::Name() << ": "
              << reduced_val();
    }
  }

 private:
  // True if the number of dimensions should be maintained.
  bool keep_dims_;
};

#define REGISTER_KERNELS(T)                                              \
  REGISTER_KERNEL_BUILDER(                                               \
      Name("SparseReduceSum").Device(DEVICE_CPU).TypeConstraint<T>("T"), \
      SparseReduceOp<T, SumOp>)
TF_CALL_NUMBER_TYPES(REGISTER_KERNELS);
#undef REGISTER_KERNELS

#define REGISTER_KERNELS(T)                                              \
  REGISTER_KERNEL_BUILDER(                                               \
      Name("SparseReduceMax").Device(DEVICE_CPU).TypeConstraint<T>("T"), \
      SparseReduceOp<T, MaxOp>)
TF_CALL_REAL_NUMBER_TYPES(REGISTER_KERNELS);
#undef REGISTER_KERNELS

template <typename T, typename Op>
class SparseReduceSparseOp : public OpKernel {
 public:
  explicit SparseReduceSparseOp(OpKernelConstruction *ctx) : OpKernel(ctx) {
    OP_REQUIRES_OK(ctx, ctx->GetAttr("keep_dims", &keep_dims_));
  }

  void Compute(OpKernelContext *ctx) override {
    const Tensor *indices_t, *values_t, *shape_t, *reduction_axes_t;
    OP_REQUIRES_OK(ctx, ctx->input("input_indices", &indices_t));
    OP_REQUIRES_OK(ctx, ctx->input("input_values", &values_t));
    OP_REQUIRES_OK(ctx, ctx->input("input_shape", &shape_t));
    OP_REQUIRES_OK(ctx, ctx->input("reduction_axes", &reduction_axes_t));

    OP_REQUIRES_OK(ctx, ValidateInputs(shape_t, reduction_axes_t));

    SparseTensor sp;
    OP_REQUIRES_OK(ctx, SparseTensor::Create(tensor::DeepCopy(*indices_t),
                                         tensor::DeepCopy(*values_t),
                    TensorShape(shape_t->vec<int64>()), &sp));
    ReduceDetails reduction = SparseTensorReduceHelper(
        sp, reduction_axes_t->flat<int32>(), keep_dims_);

    sp.Reorder<T>(reduction.reorder_dims);
    // Count nnzs in the output SparseTensor.
    int64 nnz = 0;
    auto iter = sp.group(reduction.group_by_dims);
    for (auto it = iter.begin(); it != iter.end(); ++it) {
      nnz++;
    }

    Tensor *out_indices_t;
    OP_REQUIRES_OK(ctx,
                   ctx->allocate_output(
                       0, TensorShape({nnz, reduction.reduced_shape.dims()}),
                       &out_indices_t));
    typename TTypes<int64>::Matrix out_indices_mat =
        out_indices_t->matrix<int64>();
    // For keep_dims. We don't explicitly set dim fields for reduced dims below.
    out_indices_mat.setZero();

    Tensor *out_values_t;
    OP_REQUIRES_OK(ctx,
                   ctx->allocate_output(1, TensorShape({nnz}), &out_values_t));
    auto out_flat = out_values_t->flat<T>();

    Tensor tmp_reduced_val;
    OP_REQUIRES_OK(ctx, ctx->allocate_temp(DataTypeToEnum<T>::value,
                                           TensorShape({}), &tmp_reduced_val));
    auto reduced_val = tmp_reduced_val.scalar<T>();
    int64 i = 0;
    for (const auto &g : sp.group(reduction.group_by_dims)) {
      Op::template Run<T>(ctx, reduced_val, g.template values<T>());
      std::vector<int64> group = g.group();
      for (int64 j = 0; j < group.size(); j++) {
        if (keep_dims_) {
          out_indices_mat(i, reduction.group_by_dims[j]) = group[j];
        } else {
          out_indices_mat(i, j) = group[j];
        }
      }
      out_flat(i) = reduced_val();
      i++;
      VLOG(2) << "coords: " << absl::StrJoin(g.group(), ",")
              << "; group " << Op::Name() << ": "
              << reduced_val();
    }

    Tensor *out_shape_t;
    OP_REQUIRES_OK(ctx, ctx->allocate_output(
                            2, TensorShape({reduction.reduced_shape.dims()}),
                            &out_shape_t));
    auto out_shape_flat = out_shape_t->flat<int64>();
    auto out_dim_sizes = reduction.reduced_shape.dim_sizes();
    if (!out_dim_sizes.empty()) {
      std::copy(out_dim_sizes.begin(), out_dim_sizes.end(), &out_shape_flat(0));
    }
  }

 private:
  // True if the number of dimensions should be maintained.
  bool keep_dims_;
};

#define REGISTER_KERNELS(T)                                                    \
  REGISTER_KERNEL_BUILDER(                                                     \
      Name("SparseReduceSumSparse").Device(DEVICE_CPU).TypeConstraint<T>("T"), \
      SparseReduceSparseOp<T, SumOp>)
TF_CALL_NUMBER_TYPES(REGISTER_KERNELS);
#undef REGISTER_KERNELS

#define REGISTER_KERNELS(T)                                                    \
  REGISTER_KERNEL_BUILDER(                                                     \
      Name("SparseReduceMaxSparse").Device(DEVICE_CPU).TypeConstraint<T>("T"), \
      SparseReduceSparseOp<T, MaxOp>)
TF_CALL_REAL_NUMBER_TYPES(REGISTER_KERNELS);
#undef REGISTER_KERNELS

}  // namespace tensorflow
<|endoftext|>


<commit_before>// Sh: A GPU metaprogramming language.
//
// Copyright (c) 2003 University of Waterloo Computer Graphics Laboratory
// Project administrator: Michael D. McCool
// Authors: Zheng Qin, Stefanus Du Toit, Kevin Moule, Tiberiu S. Popa,
//          Michael D. McCool
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must
// not claim that you wrote the original software. If you use this
// software in a product, an acknowledgment in the product documentation
// would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must
// not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//////////////////////////////////////////////////////////////////////////////
#include "PBufferStreams.hpp"

/// Turn this on if you want timings on std::cerr
//#define DO_PBUFFER_TIMING

// Turn this on to debug the fragment programs.
//#define SH_DEBUG_PBS_PRINTFP

#include <map>
#include <fstream>
#include <cstdlib>
#include <list>

#include "sh.hpp"
#include "ShOptimizations.hpp"
#include "ShException.hpp"
#include "ShError.hpp"
#include "ShTypeInfo.hpp"
#include "ShVariant.hpp"
#include "PBufferContext.hpp"
#include "Utils.hpp"

#ifdef DO_PBUFFER_TIMING
#include <sys/time.h>
#include <time.h>
#endif

namespace shgl {

using namespace SH;

#ifdef DO_PBUFFER_TIMING

class Timer {
public:
  Timer() { start(); }

  void start() { gettimeofday(&startval, 0); }

  long diff() {
    timeval endval;
    gettimeofday(&endval, 0);
    return (endval.tv_sec - startval.tv_sec)*1000
      + (endval.tv_usec/1000 - startval.tv_usec/1000);
  }

private:
  timeval startval;
};

#endif

class PBufferStreamException : public ShException {
public:
  PBufferStreamException(const std::string& message)
    : ShException("PBuffer Stream Execution: " + message)
  {
  }
};

class PBufferStreamCache : public ShInfo {
public:
  PBufferStreamCache(ShProgramNode* stream_program,
                     ShProgramNode* vertex_program);

  ShInfo* clone() const;

  void update_channels(int width, int height);

  void build_sets(ShProgramNode* vertex_program);

  typedef std::list<ShProgramSetPtr>::iterator set_iterator;
  typedef std::list<ShProgramSetPtr>::const_iterator set_const_iterator;
  typedef std::list<ShProgramNodePtr>::iterator program_iterator;
  typedef std::list<ShProgramNodePtr>::const_iterator program_const_iterator;

  set_iterator sets_begin() { return m_program_sets.begin(); }
  set_iterator sets_end() { return m_program_sets.end(); }
  set_const_iterator sets_begin() const { return m_program_sets.begin(); }
  set_const_iterator sets_end() const { return m_program_sets.end(); }

  program_iterator programs_begin() { return m_programs.begin(); }
  program_iterator programs_end() { return m_programs.end(); }
  program_const_iterator programs_begin() const { return m_programs.begin(); }
  program_const_iterator programs_end() const { return m_programs.end(); }

private:
  ShProgramNode* m_stream_program;
  ShProgramNode* m_vertex_program;
  ChannelMap m_channel_map;
  std::list<ShProgramNodePtr> m_programs;
  std::list<ShProgramSetPtr> m_program_sets;

  PBufferStreamCache(const PBufferStreamCache& other);
  PBufferStreamCache& operator=(const PBufferStreamCache& other);
};

PBufferStreamCache::PBufferStreamCache(ShProgramNode* stream_program,
                                       ShProgramNode* vertex_program)
  : m_stream_program(stream_program),
    m_vertex_program(vertex_program)
{
  FloatExtension extension = PBufferFactory::instance()->get_extension();
  ShTextureDims dims;

  switch (extension) {
  case SH_ARB_NV_FLOAT_BUFFER:
    dims = SH_TEXTURE_RECT;
    break;
  case SH_ARB_ATI_PIXEL_FORMAT_FLOAT:
    dims = SH_TEXTURE_2D;
    break;
  case SH_ARB_NO_FLOAT_EXT:
    throw PBufferStreamException("No floating point rendering target.\n"
                                 "Ensure your system supports floating point pbuffers.");
    break;
  }

  ChannelGatherer gatherer(m_channel_map, dims);
  stream_program->ctrlGraph->dfs(gatherer);

  split_program(stream_program, m_programs, "gpu:fragment");

  for (std::list<ShProgramNodePtr>::iterator I = m_programs.begin();
       I != m_programs.end(); ++I) {
    ShProgram with_tc = ShProgram(*I) & lose<ShTexCoord2f>("streamcoord");

    TexFetcher fetcher(m_channel_map, with_tc.node()->inputs.back(),
                       dims == SH_TEXTURE_RECT, with_tc.node());
    with_tc.node()->ctrlGraph->dfs(fetcher);

    optimize(with_tc);

    *I = with_tc.node();
  }

  build_sets(vertex_program);
}

ShInfo* PBufferStreamCache::clone() const
{
  return new PBufferStreamCache(m_stream_program, m_vertex_program);
}

void PBufferStreamCache::update_channels(int width, int height)
{
  for (ChannelMap::iterator I = m_channel_map.begin(); I != m_channel_map.end(); ++I) {
    ShChannelNode* channel = I->first.object();
    ShTextureNode* texture = I->second.object();

    SH_DEBUG_ASSERT(channel);
    SH_DEBUG_ASSERT(texture);

    texture->memory(channel->memory());
    texture->setTexSize(width, height);
    texture->count(channel->count());
  }
}

void PBufferStreamCache::build_sets(ShProgramNode* vertex_program)
{
  m_vertex_program = vertex_program;
  m_program_sets.clear();
  for (std::list<ShProgramNodePtr>::iterator I = m_programs.begin(); I != m_programs.end(); ++I) {
    m_program_sets.push_back(new ShProgramSet(ShProgram(vertex_program),
                                              ShProgram(*I)));
  }
}

PBufferStreams::PBufferStreams(void) :
  m_shaders(NULL), m_setup_vp(false)
{
}

PBufferStreams::~PBufferStreams()
{
}

#ifdef DO_PBUFFER_TIMING
int indent = 0;
Timer supertimer;

void fillin()
{
  long sd = supertimer.diff();
  supertimer.start();
  if (indent) for (int j = 0; j < sd; j++) {
    for (int i = 0; i < indent; i++) std::cerr << "| ";
    std::cerr << std::endl;
  }
}

#define DECLARE_TIMER(t) Timer pbtime_ ## t; do { fillin(); for (int i = 0; i < indent; i++) std::cerr << "| "; std::cerr << "^ " << # t << " starts" << std::endl; indent++;} while (0)
#define TIMING_RESULT(t) do {long d = pbtime_ ## t.diff(); fillin(); indent--; for (int i = 0; i < indent; i++) std::cerr << "| "; std::cerr << "v " << # t << " took " << d << " ms" << std::endl; supertimer.start(); } while (0)
#else
#define DECLARE_TIMER(t)
#define TIMING_RESULT(t)
#endif

void PBufferStreams::execute(const ShProgramNodeCPtr& program_const,
                             ShStream& dest)
{
  // Let's get rid of that constness... Yes, yes, I know...
  ShProgramNodePtr program = shref_const_cast<ShProgramNode>(program_const);

  DECLARE_TIMER(overhead);

  // Check program target
  if (program->target() != "gpu:stream") {
    shError(PBufferStreamException("This backend can only execute ``gpu:stream'' programs."));
    return;
  }

  // Make sure program has no inputs
  if (!program->inputs.empty()) {
    shError(PBufferStreamException("Stream program has unbound inputs, and can hence not be executed."));
    return;
  }

  if (dest.size() == 0) {
    SH_DEBUG_WARN("Stream program has no outputs?");
    return;
  }

  if ((int)program->outputs.size() != dest.size()) {
    SH_DEBUG_ERROR("Number of stream program outputs ("
                   << program->outputs.size()
                   << ") does not match number of destinations ("
                   << dest.size()
                   << ").");
    return;
  }
  TIMING_RESULT(overhead);

  // TODO: Check that the size of each output matches the size of each dest.

  int count = (*dest.begin())->count();

  for (ShStream::iterator I = dest.begin(); I != dest.end(); ++I) {
    if (count != (*I)->count()) {
      shError(PBufferStreamException("All stream outputs must be of the same size"));
    }
  }

  // Pick a size for the texture that just fits the output data.
  int tex_size = 1;

  while (tex_size * tex_size < count) {
    tex_size <<= 1;
  }

  DECLARE_TIMER(onerun);

  PBufferFactory* factory = PBufferFactory::instance();

  if (!factory) {
    throw PBufferStreamException("No PBuffer support found.\n"
                                 "Ensure your system supports floating point pbuffers.");
    return;
  }

  FloatExtension extension = factory->get_extension();

  // --- Set up the GLX context
  PBufferContextPtr context = factory->get_context(tex_size, tex_size);

  PBufferHandlePtr old_handle = context->activate();

  DECLARE_TIMER(vpsetup);

  // --- Set up the vertex program
  if (!m_setup_vp) {
    // The (trivial) vertex program
    m_vp = keep<ShPosition4f>() & keep<ShTexCoord2f>();
    m_vp.node()->target() = "gpu:vertex";
    shCompile(m_vp);
    m_setup_vp = true;
  }

  TIMING_RESULT(vpsetup);

  // --- Set up the fragment programs and such
  PBufferStreamCache* cache = program->get_info<PBufferStreamCache>();
  if (!cache) {
    cache = new PBufferStreamCache(program.object(), m_vp.node().object());
    program->add_info(cache);
  }

  cache->update_channels(tex_size, tex_size);

  // Run each fragment program

  ShStream::iterator dest_iter = dest.begin();
  for (PBufferStreamCache::set_iterator I = cache->sets_begin();
       I != cache->sets_end(); ++I, ++dest_iter) {

    ShChannelNode* output = dest_iter->object();

    DECLARE_TIMER(binding);
    // Then, bind vertex (pass-through) and fragment program
    shBind(**I);
    TIMING_RESULT(binding);

    DECLARE_TIMER(clear);
    glClear(GL_COLOR_BUFFER_BIT);
    TIMING_RESULT(clear);

    DECLARE_TIMER(rendersetup);
    glViewport(0, 0, tex_size, tex_size);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    float tc_right;
    float tc_upper;

    if (extension == SH_ARB_NV_FLOAT_BUFFER) {
      tc_right = static_cast<float>(tex_size);
      tc_upper = static_cast<float>(tex_size);
    } else {
      tc_right = 1.0;
      tc_upper = 1.0;
    }
    TIMING_RESULT(rendersetup);

    DECLARE_TIMER(render);

    // Generate quad geometry
    glBegin(GL_QUADS); {
      glTexCoord2f(0.0, 0.0);
      glVertex3f(-1.0, -1.0, 0.0);
      glTexCoord2f(0.0, tc_upper);
      glVertex3f(-1.0,  1.0, 0.0);
      glTexCoord2f(tc_right, tc_upper);
      glVertex3f( 1.0,  1.0, 0.0);
      glTexCoord2f(tc_right, 0.0);
      glVertex3f( 1.0, -1.0, 0.0);
    } glEnd();

    TIMING_RESULT(render);

    DECLARE_TIMER(finish);
    glFinish();

    TIMING_RESULT(finish);

    // Unbind, just to be safe
    shUnbind(**I);

    int gl_error = glGetError();
    if (gl_error != GL_NO_ERROR) {
      shError(PBufferStreamException("Could not render"));
      return;
    }

    DECLARE_TIMER(findouthost);

    ShValueType valueType = output->valueType();

    ShHostStoragePtr outhost
      = shref_dynamic_cast<ShHostStorage>(output->memory()->findStorage("host"));
    if (!outhost) {
      int datasize = shTypeInfo(valueType)->datasize();
      outhost = new ShHostStorage(output->memory().object(),
                                  datasize * output->size() * output->count());
    }
    TIMING_RESULT(findouthost);

    DECLARE_TIMER(dirtyouthost);
    // Read back
    outhost->dirty();
    TIMING_RESULT(dirtyouthost);

    GLenum format;
    switch (output->size()) {
    case 1:
      format = GL_RED;
      break;
    case 2:
      SH_DEBUG_ASSERT(0 && "Sorry, 2-component outputs aren't working right now!");
      break;
    case 3:
      format = GL_RGB;
      break;
    case 4:
      format = GL_RGBA;
      break;
    default:
      SH_DEBUG_ASSERT(false);
      break;
    }

    DECLARE_TIMER(readback);

    // @todo half-float
    ShVariantPtr  resultBuffer;
    int resultDatasize = output->size() * count;
    GLenum readpixelType;
    ShValueType convertedType;
    readpixelType = shGlType(valueType, convertedType);
    if(convertedType != SH_VALUETYPE_END) {
      SH_DEBUG_WARN("ARB backend does not handle stream output type " << shValueTypeName(valueType) << " natively."
                    << "  Using " << shValueTypeName(convertedType) << " temporary buffer.");
      resultBuffer = shVariantFactory(convertedType, SH_MEM)->generate(resultDatasize);
    } else {
      resultBuffer = shVariantFactory(valueType, SH_MEM)->generate(
                                                                   outhost->data(), resultDatasize, false);
    }

    glReadPixels(0, 0, tex_size, count / tex_size, format,
                 readpixelType, resultBuffer->array());
    gl_error = glGetError();
    if (gl_error != GL_NO_ERROR) {
      shError(PBufferStreamException("Could not do glReadPixels()"));
      return;
    }
    if (count % tex_size) {
      glReadPixels(0, count / tex_size, count % tex_size, 1, format, readpixelType,
                   (char*)(resultBuffer->array()) + (count - (count % tex_size)) * output->size() * resultBuffer->datasize());
      gl_error = glGetError();
      if (gl_error != GL_NO_ERROR) {
        shError(PBufferStreamException("Could not do rest of glReadPixels()"));
        return;
      }
    }

    if(convertedType != SH_VALUETYPE_END) { // need to copy to outhoust->data()
      ShVariantPtr outhostVariant = shVariantFactory(valueType, SH_MEM)->generate(
                                                                                outhost->data(), resultDatasize, false);
      outhostVariant->set(resultBuffer);
    }

    TIMING_RESULT(readback);
  }

  if (old_handle) {
    old_handle->restore();
  }
}

StreamStrategy* PBufferStreams::create()
{
  return new PBufferStreams();
}

}
<commit_msg>Initialize a variable to remove compilation warning<commit_after>// Sh: A GPU metaprogramming language.
//
// Copyright (c) 2003 University of Waterloo Computer Graphics Laboratory
// Project administrator: Michael D. McCool
// Authors: Zheng Qin, Stefanus Du Toit, Kevin Moule, Tiberiu S. Popa,
//          Michael D. McCool
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must
// not claim that you wrote the original software. If you use this
// software in a product, an acknowledgment in the product documentation
// would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must
// not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//////////////////////////////////////////////////////////////////////////////
#include "PBufferStreams.hpp"

/// Turn this on if you want timings on std::cerr
//#define DO_PBUFFER_TIMING

// Turn this on to debug the fragment programs.
//#define SH_DEBUG_PBS_PRINTFP

#include <map>
#include <fstream>
#include <cstdlib>
#include <list>

#include "sh.hpp"
#include "ShOptimizations.hpp"
#include "ShException.hpp"
#include "ShError.hpp"
#include "ShTypeInfo.hpp"
#include "ShVariant.hpp"
#include "PBufferContext.hpp"
#include "Utils.hpp"

#ifdef DO_PBUFFER_TIMING
#include <sys/time.h>
#include <time.h>
#endif

namespace shgl {

using namespace SH;

#ifdef DO_PBUFFER_TIMING

class Timer {
public:
  Timer() { start(); }

  void start() { gettimeofday(&startval, 0); }

  long diff() {
    timeval endval;
    gettimeofday(&endval, 0);
    return (endval.tv_sec - startval.tv_sec)*1000
      + (endval.tv_usec/1000 - startval.tv_usec/1000);
  }

private:
  timeval startval;
};

#endif

class PBufferStreamException : public ShException {
public:
  PBufferStreamException(const std::string& message)
    : ShException("PBuffer Stream Execution: " + message)
  {
  }
};

class PBufferStreamCache : public ShInfo {
public:
  PBufferStreamCache(ShProgramNode* stream_program,
                     ShProgramNode* vertex_program);

  ShInfo* clone() const;

  void update_channels(int width, int height);

  void build_sets(ShProgramNode* vertex_program);

  typedef std::list<ShProgramSetPtr>::iterator set_iterator;
  typedef std::list<ShProgramSetPtr>::const_iterator set_const_iterator;
  typedef std::list<ShProgramNodePtr>::iterator program_iterator;
  typedef std::list<ShProgramNodePtr>::const_iterator program_const_iterator;

  set_iterator sets_begin() { return m_program_sets.begin(); }
  set_iterator sets_end() { return m_program_sets.end(); }
  set_const_iterator sets_begin() const { return m_program_sets.begin(); }
  set_const_iterator sets_end() const { return m_program_sets.end(); }

  program_iterator programs_begin() { return m_programs.begin(); }
  program_iterator programs_end() { return m_programs.end(); }
  program_const_iterator programs_begin() const { return m_programs.begin(); }
  program_const_iterator programs_end() const { return m_programs.end(); }

private:
  ShProgramNode* m_stream_program;
  ShProgramNode* m_vertex_program;
  ChannelMap m_channel_map;
  std::list<ShProgramNodePtr> m_programs;
  std::list<ShProgramSetPtr> m_program_sets;

  PBufferStreamCache(const PBufferStreamCache& other);
  PBufferStreamCache& operator=(const PBufferStreamCache& other);
};

PBufferStreamCache::PBufferStreamCache(ShProgramNode* stream_program,
                                       ShProgramNode* vertex_program)
  : m_stream_program(stream_program),
    m_vertex_program(vertex_program)
{
  FloatExtension extension = PBufferFactory::instance()->get_extension();
  ShTextureDims dims(SH_TEXTURE_2D);

  switch (extension) {
  case SH_ARB_NV_FLOAT_BUFFER:
    dims = SH_TEXTURE_RECT;
    break;
  case SH_ARB_ATI_PIXEL_FORMAT_FLOAT:
    dims = SH_TEXTURE_2D;
    break;
  case SH_ARB_NO_FLOAT_EXT:
    throw PBufferStreamException("No floating point rendering target.\n"
                                 "Ensure your system supports floating point pbuffers.");
    break;
  }

  ChannelGatherer gatherer(m_channel_map, dims);
  stream_program->ctrlGraph->dfs(gatherer);

  split_program(stream_program, m_programs, "gpu:fragment");

  for (std::list<ShProgramNodePtr>::iterator I = m_programs.begin();
       I != m_programs.end(); ++I) {
    ShProgram with_tc = ShProgram(*I) & lose<ShTexCoord2f>("streamcoord");

    TexFetcher fetcher(m_channel_map, with_tc.node()->inputs.back(),
                       dims == SH_TEXTURE_RECT, with_tc.node());
    with_tc.node()->ctrlGraph->dfs(fetcher);

    optimize(with_tc);

    *I = with_tc.node();
  }

  build_sets(vertex_program);
}

ShInfo* PBufferStreamCache::clone() const
{
  return new PBufferStreamCache(m_stream_program, m_vertex_program);
}

void PBufferStreamCache::update_channels(int width, int height)
{
  for (ChannelMap::iterator I = m_channel_map.begin(); I != m_channel_map.end(); ++I) {
    ShChannelNode* channel = I->first.object();
    ShTextureNode* texture = I->second.object();

    SH_DEBUG_ASSERT(channel);
    SH_DEBUG_ASSERT(texture);

    texture->memory(channel->memory());
    texture->setTexSize(width, height);
    texture->count(channel->count());
  }
}

void PBufferStreamCache::build_sets(ShProgramNode* vertex_program)
{
  m_vertex_program = vertex_program;
  m_program_sets.clear();
  for (std::list<ShProgramNodePtr>::iterator I = m_programs.begin(); I != m_programs.end(); ++I) {
    m_program_sets.push_back(new ShProgramSet(ShProgram(vertex_program),
                                              ShProgram(*I)));
  }
}

PBufferStreams::PBufferStreams(void) :
  m_shaders(NULL), m_setup_vp(false)
{
}

PBufferStreams::~PBufferStreams()
{
}

#ifdef DO_PBUFFER_TIMING
int indent = 0;
Timer supertimer;

void fillin()
{
  long sd = supertimer.diff();
  supertimer.start();
  if (indent) for (int j = 0; j < sd; j++) {
    for (int i = 0; i < indent; i++) std::cerr << "| ";
    std::cerr << std::endl;
  }
}

#define DECLARE_TIMER(t) Timer pbtime_ ## t; do { fillin(); for (int i = 0; i < indent; i++) std::cerr << "| "; std::cerr << "^ " << # t << " starts" << std::endl; indent++;} while (0)
#define TIMING_RESULT(t) do {long d = pbtime_ ## t.diff(); fillin(); indent--; for (int i = 0; i < indent; i++) std::cerr << "| "; std::cerr << "v " << # t << " took " << d << " ms" << std::endl; supertimer.start(); } while (0)
#else
#define DECLARE_TIMER(t)
#define TIMING_RESULT(t)
#endif

void PBufferStreams::execute(const ShProgramNodeCPtr& program_const,
                             ShStream& dest)
{
  // Let's get rid of that constness... Yes, yes, I know...
  ShProgramNodePtr program = shref_const_cast<ShProgramNode>(program_const);

  DECLARE_TIMER(overhead);

  // Check program target
  if (program->target() != "gpu:stream") {
    shError(PBufferStreamException("This backend can only execute ``gpu:stream'' programs."));
    return;
  }

  // Make sure program has no inputs
  if (!program->inputs.empty()) {
    shError(PBufferStreamException("Stream program has unbound inputs, and can hence not be executed."));
    return;
  }

  if (dest.size() == 0) {
    SH_DEBUG_WARN("Stream program has no outputs?");
    return;
  }

  if ((int)program->outputs.size() != dest.size()) {
    SH_DEBUG_ERROR("Number of stream program outputs ("
                   << program->outputs.size()
                   << ") does not match number of destinations ("
                   << dest.size()
                   << ").");
    return;
  }
  TIMING_RESULT(overhead);

  // TODO: Check that the size of each output matches the size of each dest.

  int count = (*dest.begin())->count();

  for (ShStream::iterator I = dest.begin(); I != dest.end(); ++I) {
    if (count != (*I)->count()) {
      shError(PBufferStreamException("All stream outputs must be of the same size"));
    }
  }

  // Pick a size for the texture that just fits the output data.
  int tex_size = 1;

  while (tex_size * tex_size < count) {
    tex_size <<= 1;
  }

  DECLARE_TIMER(onerun);

  PBufferFactory* factory = PBufferFactory::instance();

  if (!factory) {
    throw PBufferStreamException("No PBuffer support found.\n"
                                 "Ensure your system supports floating point pbuffers.");
    return;
  }

  FloatExtension extension = factory->get_extension();

  // --- Set up the GLX context
  PBufferContextPtr context = factory->get_context(tex_size, tex_size);

  PBufferHandlePtr old_handle = context->activate();

  DECLARE_TIMER(vpsetup);

  // --- Set up the vertex program
  if (!m_setup_vp) {
    // The (trivial) vertex program
    m_vp = keep<ShPosition4f>() & keep<ShTexCoord2f>();
    m_vp.node()->target() = "gpu:vertex";
    shCompile(m_vp);
    m_setup_vp = true;
  }

  TIMING_RESULT(vpsetup);

  // --- Set up the fragment programs and such
  PBufferStreamCache* cache = program->get_info<PBufferStreamCache>();
  if (!cache) {
    cache = new PBufferStreamCache(program.object(), m_vp.node().object());
    program->add_info(cache);
  }

  cache->update_channels(tex_size, tex_size);

  // Run each fragment program

  ShStream::iterator dest_iter = dest.begin();
  for (PBufferStreamCache::set_iterator I = cache->sets_begin();
       I != cache->sets_end(); ++I, ++dest_iter) {

    ShChannelNode* output = dest_iter->object();

    DECLARE_TIMER(binding);
    // Then, bind vertex (pass-through) and fragment program
    shBind(**I);
    TIMING_RESULT(binding);

    DECLARE_TIMER(clear);
    glClear(GL_COLOR_BUFFER_BIT);
    TIMING_RESULT(clear);

    DECLARE_TIMER(rendersetup);
    glViewport(0, 0, tex_size, tex_size);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    float tc_right;
    float tc_upper;

    if (extension == SH_ARB_NV_FLOAT_BUFFER) {
      tc_right = static_cast<float>(tex_size);
      tc_upper = static_cast<float>(tex_size);
    } else {
      tc_right = 1.0;
      tc_upper = 1.0;
    }
    TIMING_RESULT(rendersetup);

    DECLARE_TIMER(render);

    // Generate quad geometry
    glBegin(GL_QUADS); {
      glTexCoord2f(0.0, 0.0);
      glVertex3f(-1.0, -1.0, 0.0);
      glTexCoord2f(0.0, tc_upper);
      glVertex3f(-1.0,  1.0, 0.0);
      glTexCoord2f(tc_right, tc_upper);
      glVertex3f( 1.0,  1.0, 0.0);
      glTexCoord2f(tc_right, 0.0);
      glVertex3f( 1.0, -1.0, 0.0);
    } glEnd();

    TIMING_RESULT(render);

    DECLARE_TIMER(finish);
    glFinish();

    TIMING_RESULT(finish);

    // Unbind, just to be safe
    shUnbind(**I);

    int gl_error = glGetError();
    if (gl_error != GL_NO_ERROR) {
      shError(PBufferStreamException("Could not render"));
      return;
    }

    DECLARE_TIMER(findouthost);

    ShValueType valueType = output->valueType();

    ShHostStoragePtr outhost
      = shref_dynamic_cast<ShHostStorage>(output->memory()->findStorage("host"));
    if (!outhost) {
      int datasize = shTypeInfo(valueType)->datasize();
      outhost = new ShHostStorage(output->memory().object(),
                                  datasize * output->size() * output->count());
    }
    TIMING_RESULT(findouthost);

    DECLARE_TIMER(dirtyouthost);
    // Read back
    outhost->dirty();
    TIMING_RESULT(dirtyouthost);

    GLenum format;
    switch (output->size()) {
    case 1:
      format = GL_RED;
      break;
    case 2:
      SH_DEBUG_ASSERT(0 && "Sorry, 2-component outputs aren't working right now!");
      break;
    case 3:
      format = GL_RGB;
      break;
    case 4:
      format = GL_RGBA;
      break;
    default:
      SH_DEBUG_ASSERT(false);
      break;
    }

    DECLARE_TIMER(readback);

    // @todo half-float
    ShVariantPtr  resultBuffer;
    int resultDatasize = output->size() * count;
    GLenum readpixelType;
    ShValueType convertedType;
    readpixelType = shGlType(valueType, convertedType);
    if(convertedType != SH_VALUETYPE_END) {
      SH_DEBUG_WARN("ARB backend does not handle stream output type " << shValueTypeName(valueType) << " natively."
                    << "  Using " << shValueTypeName(convertedType) << " temporary buffer.");
      resultBuffer = shVariantFactory(convertedType, SH_MEM)->generate(resultDatasize);
    } else {
      resultBuffer = shVariantFactory(valueType, SH_MEM)->generate(
                                                                   outhost->data(), resultDatasize, false);
    }

    glReadPixels(0, 0, tex_size, count / tex_size, format,
                 readpixelType, resultBuffer->array());
    gl_error = glGetError();
    if (gl_error != GL_NO_ERROR) {
      shError(PBufferStreamException("Could not do glReadPixels()"));
      return;
    }
    if (count % tex_size) {
      glReadPixels(0, count / tex_size, count % tex_size, 1, format, readpixelType,
                   (char*)(resultBuffer->array()) + (count - (count % tex_size)) * output->size() * resultBuffer->datasize());
      gl_error = glGetError();
      if (gl_error != GL_NO_ERROR) {
        shError(PBufferStreamException("Could not do rest of glReadPixels()"));
        return;
      }
    }

    if(convertedType != SH_VALUETYPE_END) { // need to copy to outhoust->data()
      ShVariantPtr outhostVariant = shVariantFactory(valueType, SH_MEM)->generate(
                                                                                outhost->data(), resultDatasize, false);
      outhostVariant->set(resultBuffer);
    }

    TIMING_RESULT(readback);
  }

  if (old_handle) {
    old_handle->restore();
  }
}

StreamStrategy* PBufferStreams::create()
{
  return new PBufferStreams();
}

}
<|endoftext|>


<commit_before>// RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -split-phi-edges=0 -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
// RUN: clang-cc -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s

extern "C" int printf(...);

struct C {
  C() : iC(6) {}
  int iC;
};

int foo() {
  return 6;
};

class X { // ...
public:
  X(int) {}
  X(const X&, int i = 1, int j = 2, int k = foo()) {
    printf("X(const X&, %d, %d, %d)\n", i, j, k);
  }
};

int main() {
  X a(1);
  X b(a, 2);
  X c = b;
  X d(a, 5, 6);
}

// CHECK-LP64: call __ZN1XC1ERKS_iii
// CHECK-LP64: call __ZN1XC1ERKS_iii
// CHECK-LP64: call __ZN1XC1ERKS_iii

// CHECK-LP32: call L__ZN1XC1ERKS_iii
// CHECK-LP32: call L__ZN1XC1ERKS_iii
// CHECK-LP32: call L__ZN1XC1ERKS_iii
<commit_msg>Undo previous test fix. -split-phi-edges now disables automatically when the local register allocator is used.<commit_after>// RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
// RUN: clang-cc -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s

extern "C" int printf(...);

struct C {
  C() : iC(6) {}
  int iC;
};

int foo() {
  return 6;
};

class X { // ...
public:
  X(int) {}
  X(const X&, int i = 1, int j = 2, int k = foo()) {
    printf("X(const X&, %d, %d, %d)\n", i, j, k);
  }
};

int main() {
  X a(1);
  X b(a, 2);
  X c = b;
  X d(a, 5, 6);
}

// CHECK-LP64: call __ZN1XC1ERKS_iii
// CHECK-LP64: call __ZN1XC1ERKS_iii
// CHECK-LP64: call __ZN1XC1ERKS_iii

// CHECK-LP32: call L__ZN1XC1ERKS_iii
// CHECK-LP32: call L__ZN1XC1ERKS_iii
// CHECK-LP32: call L__ZN1XC1ERKS_iii
<|endoftext|>


<commit_before>// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -g -emit-llvm -o - | FileCheck %s
// This test is for a crash when emitting debug info for not-yet-completed types.
// Test that we don't actually emit a forward decl for the offending class:
// CHECK:  [ DW_TAG_class_type ] [Derived<const __CFString, Foo>] {{.*}} [def]
// rdar://problem/15931354
typedef const struct __CFString * CFStringRef;
template <class R> class Returner {};
typedef const __CFString String;

template <class A, class B> class Derived;

template <class A, class B>
class Base
{
  static Derived<A, B>* create();
};

template <class A, class B>
class Derived : public Base<A, B> {
public:
  static void foo();
};

class Foo
{
  Foo();
  static Returner<Base<String,Foo> > all();
};

Foo::Foo(){}

Returner<Base<String,Foo> > Foo::all()
{
  Derived<String,Foo>::foo();
  return Foo::all();
}
<commit_msg>Simplify testcase from r200797 some more.<commit_after>// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -g -emit-llvm -o - | FileCheck %s
// This test is for a crash when emitting debug info for not-yet-completed types.
// Test that we don't actually emit a forward decl for the offending class:
// CHECK:  [ DW_TAG_class_type ] [Derived<Foo>] {{.*}} [def]
// rdar://problem/15931354
template <class R> class Returner {};
template <class A> class Derived;

template <class A>
class Base
{
  static Derived<A>* create();
};

template <class A>
class Derived : public Base<A> {
public:
  static void foo();
};

class Foo
{
  Foo();
  static Returner<Base<Foo> > all();
};

Foo::Foo(){}

Returner<Base<Foo> > Foo::all()
{
  Derived<Foo>::foo();
  return Foo::all();
}
<|endoftext|>


<commit_before>// This is a regression test on debug info to make sure that we can
// print line numbers in asm.
// RUN: %llvmgcc -S -O0 -g %s -o - | \
// RUN:    llc --disable-fp-elim -O0 -relocation-model=pic | grep {2009-07-15-LineNumbers.cpp:25$}

#include <stdlib.h>

class DeepStack {
  int seedVal;
public:
  DeepStack(int seed) : seedVal(seed) {}

  int shallowest( int x ) { return shallower(x + 1); }
  int shallower ( int x ) { return shallow(x + 2); }
  int shallow   ( int x ) { return deep(x + 3); }
  int deep      ( int x ) { return deeper(x + 4); }
  int deeper    ( int x ) { return deepest(x + 6); }
  int deepest   ( int x ) { return x + 7; }

  int runit() { return shallowest(seedVal); }
};

int main ( int argc, char** argv) {

  DeepStack DS9( (argc > 1 ? atoi(argv[1]) : 0) );
  return DS9.runit();
}
<commit_msg>Remove test to check line numbers. There are other numerous tests in our test harness to check line number information. <commit_after><|endoftext|>


<commit_before>// Regression test for https://github.com/google/sanitizers/issues/691

// RUN: %clangxx_asan -O0 %s -o %t -fstack-protector
// RUN: %run %t 1 2>&1 | FileCheck %s
// RUN: %run %t 2 2>&1 | FileCheck %s

#include <stdio.h>
#include <string.h>

// MSVC provides _alloca instead of alloca.
#if defined(_MSC_VER) && !defined(alloca)
# define alloca _alloca
#else
#include <alloca.h>
#endif

void f1_alloca() {
  char *dynamic_buffer = (char *)alloca(200);
  fprintf(stderr, "dynamic_buffer = %p\n", dynamic_buffer);
  memset(dynamic_buffer, 'y', 200);
  return;
}

static const int kDynamicArraySize = 200;

void f1_vla() {
  char dynamic_buffer[kDynamicArraySize];
  fprintf(stderr, "dynamic_buffer = %p\n", dynamic_buffer);
  memset(dynamic_buffer, 'y', kDynamicArraySize);
  return;
}

void f2() {
  char buf[1024];
  memset(buf, 'x', 1024);
}

int main(int argc, const char *argv[]) {
  if (!strcmp(argv[1], "1")) {
    f1_alloca();
  } else if (!strcmp(argv[1], "2")) {
    f1_vla();
  }
  f2();
  fprintf(stderr, "Done.\n");
  return 0;
}

// CHECK-NOT: ERROR: AddressSanitizer
// CHECK: Done.
<commit_msg>Fix ASan alloca_constant_size.cc test on FreeBSD.<commit_after>// Regression test for https://github.com/google/sanitizers/issues/691

// RUN: %clangxx_asan -O0 %s -o %t -fstack-protector
// RUN: %run %t 1 2>&1 | FileCheck %s
// RUN: %run %t 2 2>&1 | FileCheck %s

#include <stdio.h>
#include <string.h>

// MSVC provides _alloca instead of alloca.
#if defined(_MSC_VER) && !defined(alloca)
# define alloca _alloca
#elif defined(__FreeBSD__)
#include <stdlib.h>
#else
#include <alloca.h>
#endif

void f1_alloca() {
  char *dynamic_buffer = (char *)alloca(200);
  fprintf(stderr, "dynamic_buffer = %p\n", dynamic_buffer);
  memset(dynamic_buffer, 'y', 200);
  return;
}

static const int kDynamicArraySize = 200;

void f1_vla() {
  char dynamic_buffer[kDynamicArraySize];
  fprintf(stderr, "dynamic_buffer = %p\n", dynamic_buffer);
  memset(dynamic_buffer, 'y', kDynamicArraySize);
  return;
}

void f2() {
  char buf[1024];
  memset(buf, 'x', 1024);
}

int main(int argc, const char *argv[]) {
  if (!strcmp(argv[1], "1")) {
    f1_alloca();
  } else if (!strcmp(argv[1], "2")) {
    f1_vla();
  }
  f2();
  fprintf(stderr, "Done.\n");
  return 0;
}

// CHECK-NOT: ERROR: AddressSanitizer
// CHECK: Done.
<|endoftext|>