<commit_before>/*
 *  Copyright 2008-2009 NVIDIA Corporation
 *
 *  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.
 */

/*! \file copy_device_to_device.h
 *  \brief Device implementations for copying on the device.
 */

#pragma once

#include <thrust/iterator/iterator_traits.h>

#include <thrust/distance.h>
#include <thrust/device_ptr.h>

#include <thrust/detail/device/trivial_copy.h>
#include <thrust/detail/raw_buffer.h>

namespace thrust
{

namespace detail
{

namespace device
{

template<typename InputIterator,
         typename OutputIterator>
  OutputIterator copy_host_to_device(InputIterator begin,
                                     InputIterator end,
                                     OutputIterator result,
                                     thrust::experimental::incrementable_traversal_tag,
                                     thrust::experimental::random_access_traversal_tag)
{
    //std::cerr << std::endl;
    //std::cerr << "general copy_host_to_device(): InputIterator: " << typeid(InputIterator).name() << std::endl;
    //std::cerr << "general copy_host_to_device(): OutputIterator: " << typeid(OutputIterator).name() << std::endl;

    // host container to device container
    typedef typename thrust::iterator_traits<InputIterator>::value_type InputType;

    typename thrust::iterator_traits<InputIterator>::difference_type n = thrust::distance(begin, end);

    // allocate temporary storage
    InputType *temp = reinterpret_cast<InputType*>(malloc(sizeof(InputType) * n));
    InputType *temp_end = thrust::copy(begin, end, temp);

    result = thrust::copy(temp, temp_end, result);

    free(temp);
    return result;
}

// host pointer to device pointer with trivial copy
template<typename InputIterator,
         typename OutputIterator>
  OutputIterator copy_host_to_device(InputIterator begin,
                                     InputIterator end,
                                     OutputIterator result,
                                     thrust::experimental::random_access_traversal_tag,
                                     thrust::experimental::random_access_traversal_tag,
                                     true_type)
{
  //std::cerr << std::endl;
  //std::cerr << "random access copy_host_to_device(): trivial" << std::endl;
  //std::cerr << "general copy_host_to_device(): InputIterator: " << typeid(InputIterator).name() << std::endl;
  //std::cerr << "general copy_host_to_device(): OutputIterator: " << typeid(OutputIterator).name() << std::endl;

  // how many elements to copy?
  typename thrust::iterator_traits<OutputIterator>::difference_type n = end - begin;

  // what is the output type?
  typedef typename thrust::iterator_traits<OutputIterator>::value_type OutputType;

  trivial_copy_host_to_device(raw_pointer_cast(&*result), raw_pointer_cast(&*begin),  n * sizeof(OutputType));

  return result + n;
}

namespace detail
{

// random access non-trivial host iterator to random access device iterator
template<typename InputIterator,
         typename OutputIterator>
  OutputIterator non_trivial_random_access_copy_host_to_device(InputIterator begin,
                                                               InputIterator end,
                                                               OutputIterator result,
                                                               false_type) // InputIterator is non-trivial
{
  // copy the input to a temporary host buffer of OutputType
  typedef typename thrust::experimental::iterator_value<OutputIterator>::type OutputType;

  typename thrust::experimental::iterator_difference<InputIterator>::type n = thrust::distance(begin,end);

  // allocate temporary storage
  raw_buffer<OutputType, experimental::space::host> temp(begin, end);

  result = thrust::copy(temp.begin(), temp.end(), result);

  return result;
}

template<typename InputIterator,
         typename OutputIterator>
  OutputIterator non_trivial_random_access_copy_host_to_device(InputIterator begin,
                                                               InputIterator end,
                                                               OutputIterator result,
                                                               true_type) // InputIterator is trivial
{
  // copy the input to a temporary device buffer of InputType
  typedef typename thrust::experimental::iterator_value<InputIterator>::type InputType;

  typename thrust::experimental::iterator_difference<InputIterator>::type n = thrust::distance(begin,end);

  // allocate temporary storage
  raw_buffer<InputType, experimental::space::device> temp(n);

  // force a trivial copy
  thrust::detail::device::trivial_copy_host_to_device(raw_pointer_cast(&*temp.begin()), raw_pointer_cast(&*begin), n * sizeof(InputType));

  result = thrust::copy(temp.begin(), temp.end(), result);

  return result;
}

} // end detail

// random access host iterator to random access device iterator with non-trivial copy
template<typename InputIterator,
         typename OutputIterator>
  OutputIterator copy_host_to_device(InputIterator begin,
                                     InputIterator end,
                                     OutputIterator result,
                                     thrust::experimental::random_access_traversal_tag,
                                     thrust::experimental::random_access_traversal_tag,
                                     false_type)
{
  //std::cerr << std::endl;
  //std::cerr << "random access copy_host_to_device(): non-trivial" << std::endl;
  //std::cerr << "general copy_host_to_device(): InputIterator: " << typeid(InputIterator).name() << std::endl;
  //std::cerr << "general copy_host_to_device(): OutputIterator: " << typeid(OutputIterator).name() << std::endl;

  // dispatch a non-trivial random access host to device copy based on whether or not the InputIterator is trivial
  return detail::non_trivial_random_access_copy_host_to_device(begin, end, result,
      typename thrust::detail::is_trivial_iterator<InputIterator>::type());
}

// random access host iterator to random access device iterator
template<typename InputIterator,
         typename OutputIterator>
  OutputIterator copy_host_to_device(InputIterator begin,
                                     InputIterator end,
                                     OutputIterator result,
                                     thrust::experimental::random_access_traversal_tag input_traversal,
                                     thrust::experimental::random_access_traversal_tag output_traversal)
{
    // dispatch on whether this is a trivial copy
    return copy_host_to_device(begin, end, result, input_traversal, output_traversal,
            typename is_trivial_copy<InputIterator,OutputIterator>::type());
}

/////////////////
// Entry Point //
/////////////////

template<typename InputIterator,
         typename OutputIterator>
  OutputIterator copy_host_to_device(InputIterator begin,
                                     InputIterator end,
                                     OutputIterator result)
{
    return copy_host_to_device(begin, end, result,
            typename thrust::experimental::iterator_traversal<InputIterator>::type(),
            typename thrust::experimental::iterator_traversal<OutputIterator>::type());
}

} // end namespace device

} // end namespace detail

} // end namespace thrust

<commit_msg>Use raw_buffer in copy_host_to_device.<commit_after>/*
 *  Copyright 2008-2009 NVIDIA Corporation
 *
 *  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.
 */

/*! \file copy_device_to_device.h
 *  \brief Device implementations for copying on the device.
 */

#pragma once

#include <thrust/iterator/iterator_traits.h>

#include <thrust/distance.h>
#include <thrust/device_ptr.h>

#include <thrust/detail/device/trivial_copy.h>
#include <thrust/detail/raw_buffer.h>

namespace thrust
{

namespace detail
{

namespace device
{

template<typename InputIterator,
         typename OutputIterator>
  OutputIterator copy_host_to_device(InputIterator begin,
                                     InputIterator end,
                                     OutputIterator result,
                                     thrust::experimental::incrementable_traversal_tag,
                                     thrust::experimental::random_access_traversal_tag)
{
    //std::cerr << std::endl;
    //std::cerr << "general copy_host_to_device(): InputIterator: " << typeid(InputIterator).name() << std::endl;
    //std::cerr << "general copy_host_to_device(): OutputIterator: " << typeid(OutputIterator).name() << std::endl;

    // host container to device container
    typedef typename thrust::iterator_traits<InputIterator>::value_type InputType;

    // allocate temporary storage
    raw_buffer<InputType, experimental::space::host> temp(begin,end);

    result = thrust::copy(temp.begin(), temp.end(), result);

    return result;
}

// host pointer to device pointer with trivial copy
template<typename InputIterator,
         typename OutputIterator>
  OutputIterator copy_host_to_device(InputIterator begin,
                                     InputIterator end,
                                     OutputIterator result,
                                     thrust::experimental::random_access_traversal_tag,
                                     thrust::experimental::random_access_traversal_tag,
                                     true_type)
{
  //std::cerr << std::endl;
  //std::cerr << "random access copy_host_to_device(): trivial" << std::endl;
  //std::cerr << "general copy_host_to_device(): InputIterator: " << typeid(InputIterator).name() << std::endl;
  //std::cerr << "general copy_host_to_device(): OutputIterator: " << typeid(OutputIterator).name() << std::endl;

  // how many elements to copy?
  typename thrust::iterator_traits<OutputIterator>::difference_type n = end - begin;

  // what is the output type?
  typedef typename thrust::iterator_traits<OutputIterator>::value_type OutputType;

  trivial_copy_host_to_device(raw_pointer_cast(&*result), raw_pointer_cast(&*begin),  n * sizeof(OutputType));

  return result + n;
}

namespace detail
{

// random access non-trivial host iterator to random access device iterator
template<typename InputIterator,
         typename OutputIterator>
  OutputIterator non_trivial_random_access_copy_host_to_device(InputIterator begin,
                                                               InputIterator end,
                                                               OutputIterator result,
                                                               false_type) // InputIterator is non-trivial
{
  // copy the input to a temporary host buffer of OutputType
  typedef typename thrust::experimental::iterator_value<OutputIterator>::type OutputType;

  typename thrust::experimental::iterator_difference<InputIterator>::type n = thrust::distance(begin,end);

  // allocate temporary storage
  raw_buffer<OutputType, experimental::space::host> temp(begin, end);

  result = thrust::copy(temp.begin(), temp.end(), result);

  return result;
}

template<typename InputIterator,
         typename OutputIterator>
  OutputIterator non_trivial_random_access_copy_host_to_device(InputIterator begin,
                                                               InputIterator end,
                                                               OutputIterator result,
                                                               true_type) // InputIterator is trivial
{
  // copy the input to a temporary device buffer of InputType
  typedef typename thrust::experimental::iterator_value<InputIterator>::type InputType;

  typename thrust::experimental::iterator_difference<InputIterator>::type n = thrust::distance(begin,end);

  // allocate temporary storage
  raw_buffer<InputType, experimental::space::device> temp(n);

  // force a trivial copy
  thrust::detail::device::trivial_copy_host_to_device(raw_pointer_cast(&*temp.begin()), raw_pointer_cast(&*begin), n * sizeof(InputType));

  result = thrust::copy(temp.begin(), temp.end(), result);

  return result;
}

} // end detail

// random access host iterator to random access device iterator with non-trivial copy
template<typename InputIterator,
         typename OutputIterator>
  OutputIterator copy_host_to_device(InputIterator begin,
                                     InputIterator end,
                                     OutputIterator result,
                                     thrust::experimental::random_access_traversal_tag,
                                     thrust::experimental::random_access_traversal_tag,
                                     false_type)
{
  //std::cerr << std::endl;
  //std::cerr << "random access copy_host_to_device(): non-trivial" << std::endl;
  //std::cerr << "general copy_host_to_device(): InputIterator: " << typeid(InputIterator).name() << std::endl;
  //std::cerr << "general copy_host_to_device(): OutputIterator: " << typeid(OutputIterator).name() << std::endl;

  // dispatch a non-trivial random access host to device copy based on whether or not the InputIterator is trivial
  return detail::non_trivial_random_access_copy_host_to_device(begin, end, result,
      typename thrust::detail::is_trivial_iterator<InputIterator>::type());
}

// random access host iterator to random access device iterator
template<typename InputIterator,
         typename OutputIterator>
  OutputIterator copy_host_to_device(InputIterator begin,
                                     InputIterator end,
                                     OutputIterator result,
                                     thrust::experimental::random_access_traversal_tag input_traversal,
                                     thrust::experimental::random_access_traversal_tag output_traversal)
{
    // dispatch on whether this is a trivial copy
    return copy_host_to_device(begin, end, result, input_traversal, output_traversal,
            typename is_trivial_copy<InputIterator,OutputIterator>::type());
}

/////////////////
// Entry Point //
/////////////////

template<typename InputIterator,
         typename OutputIterator>
  OutputIterator copy_host_to_device(InputIterator begin,
                                     InputIterator end,
                                     OutputIterator result)
{
    return copy_host_to_device(begin, end, result,
            typename thrust::experimental::iterator_traversal<InputIterator>::type(),
            typename thrust::experimental::iterator_traversal<OutputIterator>::type());
}

} // end namespace device

} // end namespace detail

} // end namespace thrust

<|endoftext|>


<commit_before>#include <map>
#include <string>
#include <peglib.h>

struct Environment;

struct Value
{
    enum Type { Undefined, Bool, Long, String, Array, Function };

    struct ArrayValue {
        std::vector<Value> values;
    };

    struct FunctionValue {
        std::vector<std::string>                                params;
        std::function<Value (std::shared_ptr<Environment> env)> eval;
    };

    explicit Value() : type(Undefined) {}
    explicit Value(bool b) : type(Bool), v(b) {}
    explicit Value(long l) : type(Long), v(l) {}
    explicit Value(std::string&& s) : type(String), v(s) {}
    explicit Value(ArrayValue&& a) : type(Array), v(a) {}
    explicit Value(FunctionValue&& f) : type(Function), v(f) {}

    Value(const Value&) = default;
    Value(Value&& rhs) : type(rhs.type), v(rhs.v) {}

    bool to_bool() const {
        switch (type) {
            case Bool: return v.get<bool>();
            case Long: return v.get<long>() != 0;
        }
        throw std::runtime_error("type error.");
    }

    long to_long() const {
        switch (type) {
            case Bool: return v.get<bool>();
            case Long: return v.get<long>();
        }
        throw std::runtime_error("type error.");
    }

    std::string to_string() const {
        switch (type) {
            case String: return v.get<std::string>();
        }
        throw std::runtime_error("type error.");
    }

    ArrayValue to_array() const {
        switch (type) {
            case Array: return v.get<ArrayValue>();
        }
        throw std::runtime_error("type error.");
    }

    FunctionValue to_function() const {
        switch (type) {
            case Function: return v.get<FunctionValue>();
        }
        throw std::runtime_error("type error.");
    }

    std::string str() const {
        switch (type) {
            case Undefined: return "undefined";
            case Bool:      return to_bool() ? "true" : "false";
            case Long:      return std::to_string(to_long()); break;
            case String:    return to_string();
            case Function:  return "[function]";
            case Array:     return "[array]";
            default: throw std::logic_error("invalid internal condition.");
        }
        // NOTREACHED
    }

    std::ostream& out(std::ostream& os) const {
        switch (type) {
            case Undefined: os << "undefined"; break;
            case Bool:      os << (to_bool() ? "true" : "false"); break;
            case Long:      os << to_long(); break;
            case String:    os << "'" << to_string() << "'"; break;
            case Function:  os << "[function]"; break;
            case Array:     os << "[array]"; break;
            default: throw std::logic_error("invalid internal condition.");
        }
        return os;
    }

    bool operator==(const Value& rhs) const {
        switch (type) {
            case Undefined: return true;
            case Bool:      return to_bool() == rhs.to_bool();
            case Long:      return to_long() == rhs.to_long();
            case String:    return to_string() == rhs.to_string();
            default: throw std::logic_error("invalid internal condition.");
        }
        // NOTREACHED
    }

    bool operator!=(const Value& rhs) const {
        switch (type) {
            case Undefined: return false;
            case Bool:      return to_bool() != rhs.to_bool();
            case Long:      return to_long() != rhs.to_long();
            case String:    return to_string() != rhs.to_string();
            default: throw std::logic_error("invalid internal condition.");
        }
        // NOTREACHED
    }

    bool operator<=(const Value& rhs) const {
        switch (type) {
            case Undefined: return false;
            case Bool:      return to_bool() <= rhs.to_bool();
            case Long:      return to_long() <= rhs.to_long();
            case String:    return to_string() <= rhs.to_string();
            default: throw std::logic_error("invalid internal condition.");
        }
        // NOTREACHED
    }

    bool operator<(const Value& rhs) const {
        switch (type) {
            case Undefined: return false;
            case Bool:      return to_bool() < rhs.to_bool();
            case Long:      return to_long() < rhs.to_long();
            case String:    return to_string() < rhs.to_string();
            default: throw std::logic_error("invalid internal condition.");
        }
        // NOTREACHED
    }

    bool operator>=(const Value& rhs) const {
        switch (type) {
            case Undefined: return false;
            case Bool:      return to_bool() >= rhs.to_bool();
            case Long:      return to_long() >= rhs.to_long();
            case String:    return to_string() >= rhs.to_string();
            default: throw std::logic_error("invalid internal condition.");
        }
        // NOTREACHED
    }

    bool operator>(const Value& rhs) const {
        switch (type) {
            case Undefined: return false;
            case Bool:      return to_bool() > rhs.to_bool();
            case Long:      return to_long() > rhs.to_long();
            case String:    return to_string() > rhs.to_string();
            default: throw std::logic_error("invalid internal condition.");
        }
        // NOTREACHED
    }

private:
    friend std::ostream& operator<<(std::ostream&, const Value&);

    int         type;
    peglib::any v;

};

std::ostream& operator<<(std::ostream& os, const Value& val);

struct Environment
{
    Environment() = default;

    void push_outer(std::shared_ptr<Environment> outer) {
        outers_.push_back(outer);
    }

    bool has(const std::string& s) const {
        if (dic_.find(s) != dic_.end()) {
            return true;
        }
        for (auto& outer: outers_) {
            if (outer->has(s)) {
                return true;
            }
        }
        return false;
    }

    Value get(const std::string& s) const {
        assert(has(s));
        if (dic_.find(s) != dic_.end()) {
            return dic_.at(s);
        }
        for (auto& outer: outers_) {
            if (outer->has(s)) {
                return outer->get(s);
            }
        }
        // NOT REACHED
    }

    void set(const std::string& s, const Value& val) {
        if (dic_.find(s) != dic_.end()) {
            dic_[s] = val;
        }
        for (auto& outer: outers_) {
            if (outer->has(s)) {
                outer->set(s, val);
                return;
            }
        }
        dic_[s] = val;
    }

    void setup_built_in_functions() {
        set("pp", Value(Value::FunctionValue {
            { "arg" },
            [](std::shared_ptr<Environment> env) {
                std::cout << env->get("arg").str() << std::endl;
                return Value();
            }
        }));
    }

private:
    std::vector<std::shared_ptr<Environment>> outers_;
    std::map<std::string, Value> dic_;
};

bool run(const std::string& path, std::shared_ptr<Environment> env, const char* expr, size_t len, Value& val, std::string& msg, bool print_ast);
<commit_msg>Added NOTREACHED.<commit_after>#include <map>
#include <string>
#include <peglib.h>

struct Environment;

struct Value
{
    enum Type { Undefined, Bool, Long, String, Array, Function };

    struct ArrayValue {
        std::vector<Value> values;
    };

    struct FunctionValue {
        std::vector<std::string>                                params;
        std::function<Value (std::shared_ptr<Environment> env)> eval;
    };

    explicit Value() : type(Undefined) {}
    explicit Value(bool b) : type(Bool), v(b) {}
    explicit Value(long l) : type(Long), v(l) {}
    explicit Value(std::string&& s) : type(String), v(s) {}
    explicit Value(ArrayValue&& a) : type(Array), v(a) {}
    explicit Value(FunctionValue&& f) : type(Function), v(f) {}

    Value(const Value&) = default;
    Value(Value&& rhs) : type(rhs.type), v(rhs.v) {}

    bool to_bool() const {
        switch (type) {
            case Bool: return v.get<bool>();
            case Long: return v.get<long>() != 0;
        }
        throw std::runtime_error("type error.");
    }

    long to_long() const {
        switch (type) {
            case Bool: return v.get<bool>();
            case Long: return v.get<long>();
        }
        throw std::runtime_error("type error.");
    }

    std::string to_string() const {
        switch (type) {
            case String: return v.get<std::string>();
        }
        throw std::runtime_error("type error.");
    }

    ArrayValue to_array() const {
        switch (type) {
            case Array: return v.get<ArrayValue>();
        }
        throw std::runtime_error("type error.");
    }

    FunctionValue to_function() const {
        switch (type) {
            case Function: return v.get<FunctionValue>();
        }
        throw std::runtime_error("type error.");
    }

    std::string str() const {
        switch (type) {
            case Undefined: return "undefined";
            case Bool:      return to_bool() ? "true" : "false";
            case Long:      return std::to_string(to_long()); break;
            case String:    return to_string();
            case Function:  return "[function]";
            case Array:     return "[array]";
            default: throw std::logic_error("invalid internal condition.");
        }
        // NOTREACHED
    }

    std::ostream& out(std::ostream& os) const {
        switch (type) {
            case Undefined: os << "undefined"; break;
            case Bool:      os << (to_bool() ? "true" : "false"); break;
            case Long:      os << to_long(); break;
            case String:    os << "'" << to_string() << "'"; break;
            case Function:  os << "[function]"; break;
            case Array:     os << "[array]"; break;
            default: throw std::logic_error("invalid internal condition.");
        }
        return os;
    }

    bool operator==(const Value& rhs) const {
        switch (type) {
            case Undefined: return true;
            case Bool:      return to_bool() == rhs.to_bool();
            case Long:      return to_long() == rhs.to_long();
            case String:    return to_string() == rhs.to_string();
            default: throw std::logic_error("invalid internal condition.");
        }
        // NOTREACHED
    }

    bool operator!=(const Value& rhs) const {
        switch (type) {
            case Undefined: return false;
            case Bool:      return to_bool() != rhs.to_bool();
            case Long:      return to_long() != rhs.to_long();
            case String:    return to_string() != rhs.to_string();
            default: throw std::logic_error("invalid internal condition.");
        }
        // NOTREACHED
    }

    bool operator<=(const Value& rhs) const {
        switch (type) {
            case Undefined: return false;
            case Bool:      return to_bool() <= rhs.to_bool();
            case Long:      return to_long() <= rhs.to_long();
            case String:    return to_string() <= rhs.to_string();
            default: throw std::logic_error("invalid internal condition.");
        }
        // NOTREACHED
    }

    bool operator<(const Value& rhs) const {
        switch (type) {
            case Undefined: return false;
            case Bool:      return to_bool() < rhs.to_bool();
            case Long:      return to_long() < rhs.to_long();
            case String:    return to_string() < rhs.to_string();
            default: throw std::logic_error("invalid internal condition.");
        }
        // NOTREACHED
    }

    bool operator>=(const Value& rhs) const {
        switch (type) {
            case Undefined: return false;
            case Bool:      return to_bool() >= rhs.to_bool();
            case Long:      return to_long() >= rhs.to_long();
            case String:    return to_string() >= rhs.to_string();
            default: throw std::logic_error("invalid internal condition.");
        }
        // NOTREACHED
    }

    bool operator>(const Value& rhs) const {
        switch (type) {
            case Undefined: return false;
            case Bool:      return to_bool() > rhs.to_bool();
            case Long:      return to_long() > rhs.to_long();
            case String:    return to_string() > rhs.to_string();
            default: throw std::logic_error("invalid internal condition.");
        }
        // NOTREACHED
    }

private:
    friend std::ostream& operator<<(std::ostream&, const Value&);

    int         type;
    peglib::any v;

};

std::ostream& operator<<(std::ostream& os, const Value& val);

struct Environment
{
    Environment() = default;

    void push_outer(std::shared_ptr<Environment> outer) {
        outers_.push_back(outer);
    }

    bool has(const std::string& s) const {
        if (dic_.find(s) != dic_.end()) {
            return true;
        }
        for (auto& outer: outers_) {
            if (outer->has(s)) {
                return true;
            }
        }
        return false;
    }

    Value get(const std::string& s) const {
        assert(has(s));

        if (dic_.find(s) != dic_.end()) {
            return dic_.at(s);
        }

        for (auto& outer: outers_) {
            if (outer->has(s)) {
                return outer->get(s);
            }
        }

        // NOTREACHED
        throw std::logic_error("invalid internal condition.");
    }

    void set(const std::string& s, const Value& val) {
        if (dic_.find(s) != dic_.end()) {
            dic_[s] = val;
        }
        for (auto& outer: outers_) {
            if (outer->has(s)) {
                outer->set(s, val);
                return;
            }
        }
        dic_[s] = val;
    }

    void setup_built_in_functions() {
        set("pp", Value(Value::FunctionValue {
            { "arg" },
            [](std::shared_ptr<Environment> env) {
                std::cout << env->get("arg").str() << std::endl;
                return Value();
            }
        }));
    }

private:
    std::vector<std::shared_ptr<Environment>> outers_;
    std::map<std::string, Value> dic_;
};

bool run(const std::string& path, std::shared_ptr<Environment> env, const char* expr, size_t len, Value& val, std::string& msg, bool print_ast);
<|endoftext|>


<commit_before>//
//  Sound.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 04/11/2020.
//  Copyright © 2020 Thomas Harte. All rights reserved.
//

#ifndef Apple_IIgs_Sound_hpp
#define Apple_IIgs_Sound_hpp

#include <atomic>

#include "../../../ClockReceiver/ClockReceiver.hpp"
#include "../../../Concurrency/AsyncTaskQueue.hpp"
#include "../../../Outputs/Speaker/Implementation/SampleSource.hpp"

namespace Apple {
namespace IIgs {
namespace Sound {

class GLU: public Outputs::Speaker::SampleSource {
	public:
		GLU(Concurrency::DeferringAsyncTaskQueue &audio_queue);

		void set_control(uint8_t);
		uint8_t get_control();
		void set_data(uint8_t);
		uint8_t get_data();
		void set_address_low(uint8_t);
		uint8_t get_address_low();
		void set_address_high(uint8_t);
		uint8_t get_address_high();

		void run_for(Cycles);
		Cycles get_next_sequence_point() const;
		bool get_interrupt_line();

		// SampleSource.
		void get_samples(std::size_t number_of_samples, std::int16_t *target);
		void set_sample_volume_range(std::int16_t range);
		void skip_samples(const std::size_t number_of_samples);

	private:
		Concurrency::DeferringAsyncTaskQueue &audio_queue_;

		uint16_t address_ = 0;

		// Use a circular buffer for piping memory alterations onto the audio
		// thread; it would be prohibitive to defer every write individually.
		//
		// Assumed: on most modern architectures, an atomic 64-bit read or
		// write can be achieved locklessly.
		struct MemoryWrite {
			uint32_t time;
			uint16_t address;
			uint8_t value;
			bool enabled;
		};
		static_assert(sizeof(MemoryWrite) == 8);
		constexpr static int StoreBufferSize = 16384;

		std::atomic<MemoryWrite> pending_stores_[StoreBufferSize];
		uint32_t pending_store_read_ = 0, pending_store_read_time_ = 0;
		uint32_t pending_store_write_ = 0, pending_store_write_time_ = 0;

		// Maintain state both 'locally' (i.e. on the emulation thread) and
		// 'remotely' (i.e. on the audio thread).
		struct EnsoniqState {
			uint8_t ram_[65536];
			struct Oscillator {
				uint32_t position;

				// Programmer-set values.
				uint16_t velocity;
				uint8_t volume;
				uint8_t address;
				uint8_t control;
				uint8_t table_size;

				// Derived state.
				uint32_t overflow_mask;			// If a non-zero bit gets anywhere into the overflow mask, this channel
												// has wrapped around. It's a function of table_size.
				bool interrupt_request = false;	// Will be non-zero if this channel would request an interrupt, were
												// it currently enabled to do so.

				uint8_t sample(uint8_t *ram);
				int16_t output(uint8_t *ram);
			} oscillators[32];

			// Some of these aren't actually needed on both threads.
			uint8_t control;
			int oscillator_count;

			void set_register(uint16_t address, uint8_t value);
		} local_, remote_;

		// Functions to update an EnsoniqState; these don't belong to the state itself
		// because they also access the pending stores (inter alia).
		void generate_audio(size_t number_of_samples, std::int16_t *target);
		void skip_audio(EnsoniqState &state, size_t number_of_samples);

		// Audio-thread state.
		int16_t output_range_ = 0;
};

}
}
}

#endif /* SoundGLU_hpp */
<commit_msg>Ensures safe startup of the Ensoniq.<commit_after>//
//  Sound.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 04/11/2020.
//  Copyright © 2020 Thomas Harte. All rights reserved.
//

#ifndef Apple_IIgs_Sound_hpp
#define Apple_IIgs_Sound_hpp

#include <atomic>

#include "../../../ClockReceiver/ClockReceiver.hpp"
#include "../../../Concurrency/AsyncTaskQueue.hpp"
#include "../../../Outputs/Speaker/Implementation/SampleSource.hpp"

namespace Apple {
namespace IIgs {
namespace Sound {

class GLU: public Outputs::Speaker::SampleSource {
	public:
		GLU(Concurrency::DeferringAsyncTaskQueue &audio_queue);

		void set_control(uint8_t);
		uint8_t get_control();
		void set_data(uint8_t);
		uint8_t get_data();
		void set_address_low(uint8_t);
		uint8_t get_address_low();
		void set_address_high(uint8_t);
		uint8_t get_address_high();

		void run_for(Cycles);
		Cycles get_next_sequence_point() const;
		bool get_interrupt_line();

		// SampleSource.
		void get_samples(std::size_t number_of_samples, std::int16_t *target);
		void set_sample_volume_range(std::int16_t range);
		void skip_samples(const std::size_t number_of_samples);

	private:
		Concurrency::DeferringAsyncTaskQueue &audio_queue_;

		uint16_t address_ = 0;

		// Use a circular buffer for piping memory alterations onto the audio
		// thread; it would be prohibitive to defer every write individually.
		//
		// Assumed: on most modern architectures, an atomic 64-bit read or
		// write can be achieved locklessly.
		struct MemoryWrite {
			uint32_t time;
			uint16_t address;
			uint8_t value;
			bool enabled;
		};
		static_assert(sizeof(MemoryWrite) == 8);
		constexpr static int StoreBufferSize = 16384;

		std::atomic<MemoryWrite> pending_stores_[StoreBufferSize];
		uint32_t pending_store_read_ = 0, pending_store_read_time_ = 0;
		uint32_t pending_store_write_ = 0, pending_store_write_time_ = 0;

		// Maintain state both 'locally' (i.e. on the emulation thread) and
		// 'remotely' (i.e. on the audio thread).
		struct EnsoniqState {
			uint8_t ram_[65536];
			struct Oscillator {
				uint32_t position;

				// Programmer-set values.
				uint16_t velocity;
				uint8_t volume;
				uint8_t address;
				uint8_t control;
				uint8_t table_size;

				// Derived state.
				uint32_t overflow_mask;			// If a non-zero bit gets anywhere into the overflow mask, this channel
												// has wrapped around. It's a function of table_size.
				bool interrupt_request = false;	// Will be non-zero if this channel would request an interrupt, were
												// it currently enabled to do so.

				uint8_t sample(uint8_t *ram);
				int16_t output(uint8_t *ram);
			} oscillators[32];

			// Some of these aren't actually needed on both threads.
			uint8_t control = 0;
			int oscillator_count = 1;

			void set_register(uint16_t address, uint8_t value);
		} local_, remote_;

		// Functions to update an EnsoniqState; these don't belong to the state itself
		// because they also access the pending stores (inter alia).
		void generate_audio(size_t number_of_samples, std::int16_t *target);
		void skip_audio(EnsoniqState &state, size_t number_of_samples);

		// Audio-thread state.
		int16_t output_range_ = 0;
};

}
}
}

#endif /* SoundGLU_hpp */
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "NdapiObject.h"

namespace Ndapi
{
	NdapiObject::NdapiObject()
	{
	}

	NdapiObject::NdapiObject(d2fob* object)
	{
		_handler = object;
	}

	void NdapiObject::FillWithObject(void* object)
	{
		_handler = object;
	}

	void NdapiObject::Create(String^ name, d2fotyp object_type)
	{
		auto object = _handler;
		NativeString<text> internal_name(name);

		auto status = d2fobcr_Create(NdapiContext::Context, NdapiContext::Context, &object, internal_name, object_type);
		if (status != D2FS_SUCCESS)
		{
			throw gcnew NdapiException(String::Format("Error creating a object. Type: {0}", object_type), status);
		}

		_handler = object;
	}

	void NdapiObject::Create(String^ name, NdapiObject^ parent, d2fotyp object_type)
	{
		auto object = _handler;
		NativeString<text> internal_name(name);

		auto status = d2fobcr_Create(NdapiContext::Context, parent->_handler, &object, internal_name, object_type);
		if (status != D2FS_SUCCESS)
		{
			throw gcnew NdapiException(String::Format("Error creating a object. Type: {0}", object_type), status);
		}

		_handler = object;
	}

	String^ NdapiObject::GetStringProperty(int property_id)
	{
		text* property_value;

		auto status = d2fobgt_GetTextProp(NdapiContext::Context, _handler, property_id, &property_value);
		if (status != D2FS_SUCCESS)
		{
			throw gcnew NdapiException(String::Format("Error getting a string property. Property id: {0}", property_id), status);
		}
		return gcnew String((char*)property_value);
	}

	void NdapiObject::SetStringProperty(int property_id, String^ value)
	{
		NativeString<text> internal_value(value);

		auto status = d2fobst_SetTextProp(NdapiContext::Context, _handler, property_id, internal_value);
		if (status != D2FS_SUCCESS)
		{
			throw gcnew NdapiException(String::Format("Error setting a string property. Property id: {0}", property_id), status);
		}

	}

	long NdapiObject::GetNumberProperty(int property_id)
	{
		number property_value;

		auto status = d2fobgn_GetNumProp(NdapiContext::Context, _handler, property_id, &property_value);
		if (status != D2FS_SUCCESS)
		{
			throw gcnew NdapiException(String::Format("Error getting a number property. Property id: {0}", property_id), status);
		}

		return (long)property_value;
	}

	void NdapiObject::SetNumberProperty(int property_id, long value)
	{
		number property_value = (number)value;

		auto status = d2fobgn_GetNumProp(NdapiContext::Context, _handler, property_id, &property_value);
		if (status != D2FS_SUCCESS)
		{
			throw gcnew NdapiException(String::Format("Error setting a number property. Property id: {0}", property_id), status);
		}
	}

	generic <class T>
	T NdapiObject::GetObjectProperty(int property_id)
	{
		d2fob* object;

		auto status = d2fobgo_GetObjProp(NdapiContext::Context, _handler, property_id, &object);
		if (status != D2FS_SUCCESS)
		{
			throw gcnew NdapiException(String::Format("Error getting a object property. Property id: {0}", property_id), status);
		}

		return safe_cast<T>(gcnew NdapiObject(object));
	}

	generic <class T>
	void NdapiObject::SetObjectProperty(int property_id, T value)
	{
		auto status = d2fobso_SetObjProp(NdapiContext::Context, _handler, property_id, value->_handler);
		if (status != D2FS_SUCCESS)
		{
			throw gcnew NdapiException(String::Format("Error setting a object property. Property id: {0}", property_id), status);
		}
	}

	String^ NdapiObject::Name::get()
	{
		return GetStringProperty(D2FP_NAME);
	}

	void NdapiObject::Name::set(String^ value)
	{
		SetStringProperty(D2FP_NAME, value);
	}

	String^ NdapiObject::ParentFileName::get()
	{
		return GetStringProperty(D2FP_PAR_FLNAM);
	}

	void NdapiObject::ParentFileName::set(String^ value)
	{
		SetStringProperty(D2FP_PAR_FLNAM, value);
	}

	String^ NdapiObject::ParentFileNamePath::get()
	{
		return GetStringProperty(D2FP_PAR_FLPATH);
	}

	void NdapiObject::ParentFileNamePath::set(String^ value)
	{
		SetStringProperty(D2FP_PAR_FLPATH, value);
	}

	ModuleStorageType NdapiObject::ParentModuleStorage::get()
	{
		return safe_cast<ModuleStorageType>(GetNumberProperty(D2FP_PAR_MODSTR));
	}

	void NdapiObject::ParentModuleStorage::set(ModuleStorageType value)
	{
		SetNumberProperty(D2FP_PAR_MODSTR, safe_cast<long>(value));
	}

	long NdapiObject::ParentModuleType::get()
	{
		return GetNumberProperty(D2FP_PAR_MODTYP);
	}

	void NdapiObject::ParentModuleType::set(long value)
	{
		SetNumberProperty(D2FP_PAR_MODTYP, value);
	}

	String^ NdapiObject::ParentModule::get()
	{
		return GetStringProperty(D2FP_PAR_MODULE);
	}

	void NdapiObject::ParentModule::set(String^ value)
	{
		SetStringProperty(D2FP_PAR_MODULE, value);
	}

	String^ NdapiObject::ParentName::get()
	{
		return GetStringProperty(D2FP_PAR_NAM);
	}

	void NdapiObject::ParentName::set(String^ value)
	{
		SetStringProperty(D2FP_PAR_NAM, value);
	}

	long NdapiObject::ParentType::get()
	{
		return GetNumberProperty(D2FP_PAR_TYP);
	}

	void NdapiObject::ParentType::set(long value)
	{
		SetNumberProperty(D2FP_PAR_TYP, value);
	}
}<commit_msg>Fix SetNumberProperty<commit_after>#include "stdafx.h"
#include "NdapiObject.h"

namespace Ndapi
{
	NdapiObject::NdapiObject()
	{
	}

	NdapiObject::NdapiObject(d2fob* object)
	{
		_handler = object;
	}

	void NdapiObject::FillWithObject(void* object)
	{
		_handler = object;
	}

	void NdapiObject::Create(String^ name, d2fotyp object_type)
	{
		auto object = _handler;
		NativeString<text> internal_name(name);

		auto status = d2fobcr_Create(NdapiContext::Context, NdapiContext::Context, &object, internal_name, object_type);
		if (status != D2FS_SUCCESS)
		{
			throw gcnew NdapiException(String::Format("Error creating a object. Type: {0}", object_type), status);
		}

		_handler = object;
	}

	void NdapiObject::Create(String^ name, NdapiObject^ parent, d2fotyp object_type)
	{
		auto object = _handler;
		NativeString<text> internal_name(name);

		auto status = d2fobcr_Create(NdapiContext::Context, parent->_handler, &object, internal_name, object_type);
		if (status != D2FS_SUCCESS)
		{
			throw gcnew NdapiException(String::Format("Error creating a object. Type: {0}", object_type), status);
		}

		_handler = object;
	}

	String^ NdapiObject::GetStringProperty(int property_id)
	{
		text* property_value;

		auto status = d2fobgt_GetTextProp(NdapiContext::Context, _handler, property_id, &property_value);
		if (status != D2FS_SUCCESS)
		{
			throw gcnew NdapiException(String::Format("Error getting a string property. Property id: {0}", property_id), status);
		}
		return gcnew String((char*)property_value);
	}

	void NdapiObject::SetStringProperty(int property_id, String^ value)
	{
		NativeString<text> internal_value(value);

		auto status = d2fobst_SetTextProp(NdapiContext::Context, _handler, property_id, internal_value);
		if (status != D2FS_SUCCESS)
		{
			throw gcnew NdapiException(String::Format("Error setting a string property. Property id: {0}", property_id), status);
		}

	}

	long NdapiObject::GetNumberProperty(int property_id)
	{
		number property_value;

		auto status = d2fobgn_GetNumProp(NdapiContext::Context, _handler, property_id, &property_value);
		if (status != D2FS_SUCCESS)
		{
			throw gcnew NdapiException(String::Format("Error getting a number property. Property id: {0}", property_id), status);
		}

		return (long)property_value;
	}

	void NdapiObject::SetNumberProperty(int property_id, long value)
	{
		number property_value = (number)value;

		auto status = d2fobsn_SetNumProp(NdapiContext::Context, _handler, property_id, property_value);
		if (status != D2FS_SUCCESS)
		{
			throw gcnew NdapiException(String::Format("Error setting a number property. Property id: {0}", property_id), status);
		}
	}

	generic <class T>
	T NdapiObject::GetObjectProperty(int property_id)
	{
		d2fob* object;

		auto status = d2fobgo_GetObjProp(NdapiContext::Context, _handler, property_id, &object);
		if (status != D2FS_SUCCESS)
		{
			throw gcnew NdapiException(String::Format("Error getting a object property. Property id: {0}", property_id), status);
		}

		return safe_cast<T>(gcnew NdapiObject(object));
	}

	generic <class T>
	void NdapiObject::SetObjectProperty(int property_id, T value)
	{
		auto status = d2fobso_SetObjProp(NdapiContext::Context, _handler, property_id, value->_handler);
		if (status != D2FS_SUCCESS)
		{
			throw gcnew NdapiException(String::Format("Error setting a object property. Property id: {0}", property_id), status);
		}
	}

	String^ NdapiObject::Name::get()
	{
		return GetStringProperty(D2FP_NAME);
	}

	void NdapiObject::Name::set(String^ value)
	{
		SetStringProperty(D2FP_NAME, value);
	}

	String^ NdapiObject::ParentFileName::get()
	{
		return GetStringProperty(D2FP_PAR_FLNAM);
	}

	void NdapiObject::ParentFileName::set(String^ value)
	{
		SetStringProperty(D2FP_PAR_FLNAM, value);
	}

	String^ NdapiObject::ParentFileNamePath::get()
	{
		return GetStringProperty(D2FP_PAR_FLPATH);
	}

	void NdapiObject::ParentFileNamePath::set(String^ value)
	{
		SetStringProperty(D2FP_PAR_FLPATH, value);
	}

	ModuleStorageType NdapiObject::ParentModuleStorage::get()
	{
		return safe_cast<ModuleStorageType>(GetNumberProperty(D2FP_PAR_MODSTR));
	}

	void NdapiObject::ParentModuleStorage::set(ModuleStorageType value)
	{
		SetNumberProperty(D2FP_PAR_MODSTR, safe_cast<long>(value));
	}

	long NdapiObject::ParentModuleType::get()
	{
		return GetNumberProperty(D2FP_PAR_MODTYP);
	}

	void NdapiObject::ParentModuleType::set(long value)
	{
		SetNumberProperty(D2FP_PAR_MODTYP, value);
	}

	String^ NdapiObject::ParentModule::get()
	{
		return GetStringProperty(D2FP_PAR_MODULE);
	}

	void NdapiObject::ParentModule::set(String^ value)
	{
		SetStringProperty(D2FP_PAR_MODULE, value);
	}

	String^ NdapiObject::ParentName::get()
	{
		return GetStringProperty(D2FP_PAR_NAM);
	}

	void NdapiObject::ParentName::set(String^ value)
	{
		SetStringProperty(D2FP_PAR_NAM, value);
	}

	long NdapiObject::ParentType::get()
	{
		return GetNumberProperty(D2FP_PAR_TYP);
	}

	void NdapiObject::ParentType::set(long value)
	{
		SetNumberProperty(D2FP_PAR_TYP, value);
	}
}<|endoftext|>


<commit_before>#include <libmesh/partitioner.h>
#include <libmesh/mesh.h>
#include <libmesh/auto_ptr.h>
#include <libmesh/mesh_generation.h>
#include <libmesh/equation_systems.h>
#include <libmesh/elem.h>
#include <libmesh/system.h>
#include <libmesh/dof_map.h>
#include <timpi/communicator.h>

#include "test_comm.h"
#include "libmesh_cppunit.h"

using namespace libMesh;

class ContrivedPartitioner : public Partitioner
{
public:
  ContrivedPartitioner() = default;
  ContrivedPartitioner(const ContrivedPartitioner &) = default;
  ContrivedPartitioner(ContrivedPartitioner &&) = default;
  ContrivedPartitioner & operator=(const ContrivedPartitioner &) = default;
  ContrivedPartitioner & operator=(ContrivedPartitioner &&) = default;
  virtual ~ContrivedPartitioner() = default;

  std::unique_ptr<Partitioner> clone() const override
  {
    return libmesh_make_unique<ContrivedPartitioner>(*this);
  }

protected:
  void _do_partition(MeshBase & mesh, const unsigned int n) override
  {
    libmesh_assert(n > 1);

    unsigned int n_interior_elems = 0;
    for (Elem * const elem : as_range(mesh.elements_begin(), mesh.elements_end()))
    {
      bool internal_elem = true;
      for (const Elem * const neighbor : elem->neighbor_ptr_range())
        if (!neighbor)
        {
          internal_elem = false;
          break;
        }

      // The interior element will go on processor 1. Other elements will go on processor 0. For a
      // system/DofMap that has all nodal variables all elements on processor 0 will appear
      // evaluable. However, for a system/DofMap that has any elemental variables the interior
      // element will not appear evaluable on processor 0
      n_interior_elems += internal_elem;
      elem->processor_id() = internal_elem;
    }

    // This test is hand-crafted for one interior element
    libmesh_assert(n_interior_elems == 1);
  }
};

class MultiEvaluablePredTest : public CppUnit::TestCase
{
public:
  CPPUNIT_TEST_SUITE(MultiEvaluablePredTest);

  CPPUNIT_TEST(test);

  CPPUNIT_TEST_SUITE_END();

public:
  void setUp() {}

  void tearDown() {}

  void test()
  {
    const auto rank = TestCommWorld->rank();
    Mesh mesh(*TestCommWorld);
    mesh.partitioner() = libmesh_make_unique<ContrivedPartitioner>();
    MeshTools::Generation::build_square(mesh, 3, 3, 0, 3, 0, 3, QUAD4);

    EquationSystems es(mesh);
    auto & nodal_system = es.add_system<System>("nodal_system");
    nodal_system.add_variable("nodal", FIRST, LAGRANGE);
    auto & nodal_dof_map = nodal_system.get_dof_map();
    nodal_dof_map.remove_default_ghosting();
    auto & elem_system = es.add_system<System>("elem_system");
    elem_system.add_variable("elem", CONSTANT, MONOMIAL);
    auto & elem_dof_map = elem_system.get_dof_map();
    elem_dof_map.remove_default_ghosting();

    es.init();

    {
      auto n_evaluable = std::distance(mesh.evaluable_elements_begin(nodal_dof_map),
                                       mesh.evaluable_elements_end(nodal_dof_map));
      typedef decltype(n_evaluable) comp_type;
      switch (rank)
      {
        case 0:
          CPPUNIT_ASSERT_EQUAL(n_evaluable, comp_type(9));
          break;

        case 1:
          CPPUNIT_ASSERT_EQUAL(n_evaluable, comp_type(1));
          break;

        default:
          CPPUNIT_ASSERT_EQUAL(n_evaluable, comp_type(0));
          break;
      }
    }

    {
      auto n_evaluable = std::distance(mesh.evaluable_elements_begin(elem_dof_map),
                                       mesh.evaluable_elements_end(elem_dof_map));
      typedef decltype(n_evaluable) comp_type;
      switch (rank)
      {
        case 0:
          CPPUNIT_ASSERT_EQUAL(n_evaluable, comp_type(TestCommWorld->size() == 1 ? 9 : 8));
          break;

        case 1:
          CPPUNIT_ASSERT_EQUAL(n_evaluable, comp_type(1));
          break;

        default:
          CPPUNIT_ASSERT_EQUAL(n_evaluable, comp_type(0));
          break;
      }
    }

    {
      std::vector<const DofMap *> dof_maps = {&nodal_dof_map, &elem_dof_map};
      auto n_evaluable = std::distance(mesh.multi_evaluable_elements_begin(dof_maps),
                                       mesh.multi_evaluable_elements_end(dof_maps));
      typedef decltype(n_evaluable) comp_type;
      switch (rank)
      {
        case 0:
          CPPUNIT_ASSERT_EQUAL(n_evaluable, comp_type(TestCommWorld->size() == 1 ? 9 : 8));
          break;

        case 1:
          CPPUNIT_ASSERT_EQUAL(n_evaluable, comp_type(1));
          break;

        default:
          CPPUNIT_ASSERT_EQUAL(n_evaluable, comp_type(0));
          break;
      }
    }
  }
};

CPPUNIT_TEST_SUITE_REGISTRATION(MultiEvaluablePredTest);
<commit_msg>Avoid unused variable in opt mode unit test<commit_after>#include <libmesh/partitioner.h>
#include <libmesh/mesh.h>
#include <libmesh/auto_ptr.h>
#include <libmesh/mesh_generation.h>
#include <libmesh/equation_systems.h>
#include <libmesh/elem.h>
#include <libmesh/system.h>
#include <libmesh/dof_map.h>
#include <timpi/communicator.h>

#include "test_comm.h"
#include "libmesh_cppunit.h"

using namespace libMesh;

class ContrivedPartitioner : public Partitioner
{
public:
  ContrivedPartitioner() = default;
  ContrivedPartitioner(const ContrivedPartitioner &) = default;
  ContrivedPartitioner(ContrivedPartitioner &&) = default;
  ContrivedPartitioner & operator=(const ContrivedPartitioner &) = default;
  ContrivedPartitioner & operator=(ContrivedPartitioner &&) = default;
  virtual ~ContrivedPartitioner() = default;

  std::unique_ptr<Partitioner> clone() const override
  {
    return libmesh_make_unique<ContrivedPartitioner>(*this);
  }

protected:
  void _do_partition(MeshBase & mesh, const unsigned int n) override
  {
    libmesh_assert(n > 1);

    unsigned int n_interior_elems = 0;
    for (Elem * const elem : as_range(mesh.elements_begin(), mesh.elements_end()))
    {
      bool internal_elem = true;
      for (const Elem * const neighbor : elem->neighbor_ptr_range())
        if (!neighbor)
        {
          internal_elem = false;
          break;
        }

      // The interior element will go on processor 1. Other elements will go on processor 0. For a
      // system/DofMap that has all nodal variables all elements on processor 0 will appear
      // evaluable. However, for a system/DofMap that has any elemental variables the interior
      // element will not appear evaluable on processor 0
      n_interior_elems += internal_elem;
      elem->processor_id() = internal_elem;
    }

    // This test is hand-crafted for one interior element
    CPPUNIT_ASSERT_EQUAL(n_interior_elems, 1u);
  }
};

class MultiEvaluablePredTest : public CppUnit::TestCase
{
public:
  CPPUNIT_TEST_SUITE(MultiEvaluablePredTest);

  CPPUNIT_TEST(test);

  CPPUNIT_TEST_SUITE_END();

public:
  void setUp() {}

  void tearDown() {}

  void test()
  {
    const auto rank = TestCommWorld->rank();
    Mesh mesh(*TestCommWorld);
    mesh.partitioner() = libmesh_make_unique<ContrivedPartitioner>();
    MeshTools::Generation::build_square(mesh, 3, 3, 0, 3, 0, 3, QUAD4);

    EquationSystems es(mesh);
    auto & nodal_system = es.add_system<System>("nodal_system");
    nodal_system.add_variable("nodal", FIRST, LAGRANGE);
    auto & nodal_dof_map = nodal_system.get_dof_map();
    nodal_dof_map.remove_default_ghosting();
    auto & elem_system = es.add_system<System>("elem_system");
    elem_system.add_variable("elem", CONSTANT, MONOMIAL);
    auto & elem_dof_map = elem_system.get_dof_map();
    elem_dof_map.remove_default_ghosting();

    es.init();

    {
      auto n_evaluable = std::distance(mesh.evaluable_elements_begin(nodal_dof_map),
                                       mesh.evaluable_elements_end(nodal_dof_map));
      typedef decltype(n_evaluable) comp_type;
      switch (rank)
      {
        case 0:
          CPPUNIT_ASSERT_EQUAL(n_evaluable, comp_type(9));
          break;

        case 1:
          CPPUNIT_ASSERT_EQUAL(n_evaluable, comp_type(1));
          break;

        default:
          CPPUNIT_ASSERT_EQUAL(n_evaluable, comp_type(0));
          break;
      }
    }

    {
      auto n_evaluable = std::distance(mesh.evaluable_elements_begin(elem_dof_map),
                                       mesh.evaluable_elements_end(elem_dof_map));
      typedef decltype(n_evaluable) comp_type;
      switch (rank)
      {
        case 0:
          CPPUNIT_ASSERT_EQUAL(n_evaluable, comp_type(TestCommWorld->size() == 1 ? 9 : 8));
          break;

        case 1:
          CPPUNIT_ASSERT_EQUAL(n_evaluable, comp_type(1));
          break;

        default:
          CPPUNIT_ASSERT_EQUAL(n_evaluable, comp_type(0));
          break;
      }
    }

    {
      std::vector<const DofMap *> dof_maps = {&nodal_dof_map, &elem_dof_map};
      auto n_evaluable = std::distance(mesh.multi_evaluable_elements_begin(dof_maps),
                                       mesh.multi_evaluable_elements_end(dof_maps));
      typedef decltype(n_evaluable) comp_type;
      switch (rank)
      {
        case 0:
          CPPUNIT_ASSERT_EQUAL(n_evaluable, comp_type(TestCommWorld->size() == 1 ? 9 : 8));
          break;

        case 1:
          CPPUNIT_ASSERT_EQUAL(n_evaluable, comp_type(1));
          break;

        default:
          CPPUNIT_ASSERT_EQUAL(n_evaluable, comp_type(0));
          break;
      }
    }
  }
};

CPPUNIT_TEST_SUITE_REGISTRATION(MultiEvaluablePredTest);
<|endoftext|>


<commit_before>#include <boost/filesystem.hpp>
#include "PsfVm.h"
#include "PsfLoader.h"
#include "MemoryUtils.h"
#include "CoffObjectFile.h"
#include "MachoObjectFile.h"
#include "StdStreamUtils.h"
#include "Jitter.h"
#include "Jitter_CodeGen_x86_32.h"
#include "Jitter_CodeGen_Arm.h"
#include "MemStream.h"
#include "Iop_PsfSubSystem.h"
#include "psp/Psp_PsfSubSystem.h"
#include "ThreadPool.h"
#include "Playlist.h"
#include "make_unique.h"

namespace filesystem = boost::filesystem;

struct FUNCTION_TABLE_ITEM
{
	AOT_BLOCK_KEY	key;
	uint32			symbolIndex;
};
typedef std::vector<FUNCTION_TABLE_ITEM> FunctionTable;

typedef std::map<AOT_BLOCK_KEY, std::vector<uint32>> AotBlockMap;

extern "C" uint32 LWL_Proxy(uint32, uint32, CMIPS*);
extern "C" uint32 LWR_Proxy(uint32, uint32, CMIPS*);
extern "C" void SWL_Proxy(uint32, uint32, CMIPS*);
extern "C" void SWR_Proxy(uint32, uint32, CMIPS*);

void Gather(const char* archivePathName, const char* outputPathName)
{
	Framework::CStdStream outputStream(outputPathName, "wb");
	CBasicBlock::SetAotBlockOutputStream(&outputStream);

	{
		Framework::CThreadPool threadPool(std::thread::hardware_concurrency());

		filesystem::path archivePath = filesystem::path(archivePathName);
		auto archive = std::unique_ptr<CPsfArchive>(CPsfArchive::CreateFromPath(archivePath));

		for(const auto& fileInfo : archive->GetFiles())
		{
			filesystem::path archiveItemPath = fileInfo.name;
			filesystem::path archiveItemExtension = archiveItemPath.extension();
			if(CPlaylist::IsLoadableExtension(archiveItemExtension.string().c_str() + 1))
			{
				threadPool.Enqueue(
					[=] ()
					{
						printf("Processing %s...\r\n", archiveItemPath.string().c_str());

						CPsfVm virtualMachine;

						CPsfLoader::LoadPsf(virtualMachine, archiveItemPath.wstring(), archivePath);
						int currentTime = 0;
						virtualMachine.OnNewFrame.connect(
							[&currentTime] ()
							{
								currentTime += 16;
							});

						virtualMachine.Resume();

#ifdef _DEBUG
						static const unsigned int executionTime = 1;
#else
						static const unsigned int executionTime = 10;
#endif
						while(currentTime <= (executionTime * 60 * 1000))
						{
							std::this_thread::sleep_for(std::chrono::milliseconds(10));
						}

						virtualMachine.Pause();
					}
				);
			}
		}
	}

	CBasicBlock::SetAotBlockOutputStream(nullptr);
}

unsigned int CompileFunction(CPsfVm& virtualMachine, CMipsJitter* jitter, const std::vector<uint32>& blockCode, Jitter::CObjectFile& objectFile, const std::string& functionName, uint32 begin, uint32 end)
{
	auto& context = virtualMachine.GetCpu();

	uint8* ram = virtualMachine.GetRam();
	for(uint32 address = begin; address <= end; address += 4)
	{
		*reinterpret_cast<uint32*>(&ram[address]) = blockCode[(address - begin) / 4];
	}

	{
		Framework::CMemStream outputStream;
		Jitter::CObjectFile::INTERNAL_SYMBOL func;

		jitter->GetCodeGen()->SetExternalSymbolReferencedHandler(
			[&] (void* symbol, uint32 offset)
			{
				Jitter::CObjectFile::SYMBOL_REFERENCE ref;
				ref.offset		= offset;
				ref.type		= Jitter::CObjectFile::SYMBOL_TYPE_EXTERNAL;
				ref.symbolIndex	= objectFile.GetExternalSymbolIndexByValue(symbol);
				func.symbolReferences.push_back(ref);
			}
		);

		jitter->SetStream(&outputStream);
		jitter->Begin();

		for(uint32 address = begin; address <= end; address += 4)
		{
			context.m_pArch->CompileInstruction(address, jitter, &context);
			//Sanity check
			assert(jitter->IsStackEmpty());
		}

		jitter->End();

		func.name		= functionName;
		func.data		= std::vector<uint8>(outputStream.GetBuffer(), outputStream.GetBuffer() + outputStream.GetSize());
		func.location	= Jitter::CObjectFile::INTERNAL_SYMBOL_LOCATION_TEXT;
		return objectFile.AddInternalSymbol(func);
	}
}

AotBlockMap GetBlocksFromCache(const filesystem::path& blockCachePath, const char* cacheFilter)
{
	AotBlockMap result;

	auto path_end = filesystem::directory_iterator();
	for(auto pathIterator = filesystem::directory_iterator(blockCachePath);
		pathIterator != path_end; pathIterator++)
	{
		const auto& filePath = (*pathIterator);
		auto filePathExtension = filePath.path().extension();
		if(filePathExtension.string() != std::string(cacheFilter))
		{
			continue;
		}

		printf("Processing %s...\r\n", filePath.path().string().c_str());

		auto blockCacheStream = Framework::CreateInputStdStream(filePath.path().native());

		uint32 fileSize = blockCacheStream.GetLength();
		while(fileSize != 0)
		{
			AOT_BLOCK_KEY key = {};
			key.crc		= blockCacheStream.Read32();
			key.begin	= blockCacheStream.Read32();
			key.end		= blockCacheStream.Read32();

			if(key.begin > key.end)
			{
				assert(0);
				throw std::runtime_error("Consistency error in block ranges.");
			}

			uint32 blockSize = (key.end - key.begin) + 4;

			std::vector<uint32> blockCode(blockSize / 4);
			blockCacheStream.Read(blockCode.data(), blockSize);

			auto blockIterator = result.find(key);
			if(blockIterator == std::end(result))
			{
				result.insert(std::make_pair(key, std::move(blockCode)));
			}
			else
			{
				if(!std::equal(std::begin(blockCode), std::end(blockCode), std::begin(blockIterator->second)))
				{
					assert(0);
					throw std::runtime_error("Block with same key already exists but with different data.");
				}
			}

			fileSize -= blockSize + 0x0C;
		}
	}

	return result;
}

void CompileFunctions(CPsfVm& virtualMachine, const AotBlockMap& blocks, CMipsJitter* jitter, Jitter::CObjectFile& objectFile, FunctionTable& functionTable)
{
	functionTable.reserve(functionTable.size() + blocks.size());

	for(const auto& blockCachePair : blocks)
	{
		const auto& blockKey = blockCachePair.first;

		auto functionName = "aotblock_" + std::to_string(blockKey.crc) + "_" + std::to_string(blockKey.begin) + "_" + std::to_string(blockKey.end);

		try
		{
			unsigned int functionSymbolIndex = CompileFunction(virtualMachine, jitter, blockCachePair.second, objectFile, functionName, blockKey.begin, blockKey.end);

			FUNCTION_TABLE_ITEM tableItem = { blockKey, functionSymbolIndex };
			functionTable.push_back(tableItem);
		}
		catch(const std::exception& exception)
		{
			//We failed to add function to the table, we assume that it's because it was
			//already added in a previous pass (in PSP pass after IOP pass has been completed)
			printf("Warning: Failed to add function '%s' in table: %s.\r\n", functionName.c_str(), exception.what());
		}
	}
}

void CompileIopFunctions(const char* databasePathName, CMipsJitter* jitter, Jitter::CObjectFile& objectFile, FunctionTable& functionTable)
{
	filesystem::path databasePath(databasePathName);
	auto blocks = GetBlocksFromCache(databasePath, ".blockcache_iop");

	printf("Got %d IOP blocks to compile.\r\n", blocks.size());

	CPsfVm virtualMachine;
	auto subSystem = std::make_shared<Iop::CPsfSubSystem>(false);
	virtualMachine.SetSubSystem(subSystem);

	CompileFunctions(virtualMachine, blocks, jitter, objectFile, functionTable);
}

void CompilePspFunctions(const char* databasePathName, CMipsJitter* jitter, Jitter::CObjectFile& objectFile, FunctionTable& functionTable)
{
	filesystem::path databasePath(databasePathName);
	auto blocks = GetBlocksFromCache(databasePath, ".blockcache_psp");

	printf("Got %d PSP blocks to compile.\r\n", blocks.size());

	CPsfVm virtualMachine;
	auto subSystem = std::make_shared<Psp::CPsfSubSystem>();
	virtualMachine.SetSubSystem(subSystem);

	CompileFunctions(virtualMachine, blocks, jitter, objectFile, functionTable);
}

void Compile(const char* databasePathName, const char* cpuArchName, const char* imageFormatName, const char* outputPath)
{
	Jitter::CCodeGen* codeGen = nullptr;
	Jitter::CObjectFile::CPU_ARCH cpuArch = Jitter::CObjectFile::CPU_ARCH_X86;
	if(!strcmp(cpuArchName, "x86"))
	{
		codeGen = new Jitter::CCodeGen_x86_32();
		cpuArch = Jitter::CObjectFile::CPU_ARCH_X86;
	}
	else if(!strcmp(cpuArchName, "arm"))
	{
		codeGen = new Jitter::CCodeGen_Arm();
		cpuArch = Jitter::CObjectFile::CPU_ARCH_ARM;
	}
	else
	{
		throw std::runtime_error("Invalid cpu target.");
	}

	std::unique_ptr<Jitter::CObjectFile> objectFile;
	if(!strcmp(imageFormatName, "coff"))
	{
		objectFile = std::make_unique<Jitter::CCoffObjectFile>(cpuArch);
	}
	else if(!strcmp(imageFormatName, "macho"))
	{
		objectFile = std::make_unique<Jitter::CMachoObjectFile>(cpuArch);
	}
	else
	{
		throw std::runtime_error("Invalid executable image type (must be coff or macho).");
	}

	codeGen->RegisterExternalSymbols(objectFile.get());
	objectFile->AddExternalSymbol("_MemoryUtils_GetByteProxy", &MemoryUtils_GetByteProxy);
	objectFile->AddExternalSymbol("_MemoryUtils_GetHalfProxy", &MemoryUtils_GetHalfProxy);
	objectFile->AddExternalSymbol("_MemoryUtils_GetWordProxy", &MemoryUtils_GetWordProxy);
	objectFile->AddExternalSymbol("_MemoryUtils_SetByteProxy", &MemoryUtils_SetByteProxy);
	objectFile->AddExternalSymbol("_MemoryUtils_SetHalfProxy", &MemoryUtils_SetHalfProxy);
	objectFile->AddExternalSymbol("_MemoryUtils_SetWordProxy", &MemoryUtils_SetWordProxy);
	objectFile->AddExternalSymbol("_LWL_Proxy", &LWL_Proxy);
	objectFile->AddExternalSymbol("_LWR_Proxy", &LWR_Proxy);
	objectFile->AddExternalSymbol("_SWL_Proxy", &SWL_Proxy);
	objectFile->AddExternalSymbol("_SWR_Proxy", &SWR_Proxy);

	//Initialize Jitter Service
	auto jitter = new CMipsJitter(codeGen);
	for(unsigned int i = 0; i < 4; i++)
	{
		jitter->SetVariableAsConstant(
			offsetof(CMIPS, m_State.nGPR[CMIPS::R0].nV[i]),
			0
			);
	}

	FunctionTable functionTable;

	CompileIopFunctions(databasePathName, jitter, *objectFile, functionTable);
	CompilePspFunctions(databasePathName, jitter, *objectFile, functionTable);

	std::sort(functionTable.begin(), functionTable.end(),
		[] (const FUNCTION_TABLE_ITEM& item1, const FUNCTION_TABLE_ITEM& item2)
		{
			return item1.key < item2.key;
		}
	);

	//Write out block table
	{
		Framework::CMemStream blockTableStream;
		Jitter::CObjectFile::INTERNAL_SYMBOL blockTableSymbol;
		blockTableSymbol.name		= "__aot_firstBlock";
		blockTableSymbol.location	= Jitter::CObjectFile::INTERNAL_SYMBOL_LOCATION_DATA;

		for(const auto& functionTableItem : functionTable)
		{
			blockTableStream.Write32(functionTableItem.key.crc);
			blockTableStream.Write32(functionTableItem.key.begin);
			blockTableStream.Write32(functionTableItem.key.end);

			{
				Jitter::CObjectFile::SYMBOL_REFERENCE ref;
				ref.offset		= static_cast<uint32>(blockTableStream.Tell());
				ref.type		= Jitter::CObjectFile::SYMBOL_TYPE_INTERNAL;
				ref.symbolIndex	= functionTableItem.symbolIndex;
				blockTableSymbol.symbolReferences.push_back(ref);
			}

			blockTableStream.Write32(0);
		}

		blockTableSymbol.data = std::vector<uint8>(blockTableStream.GetBuffer(), blockTableStream.GetBuffer() + blockTableStream.GetLength());
		objectFile->AddInternalSymbol(blockTableSymbol);
	}

	//Write out block count
	{
		Jitter::CObjectFile::INTERNAL_SYMBOL blockCountSymbol;
		blockCountSymbol.name		= "__aot_blockCount";
		blockCountSymbol.location	= Jitter::CObjectFile::INTERNAL_SYMBOL_LOCATION_DATA;
		blockCountSymbol.data		= std::vector<uint8>(4);
		*reinterpret_cast<uint32*>(blockCountSymbol.data.data()) = functionTable.size();
		objectFile->AddInternalSymbol(blockCountSymbol);
	}

	objectFile->Write(Framework::CStdStream(outputPath, "wb"));
}

void PrintUsage()
{
	printf("PsfAot usage:\r\n");
	printf("\tPsfAot gather [InputFile] [DatabasePath]\r\n");
	printf("\tPsfAot compile [DatabasePath] [x86|x64|arm] [coff|macho] [OutputFile]\r\n");
}

int main(int argc, char** argv)
{
	if(argc <= 2)
	{
		PrintUsage();
		return -1;
	}

	if(!strcmp(argv[1], "gather"))
	{
		if(argc < 4)
		{
			PrintUsage();
			return -1;
		}
		else
		{
			Gather(argv[2], argv[3]);
		}
	}
	else if(!strcmp(argv[1], "compile"))
	{
		if(argc < 6)
		{
			PrintUsage();
			return -1;
		}

		try
		{
			const char* databasePath = argv[2];
			const char* cpuArchName = argv[3];
			const char* imageFormatName = argv[4];
			const char* outputPath = argv[5];
			Compile(databasePath, cpuArchName, imageFormatName, outputPath);
		}
		catch(const std::exception& exception)
		{
			printf("Failed to compile: %s\r\n", exception.what());
			return -1;
		}
	}

	return 0;
}
<commit_msg>Made PsfAot more verbose.<commit_after>#include <boost/filesystem.hpp>
#include "PsfVm.h"
#include "PsfLoader.h"
#include "MemoryUtils.h"
#include "CoffObjectFile.h"
#include "MachoObjectFile.h"
#include "StdStreamUtils.h"
#include "Jitter.h"
#include "Jitter_CodeGen_x86_32.h"
#include "Jitter_CodeGen_Arm.h"
#include "MemStream.h"
#include "Iop_PsfSubSystem.h"
#include "psp/Psp_PsfSubSystem.h"
#include "ThreadPool.h"
#include "Playlist.h"
#include "make_unique.h"

namespace filesystem = boost::filesystem;

struct FUNCTION_TABLE_ITEM
{
	AOT_BLOCK_KEY	key;
	uint32			symbolIndex;
};
typedef std::vector<FUNCTION_TABLE_ITEM> FunctionTable;

typedef std::map<AOT_BLOCK_KEY, std::vector<uint32>> AotBlockMap;

extern "C" uint32 LWL_Proxy(uint32, uint32, CMIPS*);
extern "C" uint32 LWR_Proxy(uint32, uint32, CMIPS*);
extern "C" void SWL_Proxy(uint32, uint32, CMIPS*);
extern "C" void SWR_Proxy(uint32, uint32, CMIPS*);

void Gather(const char* archivePathName, const char* outputPathName)
{
	Framework::CStdStream outputStream(outputPathName, "wb");
	CBasicBlock::SetAotBlockOutputStream(&outputStream);

	{
		Framework::CThreadPool threadPool(std::thread::hardware_concurrency());

		filesystem::path archivePath = filesystem::path(archivePathName);
		auto archive = std::unique_ptr<CPsfArchive>(CPsfArchive::CreateFromPath(archivePath));

		for(const auto& fileInfo : archive->GetFiles())
		{
			filesystem::path archiveItemPath = fileInfo.name;
			filesystem::path archiveItemExtension = archiveItemPath.extension();
			if(CPlaylist::IsLoadableExtension(archiveItemExtension.string().c_str() + 1))
			{
				threadPool.Enqueue(
					[=] ()
					{
						printf("Processing %s...\r\n", archiveItemPath.string().c_str());
						fflush(stdout);

						try
						{
							CPsfVm virtualMachine;

							CPsfLoader::LoadPsf(virtualMachine, archiveItemPath.wstring(), archivePath);
							int currentTime = 0;
							virtualMachine.OnNewFrame.connect(
								[&currentTime] ()
								{
									currentTime += 16;
								});

							virtualMachine.Resume();

#ifdef _DEBUG
							static const unsigned int executionTime = 1;
#else
							static const unsigned int executionTime = 10;
#endif
							while(currentTime <= (executionTime * 60 * 1000))
							{
								std::this_thread::sleep_for(std::chrono::milliseconds(10));
							}

							virtualMachine.Pause();
						}
						catch(const std::exception& exception)
						{
							printf("Failed to process '%s', reason: '%s'.\r\n",
								archiveItemPath.string().c_str(), exception.what());
							fflush(stdout);
							throw;
						}
					}
				);
			}
		}
	}

	CBasicBlock::SetAotBlockOutputStream(nullptr);
}

unsigned int CompileFunction(CPsfVm& virtualMachine, CMipsJitter* jitter, const std::vector<uint32>& blockCode, Jitter::CObjectFile& objectFile, const std::string& functionName, uint32 begin, uint32 end)
{
	auto& context = virtualMachine.GetCpu();

	uint8* ram = virtualMachine.GetRam();
	for(uint32 address = begin; address <= end; address += 4)
	{
		*reinterpret_cast<uint32*>(&ram[address]) = blockCode[(address - begin) / 4];
	}

	{
		Framework::CMemStream outputStream;
		Jitter::CObjectFile::INTERNAL_SYMBOL func;

		jitter->GetCodeGen()->SetExternalSymbolReferencedHandler(
			[&] (void* symbol, uint32 offset)
			{
				Jitter::CObjectFile::SYMBOL_REFERENCE ref;
				ref.offset		= offset;
				ref.type		= Jitter::CObjectFile::SYMBOL_TYPE_EXTERNAL;
				ref.symbolIndex	= objectFile.GetExternalSymbolIndexByValue(symbol);
				func.symbolReferences.push_back(ref);
			}
		);

		jitter->SetStream(&outputStream);
		jitter->Begin();

		for(uint32 address = begin; address <= end; address += 4)
		{
			context.m_pArch->CompileInstruction(address, jitter, &context);
			//Sanity check
			assert(jitter->IsStackEmpty());
		}

		jitter->End();

		func.name		= functionName;
		func.data		= std::vector<uint8>(outputStream.GetBuffer(), outputStream.GetBuffer() + outputStream.GetSize());
		func.location	= Jitter::CObjectFile::INTERNAL_SYMBOL_LOCATION_TEXT;
		return objectFile.AddInternalSymbol(func);
	}
}

AotBlockMap GetBlocksFromCache(const filesystem::path& blockCachePath, const char* cacheFilter)
{
	AotBlockMap result;

	auto path_end = filesystem::directory_iterator();
	for(auto pathIterator = filesystem::directory_iterator(blockCachePath);
		pathIterator != path_end; pathIterator++)
	{
		const auto& filePath = (*pathIterator);
		auto filePathExtension = filePath.path().extension();
		if(filePathExtension.string() != std::string(cacheFilter))
		{
			continue;
		}

		printf("Processing %s...\r\n", filePath.path().string().c_str());

		auto blockCacheStream = Framework::CreateInputStdStream(filePath.path().native());

		uint32 fileSize = blockCacheStream.GetLength();
		while(fileSize != 0)
		{
			AOT_BLOCK_KEY key = {};
			key.crc		= blockCacheStream.Read32();
			key.begin	= blockCacheStream.Read32();
			key.end		= blockCacheStream.Read32();

			if(key.begin > key.end)
			{
				assert(0);
				throw std::runtime_error("Consistency error in block ranges.");
			}

			uint32 blockSize = (key.end - key.begin) + 4;

			std::vector<uint32> blockCode(blockSize / 4);
			blockCacheStream.Read(blockCode.data(), blockSize);

			auto blockIterator = result.find(key);
			if(blockIterator == std::end(result))
			{
				result.insert(std::make_pair(key, std::move(blockCode)));
			}
			else
			{
				if(!std::equal(std::begin(blockCode), std::end(blockCode), std::begin(blockIterator->second)))
				{
					assert(0);
					throw std::runtime_error("Block with same key already exists but with different data.");
				}
			}

			fileSize -= blockSize + 0x0C;
		}
	}

	return result;
}

void CompileFunctions(CPsfVm& virtualMachine, const AotBlockMap& blocks, CMipsJitter* jitter, Jitter::CObjectFile& objectFile, FunctionTable& functionTable)
{
	functionTable.reserve(functionTable.size() + blocks.size());

	for(const auto& blockCachePair : blocks)
	{
		const auto& blockKey = blockCachePair.first;

		auto functionName = "aotblock_" + std::to_string(blockKey.crc) + "_" + std::to_string(blockKey.begin) + "_" + std::to_string(blockKey.end);

		try
		{
			unsigned int functionSymbolIndex = CompileFunction(virtualMachine, jitter, blockCachePair.second, objectFile, functionName, blockKey.begin, blockKey.end);

			FUNCTION_TABLE_ITEM tableItem = { blockKey, functionSymbolIndex };
			functionTable.push_back(tableItem);
		}
		catch(const std::exception& exception)
		{
			//We failed to add function to the table, we assume that it's because it was
			//already added in a previous pass (in PSP pass after IOP pass has been completed)
			printf("Warning: Failed to add function '%s' in table: %s.\r\n", functionName.c_str(), exception.what());
		}
	}
}

void CompileIopFunctions(const char* databasePathName, CMipsJitter* jitter, Jitter::CObjectFile& objectFile, FunctionTable& functionTable)
{
	filesystem::path databasePath(databasePathName);
	auto blocks = GetBlocksFromCache(databasePath, ".blockcache_iop");

	printf("Got %d IOP blocks to compile.\r\n", blocks.size());

	CPsfVm virtualMachine;
	auto subSystem = std::make_shared<Iop::CPsfSubSystem>(false);
	virtualMachine.SetSubSystem(subSystem);

	CompileFunctions(virtualMachine, blocks, jitter, objectFile, functionTable);
}

void CompilePspFunctions(const char* databasePathName, CMipsJitter* jitter, Jitter::CObjectFile& objectFile, FunctionTable& functionTable)
{
	filesystem::path databasePath(databasePathName);
	auto blocks = GetBlocksFromCache(databasePath, ".blockcache_psp");

	printf("Got %d PSP blocks to compile.\r\n", blocks.size());

	CPsfVm virtualMachine;
	auto subSystem = std::make_shared<Psp::CPsfSubSystem>();
	virtualMachine.SetSubSystem(subSystem);

	CompileFunctions(virtualMachine, blocks, jitter, objectFile, functionTable);
}

void Compile(const char* databasePathName, const char* cpuArchName, const char* imageFormatName, const char* outputPath)
{
	Jitter::CCodeGen* codeGen = nullptr;
	Jitter::CObjectFile::CPU_ARCH cpuArch = Jitter::CObjectFile::CPU_ARCH_X86;
	if(!strcmp(cpuArchName, "x86"))
	{
		codeGen = new Jitter::CCodeGen_x86_32();
		cpuArch = Jitter::CObjectFile::CPU_ARCH_X86;
	}
	else if(!strcmp(cpuArchName, "arm"))
	{
		codeGen = new Jitter::CCodeGen_Arm();
		cpuArch = Jitter::CObjectFile::CPU_ARCH_ARM;
	}
	else
	{
		throw std::runtime_error("Invalid cpu target.");
	}

	std::unique_ptr<Jitter::CObjectFile> objectFile;
	if(!strcmp(imageFormatName, "coff"))
	{
		objectFile = std::make_unique<Jitter::CCoffObjectFile>(cpuArch);
	}
	else if(!strcmp(imageFormatName, "macho"))
	{
		objectFile = std::make_unique<Jitter::CMachoObjectFile>(cpuArch);
	}
	else
	{
		throw std::runtime_error("Invalid executable image type (must be coff or macho).");
	}

	codeGen->RegisterExternalSymbols(objectFile.get());
	objectFile->AddExternalSymbol("_MemoryUtils_GetByteProxy", &MemoryUtils_GetByteProxy);
	objectFile->AddExternalSymbol("_MemoryUtils_GetHalfProxy", &MemoryUtils_GetHalfProxy);
	objectFile->AddExternalSymbol("_MemoryUtils_GetWordProxy", &MemoryUtils_GetWordProxy);
	objectFile->AddExternalSymbol("_MemoryUtils_SetByteProxy", &MemoryUtils_SetByteProxy);
	objectFile->AddExternalSymbol("_MemoryUtils_SetHalfProxy", &MemoryUtils_SetHalfProxy);
	objectFile->AddExternalSymbol("_MemoryUtils_SetWordProxy", &MemoryUtils_SetWordProxy);
	objectFile->AddExternalSymbol("_LWL_Proxy", &LWL_Proxy);
	objectFile->AddExternalSymbol("_LWR_Proxy", &LWR_Proxy);
	objectFile->AddExternalSymbol("_SWL_Proxy", &SWL_Proxy);
	objectFile->AddExternalSymbol("_SWR_Proxy", &SWR_Proxy);

	//Initialize Jitter Service
	auto jitter = new CMipsJitter(codeGen);
	for(unsigned int i = 0; i < 4; i++)
	{
		jitter->SetVariableAsConstant(
			offsetof(CMIPS, m_State.nGPR[CMIPS::R0].nV[i]),
			0
			);
	}

	FunctionTable functionTable;

	CompileIopFunctions(databasePathName, jitter, *objectFile, functionTable);
	CompilePspFunctions(databasePathName, jitter, *objectFile, functionTable);

	std::sort(functionTable.begin(), functionTable.end(),
		[] (const FUNCTION_TABLE_ITEM& item1, const FUNCTION_TABLE_ITEM& item2)
		{
			return item1.key < item2.key;
		}
	);

	//Write out block table
	{
		Framework::CMemStream blockTableStream;
		Jitter::CObjectFile::INTERNAL_SYMBOL blockTableSymbol;
		blockTableSymbol.name		= "__aot_firstBlock";
		blockTableSymbol.location	= Jitter::CObjectFile::INTERNAL_SYMBOL_LOCATION_DATA;

		for(const auto& functionTableItem : functionTable)
		{
			blockTableStream.Write32(functionTableItem.key.crc);
			blockTableStream.Write32(functionTableItem.key.begin);
			blockTableStream.Write32(functionTableItem.key.end);

			{
				Jitter::CObjectFile::SYMBOL_REFERENCE ref;
				ref.offset		= static_cast<uint32>(blockTableStream.Tell());
				ref.type		= Jitter::CObjectFile::SYMBOL_TYPE_INTERNAL;
				ref.symbolIndex	= functionTableItem.symbolIndex;
				blockTableSymbol.symbolReferences.push_back(ref);
			}

			blockTableStream.Write32(0);
		}

		blockTableSymbol.data = std::vector<uint8>(blockTableStream.GetBuffer(), blockTableStream.GetBuffer() + blockTableStream.GetLength());
		objectFile->AddInternalSymbol(blockTableSymbol);
	}

	//Write out block count
	{
		Jitter::CObjectFile::INTERNAL_SYMBOL blockCountSymbol;
		blockCountSymbol.name		= "__aot_blockCount";
		blockCountSymbol.location	= Jitter::CObjectFile::INTERNAL_SYMBOL_LOCATION_DATA;
		blockCountSymbol.data		= std::vector<uint8>(4);
		*reinterpret_cast<uint32*>(blockCountSymbol.data.data()) = functionTable.size();
		objectFile->AddInternalSymbol(blockCountSymbol);
	}

	objectFile->Write(Framework::CStdStream(outputPath, "wb"));
}

void PrintUsage()
{
	printf("PsfAot usage:\r\n");
	printf("\tPsfAot gather [InputFile] [DatabasePath]\r\n");
	printf("\tPsfAot compile [DatabasePath] [x86|x64|arm] [coff|macho] [OutputFile]\r\n");
}

int main(int argc, char** argv)
{
	if(argc <= 2)
	{
		PrintUsage();
		return -1;
	}

	if(!strcmp(argv[1], "gather"))
	{
		if(argc < 4)
		{
			PrintUsage();
			return -1;
		}

		try
		{
			Gather(argv[2], argv[3]);
		}
		catch(const std::exception& exception)
		{
			printf("Failed to gather: %s\r\n", exception.what());
			return -1;
		}
	}
	else if(!strcmp(argv[1], "compile"))
	{
		if(argc < 6)
		{
			PrintUsage();
			return -1;
		}

		try
		{
			const char* databasePath = argv[2];
			const char* cpuArchName = argv[3];
			const char* imageFormatName = argv[4];
			const char* outputPath = argv[5];
			Compile(databasePath, cpuArchName, imageFormatName, outputPath);
		}
		catch(const std::exception& exception)
		{
			printf("Failed to compile: %s\r\n", exception.what());
			return -1;
		}
	}

	return 0;
}
<|endoftext|>


<commit_before>#include "oglWidget.h"

//
// CONSTRUCTORS ////////////////////////////////////////////////////////////////
//

/**
 * @brief      Default constructor for OGLWidget.
 */
OGLWidget::OGLWidget()
{
    // Update the widget after a frameswap
    connect( this, SIGNAL( frameSwapped() ),
        this, SLOT( update() ) );

    // Allows keyboard input to fall through
    setFocusPolicy( Qt::ClickFocus );

    // Setup the Camera
    camera.rotate( -40.0f, 1.0f, 0.0f, 0.0f );
    camera.translate( 0.0f, 30.0f, 45.0f );

    renderables.push_back( new Sun() );
    renderables.push_back( new Skybox() );

    // this is so all the planets aren't stacked together in the beginning
    for( auto renderable : renderables )
    {
        renderable->update();
    }
}

/**
 * @brief      Destructor class to unallocate OpenGL information.
 */
OGLWidget::~OGLWidget()
{
    makeCurrent();
    teardownGL();
}

//
// OPENGL FUNCTIONS ////////////////////////////////////////////////////////////
//

void OGLWidget::initializeGL()
{
    // Init OpenGL Backend
    initializeOpenGLFunctions();
    printContextInfo();

    QVectorIterator<Renderable*> i_renderable( renderables );
    while( i_renderable.hasNext() )
    {
        ( i_renderable.next() )->initializeGL();
    }
}

/**
 * @brief      Sets the prespective whenever the window is resized.
 *
 * @param[in]  width   The width of the new window.
 * @param[in]  height  The height of the new window.
 */
void OGLWidget::resizeGL( int width, int height )
{
    projection.setToIdentity();
    projection.perspective( 55.0f,  // Field of view angle
                            float( width ) / float( height ),   // Aspect Ratio
                            0.01f,  // Near Plane (MUST BE GREATER THAN 0)
                            1000.0f );  // Far Plane
}

/**
 * @brief      OpenGL function to draw elements to the surface.
 */
void OGLWidget::paintGL()
{
    glEnable( GL_DEPTH_TEST );
    glDepthFunc( GL_LEQUAL );
    glDepthMask( GL_TRUE );
    glEnable( GL_CULL_FACE );
    glClearColor( 0.0f, 0.0f, 0.2f, 1.0f );

    // Clear the screen
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    QVectorIterator<Renderable*> i_renderable( renderables );
    while( i_renderable.hasNext() )
    {
        ( i_renderable.next() )->paintGL( camera, projection );
    }
}

/**
 * @brief      Destroys any OpenGL data.
 */
void OGLWidget::teardownGL()
{
    QVectorIterator<Renderable*> i_renderable( renderables );
    while( i_renderable.hasNext() )
    {
        ( i_renderable.next() )->teardownGL();
    }
}

//
// QT SLOTS ////////////////////////////////////////////////////////////////////
//

/**
 * @brief      Updates any user interactions and model transformations.
 */
void OGLWidget::update()
{
    Input::update();

    // Camera Transforms
    if( Input::buttonPressed( Qt::RightButton ) )
    {
        static const float cameraTranslationSpeed = 0.3f;
        static const float cameraRotationSpeed = 0.1f;

        camera.rotate( -cameraRotationSpeed * Input::mouseDelta().x(),
            Camera3D::LocalUp );
        camera.rotate( -cameraRotationSpeed * Input::mouseDelta().y(),
            camera.right() );

        QVector3D cameraTranslations;
        if( Input::keyPressed( Qt::Key_W ) )
            cameraTranslations += camera.forward();
        if( Input::keyPressed( Qt::Key_S ) )
            cameraTranslations -= camera.forward();
        if( Input::keyPressed( Qt::Key_A ) )
            cameraTranslations -= camera.right();
        if( Input::keyPressed( Qt::Key_D ) )
            cameraTranslations += camera.right();
        if( Input::keyPressed( Qt::Key_Q ) )
            cameraTranslations -= camera.up();
        if( Input::keyPressed( Qt::Key_E ) )
            cameraTranslations += camera.up();
        camera.translate( cameraTranslationSpeed * cameraTranslations );
    }

    if( !paused )
    {
        for( auto renderable : renderables )
        {
            renderable->update();
        }
    }

    QOpenGLWidget::update();
}

/**
* @brief      Slot for pausing/unpausing.
*/
void OGLWidget::swapPause()
{
    paused = !paused;
}

void OGLWidget::swapScaledView()
{
    Planet::SCALED = !Planet::SCALED;
}

//
// INPUT EVENTS ////////////////////////////////////////////////////////////////
//

/**
 * @brief      Default slot for handling key press events.
 *
 * @param      event  The key event information.
 */
void OGLWidget::keyPressEvent( QKeyEvent* event )
{
    if( event->isAutoRepeat() )
        event->ignore();
    else
        Input::registerKeyPress( event->key() );
}

/**
 * @brief      Default slot for handling key release events.
 *
 * @param      event  The key event information.
 */
void OGLWidget::keyReleaseEvent( QKeyEvent* event )
{
    if( event->isAutoRepeat() )
        event->ignore();
    else
        Input::registerKeyRelease( event->key() );
}

/**
 * @brief      Default slot for handling mouse press events.
 *
 * @param      event  The mouse event information.
 */
void OGLWidget::mousePressEvent( QMouseEvent* event )
{
    Input::registerMousePress( event->button() );
}

/**
 * @brief      Default slot for handling mouse release events.
 *
 * @param      event  The mouse event information.
 */
void OGLWidget::mouseReleaseEvent( QMouseEvent* event )
{
    Input::registerMouseRelease( event->button() );
}

//
// PRIVATE HELPER FUNCTIONS ////////////////////////////////////////////////////
//

/**
 * @brief      Helper function to print OpenGL Context information to the debug.
 */
void OGLWidget::printContextInfo()
{
    QString glType;
    QString glVersion;
    QString glProfile;

    // Get Version Information
    glType = ( context()->isOpenGLES() ) ? "OpenGL ES" : "OpenGL";
    glVersion = reinterpret_cast<const char*>( glGetString( GL_VERSION ) );

    // Get Profile Information
    switch( format().profile() )
    {
        case QSurfaceFormat::NoProfile:
            glProfile = "No Profile";
            break;
        case QSurfaceFormat::CoreProfile:
            glProfile = "Core Profile";
            break;
        case QSurfaceFormat::CompatibilityProfile:
            glProfile = "Compatibility Profile";
            break;
    }

    qDebug() << qPrintable( glType ) << qPrintable( glVersion ) <<
        "(" << qPrintable( glProfile ) << ")";
}<commit_msg>Can update scale when paused. Allows someone to update through pause by holding ctrl+r<commit_after>#include "oglWidget.h"

//
// CONSTRUCTORS ////////////////////////////////////////////////////////////////
//

/**
 * @brief      Default constructor for OGLWidget.
 */
OGLWidget::OGLWidget()
{
    // Update the widget after a frameswap
    connect( this, SIGNAL( frameSwapped() ),
        this, SLOT( update() ) );

    // Allows keyboard input to fall through
    setFocusPolicy( Qt::ClickFocus );

    // Setup the Camera
    camera.rotate( -40.0f, 1.0f, 0.0f, 0.0f );
    camera.translate( 0.0f, 30.0f, 45.0f );

    renderables.push_back( new Sun() );
    renderables.push_back( new Skybox() );

    // update the solar system once in the beginning
    // this is so all the planets aren't stacked on top of each other
    renderables[0]->update();
}

/**
 * @brief      Destructor class to unallocate OpenGL information.
 */
OGLWidget::~OGLWidget()
{
    makeCurrent();
    teardownGL();
}

//
// OPENGL FUNCTIONS ////////////////////////////////////////////////////////////
//

void OGLWidget::initializeGL()
{
    // Init OpenGL Backend
    initializeOpenGLFunctions();
    printContextInfo();

    QVectorIterator<Renderable*> i_renderable( renderables );
    while( i_renderable.hasNext() )
    {
        ( i_renderable.next() )->initializeGL();
    }
}

/**
 * @brief      Sets the prespective whenever the window is resized.
 *
 * @param[in]  width   The width of the new window.
 * @param[in]  height  The height of the new window.
 */
void OGLWidget::resizeGL( int width, int height )
{
    projection.setToIdentity();
    projection.perspective( 55.0f,  // Field of view angle
                            float( width ) / float( height ),   // Aspect Ratio
                            0.01f,  // Near Plane (MUST BE GREATER THAN 0)
                            1000.0f );  // Far Plane
}

/**
 * @brief      OpenGL function to draw elements to the surface.
 */
void OGLWidget::paintGL()
{
    glEnable( GL_DEPTH_TEST );
    glDepthFunc( GL_LEQUAL );
    glDepthMask( GL_TRUE );
    glEnable( GL_CULL_FACE );
    glClearColor( 0.0f, 0.0f, 0.2f, 1.0f );

    // Clear the screen
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    QVectorIterator<Renderable*> i_renderable( renderables );
    while( i_renderable.hasNext() )
    {
        ( i_renderable.next() )->paintGL( camera, projection );
    }
}

/**
 * @brief      Destroys any OpenGL data.
 */
void OGLWidget::teardownGL()
{
    QVectorIterator<Renderable*> i_renderable( renderables );
    while( i_renderable.hasNext() )
    {
        ( i_renderable.next() )->teardownGL();
    }
}

//
// QT SLOTS ////////////////////////////////////////////////////////////////////
//

/**
 * @brief      Updates any user interactions and model transformations.
 */
void OGLWidget::update()
{
    Input::update();

    // Camera Transforms
    if( Input::buttonPressed( Qt::RightButton ) )
    {
        static const float cameraTranslationSpeed = 0.3f;
        static const float cameraRotationSpeed = 0.1f;

        camera.rotate( -cameraRotationSpeed * Input::mouseDelta().x(),
            Camera3D::LocalUp );
        camera.rotate( -cameraRotationSpeed * Input::mouseDelta().y(),
            camera.right() );

        QVector3D cameraTranslations;
        if( Input::keyPressed( Qt::Key_W ) )
            cameraTranslations += camera.forward();
        if( Input::keyPressed( Qt::Key_S ) )
            cameraTranslations -= camera.forward();
        if( Input::keyPressed( Qt::Key_A ) )
            cameraTranslations -= camera.right();
        if( Input::keyPressed( Qt::Key_D ) )
            cameraTranslations += camera.right();
        if( Input::keyPressed( Qt::Key_Q ) )
            cameraTranslations -= camera.up();
        if( Input::keyPressed( Qt::Key_E ) )
            cameraTranslations += camera.up();
        camera.translate( cameraTranslationSpeed * cameraTranslations );
    }

    if( !paused )
    {
        for( auto renderable : renderables )
        {
            renderable->update();
        }
    }

    QOpenGLWidget::update();
}

/**
* @brief      Slot for pausing/unpausing.
*/
void OGLWidget::swapPause()
{
    paused = !paused;
}

void OGLWidget::swapScaledView()
{
    Planet::SCALED = !Planet::SCALED;

    // want to see the scale change even if paused
    if(paused)
    {
        renderables[0]->update();
    }
}

//
// INPUT EVENTS ////////////////////////////////////////////////////////////////
//

/**
 * @brief      Default slot for handling key press events.
 *
 * @param      event  The key event information.
 */
void OGLWidget::keyPressEvent( QKeyEvent* event )
{
    if( event->isAutoRepeat() )
        event->ignore();
    else
        Input::registerKeyPress( event->key() );
}

/**
 * @brief      Default slot for handling key release events.
 *
 * @param      event  The key event information.
 */
void OGLWidget::keyReleaseEvent( QKeyEvent* event )
{
    if( event->isAutoRepeat() )
        event->ignore();
    else
        Input::registerKeyRelease( event->key() );
}

/**
 * @brief      Default slot for handling mouse press events.
 *
 * @param      event  The mouse event information.
 */
void OGLWidget::mousePressEvent( QMouseEvent* event )
{
    Input::registerMousePress( event->button() );
}

/**
 * @brief      Default slot for handling mouse release events.
 *
 * @param      event  The mouse event information.
 */
void OGLWidget::mouseReleaseEvent( QMouseEvent* event )
{
    Input::registerMouseRelease( event->button() );
}

//
// PRIVATE HELPER FUNCTIONS ////////////////////////////////////////////////////
//

/**
 * @brief      Helper function to print OpenGL Context information to the debug.
 */
void OGLWidget::printContextInfo()
{
    QString glType;
    QString glVersion;
    QString glProfile;

    // Get Version Information
    glType = ( context()->isOpenGLES() ) ? "OpenGL ES" : "OpenGL";
    glVersion = reinterpret_cast<const char*>( glGetString( GL_VERSION ) );

    // Get Profile Information
    switch( format().profile() )
    {
        case QSurfaceFormat::NoProfile:
            glProfile = "No Profile";
            break;
        case QSurfaceFormat::CoreProfile:
            glProfile = "Core Profile";
            break;
        case QSurfaceFormat::CompatibilityProfile:
            glProfile = "Compatibility Profile";
            break;
    }

    qDebug() << qPrintable( glType ) << qPrintable( glVersion ) <<
        "(" << qPrintable( glProfile ) << ")";
}<|endoftext|>