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

#include <algorithm>
#include <cassert>
#include <cstring>
#include <string>
#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/error.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 is_contiguous, std::shared_ptr<void> data, int64_t offset,
                     std::vector<std::shared_ptr<ArrayNode>> nodes)
    : shape_(shape), dtype_(dtype), is_contiguous_(is_contiguous), data_(std::move(data)), offset_(offset), nodes_(std::move(nodes)) {}

bool ArrayBody::HasNode(const GraphId& graph_id) const {
    return std::find_if(nodes_.begin(), nodes_.end(), [&graph_id](const auto& node) { return graph_id == node->graph_id(); }) !=
           nodes_.end();
}

std::shared_ptr<const ArrayNode> ArrayBody::GetNode(const GraphId& graph_id) const { return GetMutableNode(graph_id); }

const std::shared_ptr<ArrayNode>& ArrayBody::GetMutableNode(const GraphId& graph_id) const {
    auto it = std::find_if(nodes_.begin(), nodes_.end(), [&graph_id](const auto& node) { return graph_id == node->graph_id(); });
    if (it == nodes_.end()) {
        throw XchainerError("Cannot find ArrayNode for graph: " + graph_id);
    }
    return *it;
}

const std::shared_ptr<ArrayNode>& ArrayBody::CreateNode(const GraphId& graph_id) {
    if (HasNode(graph_id)) {
        throw XchainerError("Duplicate graph registration: " + graph_id);
    }
    nodes_.emplace_back(std::make_shared<ArrayNode>(graph_id));
    return nodes_.back();
}

void SetUpOpNodes(const std::string& name, const std::vector<std::reference_wrapper<const Array>>& inputs, Array& out,
                  const std::vector<std::function<Array(const Array&)>>& backward_functions) {
    if (inputs.size() != backward_functions.size()) {
        throw XchainerError("Cannot construct a graph where numbers of input Arrays and backward functions do not match.");
    }

    std::unordered_map<GraphId, std::shared_ptr<OpNode>> graph_edges;

    // Helper function to create an edge in the graph
    auto create_edge = [&name, &graph_edges](const std::shared_ptr<ArrayNode>& next_node, auto& backward_function) {
        std::shared_ptr<OpNode>& op_node = graph_edges[next_node->graph_id()];  // Create if not exists
        if (!op_node) {
            op_node = std::make_shared<OpNode>(name);
        }
        op_node->set_rank(std::max(op_node->rank(), next_node->rank()));
        op_node->RegisterNextNode(next_node, backward_function);
    };

    for (size_t i = 0; i < inputs.size(); ++i) {                                  // For each input
        for (const std::shared_ptr<ArrayNode>& node : inputs[i].get().nodes()) {  // For each graph, create an edge
            create_edge(node, backward_functions[i]);
        }
    }

    if (!graph_edges.empty() && std::any_of(inputs.begin(), inputs.end(), [&out](const Array& input) { return &out == &input; })) {
        throw XchainerError("In-place operation (" + name + ") is not supported for an array that require gradients.");
    }

    // Bind edges to output
    for (const auto& edge : graph_edges) {
        const GraphId& graph_id = edge.first;
        const std::shared_ptr<OpNode>& op_node = edge.second;

        const std::shared_ptr<ArrayNode>& out_node = out.body()->CreateNode(graph_id);
        out_node->set_next_node(op_node);
        out_node->set_rank(op_node->rank() + 1);
    }
}

}  // namespace internal

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

Array::Array(const Array& other)
    : body_(std::make_shared<internal::ArrayBody>(other.shape(), other.dtype(), other.is_contiguous(), other.body_->data_, other.offset(),
                                                  other.body_->nodes_)) {}

const nonstd::optional<Array>& Array::GetGrad(const GraphId& graph_id) const { return body_->GetNode(graph_id)->grad(); }

void Array::SetGrad(Array grad, const GraphId& graph_id) { body_->GetMutableNode(graph_id)->set_grad(std::move(grad)); }

void Array::ClearGrad(const GraphId& graph_id) { body_->GetMutableNode(graph_id)->ClearGrad(); }

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};
}

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};
}

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 {
    internal::SetUpOpNodes("copy", {*this}, out, {[](const Array& gout) { return gout; }});

    // 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());
}

Array Array::AsConstant(CopyKind kind) const {
    std::vector<GraphId> graph_ids;
    for (const std::shared_ptr<ArrayNode>& node : nodes()) {
        graph_ids.emplace_back(node->graph_id());
    }
    return AsConstant(kind, graph_ids);
}

Array Array::AsConstant(CopyKind kind, const std::vector<GraphId>& graph_ids) const {
    switch (kind) {
        case CopyKind::kCopy:
            // TODO(takgi): implement deep copy version
            throw NotImplementedError("not implemented");
        case CopyKind::kView: {
            Array out{shape(), dtype(), body_->data_, is_contiguous(), offset()};
            for (const std::shared_ptr<ArrayNode>& node : nodes()) {
                if (std::find(graph_ids.begin(), graph_ids.end(), node->graph_id()) == graph_ids.end()) {
                    out.body_->nodes_.emplace_back(node);
                }
            }
            return std::move(out);
        }
        default:
            assert(false);  // should never be reached
    }
}

void Array::Add(const Array& rhs, Array& out) const {
    // TODO(sonots): dtype conversion
    CheckEqual(dtype(), rhs.dtype());
    // TODO(sonots): broadcasting
    CheckEqual(shape(), rhs.shape());

    auto lhs_backward_function = [](const Array& gout) -> Array { return gout; };
    auto rhs_backward_function = lhs_backward_function;
    internal::SetUpOpNodes("add", {*this, rhs}, out, {lhs_backward_function, rhs_backward_function});

    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 {
    // TODO(sonots): dtype conversion
    CheckEqual(dtype(), rhs.dtype());
    // TODO(sonots): broadcasting
    CheckEqual(shape(), rhs.shape());

    auto lhs_backward_function = [other_view = rhs](const Array& gout) { return gout * other_view; };
    auto rhs_backward_function = [other_view = *this](const Array& gout) { return gout * other_view; };
    internal::SetUpOpNodes("mul", {*this, rhs}, out, {lhs_backward_function, rhs_backward_function});

    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, const GraphId& graph_id, int indent) {
    DebugDumpComputationalGraph(os, *array.GetNode(graph_id), indent);
}

}  // namespace xchainer
<commit_msg>Fix implementation<commit_after>#include "xchainer/array.h"

#include <algorithm>
#include <cassert>
#include <cstring>
#include <string>
#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/error.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 is_contiguous, std::shared_ptr<void> data, int64_t offset,
                     std::vector<std::shared_ptr<ArrayNode>> nodes)
    : shape_(shape), dtype_(dtype), is_contiguous_(is_contiguous), data_(std::move(data)), offset_(offset), nodes_(std::move(nodes)) {}

bool ArrayBody::HasNode(const GraphId& graph_id) const {
    return std::find_if(nodes_.begin(), nodes_.end(), [&graph_id](const auto& node) { return graph_id == node->graph_id(); }) !=
           nodes_.end();
}

std::shared_ptr<const ArrayNode> ArrayBody::GetNode(const GraphId& graph_id) const { return GetMutableNode(graph_id); }

const std::shared_ptr<ArrayNode>& ArrayBody::GetMutableNode(const GraphId& graph_id) const {
    auto it = std::find_if(nodes_.begin(), nodes_.end(), [&graph_id](const auto& node) { return graph_id == node->graph_id(); });
    if (it == nodes_.end()) {
        throw XchainerError("Cannot find ArrayNode for graph: " + graph_id);
    }
    return *it;
}

const std::shared_ptr<ArrayNode>& ArrayBody::CreateNode(const GraphId& graph_id) {
    if (HasNode(graph_id)) {
        throw XchainerError("Duplicate graph registration: " + graph_id);
    }
    nodes_.emplace_back(std::make_shared<ArrayNode>(graph_id));
    return nodes_.back();
}

void SetUpOpNodes(const std::string& name, const std::vector<std::reference_wrapper<const Array>>& inputs, Array& out,
                  const std::vector<std::function<Array(const Array&)>>& backward_functions) {
    if (inputs.size() != backward_functions.size()) {
        throw XchainerError("Cannot construct a graph where numbers of input Arrays and backward functions do not match.");
    }

    std::unordered_map<GraphId, std::shared_ptr<OpNode>> graph_edges;

    // Helper function to create an edge in the graph
    auto create_edge = [&name, &graph_edges](const std::shared_ptr<ArrayNode>& next_node, auto& backward_function) {
        std::shared_ptr<OpNode>& op_node = graph_edges[next_node->graph_id()];  // Create if not exists
        if (!op_node) {
            op_node = std::make_shared<OpNode>(name);
        }
        op_node->set_rank(std::max(op_node->rank(), next_node->rank()));
        op_node->RegisterNextNode(next_node, backward_function);
    };

    for (size_t i = 0; i < inputs.size(); ++i) {                                  // For each input
        for (const std::shared_ptr<ArrayNode>& node : inputs[i].get().nodes()) {  // For each graph, create an edge
            create_edge(node, backward_functions[i]);
        }
    }

    if (!graph_edges.empty() && std::any_of(inputs.begin(), inputs.end(), [&out](const Array& input) { return &out == &input; })) {
        throw XchainerError("In-place operation (" + name + ") is not supported for an array that require gradients.");
    }

    // Bind edges to output
    for (const auto& edge : graph_edges) {
        const GraphId& graph_id = edge.first;
        const std::shared_ptr<OpNode>& op_node = edge.second;

        const std::shared_ptr<ArrayNode>& out_node = out.body()->CreateNode(graph_id);
        out_node->set_next_node(op_node);
        out_node->set_rank(op_node->rank() + 1);
    }
}

}  // namespace internal

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

Array::Array(const Array& other)
    : body_(std::make_shared<internal::ArrayBody>(other.shape(), other.dtype(), other.is_contiguous(), other.body_->data_, other.offset(),
                                                  other.body_->nodes_)) {}

const nonstd::optional<Array>& Array::GetGrad(const GraphId& graph_id) const { return body_->GetNode(graph_id)->grad(); }

void Array::SetGrad(Array grad, const GraphId& graph_id) { body_->GetMutableNode(graph_id)->set_grad(std::move(grad)); }

void Array::ClearGrad(const GraphId& graph_id) { body_->GetMutableNode(graph_id)->ClearGrad(); }

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};
}

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};
}

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 {
    internal::SetUpOpNodes("copy", {*this}, out, {[](const Array& gout) { return gout; }});

    // 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());
}

Array Array::AsConstant(CopyKind kind) const {
    switch (kind) {
        case CopyKind::kCopy:
            // TODO(takgi): implement deep copy version
            throw NotImplementedError("not implemented");
        case CopyKind::kView:
            return Array{shape(), dtype(), body_->data_, is_contiguous(), offset()};
        default:
            assert(false);  // should never be reached
    }
}

Array Array::AsConstant(CopyKind kind, const std::vector<GraphId>& graph_ids) const {
    switch (kind) {
        case CopyKind::kCopy:
            // TODO(takgi): implement deep copy version
            throw NotImplementedError("not implemented");
        case CopyKind::kView: {
            Array out{shape(), dtype(), body_->data_, is_contiguous(), offset()};
            for (const std::shared_ptr<ArrayNode>& node : nodes()) {
                if (std::find(graph_ids.begin(), graph_ids.end(), node->graph_id()) == graph_ids.end()) {
                    out.body_->nodes_.emplace_back(node);
                }
            }
            return std::move(out);
        }
        default:
            assert(false);  // should never be reached
    }
}

void Array::Add(const Array& rhs, Array& out) const {
    // TODO(sonots): dtype conversion
    CheckEqual(dtype(), rhs.dtype());
    // TODO(sonots): broadcasting
    CheckEqual(shape(), rhs.shape());

    auto lhs_backward_function = [](const Array& gout) -> Array { return gout; };
    auto rhs_backward_function = lhs_backward_function;
    internal::SetUpOpNodes("add", {*this, rhs}, out, {lhs_backward_function, rhs_backward_function});

    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 {
    // TODO(sonots): dtype conversion
    CheckEqual(dtype(), rhs.dtype());
    // TODO(sonots): broadcasting
    CheckEqual(shape(), rhs.shape());

    auto lhs_backward_function = [other_view = rhs](const Array& gout) { return gout * other_view; };
    auto rhs_backward_function = [other_view = *this](const Array& gout) { return gout * other_view; };
    internal::SetUpOpNodes("mul", {*this, rhs}, out, {lhs_backward_function, rhs_backward_function});

    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, const GraphId& graph_id, int indent) {
    DebugDumpComputationalGraph(os, *array.GetNode(graph_id), indent);
}

}  // namespace xchainer
<|endoftext|>


<commit_before>#ifndef MJOLNIR_INPUT_READ_UNIT_SYSTEM_HPP
#define MJOLNIR_INPUT_READ_UNIT_SYSTEM_HPP
#include <extlib/toml/toml.hpp>
#include <mjolnir/math/constants.hpp>
#include <mjolnir/core/Unit.hpp>
#include <mjolnir/util/logger.hpp>
#include <mjolnir/input/read_simulator.hpp>
#include <cmath>

namespace mjolnir
{

template<typename traitsT>
std::unique_ptr<SimulatorBase> read_units(const toml::table& data)
{
    MJOLNIR_GET_DEFAULT_LOGGER();
    MJOLNIR_LOG_FUNCTION();
    using real_type = typename traitsT::real_type;
    using phys_type = physics::constants<real_type>;
    using unit_type = unit::constants<real_type>;

    const auto& units  = toml::find<toml::value>(data,  "units");
    const auto& energy = toml::find<std::string>(units, "energy");
    const auto& length = toml::find<std::string>(units, "length");
    MJOLNIR_LOG_NOTICE("energy unit is [", energy, ']');
    MJOLNIR_LOG_NOTICE("length unit is [", length, ']');

    if(energy == "kcal/mol")
    {
        // kB [J/K] -> [kcal/mol/K] by * (J to cal) * 1e-3 * (/mol)
        phys_type::set_kB(phys_type::kB() * (unit_type::J_to_cal / 1000.0) *
                          unit_type::avogadro_constant);

        // eps0 [F/m] == [C^2/J/m] -> [C^2/(kcal/mol)/m]
        phys_type::set_eps0(phys_type::eps0() * (1000.0 / unit_type::J_to_cal) /
                            unit_type::avogadro_constant);
    }
    else if(energy == "kJ/mol")
    {
        // kB [J/K] -> [kJ/mol/K]
        phys_type::set_kB(phys_type::kB() * 1e-3 * unit_type::avogadro_constant);
        // eps0 [F/m] == [C^2/J/m] -> [C^2/kJ/mol/m]
        phys_type::set_eps0(phys_type::eps0() * 1e+3 /
                            unit_type::avogadro_constant);
    }
    else
    {
        throw_exception<std::runtime_error>(toml::format_error("[error] "
            "mjolnir::read_units: unknown unit for energy: `",
            toml::find(units, "energy"), "here", {
            "expected value is one of the following.",
            "- \"kcal/mol\"",
            "- \"kJ/mol\""
            }));
    }

    // until here, SI `m` are used as length unit.

    // 1 [mol/m^3] = 1e-3  [mol/L] = 1e-27 [mol/nm^3] = 1e-30 [mol/A^3]
    //               1     [mol/L] = 1e-24 [mol/nm^3] = 1e-27 [mol/A^3]
    if(length == "angstrom" || length == u8"Å")
    {
        // eps0 [C^2/Energy/m] -> [C^2/Energy/Angstrom]
        phys_type::set_eps0(phys_type::eps0() / unit_type::m_to_angstrom);

        // 1 m = 10^9 nm, 1 nm = 10^-9 m
        phys_type::set_m_to_length(unit_type::m_to_angstrom);
        phys_type::set_length_to_m(unit_type::angstrom_to_m);

        // 1 [L] = 1e-3 [m^3] = 1e+24 [nm^3]; 1 [m^3] = 1e27 [nm^3]
        phys_type::set_L_to_volume(1e-3 * std::pow(unit_type::m_to_angstrom, 3));
        phys_type::set_volume_to_L(1e+3 * std::pow(unit_type::angstrom_to_m, 3));

        MJOLNIR_LOG_INFO("1 [m] = ", phys_type::m_to_length(), " [", length, "]");
        MJOLNIR_LOG_INFO("1 [", length, "] = ", phys_type::length_to_m(), " [m]");

        MJOLNIR_LOG_INFO("1 [L] = ", phys_type::L_to_volume(), " [", length, "^3]");
        MJOLNIR_LOG_INFO("1 [", length, "^3] = ", phys_type::volume_to_L(), " [L]");
    }
    else if(length == "nm")
    {
        // eps0 [C^2/Energy/m] -> [C^2/Energy/nm]
        phys_type::set_eps0(phys_type::eps0() / unit_type::m_to_nm);

        // 1 m = 10^9 nm, 1 nm = 10^-9 m
        phys_type::set_m_to_length(unit_type::m_to_nm);
        phys_type::set_length_to_m(unit_type::nm_to_m);

        // 1 [L] = 1e-3 [m^3] = 1e+24 [nm^3]; 1 [m^3] = 1e27 [nm^3]
        phys_type::set_L_to_volume(1e-3 * std::pow(unit_type::m_to_nm, 3));
        phys_type::set_volume_to_L(1e+3 * std::pow(unit_type::nm_to_m, 3));

        MJOLNIR_LOG_INFO("1 [m] = ", phys_type::m_to_length(), " [", length, "]");
        MJOLNIR_LOG_INFO("1 [", length, "] = ", phys_type::length_to_m(), " [m]");

        MJOLNIR_LOG_INFO("1 [L] = ", phys_type::L_to_volume(), " [", length, "^3]");
        MJOLNIR_LOG_INFO("1 [", length, "^3] = ", phys_type::volume_to_L(), " [L]");
    }
    else
    {
        throw_exception<std::runtime_error>(toml::format_error("[error] "
            "mjolnir::read_units: unknown unit for length: `",
            toml::find(units, "length"), "here", {
            "expected value is one of the following.",
            "- \"nm\"",
            "- \"angstrom\""
            }));
    }

    MJOLNIR_LOG_INFO(u8"phys::kB = ", phys_type::kB(), " [", energy, "]");
    MJOLNIR_LOG_INFO(u8"phys::NA = ", phys_type::NA(), " [1/mol]");
    MJOLNIR_LOG_INFO(u8"phys::ε0 = ", phys_type::eps0(),
                     " [e^2 / (", energy, '*', length, ")]");

    return read_simulator<traitsT>(data);
}

#ifdef MJOLNIR_SEPARATE_BUILD
extern template std::unique_ptr<SimulatorBase> read_units<SimulatorTraits<double, UnlimitedBoundary>>(const toml::table& data);
extern template std::unique_ptr<SimulatorBase> read_units<SimulatorTraits<float,  UnlimitedBoundary>>(const toml::table& data);
extern template std::unique_ptr<SimulatorBase> read_units<SimulatorTraits<double, CuboidalPeriodicBoundary>>(const toml::table& data);
extern template std::unique_ptr<SimulatorBase> read_units<SimulatorTraits<float,  CuboidalPeriodicBoundary>>(const toml::table& data);
#endif

} // mjolnir
#endif// MJOLNIR_READ_UNIT_SYSTEM_HPP
<commit_msg>feat: set energy unit names in read_units<commit_after>#ifndef MJOLNIR_INPUT_READ_UNIT_SYSTEM_HPP
#define MJOLNIR_INPUT_READ_UNIT_SYSTEM_HPP
#include <extlib/toml/toml.hpp>
#include <mjolnir/math/constants.hpp>
#include <mjolnir/core/Unit.hpp>
#include <mjolnir/util/logger.hpp>
#include <mjolnir/input/read_simulator.hpp>
#include <cmath>

namespace mjolnir
{

template<typename traitsT>
std::unique_ptr<SimulatorBase> read_units(const toml::table& data)
{
    MJOLNIR_GET_DEFAULT_LOGGER();
    MJOLNIR_LOG_FUNCTION();
    using real_type = typename traitsT::real_type;
    using phys_type = physics::constants<real_type>;
    using unit_type = unit::constants<real_type>;

    const auto& units  = toml::find<toml::value>(data,  "units");
    const auto& energy = toml::find<std::string>(units, "energy");
    const auto& length = toml::find<std::string>(units, "length");
    MJOLNIR_LOG_NOTICE("energy unit is [", energy, ']');
    MJOLNIR_LOG_NOTICE("length unit is [", length, ']');

    if(energy == "kcal/mol")
    {
        // kB [J/K] -> [kcal/mol/K] by * (J to cal) * 1e-3 * (/mol)
        phys_type::set_kB(phys_type::kB() * (unit_type::J_to_cal / 1000.0) *
                          unit_type::avogadro_constant);

        // eps0 [F/m] == [C^2/J/m] -> [C^2/(kcal/mol)/m]
        phys_type::set_eps0(phys_type::eps0() * (1000.0 / unit_type::J_to_cal) /
                            unit_type::avogadro_constant);

        // set name of energy unit
        phys_type::set_energy_unit(energy);
    }
    else if(energy == "kJ/mol")
    {
        // kB [J/K] -> [kJ/mol/K]
        phys_type::set_kB(phys_type::kB() * 1e-3 * unit_type::avogadro_constant);
        // eps0 [F/m] == [C^2/J/m] -> [C^2/kJ/mol/m]
        phys_type::set_eps0(phys_type::eps0() * 1e+3 /
                            unit_type::avogadro_constant);

        // set name of energy unit
        phys_type::set_energy_unit(energy);
    }
    else
    {
        throw_exception<std::runtime_error>(toml::format_error("[error] "
            "mjolnir::read_units: unknown unit for energy: `",
            toml::find(units, "energy"), "here", {
            "expected value is one of the following.",
            "- \"kcal/mol\"",
            "- \"kJ/mol\""
            }));
    }

    // until here, SI `m` are used as length unit.

    // 1 [mol/m^3] = 1e-3  [mol/L] = 1e-27 [mol/nm^3] = 1e-30 [mol/A^3]
    //               1     [mol/L] = 1e-24 [mol/nm^3] = 1e-27 [mol/A^3]
    if(length == "angstrom" || length == u8"Å")
    {
        // eps0 [C^2/Energy/m] -> [C^2/Energy/Angstrom]
        phys_type::set_eps0(phys_type::eps0() / unit_type::m_to_angstrom);

        // 1 m = 10^9 nm, 1 nm = 10^-9 m
        phys_type::set_m_to_length(unit_type::m_to_angstrom);
        phys_type::set_length_to_m(unit_type::angstrom_to_m);

        // 1 [L] = 1e-3 [m^3] = 1e+24 [nm^3]; 1 [m^3] = 1e27 [nm^3]
        phys_type::set_L_to_volume(1e-3 * std::pow(unit_type::m_to_angstrom, 3));
        phys_type::set_volume_to_L(1e+3 * std::pow(unit_type::angstrom_to_m, 3));

        MJOLNIR_LOG_INFO("1 [m] = ", phys_type::m_to_length(), " [", length, "]");
        MJOLNIR_LOG_INFO("1 [", length, "] = ", phys_type::length_to_m(), " [m]");

        MJOLNIR_LOG_INFO("1 [L] = ", phys_type::L_to_volume(), " [", length, "^3]");
        MJOLNIR_LOG_INFO("1 [", length, "^3] = ", phys_type::volume_to_L(), " [L]");

        // set name of length unit
        phys_type::set_length_unit("angstrom");
    }
    else if(length == "nm")
    {
        // eps0 [C^2/Energy/m] -> [C^2/Energy/nm]
        phys_type::set_eps0(phys_type::eps0() / unit_type::m_to_nm);

        // 1 m = 10^9 nm, 1 nm = 10^-9 m
        phys_type::set_m_to_length(unit_type::m_to_nm);
        phys_type::set_length_to_m(unit_type::nm_to_m);

        // 1 [L] = 1e-3 [m^3] = 1e+24 [nm^3]; 1 [m^3] = 1e27 [nm^3]
        phys_type::set_L_to_volume(1e-3 * std::pow(unit_type::m_to_nm, 3));
        phys_type::set_volume_to_L(1e+3 * std::pow(unit_type::nm_to_m, 3));

        MJOLNIR_LOG_INFO("1 [m] = ", phys_type::m_to_length(), " [", length, "]");
        MJOLNIR_LOG_INFO("1 [", length, "] = ", phys_type::length_to_m(), " [m]");

        MJOLNIR_LOG_INFO("1 [L] = ", phys_type::L_to_volume(), " [", length, "^3]");
        MJOLNIR_LOG_INFO("1 [", length, "^3] = ", phys_type::volume_to_L(), " [L]");

        // set name of length unit
        phys_type::set_length_unit("nm");
    }
    else
    {
        throw_exception<std::runtime_error>(toml::format_error("[error] "
            "mjolnir::read_units: unknown unit for length: `",
            toml::find(units, "length"), "here", {
            "expected value is one of the following.",
            "- \"nm\"",
            "- \"angstrom\""
            }));
    }

    MJOLNIR_LOG_INFO(u8"phys::kB = ", phys_type::kB(), " [", energy, "]");
    MJOLNIR_LOG_INFO(u8"phys::NA = ", phys_type::NA(), " [1/mol]");
    MJOLNIR_LOG_INFO(u8"phys::ε0 = ", phys_type::eps0(),
                     " [e^2 / (", energy, '*', length, ")]");

    return read_simulator<traitsT>(data);
}

#ifdef MJOLNIR_SEPARATE_BUILD
extern template std::unique_ptr<SimulatorBase> read_units<SimulatorTraits<double, UnlimitedBoundary>>(const toml::table& data);
extern template std::unique_ptr<SimulatorBase> read_units<SimulatorTraits<float,  UnlimitedBoundary>>(const toml::table& data);
extern template std::unique_ptr<SimulatorBase> read_units<SimulatorTraits<double, CuboidalPeriodicBoundary>>(const toml::table& data);
extern template std::unique_ptr<SimulatorBase> read_units<SimulatorTraits<float,  CuboidalPeriodicBoundary>>(const toml::table& data);
#endif

} // mjolnir
#endif// MJOLNIR_READ_UNIT_SYSTEM_HPP
<|endoftext|>


<commit_before>/*
 * Joey Button
 *
 *
 */

#include <stdio.h>
#include <opencv2/video/background_segm.hpp>
#include "opencv2/opencv.hpp"

// #include <iostream>
// #include <sstream>

using namespace cv;
using namespace std;
#define RADIUS 32

Mat fgMaskMOG; //fg mask generated by MOG method

BackgroundSubtractorMOG2 MOG;

const char *win = "video";

void drawCircle(Mat img, Point center)
{
    int thickness = -1;
    int lineType = 8;

    circle( img,
            center,
            RADIUS,
            Scalar( 255, 255, 255 ),
            thickness,
            lineType);
}

void calcDir(Point *momentum, Point *pt, int height, int width){
      pt->x += momentum->x;
      pt->y += momentum->y;

      if (pt->y < height) {
           // Accelerate due to Gravity
          momentum->y += 1;
      } else {
          momentum->x = momentum->x *0.9;
          momentum->y = -(momentum->y * .5);   // bounce back up and halt it
          pt->y = height;
      }

      //off the top
      if (pt->y < RADIUS) {
            pt->y=RADIUS;
            momentum->y += 1;
            momentum->y = -(momentum->y * .5);
            momentum->x = momentum->x *0.9;
      }

      if (momentum->y * momentum->y <= 49 && pt->y > height){
          momentum->y = 0;
      }

}

int main()
{
    int cam = 0; // default camera
    VideoCapture cap(cam);
    if (!cap.isOpened()) {
        fprintf(stderr, "cannot open camera %d\n", cam);
        exit(1);
    }

    // namedWindow(win);
    namedWindow(win, 1);
    Mat inputFrame, outFrame;
    Point pt;
    pt.x = 500;
    pt.y = 0;

    Point momentum;
    momentum.x = 0;
    momentum.y = 150;

    double count = 0;

    cap >> inputFrame;
    cvtColor(inputFrame, outFrame, CV_LOAD_IMAGE_COLOR);

    int height = inputFrame.rows-2*RADIUS;
    int width = inputFrame.cols-2*RADIUS;

    while (++count) {
        cap >> inputFrame;

        calcDir(&momentum, &pt, height, width);

        MOG(inputFrame, fgMaskMOG);

        //EVERYTHING ABOVE THIS SHOULD BE CALCULATING WHERE TO DRAW

        //EVERYTHING BELOW THIS LINE SHOULD BE DRAWING THE outFrame
        outFrame.setTo(Scalar(0,0,0)); //set all of outFrame to be black

        drawCircle(fgMaskMOG,pt);//for testing
        imshow(win, fgMaskMOG);//for testing

        // drawCircle(outFrame,pt);//The real one
        // imshow(win, outFrame);//The real one

        if (waitKey(1) >= 0) // wait up to 30 msec
	        break;
    }

    return 0;
}

/*
    Mat BGRChannels[3];
    split(outFrame,BGRChannels); // split the BGR channesl
    BGRChannels[1]=Mat::zeros(outFrame.rows,outFrame.cols,CV_8UC1);// removing Green channel
    merge(BGRChannels,3,outFrame); // pack the image

    waitKey(0);
*/
<commit_msg>Added thresholding to outFrame. Less noise now.<commit_after>/*
 * Joey Button
 *
 *
 */

#include <stdio.h>
#include <opencv2/video/background_segm.hpp>
#include "opencv2/opencv.hpp"

// #include <iostream>
// #include <sstream>

using namespace cv;
using namespace std;
#define RADIUS 32
#define THRESH 240.0f

Mat fgMaskMOG; //fg mask generated by MOG method

BackgroundSubtractorMOG2 MOG;

const char *win = "video";

void drawCircle(Mat img, Point center)
{
    int thickness = -1;
    int lineType = 8;

    circle( img,
            center,
            RADIUS,
            Scalar( 255, 255, 255 ),
            thickness,
            lineType);
}

void calcDir(Point *momentum, Point *pt, int height){
      pt->x += momentum->x;
      pt->y += momentum->y;

      if (pt->y < height) {
           // Accelerate due to Gravity
          momentum->y += 1;
      } else {
          momentum->x = momentum->x * 0.9;
          momentum->y = -(momentum->y * .5);   // bounce back up and halt it
          pt->y = height;
      }

      //off the top
      if (pt->y < RADIUS) {
            pt->y=RADIUS;
            momentum->y += 1;
            momentum->y = -(momentum->y * .5);
            momentum->x = momentum->x *0.9;
      }

      if (momentum->y * momentum->y <= 49 && pt->y > height){
          momentum->y = 0;
      }

}

int main()
{
    int cam = 0; // default camera
    VideoCapture cap(cam);
    if (!cap.isOpened()) {
        fprintf(stderr, "cannot open camera %d\n", cam);
        exit(1);
    }

    // namedWindow(win);
    namedWindow(win, 1);
    Mat inputFrame, outFrame;
    Point pt;
    pt.x = 500;
    pt.y = 0;

    Point momentum;
    momentum.x = 0;
    momentum.y = 100;

    int count = 0;

    cap >> inputFrame;
    cvtColor(inputFrame, outFrame, CV_LOAD_IMAGE_COLOR);

    int height = inputFrame.rows - 2 * RADIUS;
    // int width = inputFrame.cols - 2 * RADIUS;

    Mat mask;

    while (++count) {
        cap >> inputFrame;

        calcDir(&momentum, &pt, height);

        MOG(inputFrame, fgMaskMOG);

        // EVERYTHING ABOVE THIS SHOULD BE CALCULATING WHERE TO DRAW

        // EVERYTHING BELOW THIS LINE SHOULD BE DRAWING THE outFrame
        outFrame.setTo(Scalar(0,0,0));      // set all of outFrame to be black
        mask = fgMaskMOG > THRESH;            // have to put here otherwise floating point exception
        outFrame.setTo(Scalar(255, 255, 255), mask);

        drawCircle(outFrame, pt);           // The real one
        imshow(win, outFrame);              // The real one

        if (waitKey(1) >= 0) // wait up to 30 msec
	        break;
    }

    return 0;
}

/*
    Mat BGRChannels[3];
    split(outFrame,BGRChannels); // split the BGR channesl
    BGRChannels[1]=Mat::zeros(outFrame.rows,outFrame.cols,CV_8UC1);// removing Green channel
    merge(BGRChannels,3,outFrame); // pack the image

    waitKey(0);
*/
<|endoftext|>


<commit_before>#include "master.hpp"

namespace factor {

bool factor_vm::fatal_erroring_p;

static inline void fa_diddly_atal_error() {
  printf("fatal_error in fatal_error!\n");
  breakpoint();
  ::_exit(86);
}

void fatal_error(const char* msg, cell tagged) {
  if (factor_vm::fatal_erroring_p)
    fa_diddly_atal_error();

  factor_vm::fatal_erroring_p = true;

  std::cout << "fatal_error: " << msg;
  std::cout << ": " << (void*)tagged;
  std::cout << std::endl;
  abort();
}

void critical_error(const char* msg, cell tagged) {
  std::cout << "You have triggered a bug in Factor. Please report.\n";
  std::cout << "critical_error: " << msg;
  std::cout << ": " << std::hex << tagged << std::dec;
  std::cout << std::endl;
  current_vm()->factorbug();
}

void out_of_memory() {
  std::cout << "Out of memory\n\n";
  current_vm()->dump_generations();
  abort();
}

/* Allocates memory */
void factor_vm::general_error(vm_error_type error, cell arg1_, cell arg2_) {

  /* If we got here from memory_protection_error(), then the stack
     pointer has been fiddled with and the elements of these vectors,
     which address stack-allocated objects, are bogus and needs to be
     resetted. */
  data_roots.clear();
  bignum_roots.clear();
  code_roots.clear();

  data_root<object> arg1(arg1_, this);
  data_root<object> arg2(arg2_, this);

  faulting_p = true;

  /* If we had an underflow or overflow, data or retain stack
     pointers might be out of bounds, so fix them before allocating
     anything */
  ctx->fix_stacks();

  /* If error was thrown during heap scan, we re-enable the GC */
  gc_off = false;

  /* If the error handler is set, we rewind any C stack frames and
     pass the error to user-space. */
  if (!current_gc && to_boolean(special_objects[ERROR_HANDLER_QUOT])) {
#ifdef FACTOR_DEBUG
    /* Doing a GC here triggers all kinds of funny errors */
    primitive_compact_gc();
#endif

    /* Now its safe to allocate and GC */
    cell error_object =
        allot_array_4(special_objects[OBJ_ERROR], tag_fixnum(error),
                      arg1.value(), arg2.value());

    ctx->push(error_object);

    /* The unwind-native-frames subprimitive will clear faulting_p
       if it was successfully reached. */
    unwind_native_frames(special_objects[ERROR_HANDLER_QUOT],
                         ctx->callstack_top);
  } /* Error was thrown in early startup before error handler is set, so just
       crash. */
  else {
    std::cout << "You have triggered a bug in Factor. Please report.\n";
    std::cout << "error: " << error << std::endl;
    std::cout << "arg 1: ";
    print_obj(arg1.value());
    std::cout << std::endl;
    std::cout << "arg 2: ";
    print_obj(arg2.value());
    std::cout << std::endl;
    factorbug();
    abort();
  }
}

void factor_vm::type_error(cell type, cell tagged) {
  general_error(ERROR_TYPE, tag_fixnum(type), tagged);
}

void factor_vm::not_implemented_error() {
  general_error(ERROR_NOT_IMPLEMENTED, false_object, false_object);
}

void factor_vm::verify_memory_protection_error(cell addr) {
  /* Called from the OS-specific top halves of the signal handlers to
     make sure it's safe to dispatch to memory_protection_error */
  if (fatal_erroring_p)
    fa_diddly_atal_error();
  if (faulting_p && !code->safepoint_p(addr))
    fatal_error("Double fault", addr);
  else if (fep_p)
    fatal_error("Memory protection fault during low-level debugger", addr);
  else if (atomic::load(&current_gc_p))
    fatal_error("Memory protection fault during gc", addr);
}

/* Allocates memory */
void factor_vm::memory_protection_error(cell pc, cell addr) {
  if (code->safepoint_p(addr))
    safepoint.handle_safepoint(this, pc);
  else if (ctx->datastack_seg->underflow_p(addr))
    general_error(ERROR_DATASTACK_UNDERFLOW, false_object, false_object);
  else if (ctx->datastack_seg->overflow_p(addr))
    general_error(ERROR_DATASTACK_OVERFLOW, false_object, false_object);
  else if (ctx->retainstack_seg->underflow_p(addr))
    general_error(ERROR_RETAINSTACK_UNDERFLOW, false_object, false_object);
  else if (ctx->retainstack_seg->overflow_p(addr))
    general_error(ERROR_RETAINSTACK_OVERFLOW, false_object, false_object);
  else if (ctx->callstack_seg->underflow_p(addr))
    general_error(ERROR_CALLSTACK_OVERFLOW, false_object, false_object);
  else if (ctx->callstack_seg->overflow_p(addr))
    general_error(ERROR_CALLSTACK_UNDERFLOW, false_object, false_object);
  else
    general_error(ERROR_MEMORY, from_unsigned_cell(addr), false_object);
}

/* Allocates memory */
void factor_vm::signal_error(cell signal) {
  general_error(ERROR_SIGNAL, from_unsigned_cell(signal), false_object);
}

void factor_vm::divide_by_zero_error() {
  general_error(ERROR_DIVIDE_BY_ZERO, false_object, false_object);
}

void factor_vm::fp_trap_error(unsigned int fpu_status) {
  general_error(ERROR_FP_TRAP, tag_fixnum(fpu_status), false_object);
}

/* For testing purposes */
void factor_vm::primitive_unimplemented() { not_implemented_error(); }

void factor_vm::memory_signal_handler_impl() {
  memory_protection_error(signal_fault_pc, signal_fault_addr);
  if (!signal_resumable) {
    /* In theory we should only get here if the callstack overflowed during a
       safepoint */
    general_error(ERROR_CALLSTACK_OVERFLOW, false_object, false_object);
  }
}

void memory_signal_handler_impl() {
  current_vm()->memory_signal_handler_impl();
}

void factor_vm::synchronous_signal_handler_impl() {
  signal_error(signal_number);
}

void synchronous_signal_handler_impl() {
  current_vm()->synchronous_signal_handler_impl();
}

void factor_vm::fp_signal_handler_impl() {
  /* Clear pending exceptions to avoid getting stuck in a loop */
  set_fpu_state(get_fpu_state());

  fp_trap_error(signal_fpu_status);
}

void fp_signal_handler_impl() { current_vm()->fp_signal_handler_impl(); }
}
<commit_msg>VM: data_roots must be empty before unwind_native_frames is called because it doesn't return<commit_after>#include "master.hpp"

namespace factor {

bool factor_vm::fatal_erroring_p;

static inline void fa_diddly_atal_error() {
  printf("fatal_error in fatal_error!\n");
  breakpoint();
  ::_exit(86);
}

void fatal_error(const char* msg, cell tagged) {
  if (factor_vm::fatal_erroring_p)
    fa_diddly_atal_error();

  factor_vm::fatal_erroring_p = true;

  std::cout << "fatal_error: " << msg;
  std::cout << ": " << (void*)tagged;
  std::cout << std::endl;
  abort();
}

void critical_error(const char* msg, cell tagged) {
  std::cout << "You have triggered a bug in Factor. Please report.\n";
  std::cout << "critical_error: " << msg;
  std::cout << ": " << std::hex << tagged << std::dec;
  std::cout << std::endl;
  current_vm()->factorbug();
}

void out_of_memory() {
  std::cout << "Out of memory\n\n";
  current_vm()->dump_generations();
  abort();
}

/* Allocates memory */
void factor_vm::general_error(vm_error_type error, cell arg1_, cell arg2_) {

  /* If we got here from memory_protection_error(), then the stack
     pointer has been fiddled with and the elements of these vectors,
     which address stack-allocated objects, are bogus and needs to be
     resetted. */
  data_roots.clear();
  bignum_roots.clear();
  code_roots.clear();

  data_root<object> arg1(arg1_, this);
  data_root<object> arg2(arg2_, this);

  faulting_p = true;

  /* If we had an underflow or overflow, data or retain stack
     pointers might be out of bounds, so fix them before allocating
     anything */
  ctx->fix_stacks();

  /* If error was thrown during heap scan, we re-enable the GC */
  gc_off = false;

  /* If the error handler is set, we rewind any C stack frames and
     pass the error to user-space. */
  if (!current_gc && to_boolean(special_objects[ERROR_HANDLER_QUOT])) {
#ifdef FACTOR_DEBUG
    /* Doing a GC here triggers all kinds of funny errors */
    primitive_compact_gc();
#endif

    /* Now its safe to allocate and GC */
    cell error_object =
        allot_array_4(special_objects[OBJ_ERROR], tag_fixnum(error),
                      arg1.value(), arg2.value());
    ctx->push(error_object);

    /* Clear the data roots again since arg1 and arg2's destructors
       won't be called. */
    data_roots.clear();

    /* The unwind-native-frames subprimitive will clear faulting_p
       if it was successfully reached. */
    unwind_native_frames(special_objects[ERROR_HANDLER_QUOT],
                         ctx->callstack_top);
  } /* Error was thrown in early startup before error handler is set, so just
       crash. */
  else {
    std::cout << "You have triggered a bug in Factor. Please report.\n";
    std::cout << "error: " << error << std::endl;
    std::cout << "arg 1: ";
    print_obj(arg1.value());
    std::cout << std::endl;
    std::cout << "arg 2: ";
    print_obj(arg2.value());
    std::cout << std::endl;
    factorbug();
    abort();
  }
}

void factor_vm::type_error(cell type, cell tagged) {
  general_error(ERROR_TYPE, tag_fixnum(type), tagged);
}

void factor_vm::not_implemented_error() {
  general_error(ERROR_NOT_IMPLEMENTED, false_object, false_object);
}

void factor_vm::verify_memory_protection_error(cell addr) {
  /* Called from the OS-specific top halves of the signal handlers to
     make sure it's safe to dispatch to memory_protection_error */
  if (fatal_erroring_p)
    fa_diddly_atal_error();
  if (faulting_p && !code->safepoint_p(addr))
    fatal_error("Double fault", addr);
  else if (fep_p)
    fatal_error("Memory protection fault during low-level debugger", addr);
  else if (atomic::load(&current_gc_p))
    fatal_error("Memory protection fault during gc", addr);
}

/* Allocates memory */
void factor_vm::memory_protection_error(cell pc, cell addr) {
  if (code->safepoint_p(addr))
    safepoint.handle_safepoint(this, pc);
  else if (ctx->datastack_seg->underflow_p(addr))
    general_error(ERROR_DATASTACK_UNDERFLOW, false_object, false_object);
  else if (ctx->datastack_seg->overflow_p(addr))
    general_error(ERROR_DATASTACK_OVERFLOW, false_object, false_object);
  else if (ctx->retainstack_seg->underflow_p(addr))
    general_error(ERROR_RETAINSTACK_UNDERFLOW, false_object, false_object);
  else if (ctx->retainstack_seg->overflow_p(addr))
    general_error(ERROR_RETAINSTACK_OVERFLOW, false_object, false_object);
  else if (ctx->callstack_seg->underflow_p(addr))
    general_error(ERROR_CALLSTACK_OVERFLOW, false_object, false_object);
  else if (ctx->callstack_seg->overflow_p(addr))
    general_error(ERROR_CALLSTACK_UNDERFLOW, false_object, false_object);
  else
    general_error(ERROR_MEMORY, from_unsigned_cell(addr), false_object);
}

/* Allocates memory */
void factor_vm::signal_error(cell signal) {
  general_error(ERROR_SIGNAL, from_unsigned_cell(signal), false_object);
}

void factor_vm::divide_by_zero_error() {
  general_error(ERROR_DIVIDE_BY_ZERO, false_object, false_object);
}

void factor_vm::fp_trap_error(unsigned int fpu_status) {
  general_error(ERROR_FP_TRAP, tag_fixnum(fpu_status), false_object);
}

/* For testing purposes */
void factor_vm::primitive_unimplemented() { not_implemented_error(); }

void factor_vm::memory_signal_handler_impl() {
  memory_protection_error(signal_fault_pc, signal_fault_addr);
  if (!signal_resumable) {
    /* In theory we should only get here if the callstack overflowed during a
       safepoint */
    general_error(ERROR_CALLSTACK_OVERFLOW, false_object, false_object);
  }
}

void memory_signal_handler_impl() {
  current_vm()->memory_signal_handler_impl();
}

void factor_vm::synchronous_signal_handler_impl() {
  signal_error(signal_number);
}

void synchronous_signal_handler_impl() {
  current_vm()->synchronous_signal_handler_impl();
}

void factor_vm::fp_signal_handler_impl() {
  /* Clear pending exceptions to avoid getting stuck in a loop */
  set_fpu_state(get_fpu_state());

  fp_trap_error(signal_fpu_status);
}

void fp_signal_handler_impl() { current_vm()->fp_signal_handler_impl(); }
}
<|endoftext|>


<commit_before>/*  This file is part of the Vc library.

    Copyright (C) 2010 Matthias Kretz <kretz@kde.org>

    Vc is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as
    published by the Free Software Foundation, either version 3 of
    the License, or (at your option) any later version.

    Vc is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "support.h"
#include "../cpuid.h"

namespace Vc
{

bool isImplementationSupported(Implementation impl)
{
    // for AVX we need to check for OSXSAVE and AVX

    switch (impl) {
    case ScalarImpl:
        return true;
    case SSE2Impl:
        return CpuId::hasSse2();
    case SSE3Impl:
        return CpuId::hasSse3();
    case SSSE3Impl:
        return CpuId::hasSsse3();
    case SSE41Impl:
        return CpuId::hasSse41();
    case SSE42Impl:
        return CpuId::hasSse42();
    case SSE4aImpl:
        return CpuId::hasSse4a();
    case AVXImpl:
        if (CpuId::hasOsxsave() && CpuId::hasAvx()) {
            unsigned int eax;
#ifdef _MSC_VER
			// MSVC does not support inline assembly on 64 bit! :( And searching the help for xgetbv doesn't turn up anything. So just fall back to not supporting AVX on Windows :(
			return false;
#else
            asm("xgetbv" : "=a"(eax) :: "edx");
            return (eax & 0x06) == 0x06;
#endif
        }
        return false;
    case LRBniImpl:
        // TODO
        return false;
    case LRBniPrototypeImpl:
        return true;
    }
    return false;
}

} // namespace Vc

// vim: sw=4 sts=4 et tw=100
<commit_msg>variable eax is only used in the real code<commit_after>/*  This file is part of the Vc library.

    Copyright (C) 2010 Matthias Kretz <kretz@kde.org>

    Vc is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as
    published by the Free Software Foundation, either version 3 of
    the License, or (at your option) any later version.

    Vc is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "support.h"
#include "../cpuid.h"

namespace Vc
{

bool isImplementationSupported(Implementation impl)
{
    // for AVX we need to check for OSXSAVE and AVX

    switch (impl) {
    case ScalarImpl:
        return true;
    case SSE2Impl:
        return CpuId::hasSse2();
    case SSE3Impl:
        return CpuId::hasSse3();
    case SSSE3Impl:
        return CpuId::hasSsse3();
    case SSE41Impl:
        return CpuId::hasSse41();
    case SSE42Impl:
        return CpuId::hasSse42();
    case SSE4aImpl:
        return CpuId::hasSse4a();
    case AVXImpl:
        if (CpuId::hasOsxsave() && CpuId::hasAvx()) {
#ifdef _MSC_VER
			// MSVC does not support inline assembly on 64 bit! :( And searching the help for xgetbv doesn't turn up anything. So just fall back to not supporting AVX on Windows :(
			return false;
#else
            unsigned int eax;
            asm("xgetbv" : "=a"(eax) :: "edx");
            return (eax & 0x06) == 0x06;
#endif
        }
        return false;
    case LRBniImpl:
        // TODO
        return false;
    case LRBniPrototypeImpl:
        return true;
    }
    return false;
}

} // namespace Vc

// vim: sw=4 sts=4 et tw=100
<|endoftext|>


<commit_before>/* The following applies to this software package and all subparts therein
 *
 * Cognosco Copyright (C) 2015 Philip J. Uren
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or (at
 * your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

// stl includes
#include <string>
#include <vector>

// local includes
#include "Dataset.hpp"
#include "KMedoids.hpp"
#include "KMedoidsClassifier.hpp"
#include "DistanceMatrix.hpp"

// bring these names into the local namespace
using std::string;
using std::vector;
using std::set;

/*****************************************************************************
 *                              UI DEFINITION                                *
 *****************************************************************************/

static CommandlineInterface
get_cli() {
  const size_t MIN_ARGS = 0;
  const size_t MAX_ARGS = 0;
  const string about = "about kmeds classifier...";

  CommandlineInterface cli ("KMedoidsClassifier", about, MIN_ARGS, MAX_ARGS);
  cli.add_boolean_option("verbose", 'v', "output additional status messages "
                         "during run to stderr", false);
  cli.add_string_option("name-attribute", 'n', "the attribute which provides "
                        "the name of the instances");
  cli.add_size_option("k", 'k', "number of clusters to use", 2);
  return cli;
}

/*****************************************************************************
 *                         STATIC HELPER FUNCTIONS                           *
 *****************************************************************************/

/**
 * convert a dataset that gives the distance
 * Instances in the intial dataset have  N + 2 attributes, where N of these
 * are distances to the other N instances in the dataset and the extra two are
 * the name of the instance and the class. The names must match the attributes.
 * A new dataset is constructed where each instance is described only by the
 * attributes named in medoids.
 */
static void
build_new_dataset(const Dataset &exist_ds, Dataset &new_ds,
                  const set<string> &medoids,
                  const set<size_t> &ignore_inst_ids,
                  const string &inst_name_att_name) {
  new_ds = Dataset(exist_ds, ignore_inst_ids);

  vector<string> att_names;
  for (auto it = new_ds.begin_attributes(); it != new_ds.end_attributes(); ++it) {
    Attribute* att_ptr = (*it);
    att_names.push_back(att_ptr->get_name());
  }

  for (auto name : att_names) {
    if (std::find(medoids.begin(), medoids.end(), name) == medoids.end())
      new_ds.delete_attribute(name);
  }
}

/*****************************************************************************
 *                       Classifiers::KMedoids CLASS                         *
 *****************************************************************************/

string
Classifiers::KMedoids::to_string() const {
  std::stringstream ss;
  ss << "KMedoids classifier constructed using " << this->name_att
     << " as names; learned medoids as " << join(this->medoid_names, ", ")
     << "and nb classifier as " << this->nb_classifier.to_string();
  return ss.str();
}

void
Classifiers::KMedoids::learn(const Dataset &train_instances,
                             const string &class_label,
                             const std::set<size_t> &ignore_inst_ids) {
  // convert the dataset into a distance matrix
  std::cerr << "building distance matrix " << std::endl;
  DistanceMatrix m;
  size_t skipped = 0;
  std::set<string> inst_ids_set;
  for (auto it = train_instances.begin(); it != train_instances.end(); ++it) {
    if (ignore_inst_ids.find(it->get_instance_id()) != ignore_inst_ids.end()) {
      skipped += 1;
      continue;
    }
    string name_att_val = it->get_att_occurrence(this->name_att)->get_attribute_name();
    for (auto ait = it->begin(); ait != it->end(); ++ait) {
      AttributeOccurrence* aoc_ptr = (*ait);
      m[std::make_pair(aoc_ptr->get_attribute_name(), name_att_val)] =\
        ((*aoc_ptr) * 1.0);
      inst_ids_set.insert(aoc_ptr->get_attribute_name());
    }
  }

  // perform k-medoids clustering on the distance matrix
  std::cerr << "perform clustering " << std::endl;
  vector<string> inst_ids;
  std::copy(inst_ids_set.begin(), inst_ids_set.end(), std::back_inserter(inst_ids));
  KMedoidsClusterer clstr(2, m, inst_ids);
  clstr.train();
  this->medoid_names = clstr.get_medoids();

  // build new dataset characterized by distance to the medoids from
  // the clustering
  std::cerr << "transofrm dataset " << std::endl;
  Dataset nds;
  build_new_dataset(train_instances, nds, this->medoid_names,
                    ignore_inst_ids, this->name_att);

  // build a NB classifier from the new instances
  std::cerr << "build nb classifier " << std::endl;
  this->nb_classifier.learn(nds, class_label);
}

/**
 * \brief compute the probability that a given Instance belongs to a given
 *        class using this classifier.
 */
double
Classifiers::KMedoids::class_probability(const Instance &test_instance,
                                         const string &class_label) const {
  Instance t_cp(test_instance); // !!!!!!!!!! make sure copy constructor is set up for instance!!!
  vector<string> att_names;
  for (auto it = t_cp.begin(); it != t_cp.end(); ++it) {
    AttributeOccurrence *att_oc_ptr = (*it);
    att_names.push_back(att_oc_ptr->get_attribute_name());
  }
  for (auto it = att_names.begin(); it != att_names.end(); ++it) {
    if (this->medoid_names.find(*it) == this->medoid_names.end())
      t_cp.delete_attribute_occurrence(*it);
  }

  return this->nb_classifier.class_probability(t_cp, class_label);
}

std::string
Classifiers::KMedoids::usage() const {
  std::stringstream ss;
  ss << "KMedoidsClassifier specific options" << std::endl;
  ss << get_cli().usage() << std::endl;
  return ss.str();
}

void
Classifiers::KMedoids::set_classifier_specific_options(Commandline &cmdline) {
  CommandlineInterface cli (get_cli());
  cli.consume('n', cmdline, this->name_att);
  cli.consume('k', cmdline, this->k);
}

void
Classifiers::KMedoids::clear() {
  this->nb_classifier.clear();
  this->medoid_names.clear();
}
<commit_msg>fix bug when building distance matrix for kmedoids classifier where class and isntance name attribtues where not skipped in distance claculation<commit_after>/* The following applies to this software package and all subparts therein
 *
 * Cognosco Copyright (C) 2015 Philip J. Uren
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or (at
 * your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

// stl includes
#include <string>
#include <vector>

// local includes
#include "Dataset.hpp"
#include "KMedoids.hpp"
#include "KMedoidsClassifier.hpp"
#include "DistanceMatrix.hpp"

// bring these names into the local namespace
using std::string;
using std::vector;
using std::set;

/*****************************************************************************
 *                              UI DEFINITION                                *
 *****************************************************************************/

static CommandlineInterface
get_cli() {
  const size_t MIN_ARGS = 0;
  const size_t MAX_ARGS = 0;
  const string about = "about kmeds classifier...";

  CommandlineInterface cli ("KMedoidsClassifier", about, MIN_ARGS, MAX_ARGS);
  cli.add_boolean_option("verbose", 'v', "output additional status messages "
                         "during run to stderr", false);
  cli.add_string_option("name-attribute", 'n', "the attribute which provides "
                        "the name of the instances");
  cli.add_size_option("k", 'k', "number of clusters to use", 2);
  return cli;
}

/*****************************************************************************
 *                         STATIC HELPER FUNCTIONS                           *
 *****************************************************************************/

/**
 * convert a dataset that gives the distance
 * Instances in the intial dataset have  N + 2 attributes, where N of these
 * are distances to the other N instances in the dataset and the extra two are
 * the name of the instance and the class. The names must match the attributes.
 * A new dataset is constructed where each instance is described only by the
 * attributes named in medoids.
 */
static void
build_new_dataset(const Dataset &exist_ds, Dataset &new_ds,
                  const set<string> &medoids,
                  const set<size_t> &ignore_inst_ids,
                  const string &inst_name_att_name) {
  new_ds = Dataset(exist_ds, ignore_inst_ids);

  vector<string> att_names;
  for (auto it = new_ds.begin_attributes(); it != new_ds.end_attributes(); ++it) {
    Attribute* att_ptr = (*it);
    att_names.push_back(att_ptr->get_name());
  }

  for (auto name : att_names) {
    if (std::find(medoids.begin(), medoids.end(), name) == medoids.end())
      new_ds.delete_attribute(name);
  }
}

/*****************************************************************************
 *                       Classifiers::KMedoids CLASS                         *
 *****************************************************************************/

string
Classifiers::KMedoids::to_string() const {
  std::stringstream ss;
  ss << "KMedoids classifier constructed using " << this->name_att
     << " as names; learned medoids as " << join(this->medoid_names, ", ")
     << "and nb classifier as " << this->nb_classifier.to_string();
  return ss.str();
}

void
Classifiers::KMedoids::learn(const Dataset &train_instances,
                             const string &class_label,
                             const std::set<size_t> &ignore_inst_ids) {
  // convert the dataset into a distance matrix
  std::cerr << "building distance matrix " << std::endl;
  DistanceMatrix m;
  size_t skipped = 0;
  std::set<string> inst_ids_set;
  for (auto it = train_instances.begin(); it != train_instances.end(); ++it) {
    if (ignore_inst_ids.find(it->get_instance_id()) != ignore_inst_ids.end()) {
      skipped += 1;
      continue;
    }
    std::cerr << "looking for " << this->name_att << std::endl;
    for (auto xx = it->begin(); xx != it->end(); ++xx) {
      std::cerr << (*xx)->get_attribute_name() << std::endl;
    }
    string name_att_val = it->get_att_occurrence(this->name_att)->get_attribute_name();
    for (auto ait = it->begin(); ait != it->end(); ++ait) {
      AttributeOccurrence* aoc_ptr = (*ait);
      const string this_att_name(aoc_ptr->get_attribute_name());

      // skip class and name attributes
      if ((this_att_name == class_label) || (this_att_name == this->name_att))
        continue;

      std::cerr << "doing '" << this_att_name << "'" << std::endl;
      m[std::make_pair(aoc_ptr->get_attribute_name(), name_att_val)] =\
        ((*aoc_ptr) * 1.0);
      inst_ids_set.insert(aoc_ptr->get_attribute_name());
    }
  }

  // perform k-medoids clustering on the distance matrix
  std::cerr << "perform clustering " << std::endl;
  vector<string> inst_ids;
  std::copy(inst_ids_set.begin(), inst_ids_set.end(), std::back_inserter(inst_ids));
  KMedoidsClusterer clstr(2, m, inst_ids);
  clstr.train();
  this->medoid_names = clstr.get_medoids();

  // build new dataset characterized by distance to the medoids from
  // the clustering
  std::cerr << "transofrm dataset " << std::endl;
  Dataset nds;
  build_new_dataset(train_instances, nds, this->medoid_names,
                    ignore_inst_ids, this->name_att);

  // build a NB classifier from the new instances
  std::cerr << "build nb classifier " << std::endl;
  this->nb_classifier.learn(nds, class_label);
}

/**
 * \brief compute the probability that a given Instance belongs to a given
 *        class using this classifier.
 */
double
Classifiers::KMedoids::class_probability(const Instance &test_instance,
                                         const string &class_label) const {
  Instance t_cp(test_instance); // !!!!!!!!!! make sure copy constructor is set up for instance!!!
  vector<string> att_names;
  for (auto it = t_cp.begin(); it != t_cp.end(); ++it) {
    AttributeOccurrence *att_oc_ptr = (*it);
    att_names.push_back(att_oc_ptr->get_attribute_name());
  }
  for (auto it = att_names.begin(); it != att_names.end(); ++it) {
    if (this->medoid_names.find(*it) == this->medoid_names.end())
      t_cp.delete_attribute_occurrence(*it);
  }

  return this->nb_classifier.class_probability(t_cp, class_label);
}

std::string
Classifiers::KMedoids::usage() const {
  std::stringstream ss;
  ss << "KMedoidsClassifier specific options" << std::endl;
  ss << get_cli().usage() << std::endl;
  return ss.str();
}

void
Classifiers::KMedoids::set_classifier_specific_options(Commandline &cmdline) {
  CommandlineInterface cli (get_cli());
  cli.consume('n', cmdline, this->name_att);
  cli.consume('k', cmdline, this->k);
}

void
Classifiers::KMedoids::clear() {
  this->nb_classifier.clear();
  this->medoid_names.clear();
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 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 <string>

#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/test/test_server.h"

using std::wstring;

namespace {

const FilePath::CharType kDocRoot[] = FILE_PATH_LITERAL("chrome/test/data");

}  // namespace

class LoginPromptTest : public UITest {
 protected:
  LoginPromptTest()
      : username_basic_(L"basicuser"),
        username_digest_(L"digestuser"),
        password_(L"secret"),
        password_bad_(L"denyme"),
        test_server_(net::TestServer::TYPE_HTTP, FilePath(kDocRoot)) {
  }

  void AppendTab(const GURL& url) {
    scoped_refptr<BrowserProxy> window_proxy(automation()->GetBrowserWindow(0));
    ASSERT_TRUE(window_proxy.get());
    ASSERT_TRUE(window_proxy->AppendTab(url));
  }

 protected:
  wstring username_basic_;
  wstring username_digest_;
  wstring password_;
  wstring password_bad_;

  net::TestServer test_server_;
};

wstring ExpectedTitleFromAuth(const wstring& username,
                              const wstring& password) {
  // The TestServer sets the title to username/password on successful login.
  return username + L"/" + password;
}

// Test that "Basic" HTTP authentication works.
TEST_F(LoginPromptTest, TestBasicAuth) {
  ASSERT_TRUE(test_server_.Start());

  scoped_refptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab.get());
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            tab->NavigateToURL(test_server_.GetURL("auth-basic")));

  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_FALSE(tab->SetAuth(username_basic_, password_bad_));
  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_TRUE(tab->CancelAuth());
  EXPECT_EQ(L"Denied: wrong password", GetActiveTabTitle());

  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            tab->NavigateToURL(test_server_.GetURL("auth-basic")));

  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_TRUE(tab->SetAuth(username_basic_, password_));
  EXPECT_EQ(ExpectedTitleFromAuth(username_basic_, password_),
            GetActiveTabTitle());
}

// Test that "Digest" HTTP authentication works.
TEST_F(LoginPromptTest, TestDigestAuth) {
  ASSERT_TRUE(test_server_.Start());

  scoped_refptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab.get());
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            tab->NavigateToURL(test_server_.GetURL("auth-digest")));

  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_FALSE(tab->SetAuth(username_digest_, password_bad_));
  EXPECT_TRUE(tab->CancelAuth());
  EXPECT_EQ(L"Denied: wrong password", GetActiveTabTitle());

  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            tab->NavigateToURL(test_server_.GetURL("auth-digest")));

  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_TRUE(tab->SetAuth(username_digest_, password_));
  EXPECT_EQ(ExpectedTitleFromAuth(username_digest_, password_),
            GetActiveTabTitle());
}

// Test that logging in on 2 tabs at once works.
TEST_F(LoginPromptTest, TestTwoAuths) {
  ASSERT_TRUE(test_server_.Start());

  scoped_refptr<TabProxy> basic_tab(GetActiveTab());
  ASSERT_TRUE(basic_tab.get());
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            basic_tab->NavigateToURL(test_server_.GetURL("auth-basic")));

  AppendTab(GURL(chrome::kAboutBlankURL));
  scoped_refptr<TabProxy> digest_tab(GetActiveTab());
  ASSERT_TRUE(digest_tab.get());
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            digest_tab->NavigateToURL(test_server_.GetURL("auth-digest")));

  EXPECT_TRUE(basic_tab->NeedsAuth());
  EXPECT_TRUE(basic_tab->SetAuth(username_basic_, password_));
  EXPECT_TRUE(digest_tab->NeedsAuth());
  EXPECT_TRUE(digest_tab->SetAuth(username_digest_, password_));

  wstring title;
  EXPECT_TRUE(basic_tab->GetTabTitle(&title));
  EXPECT_EQ(ExpectedTitleFromAuth(username_basic_, password_), title);

  EXPECT_TRUE(digest_tab->GetTabTitle(&title));
  EXPECT_EQ(ExpectedTitleFromAuth(username_digest_, password_), title);
}

// Test that cancelling authentication works.
TEST_F(LoginPromptTest, TestCancelAuth) {
  ASSERT_TRUE(test_server_.Start());

  scoped_refptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab.get());

  // First navigate to a test server page so we have something to go back to.
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
            tab->NavigateToURL(test_server_.GetURL("a")));

  // Navigating while auth is requested is the same as cancelling.
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            tab->NavigateToURL(test_server_.GetURL("auth-basic")));
  EXPECT_TRUE(tab->NeedsAuth());
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
            tab->NavigateToURL(test_server_.GetURL("b")));
  EXPECT_FALSE(tab->NeedsAuth());

  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            tab->NavigateToURL(test_server_.GetURL("auth-basic")));
  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_TRUE(tab->GoBack());  // should bring us back to 'a'
  EXPECT_FALSE(tab->NeedsAuth());

  // Now add a page and go back, so we have something to go forward to.
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
            tab->NavigateToURL(test_server_.GetURL("c")));
  EXPECT_TRUE(tab->GoBack());  // should bring us back to 'a'

  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            tab->NavigateToURL(test_server_.GetURL("auth-basic")));
  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_TRUE(tab->GoForward());  // should bring us to 'c'
  EXPECT_FALSE(tab->NeedsAuth());

  // Now test that cancelling works as expected.
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            tab->NavigateToURL(test_server_.GetURL("auth-basic")));
  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_TRUE(tab->CancelAuth());
  EXPECT_FALSE(tab->NeedsAuth());
  EXPECT_EQ(L"Denied: no auth", GetActiveTabTitle());
}

// If multiple tabs are looking for the same auth, the user should only have to
// enter it once.
TEST_F(LoginPromptTest, SupplyRedundantAuths) {
  ASSERT_TRUE(test_server_.Start());

  scoped_refptr<TabProxy> basic_tab1(GetActiveTab());
  ASSERT_TRUE(basic_tab1.get());
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            basic_tab1->NavigateToURL(test_server_.GetURL("auth-basic/1")));
  EXPECT_TRUE(basic_tab1->NeedsAuth());

  AppendTab(GURL(chrome::kAboutBlankURL));
  scoped_refptr<TabProxy> basic_tab2(GetActiveTab());
  ASSERT_TRUE(basic_tab2.get());
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            basic_tab2->NavigateToURL(test_server_.GetURL("auth-basic/2")));
  EXPECT_TRUE(basic_tab2->NeedsAuth());

  // Set the auth in only one of the tabs (but wait for the other to load).
  int64 last_navigation_time;
  ASSERT_TRUE(basic_tab2->GetLastNavigationTime(&last_navigation_time));
  EXPECT_TRUE(basic_tab1->SetAuth(username_basic_, password_));
  EXPECT_TRUE(basic_tab2->WaitForNavigation(last_navigation_time));

  // Now both tabs have loaded.
  wstring title1;
  EXPECT_TRUE(basic_tab1->GetTabTitle(&title1));
  EXPECT_EQ(ExpectedTitleFromAuth(username_basic_, password_), title1);
  wstring title2;
  EXPECT_TRUE(basic_tab2->GetTabTitle(&title2));
  EXPECT_EQ(ExpectedTitleFromAuth(username_basic_, password_), title2);
}

// If multiple tabs are looking for the same auth, and one is cancelled, the
// other should be cancelled as well.
TEST_F(LoginPromptTest, CancelRedundantAuths) {
  ASSERT_TRUE(test_server_.Start());

  scoped_refptr<TabProxy> basic_tab1(GetActiveTab());
  ASSERT_TRUE(basic_tab1.get());
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            basic_tab1->NavigateToURL(test_server_.GetURL("auth-basic/1")));
  EXPECT_TRUE(basic_tab1->NeedsAuth());

  AppendTab(GURL(chrome::kAboutBlankURL));
  scoped_refptr<TabProxy> basic_tab2(GetActiveTab());
  ASSERT_TRUE(basic_tab2.get());
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            basic_tab2->NavigateToURL(test_server_.GetURL("auth-basic/2")));
  EXPECT_TRUE(basic_tab2->NeedsAuth());

  // Cancel the auth in only one of the tabs (but wait for the other to load).
  int64 last_navigation_time;
  ASSERT_TRUE(basic_tab2->GetLastNavigationTime(&last_navigation_time));
  EXPECT_TRUE(basic_tab1->CancelAuth());
  EXPECT_TRUE(basic_tab2->WaitForNavigation(last_navigation_time));

  // Now both tabs have been denied.
  wstring title1;
  EXPECT_TRUE(basic_tab1->GetTabTitle(&title1));
  EXPECT_EQ(L"Denied: no auth", title1);
  wstring title2;
  EXPECT_TRUE(basic_tab2->GetTabTitle(&title2));
  EXPECT_EQ(L"Denied: no auth", title2);
}
<commit_msg>Marking a bunch of login prompt tests as faily on windows due to them relying on a flaky test server:<commit_after>// Copyright (c) 2006-2008 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 <string>

#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/test/test_server.h"

using std::wstring;

namespace {

const FilePath::CharType kDocRoot[] = FILE_PATH_LITERAL("chrome/test/data");

}  // namespace

class LoginPromptTest : public UITest {
 protected:
  LoginPromptTest()
      : username_basic_(L"basicuser"),
        username_digest_(L"digestuser"),
        password_(L"secret"),
        password_bad_(L"denyme"),
        test_server_(net::TestServer::TYPE_HTTP, FilePath(kDocRoot)) {
  }

  void AppendTab(const GURL& url) {
    scoped_refptr<BrowserProxy> window_proxy(automation()->GetBrowserWindow(0));
    ASSERT_TRUE(window_proxy.get());
    ASSERT_TRUE(window_proxy->AppendTab(url));
  }

 protected:
  wstring username_basic_;
  wstring username_digest_;
  wstring password_;
  wstring password_bad_;

  net::TestServer test_server_;
};

wstring ExpectedTitleFromAuth(const wstring& username,
                              const wstring& password) {
  // The TestServer sets the title to username/password on successful login.
  return username + L"/" + password;
}

#if defined(OS_WIN)
// Probably related to test server flakiness in http://crbug.com/60937
#define MAYBE_TestBasicAuth FLAKY_TestBasicAuth
#else
#define MAYBE_TestBasicAuth TestBasicAuth
#endif

// Test that "Basic" HTTP authentication works.
TEST_F(LoginPromptTest, MAYBE_TestBasicAuth) {
  ASSERT_TRUE(test_server_.Start());

  scoped_refptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab.get());
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            tab->NavigateToURL(test_server_.GetURL("auth-basic")));

  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_FALSE(tab->SetAuth(username_basic_, password_bad_));
  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_TRUE(tab->CancelAuth());
  EXPECT_EQ(L"Denied: wrong password", GetActiveTabTitle());

  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            tab->NavigateToURL(test_server_.GetURL("auth-basic")));

  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_TRUE(tab->SetAuth(username_basic_, password_));
  EXPECT_EQ(ExpectedTitleFromAuth(username_basic_, password_),
            GetActiveTabTitle());
}

#if defined(OS_WIN)
// Probably related to test server flakiness in http://crbug.com/60937
#define MAYBE_TestDigestAuth FLAKY_TestDigestAuth
#else
#define MAYBE_TestDigestAuth TestDigestAuth
#endif

// Test that "Digest" HTTP authentication works.
TEST_F(LoginPromptTest, MAYBE_TestDigestAuth) {
  ASSERT_TRUE(test_server_.Start());

  scoped_refptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab.get());
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            tab->NavigateToURL(test_server_.GetURL("auth-digest")));

  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_FALSE(tab->SetAuth(username_digest_, password_bad_));
  EXPECT_TRUE(tab->CancelAuth());
  EXPECT_EQ(L"Denied: wrong password", GetActiveTabTitle());

  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            tab->NavigateToURL(test_server_.GetURL("auth-digest")));

  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_TRUE(tab->SetAuth(username_digest_, password_));
  EXPECT_EQ(ExpectedTitleFromAuth(username_digest_, password_),
            GetActiveTabTitle());
}

#if defined(OS_WIN)
// Probably related to test server flakiness in http://crbug.com/60937
#define MAYBE_TestTwoAuths FLAKY_TestTwoAuths
#else
#define MAYBE_TestTwoAuths TestTwoAuths
#endif

// Test that logging in on 2 tabs at once works.
TEST_F(LoginPromptTest, MAYBE_TestTwoAuths) {
  ASSERT_TRUE(test_server_.Start());

  scoped_refptr<TabProxy> basic_tab(GetActiveTab());
  ASSERT_TRUE(basic_tab.get());
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            basic_tab->NavigateToURL(test_server_.GetURL("auth-basic")));

  AppendTab(GURL(chrome::kAboutBlankURL));
  scoped_refptr<TabProxy> digest_tab(GetActiveTab());
  ASSERT_TRUE(digest_tab.get());
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            digest_tab->NavigateToURL(test_server_.GetURL("auth-digest")));

  EXPECT_TRUE(basic_tab->NeedsAuth());
  EXPECT_TRUE(basic_tab->SetAuth(username_basic_, password_));
  EXPECT_TRUE(digest_tab->NeedsAuth());
  EXPECT_TRUE(digest_tab->SetAuth(username_digest_, password_));

  wstring title;
  EXPECT_TRUE(basic_tab->GetTabTitle(&title));
  EXPECT_EQ(ExpectedTitleFromAuth(username_basic_, password_), title);

  EXPECT_TRUE(digest_tab->GetTabTitle(&title));
  EXPECT_EQ(ExpectedTitleFromAuth(username_digest_, password_), title);
}

#if defined(OS_WIN)
// Probably related to test server flakiness in http://crbug.com/60937
#define MAYBE_TestCancelAuth FLAKY_TestCancelAuth
#else
#define MAYBE_TestCancelAuth TestCancelAuth
#endif

// Test that cancelling authentication works.
TEST_F(LoginPromptTest, MAYBE_TestCancelAuth) {
  ASSERT_TRUE(test_server_.Start());

  scoped_refptr<TabProxy> tab(GetActiveTab());
  ASSERT_TRUE(tab.get());

  // First navigate to a test server page so we have something to go back to.
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
            tab->NavigateToURL(test_server_.GetURL("a")));

  // Navigating while auth is requested is the same as cancelling.
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            tab->NavigateToURL(test_server_.GetURL("auth-basic")));
  EXPECT_TRUE(tab->NeedsAuth());
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
            tab->NavigateToURL(test_server_.GetURL("b")));
  EXPECT_FALSE(tab->NeedsAuth());

  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            tab->NavigateToURL(test_server_.GetURL("auth-basic")));
  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_TRUE(tab->GoBack());  // should bring us back to 'a'
  EXPECT_FALSE(tab->NeedsAuth());

  // Now add a page and go back, so we have something to go forward to.
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
            tab->NavigateToURL(test_server_.GetURL("c")));
  EXPECT_TRUE(tab->GoBack());  // should bring us back to 'a'

  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            tab->NavigateToURL(test_server_.GetURL("auth-basic")));
  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_TRUE(tab->GoForward());  // should bring us to 'c'
  EXPECT_FALSE(tab->NeedsAuth());

  // Now test that cancelling works as expected.
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            tab->NavigateToURL(test_server_.GetURL("auth-basic")));
  EXPECT_TRUE(tab->NeedsAuth());
  EXPECT_TRUE(tab->CancelAuth());
  EXPECT_FALSE(tab->NeedsAuth());
  EXPECT_EQ(L"Denied: no auth", GetActiveTabTitle());
}

#if defined(OS_WIN)
// Probably related to test server flakiness in http://crbug.com/60937
#define MAYBE_SupplyRedundantAuths FLAKY_SupplyRedundantAuths
#else
#define MAYBE_SupplyRedundantAuths SupplyRedundantAuths
#endif

// If multiple tabs are looking for the same auth, the user should only have to
// enter it once.
TEST_F(LoginPromptTest, MAYBE_SupplyRedundantAuths) {
  ASSERT_TRUE(test_server_.Start());

  scoped_refptr<TabProxy> basic_tab1(GetActiveTab());
  ASSERT_TRUE(basic_tab1.get());
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            basic_tab1->NavigateToURL(test_server_.GetURL("auth-basic/1")));
  EXPECT_TRUE(basic_tab1->NeedsAuth());

  AppendTab(GURL(chrome::kAboutBlankURL));
  scoped_refptr<TabProxy> basic_tab2(GetActiveTab());
  ASSERT_TRUE(basic_tab2.get());
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            basic_tab2->NavigateToURL(test_server_.GetURL("auth-basic/2")));
  EXPECT_TRUE(basic_tab2->NeedsAuth());

  // Set the auth in only one of the tabs (but wait for the other to load).
  int64 last_navigation_time;
  ASSERT_TRUE(basic_tab2->GetLastNavigationTime(&last_navigation_time));
  EXPECT_TRUE(basic_tab1->SetAuth(username_basic_, password_));
  EXPECT_TRUE(basic_tab2->WaitForNavigation(last_navigation_time));

  // Now both tabs have loaded.
  wstring title1;
  EXPECT_TRUE(basic_tab1->GetTabTitle(&title1));
  EXPECT_EQ(ExpectedTitleFromAuth(username_basic_, password_), title1);
  wstring title2;
  EXPECT_TRUE(basic_tab2->GetTabTitle(&title2));
  EXPECT_EQ(ExpectedTitleFromAuth(username_basic_, password_), title2);
}

#if defined(OS_WIN)
// Probably related to test server flakiness in http://crbug.com/60937
#define MAYBE_CancelRedundantAuths FLAKY_CancelRedundantAuths
#else
#define MAYBE_CancelRedundantAuths CancelRedundantAuths
#endif

// If multiple tabs are looking for the same auth, and one is cancelled, the
// other should be cancelled as well.
TEST_F(LoginPromptTest, MAYBE_CancelRedundantAuths) {
  ASSERT_TRUE(test_server_.Start());

  scoped_refptr<TabProxy> basic_tab1(GetActiveTab());
  ASSERT_TRUE(basic_tab1.get());
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            basic_tab1->NavigateToURL(test_server_.GetURL("auth-basic/1")));
  EXPECT_TRUE(basic_tab1->NeedsAuth());

  AppendTab(GURL(chrome::kAboutBlankURL));
  scoped_refptr<TabProxy> basic_tab2(GetActiveTab());
  ASSERT_TRUE(basic_tab2.get());
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
            basic_tab2->NavigateToURL(test_server_.GetURL("auth-basic/2")));
  EXPECT_TRUE(basic_tab2->NeedsAuth());

  // Cancel the auth in only one of the tabs (but wait for the other to load).
  int64 last_navigation_time;
  ASSERT_TRUE(basic_tab2->GetLastNavigationTime(&last_navigation_time));
  EXPECT_TRUE(basic_tab1->CancelAuth());
  EXPECT_TRUE(basic_tab2->WaitForNavigation(last_navigation_time));

  // Now both tabs have been denied.
  wstring title1;
  EXPECT_TRUE(basic_tab1->GetTabTitle(&title1));
  EXPECT_EQ(L"Denied: no auth", title1);
  wstring title2;
  EXPECT_TRUE(basic_tab2->GetTabTitle(&title2));
  EXPECT_EQ(L"Denied: no auth", title2);
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 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 "chrome/common/notification_service.h"

#include "base/lazy_instance.h"
#include "base/thread_local.h"

static base::LazyInstance<base::ThreadLocalPointer<NotificationService> >
    lazy_tls_ptr(base::LINKER_INITIALIZED);

// static
NotificationService* NotificationService::current() {
  return lazy_tls_ptr.Pointer()->Get();
}

// static
bool NotificationService::HasKey(const NotificationSourceMap& map,
                                 const NotificationSource& source) {
  return map.find(source.map_key()) != map.end();
}

NotificationService::NotificationService() {
  DCHECK(current() == NULL);
#ifndef NDEBUG
  memset(observer_counts_, 0, sizeof(observer_counts_));
#endif

  lazy_tls_ptr.Pointer()->Set(this);
}

void NotificationService::AddObserver(NotificationObserver* observer,
                                      NotificationType type,
                                      const NotificationSource& source) {
  DCHECK(type.value < NotificationType::NOTIFICATION_TYPE_COUNT);

  NotificationObserverList* observer_list;
  if (HasKey(observers_[type.value], source)) {
    observer_list = observers_[type.value][source.map_key()];
  } else {
    observer_list = new NotificationObserverList;
    observers_[type.value][source.map_key()] = observer_list;
  }

  observer_list->AddObserver(observer);
#ifndef NDEBUG
  ++observer_counts_[type.value];
#endif
}

void NotificationService::RemoveObserver(NotificationObserver* observer,
                                         NotificationType type,
                                         const NotificationSource& source) {
  DCHECK(type.value < NotificationType::NOTIFICATION_TYPE_COUNT);
  DCHECK(HasKey(observers_[type.value], source));

  NotificationObserverList* observer_list =
      observers_[type.value][source.map_key()];
  if (observer_list) {
    observer_list->RemoveObserver(observer);
#ifndef NDEBUG
    --observer_counts_[type.value];
#endif
  }

  // TODO(jhughes): Remove observer list from map if empty?
}

void NotificationService::Notify(NotificationType type,
                                 const NotificationSource& source,
                                 const NotificationDetails& details) {
  DCHECK(type.value > NotificationType::ALL) <<
      "Allowed for observing, but not posting.";
  DCHECK(type.value < NotificationType::NOTIFICATION_TYPE_COUNT);

  // There's no particular reason for the order in which the different
  // classes of observers get notified here.

  // Notify observers of all types and all sources
  if (HasKey(observers_[NotificationType::ALL], AllSources()) &&
      source != AllSources()) {
    FOR_EACH_OBSERVER(NotificationObserver,
       *observers_[NotificationType::ALL][AllSources().map_key()],
       Observe(type, source, details));
  }

  // Notify observers of all types and the given source
  if (HasKey(observers_[NotificationType::ALL], source)) {
    FOR_EACH_OBSERVER(NotificationObserver,
        *observers_[NotificationType::ALL][source.map_key()],
        Observe(type, source, details));
  }

  // Notify observers of the given type and all sources
  if (HasKey(observers_[type.value], AllSources()) &&
      source != AllSources()) {
    FOR_EACH_OBSERVER(NotificationObserver,
                      *observers_[type.value][AllSources().map_key()],
                      Observe(type, source, details));
  }

  // Notify observers of the given type and the given source
  if (HasKey(observers_[type.value], source)) {
    FOR_EACH_OBSERVER(NotificationObserver,
                      *observers_[type.value][source.map_key()],
                      Observe(type, source, details));
  }
}

NotificationService::~NotificationService() {
  lazy_tls_ptr.Pointer()->Set(NULL);

#ifndef NDEBUG
  for (int i = 0; i < NotificationType::NOTIFICATION_TYPE_COUNT; i++) {
    if (observer_counts_[i] > 0) {
      LOG(WARNING) << observer_counts_[i] << " notification observer(s) leaked"
          << " of notification type " << i;
    }
  }
#endif

  for (int i = 0; i < NotificationType::NOTIFICATION_TYPE_COUNT; i++) {
    NotificationSourceMap omap = observers_[i];
    for (NotificationSourceMap::iterator it = omap.begin();
         it != omap.end(); ++it) {
      delete it->second;
    }
  }
}

NotificationObserver::~NotificationObserver() {}

<commit_msg>Add a CHECK for NULL observers. I got a NULL pointer exception when notifying on a notification, which is impossible to track down since I don't know who added it. Review URL: http://codereview.chromium.org/20502<commit_after>// Copyright (c) 2006-2008 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 "chrome/common/notification_service.h"

#include "base/lazy_instance.h"
#include "base/thread_local.h"

static base::LazyInstance<base::ThreadLocalPointer<NotificationService> >
    lazy_tls_ptr(base::LINKER_INITIALIZED);

// static
NotificationService* NotificationService::current() {
  return lazy_tls_ptr.Pointer()->Get();
}

// static
bool NotificationService::HasKey(const NotificationSourceMap& map,
                                 const NotificationSource& source) {
  return map.find(source.map_key()) != map.end();
}

NotificationService::NotificationService() {
  DCHECK(current() == NULL);
#ifndef NDEBUG
  memset(observer_counts_, 0, sizeof(observer_counts_));
#endif

  lazy_tls_ptr.Pointer()->Set(this);
}

void NotificationService::AddObserver(NotificationObserver* observer,
                                      NotificationType type,
                                      const NotificationSource& source) {
  DCHECK(type.value < NotificationType::NOTIFICATION_TYPE_COUNT);

  // We have gotten some crashes where the observer pointer is NULL. The problem
  // is that this happens when we actually execute a notification, so have no
  // way of knowing who the bad observer was. We want to know when this happens
  // in release mode so we know what code to blame the crash on (since this is
  // guaranteed to crash later).
  CHECK(observer);

  NotificationObserverList* observer_list;
  if (HasKey(observers_[type.value], source)) {
    observer_list = observers_[type.value][source.map_key()];
  } else {
    observer_list = new NotificationObserverList;
    observers_[type.value][source.map_key()] = observer_list;
  }

  observer_list->AddObserver(observer);
#ifndef NDEBUG
  ++observer_counts_[type.value];
#endif
}

void NotificationService::RemoveObserver(NotificationObserver* observer,
                                         NotificationType type,
                                         const NotificationSource& source) {
  DCHECK(type.value < NotificationType::NOTIFICATION_TYPE_COUNT);
  DCHECK(HasKey(observers_[type.value], source));

  NotificationObserverList* observer_list =
      observers_[type.value][source.map_key()];
  if (observer_list) {
    observer_list->RemoveObserver(observer);
#ifndef NDEBUG
    --observer_counts_[type.value];
#endif
  }

  // TODO(jhughes): Remove observer list from map if empty?
}

void NotificationService::Notify(NotificationType type,
                                 const NotificationSource& source,
                                 const NotificationDetails& details) {
  DCHECK(type.value > NotificationType::ALL) <<
      "Allowed for observing, but not posting.";
  DCHECK(type.value < NotificationType::NOTIFICATION_TYPE_COUNT);

  // There's no particular reason for the order in which the different
  // classes of observers get notified here.

  // Notify observers of all types and all sources
  if (HasKey(observers_[NotificationType::ALL], AllSources()) &&
      source != AllSources()) {
    FOR_EACH_OBSERVER(NotificationObserver,
       *observers_[NotificationType::ALL][AllSources().map_key()],
       Observe(type, source, details));
  }

  // Notify observers of all types and the given source
  if (HasKey(observers_[NotificationType::ALL], source)) {
    FOR_EACH_OBSERVER(NotificationObserver,
        *observers_[NotificationType::ALL][source.map_key()],
        Observe(type, source, details));
  }

  // Notify observers of the given type and all sources
  if (HasKey(observers_[type.value], AllSources()) &&
      source != AllSources()) {
    FOR_EACH_OBSERVER(NotificationObserver,
                      *observers_[type.value][AllSources().map_key()],
                      Observe(type, source, details));
  }

  // Notify observers of the given type and the given source
  if (HasKey(observers_[type.value], source)) {
    FOR_EACH_OBSERVER(NotificationObserver,
                      *observers_[type.value][source.map_key()],
                      Observe(type, source, details));
  }
}

NotificationService::~NotificationService() {
  lazy_tls_ptr.Pointer()->Set(NULL);

#ifndef NDEBUG
  for (int i = 0; i < NotificationType::NOTIFICATION_TYPE_COUNT; i++) {
    if (observer_counts_[i] > 0) {
      LOG(WARNING) << observer_counts_[i] << " notification observer(s) leaked"
          << " of notification type " << i;
    }
  }
#endif

  for (int i = 0; i < NotificationType::NOTIFICATION_TYPE_COUNT; i++) {
    NotificationSourceMap omap = observers_[i];
    for (NotificationSourceMap::iterator it = omap.begin();
         it != omap.end(); ++it) {
      delete it->second;
    }
  }
}

NotificationObserver::~NotificationObserver() {}

<|endoftext|>