<commit_before>#include "partition/partition_config.hpp"
#include "partition/partitioner.hpp"

#include "util/log.hpp"
#include "util/meminfo.hpp"
#include "util/timing_util.hpp"
#include "util/version.hpp"

#include <tbb/task_scheduler_init.h>

#include <boost/algorithm/string/join.hpp>
#include <boost/assert.hpp>
#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>
#include <boost/range/adaptor/tokenized.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/copy.hpp>

#include <iostream>

using namespace osrm;

enum class return_code : unsigned
{
    ok,
    fail,
    exit
};

struct MaxCellSizesArgument
{
    std::vector<size_t> value;
};

std::ostream &operator<<(std::ostream &os, const MaxCellSizesArgument &arg)
{
    return os << boost::algorithm::join(
               arg.value | boost::adaptors::transformed([](auto x) { return std::to_string(x); }),
               ",");
}

void validate(boost::any &v, const std::vector<std::string> &values, MaxCellSizesArgument *, int)
{
    using namespace boost::program_options;
    using namespace boost::adaptors;

    // Make sure no previous assignment to 'v' was made.
    validators::check_first_occurrence(v);
    // Extract the first string from 'values'. If there is more than
    // one string, it's an error, and exception will be thrown.
    const std::string &s = validators::get_single_string(values);

    std::vector<size_t> output;
    boost::copy(s | tokenized(boost::regex("[^,]+")) | transformed([](const auto &x) {
                    try
                    {
                        return boost::lexical_cast<std::size_t>(x);
                    }
                    catch (const boost::bad_lexical_cast &)
                    {
                        throw validation_error(validation_error::invalid_option_value);
                    }
                }),
                std::back_inserter(output));

    v = boost::any(MaxCellSizesArgument{output});
}

return_code parseArguments(int argc, char *argv[], partition::PartitionConfig &config)
{
    // declare a group of options that will be allowed only on command line
    boost::program_options::options_description generic_options("Options");
    generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message");

    // declare a group of options that will be allowed both on command line
    boost::program_options::options_description config_options("Configuration");
    config_options.add_options()
        //
        ("threads,t",
         boost::program_options::value<unsigned int>(&config.requested_num_threads)
             ->default_value(tbb::task_scheduler_init::default_num_threads()),
         "Number of threads to use")
        //
        ("balance",
         boost::program_options::value<double>(&config.balance)->default_value(config.balance),
         "Balance for left and right side in single bisection")
        //
        ("boundary",
         boost::program_options::value<double>(&config.boundary_factor)
             ->default_value(config.boundary_factor),
         "Percentage of embedded nodes to contract as sources and sinks")
        //
        ("optimizing-cuts",
         boost::program_options::value<std::size_t>(&config.num_optimizing_cuts)
             ->default_value(config.num_optimizing_cuts),
         "Number of cuts to use for optimizing a single bisection")
        //
        ("small-component-size",
         boost::program_options::value<std::size_t>(&config.small_component_size)
             ->default_value(config.small_component_size),
         "Size threshold for small components.")
        //
        ("max-cell-sizes",
         boost::program_options::value<MaxCellSizesArgument>()->default_value(
             MaxCellSizesArgument{config.max_cell_sizes}),
         "Maximum cell sizes starting from the level 1. The first cell size value is a bisection "
         "termination citerion");

    // hidden options, will be allowed on command line, but will not be
    // shown to the user
    boost::program_options::options_description hidden_options("Hidden options");
    hidden_options.add_options()(
        "input,i",
        boost::program_options::value<boost::filesystem::path>(&config.base_path),
        "Input file in .osrm format");

    // positional option
    boost::program_options::positional_options_description positional_options;
    positional_options.add("input", 1);

    // combine above options for parsing
    boost::program_options::options_description cmdline_options;
    cmdline_options.add(generic_options).add(config_options).add(hidden_options);

    const auto *executable = argv[0];
    boost::program_options::options_description visible_options(
        boost::filesystem::path(executable).filename().string() + " <input.osrm> [options]");
    visible_options.add(generic_options).add(config_options);

    // parse command line options
    boost::program_options::variables_map option_variables;
    try
    {
        boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
                                          .options(cmdline_options)
                                          .positional(positional_options)
                                          .run(),
                                      option_variables);
    }
    catch (const boost::program_options::error &e)
    {
        util::Log(logERROR) << e.what();
        return return_code::fail;
    }

    if (option_variables.count("version"))
    {
        std::cout << OSRM_VERSION << std::endl;
        return return_code::exit;
    }

    if (option_variables.count("help"))
    {
        std::cout << visible_options;
        return return_code::exit;
    }

    boost::program_options::notify(option_variables);

    if (!option_variables.count("input"))
    {
        std::cout << visible_options;
        return return_code::fail;
    }

    if (option_variables.count("max-cell-sizes"))
    {
        config.max_cell_sizes = option_variables["max-cell-sizes"].as<MaxCellSizesArgument>().value;

        if (!std::is_sorted(config.max_cell_sizes.begin(), config.max_cell_sizes.end()))
        {
            util::Log(logERROR)
                << "The maximum cell sizes array must be sorted in non-descending order.";
            return return_code::fail;
        }
    }

    return return_code::ok;
}

int main(int argc, char *argv[]) try
{
    util::LogPolicy::GetInstance().Unmute();
    partition::PartitionConfig partition_config;

    const auto result = parseArguments(argc, argv, partition_config);

    if (return_code::fail == result)
    {
        return EXIT_FAILURE;
    }

    if (return_code::exit == result)
    {
        return EXIT_SUCCESS;
    }

    // set the default in/output names
    partition_config.UseDefaults();

    if (1 > partition_config.requested_num_threads)
    {
        util::Log(logERROR) << "Number of threads must be 1 or larger";
        return EXIT_FAILURE;
    }

    auto check_file = [](const boost::filesystem::path &path) {
        if (!boost::filesystem::is_regular_file(path))
        {
            util::Log(logERROR) << "Input file " << path << " not found!";
            return false;
        }
        else
        {
            return true;
        }
    };

    if (!check_file(partition_config.edge_based_graph_path) ||
        !check_file(partition_config.cnbg_ebg_mapping_path) ||
        !check_file(partition_config.compressed_node_based_graph_path))
    {
        return EXIT_FAILURE;
    }

    tbb::task_scheduler_init init(partition_config.requested_num_threads);
    BOOST_ASSERT(init.is_active());
    util::Log() << "Computing recursive bisection";

    TIMER_START(bisect);
    auto exitcode = partition::Partitioner().Run(partition_config);
    TIMER_STOP(bisect);
    util::Log() << "Bisection took " << TIMER_SEC(bisect) << " seconds.";

    util::DumpMemoryStats();

    return exitcode;
}
catch (const std::bad_alloc &e)
{
    util::Log(logERROR) << "[exception] " << e.what();
    util::Log(logERROR) << "Please provide more memory or consider using a larger swapfile";
    return EXIT_FAILURE;
}
#ifdef _WIN32
catch (const std::exception &e)
{
    util::Log(logERROR) << "[exception] " << e.what() << std::endl;
    return EXIT_FAILURE;
}
#endif
<commit_msg>use std::regex_token_iterator instead of boost tokenized<commit_after>#include "partition/partition_config.hpp"
#include "partition/partitioner.hpp"

#include "util/log.hpp"
#include "util/meminfo.hpp"
#include "util/timing_util.hpp"
#include "util/version.hpp"

#include <tbb/task_scheduler_init.h>

#include <boost/algorithm/string/join.hpp>
#include <boost/assert.hpp>
#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>
#include <boost/range/adaptor/transformed.hpp>

#include <iostream>
#include <iterator>
#include <regex>

using namespace osrm;

enum class return_code : unsigned
{
    ok,
    fail,
    exit
};

struct MaxCellSizesArgument
{
    std::vector<size_t> value;
};

std::ostream &operator<<(std::ostream &os, const MaxCellSizesArgument &arg)
{
    auto to_string = [](std::size_t x) { return std::to_string(x); };
    return os << boost::algorithm::join(arg.value | boost::adaptors::transformed(to_string), ",");
}

void validate(boost::any &v, const std::vector<std::string> &values, MaxCellSizesArgument *, int)
{
    using namespace boost::program_options;
    using namespace boost::adaptors;

    // Make sure no previous assignment to 'v' was made.
    validators::check_first_occurrence(v);
    // Extract the first string from 'values'. If there is more than
    // one string, it's an error, and exception will be thrown.
    const std::string &s = validators::get_single_string(values);

    std::regex re(",");
    std::vector<size_t> output;
    std::transform(std::sregex_token_iterator(s.begin(), s.end(), re, -1),
                   std::sregex_token_iterator(),
                   std::back_inserter(output),
                   [](const auto &x) {
                       try
                       {
                           return boost::lexical_cast<std::size_t>(x);
                       }
                       catch (const boost::bad_lexical_cast &)
                       {
                           throw validation_error(validation_error::invalid_option_value);
                       }
                   });

    v = boost::any(MaxCellSizesArgument{output});
}

return_code parseArguments(int argc, char *argv[], partition::PartitionConfig &config)
{
    // declare a group of options that will be allowed only on command line
    boost::program_options::options_description generic_options("Options");
    generic_options.add_options()("version,v", "Show version")("help,h", "Show this help message");

    // declare a group of options that will be allowed both on command line
    boost::program_options::options_description config_options("Configuration");
    config_options.add_options()
        //
        ("threads,t",
         boost::program_options::value<unsigned int>(&config.requested_num_threads)
             ->default_value(tbb::task_scheduler_init::default_num_threads()),
         "Number of threads to use")
        //
        ("balance",
         boost::program_options::value<double>(&config.balance)->default_value(config.balance),
         "Balance for left and right side in single bisection")
        //
        ("boundary",
         boost::program_options::value<double>(&config.boundary_factor)
             ->default_value(config.boundary_factor),
         "Percentage of embedded nodes to contract as sources and sinks")
        //
        ("optimizing-cuts",
         boost::program_options::value<std::size_t>(&config.num_optimizing_cuts)
             ->default_value(config.num_optimizing_cuts),
         "Number of cuts to use for optimizing a single bisection")
        //
        ("small-component-size",
         boost::program_options::value<std::size_t>(&config.small_component_size)
             ->default_value(config.small_component_size),
         "Size threshold for small components.")
        //
        ("max-cell-sizes",
         boost::program_options::value<MaxCellSizesArgument>()->default_value(
             MaxCellSizesArgument{config.max_cell_sizes}),
         "Maximum cell sizes starting from the level 1. The first cell size value is a bisection "
         "termination citerion");

    // hidden options, will be allowed on command line, but will not be
    // shown to the user
    boost::program_options::options_description hidden_options("Hidden options");
    hidden_options.add_options()(
        "input,i",
        boost::program_options::value<boost::filesystem::path>(&config.base_path),
        "Input file in .osrm format");

    // positional option
    boost::program_options::positional_options_description positional_options;
    positional_options.add("input", 1);

    // combine above options for parsing
    boost::program_options::options_description cmdline_options;
    cmdline_options.add(generic_options).add(config_options).add(hidden_options);

    const auto *executable = argv[0];
    boost::program_options::options_description visible_options(
        boost::filesystem::path(executable).filename().string() + " <input.osrm> [options]");
    visible_options.add(generic_options).add(config_options);

    // parse command line options
    boost::program_options::variables_map option_variables;
    try
    {
        boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
                                          .options(cmdline_options)
                                          .positional(positional_options)
                                          .run(),
                                      option_variables);
    }
    catch (const boost::program_options::error &e)
    {
        util::Log(logERROR) << e.what();
        return return_code::fail;
    }

    if (option_variables.count("version"))
    {
        std::cout << OSRM_VERSION << std::endl;
        return return_code::exit;
    }

    if (option_variables.count("help"))
    {
        std::cout << visible_options;
        return return_code::exit;
    }

    boost::program_options::notify(option_variables);

    if (!option_variables.count("input"))
    {
        std::cout << visible_options;
        return return_code::fail;
    }

    if (option_variables.count("max-cell-sizes"))
    {
        config.max_cell_sizes = option_variables["max-cell-sizes"].as<MaxCellSizesArgument>().value;

        if (!std::is_sorted(config.max_cell_sizes.begin(), config.max_cell_sizes.end()))
        {
            util::Log(logERROR)
                << "The maximum cell sizes array must be sorted in non-descending order.";
            return return_code::fail;
        }
    }

    return return_code::ok;
}

int main(int argc, char *argv[]) try
{
    util::LogPolicy::GetInstance().Unmute();
    partition::PartitionConfig partition_config;

    const auto result = parseArguments(argc, argv, partition_config);

    if (return_code::fail == result)
    {
        return EXIT_FAILURE;
    }

    if (return_code::exit == result)
    {
        return EXIT_SUCCESS;
    }

    // set the default in/output names
    partition_config.UseDefaults();

    if (1 > partition_config.requested_num_threads)
    {
        util::Log(logERROR) << "Number of threads must be 1 or larger";
        return EXIT_FAILURE;
    }

    auto check_file = [](const boost::filesystem::path &path) {
        if (!boost::filesystem::is_regular_file(path))
        {
            util::Log(logERROR) << "Input file " << path << " not found!";
            return false;
        }
        else
        {
            return true;
        }
    };

    if (!check_file(partition_config.edge_based_graph_path) ||
        !check_file(partition_config.cnbg_ebg_mapping_path) ||
        !check_file(partition_config.compressed_node_based_graph_path))
    {
        return EXIT_FAILURE;
    }

    tbb::task_scheduler_init init(partition_config.requested_num_threads);
    BOOST_ASSERT(init.is_active());
    util::Log() << "Computing recursive bisection";

    TIMER_START(bisect);
    auto exitcode = partition::Partitioner().Run(partition_config);
    TIMER_STOP(bisect);
    util::Log() << "Bisection took " << TIMER_SEC(bisect) << " seconds.";

    util::DumpMemoryStats();

    return exitcode;
}
catch (const std::bad_alloc &e)
{
    util::Log(logERROR) << "[exception] " << e.what();
    util::Log(logERROR) << "Please provide more memory or consider using a larger swapfile";
    return EXIT_FAILURE;
}
#ifdef _WIN32
catch (const std::exception &e)
{
    util::Log(logERROR) << "[exception] " << e.what() << std::endl;
    return EXIT_FAILURE;
}
#endif
<|endoftext|>


<commit_before>// This code is in the public domain -- Ignacio Castao <castano@gmail.com>

#pragma once
#ifndef NV_CORE_ARRAY_INL
#define NV_CORE_ARRAY_INL

#include "Array.h"

#include "Stream.h"
#include "Utils.h" // swap

#include <string.h>	// memmove
#include <new> // for placement new

namespace nv
{

    // Push an element at the end of the vector.
    template <typename T>
    NV_FORCEINLINE void Array<T>::push_back( const T & val )
    {
#if 1
        nvDebugCheck(&val < m_buffer || &val > m_buffer+m_size);

        uint old_size = m_size;
        uint new_size = m_size + 1;

        setArraySize(new_size);

        construct_range(m_buffer, new_size, old_size, val);
#else
        uint new_size = m_size + 1;

        if (new_size > m_capacity)
        {
            // @@ Is there any way to avoid this copy?
            // @@ Can we create a copy without side effects? Ie. without calls to constructor/destructor. Use alloca + memcpy?
            // @@ Assert instead of copy?
            const T copy(val);	// create a copy in case value is inside of this array.

            setArraySize(new_size);

            new (m_buffer+new_size-1) T(copy);
        }
        else
        {
            m_size = new_size;
            new(m_buffer+new_size-1) T(val);
        }
#endif // 0/1
    }
    template <typename T>
    NV_FORCEINLINE void Array<T>::pushBack( const T & val )
    {
        push_back(val);
    }
    template <typename T>
    NV_FORCEINLINE void Array<T>::append( const T & val )
    {
        push_back(val);
    }

    // Qt like push operator.
    template <typename T>
    NV_FORCEINLINE Array<T> & Array<T>::operator<< ( T & t )
    {
        push_back(t);
        return *this;
    }

    // Pop the element at the end of the vector.
    template <typename T>
    NV_FORCEINLINE void Array<T>::pop_back()
    {
        nvDebugCheck( m_size > 0 );
        resize( m_size - 1 );
    }
    template <typename T>
    NV_FORCEINLINE void Array<T>::popBack()
    {
        pop_back();
    }

    // Get back element.
    template <typename T>
    NV_FORCEINLINE const T & Array<T>::back() const
    {
        nvDebugCheck( m_size > 0 );
        return m_buffer[m_size-1];
    }

    // Get back element.
    template <typename T>
    NV_FORCEINLINE T & Array<T>::back()
    {
        nvDebugCheck( m_size > 0 );
        return m_buffer[m_size-1];
    }

    // Get front element.
    template <typename T>
    NV_FORCEINLINE const T & Array<T>::front() const
    {
        nvDebugCheck( m_size > 0 );
        return m_buffer[0];
    }

    // Get front element.
    template <typename T>
    NV_FORCEINLINE T & Array<T>::front()
    {
        nvDebugCheck( m_size > 0 );
        return m_buffer[0];
    }

    // Check if the given element is contained in the array.
    template <typename T>
    NV_FORCEINLINE bool Array<T>::contains(const T & e) const
    {
        return find(e, NULL);
    }

    // Return true if element found.
    template <typename T>
    NV_FORCEINLINE bool Array<T>::find(const T & element, uint * indexPtr) const
    {
        return find(element, 0, m_size, indexPtr);
    }

    // Return true if element found within the given range.
    template <typename T>
    NV_FORCEINLINE bool Array<T>::find(const T & element, uint begin, uint end, uint * indexPtr) const
    {
        return ::nv::find(element, m_buffer, begin, end, indexPtr);
    }

    // Remove the element at the given index. This is an expensive operation!
    template <typename T>
    void Array<T>::removeAt(uint index)
    {
        nvDebugCheck(index >= 0 && index < m_size);

        if (m_size == 1) {
            clear();
        }
        else {
            m_buffer[index].~T();

            memmove(m_buffer+index, m_buffer+index+1, sizeof(T) * (m_size - 1 - index));
            m_size--;
        }
    }

    // Remove the first instance of the given element.
    template <typename T>
    bool Array<T>::remove(const T & element)
    {
        uint index;
        if (find(element, &index)) {
            removeAt(index);
            return true;
        }
        return false;
    }

    // Insert the given element at the given index shifting all the elements up.
    template <typename T>
    void Array<T>::insertAt(uint index, const T & val/*=T()*/)
    {
        nvDebugCheck( index >= 0 && index <= m_size );

        setArraySize(m_size + 1);

        if (index < m_size - 1) {
            memmove(m_buffer+index+1, m_buffer+index, sizeof(T) * (m_size - 1 - index));
        }

        // Copy-construct into the newly opened slot.
        new(m_buffer+index) T(val);
    }

    // Append the given data to our vector.
    template <typename T>
    NV_FORCEINLINE void Array<T>::append(const Array<T> & other)
    {
        append(other.m_buffer, other.m_size);
    }

    // Append the given data to our vector.
    template <typename T>
    void Array<T>::append(const T other[], uint count)
    {
        if (count > 0) {
            const uint old_size = m_size;

            setArraySize(m_size + count);

            for (uint i = 0; i < count; i++ ) {
                new(m_buffer + old_size + i) T(other[i]);
            }
        }
    }

    // Remove the given element by replacing it with the last one.
    template <typename T>
    void Array<T>::replaceWithLast(uint index)
    {
        nvDebugCheck( index < m_size );
        nv::swap(m_buffer[index], back());
        (m_buffer+m_size-1)->~T();
        m_size--;
    }

    // Resize the vector preserving existing elements.
    template <typename T>
    void Array<T>::resize(uint new_size)
    {
        uint old_size = m_size;

        // Destruct old elements (if we're shrinking).
        destroy_range(m_buffer, new_size, old_size);

        setArraySize(new_size);

        // Call default constructors
        construct_range(m_buffer, new_size, old_size);
    }

    // Resize the vector preserving existing elements and initializing the
    // new ones with the given value.
    template <typename T>
    void Array<T>::resize(uint new_size, const T & elem)
    {
        nvDebugCheck(&elem < m_buffer || &elem > m_buffer+m_size);

        uint old_size = m_size;

        // Destruct old elements (if we're shrinking).
        destroy_range(m_buffer, new_size, old_size);

        setArraySize(new_size);

        // Call copy constructors
        construct_range(m_buffer, new_size, old_size, elem);
    }

    // Fill array with the given value.
    template <typename T>
    void Array<T>::fill(const T & elem)
    {
        fill(m_buffer, m_size, elem)
    }

    // Clear the buffer.
    template <typename T>
    NV_FORCEINLINE void Array<T>::clear()
    {
        nvDebugCheck(isValidPtr(m_buffer));

        // Destruct old elements
        destroy_range(m_buffer, 0, m_size);

        m_size = 0;
    }

    // Shrink the allocated vector.
    template <typename T>
    NV_FORCEINLINE void Array<T>::shrink()
    {
        if (m_size < m_capacity) {
            setArrayCapacity(m_size);
        }
    }

    // Preallocate space.
    template <typename T>
    NV_FORCEINLINE void Array<T>::reserve(uint desired_size)
    {
        if (desired_size > m_capacity) {
            setArrayCapacity(desired_size);
        }
    }

    // Copy elements to this array. Resizes it if needed.
    template <typename T>
    NV_FORCEINLINE void Array<T>::copy(const T * data, uint count)
    {
#if 1   // More simple, but maybe not be as efficient?
        destroy_range(m_buffer, 0, m_size);

        setArraySize(count);

        construct_range(m_buffer, count, 0, data);
#else
        const uint old_size = m_size;

        destroy_range(m_buffer, count, old_size);

        setArraySize(count);

        copy_range(m_buffer, data, old_size);

        construct_range(m_buffer, count, old_size, data);
#endif
    }

    // Assignment operator.
    template <typename T>
    NV_FORCEINLINE Array<T> & Array<T>::operator=( const Array<T> & a )
    {
        copy(a.m_buffer, a.m_size);
        return *this;
    }

    // Release ownership of allocated memory and returns pointer to it.
    template <typename T>
    T * Array<T>::release() {
        T * tmp = m_buffer;
        m_buffer = NULL;
        m_capacity = 0;
        m_size = 0;
        return tmp;
    }

    // Change array size.
    template <typename T>
    inline void Array<T>::setArraySize(uint new_size) {
        m_size = new_size;

        if (new_size > m_capacity) {
            uint new_buffer_size;
            if (m_capacity == 0) {
                // first allocation is exact
                new_buffer_size = new_size;
            }
            else {
                // following allocations grow array by 25%
                new_buffer_size = new_size + (new_size >> 2);
            }

            setArrayCapacity( new_buffer_size );
        }
    }

    // Change array capacity.
    template <typename T>
    inline void Array<T>::setArrayCapacity(uint new_capacity) {
        nvDebugCheck(new_capacity >= m_size);

        if (new_capacity == 0) {
            // free the buffer.
            if (m_buffer != NULL) {
                free<T>(m_buffer);
                m_buffer = NULL;
            }
        }
        else {
            // realloc the buffer
            m_buffer = realloc<T>(m_buffer, new_capacity);
        }

        m_capacity = new_capacity;
    }

    // Array serialization.
    template <typename Typ>
    inline Stream & operator<< ( Stream & s, Array<Typ> & p )
    {
        if (s.isLoading()) {
            uint size;
            s << size;
            p.resize( size );
        }
        else {
            s << p.m_size;
        }

        for (uint i = 0; i < p.m_size; i++) {
            s << p.m_buffer[i];
        }

        return s;
    }

    // Swap the members of the two given vectors.
    template <typename Typ>
    inline void swap(Array<Typ> & a, Array<Typ> & b)
    {
        nv::swap(a.m_buffer, b.m_buffer);
        nv::swap(a.m_capacity, b.m_capacity);
        nv::swap(a.m_size, b.m_size);
    }

} // nv namespace

#endif // NV_CORE_ARRAY_INL
<commit_msg>Add missing semicolon. Fixes issue 179.<commit_after>// This code is in the public domain -- Ignacio Castao <castano@gmail.com>

#pragma once
#ifndef NV_CORE_ARRAY_INL
#define NV_CORE_ARRAY_INL

#include "Array.h"

#include "Stream.h"
#include "Utils.h" // swap

#include <string.h>	// memmove
#include <new> // for placement new

namespace nv
{

    // Push an element at the end of the vector.
    template <typename T>
    NV_FORCEINLINE void Array<T>::push_back( const T & val )
    {
#if 1
        nvDebugCheck(&val < m_buffer || &val > m_buffer+m_size);

        uint old_size = m_size;
        uint new_size = m_size + 1;

        setArraySize(new_size);

        construct_range(m_buffer, new_size, old_size, val);
#else
        uint new_size = m_size + 1;

        if (new_size > m_capacity)
        {
            // @@ Is there any way to avoid this copy?
            // @@ Can we create a copy without side effects? Ie. without calls to constructor/destructor. Use alloca + memcpy?
            // @@ Assert instead of copy?
            const T copy(val);	// create a copy in case value is inside of this array.

            setArraySize(new_size);

            new (m_buffer+new_size-1) T(copy);
        }
        else
        {
            m_size = new_size;
            new(m_buffer+new_size-1) T(val);
        }
#endif // 0/1
    }
    template <typename T>
    NV_FORCEINLINE void Array<T>::pushBack( const T & val )
    {
        push_back(val);
    }
    template <typename T>
    NV_FORCEINLINE void Array<T>::append( const T & val )
    {
        push_back(val);
    }

    // Qt like push operator.
    template <typename T>
    NV_FORCEINLINE Array<T> & Array<T>::operator<< ( T & t )
    {
        push_back(t);
        return *this;
    }

    // Pop the element at the end of the vector.
    template <typename T>
    NV_FORCEINLINE void Array<T>::pop_back()
    {
        nvDebugCheck( m_size > 0 );
        resize( m_size - 1 );
    }
    template <typename T>
    NV_FORCEINLINE void Array<T>::popBack()
    {
        pop_back();
    }

    // Get back element.
    template <typename T>
    NV_FORCEINLINE const T & Array<T>::back() const
    {
        nvDebugCheck( m_size > 0 );
        return m_buffer[m_size-1];
    }

    // Get back element.
    template <typename T>
    NV_FORCEINLINE T & Array<T>::back()
    {
        nvDebugCheck( m_size > 0 );
        return m_buffer[m_size-1];
    }

    // Get front element.
    template <typename T>
    NV_FORCEINLINE const T & Array<T>::front() const
    {
        nvDebugCheck( m_size > 0 );
        return m_buffer[0];
    }

    // Get front element.
    template <typename T>
    NV_FORCEINLINE T & Array<T>::front()
    {
        nvDebugCheck( m_size > 0 );
        return m_buffer[0];
    }

    // Check if the given element is contained in the array.
    template <typename T>
    NV_FORCEINLINE bool Array<T>::contains(const T & e) const
    {
        return find(e, NULL);
    }

    // Return true if element found.
    template <typename T>
    NV_FORCEINLINE bool Array<T>::find(const T & element, uint * indexPtr) const
    {
        return find(element, 0, m_size, indexPtr);
    }

    // Return true if element found within the given range.
    template <typename T>
    NV_FORCEINLINE bool Array<T>::find(const T & element, uint begin, uint end, uint * indexPtr) const
    {
        return ::nv::find(element, m_buffer, begin, end, indexPtr);
    }

    // Remove the element at the given index. This is an expensive operation!
    template <typename T>
    void Array<T>::removeAt(uint index)
    {
        nvDebugCheck(index >= 0 && index < m_size);

        if (m_size == 1) {
            clear();
        }
        else {
            m_buffer[index].~T();

            memmove(m_buffer+index, m_buffer+index+1, sizeof(T) * (m_size - 1 - index));
            m_size--;
        }
    }

    // Remove the first instance of the given element.
    template <typename T>
    bool Array<T>::remove(const T & element)
    {
        uint index;
        if (find(element, &index)) {
            removeAt(index);
            return true;
        }
        return false;
    }

    // Insert the given element at the given index shifting all the elements up.
    template <typename T>
    void Array<T>::insertAt(uint index, const T & val/*=T()*/)
    {
        nvDebugCheck( index >= 0 && index <= m_size );

        setArraySize(m_size + 1);

        if (index < m_size - 1) {
            memmove(m_buffer+index+1, m_buffer+index, sizeof(T) * (m_size - 1 - index));
        }

        // Copy-construct into the newly opened slot.
        new(m_buffer+index) T(val);
    }

    // Append the given data to our vector.
    template <typename T>
    NV_FORCEINLINE void Array<T>::append(const Array<T> & other)
    {
        append(other.m_buffer, other.m_size);
    }

    // Append the given data to our vector.
    template <typename T>
    void Array<T>::append(const T other[], uint count)
    {
        if (count > 0) {
            const uint old_size = m_size;

            setArraySize(m_size + count);

            for (uint i = 0; i < count; i++ ) {
                new(m_buffer + old_size + i) T(other[i]);
            }
        }
    }

    // Remove the given element by replacing it with the last one.
    template <typename T>
    void Array<T>::replaceWithLast(uint index)
    {
        nvDebugCheck( index < m_size );
        nv::swap(m_buffer[index], back());
        (m_buffer+m_size-1)->~T();
        m_size--;
    }

    // Resize the vector preserving existing elements.
    template <typename T>
    void Array<T>::resize(uint new_size)
    {
        uint old_size = m_size;

        // Destruct old elements (if we're shrinking).
        destroy_range(m_buffer, new_size, old_size);

        setArraySize(new_size);

        // Call default constructors
        construct_range(m_buffer, new_size, old_size);
    }

    // Resize the vector preserving existing elements and initializing the
    // new ones with the given value.
    template <typename T>
    void Array<T>::resize(uint new_size, const T & elem)
    {
        nvDebugCheck(&elem < m_buffer || &elem > m_buffer+m_size);

        uint old_size = m_size;

        // Destruct old elements (if we're shrinking).
        destroy_range(m_buffer, new_size, old_size);

        setArraySize(new_size);

        // Call copy constructors
        construct_range(m_buffer, new_size, old_size, elem);
    }

    // Fill array with the given value.
    template <typename T>
    void Array<T>::fill(const T & elem)
    {
        fill(m_buffer, m_size, elem);
    }

    // Clear the buffer.
    template <typename T>
    NV_FORCEINLINE void Array<T>::clear()
    {
        nvDebugCheck(isValidPtr(m_buffer));

        // Destruct old elements
        destroy_range(m_buffer, 0, m_size);

        m_size = 0;
    }

    // Shrink the allocated vector.
    template <typename T>
    NV_FORCEINLINE void Array<T>::shrink()
    {
        if (m_size < m_capacity) {
            setArrayCapacity(m_size);
        }
    }

    // Preallocate space.
    template <typename T>
    NV_FORCEINLINE void Array<T>::reserve(uint desired_size)
    {
        if (desired_size > m_capacity) {
            setArrayCapacity(desired_size);
        }
    }

    // Copy elements to this array. Resizes it if needed.
    template <typename T>
    NV_FORCEINLINE void Array<T>::copy(const T * data, uint count)
    {
#if 1   // More simple, but maybe not be as efficient?
        destroy_range(m_buffer, 0, m_size);

        setArraySize(count);

        construct_range(m_buffer, count, 0, data);
#else
        const uint old_size = m_size;

        destroy_range(m_buffer, count, old_size);

        setArraySize(count);

        copy_range(m_buffer, data, old_size);

        construct_range(m_buffer, count, old_size, data);
#endif
    }

    // Assignment operator.
    template <typename T>
    NV_FORCEINLINE Array<T> & Array<T>::operator=( const Array<T> & a )
    {
        copy(a.m_buffer, a.m_size);
        return *this;
    }

    // Release ownership of allocated memory and returns pointer to it.
    template <typename T>
    T * Array<T>::release() {
        T * tmp = m_buffer;
        m_buffer = NULL;
        m_capacity = 0;
        m_size = 0;
        return tmp;
    }

    // Change array size.
    template <typename T>
    inline void Array<T>::setArraySize(uint new_size) {
        m_size = new_size;

        if (new_size > m_capacity) {
            uint new_buffer_size;
            if (m_capacity == 0) {
                // first allocation is exact
                new_buffer_size = new_size;
            }
            else {
                // following allocations grow array by 25%
                new_buffer_size = new_size + (new_size >> 2);
            }

            setArrayCapacity( new_buffer_size );
        }
    }

    // Change array capacity.
    template <typename T>
    inline void Array<T>::setArrayCapacity(uint new_capacity) {
        nvDebugCheck(new_capacity >= m_size);

        if (new_capacity == 0) {
            // free the buffer.
            if (m_buffer != NULL) {
                free<T>(m_buffer);
                m_buffer = NULL;
            }
        }
        else {
            // realloc the buffer
            m_buffer = realloc<T>(m_buffer, new_capacity);
        }

        m_capacity = new_capacity;
    }

    // Array serialization.
    template <typename Typ>
    inline Stream & operator<< ( Stream & s, Array<Typ> & p )
    {
        if (s.isLoading()) {
            uint size;
            s << size;
            p.resize( size );
        }
        else {
            s << p.m_size;
        }

        for (uint i = 0; i < p.m_size; i++) {
            s << p.m_buffer[i];
        }

        return s;
    }

    // Swap the members of the two given vectors.
    template <typename Typ>
    inline void swap(Array<Typ> & a, Array<Typ> & b)
    {
        nv::swap(a.m_buffer, b.m_buffer);
        nv::swap(a.m_capacity, b.m_capacity);
        nv::swap(a.m_size, b.m_size);
    }

} // nv namespace

#endif // NV_CORE_ARRAY_INL
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2011, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

#include <urbi/object/vector.hh>
#include <urbi/object/matrix.hh>
#include <kernel/uvalue-cast.hh>
#include <urbi/uvalue.hh>
#include <boost/numeric/ublas/lu.hpp> // boost::numeric::ublas::row

namespace urbi
{
  namespace object
  {

    /*---------.
    | Vector.  |
    `---------*/

    Vector::Vector()
    {
      proto_add(proto);
    }

    Vector::Vector(const rVector& model)
      : value_(model->value_)
    {
      proto_add(proto);
    }

    Vector::Vector(const value_type& model)
      : value_(model)
    {
      proto_add(proto);
    }

    Vector::Vector(const objects_type& model)
      : value_(model.size())
    {
      proto_add(proto);
      fromList(model);
    }

    Vector::Vector(size_t s)
      : value_(s)
    {
      proto_add(proto);
    }

    rVector
    Vector::init(const objects_type& args)
    {
      rVector self = args[0]->as<Vector>();
      if (!self)
        runner::raise_type_error(args[1], Vector::proto);
      if (args.size() == 2)
      {
        if (rList l = args[1]->as<List>())
          return self->fromList(l->value_get());
        else if (rVector v = args[1]->as<Vector>())
        {
          self->value_ = v->value_;
          return self;
        }
      }
      self->value_.resize(args.size() - 1);
      for (unsigned i = 1; i < args.size(); ++i)
        self->value_(i-1) = from_urbi<ufloat>(args[i]);
      return self;
    }

    Vector*
    Vector::fromList(const objects_type& model)
    {
      size_t size = model.size();
      value_.resize(size);
      for (unsigned i = 0; i < size; ++i)
        value_(i) = from_urbi<ufloat>(model[i]);
      return this;
    }

    URBI_CXX_OBJECT_INIT(Vector)
    {
      BIND(PLUS, operator+, Vector*, ());
      BIND(PLUS, operator+, value_type, (const rObject&) const);
      /* Something is wrong with the handling of these two overloads.
       * so use a disambiguator.
      BIND(PLUS, operator+, value_type, (const value_type&));
      BIND(PLUS, operator+, value_type, (ufloat));
           */
      BIND(MINUS, operator-, value_type, ());
      BIND(MINUS, operator-, value_type, (const rObject&) const);
      /*
      BIND(MINUS, operator-, value_type, (const value_type&));
      BIND(MINUS, operator-, value_type, (ufloat));
      */
      BIND(STAR, operator*, value_type, (const rObject&) const);
      BIND(SLASH, operator/, value_type, (const rObject&) const);

      BIND(EQ_EQ, operator==, bool, (const rObject&) const);
      BIND(LT, operator<, bool, (const Object&) const);

      BIND(SBL_SBR, operator[]);
      BIND(SBL_SBR_EQ, set);
      BIND(asString, as_string);
      BIND(combAdd);
      BIND(combDiv);
      BIND(combMul);
      BIND(combSub);
      BIND(distance);
      BIND(norm);
      BIND(resize);
      BIND(scalarGE);
      BIND(scalarLE);
      BIND(set, fromList);
      BIND(size);
      BIND(sum);
      BIND(trueIndexes);
      BIND(uvalueSerialize);
      bind(libport::Symbol("scalar" "EQ"), &Vector::scalarEQ);
      bind(libport::Symbol("scalar" "GT"), &Vector::scalarGT);
      bind(libport::Symbol("scalar" "LT"), &Vector::scalarLT);
      slot_set(SYMBOL(init), new Primitive(&init));
    }

    std::string
    Vector::as_string() const
    {
      std::ostringstream s;
      s << '<';
      for (unsigned i = 0; i < size(); ++i)
      {
        if (i)
          s << ", ";
        s << value_(i);
      }
      s << '>';
      return s.str();
    }

    ufloat
    Vector::operator[](int i) const
    {
      return value_(index(i));
    }

    ufloat
    Vector::set(int i, ufloat v)
    {
      return value_(index(i)) = v;
    }

    size_t
    Vector::size() const
    {
      return value_.size();
    }

    ufloat
    Vector::norm() const
    {
      return norm_2(value_);
    }

    ufloat
    Vector::distance(const value_type& that) const
    {
      return norm_2(*this - that);
    }

    size_t
    Vector::index(int i) const
    {
      int res = i;
      if (res < 0)
        res += size();
      if (res < 0 || size() <= size_t(res))
        FRAISE("invalid index: %s", i);
      return res;
    }

#define OP(Name, Op)                                            \
    Vector::value_type                                          \
    Vector::Name(const value_type &b) const                     \
    {                                                           \
      size_t s1 = size();                                       \
      size_t s2 = b.size();                                     \
      if (s1 != s2)                                             \
        FRAISE("incompatible vector sizes: %s, %s", s1, s2);    \
      value_type res(s1);                                       \
      for (unsigned i = 0; i < s1; ++i)                         \
        res(i) = value_(i) Op b(i);                             \
      return res;                                               \
    }

    OP(scalarGT, >)
    OP(scalarLT, <)
    OP(scalarLE, <=)
    OP(scalarGE, >=)
    OP(scalarEQ, ==)
    OP(operator *, *)
    OP(operator /, /)
#undef OP

    Vector::value_type
    Vector::trueIndexes() const
    {
      unsigned count = 0;
      for (unsigned i = 0; i < size(); ++i)
        if (value_(i))
          ++count;
      value_type res(count);
      unsigned pos = 0;
      for (unsigned i = 0; i < size(); ++i)
        if (value_(i))
          res(pos++) = i;
      return res;
    }

#define OP(Name, Op)                                    \
    Vector::matrix_type                                 \
    Vector::comb ## Name(const value_type& b) const     \
    {                                                   \
      size_t s1 = size();                               \
      size_t s2 = b.size();                             \
      matrix_type res(s1, s2);                          \
      for (unsigned i = 0; i < s1; ++i)                 \
        for (unsigned j = 0; j < s2; ++j)               \
          res(i, j) = value_(i) Op b(j);                \
      return res;                                       \
    }

    OP(Add, +)
    OP(Div, /)
    OP(Mul, *)
    OP(Sub, -)
#undef OP

    Vector*
    Vector::resize(size_t s)
    {
      value_.resize(s);
      return this;
    }

#define OP(Op)                                                          \
    Vector::value_type                                                  \
    Vector::operator Op (const rObject& b) const                        \
    {                                                                   \
      if (rVector v = b->as<Vector>())                                  \
        return operator Op(v->value_get());                             \
      else                                                              \
        return operator Op(b->as_checked<Float>()->value_get());        \
    }

    OP(+)
    OP(-)
    OP(*)
    OP(/)
#undef OP

    ufloat
    Vector::sum() const
    {
      ufloat res = 0;
      for (unsigned i = 0; i < size(); ++i)
        res += value_(i);
      return res;
    }

    bool
    Vector::operator<(const value_type& b) const
    {
      for (size_t i = 0; i < std::min(size(), b.size()); ++i)
        if (value_(i) != b(i))
          return value_(i) < b(i);
      return size() < b.size();
    }

    rObject
    Vector::uvalueSerialize() const
    {
      CAPTURE_GLOBAL(Binary);
      // This is ugly: we cannot go through object-cast as it would give us
      // back the vector. So make the Binary ourselve.
      rObject o(const_cast<Vector*>(this));
      urbi::UValue v = ::uvalue_cast(o);
      rObject res = new object::Object();
      res->proto_add(Binary);
      res->slot_set(SYMBOL(keywords),
                    new object::String(v.binary->getMessage()));
      res->slot_set(SYMBOL(data),
                    new object::String
                    (std::string(static_cast<char*>(v.binary->common.data),
				 v.binary->common.size)));
      return res;
    }
  }
}
<commit_msg>Comment changes.<commit_after>/*
 * Copyright (C) 2011, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

#include <urbi/object/vector.hh>
#include <urbi/object/matrix.hh>
#include <kernel/uvalue-cast.hh>
#include <urbi/uvalue.hh>
#include <boost/numeric/ublas/lu.hpp> // boost::numeric::ublas::row

namespace urbi
{
  namespace object
  {

    /*---------.
    | Vector.  |
    `---------*/

    Vector::Vector()
    {
      proto_add(proto);
    }

    Vector::Vector(const rVector& model)
      : value_(model->value_)
    {
      proto_add(proto);
    }

    Vector::Vector(const value_type& model)
      : value_(model)
    {
      proto_add(proto);
    }

    Vector::Vector(const objects_type& model)
      : value_(model.size())
    {
      proto_add(proto);
      fromList(model);
    }

    Vector::Vector(size_t s)
      : value_(s)
    {
      proto_add(proto);
    }

    rVector
    Vector::init(const objects_type& args)
    {
      rVector self = args[0]->as<Vector>();
      if (!self)
        runner::raise_type_error(args[1], Vector::proto);
      if (args.size() == 2)
      {
        if (rList l = args[1]->as<List>())
          return self->fromList(l->value_get());
        else if (rVector v = args[1]->as<Vector>())
        {
          self->value_ = v->value_;
          return self;
        }
      }
      self->value_.resize(args.size() - 1);
      for (unsigned i = 1; i < args.size(); ++i)
        self->value_(i-1) = from_urbi<ufloat>(args[i]);
      return self;
    }

    Vector*
    Vector::fromList(const objects_type& model)
    {
      size_t size = model.size();
      value_.resize(size);
      for (unsigned i = 0; i < size; ++i)
        value_(i) = from_urbi<ufloat>(model[i]);
      return this;
    }

    URBI_CXX_OBJECT_INIT(Vector)
    {
      BIND(PLUS, operator+, Vector*, ());
      BIND(PLUS, operator+, value_type, (const rObject&) const);
      /* Something is wrong with the handling of these two overloads.
       * so use a disambiguator.
      BIND(PLUS, operator+, value_type, (const value_type&));
      BIND(PLUS, operator+, value_type, (ufloat));
           */
      BIND(MINUS, operator-, value_type, ());
      BIND(MINUS, operator-, value_type, (const rObject&) const);
      /*
      BIND(MINUS, operator-, value_type, (const value_type&));
      BIND(MINUS, operator-, value_type, (ufloat));
      */
      BIND(STAR, operator*, value_type, (const rObject&) const);
      BIND(SLASH, operator/, value_type, (const rObject&) const);

      BIND(EQ_EQ, operator==, bool, (const rObject&) const);
      BIND(LT, operator<, bool, (const Object&) const);

      BIND(SBL_SBR, operator[]);
      BIND(SBL_SBR_EQ, set);
      BIND(asString, as_string);
      BIND(combAdd);
      BIND(combDiv);
      BIND(combMul);
      BIND(combSub);
      BIND(distance);
      BIND(norm);
      BIND(resize);
      BIND(scalarGE);
      BIND(scalarLE);
      BIND(set, fromList);
      BIND(size);
      BIND(sum);
      BIND(trueIndexes);
      BIND(uvalueSerialize);
      bind(libport::Symbol("scalar" "EQ"), &Vector::scalarEQ);
      bind(libport::Symbol("scalar" "GT"), &Vector::scalarGT);
      bind(libport::Symbol("scalar" "LT"), &Vector::scalarLT);
      slot_set(SYMBOL(init), new Primitive(&init));
    }

    std::string
    Vector::as_string() const
    {
      std::ostringstream s;
      s << '<';
      for (unsigned i = 0; i < size(); ++i)
      {
        if (i)
          s << ", ";
        s << value_(i);
      }
      s << '>';
      return s.str();
    }

    ufloat
    Vector::operator[](int i) const
    {
      return value_(index(i));
    }

    ufloat
    Vector::set(int i, ufloat v)
    {
      return value_(index(i)) = v;
    }

    size_t
    Vector::size() const
    {
      return value_.size();
    }

    ufloat
    Vector::norm() const
    {
      return norm_2(value_);
    }

    ufloat
    Vector::distance(const value_type& that) const
    {
      return norm_2(*this - that);
    }

    size_t
    Vector::index(int i) const
    {
      int res = i;
      if (res < 0)
        res += size();
      if (res < 0 || size() <= size_t(res))
        FRAISE("invalid index: %s", i);
      return res;
    }

#define OP(Name, Op)                                            \
    Vector::value_type                                          \
    Vector::Name(const value_type &b) const                     \
    {                                                           \
      size_t s1 = size();                                       \
      size_t s2 = b.size();                                     \
      if (s1 != s2)                                             \
        FRAISE("incompatible vector sizes: %s, %s", s1, s2);    \
      value_type res(s1);                                       \
      for (unsigned i = 0; i < s1; ++i)                         \
        res(i) = value_(i) Op b(i);                             \
      return res;                                               \
    }

    OP(scalarGT, >)
    OP(scalarLT, <)
    OP(scalarLE, <=)
    OP(scalarGE, >=)
    OP(scalarEQ, ==)
    OP(operator *, *)
    OP(operator /, /)
#undef OP

    Vector::value_type
    Vector::trueIndexes() const
    {
      unsigned count = 0;
      for (unsigned i = 0; i < size(); ++i)
        if (value_(i))
          ++count;
      value_type res(count);
      unsigned pos = 0;
      for (unsigned i = 0; i < size(); ++i)
        if (value_(i))
          res(pos++) = i;
      return res;
    }

#define OP(Name, Op)                                    \
    Vector::matrix_type                                 \
    Vector::comb ## Name(const value_type& b) const     \
    {                                                   \
      size_t s1 = size();                               \
      size_t s2 = b.size();                             \
      matrix_type res(s1, s2);                          \
      for (unsigned i = 0; i < s1; ++i)                 \
        for (unsigned j = 0; j < s2; ++j)               \
          res(i, j) = value_(i) Op b(j);                \
      return res;                                       \
    }

    OP(Add, +)
    OP(Div, /)
    OP(Mul, *)
    OP(Sub, -)
#undef OP

    Vector*
    Vector::resize(size_t s)
    {
      value_.resize(s);
      return this;
    }

#define OP(Op)                                                          \
    Vector::value_type                                                  \
    Vector::operator Op (const rObject& b) const                        \
    {                                                                   \
      if (rVector v = b->as<Vector>())                                  \
        return operator Op(v->value_get());                             \
      else                                                              \
        return operator Op(b->as_checked<Float>()->value_get());        \
    }

    OP(+)
    OP(-)
    OP(*)
    OP(/)
#undef OP

    ufloat
    Vector::sum() const
    {
      ufloat res = 0;
      for (unsigned i = 0; i < size(); ++i)
        res += value_(i);
      return res;
    }

    bool
    Vector::operator<(const value_type& b) const
    {
      for (size_t i = 0; i < std::min(size(), b.size()); ++i)
        if (value_(i) != b(i))
          return value_(i) < b(i);
      return size() < b.size();
    }

    rObject
    Vector::uvalueSerialize() const
    {
      CAPTURE_GLOBAL(Binary);
      // This is ugly: we cannot go through object-cast as it would give us
      // back the vector. So make the Binary ourselves.
      rObject o(const_cast<Vector*>(this));
      urbi::UValue v = ::uvalue_cast(o);
      rObject res = new object::Object();
      res->proto_add(Binary);
      res->slot_set(SYMBOL(keywords),
                    new object::String(v.binary->getMessage()));
      res->slot_set(SYMBOL(data),
                    new object::String
                    (std::string(static_cast<char*>(v.binary->common.data),
				 v.binary->common.size)));
      return res;
    }
  }
}
<|endoftext|>


<commit_before>#include <cstring>
#include <vector>
#include <string>
#include <fstream>
#include <cstdio>
#include <miopen/gcn_asm_utils.h>
#include <miopen/clhelper.hpp>
#include <miopen/kernel.hpp>
#include <miopen/errors.hpp>
#include <miopen/stringutils.hpp>
#ifndef _WIN32 //Linux or APPLE
#include <unistd.h>
#include <paths.h>
#include <sys/types.h>
#include <sys/wait.h>
#endif //WIN32

#ifndef _WIN32 //Linux or APPLE
class TempFile
{
public:
    TempFile(const std::string& path_template)
        : _path(GetTempDirectoryPath() + "/" + path_template + "-XXXXXX")
    {
        _fd = mkstemp(&_path[0]);
        if (_fd == -1) { MIOPEN_THROW("Error: TempFile: mkstemp()"); }
    }

    ~TempFile()
    {
        const int remove_rc = std::remove(_path.c_str());
        const int close_rc = close(_fd);
        if (remove_rc != 0 || close_rc != 0) {
#ifndef NDEBUG // Be quiet in release versions.
            std::fprintf(stderr, "Error: TempFile: On removal of '%s', remove_rc = %d, close_rc = %d.\n", _path.c_str(), remove_rc, close_rc);
#endif
        }
    }

    inline operator const std::string&() { return _path; }

private:
    std::string _path;
    int _fd;

    static
    const std::string GetTempDirectoryPath()
    {
        const auto path = getenv("TMPDIR");
        if (path != nullptr) {
            return path;
        }
#if defined(P_tmpdir)
        return P_tmpdir; // a string literal, if defined.
#elif defined(_PATH_TMP)
        return _PATH_TMP; // a string literal, if defined.
#else
        return "/tmp";
#endif
	}
};
#endif

namespace miopen {

static cl_program CreateProgram(cl_context ctx, const char* char_source, size_t size)
{
	cl_int status;
	auto result = clCreateProgramWithSource(ctx,
		1,
		&char_source,
		&size,
		&status);

	if (status != CL_SUCCESS) { MIOPEN_THROW_CL_STATUS(status, "Error Creating OpenCL Program (cl_program) in LoadProgram()"); }

	return result;
}

/*
 * Temporary function which emulates online assembly feature of OpenCL-on-ROCm being developed.
 * Not intended to be used in production code, so error handling is very straghtforward,
 * just catch whatever possible and throw an exception.
 */
static void ExperimentalAmdgcnAssemble(cl_device_id device, std::string& source, const std::string& params)
{
#ifndef _WIN32 //Linux or APPLE
	TempFile outfile("amdgcn-asm-out-XXXXXX");

	std::vector<std::string> args ({
		"-x",
		"assembler",
		"-target",
		"amdgcn--amdhsa",
	});

	{ 	// Add -mcpu=name as reported by OpenCL-on-ROCm runtime.
		char name[64] = {0};
		if (CL_SUCCESS != clGetDeviceInfo(device, CL_DEVICE_NAME, sizeof(name), name, nullptr)) {
			MIOPEN_THROW("Error: X-AMDGCN-ASM: clGetDeviceInfo()");
		}
		args.push_back("-mcpu=" + std::string(name));
	}

	{
		std::istringstream iss(params);
		std::string param;
		while (iss >> param) {
			args.push_back(param);
		};
	}
	args.push_back("-");
	args.push_back("-o");
	args.push_back(outfile);

	std::istringstream clang_stdin(source);
	const auto clang_rc = ExecuteGcnAssembler(args, &clang_stdin, nullptr);
	if (clang_rc != 0) MIOPEN_THROW("Assembly error(" + std::to_string(clang_rc) + ")");

	std::ifstream file(outfile, std::ios::binary | std::ios::ate);
	bool outfile_read_failed = false;
	do {
		const auto size = file.tellg();
		if (size == -1) { outfile_read_failed = true; break; }
		source.resize(size, '\0');
		file.seekg(std::ios::beg);
		if (file.fail()) { outfile_read_failed = true; break; }
		if (file.rdbuf()->sgetn(&source[0], size) != size) { outfile_read_failed = true; break; }
	} while (false);
	file.close();
	if (outfile_read_failed) {
		MIOPEN_THROW("Error: X-AMDGCN-ASM: outfile_read_failed");
	}
#else
	(void)device; // -warning
	(void)source; // -warning
	(void)params; // -warning
	MIOPEN_THROW("Error: X-AMDGCN-ASM: online assembly under Windows is not supported");
#endif //WIN32
}

static cl_program CreateProgramWithBinary(cl_context ctx, cl_device_id device, const char* char_source, size_t size)
{
	cl_int status, binaryStatus;
	auto result = clCreateProgramWithBinary(ctx,
		1,
		&device,
		reinterpret_cast<const size_t*>(&size),
		reinterpret_cast<const unsigned char**>(&char_source),
		&status,
		&binaryStatus);

	if (status != CL_SUCCESS) { MIOPEN_THROW_CL_STATUS(status, "Error creating code object program (cl_program) in LoadProgramFromBinary()"); }

	return result;
}

static void BuildProgram(cl_program program, cl_device_id device, const std::string& params = "")
{
	auto status = clBuildProgram(program,
		1, &device, params.c_str(),
		nullptr,
		nullptr);

	if (status != CL_SUCCESS)
	{
		std::string msg = "Error Building OpenCL Program in BuildProgram()\n";
		std::vector<char> errorbuf(1024 * 1024);
		size_t psize;
		clGetProgramBuildInfo(program,
			device,
			CL_PROGRAM_BUILD_LOG,
			1024 * 1024,
			errorbuf.data(),
			&psize);

		msg += errorbuf.data();
		if (status != CL_SUCCESS) { MIOPEN_THROW_CL_STATUS(status, msg); }
	}
}

ClProgramPtr LoadProgram(cl_context ctx, cl_device_id device, const std::string &program_name, std::string params, bool is_kernel_str)
{
	bool is_binary = false;
	std::string source;
	if (is_kernel_str) {
		source = program_name;
	} else {
		source = miopen::GetKernelSrc(program_name);
		auto is_asm = miopen::EndsWith(program_name, ".s");
		if (is_asm) { // Overwrites source (asm text) by binary results of assembly:
			ExperimentalAmdgcnAssemble(device, source, params);
			is_binary = true;
		} else {
			is_binary = miopen::EndsWith(program_name, ".so");
		}
	}

	cl_program result = nullptr;
	if (is_binary) {
		result = CreateProgramWithBinary(ctx, device, source.data(), source.size());
		BuildProgram(result, device);
	} else {
		result = CreateProgram(ctx, source.data(), source.size());
#if MIOPEN_BUILD_DEV && defined(__linux__)
		params += " -Werror";
#endif
		params += " -cl-std=CL1.2";
		std::cout << "BuildProgram: " << params << std::endl;
		BuildProgram(result, device, params);
	}
	return ClProgramPtr{ result };
}

ClKernelPtr CreateKernel(cl_program program, const std::string& kernel_name)
{
	cl_int status;
	ClKernelPtr result{clCreateKernel(program,
			kernel_name.c_str(),
			&status)};

	if (status != CL_SUCCESS) { MIOPEN_THROW_CL_STATUS(status); }

	return result;
}

cl_device_id GetDevice(cl_command_queue q)
{
	cl_device_id device;
	cl_int status = clGetCommandQueueInfo(q,
			CL_QUEUE_DEVICE,
			sizeof(cl_device_id),
			&device,
			nullptr);
	if (status != CL_SUCCESS) { MIOPEN_THROW_CL_STATUS(status, "Error Getting Device Info from Queue in GetDevice()"); }

	return device;
}

cl_context GetContext(cl_command_queue q)
{
	cl_context context;
	cl_int status = clGetCommandQueueInfo(q,
			CL_QUEUE_CONTEXT,
			sizeof(cl_context),
			&context,
			nullptr);
	if (status != CL_SUCCESS) { MIOPEN_THROW_CL_STATUS(status, "Error Getting Device Info from Queue in GetDevice()"); }
	return context;
}

ClAqPtr CreateQueueWithProfiling(cl_context ctx, cl_device_id dev)
{
	cl_int status;
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
	ClAqPtr q{clCreateCommandQueue(ctx, dev, CL_QUEUE_PROFILING_ENABLE, &status)};
#ifdef __clang__
#pragma clang diagnostic pop
#endif

	if(status != CL_SUCCESS) { MIOPEN_THROW_CL_STATUS(status); }

	return q;
}

} // namespace miopen
<commit_msg>Remove linux check<commit_after>#include <cstring>
#include <vector>
#include <string>
#include <fstream>
#include <cstdio>
#include <miopen/gcn_asm_utils.h>
#include <miopen/clhelper.hpp>
#include <miopen/kernel.hpp>
#include <miopen/errors.hpp>
#include <miopen/stringutils.hpp>
#ifndef _WIN32 //Linux or APPLE
#include <unistd.h>
#include <paths.h>
#include <sys/types.h>
#include <sys/wait.h>
#endif //WIN32

#ifndef _WIN32 //Linux or APPLE
class TempFile
{
public:
    TempFile(const std::string& path_template)
        : _path(GetTempDirectoryPath() + "/" + path_template + "-XXXXXX")
    {
        _fd = mkstemp(&_path[0]);
        if (_fd == -1) { MIOPEN_THROW("Error: TempFile: mkstemp()"); }
    }

    ~TempFile()
    {
        const int remove_rc = std::remove(_path.c_str());
        const int close_rc = close(_fd);
        if (remove_rc != 0 || close_rc != 0) {
#ifndef NDEBUG // Be quiet in release versions.
            std::fprintf(stderr, "Error: TempFile: On removal of '%s', remove_rc = %d, close_rc = %d.\n", _path.c_str(), remove_rc, close_rc);
#endif
        }
    }

    inline operator const std::string&() { return _path; }

private:
    std::string _path;
    int _fd;

    static
    const std::string GetTempDirectoryPath()
    {
        const auto path = getenv("TMPDIR");
        if (path != nullptr) {
            return path;
        }
#if defined(P_tmpdir)
        return P_tmpdir; // a string literal, if defined.
#elif defined(_PATH_TMP)
        return _PATH_TMP; // a string literal, if defined.
#else
        return "/tmp";
#endif
	}
};
#endif

namespace miopen {

static cl_program CreateProgram(cl_context ctx, const char* char_source, size_t size)
{
	cl_int status;
	auto result = clCreateProgramWithSource(ctx,
		1,
		&char_source,
		&size,
		&status);

	if (status != CL_SUCCESS) { MIOPEN_THROW_CL_STATUS(status, "Error Creating OpenCL Program (cl_program) in LoadProgram()"); }

	return result;
}

/*
 * Temporary function which emulates online assembly feature of OpenCL-on-ROCm being developed.
 * Not intended to be used in production code, so error handling is very straghtforward,
 * just catch whatever possible and throw an exception.
 */
static void ExperimentalAmdgcnAssemble(cl_device_id device, std::string& source, const std::string& params)
{
#ifndef _WIN32 //Linux or APPLE
	TempFile outfile("amdgcn-asm-out-XXXXXX");

	std::vector<std::string> args ({
		"-x",
		"assembler",
		"-target",
		"amdgcn--amdhsa",
	});

	{ 	// Add -mcpu=name as reported by OpenCL-on-ROCm runtime.
		char name[64] = {0};
		if (CL_SUCCESS != clGetDeviceInfo(device, CL_DEVICE_NAME, sizeof(name), name, nullptr)) {
			MIOPEN_THROW("Error: X-AMDGCN-ASM: clGetDeviceInfo()");
		}
		args.push_back("-mcpu=" + std::string(name));
	}

	{
		std::istringstream iss(params);
		std::string param;
		while (iss >> param) {
			args.push_back(param);
		};
	}
	args.push_back("-");
	args.push_back("-o");
	args.push_back(outfile);

	std::istringstream clang_stdin(source);
	const auto clang_rc = ExecuteGcnAssembler(args, &clang_stdin, nullptr);
	if (clang_rc != 0) MIOPEN_THROW("Assembly error(" + std::to_string(clang_rc) + ")");

	std::ifstream file(outfile, std::ios::binary | std::ios::ate);
	bool outfile_read_failed = false;
	do {
		const auto size = file.tellg();
		if (size == -1) { outfile_read_failed = true; break; }
		source.resize(size, '\0');
		file.seekg(std::ios::beg);
		if (file.fail()) { outfile_read_failed = true; break; }
		if (file.rdbuf()->sgetn(&source[0], size) != size) { outfile_read_failed = true; break; }
	} while (false);
	file.close();
	if (outfile_read_failed) {
		MIOPEN_THROW("Error: X-AMDGCN-ASM: outfile_read_failed");
	}
#else
	(void)device; // -warning
	(void)source; // -warning
	(void)params; // -warning
	MIOPEN_THROW("Error: X-AMDGCN-ASM: online assembly under Windows is not supported");
#endif //WIN32
}

static cl_program CreateProgramWithBinary(cl_context ctx, cl_device_id device, const char* char_source, size_t size)
{
	cl_int status, binaryStatus;
	auto result = clCreateProgramWithBinary(ctx,
		1,
		&device,
		reinterpret_cast<const size_t*>(&size),
		reinterpret_cast<const unsigned char**>(&char_source),
		&status,
		&binaryStatus);

	if (status != CL_SUCCESS) { MIOPEN_THROW_CL_STATUS(status, "Error creating code object program (cl_program) in LoadProgramFromBinary()"); }

	return result;
}

static void BuildProgram(cl_program program, cl_device_id device, const std::string& params = "")
{
	auto status = clBuildProgram(program,
		1, &device, params.c_str(),
		nullptr,
		nullptr);

	if (status != CL_SUCCESS)
	{
		std::string msg = "Error Building OpenCL Program in BuildProgram()\n";
		std::vector<char> errorbuf(1024 * 1024);
		size_t psize;
		clGetProgramBuildInfo(program,
			device,
			CL_PROGRAM_BUILD_LOG,
			1024 * 1024,
			errorbuf.data(),
			&psize);

		msg += errorbuf.data();
		if (status != CL_SUCCESS) { MIOPEN_THROW_CL_STATUS(status, msg); }
	}
}

ClProgramPtr LoadProgram(cl_context ctx, cl_device_id device, const std::string &program_name, std::string params, bool is_kernel_str)
{
	bool is_binary = false;
	std::string source;
	if (is_kernel_str) {
		source = program_name;
	} else {
		source = miopen::GetKernelSrc(program_name);
		auto is_asm = miopen::EndsWith(program_name, ".s");
		if (is_asm) { // Overwrites source (asm text) by binary results of assembly:
			ExperimentalAmdgcnAssemble(device, source, params);
			is_binary = true;
		} else {
			is_binary = miopen::EndsWith(program_name, ".so");
		}
	}

	cl_program result = nullptr;
	if (is_binary) {
		result = CreateProgramWithBinary(ctx, device, source.data(), source.size());
		BuildProgram(result, device);
	} else {
		result = CreateProgram(ctx, source.data(), source.size());
#if MIOPEN_BUILD_DEV
		params += " -Werror";
#endif
		params += " -cl-std=CL1.2";
		std::cout << "BuildProgram: " << params << std::endl;
		BuildProgram(result, device, params);
	}
	return ClProgramPtr{ result };
}

ClKernelPtr CreateKernel(cl_program program, const std::string& kernel_name)
{
	cl_int status;
	ClKernelPtr result{clCreateKernel(program,
			kernel_name.c_str(),
			&status)};

	if (status != CL_SUCCESS) { MIOPEN_THROW_CL_STATUS(status); }

	return result;
}

cl_device_id GetDevice(cl_command_queue q)
{
	cl_device_id device;
	cl_int status = clGetCommandQueueInfo(q,
			CL_QUEUE_DEVICE,
			sizeof(cl_device_id),
			&device,
			nullptr);
	if (status != CL_SUCCESS) { MIOPEN_THROW_CL_STATUS(status, "Error Getting Device Info from Queue in GetDevice()"); }

	return device;
}

cl_context GetContext(cl_command_queue q)
{
	cl_context context;
	cl_int status = clGetCommandQueueInfo(q,
			CL_QUEUE_CONTEXT,
			sizeof(cl_context),
			&context,
			nullptr);
	if (status != CL_SUCCESS) { MIOPEN_THROW_CL_STATUS(status, "Error Getting Device Info from Queue in GetDevice()"); }
	return context;
}

ClAqPtr CreateQueueWithProfiling(cl_context ctx, cl_device_id dev)
{
	cl_int status;
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
	ClAqPtr q{clCreateCommandQueue(ctx, dev, CL_QUEUE_PROFILING_ENABLE, &status)};
#ifdef __clang__
#pragma clang diagnostic pop
#endif

	if(status != CL_SUCCESS) { MIOPEN_THROW_CL_STATUS(status); }

	return q;
}

} // namespace miopen
<|endoftext|>


<commit_before>//===--- Sema.cpp - AST Builder and Semantic Analysis Implementation ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the actions class which performs semantic analysis and
// builds an AST out of a parse stream.
//
//===----------------------------------------------------------------------===//

#include "Sema.h"
#include "clang/AST/ASTContext.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Parse/Scope.h"

using namespace clang;

bool Sema::isBuiltinObjCType(TypedefDecl *TD) {
  const char *typeName = TD->getIdentifier()->getName();
  return strcmp(typeName, "id") == 0 || strcmp(typeName, "Class") == 0 ||
         strcmp(typeName, "SEL") == 0 || strcmp(typeName, "Protocol") == 0;
}

bool Sema::isObjCObjectPointerType(QualType type) const {
  if (!type->isPointerType() && !type->isObjCQualifiedIdType())
    return false;
  if (type == Context.getObjCIdType() || type == Context.getObjCClassType() ||
      type->isObjCQualifiedIdType())
    return true;

  if (type->isPointerType()) {
    PointerType *pointerType = static_cast<PointerType*>(type.getTypePtr());
    type = pointerType->getPointeeType();
  }
  return (type->isObjCInterfaceType() || type->isObjCQualifiedIdType());
}

void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
  TUScope = S;
  CurContext = Context.getTranslationUnitDecl();
  if (!PP.getLangOptions().ObjC1) return;

  TypedefType *t;

  // Add the built-in ObjC types.
  t = cast<TypedefType>(Context.getObjCIdType().getTypePtr());
  PushOnScopeChains(t->getDecl(), TUScope);
  t = cast<TypedefType>(Context.getObjCClassType().getTypePtr());
  PushOnScopeChains(t->getDecl(), TUScope);
  ObjCInterfaceType *it = cast<ObjCInterfaceType>(Context.getObjCProtoType());
  ObjCInterfaceDecl *IDecl = it->getDecl();
  PushOnScopeChains(IDecl, TUScope);

  // Synthesize "typedef struct objc_selector *SEL;"
  RecordDecl *SelTag = RecordDecl::Create(Context, Decl::Struct, CurContext,
                                          SourceLocation(),
                                          &Context.Idents.get("objc_selector"),
                                          0);
  PushOnScopeChains(SelTag, TUScope);

  QualType SelT = Context.getPointerType(Context.getTagDeclType(SelTag));
  TypedefDecl *SelTypedef = TypedefDecl::Create(Context, CurContext,
                                                SourceLocation(),
                                                &Context.Idents.get("SEL"),
                                                SelT, 0);
  PushOnScopeChains(SelTypedef, TUScope);
  Context.setObjCSelType(SelTypedef);
}

Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer)
  : PP(pp), Context(ctxt), Consumer(consumer),
    CurFunctionDecl(0), CurMethodDecl(0), CurContext(0) {

  // Get IdentifierInfo objects for known functions for which we
  // do extra checking.
  IdentifierTable &IT = PP.getIdentifierTable();

  KnownFunctionIDs[id_printf]    = &IT.get("printf");
  KnownFunctionIDs[id_fprintf]   = &IT.get("fprintf");
  KnownFunctionIDs[id_sprintf]   = &IT.get("sprintf");
  KnownFunctionIDs[id_snprintf]  = &IT.get("snprintf");
  KnownFunctionIDs[id_asprintf]  = &IT.get("asprintf");
  KnownFunctionIDs[id_vsnprintf] = &IT.get("vsnprintf");
  KnownFunctionIDs[id_vasprintf] = &IT.get("vasprintf");
  KnownFunctionIDs[id_vfprintf]  = &IT.get("vfprintf");
  KnownFunctionIDs[id_vsprintf]  = &IT.get("vsprintf");
  KnownFunctionIDs[id_vprintf]   = &IT.get("vprintf");

  // FIXME: Move this initialization up to Sema::ActOnTranslationUnitScope()
  // and make sure the decls get inserted into TUScope!
  // FIXME: And make sure they don't leak!
  if (PP.getLangOptions().ObjC1) {
    TranslationUnitDecl *TUDecl = Context.getTranslationUnitDecl();

    // Synthesize "typedef struct objc_class *Class;"
    RecordDecl *ClassTag = RecordDecl::Create(Context, Decl::Struct,
                                              TUDecl,
                                              SourceLocation(),
                                              &IT.get("objc_class"), 0);
    QualType ClassT = Context.getPointerType(Context.getTagDeclType(ClassTag));
    TypedefDecl *ClassTypedef =
      TypedefDecl::Create(Context, TUDecl, SourceLocation(),
                          &Context.Idents.get("Class"), ClassT, 0);
    Context.setObjCClassType(ClassTypedef);

    // Synthesize "@class Protocol;
    ObjCInterfaceDecl *ProtocolDecl =
      ObjCInterfaceDecl::Create(Context, SourceLocation(), 0,
                                &Context.Idents.get("Protocol"),
                                SourceLocation(), true);
    Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl));

    // Synthesize "typedef struct objc_object { Class isa; } *id;"
    RecordDecl *ObjectTag =
      RecordDecl::Create(Context, Decl::Struct, TUDecl,
                         SourceLocation(),
                         &IT.get("objc_object"), 0);
    FieldDecl *IsaDecl = FieldDecl::Create(Context, SourceLocation(), 0,
                                           Context.getObjCClassType());
    ObjectTag->defineBody(&IsaDecl, 1);
    QualType ObjT = Context.getPointerType(Context.getTagDeclType(ObjectTag));
    TypedefDecl *IdTypedef = TypedefDecl::Create(Context, TUDecl,
                                                 SourceLocation(),
                                                 &Context.Idents.get("id"),
                                                 ObjT, 0);
    Context.setObjCIdType(IdTypedef);
  }
  TUScope = 0;
}

/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
/// If there is already an implicit cast, merge into the existing one.
void Sema::ImpCastExprToType(Expr *&Expr, QualType Type) {
  if (Expr->getType().getCanonicalType() == Type.getCanonicalType()) return;

  if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr))
    ImpCast->setType(Type);
  else
    Expr = new ImplicitCastExpr(Type, Expr);
}

void Sema::DeleteExpr(ExprTy *E) {
  delete static_cast<Expr*>(E);
}
void Sema::DeleteStmt(StmtTy *S) {
  delete static_cast<Stmt*>(S);
}

//===----------------------------------------------------------------------===//
// Helper functions.
//===----------------------------------------------------------------------===//

bool Sema::Diag(SourceLocation Loc, unsigned DiagID) {
  PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID);
  return true;
}

bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg) {
  PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID,  &Msg, 1);
  return true;
}

bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1,
                const std::string &Msg2) {
  std::string MsgArr[] = { Msg1, Msg2 };
  PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID,  MsgArr, 2);
  return true;
}

bool Sema::Diag(SourceLocation Loc, unsigned DiagID, SourceRange Range) {
  PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, 0, 0, &Range,1);
  return true;
}

bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg,
                SourceRange Range) {
  PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, &Msg, 1, &Range,1);
  return true;
}

bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1,
                const std::string &Msg2, SourceRange Range) {
  std::string MsgArr[] = { Msg1, Msg2 };
  PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, MsgArr, 2, &Range, 1);
  return true;
}

bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1,
                const std::string &Msg2, const std::string &Msg3,
                SourceRange R1) {
  std::string MsgArr[] = { Msg1, Msg2, Msg3 };
  PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, MsgArr, 3, &R1, 1);
  return true;
}

bool Sema::Diag(SourceLocation Loc, unsigned DiagID,
                SourceRange R1, SourceRange R2) {
  SourceRange RangeArr[] = { R1, R2 };
  PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, 0, 0, RangeArr, 2);
  return true;
}

bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg,
                SourceRange R1, SourceRange R2) {
  SourceRange RangeArr[] = { R1, R2 };
  PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID,  &Msg, 1, RangeArr, 2);
  return true;
}

bool Sema::Diag(SourceLocation Range, unsigned DiagID, const std::string &Msg1,
                const std::string &Msg2, SourceRange R1, SourceRange R2) {
  std::string MsgArr[] = { Msg1, Msg2 };
  SourceRange RangeArr[] = { R1, R2 };
  PP.getDiagnostics().Report(PP.getFullLoc(Range),DiagID, MsgArr,2,RangeArr, 2);
  return true;
}

const LangOptions &Sema::getLangOptions() const {
  return PP.getLangOptions();
}
<commit_msg>Give the "isa" slot a name!<commit_after>//===--- Sema.cpp - AST Builder and Semantic Analysis Implementation ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the actions class which performs semantic analysis and
// builds an AST out of a parse stream.
//
//===----------------------------------------------------------------------===//

#include "Sema.h"
#include "clang/AST/ASTContext.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Parse/Scope.h"

using namespace clang;

bool Sema::isBuiltinObjCType(TypedefDecl *TD) {
  const char *typeName = TD->getIdentifier()->getName();
  return strcmp(typeName, "id") == 0 || strcmp(typeName, "Class") == 0 ||
         strcmp(typeName, "SEL") == 0 || strcmp(typeName, "Protocol") == 0;
}

bool Sema::isObjCObjectPointerType(QualType type) const {
  if (!type->isPointerType() && !type->isObjCQualifiedIdType())
    return false;
  if (type == Context.getObjCIdType() || type == Context.getObjCClassType() ||
      type->isObjCQualifiedIdType())
    return true;

  if (type->isPointerType()) {
    PointerType *pointerType = static_cast<PointerType*>(type.getTypePtr());
    type = pointerType->getPointeeType();
  }
  return (type->isObjCInterfaceType() || type->isObjCQualifiedIdType());
}

void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
  TUScope = S;
  CurContext = Context.getTranslationUnitDecl();
  if (!PP.getLangOptions().ObjC1) return;

  TypedefType *t;

  // Add the built-in ObjC types.
  t = cast<TypedefType>(Context.getObjCIdType().getTypePtr());
  PushOnScopeChains(t->getDecl(), TUScope);
  t = cast<TypedefType>(Context.getObjCClassType().getTypePtr());
  PushOnScopeChains(t->getDecl(), TUScope);
  ObjCInterfaceType *it = cast<ObjCInterfaceType>(Context.getObjCProtoType());
  ObjCInterfaceDecl *IDecl = it->getDecl();
  PushOnScopeChains(IDecl, TUScope);

  // Synthesize "typedef struct objc_selector *SEL;"
  RecordDecl *SelTag = RecordDecl::Create(Context, Decl::Struct, CurContext,
                                          SourceLocation(),
                                          &Context.Idents.get("objc_selector"),
                                          0);
  PushOnScopeChains(SelTag, TUScope);

  QualType SelT = Context.getPointerType(Context.getTagDeclType(SelTag));
  TypedefDecl *SelTypedef = TypedefDecl::Create(Context, CurContext,
                                                SourceLocation(),
                                                &Context.Idents.get("SEL"),
                                                SelT, 0);
  PushOnScopeChains(SelTypedef, TUScope);
  Context.setObjCSelType(SelTypedef);
}

Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer)
  : PP(pp), Context(ctxt), Consumer(consumer),
    CurFunctionDecl(0), CurMethodDecl(0), CurContext(0) {

  // Get IdentifierInfo objects for known functions for which we
  // do extra checking.
  IdentifierTable &IT = PP.getIdentifierTable();

  KnownFunctionIDs[id_printf]    = &IT.get("printf");
  KnownFunctionIDs[id_fprintf]   = &IT.get("fprintf");
  KnownFunctionIDs[id_sprintf]   = &IT.get("sprintf");
  KnownFunctionIDs[id_snprintf]  = &IT.get("snprintf");
  KnownFunctionIDs[id_asprintf]  = &IT.get("asprintf");
  KnownFunctionIDs[id_vsnprintf] = &IT.get("vsnprintf");
  KnownFunctionIDs[id_vasprintf] = &IT.get("vasprintf");
  KnownFunctionIDs[id_vfprintf]  = &IT.get("vfprintf");
  KnownFunctionIDs[id_vsprintf]  = &IT.get("vsprintf");
  KnownFunctionIDs[id_vprintf]   = &IT.get("vprintf");

  // FIXME: Move this initialization up to Sema::ActOnTranslationUnitScope()
  // and make sure the decls get inserted into TUScope!
  // FIXME: And make sure they don't leak!
  if (PP.getLangOptions().ObjC1) {
    TranslationUnitDecl *TUDecl = Context.getTranslationUnitDecl();

    // Synthesize "typedef struct objc_class *Class;"
    RecordDecl *ClassTag = RecordDecl::Create(Context, Decl::Struct,
                                              TUDecl,
                                              SourceLocation(),
                                              &IT.get("objc_class"), 0);
    QualType ClassT = Context.getPointerType(Context.getTagDeclType(ClassTag));
    TypedefDecl *ClassTypedef =
      TypedefDecl::Create(Context, TUDecl, SourceLocation(),
                          &Context.Idents.get("Class"), ClassT, 0);
    Context.setObjCClassType(ClassTypedef);

    // Synthesize "@class Protocol;
    ObjCInterfaceDecl *ProtocolDecl =
      ObjCInterfaceDecl::Create(Context, SourceLocation(), 0,
                                &Context.Idents.get("Protocol"),
                                SourceLocation(), true);
    Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl));

    // Synthesize "typedef struct objc_object { Class isa; } *id;"
    RecordDecl *ObjectTag =
      RecordDecl::Create(Context, Decl::Struct, TUDecl,
                         SourceLocation(),
                         &IT.get("objc_object"), 0);
    FieldDecl *IsaDecl = FieldDecl::Create(Context, SourceLocation(),
                                           &Context.Idents.get("isa"),
                                           Context.getObjCClassType());
    ObjectTag->defineBody(&IsaDecl, 1);
    QualType ObjT = Context.getPointerType(Context.getTagDeclType(ObjectTag));
    TypedefDecl *IdTypedef = TypedefDecl::Create(Context, TUDecl,
                                                 SourceLocation(),
                                                 &Context.Idents.get("id"),
                                                 ObjT, 0);
    Context.setObjCIdType(IdTypedef);
  }
  TUScope = 0;
}

/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
/// If there is already an implicit cast, merge into the existing one.
void Sema::ImpCastExprToType(Expr *&Expr, QualType Type) {
  if (Expr->getType().getCanonicalType() == Type.getCanonicalType()) return;

  if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr))
    ImpCast->setType(Type);
  else
    Expr = new ImplicitCastExpr(Type, Expr);
}

void Sema::DeleteExpr(ExprTy *E) {
  delete static_cast<Expr*>(E);
}
void Sema::DeleteStmt(StmtTy *S) {
  delete static_cast<Stmt*>(S);
}

//===----------------------------------------------------------------------===//
// Helper functions.
//===----------------------------------------------------------------------===//

bool Sema::Diag(SourceLocation Loc, unsigned DiagID) {
  PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID);
  return true;
}

bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg) {
  PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID,  &Msg, 1);
  return true;
}

bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1,
                const std::string &Msg2) {
  std::string MsgArr[] = { Msg1, Msg2 };
  PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID,  MsgArr, 2);
  return true;
}

bool Sema::Diag(SourceLocation Loc, unsigned DiagID, SourceRange Range) {
  PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, 0, 0, &Range,1);
  return true;
}

bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg,
                SourceRange Range) {
  PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, &Msg, 1, &Range,1);
  return true;
}

bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1,
                const std::string &Msg2, SourceRange Range) {
  std::string MsgArr[] = { Msg1, Msg2 };
  PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, MsgArr, 2, &Range, 1);
  return true;
}

bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1,
                const std::string &Msg2, const std::string &Msg3,
                SourceRange R1) {
  std::string MsgArr[] = { Msg1, Msg2, Msg3 };
  PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, MsgArr, 3, &R1, 1);
  return true;
}

bool Sema::Diag(SourceLocation Loc, unsigned DiagID,
                SourceRange R1, SourceRange R2) {
  SourceRange RangeArr[] = { R1, R2 };
  PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, 0, 0, RangeArr, 2);
  return true;
}

bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg,
                SourceRange R1, SourceRange R2) {
  SourceRange RangeArr[] = { R1, R2 };
  PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID,  &Msg, 1, RangeArr, 2);
  return true;
}

bool Sema::Diag(SourceLocation Range, unsigned DiagID, const std::string &Msg1,
                const std::string &Msg2, SourceRange R1, SourceRange R2) {
  std::string MsgArr[] = { Msg1, Msg2 };
  SourceRange RangeArr[] = { R1, R2 };
  PP.getDiagnostics().Report(PP.getFullLoc(Range),DiagID, MsgArr,2,RangeArr, 2);
  return true;
}

const LangOptions &Sema::getLangOptions() const {
  return PP.getLangOptions();
}
<|endoftext|>