<commit_before>// -*- coding: us-ascii-unix -*-
// Copyright 2012 Lukas Kemmer
//
// Licensed under the Apache License, Version 2.0 (the "License"); you
// may not use this file except in compliance with the License. You
// may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.

#include <cassert>
#include "bitmap/bitmap.hh"
#include "commands/tri-cmd.hh"
#include "geo/geo-func.hh"
#include "geo/int-rect.hh"
#include "geo/int-size.hh"
#include "geo/pathpt.hh"
#include "geo/pixel-snap.hh"
#include "geo/size.hh"
#include "objects/objtext.hh"
#include "rendering/faint-dc.hh"
#include "text/slice.hh"
#include "text/split-string.hh"
#include "text/text-expression.hh"
#include "text/utf8-string.hh"
#include "util-wx/font.hh"
#include "util/default-settings.hh"
#include "util/iter.hh"
#include "util/optional.hh"
#include "util/settings.hh"
#include "util/text-geo.hh"
#include "rendering/render-text.hh"
#include "rendering/text-info-dc.hh"

namespace faint{

static utf8_string get_expression_string(const parse_result_t& result,
  const ExpressionContext& context)
{
  return result.Visit(
    [&](const ExpressionTree& tree){
      return tree.Evaluate(context).Visit(
        [](const utf8_string& result){
          return result;
        },
        [](const ExpressionEvalError& error){
          return error.description;
        });
    },
    [](const ExpressionParseError& error){
      return error.description;
    });
}

static utf8_string get_evaluated_string(const ExpressionContext& ctx,
  const Optional<parse_result_t>& maybeExpression,
  const TextBuffer& textBuf)
{
  return maybeExpression.Visit(
    [&](const parse_result_t& expression){
      return get_expression_string(expression, ctx);
    },
    [&](){
      return textBuf.get();
    });
}

ObjText::ObjText(const Tri& tri, const utf8_string& text, const Settings& s)
  : Object(s),
    m_textBuf(text),
    m_caret(LineSegment(Point(0,0),Point(0,0))),
    m_tri(tri)
{
  Init();
}

ObjText::ObjText(const ObjText& other)
  : Object(other.GetSettings()),
    m_textBuf(other.m_textBuf),
    m_caret(LineSegment(Point(0,0),Point(0,0))),
    m_tri(other.GetTri()),
    m_expression(other.m_expression)
{
  Init();
}

void ObjText::Init(){
  assert(m_settings.Has(ts_FontSize));
  assert(m_settings.Has(ts_FontFace));
  m_beingEdited = false;

  m_rowHeight = TextInfoDC(m_settings).ComputeRowHeight();
  m_lastFontSize = m_settings.Get(ts_FontSize);
  m_lastFontFace = m_settings.Get(ts_FontFace);
  m_expression.Set(parse_text_expression(m_textBuf.get()));
}

coord ObjText::BaselineOffset() const{
  return TextInfoDC(m_settings).Ascent();
}

size_t ObjText::CaretPos(const Point& posUnaligned) const{
  TextInfoDC info(m_settings);
  const auto lines = split_string(info, m_textBuf.get(),
    max_width_t(m_tri.Width()));

  const auto maxCaret = m_textBuf.size();
  auto rowHeight = RowHeight();

  return caret_index_from_pos(posUnaligned,
    m_tri,
    lines,
    rowHeight,
    maxCaret,
    [&](const utf8_string& s){return info.CumulativeTextWidth(s);});
}

Object* ObjText::Clone() const{
  return new ObjText(*this);
}

void ObjText::Draw(FaintDC& dc, ExpressionContext& ctx){
  TextInfoDC textInfo(m_settings);
  m_rowHeight = textInfo.ComputeRowHeight();

  if (m_textBuf.empty()){
    // Fixme: Tricky that this is done during rendering
    // Compute the caret position
    Tri caretTri(m_tri.P0(), m_tri.P1(), m_rowHeight);
    caretTri = offset_aligned(caretTri, 1.0, 0.0);
    m_caret = LineSegment(caretTri.P0(), caretTri.P2());
  }

  auto lines = Split(textInfo, ctx);
  render_text(dc,
    lines,
    m_textBuf.get_sel_range(),
    m_tri,
    m_beingEdited,
    textInfo,
    m_settings);

  m_caret = compute_caret(textInfo, m_textBuf, m_tri, lines, m_settings);
}

void ObjText::DrawMask(FaintDC& dc, ExpressionContext& ctx){
  TextInfoDC textInfo(m_settings);
  render_text_mask(dc,
    Split(textInfo, ctx),
    m_tri,
    textInfo,
    m_settings);
}

Rect ObjText::GetAutoSizedRect() const {
  TextInfoDC info(m_settings);
  // Fixme: Doesn't take expressions in account.
  const auto textSize = text_extents(info,
    split_string(info, m_textBuf.get(), no_option()));

  return Rect(m_tri.P0(), floated(textSize));
}

LineSegment ObjText::GetCaret() const{
  return m_caret;
}

utf8_string ObjText::GetEvaluatedString(const ExpressionContext& ctx) const{
  if (m_settings.Get(ts_ParseExpressions) && m_expression.IsSet()){
    return get_expression_string(m_expression.Get(), ctx);
  }
  else{
    return m_textBuf.get();
  }
}

std::vector<PathPt> ObjText::GetPath(const ExpressionContext& ctx) const{
  TextInfoDC textInfo(m_settings);
  text_lines_t lines = split_string(textInfo, GetEvaluatedString(ctx),
    m_settings.Get(ts_BoundedText) ? max_width_t(m_tri.Width()) : no_option());

  Align align(m_settings.Get(ts_HorizontalAlign),
    m_settings.Get(ts_VerticalAlign));

  // Build the path
  std::vector<PathPt> path;
  auto tris(text_line_regions(textInfo, m_tri, lines, align));
  for (const auto item : zip(tris, lines)){
    auto subPath(textInfo.GetTextPath(item.first, item.second.text));
    for (const auto& p : subPath){
      path.push_back(p);
    }
  }
  return path;
}

utf8_string ObjText::GetRawString() const{
  return m_textBuf.get();
}

IntRect ObjText::GetRefreshRect() const{
  if (m_settings.Get(ts_BoundedText)){
    return floiled(bounding_rect(m_tri));
  }
  else{
    // Fixme: Slow.
    TextInfoDC info(m_settings);
    text_lines_t lines = split_string(info, m_textBuf.get(), max_width_t());

    int w = 0;
    for (auto l : lines){
      w = std::max(info.GetWidth(l.text), w);
    }

    const int h = info.ComputeRowHeight() * resigned(lines.size());
    return floiled(bounding_rect(Tri(m_tri.P0(), m_tri.GetAngle(), Size(w,h))));
  }
}

TextBuffer& ObjText::GetTextBuffer(){
  return m_textBuf;
}

Tri ObjText::GetTri() const{
  if (m_settings.Get(ts_BoundedText)){
    return m_tri;
  }
  else{
    TextInfoDC info(m_settings);
    const auto textSize = text_extents(info,
      split_string(info, m_textBuf.get(), no_option()));

    return Tri(m_tri.P0(), m_tri.GetAngle(), floated(textSize));
  }
}

utf8_string ObjText::GetType() const{
  return "Text Region";
}

bool ObjText::HasSelectedRange() const{
  return !m_textBuf.get_sel_range().Empty();
}

Optional<CmdFuncs> ObjText::PixelSnapFunc(){
  if (m_tri.Skew() != 0 || !multiple_of_90(m_tri.GetAngle())){
    return {};
  }

  return {CmdFuncs(
     [this](){
       m_tri = pixel_snap_middle(m_tri);
     },
     [oldTri = m_tri, this](){
       m_tri = oldTri;
     })};
}

coord ObjText::RowHeight() const{
  if (m_settings.Get(ts_FontSize) != m_lastFontSize ||
    m_lastFontFace != m_settings.Get(ts_FontFace))
  {
    m_lastFontSize = m_settings.Get(ts_FontSize);
    m_lastFontFace = m_settings.Get(ts_FontFace);
    m_rowHeight = TextInfoDC(m_settings).ComputeRowHeight();
  }
  return m_rowHeight;
}

void ObjText::SetCaretPos(size_t pos, bool select){
  m_textBuf.caret(pos, select);
}

void ObjText::SetEdited(bool edited){
  m_beingEdited = edited;
  if (m_beingEdited == false){
    m_expression.Set(parse_text_expression(m_textBuf.get()));
  }
}

void ObjText::SetTri(const Tri& t){
  m_tri = t;
}

bool ObjText::ShowSizeBox() const{
  // Since the text object boundaries aren't clear (like say a
  // rectangle), show a box while resizing.
  return true;
}

text_lines_t ObjText::Split(const TextInfo& textInfo,
  ExpressionContext& ctx) const
{
  const auto maxWidth = m_settings.Get(ts_BoundedText) ?
    max_width_t(m_tri.Width()) :
    max_width_t();

  return (m_beingEdited || !m_settings.Get(ts_ParseExpressions)) ?
    split_string(textInfo, m_textBuf.get(), maxWidth) :
    split_string(textInfo, get_evaluated_string(ctx, m_expression, m_textBuf),
      maxWidth);
}

text_lines_t split_evaluated(ExpressionContext& ctx,
  const ObjText* text)
{
  return split_string(TextInfoDC(text->GetSettings()),
    text->GetEvaluatedString(ctx),
    text->GetTri().Width());
}

Command* crop_text_region_command(ObjText* text){
  const Tri oldTri = text->GetTri();
  Tri tri(rotated(tri_from_rect(text->GetAutoSizedRect()),
      oldTri.GetAngle(), oldTri.P0()));
  return new TriCommand(text, New(tri), Old(oldTri), "Auto-Size");
}

bool is_text(const Object* obj){
  return dynamic_cast<const ObjText*>(obj) != nullptr;
}

} // namespace
<commit_msg>Extracted empty-text caret computation.<commit_after>// -*- coding: us-ascii-unix -*-
// Copyright 2012 Lukas Kemmer
//
// Licensed under the Apache License, Version 2.0 (the "License"); you
// may not use this file except in compliance with the License. You
// may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.

#include <cassert>
#include "bitmap/bitmap.hh"
#include "commands/tri-cmd.hh"
#include "geo/geo-func.hh"
#include "geo/int-rect.hh"
#include "geo/int-size.hh"
#include "geo/pathpt.hh"
#include "geo/pixel-snap.hh"
#include "geo/size.hh"
#include "objects/objtext.hh"
#include "rendering/faint-dc.hh"
#include "text/slice.hh"
#include "text/split-string.hh"
#include "text/text-expression.hh"
#include "text/utf8-string.hh"
#include "util-wx/font.hh"
#include "util/default-settings.hh"
#include "util/iter.hh"
#include "util/optional.hh"
#include "util/settings.hh"
#include "util/text-geo.hh"
#include "rendering/render-text.hh"
#include "rendering/text-info-dc.hh"

namespace faint{

static utf8_string get_expression_string(const parse_result_t& result,
  const ExpressionContext& context)
{
  return result.Visit(
    [&](const ExpressionTree& tree){
      return tree.Evaluate(context).Visit(
        [](const utf8_string& result){
          return result;
        },
        [](const ExpressionEvalError& error){
          return error.description;
        });
    },
    [](const ExpressionParseError& error){
      return error.description;
    });
}

static utf8_string get_evaluated_string(const ExpressionContext& ctx,
  const Optional<parse_result_t>& maybeExpression,
  const TextBuffer& textBuf)
{
  return maybeExpression.Visit(
    [&](const parse_result_t& expression){
      return get_expression_string(expression, ctx);
    },
    [&](){
      return textBuf.get();
    });
}

static LineSegment empty_text_caret(const Tri& tri, coord rowHeight){
  Tri caretTri(tri.P0(), tri.P1(), rowHeight);
  caretTri = offset_aligned(caretTri, 1.0, 0.0);
  return LineSegment(caretTri.P0(), caretTri.P2());

}

ObjText::ObjText(const Tri& tri, const utf8_string& text, const Settings& s)
  : Object(s),
    m_textBuf(text),
    m_caret(LineSegment(Point(0,0),Point(0,0))),
    m_tri(tri)
{
  Init();
}

ObjText::ObjText(const ObjText& other)
  : Object(other.GetSettings()),
    m_textBuf(other.m_textBuf),
    m_caret(LineSegment(Point(0,0),Point(0,0))),
    m_tri(other.GetTri()),
    m_expression(other.m_expression)
{
  Init();
}

void ObjText::Init(){
  assert(m_settings.Has(ts_FontSize));
  assert(m_settings.Has(ts_FontFace));
  m_beingEdited = false;

  m_rowHeight = TextInfoDC(m_settings).ComputeRowHeight();
  m_lastFontSize = m_settings.Get(ts_FontSize);
  m_lastFontFace = m_settings.Get(ts_FontFace);
  m_expression.Set(parse_text_expression(m_textBuf.get()));
}

coord ObjText::BaselineOffset() const{
  return TextInfoDC(m_settings).Ascent();
}

size_t ObjText::CaretPos(const Point& imagePos) const{
  TextInfoDC info(m_settings);
  const auto lines = split_string(info, m_textBuf.get(),
    max_width_t(m_tri.Width()));

  const auto maxCaret = m_textBuf.size();
  const auto rowHeight = RowHeight();

  return caret_index_from_pos(imagePos,
    m_tri,
    lines,
    rowHeight,
    maxCaret,
    [&](const utf8_string& s){return info.CumulativeTextWidth(s);});
}

Object* ObjText::Clone() const{
  return new ObjText(*this);
}

void ObjText::Draw(FaintDC& dc, ExpressionContext& ctx){
  TextInfoDC textInfo(m_settings);
  m_rowHeight = textInfo.ComputeRowHeight();

  if (m_textBuf.empty()){
    // Fixme: Tricky that this is done during rendering
    m_caret = empty_text_caret(m_tri, m_rowHeight);
  }

  auto lines = Split(textInfo, ctx);
  render_text(dc,
    lines,
    m_textBuf.get_sel_range(),
    m_tri,
    m_beingEdited,
    textInfo,
    m_settings);

  m_caret = compute_caret(textInfo, m_textBuf, m_tri, lines, m_settings);
}

void ObjText::DrawMask(FaintDC& dc, ExpressionContext& ctx){
  TextInfoDC textInfo(m_settings);
  render_text_mask(dc,
    Split(textInfo, ctx),
    m_tri,
    textInfo,
    m_settings);
}

Rect ObjText::GetAutoSizedRect() const {
  TextInfoDC info(m_settings);
  // Fixme: Doesn't take expressions in account.
  const auto textSize = text_extents(info,
    split_string(info, m_textBuf.get(), no_option()));

  return Rect(m_tri.P0(), floated(textSize));
}

LineSegment ObjText::GetCaret() const{
  return m_caret;
}

utf8_string ObjText::GetEvaluatedString(const ExpressionContext& ctx) const{
  if (m_settings.Get(ts_ParseExpressions) && m_expression.IsSet()){
    return get_expression_string(m_expression.Get(), ctx);
  }
  else{
    return m_textBuf.get();
  }
}

std::vector<PathPt> ObjText::GetPath(const ExpressionContext& ctx) const{
  TextInfoDC textInfo(m_settings);
  text_lines_t lines = split_string(textInfo, GetEvaluatedString(ctx),
    m_settings.Get(ts_BoundedText) ? max_width_t(m_tri.Width()) : no_option());

  Align align(m_settings.Get(ts_HorizontalAlign),
    m_settings.Get(ts_VerticalAlign));

  // Build the path
  std::vector<PathPt> path;
  auto tris(text_line_regions(textInfo, m_tri, lines, align));
  for (const auto item : zip(tris, lines)){
    auto subPath(textInfo.GetTextPath(item.first, item.second.text));
    for (const auto& p : subPath){
      path.push_back(p);
    }
  }
  return path;
}

utf8_string ObjText::GetRawString() const{
  return m_textBuf.get();
}

IntRect ObjText::GetRefreshRect() const{
  if (m_settings.Get(ts_BoundedText)){
    return floiled(bounding_rect(m_tri));
  }
  else{
    // Fixme: Slow.
    TextInfoDC info(m_settings);
    text_lines_t lines = split_string(info, m_textBuf.get(), max_width_t());

    int w = 0;
    for (auto l : lines){
      w = std::max(info.GetWidth(l.text), w);
    }

    const int h = info.ComputeRowHeight() * resigned(lines.size());
    return floiled(bounding_rect(Tri(m_tri.P0(), m_tri.GetAngle(), Size(w,h))));
  }
}

TextBuffer& ObjText::GetTextBuffer(){
  return m_textBuf;
}

Tri ObjText::GetTri() const{
  if (m_settings.Get(ts_BoundedText)){
    return m_tri;
  }
  else{
    TextInfoDC info(m_settings);
    const auto textSize = text_extents(info,
      split_string(info, m_textBuf.get(), no_option()));

    return Tri(m_tri.P0(), m_tri.GetAngle(), floated(textSize));
  }
}

utf8_string ObjText::GetType() const{
  return "Text Region";
}

bool ObjText::HasSelectedRange() const{
  return !m_textBuf.get_sel_range().Empty();
}

Optional<CmdFuncs> ObjText::PixelSnapFunc(){
  if (m_tri.Skew() != 0 || !multiple_of_90(m_tri.GetAngle())){
    return {};
  }

  return {CmdFuncs(
     [this](){
       m_tri = pixel_snap_middle(m_tri);
     },
     [oldTri = m_tri, this](){
       m_tri = oldTri;
     })};
}

coord ObjText::RowHeight() const{
  if (m_settings.Get(ts_FontSize) != m_lastFontSize ||
    m_lastFontFace != m_settings.Get(ts_FontFace))
  {
    m_lastFontSize = m_settings.Get(ts_FontSize);
    m_lastFontFace = m_settings.Get(ts_FontFace);
    m_rowHeight = TextInfoDC(m_settings).ComputeRowHeight();
  }
  return m_rowHeight;
}

void ObjText::SetCaretPos(size_t pos, bool select){
  m_textBuf.caret(pos, select);
}

void ObjText::SetEdited(bool edited){
  m_beingEdited = edited;
  if (m_beingEdited == false){
    m_expression.Set(parse_text_expression(m_textBuf.get()));
  }
}

void ObjText::SetTri(const Tri& t){
  m_tri = t;
}

bool ObjText::ShowSizeBox() const{
  // Since the text object boundaries aren't clear (like say a
  // rectangle), show a box while resizing.
  return true;
}

text_lines_t ObjText::Split(const TextInfo& textInfo,
  ExpressionContext& ctx) const
{
  const auto maxWidth = m_settings.Get(ts_BoundedText) ?
    max_width_t(m_tri.Width()) :
    max_width_t();

  return (m_beingEdited || !m_settings.Get(ts_ParseExpressions)) ?
    split_string(textInfo, m_textBuf.get(), maxWidth) :
    split_string(textInfo, get_evaluated_string(ctx, m_expression, m_textBuf),
      maxWidth);
}

text_lines_t split_evaluated(ExpressionContext& ctx,
  const ObjText* text)
{
  return split_string(TextInfoDC(text->GetSettings()),
    text->GetEvaluatedString(ctx),
    text->GetTri().Width());
}

Command* crop_text_region_command(ObjText* text){
  const Tri oldTri = text->GetTri();
  Tri tri(rotated(tri_from_rect(text->GetAutoSizedRect()),
      oldTri.GetAngle(), oldTri.P0()));
  return new TriCommand(text, New(tri), Old(oldTri), "Auto-Size");
}

bool is_text(const Object* obj){
  return dynamic_cast<const ObjText*>(obj) != nullptr;
}

} // namespace
<|endoftext|>


<commit_before>#ifndef OCLUTIL_DEVLIST_HPP
#define OCLUTIL_DEVLIST_HPP

/**
 * \file   devlist.hpp
 * \author Denis Demidov <ddemidov@ksu.ru>
 * \brief  OpenCL device enumeration.
 */

#ifdef WIN32
#  pragma warning(disable : 4290 4715)
#  define NOMINMAX
#endif

#define __CL_ENABLE_EXCEPTIONS

#include <vector>
#include <string>
#include <CL/cl.hpp>

/// OpenCL convenience utilities.
namespace clu {

/// Device filters.
namespace Filter {
    /// Selects any device.
    struct All {
	bool operator()(const cl::Device &d) const {
	    return true;
	}
    };

    /// Selects devices whose platform vendor name match given value.
    struct Vendor {
	Vendor(const std::string &name) : vendor(name) {}

	bool operator()(const cl::Device &d) const {
	    return d.getInfo<CL_DEVICE_VENDOR>().find(vendor) != std::string::npos;
	}

	private:
	    const std::string &vendor;
    };

    /// Selects devices whose platform name match given value.
    struct Platform {
	Platform(const std::string &name) : platform(name) {}

	bool operator()(const cl::Device &d) const {
	    return cl::Platform(d.getInfo<CL_DEVICE_PLATFORM>()).getInfo<CL_PLATFORM_NAME>().find(platform) != std::string::npos;
	}

	private:
	    const std::string &platform;
    };

    /// Selects devices whose names match given value.
    struct Name {
	Name(const std::string &name) : devname(name) {}

	bool operator()(const cl::Device &d) const {
	    return d.getInfo<CL_DEVICE_NAME>().find(devname) != std::string::npos;
	}

	private:
	    const std::string &devname;
    };

    /// Selects devices by type.
    struct Type {
	Type(cl_device_type t) : type(t) {}

	bool operator()(const cl::Device &d) const {
	    return d.getInfo<CL_DEVICE_TYPE>() == type;
	}

	private:
	    cl_device_type type;
    };

    /// Selects devices supporting double precision.
    struct DoublePrecision {
	bool operator()(const cl::Device &d) const {
	    if (d.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_CPU)
		return true;

	    std::string ext = d.getInfo<CL_DEVICE_EXTENSIONS>();

	    return (
		    ext.find("cl_khr_fp64") != std::string::npos ||
		    ext.find("cl_amd_fp64") != std::string::npos
		   );
	}
    };

    /// Selects no more than given number of devices.
    struct Count {
	Count(int c) : count(c) {}

	bool operator()(const cl::Device &d) const {
	    return --count >= 0;
	}

	private:
	    mutable int count;
    };

    /// \internal Filter join operators.
    enum FilterOp {
	FilterAnd, FilterOr
    };

    /// \internal Filter join expression template.
    template <class LeftFilter, class RightFilter, FilterOp op>
	struct FilterBinaryOp {
	    FilterBinaryOp(const LeftFilter &l, const RightFilter &r)
		: left(l), right(r) {}

	    bool operator()(const cl::Device &d) const {
		switch (op) {
		    case FilterAnd:
			return left(d) && right(d);
		    case FilterOr:
			return left(d) || right(d);
		}
	    }

	    private:
	    const LeftFilter &left;
	    const RightFilter &right;
	};

    /// Join two filters with AND operator.
    template <class LeftFilter, class RightFilter>
	FilterBinaryOp<LeftFilter, RightFilter, FilterAnd> operator&&(
		const LeftFilter &left, const RightFilter &right)
	{
	    return FilterBinaryOp<LeftFilter, RightFilter, FilterAnd>(left, right);
	}

    /// Join two filters with OR operator.
    template <class LeftFilter, class RightFilter>
	FilterBinaryOp<LeftFilter, RightFilter, FilterOr> operator||(
		const LeftFilter &left, const RightFilter &right)
	{
	    return FilterBinaryOp<LeftFilter, RightFilter, FilterOr>(left, right);
	}

    /// \internal Negation of a filter.
    template <class Flt>
	struct NegateFilter {
	    NegateFilter(const Flt &flt) : flt(flt) {}

	    bool operator()(const cl::Device &d) const {
		return !flt(d);
	    }

	    private:
	    const Flt &flt;
	};

    /// Negate a filter.
    template <class Flt>
	NegateFilter<Flt> operator!(const Flt &flt) {
	    return NegateFilter<Flt>(flt);
	}

} // namespace Filter

/// Select devices by given criteria.
/**
 * \param filter  Device filter functor. Functors may be combined with logical
 *		  operators.
 * \param verbose If set, outputs list of selected devices to stdout.
 * \returns list of devices satisfying the provided filter.
 *
 * This example selects any GPU which supports double precision arithmetic:
 * \code
 * auto devices = device_list(
 *	    Filter::Type(CL_DEVICE_TYPE_GPU) && Filter::DoublePrecision()
 *	    );
 * \endcode
 */
template<class DevFilter = Filter::All>
std::vector<cl::Device> device_list(DevFilter filter = Filter::All(),
	bool verbose = false
	)
{
    std::vector<cl::Device> device;

    std::vector<cl::Platform> platforms;
    cl::Platform::get(&platforms);

    for(auto p = platforms.begin(); p != platforms.end(); p++) {
	std::vector<cl::Device> dev_list;

	p->getDevices(CL_DEVICE_TYPE_ALL, &dev_list);

	for(auto d = dev_list.begin(); d != dev_list.end(); d++) {
	    if (!d->getInfo<CL_DEVICE_AVAILABLE>()) continue;
	    if (!filter(*d)) continue;

	    device.push_back(*d);
	}
    }

    if (verbose) {
	uint p = 1;
	for(auto d = device.begin(); d != device.end(); d++)
	    std::cout << p++ << ". "
		      << d->getInfo<CL_DEVICE_NAME>() << std::endl;
    }

    return device;
}

/// Create command queues on devices by given criteria.
/**
 * \param filter  Device filter functor. Functors may be combined with logical
 *		  operators.
 * \param verbose If set, output list of selected devices to stdout.
 * \returns list of queues accociated with selected devices.
 * \see device_list
 */
template<class DevFilter = Filter::All>
std::pair<std::vector<cl::Context>, std::vector<cl::CommandQueue>>
queue_list(DevFilter filter = Filter::All(), bool verbose = false)
{
    std::vector<cl::Context>      context;
    std::vector<cl::CommandQueue> queue;

    std::vector<cl::Platform> platforms;
    cl::Platform::get(&platforms);

    for(auto p = platforms.begin(); p != platforms.end(); p++) {
	std::vector<cl::Device> device;
	std::vector<cl::Device> dev_list;

	p->getDevices(CL_DEVICE_TYPE_ALL, &dev_list);

	for(auto d = dev_list.begin(); d != dev_list.end(); d++) {
	    if (!d->getInfo<CL_DEVICE_AVAILABLE>()) continue;
	    if (!filter(*d)) continue;

	    device.push_back(*d);
	}

	if (device.empty()) continue;

	context.push_back(cl::Context(device));
	for(auto d = device.begin(); d != device.end(); d++)
	    queue.push_back(cl::CommandQueue(context.back(), *d));
    }

    if (verbose) {
	uint p = 1;
	for(auto q = queue.begin(); q != queue.end(); q++)
	    std::cout << p++ << ". "
		      << q->getInfo<CL_QUEUE_DEVICE>().getInfo<CL_DEVICE_NAME>()
		      << std::endl;
    }

    return std::make_pair(context, queue);
}

} // namespace clu

#endif
<commit_msg>Documentation update<commit_after>#ifndef OCLUTIL_DEVLIST_HPP
#define OCLUTIL_DEVLIST_HPP

/**
 * \file   devlist.hpp
 * \author Denis Demidov <ddemidov@ksu.ru>
 * \brief  OpenCL device enumeration.
 */

#ifdef WIN32
#  pragma warning(disable : 4290 4715)
#  define NOMINMAX
#endif

#define __CL_ENABLE_EXCEPTIONS

#include <vector>
#include <string>
#include <CL/cl.hpp>

/// OpenCL convenience utilities.
namespace clu {

/// Device filters.
namespace Filter {
    /// Selects any device.
    struct All {
	bool operator()(const cl::Device &d) const {
	    return true;
	}
    };

    /// Selects devices whose vendor name match given value.
    struct Vendor {
	Vendor(const std::string &name) : vendor(name) {}

	bool operator()(const cl::Device &d) const {
	    return d.getInfo<CL_DEVICE_VENDOR>().find(vendor) != std::string::npos;
	}

	private:
	    const std::string &vendor;
    };

    /// Selects devices whose platform name match given value.
    struct Platform {
	Platform(const std::string &name) : platform(name) {}

	bool operator()(const cl::Device &d) const {
	    return cl::Platform(d.getInfo<CL_DEVICE_PLATFORM>()).getInfo<CL_PLATFORM_NAME>().find(platform) != std::string::npos;
	}

	private:
	    const std::string &platform;
    };

    /// Selects devices whose names match given value.
    struct Name {
	Name(const std::string &name) : devname(name) {}

	bool operator()(const cl::Device &d) const {
	    return d.getInfo<CL_DEVICE_NAME>().find(devname) != std::string::npos;
	}

	private:
	    const std::string &devname;
    };

    /// Selects devices by type.
    struct Type {
	Type(cl_device_type t) : type(t) {}

	bool operator()(const cl::Device &d) const {
	    return d.getInfo<CL_DEVICE_TYPE>() == type;
	}

	private:
	    cl_device_type type;
    };

    /// Selects devices supporting double precision.
    struct DoublePrecision {
	bool operator()(const cl::Device &d) const {
	    if (d.getInfo<CL_DEVICE_TYPE>() == CL_DEVICE_TYPE_CPU)
		return true;

	    std::string ext = d.getInfo<CL_DEVICE_EXTENSIONS>();

	    return (
		    ext.find("cl_khr_fp64") != std::string::npos ||
		    ext.find("cl_amd_fp64") != std::string::npos
		   );
	}
    };

    /// Selects no more than given number of devices.
    struct Count {
	Count(int c) : count(c) {}

	bool operator()(const cl::Device &d) const {
	    return --count >= 0;
	}

	private:
	    mutable int count;
    };

    /// \internal Filter join operators.
    enum FilterOp {
	FilterAnd, FilterOr
    };

    /// \internal Filter join expression template.
    template <class LeftFilter, class RightFilter, FilterOp op>
	struct FilterBinaryOp {
	    FilterBinaryOp(const LeftFilter &l, const RightFilter &r)
		: left(l), right(r) {}

	    bool operator()(const cl::Device &d) const {
		switch (op) {
		    case FilterAnd:
			return left(d) && right(d);
		    case FilterOr:
			return left(d) || right(d);
		}
	    }

	    private:
	    const LeftFilter &left;
	    const RightFilter &right;
	};

    /// Join two filters with AND operator.
    template <class LeftFilter, class RightFilter>
	FilterBinaryOp<LeftFilter, RightFilter, FilterAnd> operator&&(
		const LeftFilter &left, const RightFilter &right)
	{
	    return FilterBinaryOp<LeftFilter, RightFilter, FilterAnd>(left, right);
	}

    /// Join two filters with OR operator.
    template <class LeftFilter, class RightFilter>
	FilterBinaryOp<LeftFilter, RightFilter, FilterOr> operator||(
		const LeftFilter &left, const RightFilter &right)
	{
	    return FilterBinaryOp<LeftFilter, RightFilter, FilterOr>(left, right);
	}

    /// \internal Negation of a filter.
    template <class Flt>
	struct NegateFilter {
	    NegateFilter(const Flt &flt) : flt(flt) {}

	    bool operator()(const cl::Device &d) const {
		return !flt(d);
	    }

	    private:
	    const Flt &flt;
	};

    /// Negate a filter.
    template <class Flt>
	NegateFilter<Flt> operator!(const Flt &flt) {
	    return NegateFilter<Flt>(flt);
	}

} // namespace Filter

/// Select devices by given criteria.
/**
 * \param filter  Device filter functor. Functors may be combined with logical
 *		  operators.
 * \param verbose If set, outputs list of selected devices to stdout.
 * \returns list of devices satisfying the provided filter.
 *
 * This example selects any GPU which supports double precision arithmetic:
 * \code
 * auto devices = device_list(
 *	    Filter::Type(CL_DEVICE_TYPE_GPU) && Filter::DoublePrecision()
 *	    );
 * \endcode
 */
template<class DevFilter = Filter::All>
std::vector<cl::Device> device_list(DevFilter filter = Filter::All(),
	bool verbose = false
	)
{
    std::vector<cl::Device> device;

    std::vector<cl::Platform> platforms;
    cl::Platform::get(&platforms);

    for(auto p = platforms.begin(); p != platforms.end(); p++) {
	std::vector<cl::Device> dev_list;

	p->getDevices(CL_DEVICE_TYPE_ALL, &dev_list);

	for(auto d = dev_list.begin(); d != dev_list.end(); d++) {
	    if (!d->getInfo<CL_DEVICE_AVAILABLE>()) continue;
	    if (!filter(*d)) continue;

	    device.push_back(*d);
	}
    }

    if (verbose) {
	uint p = 1;
	for(auto d = device.begin(); d != device.end(); d++)
	    std::cout << p++ << ". "
		      << d->getInfo<CL_DEVICE_NAME>() << std::endl;
    }

    return device;
}

/// Create command queues on devices by given criteria.
/**
 * \param filter  Device filter functor. Functors may be combined with logical
 *		  operators.
 * \param verbose If set, output list of selected devices to stdout.
 * \returns list of queues accociated with selected devices.
 * \see device_list
 */
template<class DevFilter = Filter::All>
std::pair<std::vector<cl::Context>, std::vector<cl::CommandQueue>>
queue_list(DevFilter filter = Filter::All(), bool verbose = false)
{
    std::vector<cl::Context>      context;
    std::vector<cl::CommandQueue> queue;

    std::vector<cl::Platform> platforms;
    cl::Platform::get(&platforms);

    for(auto p = platforms.begin(); p != platforms.end(); p++) {
	std::vector<cl::Device> device;
	std::vector<cl::Device> dev_list;

	p->getDevices(CL_DEVICE_TYPE_ALL, &dev_list);

	for(auto d = dev_list.begin(); d != dev_list.end(); d++) {
	    if (!d->getInfo<CL_DEVICE_AVAILABLE>()) continue;
	    if (!filter(*d)) continue;

	    device.push_back(*d);
	}

	if (device.empty()) continue;

	context.push_back(cl::Context(device));
	for(auto d = device.begin(); d != device.end(); d++)
	    queue.push_back(cl::CommandQueue(context.back(), *d));
    }

    if (verbose) {
	uint p = 1;
	for(auto q = queue.begin(); q != queue.end(); q++)
	    std::cout << p++ << ". "
		      << q->getInfo<CL_QUEUE_DEVICE>().getInfo<CL_DEVICE_NAME>()
		      << std::endl;
    }

    return std::make_pair(context, queue);
}

} // namespace clu

#endif
<|endoftext|>


<commit_before>#ifndef OCLUTIL_OCLUTIL_HPP
#define OCLUTIL_OCLUTIL_HPP

/**
 * \file   oclutil.hpp
 * \author Denis Demidov <ddemidov@ksu.ru>
 * \brief  OpenCL convenience utilities.
 */

/**
\mainpage oclutil

oclutil is header-only template library created for ease of C++ based OpenCL
development.

\section devlist Selection of compute devices

You can select any number of available compute devices, which satisfy provided
filters. Filter is a functor returning bool and acting on a cl::Device
parameter. Several standard filters are provided, such as device type or name
filter, double precision support etc. Filters can be combined with logical
operators. In the example below all devices with names matching "Radeon" and
supporting double precision are selected:
\code
#include <iostream>
#include <oclutil/oclutil.hpp>
using namespace clu;
int main() {
    auto device = device_list(
        Filter::Name("Radeon") && Filter::DoublePrecision()
        );
    std::cout << device.size() << " GPUs found:" << std::endl;
    for(auto &d : device)
        std::cout << "\t" << d.getInfo<CL_DEVICE_NAME>() << std::endl;
}
\endcode

Often you want not just device list, but initialized OpenCL context with
command queue on each available device. This may be achieved with queue_list()
function:
\code
cl::Context context;
std::vector<cl::CommandQueue> queue;
// Select no more than 2 NVIDIA GPUs:
std::tie(context, queue) = queue_list(
    [](const cl::Device &d) {
        return d.getInfo<CL_DEVICE_VENDOR>() == "NVIDIA Corporation";
    } && Filter::Count(2)
    );
\endcode

\section vector Memory allocation and vector arithmetic

Once you got queue list, you can allocate OpenCL buffers on the associated
devices. clu::vector constructor accepts std::vector of cl::CommandQueue.
The contents of the created vector will be equally partitioned between each
queue (presumably, each of the provided queues is linked with separate device).
\code
const uint n = 1 << 20;
std::vector<double> x(n);
std::generate(x.begin(), x.end(), [](){ return (double)rand() / RAND_MAX; });

cl::Context context;
std::vector<cl::CommandQueue> queue;
std::tie(context, queue) = queue_list(Filter::Type(CL_DEVICE_TYPE_GPU));

clu::vector<double> X(queue, CL_MEM_READ_ONLY,  x);
clu::vector<double> Y(queue, CL_MEM_READ_WRITE, n);
clu::vector<double> Z(queue, CL_MEM_READ_WRITE, n);
\endcode

You can now use simple vector arithmetic with device vector. For every
expression you use, appropriate kernel is compiled (first time it is
encountered in your program) and called automagically.

Vectors are processed in parallel across all devices they were allocated on:
\code
Y = Const(42);
Z = sqrt(Const(2) * X) + cos(Y);
\endcode

You can copy the result back to host or you can use vector::operator[] to
read (or write) vector elements diectly. Though latter technique is very
ineffective and should be used for debugging purposes only.
\code
copy(Z, x);
assert(x[42] == Z[42]);
\endcode

Another frequently performed operation is reduction of a vector expresion to
single value, such as summation. This can be done with clu::Reductor class:
\code
Reductor<double> sum(queue);

std::cout << sum(Z) << std::endl;
std::cout << sum(sqrt(Const(2) * X) + cos(Y)) << std::endl;
\endcode

\section spmv Sparse matrix-vector multiplication

One of the most common operations in linear algebra is matrix-vector
multiplication. Class clu::SpMat holds representation of a sparse matrix,
spanning several GPUs. In the example below it is used for solution of a system
of linear equations with conjugate gradients method:
\code
typedef double real;
// Solve system of linear equations A u = f with conjugate gradients method.
// Input matrix is represented in CSR format (parameters row, col, and val).
void cg_gpu(
	const std::vector<uint> &row,	// Indices to col and val vectors.
	const std::vector<uint> &col,	// Column numbers of non-zero elements.
	const std::vector<real> &val,	// Values of non-zero elements.
	const std::vector<real> &rhs,	// Right-hand side.
	std::vector<real> &x		// In: initial approximation; out: result.
	)
{
    // Init OpenCL
    cl::Context context;
    std::vector<cl::CommandQueue> queue;

    std::tie(context, queue) = queue_list(Filter::Type(CL_DEVICE_TYPE_GPU));

    // Move data to GPU(s)
    uint n = x.size();
    clu::SpMat<real>  A(queue, n, row.data(), col.data(), val.data());
    clu::vector<real> f(queue, CL_MEM_READ_ONLY,  rhs);
    clu::vector<real> u(queue, CL_MEM_READ_WRITE, x);
    clu::vector<real> r(queue, CL_MEM_READ_WRITE, n);
    clu::vector<real> p(queue, CL_MEM_READ_WRITE, n);
    clu::vector<real> q(queue, CL_MEM_READ_WRITE, n);

    Reductor<real,MAX> max(queue);

    // Solve equation Au = f with conjugate gradients method.
    real rho1, rho2;
    q = A * u;
    r = f - q;

    for(uint iter = 0; max(Abs(r)) > 1e-8 && iter < n; iter++) {
	rho1 = inner_product(r, r);

	if (iter == 0) {
	    p = r;
	} else {
	    real beta = rho1 / rho2;
	    p = r + Const(beta) * p;
	}

	q = A * p;

	real alpha = rho1 / inner_product(p, q);

	u = u + Const(alpha) * p;
	r = r - Const(alpha) * q;

	rho2 = rho1;
    }

    // Get result to host.
    copy(u, x);
}
\endcode

\section custkern Using custom kernels

Custom kernels are of course possible as well. vector::operator(uint)
returns cl::Buffer object for a specified device:
\code
cl::Context context;
std::vector<cl::CommandQueue> queue;
std::tie(context, queue) = queue_list(Filter::Type(CL_DEVICE_TYPE_GPU));

const uint n = 1 << 20;
clu::vector<float> x(queue, CL_MEM_WRITE_ONLY, n);

auto program = build_sources(context, std::string(
    "kernel void dummy(uint size, global float *x)\n"
    "{\n"
    "    uint i = get_global_id(0);\n"
    "    if (i < size) x[i] = 4.2;\n"
    "}\n"
    ));

for(uint d = 0; d < queue.size(); d++) {
    auto dummy = cl::Kernel(program, "dummy").bind(queue[d], alignup(n, 256), 256);
    dummy((uint)x.part_size(d), x(d));
}

std::cout << sum(x) << std::endl;
\endcode
*/

#include <CL/cl.hpp>
#include <iostream>

#include <oclutil/util.hpp>
#include <oclutil/devlist.hpp>
#include <oclutil/vector.hpp>
#include <oclutil/spmat.hpp>
#include <oclutil/reduce.hpp>

#endif
<commit_msg>Documentation update<commit_after>#ifndef OCLUTIL_OCLUTIL_HPP
#define OCLUTIL_OCLUTIL_HPP

/**
 * \file   oclutil.hpp
 * \author Denis Demidov <ddemidov@ksu.ru>
 * \brief  OpenCL convenience utilities.
 */

/**
\mainpage oclutil

oclutil is header-only template library created for ease of C++ based OpenCL
development. Vector arithmetic and multidevice computation is supported.

\section devlist Selection of compute devices

You can select any number of available compute devices, which satisfy provided
filters. Filter is a functor returning bool and acting on a cl::Device
parameter. Several standard filters are provided, such as device type or name
filter, double precision support etc. Filters can be combined with logical
operators. In the example below all devices with names matching "Radeon" and
supporting double precision are selected:
\code
#include <iostream>
#include <oclutil/oclutil.hpp>
using namespace clu;
int main() {
    auto device = device_list(
        Filter::Name("Radeon") && Filter::DoublePrecision()
        );
    std::cout << device.size() << " GPUs found:" << std::endl;
    for(auto &d : device)
        std::cout << "\t" << d.getInfo<CL_DEVICE_NAME>() << std::endl;
}
\endcode

Often you want not just device list, but initialized OpenCL context with
command queue on each available device. This may be achieved with queue_list()
function:
\code
cl::Context context;
std::vector<cl::CommandQueue> queue;
// Select no more than 2 NVIDIA GPUs:
std::tie(context, queue) = queue_list(
    [](const cl::Device &d) {
        return d.getInfo<CL_DEVICE_VENDOR>() == "NVIDIA Corporation";
    } && Filter::Count(2)
    );
\endcode

\section vector Memory allocation and vector arithmetic

Once you got queue list, you can allocate OpenCL buffers on the associated
devices. clu::vector constructor accepts std::vector of cl::CommandQueue.
The contents of the created vector will be equally partitioned between each
queue (presumably, each of the provided queues is linked with separate device).
\code
const uint n = 1 << 20;
std::vector<double> x(n);
std::generate(x.begin(), x.end(), [](){ return (double)rand() / RAND_MAX; });

cl::Context context;
std::vector<cl::CommandQueue> queue;
std::tie(context, queue) = queue_list(Filter::Type(CL_DEVICE_TYPE_GPU));

clu::vector<double> X(queue, CL_MEM_READ_ONLY,  x);
clu::vector<double> Y(queue, CL_MEM_READ_WRITE, n);
clu::vector<double> Z(queue, CL_MEM_READ_WRITE, n);
\endcode

You can now use simple vector arithmetic with device vector. For every
expression you use, appropriate kernel is compiled (first time it is
encountered in your program) and called automagically.

Vectors are processed in parallel across all devices they were allocated on:
\code
Y = Const(42);
Z = sqrt(Const(2) * X) + cos(Y);
\endcode

You can copy the result back to host or you can use vector::operator[] to
read (or write) vector elements diectly. Though latter technique is very
ineffective and should be used for debugging purposes only.
\code
copy(Z, x);
assert(x[42] == Z[42]);
\endcode

Another frequently performed operation is reduction of a vector expresion to
single value, such as summation. This can be done with clu::Reductor class:
\code
Reductor<double> sum(queue);

std::cout << sum(Z) << std::endl;
std::cout << sum(sqrt(Const(2) * X) + cos(Y)) << std::endl;
\endcode

\section spmv Sparse matrix-vector multiplication

One of the most common operations in linear algebra is matrix-vector
multiplication. Class clu::SpMat holds representation of a sparse matrix,
spanning several GPUs. In the example below it is used for solution of a system
of linear equations with conjugate gradients method:
\code
typedef double real;
// Solve system of linear equations A u = f with conjugate gradients method.
// Input matrix is represented in CSR format (parameters row, col, and val).
void cg_gpu(
	const std::vector<uint> &row,	// Indices to col and val vectors.
	const std::vector<uint> &col,	// Column numbers of non-zero elements.
	const std::vector<real> &val,	// Values of non-zero elements.
	const std::vector<real> &rhs,	// Right-hand side.
	std::vector<real> &x		// In: initial approximation; out: result.
	)
{
    // Init OpenCL
    cl::Context context;
    std::vector<cl::CommandQueue> queue;

    std::tie(context, queue) = queue_list(Filter::Type(CL_DEVICE_TYPE_GPU));

    // Move data to GPU(s)
    uint n = x.size();
    clu::SpMat<real>  A(queue, n, row.data(), col.data(), val.data());
    clu::vector<real> f(queue, CL_MEM_READ_ONLY,  rhs);
    clu::vector<real> u(queue, CL_MEM_READ_WRITE, x);
    clu::vector<real> r(queue, CL_MEM_READ_WRITE, n);
    clu::vector<real> p(queue, CL_MEM_READ_WRITE, n);
    clu::vector<real> q(queue, CL_MEM_READ_WRITE, n);

    Reductor<real,MAX> max(queue);

    // Solve equation Au = f with conjugate gradients method.
    real rho1, rho2;
    q = A * u;
    r = f - q;

    for(uint iter = 0; max(Abs(r)) > 1e-8 && iter < n; iter++) {
	rho1 = inner_product(r, r);

	if (iter == 0) {
	    p = r;
	} else {
	    real beta = rho1 / rho2;
	    p = r + Const(beta) * p;
	}

	q = A * p;

	real alpha = rho1 / inner_product(p, q);

	u = u + Const(alpha) * p;
	r = r - Const(alpha) * q;

	rho2 = rho1;
    }

    // Get result to host.
    copy(u, x);
}
\endcode

\section custkern Using custom kernels

Custom kernels are of course possible as well. vector::operator(uint)
returns cl::Buffer object for a specified device:
\code
cl::Context context;
std::vector<cl::CommandQueue> queue;
std::tie(context, queue) = queue_list(Filter::Type(CL_DEVICE_TYPE_GPU));

const uint n = 1 << 20;
clu::vector<float> x(queue, CL_MEM_WRITE_ONLY, n);

auto program = build_sources(context, std::string(
    "kernel void dummy(uint size, global float *x)\n"
    "{\n"
    "    uint i = get_global_id(0);\n"
    "    if (i < size) x[i] = 4.2;\n"
    "}\n"
    ));

for(uint d = 0; d < queue.size(); d++) {
    auto dummy = cl::Kernel(program, "dummy").bind(queue[d], alignup(n, 256), 256);
    dummy((uint)x.part_size(d), x(d));
}

std::cout << sum(x) << std::endl;
\endcode
*/

#include <CL/cl.hpp>
#include <iostream>

#include <oclutil/util.hpp>
#include <oclutil/devlist.hpp>
#include <oclutil/vector.hpp>
#include <oclutil/spmat.hpp>
#include <oclutil/reduce.hpp>

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2011 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/browser/sync/notifier/non_blocking_invalidation_notifier.h"

#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "chrome/browser/sync/notifier/mock_sync_notifier_observer.h"
#include "chrome/browser/sync/syncable/model_type.h"
#include "chrome/browser/sync/syncable/model_type_payload_map.h"
#include "chrome/test/base/test_url_request_context_getter.h"
#include "content/browser/browser_thread.h"
#include "jingle/notifier/base/fake_base_task.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace sync_notifier {

namespace {

using ::testing::InSequence;
using ::testing::StrictMock;

class NonBlockingInvalidationNotifierTest : public testing::Test {
 public:
  NonBlockingInvalidationNotifierTest()
      : io_thread_(BrowserThread::IO) {}

 protected:
  virtual void SetUp() {
    base::Thread::Options options;
    options.message_loop_type = MessageLoop::TYPE_IO;
    io_thread_.StartWithOptions(options);
    request_context_getter_ = new TestURLRequestContextGetter;
    notifier::NotifierOptions notifier_options;
    notifier_options.request_context_getter = request_context_getter_;
    invalidation_notifier_.reset(
        new NonBlockingInvalidationNotifier(notifier_options,
                                            "fake_client_info"));
    invalidation_notifier_->AddObserver(&mock_observer_);
  }

  virtual void TearDown() {
    invalidation_notifier_->RemoveObserver(&mock_observer_);
    invalidation_notifier_.reset();
    request_context_getter_ = NULL;
    io_thread_.Stop();
    ui_loop_.RunAllPending();
  }

  MessageLoop ui_loop_;
  BrowserThread io_thread_;
  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
  scoped_ptr<NonBlockingInvalidationNotifier> invalidation_notifier_;
  StrictMock<MockSyncNotifierObserver> mock_observer_;
  notifier::FakeBaseTask fake_base_task_;
};

TEST_F(NonBlockingInvalidationNotifierTest, Basic) {
  syncable::ModelTypeSet types;
  types.insert(syncable::BOOKMARKS);
  types.insert(syncable::AUTOFILL);

  invalidation_notifier_->SetState("fake_state");
  invalidation_notifier_->UpdateCredentials("foo@bar.com", "fake_token");
  invalidation_notifier_->UpdateEnabledTypes(types);
}

// TODO(akalin): Add synchronous operations for testing to
// NonBlockingInvalidationNotifierTest and use that to test it.

}  // namespace

}  // namespace sync_notifier
<commit_msg>[Sync] Add extra checks to catch leak described in http://crbug.com/96904<commit_after>// Copyright (c) 2011 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/browser/sync/notifier/non_blocking_invalidation_notifier.h"

#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "chrome/browser/sync/notifier/mock_sync_notifier_observer.h"
#include "chrome/browser/sync/syncable/model_type.h"
#include "chrome/browser/sync/syncable/model_type_payload_map.h"
#include "chrome/test/base/test_url_request_context_getter.h"
#include "content/browser/browser_thread.h"
#include "jingle/notifier/base/fake_base_task.h"
#include "net/url_request/url_request_context.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace sync_notifier {

namespace {

using ::testing::InSequence;
using ::testing::StrictMock;

class NonBlockingInvalidationNotifierTest : public testing::Test {
 public:
  NonBlockingInvalidationNotifierTest()
      : io_thread_(BrowserThread::IO) {}

 protected:
  virtual void SetUp() {
    base::Thread::Options options;
    options.message_loop_type = MessageLoop::TYPE_IO;
    io_thread_.StartWithOptions(options);
    request_context_getter_ = new TestURLRequestContextGetter;
    notifier::NotifierOptions notifier_options;
    notifier_options.request_context_getter = request_context_getter_;
    invalidation_notifier_.reset(
        new NonBlockingInvalidationNotifier(notifier_options,
                                            "fake_client_info"));
    invalidation_notifier_->AddObserver(&mock_observer_);
  }

  virtual void TearDown() {
    scoped_refptr<net::URLRequestContextGetter> request_context_getter =
        request_context_getter_;
    invalidation_notifier_->RemoveObserver(&mock_observer_);
    invalidation_notifier_.reset();
    request_context_getter_ = NULL;
    io_thread_.Stop();
    ui_loop_.RunAllPending();
    // Extra checks to catch the leak described in
    // http://crbug.com/96904.
    EXPECT_TRUE(request_context_getter->HasOneRef());
    // |request_context_getter| should be the only thing that has a
    // ref to the request context (note that GetURLRequestContext()
    // returns a raw pointer).
    EXPECT_TRUE(request_context_getter->GetURLRequestContext()->HasOneRef());
  }

  MessageLoop ui_loop_;
  BrowserThread io_thread_;
  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
  scoped_ptr<NonBlockingInvalidationNotifier> invalidation_notifier_;
  StrictMock<MockSyncNotifierObserver> mock_observer_;
  notifier::FakeBaseTask fake_base_task_;
};

TEST_F(NonBlockingInvalidationNotifierTest, Basic) {
  syncable::ModelTypeSet types;
  types.insert(syncable::BOOKMARKS);
  types.insert(syncable::AUTOFILL);

  invalidation_notifier_->SetState("fake_state");
  invalidation_notifier_->UpdateCredentials("foo@bar.com", "fake_token");
  invalidation_notifier_->UpdateEnabledTypes(types);
}

// TODO(akalin): Add synchronous operations for testing to
// NonBlockingInvalidationNotifierTest and use that to test it.

}  // namespace

}  // namespace sync_notifier
<|endoftext|>


<commit_before>// Copyright (C) 2017 Elviss Strazdins
// This file is part of the Ouzel engine.

#pragma once

#include <string>
#include "math/Matrix3.hpp"
#include "math/Matrix4.hpp"
#include "math/Quaternion.hpp"
#include "math/Size2.hpp"
#include "math/Size3.hpp"
#include "math/Vector2.hpp"
#include "math/Vector3.hpp"
#include "math/Vector4.hpp"

namespace ouzel
{
    class Log
    {
    public:
        enum class Level
        {
            OFF,
            ERR,
            WARN,
            INFO,
            ALL
        };

        static Level threshold;

        Log()
        {
        }

        Log(Level aLevel): level(aLevel)
        {
        }

        Log(const Log& other)
        {
            level = other.level;
            s = other.s;
        }

        Log(Log&& other)
        {
            level = other.level;
            other.level = Level::INFO;
            s = std::move(other.s);
        }

        Log& operator=(const Log& other)
        {
            level = other.level;
            s = other.s;

            return *this;
        }

        Log& operator=(Log&& other)
        {
            level = other.level;
            other.level = Level::INFO;
            s = std::move(other.s);

            return *this;
        }

        ~Log();

        template<typename T> Log& operator<<(T val)
        {
            if (level <= threshold)
            {
                s += std::to_string(val);
            }

            return *this;
        }

        Log& operator<<(const std::string& val)
        {
            if (level <= threshold)
            {
                s += val;
            }

            return *this;
        }

        Log& operator<<(const char* val)
        {
            if (level <= threshold)
            {
                s += val;
            }

            return *this;
        }

        Log& operator<<(char* val)
        {
            if (level <= threshold)
            {
                s += val;
            }

            return *this;
        }

        Log& operator<<(const Matrix3& val)
        {
            s += std::to_string(val.m[0]) + "," + std::to_string(val.m[1]) + "," + std::to_string(val.m[2]) + "\n" +
                std::to_string(val.m[3]) + "," + std::to_string(val.m[4]) + "," + std::to_string(val.m[5]) + "\n" +
                std::to_string(val.m[6]) + "," + std::to_string(val.m[7]) + "," + std::to_string(val.m[8]);

            return *this;
        }

        Log& operator<<(const Matrix4& val)
        {
            s += std::to_string(val.m[0]) + "," + std::to_string(val.m[1]) + "," + std::to_string(val.m[2]) + "," + std::to_string(val.m[3]) + "\n" +
                std::to_string(val.m[4]) + "," + std::to_string(val.m[5]) + "," + std::to_string(val.m[6]) + "," + std::to_string(val.m[7]) + "\n" +
                std::to_string(val.m[8]) + "," + std::to_string(val.m[9]) + "," + std::to_string(val.m[10]) + "," + std::to_string(val.m[11]) + "\n" +
                std::to_string(val.m[12]) + "," + std::to_string(val.m[13]) + "," + std::to_string(val.m[14]) + "," + std::to_string(val.m[15]);

            return *this;
        }

        Log& operator<<(const Quaternion& val)
        {
            if (level <= threshold)
            {
                s += std::to_string(val.x) + "," + std::to_string(val.y) + "," +
                    std::to_string(val.z) + "," + std::to_string(val.w);
            }

            return *this;
        }

        Log& operator<<(const Size2& val)
        {
            if (level <= threshold)
            {
                s += std::to_string(val.width) + "," + std::to_string(val.height);
            }

            return *this;
        }

        Log& operator<<(const Size3& val)
        {
            if (level <= threshold)
            {
                s += std::to_string(val.width) + "," + std::to_string(val.height) + "," +
                    std::to_string(val.depth);
            }

            return *this;
        }

        Log& operator<<(const Vector2& val)
        {
            if (level <= threshold)
            {
                s += std::to_string(val.x) + "," + std::to_string(val.y);
            }

            return *this;
        }

        Log& operator<<(const Vector3& val)
        {
            if (level <= threshold)
            {
                s += std::to_string(val.x) + "," + std::to_string(val.y) + "," +
                    std::to_string(val.z);
            }

            return *this;
        }

        Log& operator<<(const Vector4& val)
        {
            if (level <= threshold)
            {
                s += std::to_string(val.x) + "," + std::to_string(val.y) + "," +
                    std::to_string(val.z) + "," + std::to_string(val.w);
            }

            return *this;
        }

    private:
        Level level = Level::INFO;
        std::string s;
    };
}
<commit_msg>Remove the unneeded constructor from the Log class<commit_after>// Copyright (C) 2017 Elviss Strazdins
// This file is part of the Ouzel engine.

#pragma once

#include <string>
#include "math/Matrix3.hpp"
#include "math/Matrix4.hpp"
#include "math/Quaternion.hpp"
#include "math/Size2.hpp"
#include "math/Size3.hpp"
#include "math/Vector2.hpp"
#include "math/Vector3.hpp"
#include "math/Vector4.hpp"

namespace ouzel
{
    class Log
    {
    public:
        enum class Level
        {
            OFF,
            ERR,
            WARN,
            INFO,
            ALL
        };

        static Level threshold;

        Log(Level aLevel = Level::INFO): level(aLevel)
        {
        }

        Log(const Log& other)
        {
            level = other.level;
            s = other.s;
        }

        Log(Log&& other)
        {
            level = other.level;
            other.level = Level::INFO;
            s = std::move(other.s);
        }

        Log& operator=(const Log& other)
        {
            level = other.level;
            s = other.s;

            return *this;
        }

        Log& operator=(Log&& other)
        {
            level = other.level;
            other.level = Level::INFO;
            s = std::move(other.s);

            return *this;
        }

        ~Log();

        template<typename T> Log& operator<<(T val)
        {
            if (level <= threshold)
            {
                s += std::to_string(val);
            }

            return *this;
        }

        Log& operator<<(const std::string& val)
        {
            if (level <= threshold)
            {
                s += val;
            }

            return *this;
        }

        Log& operator<<(const char* val)
        {
            if (level <= threshold)
            {
                s += val;
            }

            return *this;
        }

        Log& operator<<(char* val)
        {
            if (level <= threshold)
            {
                s += val;
            }

            return *this;
        }

        Log& operator<<(const Matrix3& val)
        {
            s += std::to_string(val.m[0]) + "," + std::to_string(val.m[1]) + "," + std::to_string(val.m[2]) + "\n" +
                std::to_string(val.m[3]) + "," + std::to_string(val.m[4]) + "," + std::to_string(val.m[5]) + "\n" +
                std::to_string(val.m[6]) + "," + std::to_string(val.m[7]) + "," + std::to_string(val.m[8]);

            return *this;
        }

        Log& operator<<(const Matrix4& val)
        {
            s += std::to_string(val.m[0]) + "," + std::to_string(val.m[1]) + "," + std::to_string(val.m[2]) + "," + std::to_string(val.m[3]) + "\n" +
                std::to_string(val.m[4]) + "," + std::to_string(val.m[5]) + "," + std::to_string(val.m[6]) + "," + std::to_string(val.m[7]) + "\n" +
                std::to_string(val.m[8]) + "," + std::to_string(val.m[9]) + "," + std::to_string(val.m[10]) + "," + std::to_string(val.m[11]) + "\n" +
                std::to_string(val.m[12]) + "," + std::to_string(val.m[13]) + "," + std::to_string(val.m[14]) + "," + std::to_string(val.m[15]);

            return *this;
        }

        Log& operator<<(const Quaternion& val)
        {
            if (level <= threshold)
            {
                s += std::to_string(val.x) + "," + std::to_string(val.y) + "," +
                    std::to_string(val.z) + "," + std::to_string(val.w);
            }

            return *this;
        }

        Log& operator<<(const Size2& val)
        {
            if (level <= threshold)
            {
                s += std::to_string(val.width) + "," + std::to_string(val.height);
            }

            return *this;
        }

        Log& operator<<(const Size3& val)
        {
            if (level <= threshold)
            {
                s += std::to_string(val.width) + "," + std::to_string(val.height) + "," +
                    std::to_string(val.depth);
            }

            return *this;
        }

        Log& operator<<(const Vector2& val)
        {
            if (level <= threshold)
            {
                s += std::to_string(val.x) + "," + std::to_string(val.y);
            }

            return *this;
        }

        Log& operator<<(const Vector3& val)
        {
            if (level <= threshold)
            {
                s += std::to_string(val.x) + "," + std::to_string(val.y) + "," +
                    std::to_string(val.z);
            }

            return *this;
        }

        Log& operator<<(const Vector4& val)
        {
            if (level <= threshold)
            {
                s += std::to_string(val.x) + "," + std::to_string(val.y) + "," +
                    std::to_string(val.z) + "," + std::to_string(val.w);
            }

            return *this;
        }

    private:
        Level level = Level::INFO;
        std::string s;
    };
}
<|endoftext|>


<commit_before>// Copyright (C) 2017 Elviss Strazdins
// This file is part of the Ouzel engine.

#pragma once

#include <map>
#include <string>
#include <vector>

namespace ouzel
{
    namespace xml
    {
        class Node
        {
        public:
            enum class Type
            {
                NONE,
                COMMENT,
                CDATA,
                TYPE_DECLARATION,
                PROCESSING_INSTRUCTION,
                TAG,
                TEXT
            };

            Node() {}
            Node(Type initType): type(initType) {}

            Node& operator=(Type newType)
            {
                type = newType;
                return *this;
            }

            Type getType() const { return type; }

            const std::string& getValue() const { return value; }

            const std::vector<Node>& getChildren() const { return children; }

            bool parse(const std::vector<uint32_t>& str,
                       std::vector<uint32_t>::iterator& iterator,
                       bool preserveComments = false, bool preserveProcessingInstructions = false);
            bool encode(std::vector<uint8_t>& data) const;

        protected:
            Type type = Type::NONE;

            std::string value;
            std::map<std::string, std::string> attributes;
            std::vector<Node> children;
        };

        class Data
        {
        public:
            Data();
            Data(const std::string& filename, bool preserveComments = false, bool preserveProcessingInstructions = false);
            Data(const std::vector<uint8_t>& data, bool preserveComments = false, bool preserveProcessingInstructions = false);

            bool init(const std::string& filename, bool preserveComments = false, bool preserveProcessingInstructions = false);
            bool init(const std::vector<uint8_t>& data, bool preserveComments = false, bool preserveProcessingInstructions = false);

            bool save(const std::string& filename) const;
            bool encode(std::vector<uint8_t>& data) const;

            bool hasBOM() const { return bom; }
            void setBOM(bool newBOM) { bom = newBOM; }

            const std::vector<Node>& getChildren() const { return children; }

        protected:
            bool bom = false;
            std::vector<Node> children;
        };
    } // namespace xml
}
<commit_msg>Add value setter for XML node<commit_after>// Copyright (C) 2017 Elviss Strazdins
// This file is part of the Ouzel engine.

#pragma once

#include <map>
#include <string>
#include <vector>

namespace ouzel
{
    namespace xml
    {
        class Node
        {
        public:
            enum class Type
            {
                NONE,
                COMMENT,
                CDATA,
                TYPE_DECLARATION,
                PROCESSING_INSTRUCTION,
                TAG,
                TEXT
            };

            Node() {}
            Node(Type initType): type(initType) {}

            Node& operator=(Type newType)
            {
                type = newType;
                return *this;
            }

            Type getType() const { return type; }

            const std::string& getValue() const { return value; }
            void getValue(const std::string& newValue) { value = newValue; }

            const std::vector<Node>& getChildren() const { return children; }

            bool parse(const std::vector<uint32_t>& str,
                       std::vector<uint32_t>::iterator& iterator,
                       bool preserveComments = false, bool preserveProcessingInstructions = false);
            bool encode(std::vector<uint8_t>& data) const;

        protected:
            Type type = Type::NONE;

            std::string value;
            std::map<std::string, std::string> attributes;
            std::vector<Node> children;
        };

        class Data
        {
        public:
            Data();
            Data(const std::string& filename, bool preserveComments = false, bool preserveProcessingInstructions = false);
            Data(const std::vector<uint8_t>& data, bool preserveComments = false, bool preserveProcessingInstructions = false);

            bool init(const std::string& filename, bool preserveComments = false, bool preserveProcessingInstructions = false);
            bool init(const std::vector<uint8_t>& data, bool preserveComments = false, bool preserveProcessingInstructions = false);

            bool save(const std::string& filename) const;
            bool encode(std::vector<uint8_t>& data) const;

            bool hasBOM() const { return bom; }
            void setBOM(bool newBOM) { bom = newBOM; }

            const std::vector<Node>& getChildren() const { return children; }

        protected:
            bool bom = false;
            std::vector<Node> children;
        };
    } // namespace xml
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) Sjors Gielen, 2010
 * See LICENSE for license.
 */

#include <QtCore/QDebug>
#include <ircclient-qt/IrcBuffer>

#include "testplugin.h"

TestPlugin::TestPlugin()
: Plugin()
{}

TestPlugin::~TestPlugin() {}

void TestPlugin::init()
{
  qDebug() << "TestPlugin initialising.";
}

void TestPlugin::connected( Network &net, const Server &serv )
{
  qDebug() << "Connected to network" << net;
  if( &serv != net.activeServer() )
  {
    qWarning() << "Warning! Connected to different server" << serv;
  }
}

void TestPlugin::welcomed( Network &net )
{
  qDebug() << "Authenticated to network " << net;
  net.joinChannel( "#dazjorz" );
}

void TestPlugin::joined( Network &net, const QString &who, Irc::Buffer *channel )
{
  User u( who, &net );
  qDebug() << "User " << u << " joined channel " << channel;
  if( u.isMe() )
  {
    channel->message( "Hi all!" );
  }
  else
  {
    channel->message( "Hi " + u.nick() + "!" );
  }
}

void TestPlugin::parted( Network &net, const QString &who, const QString &leaveMessage,
                              Irc::Buffer *channel )
{
  qDebug() << "User " << who << " left channel " << channel << "on" << net
           << " (leave message " << leaveMessage << ")";
}

QHash<QString, Plugin::VariableScope> TestPlugin::variables()
{
  QHash<QString, Plugin::VariableScope> variables;
  return variables;
}
<commit_msg>No longer greet on join.<commit_after>/**
 * Copyright (c) Sjors Gielen, 2010
 * See LICENSE for license.
 */

#include <QtCore/QDebug>
#include <ircclient-qt/IrcBuffer>

#include "testplugin.h"

TestPlugin::TestPlugin()
: Plugin()
{}

TestPlugin::~TestPlugin() {}

void TestPlugin::init()
{
  qDebug() << "TestPlugin initialising.";
}

void TestPlugin::connected( Network &net, const Server &serv )
{
  qDebug() << "Connected to network" << net;
  if( &serv != net.activeServer() )
  {
    qWarning() << "Warning! Connected to different server" << serv;
  }
}

void TestPlugin::welcomed( Network &net )
{
  qDebug() << "Authenticated to network " << net;
  net.joinChannel( "#dazjorz" );
}

void TestPlugin::joined( Network &net, const QString &who, Irc::Buffer *channel )
{
  User u( who, &net );
  qDebug() << "User " << u << " joined channel " << channel;
  /* if( u.isMe() )
  {
    channel->message( "Hi all!" );
  }
  else
  {
    channel->message( "Hi " + u.nick() + "!" );
  } */
}

void TestPlugin::parted( Network &net, const QString &who, const QString &leaveMessage,
                              Irc::Buffer *channel )
{
  qDebug() << "User " << who << " left channel " << channel << "on" << net
           << " (leave message " << leaveMessage << ")";
}

QHash<QString, Plugin::VariableScope> TestPlugin::variables()
{
  QHash<QString, Plugin::VariableScope> variables;
  return variables;
}
<|endoftext|>


<commit_before>#ifndef BOP_MATRIX_HPP
#define BOP_MATRIX_HPP

#include <memory>
#include <initializer_list>
#include <string>
#include <sstream>
#include <new>
#include "Vector.hpp"

/*
	bop::maths::Matrix class file
*/

namespace bop {
	namespace maths{
		template<class T>
		class Matrix {
			protected:
				unsigned int width;
				unsigned int height;
			public:
				Vector<T>* data;

				//Constructors
				Matrix(unsigned int size, T fill = 0) {
					/*
						Square matrix constructor, sets all values as
						the given fill value.
					*/
					this->data = new Vector<T>[size];
					for (unsigned int i = 0; i < size; i++) {
						this->data[i] = Vector<T>(size, fill);
					}
					this->width = size;
					this->height = size;
				}

				Matrix(unsigned int width, unsigned int height, T fill = 0) {
					/*
						Non-square matrix constructor, sets all values as
						the given fill value.
					*/
					this->data = new Vector<T>[height];
					for (unsigned int i = 0; i < height; i++) {
						this->data[i] = Vector<T>(width, fill);
					}
					this->height = height;
					this->width = width;
				}

				Matrix(std::initializer_list< std::initializer_list<T> > list) {
					/*
						Creates a matrix from a 2-dimensional initializer_list.
					*/
					this->height = list.size();
					this->data = new Vector<T>[this->height];
					unsigned int min_w = list.begin()->size();
					unsigned int i = 0;
					for (auto elem : list) {
						if (elem.size() < min_w) min_w = elem.size();
						this->data[i] = Vector<T>(elem);
						i++;
					}
					this->width = min_w;
				}

				Matrix(Matrix<T>& mat) {
					/*
						Copy constructor.
					*/
					this->width = mat.width;
					this->height = mat.height;
					this->data = new Vector<T>[this->height];
					for (unsigned int i = 0; i < this->width; i++) {
						this->data[i] = mat.data[i];
					}
				}

				Matrix(Matrix<T>&& mat) {
					/*
						Move constructor.
					*/
					this->width = mat.width;
					this->height = mat.height;
					this->data = mat.data;
				}

				Matrix() {
					/*
						Empty constructor.
					*/
				}

				//Destructor
				~Matrix() {
					delete[] this->data;
				}

				//Operator overloads
				inline Vector<T>& operator[] (const unsigned int index) {
					return this->data[index];
				}

				Matrix<T>& operator= (const Matrix<T> &mat) {
					this->width = mat.width;
					this->height = mat.height;
					delete[] this->data;
					this->data = new Vector<T>[this->height];
					for (unsigned int i = 0; i < this->height; i++) {
						this->data[i] = mat.data[i];
					}
				}

				//Boolean logic overloads
				bool operator== (const Matrix<T>& mat) {
					if (this->width == mat.width && this->height == mat.height) {
						bool same = true;
						for (unsigned int i = 0; i < this->height && same; i++) {
							same = (this->data[i] == mat.data[i]);
						}
						return same;
					}
					else return false;
				}

				bool operator!= (const Matrix<T>& mat) {
					return !(this->operator==(mat));
				}

				//Arithmetic overloads
				Matrix<T>& operator*= (const T scalar) {
					/*
						Scalar multiplication member operator, multiplies all
						elements by the given scalar.
					*/
					for (unsigned int i = 0; i < this->height; i++) {
						this->data[i] *= scalar;
					}
					return *this;
				}

				Matrix<T>& operator*= (Matrix<T> &mat) {
					/*
						Matrix multiplication member operator.
					*/
					Vector<T>* temp = new Vector<T>[this->height];
					for (unsigned int i = 0; i < this->height; i++) {
						temp[i] = Vector<T>(mat.width);
					}
					for (unsigned int r = 0; r < this->height; r++) {
						for (unsigned int c = 0; c < mat.width; c++) {
							T product = 0;
							for (unsigned int i = 0; i < mat.width; i++) {
								product += (this->data[r][i] * mat.data[i][c]);
							}
							temp[r][c] = product;
						}
					}
					delete[] this->data;
					this->data = temp;
					this->width = mat.width;
					return *this;
				}

				Matrix<T>& operator/= (const T scalar) {
					/*
						Scalar division member operator, divides all elements
						by the given scalar.
					*/
					for (unsigned int i = 0; i < this->height; i++) {
						this->data[i] /= scalar;
					}
					return *this;
				}

				Matrix<T>& operator+= (Matrix<T> &mat) {
					/*
						Addition member operator, adds all the elements of a
						given matrix to the matrix.
					*/
					for (unsigned int i = 0; i < this->height; i++) {
						this->data[i] += mat[i];
					}
					return *this;
				}

				Matrix<T>& operator-= (Matrix<T> &mat) {
					/*
						Subtraction member operator, subtracts the value of
						each element in a given matrix from the matrix.
					*/
					for (unsigned int i = 0; i < this->height; i++) {
						this->data[i] -= mat[i];
					}
					return *this;
				}

				//Information functions
				inline unsigned int w() {
					/*
						Returns the width of the Matrix.
					*/
					return this->width;
				}

				inline unsigned int h() {
					/*
						Returns the height of the Matrix.
					*/
					return this->height;
				}

				inline bool square() {
					/*
						Tests if the Matrix is a square Matrix.
					*/
					return (this->width == this->height);
				}

				bool identity() {
					/*
						Tests if the matrix is an identity matrix.
					*/
					if (this->width == this->height) {
						bool identity = true;
						for (unsigned int y = 0; y < this->height && identity; y++) {
							for (unsigned int x = 0; x < this->width && identity; x++) {
								if (x == y) identity = (this->data[y][x] == 1);
								else identity = (this->data[y][x] == 0);
							}
						}
						return identity;
					}
					else return false;
				}

				std::string string(bool newlines = true) {
					/*
						Similar to the maths::Vector::string function, returns
						a human-readable representation of the Matrix.
					*/
					std::ostringstream mat_str;
					for (unsigned int i = 0; i < this->height; i++) {
						mat_str << '[' << this->data[i].string(false) << ']';
						if (newlines) mat_str << '\n';
					}
					return mat_str.str();
				}

				//Matrix manipulation functions.

				inline void swapRows(unsigned int index_a, unsigned int index_b) {
					/*
						Row swap function, for use in such algorithms as Gauss-Jordan
						elimination.
					*/
					this->data[index_a].swap(this->data[index_b]);
				}

				void swap(Matrix<T>& mat) {
					/*
						Matrix object swap function.
					*/
					Vector<T>* temp_arr = mat.data;
					unsigned int temp_w = mat.width;
					unsigned int temp_h = mat.height;
					mat.data = this->data;
					mat.width = this->width;
					mat.height = this->height;
					this->data = temp_arr;
					this->width = temp_w;
					this->height = temp_h;
				}
		};

		//External arithmetic overloads

		template<class T>
		Matrix<T> operator* (Matrix<T> &mat, const T scalar) {
			Matrix<T> mat_p(mat);
			mat_p *= scalar;
			return mat_p;
		}

		template<class T>
		Matrix<T> operator* (Matrix<T> &mat1, Matrix<T>& mat2) {
			Matrix<T> mat_p(mat1);
			mat_p *= mat2;
			return mat_p;
		}

		template<class T>
		Matrix<T> operator/ (Matrix<T> &mat, const T scalar) {
			Matrix<T> mat_p(mat);
			mat_p /= scalar;
			return mat_p;
		}

		template<class T>
		Matrix<T> operator+ (Matrix<T> &mat1, Matrix<T>& mat2) {
			Matrix<T> mat_sum(mat1);
			mat_sum += mat2;
			return mat_sum;
		}

		template<class T>
		Matrix<T> operator- (Matrix<T> &mat1, Matrix<T>& mat2) {
			Matrix<T> mat_sum(mat1);
			mat_sum -= mat2;
			return mat_sum;
		}

		//Matrix related functions
		template<class T>
		T det(Matrix<T>& mat, Vector<bool>& allowed_cols, unsigned int& size) {
			/*
				Recursive matrix determinant function.
			*/
			if (size == 2) {
				//the  base case, finding the 2 by 2 matrix determinant
				int c1 = -1, c2 = -1;
				for (unsigned int i = 0; i < mat.w(); i++) {
					if (allowed_cols[i]) {
						if (c1 < 0) {
							c1 = i;
						}
						else if (c2 < 0) {
							c2 = i;
						}
						else {
							break;
						}
					}
				}
				return (mat[mat.h() - 2][c1] * mat[mat.h() - 1][c2]) - (mat[mat.h() - 2][c2] * mat[mat.h() - 1][c1]);
			}
			else {
				size--;
				T product = 0;
				T multi = 1;
				for (unsigned int i = 0; i < mat.w(); i++) {
					if (!allowed_cols[i]) continue;
					else {
						allowed_cols[i] = false;
						product += (multi * (mat[mat.h() - size][i] * det(mat, allowed_cols, size)));
						multi *= -1;
						allowed_cols[i] = true;

					}
				}
				size++;
				return product;
			}
		}

		template<class T>
		T det(Matrix<T>& mat) {
			/*
				Matrix determinant init function.
			*/
			if (!mat.square()) return static_cast<T>(0);
			else {
				if (mat.w() == 2) {

					//shortcut to determinant of a 2 by 2 matrix
					return (mat[0][0] * mat[1][1]) - (mat[0][1] * mat[1][0]);
				}
				else {
					Vector<bool> allowed_cols(mat.w(), true);
					T product = 0;
					T multi = 1;
					unsigned int size = mat.h() - 1;
					for (unsigned int i = 0; i < mat.w(); i++) {
						allowed_cols[i] = false;
						product += (multi * (mat[0][i] * det(mat, allowed_cols, size)));
						multi *= -1;
						allowed_cols[i] = true;
					}
					return product;
				}
			}
		}

		template<class T>
		Matrix<T> identityMatrix(unsigned int size) {
			/*
				Returns an Identity Matrix.
			*/
			Matrix<T> unit_m(size);
			for (unsigned int i = 0; i < size; i++) {
				unit_m[i] = 1;
			}
			return unit_m;
		}

		template<class T>
		bool invertable(Matrix<T> &mat) {
			return (mat.square() && det(mat) != 0);
		}

		template<class T>
		Matrix<T> inverseMatrix(Matrix<T>& mat, bool tested = true) {
			/*
				Matrix inverse by Gauss-Jordan method ([A|I] -> [I|A']).
				Assumes that the matrix has already been tested as invertible.
				takes a COPY of a matrix, as this method requires the
				manipulation of the rows of the matrix.
			*/
			if (!tested && invertable(mat) == 0) {
				/*
					In the case that the matrix is not invertible, the function will
					return an identity matrix with the height of the given matrix.
				*/
				return identityMatrix<T>(mat.h());
			}
			else {
				T deter = det(mat);
				if (mat.h() == 2) {
					Matrix<T> inverse(2);
					/*
						2 by 2 matrix shortcut.
					*/
					inverse[0][0] = mat[1][1];
					inverse[0][1] = -mat[0][1];
					inverse[1][0] = -mat[1][0];
					inverse[1][1] = mat[0][0];

					inverse /= deter;
					return inverse;
				}
				else {
					Matrix<T> inverse = identityMatrix<T>(mat.h());
					/*
						Sort the matrix rows by pivot index and
					*/
					return inverse;
				}
			}
		}

		template<class T>
		Matrix<T> transposeMatrix(Matrix<T> &mat) {
			/*
				Creates & returns a transposed version of the given matrix.
			*/
			Matrix<T> trans(mat.h(), mat.w(), 0);
			for (unsigned int y = 0; y < mat.h(); y++) {
				for (unsigned int x = 0; x < mat.w(); x++) {
					trans[x][y] = mat[y][x];
				}
			}
			return trans;
		}

	}
}

#endif<commit_msg>Added check to dividing a matrix by a scalar<commit_after>#ifndef BOP_MATRIX_HPP
#define BOP_MATRIX_HPP

#include <memory>
#include <initializer_list>
#include <string>
#include <sstream>
#include <new>
#include "Vector.hpp"

/*
	bop::maths::Matrix class file
*/

namespace bop {
	namespace maths{
		template<class T>
		class Matrix {
			protected:
				unsigned int width;
				unsigned int height;
			public:
				Vector<T>* data;

				//Constructors
				Matrix(unsigned int size, T fill = 0) {
					/*
						Square matrix constructor, sets all values as
						the given fill value.
					*/
					this->data = new Vector<T>[size];
					for (unsigned int i = 0; i < size; i++) {
						this->data[i] = Vector<T>(size, fill);
					}
					this->width = size;
					this->height = size;
				}

				Matrix(unsigned int width, unsigned int height, T fill = 0) {
					/*
						Non-square matrix constructor, sets all values as
						the given fill value.
					*/
					this->data = new Vector<T>[height];
					for (unsigned int i = 0; i < height; i++) {
						this->data[i] = Vector<T>(width, fill);
					}
					this->height = height;
					this->width = width;
				}

				Matrix(std::initializer_list< std::initializer_list<T> > list) {
					/*
						Creates a matrix from a 2-dimensional initializer_list.
					*/
					this->height = list.size();
					this->data = new Vector<T>[this->height];
					unsigned int min_w = list.begin()->size();
					unsigned int i = 0;
					for (auto elem : list) {
						if (elem.size() < min_w) min_w = elem.size();
						this->data[i] = Vector<T>(elem);
						i++;
					}
					this->width = min_w;
				}

				Matrix(Matrix<T>& mat) {
					/*
						Copy constructor.
					*/
					this->width = mat.width;
					this->height = mat.height;
					this->data = new Vector<T>[this->height];
					for (unsigned int i = 0; i < this->width; i++) {
						this->data[i] = mat.data[i];
					}
				}

				Matrix(Matrix<T>&& mat) {
					/*
						Move constructor.
					*/
					this->width = mat.width;
					this->height = mat.height;
					this->data = mat.data;
				}

				Matrix() {
					/*
						Empty constructor.
					*/
				}

				//Destructor
				~Matrix() {
					delete[] this->data;
				}

				//Operator overloads
				inline Vector<T>& operator[] (const unsigned int index) {
					return this->data[index];
				}

				Matrix<T>& operator= (const Matrix<T> &mat) {
					this->width = mat.width;
					this->height = mat.height;
					delete[] this->data;
					this->data = new Vector<T>[this->height];
					for (unsigned int i = 0; i < this->height; i++) {
						this->data[i] = mat.data[i];
					}
				}

				//Boolean logic overloads
				bool operator== (const Matrix<T>& mat) {
					if (this->width == mat.width && this->height == mat.height) {
						bool same = true;
						for (unsigned int i = 0; i < this->height && same; i++) {
							same = (this->data[i] == mat.data[i]);
						}
						return same;
					}
					else return false;
				}

				bool operator!= (const Matrix<T>& mat) {
					return !(this->operator==(mat));
				}

				//Arithmetic overloads
				Matrix<T>& operator*= (const T scalar) {
					/*
						Scalar multiplication member operator, multiplies all
						elements by the given scalar.
					*/
					for (unsigned int i = 0; i < this->height; i++) {
						this->data[i] *= scalar;
					}
					return *this;
				}

				Matrix<T>& operator*= (Matrix<T> &mat) {
					/*
						Matrix multiplication member operator.
					*/
					Vector<T>* temp = new Vector<T>[this->height];
					for (unsigned int i = 0; i < this->height; i++) {
						temp[i] = Vector<T>(mat.width);
					}
					for (unsigned int r = 0; r < this->height; r++) {
						for (unsigned int c = 0; c < mat.width; c++) {
							T product = 0;
							for (unsigned int i = 0; i < mat.width; i++) {
								product += (this->data[r][i] * mat.data[i][c]);
							}
							temp[r][c] = product;
						}
					}
					delete[] this->data;
					this->data = temp;
					this->width = mat.width;
					return *this;
				}

				Matrix<T>& operator/= (const T scalar) {
					/*
						Scalar division member operator, divides all elements
						by the given scalar.
					*/
					if (scalar != 0) {
						for (unsigned int i = 0; i < this->height; i++) {
							this->data[i] /= scalar;
						}
					}
					return *this;
				}

				Matrix<T>& operator+= (Matrix<T> &mat) {
					/*
						Addition member operator, adds all the elements of a
						given matrix to the matrix.
					*/
					for (unsigned int i = 0; i < this->height; i++) {
						this->data[i] += mat[i];
					}
					return *this;
				}

				Matrix<T>& operator-= (Matrix<T> &mat) {
					/*
						Subtraction member operator, subtracts the value of
						each element in a given matrix from the matrix.
					*/
					for (unsigned int i = 0; i < this->height; i++) {
						this->data[i] -= mat[i];
					}
					return *this;
				}

				//Information functions
				inline unsigned int w() {
					/*
						Returns the width of the Matrix.
					*/
					return this->width;
				}

				inline unsigned int h() {
					/*
						Returns the height of the Matrix.
					*/
					return this->height;
				}

				inline bool square() {
					/*
						Tests if the Matrix is a square Matrix.
					*/
					return (this->width == this->height);
				}

				bool identity() {
					/*
						Tests if the matrix is an identity matrix.
					*/
					if (this->width == this->height) {
						bool identity = true;
						for (unsigned int y = 0; y < this->height && identity; y++) {
							for (unsigned int x = 0; x < this->width && identity; x++) {
								if (x == y) identity = (this->data[y][x] == 1);
								else identity = (this->data[y][x] == 0);
							}
						}
						return identity;
					}
					else return false;
				}

				std::string string(bool newlines = true) {
					/*
						Similar to the maths::Vector::string function, returns
						a human-readable representation of the Matrix.
					*/
					std::ostringstream mat_str;
					for (unsigned int i = 0; i < this->height; i++) {
						mat_str << '[' << this->data[i].string(false) << ']';
						if (newlines) mat_str << '\n';
					}
					return mat_str.str();
				}

				//Matrix manipulation functions.

				inline void swapRows(unsigned int index_a, unsigned int index_b) {
					/*
						Row swap function, for use in such algorithms as Gauss-Jordan
						elimination.
					*/
					this->data[index_a].swap(this->data[index_b]);
				}

				void swap(Matrix<T>& mat) {
					/*
						Matrix object swap function.
					*/
					Vector<T>* temp_arr = mat.data;
					unsigned int temp_w = mat.width;
					unsigned int temp_h = mat.height;
					mat.data = this->data;
					mat.width = this->width;
					mat.height = this->height;
					this->data = temp_arr;
					this->width = temp_w;
					this->height = temp_h;
				}
		};

		//External arithmetic overloads

		template<class T>
		Matrix<T> operator* (Matrix<T> &mat, const T scalar) {
			Matrix<T> mat_p(mat);
			mat_p *= scalar;
			return mat_p;
		}

		template<class T>
		Matrix<T> operator* (Matrix<T> &mat1, Matrix<T>& mat2) {
			Matrix<T> mat_p(mat1);
			mat_p *= mat2;
			return mat_p;
		}

		template<class T>
		Matrix<T> operator/ (Matrix<T> &mat, const T scalar) {
			Matrix<T> mat_p(mat);
			mat_p /= scalar;
			return mat_p;
		}

		template<class T>
		Matrix<T> operator+ (Matrix<T> &mat1, Matrix<T>& mat2) {
			Matrix<T> mat_sum(mat1);
			mat_sum += mat2;
			return mat_sum;
		}

		template<class T>
		Matrix<T> operator- (Matrix<T> &mat1, Matrix<T>& mat2) {
			Matrix<T> mat_sum(mat1);
			mat_sum -= mat2;
			return mat_sum;
		}

		//Matrix related functions
		template<class T>
		T det(Matrix<T>& mat, Vector<bool>& allowed_cols, unsigned int& size) {
			/*
				Recursive matrix determinant function.
			*/
			if (size == 2) {
				//the  base case, finding the 2 by 2 matrix determinant
				int c1 = -1, c2 = -1;
				for (unsigned int i = 0; i < mat.w(); i++) {
					if (allowed_cols[i]) {
						if (c1 < 0) {
							c1 = i;
						}
						else if (c2 < 0) {
							c2 = i;
						}
						else {
							break;
						}
					}
				}
				return (mat[mat.h() - 2][c1] * mat[mat.h() - 1][c2]) - (mat[mat.h() - 2][c2] * mat[mat.h() - 1][c1]);
			}
			else {
				size--;
				T product = 0;
				T multi = 1;
				for (unsigned int i = 0; i < mat.w(); i++) {
					if (!allowed_cols[i]) continue;
					else {
						allowed_cols[i] = false;
						product += (multi * (mat[mat.h() - size][i] * det(mat, allowed_cols, size)));
						multi *= -1;
						allowed_cols[i] = true;

					}
				}
				size++;
				return product;
			}
		}

		template<class T>
		T det(Matrix<T>& mat) {
			/*
				Matrix determinant init function.
			*/
			if (!mat.square()) return static_cast<T>(0);
			else {
				if (mat.w() == 2) {

					//shortcut to determinant of a 2 by 2 matrix
					return (mat[0][0] * mat[1][1]) - (mat[0][1] * mat[1][0]);
				}
				else {
					Vector<bool> allowed_cols(mat.w(), true);
					T product = 0;
					T multi = 1;
					unsigned int size = mat.h() - 1;
					for (unsigned int i = 0; i < mat.w(); i++) {
						allowed_cols[i] = false;
						product += (multi * (mat[0][i] * det(mat, allowed_cols, size)));
						multi *= -1;
						allowed_cols[i] = true;
					}
					return product;
				}
			}
		}

		template<class T>
		Matrix<T> identityMatrix(unsigned int size) {
			/*
				Returns an Identity Matrix.
			*/
			Matrix<T> unit_m(size);
			for (unsigned int i = 0; i < size; i++) {
				unit_m[i] = 1;
			}
			return unit_m;
		}

		template<class T>
		bool invertable(Matrix<T> &mat) {
			return (mat.square() && det(mat) != 0);
		}

		template<class T>
		Matrix<T> inverseMatrix(Matrix<T>& mat, bool tested = true) {
			/*
				Matrix inverse by Gauss-Jordan method ([A|I] -> [I|A']).
				Assumes that the matrix has already been tested as invertible.
				takes a COPY of a matrix, as this method requires the
				manipulation of the rows of the matrix.
			*/
			if (!tested && invertable(mat) == 0) {
				/*
					In the case that the matrix is not invertible, the function will
					return an identity matrix with the height of the given matrix.
				*/
				return identityMatrix<T>(mat.h());
			}
			else {
				T deter = det(mat);
				if (mat.h() == 2) {
					Matrix<T> inverse(2);
					/*
						2 by 2 matrix shortcut.
					*/
					inverse[0][0] = mat[1][1];
					inverse[0][1] = -mat[0][1];
					inverse[1][0] = -mat[1][0];
					inverse[1][1] = mat[0][0];

					inverse /= deter;
					return inverse;
				}
				else {
					Matrix<T> inverse = identityMatrix<T>(mat.h());
					/*
						Sort the matrix rows by pivot index and
					*/
					return inverse;
				}
			}
		}

		template<class T>
		Matrix<T> transposeMatrix(Matrix<T> &mat) {
			/*
				Creates & returns a transposed version of the given matrix.
			*/
			Matrix<T> trans(mat.h(), mat.w(), 0);
			for (unsigned int y = 0; y < mat.h(); y++) {
				for (unsigned int x = 0; x < mat.w(); x++) {
					trans[x][y] = mat[y][x];
				}
			}
			return trans;
		}

	}
}

#endif<|endoftext|>