<commit_before>#include <mos/gfx/light.hpp>
#include <glm/gtx/transform.hpp>
#include <filesystem/path.h>
#include <json.hpp>
#include <mos/util.hpp>

namespace mos {
namespace gfx {
Light::Light(const glm::vec3 &position,
             const glm::vec3 &center,
             const float angle,
             const glm::vec3 &color,
             const float strength,
             const float near_plane,
             const float far_plane)
    : color(color), angle_(angle),
      camera(position, center, glm::perspective(angle, 1.0f, near_plane, far_plane),
             glm::vec3(0.0f, 0.0001f, 1.0f)), strength(strength), near_(near), far_(far) {}

void Light::position(const glm::vec3 &position) {
  camera.position(position);
}

glm::vec3 Light::position() const {
  return camera.position();
}

void Light::angle(const float angle) {
  angle_ = angle;
  camera.projection = glm::perspective(angle_, 1.0f, near_, far_);
}

float Light::angle() const {
  return angle_;
}

void Light::center(const glm::vec3 &center) {
  camera.center(center);
}

glm::vec3 Light::center() const {
  return camera.center();
}

glm::vec3 Light::direction() const {
  return camera.direction();
}

void Light::near_far(const float near_plane, const float far_plane) {
  near_ = near_plane;
  far_ = far_plane;
  camera.projection = glm::perspective(angle_, 1.0f, near_, far_);

}
Light::Light(const std::string &directory, const std::string &path, const float near_plane, const float far_plane,
    const glm::mat4 &parent_transform) : near_(near_plane), far_(far_plane) {
  using json = nlohmann::json;
  if (!path.empty()) {
    filesystem::path fpath = path;
    if (fpath.extension() == "light") {
      auto value = json::parse(mos::text(directory + fpath.str()));

      auto transform = parent_transform * jsonarray_to_mat4(value["transform"]);
      auto position = glm::vec3(transform[3]);
      auto center = position + glm::vec3(transform * glm::vec4(0.0f, 0.0f, -1.0f, 0.0f));

      std::string t = value["light"];
      auto data_value = json::parse(mos::text(directory + t));

      color = glm::vec3(data_value["color"][0],
                             data_value["color"][1],
                             data_value["color"][2]);
      strength = data_value["strength"];
      angle_ = data_value["size"];
      auto blend = value["blend"];

      camera = mos::gfx::Camera(position, center, glm::perspective(angle_, 1.0f, near_plane, far_plane),
             glm::vec3(0.0f, 0.0001f, 1.0f));

    } else {
      throw std::runtime_error(path.substr(path.find_last_of(".")) +
          " file format is not supported.");
    }
  }
}
}
}<commit_msg>Near far.<commit_after>#include <mos/gfx/light.hpp>
#include <glm/gtx/transform.hpp>
#include <filesystem/path.h>
#include <json.hpp>
#include <mos/util.hpp>

namespace mos {
namespace gfx {
Light::Light(const glm::vec3 &position,
             const glm::vec3 &center,
             const float angle,
             const glm::vec3 &color,
             const float strength,
             const float near_plane,
             const float far_plane)
    : color(color), angle_(angle),
      camera(position, center, glm::perspective(angle, 1.0f, near_plane, far_plane),
             glm::vec3(0.0f, 0.0001f, 1.0f)), strength(strength), near_(near_plane), far_(far_plane) {}

void Light::position(const glm::vec3 &position) {
  camera.position(position);
}

glm::vec3 Light::position() const {
  return camera.position();
}

void Light::angle(const float angle) {
  angle_ = angle;
  camera.projection = glm::perspective(angle_, 1.0f, near_, far_);
}

float Light::angle() const {
  return angle_;
}

void Light::center(const glm::vec3 &center) {
  camera.center(center);
}

glm::vec3 Light::center() const {
  return camera.center();
}

glm::vec3 Light::direction() const {
  return camera.direction();
}

void Light::near_far(const float near_plane, const float far_plane) {
  near_ = near_plane;
  far_ = far_plane;
  camera.projection = glm::perspective(angle_, 1.0f, near_, far_);

}
Light::Light(const std::string &directory, const std::string &path, const float near_plane, const float far_plane,
    const glm::mat4 &parent_transform) : near_(near_plane), far_(far_plane) {
  using json = nlohmann::json;
  if (!path.empty()) {
    filesystem::path fpath = path;
    if (fpath.extension() == "light") {
      auto value = json::parse(mos::text(directory + fpath.str()));

      auto transform = parent_transform * jsonarray_to_mat4(value["transform"]);
      auto position = glm::vec3(transform[3]);
      auto center = position + glm::vec3(transform * glm::vec4(0.0f, 0.0f, -1.0f, 0.0f));

      std::string t = value["light"];
      auto data_value = json::parse(mos::text(directory + t));

      color = glm::vec3(data_value["color"][0],
                             data_value["color"][1],
                             data_value["color"][2]);
      strength = data_value["strength"];
      angle_ = data_value["size"];
      auto blend = value["blend"];

      camera = mos::gfx::Camera(position, center, glm::perspective(angle_, 1.0f, near_plane, far_plane),
             glm::vec3(0.0f, 0.0001f, 1.0f));

    } else {
      throw std::runtime_error(path.substr(path.find_last_of(".")) +
          " file format is not supported.");
    }
  }
}
}
}<|endoftext|>


<commit_before>/*

Copyright (c) 2008, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include <cctype>
#include <algorithm>
#include <stdlib.h>

#include "libtorrent/config.hpp"
#include "libtorrent/http_parser.hpp"
#include "libtorrent/assert.hpp"

using namespace libtorrent;

namespace
{
	char to_lower(char c) { return std::tolower(c); }
}

namespace libtorrent
{
	http_parser::http_parser()
		: m_recv_pos(0)
		, m_status_code(-1)
		, m_content_length(-1)
		, m_state(read_status)
		, m_recv_buffer(0, 0)
		, m_body_start_pos(0)
		, m_finished(false)
	{}

	boost::tuple<int, int> http_parser::incoming(
		buffer::const_interval recv_buffer, bool& error)
	{
		TORRENT_ASSERT(recv_buffer.left() >= m_recv_buffer.left());
		boost::tuple<int, int> ret(0, 0);
		int start_pos = m_recv_buffer.left();

		// early exit if there's nothing new in the receive buffer
		if (start_pos == recv_buffer.left()) return ret;
		m_recv_buffer = recv_buffer;

		if (m_state == error_state)
		{
			error = true;
			return ret;
		}

		char const* pos = recv_buffer.begin + m_recv_pos;
		if (m_state == read_status)
		{
			TORRENT_ASSERT(!m_finished);
			char const* newline = std::find(pos, recv_buffer.end, '\n');
			// if we don't have a full line yet, wait.
			if (newline == recv_buffer.end)
			{
				boost::get<1>(ret) += m_recv_buffer.left() - start_pos;
				return ret;
			}

			if (newline == pos)
			{
				m_state = error_state;
				error = true;
				return ret;
			}

			char const* line_end = newline;
			if (pos != line_end && *(line_end - 1) == '\r') --line_end;

			std::istringstream line(std::string(pos, line_end));
			++newline;
			int incoming = (int)std::distance(pos, newline);
			m_recv_pos += incoming;
			boost::get<1>(ret) += newline - (m_recv_buffer.begin + start_pos);
			pos = newline;

			line >> m_protocol;
			if (m_protocol.substr(0, 5) == "HTTP/")
			{
				line >> m_status_code;
				std::getline(line, m_server_message);
			}
			else
			{
				m_method = m_protocol;
				std::transform(m_method.begin(), m_method.end(), m_method.begin(), &to_lower);
				m_protocol.clear();
				line >> m_path >> m_protocol;
				m_status_code = 0;
			}
			m_state = read_header;
			start_pos = pos - recv_buffer.begin;
		}

		if (m_state == read_header)
		{
			TORRENT_ASSERT(!m_finished);
			char const* newline = std::find(pos, recv_buffer.end, '\n');
			std::string line;

			while (newline != recv_buffer.end && m_state == read_header)
			{
				// if the LF character is preceeded by a CR
				// charachter, don't copy it into the line string.
				char const* line_end = newline;
				if (pos != line_end && *(line_end - 1) == '\r') --line_end;
				line.assign(pos, line_end);
				++newline;
				m_recv_pos += newline - pos;
				pos = newline;

				std::string::size_type separator = line.find(':');
				if (separator == std::string::npos)
				{
					// this means we got a blank line,
					// the header is finished and the body
					// starts.
					m_state = read_body;
					m_body_start_pos = m_recv_pos;
					break;
				}

				std::string name = line.substr(0, separator);
				std::transform(name.begin(), name.end(), name.begin(), &to_lower);
				++separator;
				// skip whitespace
				while (separator < line.size()
					&& (line[separator] == ' ' || line[separator] == '\t'))
					++separator;
				std::string value = line.substr(separator, std::string::npos);
				m_header.insert(std::make_pair(name, value));

				if (name == "content-length")
				{
#ifdef TORRENT_WINDOWS
					m_content_length = _atoi64(value.c_str());
#else
					m_content_length = atoll(value.c_str());
#endif
				}
				else if (name == "content-range")
				{
					std::stringstream range_str(value);
					char dummy;
					std::string bytes;
					size_type range_start, range_end;
					// apparently some web servers do not send the "bytes"
					// in their content-range
					if (value.find(' ') != std::string::npos)
						range_str >> bytes;
					range_str >> range_start >> dummy >> range_end;
					if (!range_str || range_end < range_start)
					{
						m_state = error_state;
						error = true;
						return ret;
					}
					// the http range is inclusive
					m_content_length = range_end - range_start + 1;
				}

				TORRENT_ASSERT(m_recv_pos <= (int)recv_buffer.left());
				newline = std::find(pos, recv_buffer.end, '\n');
			}
			boost::get<1>(ret) += newline - (m_recv_buffer.begin + start_pos);
		}

		if (m_state == read_body)
		{
			int incoming = recv_buffer.end - pos;
			if (m_recv_pos - m_body_start_pos + incoming > m_content_length
				&& m_content_length >= 0)
				incoming = m_content_length - m_recv_pos + m_body_start_pos;

			TORRENT_ASSERT(incoming >= 0);
			m_recv_pos += incoming;
			boost::get<0>(ret) += incoming;

			if (m_content_length >= 0
				&& m_recv_pos - m_body_start_pos >= m_content_length)
			{
				m_finished = true;
			}
		}
		return ret;
	}

	buffer::const_interval http_parser::get_body() const
	{
		TORRENT_ASSERT(m_state == read_body);
		if (m_content_length >= 0)
			return buffer::const_interval(m_recv_buffer.begin + m_body_start_pos
				, m_recv_buffer.begin + (std::min)(size_type(m_recv_pos)
				, m_body_start_pos + m_content_length));
		else
			return buffer::const_interval(m_recv_buffer.begin + m_body_start_pos
				, m_recv_buffer.begin + m_recv_pos);
	}

	void http_parser::reset()
	{
		m_recv_pos = 0;
		m_body_start_pos = 0;
		m_status_code = -1;
		m_content_length = -1;
		m_finished = false;
		m_state = read_status;
		m_recv_buffer.begin = 0;
		m_recv_buffer.end = 0;
		m_header.clear();
	}

}

<commit_msg>fix to http_parser when used to parse requests instead of responses<commit_after>/*

Copyright (c) 2008, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include <cctype>
#include <algorithm>
#include <stdlib.h>

#include "libtorrent/config.hpp"
#include "libtorrent/http_parser.hpp"
#include "libtorrent/assert.hpp"

using namespace libtorrent;

namespace
{
	char to_lower(char c) { return std::tolower(c); }
}

namespace libtorrent
{
	http_parser::http_parser()
		: m_recv_pos(0)
		, m_status_code(-1)
		, m_content_length(-1)
		, m_state(read_status)
		, m_recv_buffer(0, 0)
		, m_body_start_pos(0)
		, m_finished(false)
	{}

	boost::tuple<int, int> http_parser::incoming(
		buffer::const_interval recv_buffer, bool& error)
	{
		TORRENT_ASSERT(recv_buffer.left() >= m_recv_buffer.left());
		boost::tuple<int, int> ret(0, 0);
		int start_pos = m_recv_buffer.left();

		// early exit if there's nothing new in the receive buffer
		if (start_pos == recv_buffer.left()) return ret;
		m_recv_buffer = recv_buffer;

		if (m_state == error_state)
		{
			error = true;
			return ret;
		}

		char const* pos = recv_buffer.begin + m_recv_pos;
		if (m_state == read_status)
		{
			TORRENT_ASSERT(!m_finished);
			char const* newline = std::find(pos, recv_buffer.end, '\n');
			// if we don't have a full line yet, wait.
			if (newline == recv_buffer.end)
			{
				boost::get<1>(ret) += m_recv_buffer.left() - start_pos;
				return ret;
			}

			if (newline == pos)
			{
				m_state = error_state;
				error = true;
				return ret;
			}

			char const* line_end = newline;
			if (pos != line_end && *(line_end - 1) == '\r') --line_end;

			std::istringstream line(std::string(pos, line_end));
			++newline;
			int incoming = (int)std::distance(pos, newline);
			m_recv_pos += incoming;
			boost::get<1>(ret) += newline - (m_recv_buffer.begin + start_pos);
			pos = newline;

			line >> m_protocol;
			if (m_protocol.substr(0, 5) == "HTTP/")
			{
				line >> m_status_code;
				std::getline(line, m_server_message);
			}
			else
			{
				m_method = m_protocol;
				std::transform(m_method.begin(), m_method.end(), m_method.begin(), &to_lower);
				m_protocol.clear();
				line >> m_path >> m_protocol;
				m_status_code = 0;
			}
			m_state = read_header;
			start_pos = pos - recv_buffer.begin;
		}

		if (m_state == read_header)
		{
			TORRENT_ASSERT(!m_finished);
			char const* newline = std::find(pos, recv_buffer.end, '\n');
			std::string line;

			while (newline != recv_buffer.end && m_state == read_header)
			{
				// if the LF character is preceeded by a CR
				// charachter, don't copy it into the line string.
				char const* line_end = newline;
				if (pos != line_end && *(line_end - 1) == '\r') --line_end;
				line.assign(pos, line_end);
				++newline;
				m_recv_pos += newline - pos;
				pos = newline;

				std::string::size_type separator = line.find(':');
				if (separator == std::string::npos)
				{
					// this means we got a blank line,
					// the header is finished and the body
					// starts.
					m_state = read_body;
					// if this is a request (not a response)
					// we're done once we reach the end of the headers
					if (!m_method.empty()) m_finished = true;
					m_body_start_pos = m_recv_pos;
					break;
				}

				std::string name = line.substr(0, separator);
				std::transform(name.begin(), name.end(), name.begin(), &to_lower);
				++separator;
				// skip whitespace
				while (separator < line.size()
					&& (line[separator] == ' ' || line[separator] == '\t'))
					++separator;
				std::string value = line.substr(separator, std::string::npos);
				m_header.insert(std::make_pair(name, value));

				if (name == "content-length")
				{
#ifdef TORRENT_WINDOWS
					m_content_length = _atoi64(value.c_str());
#else
					m_content_length = atoll(value.c_str());
#endif
				}
				else if (name == "content-range")
				{
					std::stringstream range_str(value);
					char dummy;
					std::string bytes;
					size_type range_start, range_end;
					// apparently some web servers do not send the "bytes"
					// in their content-range
					if (value.find(' ') != std::string::npos)
						range_str >> bytes;
					range_str >> range_start >> dummy >> range_end;
					if (!range_str || range_end < range_start)
					{
						m_state = error_state;
						error = true;
						return ret;
					}
					// the http range is inclusive
					m_content_length = range_end - range_start + 1;
				}

				TORRENT_ASSERT(m_recv_pos <= (int)recv_buffer.left());
				newline = std::find(pos, recv_buffer.end, '\n');
			}
			boost::get<1>(ret) += newline - (m_recv_buffer.begin + start_pos);
		}

		if (m_state == read_body)
		{
			int incoming = recv_buffer.end - pos;
			if (m_recv_pos - m_body_start_pos + incoming > m_content_length
				&& m_content_length >= 0)
				incoming = m_content_length - m_recv_pos + m_body_start_pos;

			TORRENT_ASSERT(incoming >= 0);
			m_recv_pos += incoming;
			boost::get<0>(ret) += incoming;

			if (m_content_length >= 0
				&& m_recv_pos - m_body_start_pos >= m_content_length)
			{
				m_finished = true;
			}
		}
		return ret;
	}

	buffer::const_interval http_parser::get_body() const
	{
		TORRENT_ASSERT(m_state == read_body);
		if (m_content_length >= 0)
			return buffer::const_interval(m_recv_buffer.begin + m_body_start_pos
				, m_recv_buffer.begin + (std::min)(size_type(m_recv_pos)
				, m_body_start_pos + m_content_length));
		else
			return buffer::const_interval(m_recv_buffer.begin + m_body_start_pos
				, m_recv_buffer.begin + m_recv_pos);
	}

	void http_parser::reset()
	{
		m_recv_pos = 0;
		m_body_start_pos = 0;
		m_status_code = -1;
		m_content_length = -1;
		m_finished = false;
		m_state = read_status;
		m_recv_buffer.begin = 0;
		m_recv_buffer.end = 0;
		m_header.clear();
	}

}

<|endoftext|>


<commit_before>#include <type_traits>
#include <loom/infer_grid.hpp>
#include <loom/hyper_kernel.hpp>

namespace loom
{

using distributions::sample_from_scores_overwrite;
using distributions::fast_log;
using distributions::fast_lgamma;

template<class GridPrior>
inline void HyperKernel::infer_outer_clustering_hypers (
        const GridPrior & grid_prior,
        rng_t & rng)
{
    if (grid_prior.size()) {
        std::vector<int> counts;
        counts.reserve(cross_cat_.kinds.size());
        for (const auto & kind : cross_cat_.kinds) {
            counts.push_back(kind.featureids.size());
        }
        cross_cat_.feature_clustering =
            sample_clustering_posterior(grid_prior, counts, rng);
    }
}

inline void HyperKernel::infer_inner_clustering_hypers (
        ProductModel & model,
        ProductMixture & mixture,
        const HyperPrior & hyper_prior,
        rng_t & rng)
{
    const auto & grid_prior = hyper_prior.clustering();
    if (grid_prior.size()) {
        const auto & counts = mixture.clustering.counts();
        model.clustering = sample_clustering_posterior(grid_prior, counts, rng);
        mixture.clustering.init(model.clustering);
    }
}

struct HyperKernel::infer_feature_hypers_fun
{
    const HyperPrior & hyper_prior;
    ProductMixture::Features & mixtures;
    rng_t & rng;

    template<class T>
    void operator() (T * t, size_t i, typename T::Shared & shared)
    {
        auto & mixture = mixtures[t][i];
        typedef typename std::remove_reference<decltype(mixture)>::type Mixture;
        InferShared<Mixture> infer_shared(shared, mixture, rng);
        const auto & grid_prior = protobuf::Fields<T>::get(hyper_prior);
        distributions::for_each_gridpoint(grid_prior, infer_shared);
        mixture.init(shared, rng);
    }

    void operator() (DPD * t, size_t i, DPD::Shared & shared);
};

void HyperKernel::infer_feature_hypers_fun::operator() (
        DPD * t,
        size_t i,
        DPD::Shared & shared)
{
    auto & mixture = mixtures[t][i];
    typedef typename std::remove_reference<decltype(mixture)>::type Mixture;
    InferShared<Mixture> infer_shared(shared, mixture, rng);
    const auto & grid_prior = protobuf::Fields<DPD>::get(hyper_prior);
    VectorFloat scores;

    // sample aux_counts
    typedef uint32_t count_t;
    std::unordered_map<DPD::Value, count_t> aux_counts;
    for (const auto & group : mixture.groups()) {
        for (const auto & i : group.counts) {
            auto value = i.first;
            auto count = i.second;
            float beta = shared.betas.get(value);
            LOOM_ASSERT_LT(0, beta);
            float log_prior = log(shared.alpha * beta);
            distributions::get_log_stirling1_row(count, scores);
            LOOM_ASSERT_EQ(scores.size(), count + 1);
            for (size_t k = 0; k <= count; ++k) {
                scores[k] += k * log_prior;
            }
            size_t aux_count = sample_from_scores_overwrite(rng, scores);
            LOOM_ASSERT_LT(0, aux_count);
            aux_counts[value] += aux_count;
        }
    }

    // only infer hypers if all values have been observed
    if (LOOM_LIKELY(aux_counts.size() == shared.betas.size())) {

        // grid gibbs gamma | aux_counts
        if (grid_prior.gamma_size()) {
            size_t aux_total = 0;
            for (const auto & i : aux_counts) {
                aux_total += i.second;
            }
            scores.clear();
            scores.reserve(grid_prior.gamma_size());
            for (float gamma : grid_prior.gamma()) {
                float score = aux_counts.size() * fast_log(gamma)
                            + fast_lgamma(gamma)
                            - fast_lgamma(gamma + aux_total);
                scores.push_back(score);
            }
            size_t index = sample_from_scores_overwrite(rng, scores);
            shared.gamma = grid_prior.gamma(index);
        }

        // sample beta0, betas | aux_counts, gamma
        if (grid_prior.alpha_size()) {
            std::vector<DPD::Value> values;
            std::vector<float> betas;
            values.reserve(aux_counts.size() + 1);
            betas.reserve(aux_counts.size() + 1);
            for (const auto & i : aux_counts) {
                values.push_back(i.first);
                betas.push_back(i.second);
            }
            values.push_back(shared.OTHER());
            betas.push_back(shared.gamma);

            distributions::sample_dirichlet(
                rng,
                betas.size(),
                betas.data(),
                betas.data());

            for (size_t i = 0, size = aux_counts.size(); i < size; ++i) {
                shared.betas.get(values[i]) = betas[i];
            }
            shared.beta0 = betas.back();
        }

        // grid gibbs alpha | beta0, betas, gamma
        if (grid_prior.alpha_size()) {
            mixture.init(shared, rng);
            for (auto alpha : grid_prior.alpha()) {
                infer_shared.add().alpha = alpha;
            }
            infer_shared.done();
        }
    }

    mixture.init(shared, rng);
}

inline void HyperKernel::infer_feature_hypers (
        ProductModel & model,
        ProductMixture & mixture,
        const HyperPrior & hyper_prior,
        size_t featureid,
        rng_t & rng)
{
    infer_feature_hypers_fun fun = {hyper_prior, mixture.features, rng};
    for_one_feature(fun, model.features, featureid);
}

void HyperKernel::run (rng_t & rng)
{
    Timer::Scope timer(timer_);
    LOOM_ASSERT(run_, "hyper kernel should not be run");

    const size_t kind_count = cross_cat_.kinds.size();
    const size_t feature_count = cross_cat_.featureid_to_kindid.size();
    const auto & outer_prior = cross_cat_.hyper_prior.outer_prior();
    const auto & inner_prior = cross_cat_.hyper_prior.inner_prior();
    const size_t task_count = 1 + kind_count + feature_count;
    const auto seed = rng();

    #pragma omp parallel for if(parallel_) schedule(dynamic, 1)
    for (size_t taskid = 0; taskid < task_count; ++taskid) {
        rng_t rng(seed + taskid);
        if (taskid == 0) {

            infer_outer_clustering_hypers(outer_prior, rng);

        } else if (taskid < 1 + kind_count) {

            size_t kindid = taskid - 1;
            auto & kind = cross_cat_.kinds[kindid];
            infer_inner_clustering_hypers(
                kind.model,
                kind.mixture,
                inner_prior,
                rng);

        } else {

            size_t featureid = taskid - 1 - kind_count;
            size_t kindid = cross_cat_.featureid_to_kindid[featureid];
            auto & kind = cross_cat_.kinds[kindid];
            infer_feature_hypers(
                kind.model,
                kind.mixture,
                inner_prior,
                featureid,
                rng);
        }
    }
}

} // namespace loom

<commit_msg>Use safer sampling in DPD<commit_after>#include <type_traits>
#include <loom/infer_grid.hpp>
#include <loom/hyper_kernel.hpp>

namespace loom
{

using distributions::sample_from_scores_overwrite;
using distributions::fast_log;
using distributions::fast_lgamma;

template<class GridPrior>
inline void HyperKernel::infer_outer_clustering_hypers (
        const GridPrior & grid_prior,
        rng_t & rng)
{
    if (grid_prior.size()) {
        std::vector<int> counts;
        counts.reserve(cross_cat_.kinds.size());
        for (const auto & kind : cross_cat_.kinds) {
            counts.push_back(kind.featureids.size());
        }
        cross_cat_.feature_clustering =
            sample_clustering_posterior(grid_prior, counts, rng);
    }
}

inline void HyperKernel::infer_inner_clustering_hypers (
        ProductModel & model,
        ProductMixture & mixture,
        const HyperPrior & hyper_prior,
        rng_t & rng)
{
    const auto & grid_prior = hyper_prior.clustering();
    if (grid_prior.size()) {
        const auto & counts = mixture.clustering.counts();
        model.clustering = sample_clustering_posterior(grid_prior, counts, rng);
        mixture.clustering.init(model.clustering);
    }
}

struct HyperKernel::infer_feature_hypers_fun
{
    const HyperPrior & hyper_prior;
    ProductMixture::Features & mixtures;
    rng_t & rng;

    template<class T>
    void operator() (T * t, size_t i, typename T::Shared & shared)
    {
        auto & mixture = mixtures[t][i];
        typedef typename std::remove_reference<decltype(mixture)>::type Mixture;
        InferShared<Mixture> infer_shared(shared, mixture, rng);
        const auto & grid_prior = protobuf::Fields<T>::get(hyper_prior);
        distributions::for_each_gridpoint(grid_prior, infer_shared);
        mixture.init(shared, rng);
    }

    void operator() (DPD * t, size_t i, DPD::Shared & shared);
};

void HyperKernel::infer_feature_hypers_fun::operator() (
        DPD * t,
        size_t i,
        DPD::Shared & shared)
{
    auto & mixture = mixtures[t][i];
    typedef typename std::remove_reference<decltype(mixture)>::type Mixture;
    InferShared<Mixture> infer_shared(shared, mixture, rng);
    const auto & grid_prior = protobuf::Fields<DPD>::get(hyper_prior);
    VectorFloat scores;

    // sample aux_counts
    typedef uint32_t count_t;
    std::unordered_map<DPD::Value, count_t> aux_counts;
    for (const auto & group : mixture.groups()) {
        for (const auto & i : group.counts) {
            auto value = i.first;
            auto count = i.second;
            float beta = shared.betas.get(value);
            LOOM_ASSERT_LT(0, beta);
            float log_prior = log(shared.alpha * beta);
            distributions::get_log_stirling1_row(count, scores);
            LOOM_ASSERT_EQ(scores.size(), count + 1);
            for (size_t k = 0; k <= count; ++k) {
                scores[k] += k * log_prior;
            }
            size_t aux_count = sample_from_scores_overwrite(rng, scores);
            LOOM_ASSERT_LT(0, aux_count);
            aux_counts[value] += aux_count;
        }
    }

    // only infer hypers if all values have been observed
    if (LOOM_LIKELY(aux_counts.size() == shared.betas.size())) {

        // grid gibbs gamma | aux_counts
        if (grid_prior.gamma_size()) {
            size_t aux_total = 0;
            for (const auto & i : aux_counts) {
                aux_total += i.second;
            }
            scores.clear();
            scores.reserve(grid_prior.gamma_size());
            for (float gamma : grid_prior.gamma()) {
                float score = aux_counts.size() * fast_log(gamma)
                            + fast_lgamma(gamma)
                            - fast_lgamma(gamma + aux_total);
                scores.push_back(score);
            }
            size_t index = sample_from_scores_overwrite(rng, scores);
            shared.gamma = grid_prior.gamma(index);
        }

        // sample beta0, betas | aux_counts, gamma
        if (grid_prior.alpha_size()) {
            std::vector<DPD::Value> values;
            std::vector<float> betas;
            values.reserve(aux_counts.size() + 1);
            betas.reserve(aux_counts.size() + 1);
            for (const auto & i : aux_counts) {
                values.push_back(i.first);
                betas.push_back(i.second);
            }
            values.push_back(DPD::Model::OTHER());
            betas.push_back(shared.gamma);

            distributions::sample_dirichlet_safe(
                rng,
                betas.size(),
                betas.data(),
                betas.data(),
                DPD::Model::MIN_BETA());

            for (size_t i = 0, size = aux_counts.size(); i < size; ++i) {
                shared.betas.get(values[i]) = betas[i];
            }
            shared.beta0 = betas.back();
        }

        // grid gibbs alpha | beta0, betas, gamma
        if (grid_prior.alpha_size()) {
            mixture.init(shared, rng);
            for (auto alpha : grid_prior.alpha()) {
                infer_shared.add().alpha = alpha;
            }
            infer_shared.done();
        }
    }

    mixture.init(shared, rng);
}

inline void HyperKernel::infer_feature_hypers (
        ProductModel & model,
        ProductMixture & mixture,
        const HyperPrior & hyper_prior,
        size_t featureid,
        rng_t & rng)
{
    infer_feature_hypers_fun fun = {hyper_prior, mixture.features, rng};
    for_one_feature(fun, model.features, featureid);
}

void HyperKernel::run (rng_t & rng)
{
    Timer::Scope timer(timer_);
    LOOM_ASSERT(run_, "hyper kernel should not be run");

    const size_t kind_count = cross_cat_.kinds.size();
    const size_t feature_count = cross_cat_.featureid_to_kindid.size();
    const auto & outer_prior = cross_cat_.hyper_prior.outer_prior();
    const auto & inner_prior = cross_cat_.hyper_prior.inner_prior();
    const size_t task_count = 1 + kind_count + feature_count;
    const auto seed = rng();

    #pragma omp parallel for if(parallel_) schedule(dynamic, 1)
    for (size_t taskid = 0; taskid < task_count; ++taskid) {
        rng_t rng(seed + taskid);
        if (taskid == 0) {

            infer_outer_clustering_hypers(outer_prior, rng);

        } else if (taskid < 1 + kind_count) {

            size_t kindid = taskid - 1;
            auto & kind = cross_cat_.kinds[kindid];
            infer_inner_clustering_hypers(
                kind.model,
                kind.mixture,
                inner_prior,
                rng);

        } else {

            size_t featureid = taskid - 1 - kind_count;
            size_t kindid = cross_cat_.featureid_to_kindid[featureid];
            auto & kind = cross_cat_.kinds[kindid];
            infer_feature_hypers(
                kind.model,
                kind.mixture,
                inner_prior,
                featureid,
                rng);
        }
    }
}

} // namespace loom

<|endoftext|>


<commit_before><commit_msg>coverity#1308494 Uncaught exception<commit_after><|endoftext|>


<commit_before>// Copyright 2012 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/v8.h"

#include "src/version.h"

// These macros define the version number for the current version.
// NOTE these macros are used by some of the tool scripts and the build
// system so their names cannot be changed without changing the scripts.
#define MAJOR_VERSION     3
#define MINOR_VERSION     29
#define BUILD_NUMBER      47
#define PATCH_LEVEL       0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 1

// Define SONAME to have the build system put a specific SONAME into the
// shared library instead the generic SONAME generated from the V8 version
// number. This define is mainly used by the build system script.
#define SONAME            ""

#if IS_CANDIDATE_VERSION
#define CANDIDATE_STRING " (candidate)"
#else
#define CANDIDATE_STRING ""
#endif

#define SX(x) #x
#define S(x) SX(x)

#if PATCH_LEVEL > 0
#define VERSION_STRING                                                         \
    S(MAJOR_VERSION) "." S(MINOR_VERSION) "." S(BUILD_NUMBER) "."              \
        S(PATCH_LEVEL) CANDIDATE_STRING
#else
#define VERSION_STRING                                                         \
    S(MAJOR_VERSION) "." S(MINOR_VERSION) "." S(BUILD_NUMBER)                  \
        CANDIDATE_STRING
#endif

namespace v8 {
namespace internal {

int Version::major_ = MAJOR_VERSION;
int Version::minor_ = MINOR_VERSION;
int Version::build_ = BUILD_NUMBER;
int Version::patch_ = PATCH_LEVEL;
bool Version::candidate_ = (IS_CANDIDATE_VERSION != 0);
const char* Version::soname_ = SONAME;
const char* Version::version_string_ = VERSION_STRING;

// Calculate the V8 version string.
void Version::GetString(Vector<char> str) {
  const char* candidate = IsCandidate() ? " (candidate)" : "";
#ifdef USE_SIMULATOR
  const char* is_simulator = " SIMULATOR";
#else
  const char* is_simulator = "";
#endif  // USE_SIMULATOR
  if (GetPatch() > 0) {
    SNPrintF(str, "%d.%d.%d.%d%s%s",
             GetMajor(), GetMinor(), GetBuild(), GetPatch(), candidate,
             is_simulator);
  } else {
    SNPrintF(str, "%d.%d.%d%s%s",
             GetMajor(), GetMinor(), GetBuild(), candidate,
             is_simulator);
  }
}

// Calculate the SONAME for the V8 shared library.
void Version::GetSONAME(Vector<char> str) {
  if (soname_ == NULL || *soname_ == '\0') {
    // Generate generic SONAME if no specific SONAME is defined.
    const char* candidate = IsCandidate() ? "-candidate" : "";
    if (GetPatch() > 0) {
      SNPrintF(str, "libv8-%d.%d.%d.%d%s.so",
               GetMajor(), GetMinor(), GetBuild(), GetPatch(), candidate);
    } else {
      SNPrintF(str, "libv8-%d.%d.%d%s.so",
               GetMajor(), GetMinor(), GetBuild(), candidate);
    }
  } else {
    // Use specific SONAME.
    SNPrintF(str, "%s", soname_);
  }
}

} }  // namespace v8::internal
<commit_msg>[Auto-roll] Bump up version to 3.29.48.0<commit_after>// Copyright 2012 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/v8.h"

#include "src/version.h"

// These macros define the version number for the current version.
// NOTE these macros are used by some of the tool scripts and the build
// system so their names cannot be changed without changing the scripts.
#define MAJOR_VERSION     3
#define MINOR_VERSION     29
#define BUILD_NUMBER      48
#define PATCH_LEVEL       0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 1

// Define SONAME to have the build system put a specific SONAME into the
// shared library instead the generic SONAME generated from the V8 version
// number. This define is mainly used by the build system script.
#define SONAME            ""

#if IS_CANDIDATE_VERSION
#define CANDIDATE_STRING " (candidate)"
#else
#define CANDIDATE_STRING ""
#endif

#define SX(x) #x
#define S(x) SX(x)

#if PATCH_LEVEL > 0
#define VERSION_STRING                                                         \
    S(MAJOR_VERSION) "." S(MINOR_VERSION) "." S(BUILD_NUMBER) "."              \
        S(PATCH_LEVEL) CANDIDATE_STRING
#else
#define VERSION_STRING                                                         \
    S(MAJOR_VERSION) "." S(MINOR_VERSION) "." S(BUILD_NUMBER)                  \
        CANDIDATE_STRING
#endif

namespace v8 {
namespace internal {

int Version::major_ = MAJOR_VERSION;
int Version::minor_ = MINOR_VERSION;
int Version::build_ = BUILD_NUMBER;
int Version::patch_ = PATCH_LEVEL;
bool Version::candidate_ = (IS_CANDIDATE_VERSION != 0);
const char* Version::soname_ = SONAME;
const char* Version::version_string_ = VERSION_STRING;

// Calculate the V8 version string.
void Version::GetString(Vector<char> str) {
  const char* candidate = IsCandidate() ? " (candidate)" : "";
#ifdef USE_SIMULATOR
  const char* is_simulator = " SIMULATOR";
#else
  const char* is_simulator = "";
#endif  // USE_SIMULATOR
  if (GetPatch() > 0) {
    SNPrintF(str, "%d.%d.%d.%d%s%s",
             GetMajor(), GetMinor(), GetBuild(), GetPatch(), candidate,
             is_simulator);
  } else {
    SNPrintF(str, "%d.%d.%d%s%s",
             GetMajor(), GetMinor(), GetBuild(), candidate,
             is_simulator);
  }
}

// Calculate the SONAME for the V8 shared library.
void Version::GetSONAME(Vector<char> str) {
  if (soname_ == NULL || *soname_ == '\0') {
    // Generate generic SONAME if no specific SONAME is defined.
    const char* candidate = IsCandidate() ? "-candidate" : "";
    if (GetPatch() > 0) {
      SNPrintF(str, "libv8-%d.%d.%d.%d%s.so",
               GetMajor(), GetMinor(), GetBuild(), GetPatch(), candidate);
    } else {
      SNPrintF(str, "libv8-%d.%d.%d%s.so",
               GetMajor(), GetMinor(), GetBuild(), candidate);
    }
  } else {
    // Use specific SONAME.
    SNPrintF(str, "%s", soname_);
  }
}

} }  // namespace v8::internal
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/aura/test/test_screen.h"

#include "base/logging.h"
#include "ui/aura/env.h"
#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/rect_conversions.h"
#include "ui/gfx/screen.h"

namespace aura {

// static
TestScreen* TestScreen::Create() {
  // Use (0,0) because the desktop aura tests are executed in
  // native environment where the display's origin is (0,0).
  return new TestScreen(gfx::Rect(0, 0, 800, 600));
}

// static
TestScreen* TestScreen::CreateFullscreen() {
  return new TestScreen(gfx::Rect(WindowTreeHost::GetNativeScreenSize()));
}

TestScreen::~TestScreen() {
}

RootWindow* TestScreen::CreateRootWindowForPrimaryDisplay() {
  DCHECK(!root_window_);
  root_window_ = new RootWindow(RootWindow::CreateParams(display_.bounds()));
  root_window_->window()->AddObserver(this);
  root_window_->Init();
  return root_window_;
}

void TestScreen::SetDeviceScaleFactor(float device_scale_factor) {
  gfx::Rect bounds_in_pixel(display_.GetSizeInPixel());
  display_.SetScaleAndBounds(device_scale_factor, bounds_in_pixel);
  root_window_->host()->NotifyHostResized(bounds_in_pixel.size());
}

void TestScreen::SetDisplayRotation(gfx::Display::Rotation rotation) {
  display_.set_rotation(rotation);
  // TODO(oshima|mukai): Update the display_ as well.
  root_window_->host()->SetTransform(
      GetRotationTransform() * GetUIScaleTransform());
}

void TestScreen::SetUIScale(float ui_scale) {
  ui_scale_ = ui_scale;
  gfx::Rect bounds_in_pixel(display_.GetSizeInPixel());
  gfx::Rect new_bounds = gfx::ToNearestRect(
      gfx::ScaleRect(bounds_in_pixel, 1.0f / ui_scale));
  display_.SetScaleAndBounds(display_.device_scale_factor(), new_bounds);
  root_window_->host()->SetTransform(
      GetRotationTransform() * GetUIScaleTransform());
}

gfx::Transform TestScreen::GetRotationTransform() const {
  gfx::Transform rotate;
  float one_pixel = 1.0f / display_.device_scale_factor();
  switch (display_.rotation()) {
    case gfx::Display::ROTATE_0:
      break;
    case gfx::Display::ROTATE_90:
      rotate.Translate(display_.bounds().height() - one_pixel, 0);
      rotate.Rotate(90);
      break;
    case gfx::Display::ROTATE_270:
      rotate.Translate(0, display_.bounds().width() - one_pixel);
      rotate.Rotate(270);
      break;
    case gfx::Display::ROTATE_180:
      rotate.Translate(display_.bounds().width() - one_pixel,
                       display_.bounds().height() - one_pixel);
      rotate.Rotate(180);
      break;
  }

  return rotate;
}

gfx::Transform TestScreen::GetUIScaleTransform() const {
  gfx::Transform ui_scale;
  ui_scale.Scale(1.0f / ui_scale_, 1.0f / ui_scale_);
  return ui_scale;
}

bool TestScreen::IsDIPEnabled() {
  return true;
}

void TestScreen::OnWindowBoundsChanged(
    Window* window, const gfx::Rect& old_bounds, const gfx::Rect& new_bounds) {
  DCHECK_EQ(root_window_->window(), window);
  display_.SetSize(new_bounds.size());
}

void TestScreen::OnWindowDestroying(Window* window) {
  if (root_window_->window() == window)
    root_window_ = NULL;
}

gfx::Point TestScreen::GetCursorScreenPoint() {
  return Env::GetInstance()->last_mouse_location();
}

gfx::NativeWindow TestScreen::GetWindowUnderCursor() {
  return GetWindowAtScreenPoint(GetCursorScreenPoint());
}

gfx::NativeWindow TestScreen::GetWindowAtScreenPoint(const gfx::Point& point) {
  return root_window_->window()->GetTopWindowContainingPoint(point);
}

int TestScreen::GetNumDisplays() const {
  return 1;
}

std::vector<gfx::Display> TestScreen::GetAllDisplays() const {
  return std::vector<gfx::Display>(1, display_);
}

gfx::Display TestScreen::GetDisplayNearestWindow(
    gfx::NativeWindow window) const {
  return display_;
}

gfx::Display TestScreen::GetDisplayNearestPoint(const gfx::Point& point) const {
  return display_;
}

gfx::Display TestScreen::GetDisplayMatching(const gfx::Rect& match_rect) const {
  return display_;
}

gfx::Display TestScreen::GetPrimaryDisplay() const {
  return display_;
}

void TestScreen::AddObserver(gfx::DisplayObserver* observer) {
}

void TestScreen::RemoveObserver(gfx::DisplayObserver* observer) {
}

TestScreen::TestScreen(const gfx::Rect& screen_bounds)
    : root_window_(NULL),
      ui_scale_(1.0f) {
  static int64 synthesized_display_id = 2000;
  display_.set_id(synthesized_display_id++);
  display_.SetScaleAndBounds(1.0f, screen_bounds);
}

}  // namespace aura
<commit_msg>aura: Fix unit conversion in test_screen<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/aura/test/test_screen.h"

#include "base/logging.h"
#include "ui/aura/env.h"
#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/rect_conversions.h"
#include "ui/gfx/screen.h"

namespace aura {

// static
TestScreen* TestScreen::Create() {
  // Use (0,0) because the desktop aura tests are executed in
  // native environment where the display's origin is (0,0).
  return new TestScreen(gfx::Rect(0, 0, 800, 600));
}

// static
TestScreen* TestScreen::CreateFullscreen() {
  return new TestScreen(gfx::Rect(WindowTreeHost::GetNativeScreenSize()));
}

TestScreen::~TestScreen() {
}

RootWindow* TestScreen::CreateRootWindowForPrimaryDisplay() {
  DCHECK(!root_window_);
  root_window_ = new RootWindow(
      RootWindow::CreateParams(gfx::Rect(display_.GetSizeInPixel())));
  root_window_->window()->AddObserver(this);
  root_window_->Init();
  return root_window_;
}

void TestScreen::SetDeviceScaleFactor(float device_scale_factor) {
  gfx::Rect bounds_in_pixel(display_.GetSizeInPixel());
  display_.SetScaleAndBounds(device_scale_factor, bounds_in_pixel);
  root_window_->host()->NotifyHostResized(bounds_in_pixel.size());
}

void TestScreen::SetDisplayRotation(gfx::Display::Rotation rotation) {
  display_.set_rotation(rotation);
  // TODO(oshima|mukai): Update the display_ as well.
  root_window_->host()->SetTransform(
      GetRotationTransform() * GetUIScaleTransform());
}

void TestScreen::SetUIScale(float ui_scale) {
  ui_scale_ = ui_scale;
  gfx::Rect bounds_in_pixel(display_.GetSizeInPixel());
  gfx::Rect new_bounds = gfx::ToNearestRect(
      gfx::ScaleRect(bounds_in_pixel, 1.0f / ui_scale));
  display_.SetScaleAndBounds(display_.device_scale_factor(), new_bounds);
  root_window_->host()->SetTransform(
      GetRotationTransform() * GetUIScaleTransform());
}

gfx::Transform TestScreen::GetRotationTransform() const {
  gfx::Transform rotate;
  float one_pixel = 1.0f / display_.device_scale_factor();
  switch (display_.rotation()) {
    case gfx::Display::ROTATE_0:
      break;
    case gfx::Display::ROTATE_90:
      rotate.Translate(display_.bounds().height() - one_pixel, 0);
      rotate.Rotate(90);
      break;
    case gfx::Display::ROTATE_270:
      rotate.Translate(0, display_.bounds().width() - one_pixel);
      rotate.Rotate(270);
      break;
    case gfx::Display::ROTATE_180:
      rotate.Translate(display_.bounds().width() - one_pixel,
                       display_.bounds().height() - one_pixel);
      rotate.Rotate(180);
      break;
  }

  return rotate;
}

gfx::Transform TestScreen::GetUIScaleTransform() const {
  gfx::Transform ui_scale;
  ui_scale.Scale(1.0f / ui_scale_, 1.0f / ui_scale_);
  return ui_scale;
}

bool TestScreen::IsDIPEnabled() {
  return true;
}

void TestScreen::OnWindowBoundsChanged(
    Window* window, const gfx::Rect& old_bounds, const gfx::Rect& new_bounds) {
  DCHECK_EQ(root_window_->window(), window);
  display_.SetSize(gfx::ToFlooredSize(
      gfx::ScaleSize(new_bounds.size(), display_.device_scale_factor())));
}

void TestScreen::OnWindowDestroying(Window* window) {
  if (root_window_->window() == window)
    root_window_ = NULL;
}

gfx::Point TestScreen::GetCursorScreenPoint() {
  return Env::GetInstance()->last_mouse_location();
}

gfx::NativeWindow TestScreen::GetWindowUnderCursor() {
  return GetWindowAtScreenPoint(GetCursorScreenPoint());
}

gfx::NativeWindow TestScreen::GetWindowAtScreenPoint(const gfx::Point& point) {
  return root_window_->window()->GetTopWindowContainingPoint(point);
}

int TestScreen::GetNumDisplays() const {
  return 1;
}

std::vector<gfx::Display> TestScreen::GetAllDisplays() const {
  return std::vector<gfx::Display>(1, display_);
}

gfx::Display TestScreen::GetDisplayNearestWindow(
    gfx::NativeWindow window) const {
  return display_;
}

gfx::Display TestScreen::GetDisplayNearestPoint(const gfx::Point& point) const {
  return display_;
}

gfx::Display TestScreen::GetDisplayMatching(const gfx::Rect& match_rect) const {
  return display_;
}

gfx::Display TestScreen::GetPrimaryDisplay() const {
  return display_;
}

void TestScreen::AddObserver(gfx::DisplayObserver* observer) {
}

void TestScreen::RemoveObserver(gfx::DisplayObserver* observer) {
}

TestScreen::TestScreen(const gfx::Rect& screen_bounds)
    : root_window_(NULL),
      ui_scale_(1.0f) {
  static int64 synthesized_display_id = 2000;
  display_.set_id(synthesized_display_id++);
  display_.SetScaleAndBounds(1.0f, screen_bounds);
}

}  // namespace aura
<|endoftext|>


<commit_before>#include "vparam.h"

#include <ppasskeeper.h>

#define STRING_TYPE "string"
#define INT_TYPE "int"
#define FLOAT_TYPE "float"
#define TYPE_SEPARATOR ":"

#ifdef USE_ELEKTRA

//===----------------------------------------------------------------------===//
// VParamImpl class implementation for elektra
//===----------------------------------------------------------------------===//

#include <kdb.h>
#include <sstream>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

class VParamImpl
{
	friend class VParam;

	std::string elektraKeyName(const char* module_id, const char* key)
	{
		std::ostringstream keyName;
		keyName << "user/sw/ppasskeeper/" << module_id << '/' << key;
		return keyName.str();
	}

	bool saveParam(const char* module_id, const char* key, const cvariant value)
	{
		//Get the type of the value to store
		std::string type, s_value, final_value;
		switch(cvariant_get_type(value))
		{
		case cvariant_string:
			type=STRING_TYPE;
			s_value=cvariant_get_string(value);
			break;

		case cvariant_int:
			type=INT_TYPE;
			s_value=cvariant_get_int(value);
			break;

		case cvariant_float:
			type=FLOAT_TYPE;
			s_value=cvariant_get_float(value);
			break;
		case cvariant_none:
			break;
		}

		//Create the value name
		final_value=type+TYPE_SEPARATOR+s_value;

		//Open libElektra
		ckdb::KDB* handle;
		if ((handle = ckdb::kdbOpen()) == NULL)
		{
			perror("kdbOpen");
			return false;
		}

		//Create the key
		ckdb::Key *k = ckdb::keyNew(elektraKeyName(module_id, key).c_str(), KEY_VALUE, final_value.c_str(), KEY_END);

		bool r;
		if (k == NULL)
		{
			std::cerr << "Invalid parameter name" << std::endl;
			r = false;
		}
		else
		{
			//Set the key
			int err = ckdb::kdbSetKey(handle, k);
			ckdb::keyDel(k);

			if (err == 0)
				r = true;
			else
			{
				perror("kbdSetKey");
				r = false;
			}
		}

		//Close libelektra
		if (ckdb::kdbClose(handle) != 0)
			perror("kdbClose");
		return r;
	}

	cvariant getParam(const char* module_id, const char* key)
	{
		cvariant result=cvariant_null();
		char returnedString[1001];

		//Get data from elektra
		ckdb::KDB* handle;
		if ((handle = ckdb::kdbOpen()) == NULL)
		{
			perror("kdbOpen");
			return result;
		}

		/*int size = */ckdb::kdbGetString(handle, elektraKeyName(module_id, key).c_str(), returnedString, sizeof(returnedString)-1);

		if (ckdb::kdbClose(handle) != 0)
			perror("kdbClose");

		//avoid potential buffer overflows
		returnedString[sizeof(returnedString)] = '\0';
		std::string value=returnedString;

		if(value.substr(0, strlen(STRING_TYPE TYPE_SEPARATOR))==STRING_TYPE TYPE_SEPARATOR)
		{
			value=value.substr(strlen(STRING_TYPE TYPE_SEPARATOR));
			result=cvariant_from_string_copy(value.c_str(), value.size());
		}
		else if(value.substr(0, strlen(INT_TYPE TYPE_SEPARATOR))==INT_TYPE TYPE_SEPARATOR)
		{
			value=value.substr(strlen(INT_TYPE TYPE_SEPARATOR));
			result=cvariant_from_int(atoi(value.c_str()));
		}

		return result;
	}

	std::vector<std::string> listParams(const char* module_id)
	{
		std::vector<std::string> list;

		ckdb::KeySet *myConfig=ckdb::ksNew(0);
		ckdb::KDB * handle=ckdb::kdbOpen();

		/* Get all value keys for this application */
		if (ckdb::kdbGetByName(handle, myConfig, elektraKeyName(module_id,"").c_str(),  0) == -1)
		{
			perror("Couldn't get user configuration. Reason");
		} else {
			//size = (int)ksGetSize(myConfig);

			ckdb::Key *current;
			cursor_t cursor = ckdb::ksGetCursor (myConfig);
			ckdb::ksRewind (myConfig);
			while ((current = ckdb::ksNext (myConfig)) != 0)
				list.push_back((const char*)ckdb::keyBaseName(current));
			ckdb::ksSetCursor(myConfig, cursor);
		}

		ckdb::kdbClose(handle);
		ckdb::ksDel(myConfig);

		return list;
	}

	bool removeParam(const char* module_id, const char* key)
	{
		bool r;

		ckdb::KDB* handle;
		if ((handle = ckdb::kdbOpen()) == NULL)
		{
			perror("kdbOpen");
			return false;
		}

		int err=ckdb::kdbRemove(handle, elektraKeyName(module_id, key).c_str());
		if (err == 0)
			r = true;
		else
		{
			perror("kdbRemove");
			r = false;
		}

		if (ckdb::kdbClose(handle) != 0)
			perror("kdbClose");

		return r;
	}
};

#else // Use XML

//===----------------------------------------------------------------------===//
// VParamImpl class implementation for XML
//===----------------------------------------------------------------------===//

#include <fstream>
#include <sstream>
#include <iostream>
#include "tokenizer.h"
#include "xmlsp.h"

#include <ppasskeeper/utils.h>

class VParamImpl : public XMLSP::Parser
{
	friend class VParam;

	std::string xml_path;
	//We associate <module, key> to <type, value>
	std::map< std::pair<std::string, std::string>, std::pair<int, std::string> > params;

	VParamImpl()
	{
		xml_path = ppk_settings_directory() + std::string("/xmlParam.xml");

		std::ifstream is(xml_path.c_str());
		if(is.is_open())
		{
			std::ostringstream iss;
			iss << is.rdbuf();

			if(!parse(iss.str()))
			{
				std::cerr << "XMLParamImpl : parse(iss.str()) returned false !" << std::endl;
			}
		}

		this->xml_path = xml_path;
	}

	virtual bool on_tag_open(const std::string& tag_name, XMLSP::StringMap& attributes)
	{
		if (tag_name == "entry")
		{
			std::pair<std::string, std::string> pair(attributes["module"], attributes["key"]);

			if(attributes["type"]==STRING_TYPE)
				params[pair]=std::make_pair(cvariant_string, attributes["value"]);
			else if(attributes["type"]==INT_TYPE)
				params[pair]=std::make_pair(cvariant_int, attributes["value"]);
			else if(attributes["type"]==FLOAT_TYPE)
				params[pair]=std::make_pair(cvariant_float, attributes["value"]);
		}
		return true;
	}

	virtual bool on_cdata(const std::string& cdata) { return true; }
	virtual bool on_tag_close(const std::string& tag_name) { return true; }
	virtual bool on_comment(const std::string& comment) { return true; }
	virtual bool on_processing(const std::string& value) { return true; }
	virtual bool on_doctype(const std::string& value) { return true; }
	virtual bool on_document_begin() { return true; }
	virtual bool on_document_end() { return true; }
	virtual void on_error(int errnr, int line, int col, const std::string& message) {}

	bool flush()
	{
		std::ofstream os(xml_path.c_str());
		if(os.is_open())
		{
			os << "<ppk_params>" << std::endl;

			std::map<std::pair<std::string, std::string>, std::pair<int, std::string> >::iterator iter;
			for( iter = params.begin(); iter != params.end(); iter++ )
			{
				std::string type;
				switch(iter->second.first)
				{
				case cvariant_string:
					type=STRING_TYPE;
					break;

				case cvariant_int:
					type=INT_TYPE;
					break;

				case cvariant_float:
					type=FLOAT_TYPE;
					break;
				}
				case cvariant_none:
					break;

				os << " <entry module=\"" << iter->first.first << "\" key=\"" << iter->first.second << "\" type=\"" <<  type << "\" value=\"" <<  iter->second.second << "\" />" << std::endl;
			}

			os << "</ppk_params>" << std::endl;

			return true;
		}
		else
			std::cerr << "ppk_saveParam : '" << xml_path << "' cannot be opened for writing purpose." << std::endl << "Check your file permission." << std::endl;

		return false;
	}

	bool saveParam(const char* module_id, const char* key, const cvariant value)
	{
		std::string s_value;
		switch(cvariant_get_type(value))
		{
		case cvariant_string:
			s_value=cvariant_get_string(value);
			break;

		case cvariant_int:
			s_value=toString(cvariant_get_int(value));
			break;

		case cvariant_float:
			s_value=toString(cvariant_get_float(value));
			break;

		case cvariant_none:
			return false;
			break;
		}

		params[std::make_pair(module_id, key)]=std::make_pair(cvariant_get_type(value), s_value);

		return flush();
	}

	cvariant getParam(const char* module_id, const char* key)
	{
		std::pair<std::string, std::string> pair(module_id, key);
		std::pair<int, std::string> value=params[pair];

		cvariant cv=cvariant_null();
		switch(value.first)
		{
		case cvariant_string:
			cv=cvariant_from_string(value.second.c_str());
			break;

		case cvariant_int:
			cv=cvariant_from_int(stringTo<int>(value.second.c_str()));
			break;

		case cvariant_float:
			cv=cvariant_from_float(stringTo<double>(value.second.c_str()));
			break;

		case cvariant_none:
			//Will return cvariant_null()
			break;
		}

		return cv;
	}

	std::vector<std::string> listParams(const char* module_id)
	{
		std::vector<std::string> list;

		std::map<std::pair<std::string, std::string>, std::pair<int, std::string> >::iterator iter;
		for(iter = params.begin(); iter != params.end(); iter++)
			if(iter->first.first==module_id)
				list.push_back(iter->first.second);

		return list;
	}

	bool removeParam(const char* module_id, const char* key)
	{
		std::map<std::pair<std::string, std::string>, std::pair<int, std::string> >::iterator iter;
		for(iter = params.begin(); iter != params.end(); iter++)
		{
			if(iter->first.second==key)
			{
				params.erase(iter);
				return flush();
			}
		}

		return false;
	}
};

#endif

//===----------------------------------------------------------------------===//
// VParam class implementation
//===----------------------------------------------------------------------===//

VParam::VParam() {}

VParam& VParam::instance()
{
	static VParam inst;

	//initialize impl immediately (thread-safety)
	(void) inst.impl();

	return inst;
}

VParamImpl& VParam::impl()
{
	static VParamImpl _impl;
	return _impl;
}

bool VParam::saveParam(const char* module_id, const char* key, const cvariant value)
{
	return impl().saveParam(module_id, key, value);
}

cvariant VParam::getParam(const char* module_id, const char* key)
{
	return impl().getParam(module_id, key);
}

std::vector<std::string> VParam::listParams(const char* module_id)
{
	return impl().listParams(module_id);
}

bool VParam::removeParam(const char* module_id, const char* key)
{
	return impl().removeParam(module_id, key);
}
<commit_msg>Woops, fixes build after last commit<commit_after>#include "vparam.h"

#include <ppasskeeper.h>

#define STRING_TYPE "string"
#define INT_TYPE "int"
#define FLOAT_TYPE "float"
#define TYPE_SEPARATOR ":"

#ifdef USE_ELEKTRA

//===----------------------------------------------------------------------===//
// VParamImpl class implementation for elektra
//===----------------------------------------------------------------------===//

#include <kdb.h>
#include <sstream>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

class VParamImpl
{
	friend class VParam;

	std::string elektraKeyName(const char* module_id, const char* key)
	{
		std::ostringstream keyName;
		keyName << "user/sw/ppasskeeper/" << module_id << '/' << key;
		return keyName.str();
	}

	bool saveParam(const char* module_id, const char* key, const cvariant value)
	{
		//Get the type of the value to store
		std::string type, s_value, final_value;
		switch(cvariant_get_type(value))
		{
		case cvariant_string:
			type=STRING_TYPE;
			s_value=cvariant_get_string(value);
			break;

		case cvariant_int:
			type=INT_TYPE;
			s_value=cvariant_get_int(value);
			break;

		case cvariant_float:
			type=FLOAT_TYPE;
			s_value=cvariant_get_float(value);
			break;
		case cvariant_none:
			break;
		}

		//Create the value name
		final_value=type+TYPE_SEPARATOR+s_value;

		//Open libElektra
		ckdb::KDB* handle;
		if ((handle = ckdb::kdbOpen()) == NULL)
		{
			perror("kdbOpen");
			return false;
		}

		//Create the key
		ckdb::Key *k = ckdb::keyNew(elektraKeyName(module_id, key).c_str(), KEY_VALUE, final_value.c_str(), KEY_END);

		bool r;
		if (k == NULL)
		{
			std::cerr << "Invalid parameter name" << std::endl;
			r = false;
		}
		else
		{
			//Set the key
			int err = ckdb::kdbSetKey(handle, k);
			ckdb::keyDel(k);

			if (err == 0)
				r = true;
			else
			{
				perror("kbdSetKey");
				r = false;
			}
		}

		//Close libelektra
		if (ckdb::kdbClose(handle) != 0)
			perror("kdbClose");
		return r;
	}

	cvariant getParam(const char* module_id, const char* key)
	{
		cvariant result=cvariant_null();
		char returnedString[1001];

		//Get data from elektra
		ckdb::KDB* handle;
		if ((handle = ckdb::kdbOpen()) == NULL)
		{
			perror("kdbOpen");
			return result;
		}

		/*int size = */ckdb::kdbGetString(handle, elektraKeyName(module_id, key).c_str(), returnedString, sizeof(returnedString)-1);

		if (ckdb::kdbClose(handle) != 0)
			perror("kdbClose");

		//avoid potential buffer overflows
		returnedString[sizeof(returnedString)] = '\0';
		std::string value=returnedString;

		if(value.substr(0, strlen(STRING_TYPE TYPE_SEPARATOR))==STRING_TYPE TYPE_SEPARATOR)
		{
			value=value.substr(strlen(STRING_TYPE TYPE_SEPARATOR));
			result=cvariant_from_string_copy(value.c_str(), value.size());
		}
		else if(value.substr(0, strlen(INT_TYPE TYPE_SEPARATOR))==INT_TYPE TYPE_SEPARATOR)
		{
			value=value.substr(strlen(INT_TYPE TYPE_SEPARATOR));
			result=cvariant_from_int(atoi(value.c_str()));
		}

		return result;
	}

	std::vector<std::string> listParams(const char* module_id)
	{
		std::vector<std::string> list;

		ckdb::KeySet *myConfig=ckdb::ksNew(0);
		ckdb::KDB * handle=ckdb::kdbOpen();

		/* Get all value keys for this application */
		if (ckdb::kdbGetByName(handle, myConfig, elektraKeyName(module_id,"").c_str(),  0) == -1)
		{
			perror("Couldn't get user configuration. Reason");
		} else {
			//size = (int)ksGetSize(myConfig);

			ckdb::Key *current;
			cursor_t cursor = ckdb::ksGetCursor (myConfig);
			ckdb::ksRewind (myConfig);
			while ((current = ckdb::ksNext (myConfig)) != 0)
				list.push_back((const char*)ckdb::keyBaseName(current));
			ckdb::ksSetCursor(myConfig, cursor);
		}

		ckdb::kdbClose(handle);
		ckdb::ksDel(myConfig);

		return list;
	}

	bool removeParam(const char* module_id, const char* key)
	{
		bool r;

		ckdb::KDB* handle;
		if ((handle = ckdb::kdbOpen()) == NULL)
		{
			perror("kdbOpen");
			return false;
		}

		int err=ckdb::kdbRemove(handle, elektraKeyName(module_id, key).c_str());
		if (err == 0)
			r = true;
		else
		{
			perror("kdbRemove");
			r = false;
		}

		if (ckdb::kdbClose(handle) != 0)
			perror("kdbClose");

		return r;
	}
};

#else // Use XML

//===----------------------------------------------------------------------===//
// VParamImpl class implementation for XML
//===----------------------------------------------------------------------===//

#include <fstream>
#include <sstream>
#include <iostream>
#include "tokenizer.h"
#include "xmlsp.h"

#include <ppasskeeper/utils.h>

class VParamImpl : public XMLSP::Parser
{
	friend class VParam;

	std::string xml_path;
	//We associate <module, key> to <type, value>
	std::map< std::pair<std::string, std::string>, std::pair<int, std::string> > params;

	VParamImpl()
	{
		xml_path = ppk_settings_directory() + std::string("/xmlParam.xml");

		std::ifstream is(xml_path.c_str());
		if(is.is_open())
		{
			std::ostringstream iss;
			iss << is.rdbuf();

			if(!parse(iss.str()))
			{
				std::cerr << "XMLParamImpl : parse(iss.str()) returned false !" << std::endl;
			}
		}

		this->xml_path = xml_path;
	}

	virtual bool on_tag_open(const std::string& tag_name, XMLSP::StringMap& attributes)
	{
		if (tag_name == "entry")
		{
			std::pair<std::string, std::string> pair(attributes["module"], attributes["key"]);

			if(attributes["type"]==STRING_TYPE)
				params[pair]=std::make_pair(cvariant_string, attributes["value"]);
			else if(attributes["type"]==INT_TYPE)
				params[pair]=std::make_pair(cvariant_int, attributes["value"]);
			else if(attributes["type"]==FLOAT_TYPE)
				params[pair]=std::make_pair(cvariant_float, attributes["value"]);
		}
		return true;
	}

	virtual bool on_cdata(const std::string& cdata) { return true; }
	virtual bool on_tag_close(const std::string& tag_name) { return true; }
	virtual bool on_comment(const std::string& comment) { return true; }
	virtual bool on_processing(const std::string& value) { return true; }
	virtual bool on_doctype(const std::string& value) { return true; }
	virtual bool on_document_begin() { return true; }
	virtual bool on_document_end() { return true; }
	virtual void on_error(int errnr, int line, int col, const std::string& message) {}

	bool flush()
	{
		std::ofstream os(xml_path.c_str());
		if(os.is_open())
		{
			os << "<ppk_params>" << std::endl;

			std::map<std::pair<std::string, std::string>, std::pair<int, std::string> >::iterator iter;
			for( iter = params.begin(); iter != params.end(); iter++ )
			{
				std::string type;
				switch(iter->second.first)
				{
				case cvariant_string:
					type=STRING_TYPE;
					break;

				case cvariant_int:
					type=INT_TYPE;
					break;

				case cvariant_float:
					type=FLOAT_TYPE;
					break;

				case cvariant_none:
					break;
				}

				os << " <entry module=\"" << iter->first.first << "\" key=\"" << iter->first.second << "\" type=\"" <<  type << "\" value=\"" <<  iter->second.second << "\" />" << std::endl;
			}

			os << "</ppk_params>" << std::endl;

			return true;
		}
		else
			std::cerr << "ppk_saveParam : '" << xml_path << "' cannot be opened for writing purpose." << std::endl << "Check your file permission." << std::endl;

		return false;
	}

	bool saveParam(const char* module_id, const char* key, const cvariant value)
	{
		std::string s_value;
		switch(cvariant_get_type(value))
		{
		case cvariant_string:
			s_value=cvariant_get_string(value);
			break;

		case cvariant_int:
			s_value=toString(cvariant_get_int(value));
			break;

		case cvariant_float:
			s_value=toString(cvariant_get_float(value));
			break;

		case cvariant_none:
			return false;
			break;
		}

		params[std::make_pair(module_id, key)]=std::make_pair(cvariant_get_type(value), s_value);

		return flush();
	}

	cvariant getParam(const char* module_id, const char* key)
	{
		std::pair<std::string, std::string> pair(module_id, key);
		std::pair<int, std::string> value=params[pair];

		cvariant cv=cvariant_null();
		switch(value.first)
		{
		case cvariant_string:
			cv=cvariant_from_string(value.second.c_str());
			break;

		case cvariant_int:
			cv=cvariant_from_int(stringTo<int>(value.second.c_str()));
			break;

		case cvariant_float:
			cv=cvariant_from_float(stringTo<double>(value.second.c_str()));
			break;

		case cvariant_none:
			//Will return cvariant_null()
			break;
		}

		return cv;
	}

	std::vector<std::string> listParams(const char* module_id)
	{
		std::vector<std::string> list;

		std::map<std::pair<std::string, std::string>, std::pair<int, std::string> >::iterator iter;
		for(iter = params.begin(); iter != params.end(); iter++)
			if(iter->first.first==module_id)
				list.push_back(iter->first.second);

		return list;
	}

	bool removeParam(const char* module_id, const char* key)
	{
		std::map<std::pair<std::string, std::string>, std::pair<int, std::string> >::iterator iter;
		for(iter = params.begin(); iter != params.end(); iter++)
		{
			if(iter->first.second==key)
			{
				params.erase(iter);
				return flush();
			}
		}

		return false;
	}
};

#endif

//===----------------------------------------------------------------------===//
// VParam class implementation
//===----------------------------------------------------------------------===//

VParam::VParam() {}

VParam& VParam::instance()
{
	static VParam inst;

	//initialize impl immediately (thread-safety)
	(void) inst.impl();

	return inst;
}

VParamImpl& VParam::impl()
{
	static VParamImpl _impl;
	return _impl;
}

bool VParam::saveParam(const char* module_id, const char* key, const cvariant value)
{
	return impl().saveParam(module_id, key, value);
}

cvariant VParam::getParam(const char* module_id, const char* key)
{
	return impl().getParam(module_id, key);
}

std::vector<std::string> VParam::listParams(const char* module_id)
{
	return impl().listParams(module_id);
}

bool VParam::removeParam(const char* module_id, const char* key)
{
	return impl().removeParam(module_id, key);
}
<|endoftext|>


<commit_before>#include "xchainer/array.h"

#include <algorithm>
#include <cassert>
#include <cstring>
#include <iostream> // TODO(hvy): Remove me
#include <string>
// #include <unordered_set>
#include <unordered_map>

#ifdef XCHAINER_ENABLE_CUDA
#include <cuda.h>
#include <cuda_runtime.h>
#endif  // XCHAINER_ENABLE_CUDA
#include <gsl/gsl>

#include "xchainer/array_fill.h"
#include "xchainer/array_math.h"
#include "xchainer/array_repr.h"
#ifdef XCHAINER_ENABLE_CUDA
#include "xchainer/cuda/array_fill.h"
#include "xchainer/cuda/array_math.h"
#include "xchainer/cuda/cuda_runtime.h"
#endif  // XCHAINER_ENABLE_CUDA
#include "xchainer/device.h"
#include "xchainer/memory.h"
#include "xchainer/op_node.h"
#include "xchainer/scalar.h"

namespace xchainer {
namespace internal {

// Private definition of ArrayBody
ArrayBody::ArrayBody(const Shape& shape, Dtype dtype, bool requires_grad, bool is_contiguous, std::shared_ptr<void> data, int64_t offset,
                     std::shared_ptr<ArrayNode> node, std::string graph_name)
    : shape_(shape),
      dtype_(dtype),
      is_contiguous_(is_contiguous),
      data_(std::move(data)),
      offset_(offset),
      nodes_({{std::move(graph_name), {std::move(node), requires_grad}}}) {}

const std::shared_ptr<ArrayNode>& ArrayBody::GetOrCreateNode(const std::string& graph_name, bool default_requires_grad) {
    auto named_nodes =
        std::find_if(nodes_.begin(), nodes_.end(),
                     [&graph_name](const std::pair<std::string, ArrayNodeGradientProperty>& node) { return node.first == graph_name; });

    if (named_nodes != nodes_.end()) {
        // Return match
        return named_nodes->second.node;
    }

    // Create and return new
    std::shared_ptr<ArrayNode> node = std::make_shared<ArrayNode>();
    ArrayNodeGradientProperty node_property(node, default_requires_grad);
    nodes_.push_back({graph_name, node_property});
    return nodes_.back().second.node;
}

}  // namespace internal

Array::Array(const Shape& shape, Dtype dtype, std::shared_ptr<void> data, std::shared_ptr<ArrayNode> node, bool requires_grad,
             bool is_contiguous, int64_t offset, const std::string& graph_name)
    : body_(std::make_shared<internal::ArrayBody>(shape, dtype, requires_grad, is_contiguous, std::move(data), offset, std::move(node),
                                                  std::move(graph_name))) {}

Array::Array(const Array& other)
    : Array(other.shape(), other.dtype(), internal::Allocate(GetCurrentDevice(), other.total_bytes()), std::make_shared<ArrayNode>(),
            other.requires_grad(), true, 0, "") {
    // TODO(hvy): Do no set default empty string graph_name, but instead skip initializing the ArrayNode here

    // Memory layout-related members are not copied in this copy ctor since new C-contiguous memory is allocated
    other.CopyTo(*this);
}

// TODO(hvy): Multi-graph support
// const std::shared_ptr<ArrayNode>& Array::RenewNode() { return body_->node_ = std::make_shared<ArrayNode>(); }

const nonstd::optional<Array>& Array::grad(const std::string& graph_name) const { return body_->node(graph_name)->grad(); }

void Array::set_grad(Array grad, const std::string& graph_name) { body_->mutable_node(graph_name)->set_grad(std::move(grad)); }

void Array::ClearGrad(const std::string& graph_name) { body_->mutable_node(graph_name)->ClearGrad(); }

// TODO(hvy): Multi-graph support, i.e. specify graph_name
Array Array::FromBuffer(const Shape& shape, Dtype dtype, std::shared_ptr<void> data) {
    auto bytesize = static_cast<size_t>(shape.total_size() * GetElementSize(dtype));
    std::shared_ptr<void> device_data = internal::MemoryFromBuffer(GetCurrentDevice(), data, bytesize);
    return {shape, dtype, device_data, std::make_unique<ArrayNode>()};
}

Array Array::Empty(const Shape& shape, Dtype dtype) {
    auto bytesize = static_cast<size_t>(shape.total_size() * GetElementSize(dtype));
    std::shared_ptr<void> data = internal::Allocate(GetCurrentDevice(), bytesize);
    return {shape, dtype, data, std::make_unique<ArrayNode>()};
}

Array Array::Full(const Shape& shape, Scalar scalar, Dtype dtype) {
    Array array = Empty(shape, dtype);
    array.Fill(scalar);
    return array;
}

Array Array::Full(const Shape& shape, Scalar scalar) { return Full(shape, scalar, scalar.dtype()); }

Array Array::Zeros(const Shape& shape, Dtype dtype) { return Full(shape, 0, dtype); }

Array Array::Ones(const Shape& shape, Dtype dtype) { return Full(shape, 1, dtype); }

Array Array::EmptyLike(const Array& array) { return Empty(array.shape(), array.dtype()); }

Array Array::FullLike(const Array& array, Scalar scalar) { return Full(array.shape(), scalar, array.dtype()); }

Array Array::ZerosLike(const Array& array) { return Zeros(array.shape(), array.dtype()); }

Array Array::OnesLike(const Array& array) { return Ones(array.shape(), array.dtype()); }

Array& Array::operator+=(const Array& rhs) {
    Add(rhs, *this);
    // set_requires_grad(requires_grad() || rhs.requires_grad());
    return *this;
}

Array& Array::operator*=(const Array& rhs) {
    Mul(rhs, *this);
    // set_requires_grad(requires_grad() || rhs.requires_grad());
    return *this;
}

Array Array::operator+(const Array& rhs) const {
    Array out = Array::EmptyLike(*this);
    // out.set_requires_grad(requires_grad() || rhs.requires_grad());
    Add(rhs, out);
    return out;
}

Array Array::operator*(const Array& rhs) const {
    Array out = Array::EmptyLike(*this);
    // out.set_requires_grad(requires_grad() || rhs.requires_grad());
    Mul(rhs, out);
    return out;
}

Array Array::Copy() const {
    Array out = Array::EmptyLike(*this);
    // out.set_requires_grad(requires_grad());
    CopyTo(out);
    return out;
}

void Array::CopyTo(Array& out) const {
    for (auto& named_node : body_->nodes_) {    // For each graph, or ArrayNode
        if (named_node.second.requires_grad) {  // If ArrayNode requires gradients
            const ArrayNodeGradientProperty& node_prop = named_node.second;
            std::shared_ptr<ArrayNode> out_node = out.GetOrCreateNode(named_node.first, true);
            int64_t out_rank = node_prop.node->rank();
            auto next_nodes = std::vector<std::shared_ptr<ArrayNode>>{node_prop.node};
            auto in_func = [](const Array& gout) { return gout; };
            auto backward_functions = std::vector<std::function<Array(const Array&)>>{in_func};
            auto op_node = std::make_shared<OpNode>("copy", out_rank, next_nodes, backward_functions);
            out_node->set_next_node(op_node);
            out_node->set_rank(out_rank + 1);
        }
    }

    /*
    if (requires_grad()) {
        std::shared_ptr<ArrayNode> out_node = out.RenewNode();
        int64_t out_rank = node()->rank();
        auto next_nodes = std::vector<std::shared_ptr<ArrayNode>>{body_->node_};
        auto in_func = [](const Array& gout) { return gout; };
        auto backward_functions = std::vector<std::function<Array(const Array&)>>{in_func};
        auto op_node = std::make_shared<OpNode>("copy", out_rank, next_nodes, backward_functions);
        out_node->set_next_node(op_node);
        out_node->set_rank(out_rank + 1);
    }
    */

    // TODO(hvy): When non-C-contiguous orders are supported, we cannot blindly copy all elements but need to take
    // is_contiguous_ and offset_ into account
    internal::MemoryCopy(out.data().get(), body_->data_.get(), total_bytes());
}

void Array::Add(const Array& rhs, Array& out) const {
    /*
    if ((&out == this || &out == &rhs) && out.requires_grad()) {
        throw XchainerError("In-place operation (Add) is not supported for an array with requires_grad=true.");
    }
    */

    // TODO(sonots): dtype conversion
    CheckEqual(dtype(), rhs.dtype());
    // TODO(sonots): broadcasting
    CheckEqual(shape(), rhs.shape());

    std::unordered_map<std::string, OpNode> graph_op_nodes;

    // LHS
    for (auto& named_node : body_->nodes_) {  // For each graph
        const std::string& graph_name = named_node.first;
        if (named_node.second.requires_grad) {
            std::shared_ptr<ArrayNode> lhs_node = mutable_node(graph_name);
            auto lhs_func = [](const Array& gout) { return gout; };
            OpNode& op_node = graph_op_nodes[graph_name];  // Create if not exists
            op_node.set_name("add");
            op_node.RegisterNextNode(lhs_node);
            op_node.RegisterBackwardFunction(lhs_func);
        }
    }

    // RHS
    for (auto& named_node : rhs.nodes()) {
        const std::string& graph_name = named_node.first;
        if (named_node.second.requires_grad) {
            std::shared_ptr<ArrayNode> rhs_node = rhs.mutable_node(graph_name);
            auto rhs_func = [](const Array& gout) { return gout; };
            OpNode& op_node = graph_op_nodes[graph_name];
            op_node.set_name("add");
            op_node.RegisterNextNode(rhs_node);
            op_node.RegisterBackwardFunction(rhs_func);
        }
    }

    for (const auto& graph_op_node : graph_op_nodes) {
        std::shared_ptr<ArrayNode> out_node = out.GetOrCreateNode(graph_op_node.first, true);
        gsl::span<const std::shared_ptr<ArrayNode>> next_nodes = graph_op_node.second.next_nodes();
        out_node->set_next_node(std::make_shared<OpNode>(graph_op_node.second));
        out_node->set_rank((*std::max_element(next_nodes.begin(), next_nodes.end(),
                                              [](const std::shared_ptr<ArrayNode>& a, const std::shared_ptr<ArrayNode>& b) {
                                                  return a->rank() < b->rank();
                                              }))
                               ->rank() +
                           1);
    }

    Device device = GetCurrentDevice();
    if (device == MakeDevice("cpu")) {
        xchainer::Add(*this, rhs, out);
#ifdef XCHAINER_ENABLE_CUDA
    } else if (device == MakeDevice("cuda")) {
        xchainer::cuda::Add(*this, rhs, out);
#endif  // XCHAINER_ENABLE_CUDA
    } else {
        throw DeviceError("invalid device");
    }
}

void Array::Mul(const Array& rhs, Array& out) const {
    /*
    if ((&out == this || &out == &rhs) && out.requires_grad()) {
        throw XchainerError("In-place operation (Mul) is not supported for an array with requires_grad=true.");
    }
    */

    // TODO(sonots): dtype conversion
    CheckEqual(dtype(), rhs.dtype());
    // TODO(sonots): broadcasting
    CheckEqual(shape(), rhs.shape());

    std::unordered_map<std::string, OpNode> graph_op_nodes;

    // LHS
    for (auto& named_node : body_->nodes_) {
        const std::string& graph_name = named_node.first;
        if (named_node.second.requires_grad) {
            std::shared_ptr<ArrayNode> lhs_node = mutable_node(graph_name);
            // TODO(sonots): turn off constructing graph (requires_grad) in backward (but, turn on for double backprop)
            auto lhs_func = [rhs_view = rhs.MakeView()](const Array& gout) { return gout * rhs_view; };
            OpNode& op_node = graph_op_nodes[graph_name];
            op_node.set_name("mul");
            op_node.RegisterNextNode(lhs_node);
            op_node.RegisterBackwardFunction(lhs_func);
        }
    }

    // RHS
    for (auto& named_node : rhs.nodes()) {
        const std::string& graph_name = named_node.first;
        if (named_node.second.requires_grad) {
            std::shared_ptr<ArrayNode> rhs_node = rhs.mutable_node(graph_name);
            auto rhs_func = [lhs_view = MakeView()](const Array& gout) { return gout * lhs_view; };
            OpNode& op_node = graph_op_nodes[graph_name];
            op_node.set_name("mul");
            op_node.RegisterNextNode(rhs_node);
            op_node.RegisterBackwardFunction(rhs_func);
        }
    }

    for (const auto& graph_op_node : graph_op_nodes) {
        std::shared_ptr<ArrayNode> out_node = out.GetOrCreateNode(graph_op_node.first, true);
        gsl::span<const std::shared_ptr<ArrayNode>> next_nodes = graph_op_node.second.next_nodes();
        out_node->set_next_node(std::make_shared<OpNode>(graph_op_node.second));
        out_node->set_rank((*std::max_element(next_nodes.begin(), next_nodes.end(),
                                              [](const std::shared_ptr<ArrayNode>& a, const std::shared_ptr<ArrayNode>& b) {
                                                  return a->rank() < b->rank();
                                              }))
                               ->rank() +
                           1);
    }

    Device device = GetCurrentDevice();
    if (device == MakeDevice("cpu")) {
        xchainer::Mul(*this, rhs, out);
#ifdef XCHAINER_ENABLE_CUDA
    } else if (device == MakeDevice("cuda")) {
        xchainer::cuda::Mul(*this, rhs, out);
#endif  // XCHAINER_ENABLE_CUDA
    } else {
        throw DeviceError("invalid device");
    }
}

void Array::Fill(Scalar value) {
    Device device = GetCurrentDevice();
    if (device == MakeDevice("cpu")) {
        xchainer::Fill(*this, value);
#ifdef XCHAINER_ENABLE_CUDA
    } else if (device == MakeDevice("cuda")) {
        xchainer::cuda::Fill(*this, value);
#endif  // XCHAINER_ENABLE_CUDA
    } else {
        throw DeviceError("invalid device");
    }
}

std::string Array::ToString() const { return ArrayRepr(*this); }

namespace {

void DebugDumpComputationalGraph(std::ostream& os, const ArrayNode& array_node, int indent) {
    static const char kIndentChar = ' ';

    os << std::string(static_cast<size_t>(indent * 2), kIndentChar) << "ArrayNode<" << &array_node << ">" << std::endl;

    std::shared_ptr<const OpNode> op = array_node.next_node();
    if (op) {
        os << std::string(static_cast<size_t>((indent + 1) * 2), kIndentChar) << "Op<" << op->name() << ">" << std::endl;
        for (const std::shared_ptr<const ArrayNode>& next_node : op->next_nodes()) {
            DebugDumpComputationalGraph(os, *next_node, static_cast<size_t>(indent + 2));
        }
    }
}

}  // namespace

void DebugDumpComputationalGraph(std::ostream& os, const Array& array, int indent) {
    // DebugDumpComputationalGraph(os, *array.node(), indent);
}

}  // namespace xchainer
<commit_msg>Clean up array<commit_after>#include "xchainer/array.h"

#include <algorithm>
#include <cassert>
#include <cstring>
#include <string>
// #include <unordered_set>
#include <unordered_map>

#ifdef XCHAINER_ENABLE_CUDA
#include <cuda.h>
#include <cuda_runtime.h>
#endif  // XCHAINER_ENABLE_CUDA
#include <gsl/gsl>

#include "xchainer/array_fill.h"
#include "xchainer/array_math.h"
#include "xchainer/array_repr.h"
#ifdef XCHAINER_ENABLE_CUDA
#include "xchainer/cuda/array_fill.h"
#include "xchainer/cuda/array_math.h"
#include "xchainer/cuda/cuda_runtime.h"
#endif  // XCHAINER_ENABLE_CUDA
#include "xchainer/device.h"
#include "xchainer/memory.h"
#include "xchainer/op_node.h"
#include "xchainer/scalar.h"

namespace xchainer {
namespace internal {

// Private definition of ArrayBody
ArrayBody::ArrayBody(const Shape& shape, Dtype dtype, bool requires_grad, bool is_contiguous, std::shared_ptr<void> data, int64_t offset,
                     std::shared_ptr<ArrayNode> node, std::string graph_name)
    : shape_(shape),
      dtype_(dtype),
      is_contiguous_(is_contiguous),
      data_(std::move(data)),
      offset_(offset),
      nodes_({{std::move(graph_name), {std::move(node), requires_grad}}}) {}

const std::shared_ptr<ArrayNode>& ArrayBody::GetOrCreateNode(const std::string& graph_name, bool default_requires_grad) {
    auto named_nodes =
        std::find_if(nodes_.begin(), nodes_.end(),
                     [&graph_name](const std::pair<std::string, ArrayNodeGradientProperty>& node) { return node.first == graph_name; });

    if (named_nodes != nodes_.end()) {
        // Return match
        return named_nodes->second.node;
    }

    // Create and return new
    std::shared_ptr<ArrayNode> node = std::make_shared<ArrayNode>();
    ArrayNodeGradientProperty node_property(node, default_requires_grad);
    nodes_.push_back({graph_name, node_property});
    return nodes_.back().second.node;
}

}  // namespace internal

Array::Array(const Shape& shape, Dtype dtype, std::shared_ptr<void> data, std::shared_ptr<ArrayNode> node, bool requires_grad,
             bool is_contiguous, int64_t offset, const std::string& graph_name)
    : body_(std::make_shared<internal::ArrayBody>(shape, dtype, requires_grad, is_contiguous, std::move(data), offset, std::move(node),
                                                  std::move(graph_name))) {}

Array::Array(const Array& other)
    : Array(other.shape(), other.dtype(), internal::Allocate(GetCurrentDevice(), other.total_bytes()), std::make_shared<ArrayNode>(),
            other.requires_grad(), true, 0, "") {
    // TODO(hvy): Do no set default empty string graph_name, but instead skip initializing the ArrayNode here

    // Memory layout-related members are not copied in this copy ctor since new C-contiguous memory is allocated
    other.CopyTo(*this);
}

// TODO(hvy): Multi-graph support
// const std::shared_ptr<ArrayNode>& Array::RenewNode() { return body_->node_ = std::make_shared<ArrayNode>(); }

const nonstd::optional<Array>& Array::grad(const std::string& graph_name) const { return body_->node(graph_name)->grad(); }

void Array::set_grad(Array grad, const std::string& graph_name) { body_->mutable_node(graph_name)->set_grad(std::move(grad)); }

void Array::ClearGrad(const std::string& graph_name) { body_->mutable_node(graph_name)->ClearGrad(); }

// TODO(hvy): Multi-graph support, i.e. specify graph_name
Array Array::FromBuffer(const Shape& shape, Dtype dtype, std::shared_ptr<void> data) {
    auto bytesize = static_cast<size_t>(shape.total_size() * GetElementSize(dtype));
    std::shared_ptr<void> device_data = internal::MemoryFromBuffer(GetCurrentDevice(), data, bytesize);
    return {shape, dtype, device_data, std::make_unique<ArrayNode>()};
}

Array Array::Empty(const Shape& shape, Dtype dtype) {
    auto bytesize = static_cast<size_t>(shape.total_size() * GetElementSize(dtype));
    std::shared_ptr<void> data = internal::Allocate(GetCurrentDevice(), bytesize);
    return {shape, dtype, data, std::make_unique<ArrayNode>()};
}

Array Array::Full(const Shape& shape, Scalar scalar, Dtype dtype) {
    Array array = Empty(shape, dtype);
    array.Fill(scalar);
    return array;
}

Array Array::Full(const Shape& shape, Scalar scalar) { return Full(shape, scalar, scalar.dtype()); }

Array Array::Zeros(const Shape& shape, Dtype dtype) { return Full(shape, 0, dtype); }

Array Array::Ones(const Shape& shape, Dtype dtype) { return Full(shape, 1, dtype); }

Array Array::EmptyLike(const Array& array) { return Empty(array.shape(), array.dtype()); }

Array Array::FullLike(const Array& array, Scalar scalar) { return Full(array.shape(), scalar, array.dtype()); }

Array Array::ZerosLike(const Array& array) { return Zeros(array.shape(), array.dtype()); }

Array Array::OnesLike(const Array& array) { return Ones(array.shape(), array.dtype()); }

Array& Array::operator+=(const Array& rhs) {
    Add(rhs, *this);
    return *this;
}

Array& Array::operator*=(const Array& rhs) {
    Mul(rhs, *this);
    return *this;
}

Array Array::operator+(const Array& rhs) const {
    Array out = Array::EmptyLike(*this);
    Add(rhs, out);
    return out;
}

Array Array::operator*(const Array& rhs) const {
    Array out = Array::EmptyLike(*this);
    Mul(rhs, out);
    return out;
}

Array Array::Copy() const {
    Array out = Array::EmptyLike(*this);
    CopyTo(out);
    return out;
}

void Array::CopyTo(Array& out) const {
    for (auto& named_node : body_->nodes_) {    // For each graph, or ArrayNode
        if (named_node.second.requires_grad) {  // If ArrayNode requires gradients
            const ArrayNodeGradientProperty& node_prop = named_node.second;
            std::shared_ptr<ArrayNode> out_node = out.GetOrCreateNode(named_node.first, true);
            int64_t out_rank = node_prop.node->rank();
            auto next_nodes = std::vector<std::shared_ptr<ArrayNode>>{node_prop.node};
            auto in_func = [](const Array& gout) { return gout; };
            auto backward_functions = std::vector<std::function<Array(const Array&)>>{in_func};
            auto op_node = std::make_shared<OpNode>("copy", out_rank, next_nodes, backward_functions);
            out_node->set_next_node(op_node);
            out_node->set_rank(out_rank + 1);
        }
    }

    // TODO(hvy): When non-C-contiguous orders are supported, we cannot blindly copy all elements but need to take
    // is_contiguous_ and offset_ into account
    internal::MemoryCopy(out.data().get(), body_->data_.get(), total_bytes());
}

void Array::Add(const Array& rhs, Array& out) const {
    /*
    if ((&out == this || &out == &rhs) && out.requires_grad()) {
        throw XchainerError("In-place operation (Add) is not supported for an array with requires_grad=true.");
    }
    */

    // TODO(sonots): dtype conversion
    CheckEqual(dtype(), rhs.dtype());
    // TODO(sonots): broadcasting
    CheckEqual(shape(), rhs.shape());

    std::unordered_map<std::string, OpNode> graph_op_nodes;

    // LHS
    for (auto& named_node : body_->nodes_) {  // For each graph
        const std::string& graph_name = named_node.first;
        if (named_node.second.requires_grad) {
            std::shared_ptr<ArrayNode> lhs_node = mutable_node(graph_name);
            auto lhs_func = [](const Array& gout) { return gout; };
            OpNode& op_node = graph_op_nodes[graph_name];  // Create if not exists
            op_node.set_name("add");
            op_node.RegisterNextNode(lhs_node);
            op_node.RegisterBackwardFunction(lhs_func);
        }
    }

    // RHS
    for (auto& named_node : rhs.nodes()) {
        const std::string& graph_name = named_node.first;
        if (named_node.second.requires_grad) {
            std::shared_ptr<ArrayNode> rhs_node = rhs.mutable_node(graph_name);
            auto rhs_func = [](const Array& gout) { return gout; };
            OpNode& op_node = graph_op_nodes[graph_name];
            op_node.set_name("add");
            op_node.RegisterNextNode(rhs_node);
            op_node.RegisterBackwardFunction(rhs_func);
        }
    }

    for (const auto& graph_op_node : graph_op_nodes) {
        std::shared_ptr<ArrayNode> out_node = out.GetOrCreateNode(graph_op_node.first, true);
        gsl::span<const std::shared_ptr<ArrayNode>> next_nodes = graph_op_node.second.next_nodes();
        out_node->set_next_node(std::make_shared<OpNode>(graph_op_node.second));
        out_node->set_rank((*std::max_element(next_nodes.begin(), next_nodes.end(),
                                              [](const std::shared_ptr<ArrayNode>& a, const std::shared_ptr<ArrayNode>& b) {
                                                  return a->rank() < b->rank();
                                              }))
                               ->rank() +
                           1);
    }

    Device device = GetCurrentDevice();
    if (device == MakeDevice("cpu")) {
        xchainer::Add(*this, rhs, out);
#ifdef XCHAINER_ENABLE_CUDA
    } else if (device == MakeDevice("cuda")) {
        xchainer::cuda::Add(*this, rhs, out);
#endif  // XCHAINER_ENABLE_CUDA
    } else {
        throw DeviceError("invalid device");
    }
}

void Array::Mul(const Array& rhs, Array& out) const {
    /*
    if ((&out == this || &out == &rhs) && out.requires_grad()) {
        throw XchainerError("In-place operation (Mul) is not supported for an array with requires_grad=true.");
    }
    */

    // TODO(sonots): dtype conversion
    CheckEqual(dtype(), rhs.dtype());
    // TODO(sonots): broadcasting
    CheckEqual(shape(), rhs.shape());

    std::unordered_map<std::string, OpNode> graph_op_nodes;

    // LHS
    for (auto& named_node : body_->nodes_) {
        const std::string& graph_name = named_node.first;
        if (named_node.second.requires_grad) {
            std::shared_ptr<ArrayNode> lhs_node = mutable_node(graph_name);
            // TODO(sonots): turn off constructing graph (requires_grad) in backward (but, turn on for double backprop)
            auto lhs_func = [rhs_view = rhs.MakeView()](const Array& gout) { return gout * rhs_view; };
            OpNode& op_node = graph_op_nodes[graph_name];
            op_node.set_name("mul");
            op_node.RegisterNextNode(lhs_node);
            op_node.RegisterBackwardFunction(lhs_func);
        }
    }

    // RHS
    for (auto& named_node : rhs.nodes()) {
        const std::string& graph_name = named_node.first;
        if (named_node.second.requires_grad) {
            std::shared_ptr<ArrayNode> rhs_node = rhs.mutable_node(graph_name);
            auto rhs_func = [lhs_view = MakeView()](const Array& gout) { return gout * lhs_view; };
            OpNode& op_node = graph_op_nodes[graph_name];
            op_node.set_name("mul");
            op_node.RegisterNextNode(rhs_node);
            op_node.RegisterBackwardFunction(rhs_func);
        }
    }

    for (const auto& graph_op_node : graph_op_nodes) {
        std::shared_ptr<ArrayNode> out_node = out.GetOrCreateNode(graph_op_node.first, true);
        gsl::span<const std::shared_ptr<ArrayNode>> next_nodes = graph_op_node.second.next_nodes();
        out_node->set_next_node(std::make_shared<OpNode>(graph_op_node.second));
        out_node->set_rank((*std::max_element(next_nodes.begin(), next_nodes.end(),
                                              [](const std::shared_ptr<ArrayNode>& a, const std::shared_ptr<ArrayNode>& b) {
                                                  return a->rank() < b->rank();
                                              }))
                               ->rank() +
                           1);
    }

    Device device = GetCurrentDevice();
    if (device == MakeDevice("cpu")) {
        xchainer::Mul(*this, rhs, out);
#ifdef XCHAINER_ENABLE_CUDA
    } else if (device == MakeDevice("cuda")) {
        xchainer::cuda::Mul(*this, rhs, out);
#endif  // XCHAINER_ENABLE_CUDA
    } else {
        throw DeviceError("invalid device");
    }
}

void Array::Fill(Scalar value) {
    Device device = GetCurrentDevice();
    if (device == MakeDevice("cpu")) {
        xchainer::Fill(*this, value);
#ifdef XCHAINER_ENABLE_CUDA
    } else if (device == MakeDevice("cuda")) {
        xchainer::cuda::Fill(*this, value);
#endif  // XCHAINER_ENABLE_CUDA
    } else {
        throw DeviceError("invalid device");
    }
}

std::string Array::ToString() const { return ArrayRepr(*this); }

namespace {

void DebugDumpComputationalGraph(std::ostream& os, const ArrayNode& array_node, int indent) {
    static const char kIndentChar = ' ';

    os << std::string(static_cast<size_t>(indent * 2), kIndentChar) << "ArrayNode<" << &array_node << ">" << std::endl;

    std::shared_ptr<const OpNode> op = array_node.next_node();
    if (op) {
        os << std::string(static_cast<size_t>((indent + 1) * 2), kIndentChar) << "Op<" << op->name() << ">" << std::endl;
        for (const std::shared_ptr<const ArrayNode>& next_node : op->next_nodes()) {
            DebugDumpComputationalGraph(os, *next_node, static_cast<size_t>(indent + 2));
        }
    }
}

}  // namespace

void DebugDumpComputationalGraph(std::ostream& os, const Array& array, int indent) {
    // DebugDumpComputationalGraph(os, *array.node(), indent);
}

}  // namespace xchainer
<|endoftext|>