<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/views/label.h"

#include <math.h>

#include "base/logging.h"
#include "base/string_util.h"
#include "chrome/common/gfx/chrome_canvas.h"
#include "chrome/common/gfx/chrome_font.h"
#include "chrome/common/gfx/insets.h"
#include "chrome/common/gfx/text_elider.h"
#include "chrome/common/l10n_util.h"
#include "chrome/common/resource_bundle.h"
#include "chrome/views/background.h"

namespace views {

const char Label::kViewClassName[] = "chrome/views/Label";

static const SkColor kEnabledColor = SK_ColorBLACK;
static const SkColor kDisabledColor = SkColorSetRGB(161, 161, 146);

Label::Label() {
  Init(L"", GetDefaultFont());
}

Label::Label(const std::wstring& text) {
  Init(text, GetDefaultFont());
}

Label::Label(const std::wstring& text, const ChromeFont& font) {
  Init(text, font);
}

void Label::Init(const std::wstring& text, const ChromeFont& font) {
  contains_mouse_ = false;
  font_ = font;
  text_size_valid_ = false;
  SetText(text);
  url_set_ = false;
  color_ = kEnabledColor;
  horiz_alignment_ = ALIGN_CENTER;
  is_multi_line_ = false;
}

Label::~Label() {
}

gfx::Size Label::GetPreferredSize() {
  gfx::Size prefsize;
  if (is_multi_line_) {
    int w = width(), h = 0;
    ChromeCanvas::SizeStringInt(text_, font_, &w, &h, ComputeMultiLineFlags());
    prefsize.SetSize(w, h);
  } else {
    prefsize = GetTextSize();
  }

  gfx::Insets insets = GetInsets();
  prefsize.Enlarge(insets.width(), insets.height());
  return prefsize;
}

int Label::ComputeMultiLineFlags() {
  int flags = ChromeCanvas::MULTI_LINE;
  switch (horiz_alignment_) {
    case ALIGN_LEFT:
      flags |= ChromeCanvas::TEXT_ALIGN_LEFT;
      break;
    case ALIGN_CENTER:
      flags |= ChromeCanvas::TEXT_ALIGN_CENTER;
      break;
    case ALIGN_RIGHT:
      flags |= ChromeCanvas::TEXT_ALIGN_RIGHT;
      break;
  }
  return flags;
}

void Label::CalculateDrawStringParams(
    std::wstring* paint_text, gfx::Rect* text_bounds, int* flags) {
  DCHECK(paint_text && text_bounds && flags);

  if (url_set_) {
    // TODO(jungshik) : Figure out how to get 'intl.accept_languages'
    // preference and use it when calling ElideUrl.
    *paint_text = gfx::ElideUrl(url_, font_, width(), std::wstring());

    // An URLs is always treated as an LTR text and therefore we should
    // explicitly mark it as such if the locale is RTL so that URLs containing
    // Hebrew or Arabic characters are displayed correctly.
    //
    // Note that we don't check the View's UI layout setting in order to
    // determine whether or not to insert the special Unicode formatting
    // characters. We use the locale settings because an URL is always treated
    // as an LTR string, even if its containing view does not use an RTL UI
    // layout.
    if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT)
      l10n_util::WrapStringWithLTRFormatting(paint_text);
  } else {
    *paint_text = text_;
  }

  if (is_multi_line_) {
    gfx::Insets insets = GetInsets();
    text_bounds->SetRect(insets.left(),
                         insets.top(),
                         width() - insets.width(),
                         height() - insets.height());
    *flags = ComputeMultiLineFlags();
  } else {
    *text_bounds = GetTextBounds();
    *flags = 0;
  }
}

void Label::Paint(ChromeCanvas* canvas) {
  PaintBackground(canvas);
  std::wstring paint_text;
  gfx::Rect text_bounds;
  int flags = 0;
  CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
  canvas->DrawStringInt(paint_text,
                        font_,
                        color_,
                        text_bounds.x(),
                        text_bounds.y(),
                        text_bounds.width(),
                        text_bounds.height(),
                        flags);

  if (is_multi_line_) {
    PaintFocusBorder(canvas);
  } else {
    // We'll draw the focus border ourselves, so it is around the text.
    if (HasFocus())
      canvas->DrawFocusRect(text_bounds.x(),
                            text_bounds.y(),
                            text_bounds.width(),
                            text_bounds.height());
  }
}

void Label::PaintBackground(ChromeCanvas* canvas) {
  const Background* bg = contains_mouse_ ? GetMouseOverBackground() : NULL;
  if (!bg)
    bg = background();
  if (bg)
    bg->Paint(canvas, this);
}

void Label::SetFont(const ChromeFont& font) {
  font_ = font;
  text_size_valid_ = false;
  SchedulePaint();
}

ChromeFont Label::GetFont() const {
  return font_;
}

void Label::SetText(const std::wstring& text) {
  text_ = text;
  url_set_ = false;
  text_size_valid_ = false;
  SchedulePaint();
}

void Label::SetURL(const GURL& url) {
  url_ = url;
  text_ = UTF8ToWide(url_.spec());
  url_set_ = true;
  text_size_valid_ = false;
  SchedulePaint();
}

const std::wstring Label::GetText() const {
  if (url_set_)
    return UTF8ToWide(url_.spec());
  else
    return text_;
}

const GURL Label::GetURL() const {
  if (url_set_)
    return url_;
  else
    return GURL(WideToUTF8(text_));
}

gfx::Size Label::GetTextSize() {
  if (!text_size_valid_) {
    text_size_.SetSize(font_.GetStringWidth(text_), font_.height());
    text_size_valid_ = true;
  }

  if (text_size_valid_)
    return text_size_;
  return gfx::Size();
}

int Label::GetHeightForWidth(int w) {
  if (is_multi_line_) {
    gfx::Insets insets = GetInsets();
    w = std::max<int>(0, w - insets.width());
    int h = 0;
    ChromeCanvas cc(0, 0, true);
    cc.SizeStringInt(text_, font_, &w, &h, ComputeMultiLineFlags());
    return h + insets.height();
  }

  return View::GetHeightForWidth(w);
}

std::string Label::GetClassName() const {
  return kViewClassName;
}

void Label::SetColor(const SkColor& color) {
  color_ = color;
}

const SkColor Label::GetColor() const {
  return color_;
}

void Label::SetHorizontalAlignment(Alignment a) {
  if (horiz_alignment_ != a) {

    // If the View's UI layout is right-to-left, we need to flip the alignment
    // so that the alignment settings take into account the text
    // directionality.
    if (UILayoutIsRightToLeft()) {
      if (a == ALIGN_LEFT)
        a = ALIGN_RIGHT;
      else if (a == ALIGN_RIGHT)
        a = ALIGN_LEFT;
    }
    horiz_alignment_ = a;
    SchedulePaint();
  }
}

Label::Alignment Label::GetHorizontalAlignment() const {
  return horiz_alignment_;
}

void Label::SetMultiLine(bool f) {
  if (f != is_multi_line_) {
    is_multi_line_ = f;
    SchedulePaint();
  }
}

bool Label::IsMultiLine() {
  return is_multi_line_;
}

void Label::SetTooltipText(const std::wstring& tooltip_text) {
  tooltip_text_ = tooltip_text;
}

bool Label::GetTooltipText(int x, int y, std::wstring* tooltip) {
  DCHECK(tooltip);

  // If a tooltip has been explicitly set, use it.
  if (!tooltip_text_.empty()) {
    tooltip->assign(tooltip_text_);
    return true;
  }

  // Show the full text if the text does not fit.
  if (!is_multi_line_ && font_.GetStringWidth(text_) > width()) {
    *tooltip = text_;
    return true;
  }
  return false;
}

void Label::OnMouseMoved(const MouseEvent& e) {
  UpdateContainsMouse(e);
}

void Label::OnMouseEntered(const MouseEvent& event) {
  UpdateContainsMouse(event);
}

void Label::OnMouseExited(const MouseEvent& event) {
  SetContainsMouse(false);
}

void Label::SetMouseOverBackground(Background* background) {
  mouse_over_background_.reset(background);
}

const Background* Label::GetMouseOverBackground() const {
  return mouse_over_background_.get();
}

void Label::SetEnabled(bool enabled) {
  if (enabled == enabled_)
    return;
  View::SetEnabled(enabled);
  SetColor(enabled ? kEnabledColor : kDisabledColor);
}

// static
ChromeFont Label::GetDefaultFont() {
  return ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont);
}

void Label::UpdateContainsMouse(const MouseEvent& event) {
  SetContainsMouse(GetTextBounds().Contains(event.x(), event.y()));
}

void Label::SetContainsMouse(bool contains_mouse) {
  if (contains_mouse_ == contains_mouse)
    return;
  contains_mouse_ = contains_mouse;
  if (GetMouseOverBackground())
    SchedulePaint();
}

gfx::Rect Label::GetTextBounds() {
  gfx::Size text_size = GetTextSize();
  gfx::Insets insets = GetInsets();
  int avail_width = width() - insets.width();
  // Respect the size set by the owner view
  text_size.set_width(std::min(avail_width, text_size.width()));

  int text_y = insets.top() +
      (height() - text_size.height() - insets.height()) / 2;
  int text_x;
  switch (horiz_alignment_) {
    case ALIGN_LEFT:
      text_x = insets.left();
      break;
    case ALIGN_CENTER:
      // We put any extra margin pixel on the left rather than the right, since
      // GetTextExtentPoint32() can report a value one too large on the right.
      text_x = insets.left() + (avail_width + 1 - text_size.width()) / 2;
      break;
    case ALIGN_RIGHT:
      text_x = width() - insets.right() - text_size.width();
      break;
    default:
      text_x = 0;
      break;
  }
  return gfx::Rect(text_x, text_y, text_size.width(), text_size.height());
}

void Label::SizeToFit(int max_width) {
  DCHECK(is_multi_line_);

  std::vector<std::wstring> lines;
  SplitString(text_, L'\n', &lines);

  int label_width = 0;
  for (std::vector<std::wstring>::const_iterator iter = lines.begin();
       iter != lines.end(); ++iter) {
    label_width = std::max(label_width, font_.GetStringWidth(*iter));
  }

  gfx::Insets insets = GetInsets();
  label_width += insets.width();

  if (max_width > 0)
    label_width = std::min(label_width, max_width);

  SetBounds(x(), y(), label_width, 0);
  SizeToPreferredSize();
}

#if defined(OS_WIN)
bool Label::GetAccessibleRole(VARIANT* role) {
  DCHECK(role);

  role->vt = VT_I4;
  role->lVal = ROLE_SYSTEM_TEXT;
  return true;
}

bool Label::GetAccessibleName(std::wstring* name) {
  *name = GetText();
  return true;
}

bool Label::GetAccessibleState(VARIANT* state) {
  DCHECK(state);

  state->lVal |= STATE_SYSTEM_READONLY;
  return true;
}
#endif  // defined(OS_WIN)

}  // namespace views
<commit_msg>Add NOTREACHED() in switch default part which should never be reached.<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/views/label.h"

#include <math.h>

#include "base/logging.h"
#include "base/string_util.h"
#include "chrome/common/gfx/chrome_canvas.h"
#include "chrome/common/gfx/chrome_font.h"
#include "chrome/common/gfx/insets.h"
#include "chrome/common/gfx/text_elider.h"
#include "chrome/common/l10n_util.h"
#include "chrome/common/resource_bundle.h"
#include "chrome/views/background.h"

namespace views {

const char Label::kViewClassName[] = "chrome/views/Label";

static const SkColor kEnabledColor = SK_ColorBLACK;
static const SkColor kDisabledColor = SkColorSetRGB(161, 161, 146);

Label::Label() {
  Init(L"", GetDefaultFont());
}

Label::Label(const std::wstring& text) {
  Init(text, GetDefaultFont());
}

Label::Label(const std::wstring& text, const ChromeFont& font) {
  Init(text, font);
}

void Label::Init(const std::wstring& text, const ChromeFont& font) {
  contains_mouse_ = false;
  font_ = font;
  text_size_valid_ = false;
  SetText(text);
  url_set_ = false;
  color_ = kEnabledColor;
  horiz_alignment_ = ALIGN_CENTER;
  is_multi_line_ = false;
}

Label::~Label() {
}

gfx::Size Label::GetPreferredSize() {
  gfx::Size prefsize;
  if (is_multi_line_) {
    int w = width(), h = 0;
    ChromeCanvas::SizeStringInt(text_, font_, &w, &h, ComputeMultiLineFlags());
    prefsize.SetSize(w, h);
  } else {
    prefsize = GetTextSize();
  }

  gfx::Insets insets = GetInsets();
  prefsize.Enlarge(insets.width(), insets.height());
  return prefsize;
}

int Label::ComputeMultiLineFlags() {
  int flags = ChromeCanvas::MULTI_LINE;
  switch (horiz_alignment_) {
    case ALIGN_LEFT:
      flags |= ChromeCanvas::TEXT_ALIGN_LEFT;
      break;
    case ALIGN_CENTER:
      flags |= ChromeCanvas::TEXT_ALIGN_CENTER;
      break;
    case ALIGN_RIGHT:
      flags |= ChromeCanvas::TEXT_ALIGN_RIGHT;
      break;
  }
  return flags;
}

void Label::CalculateDrawStringParams(
    std::wstring* paint_text, gfx::Rect* text_bounds, int* flags) {
  DCHECK(paint_text && text_bounds && flags);

  if (url_set_) {
    // TODO(jungshik) : Figure out how to get 'intl.accept_languages'
    // preference and use it when calling ElideUrl.
    *paint_text = gfx::ElideUrl(url_, font_, width(), std::wstring());

    // An URLs is always treated as an LTR text and therefore we should
    // explicitly mark it as such if the locale is RTL so that URLs containing
    // Hebrew or Arabic characters are displayed correctly.
    //
    // Note that we don't check the View's UI layout setting in order to
    // determine whether or not to insert the special Unicode formatting
    // characters. We use the locale settings because an URL is always treated
    // as an LTR string, even if its containing view does not use an RTL UI
    // layout.
    if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT)
      l10n_util::WrapStringWithLTRFormatting(paint_text);
  } else {
    *paint_text = text_;
  }

  if (is_multi_line_) {
    gfx::Insets insets = GetInsets();
    text_bounds->SetRect(insets.left(),
                         insets.top(),
                         width() - insets.width(),
                         height() - insets.height());
    *flags = ComputeMultiLineFlags();
  } else {
    *text_bounds = GetTextBounds();
    *flags = 0;
  }
}

void Label::Paint(ChromeCanvas* canvas) {
  PaintBackground(canvas);
  std::wstring paint_text;
  gfx::Rect text_bounds;
  int flags = 0;
  CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
  canvas->DrawStringInt(paint_text,
                        font_,
                        color_,
                        text_bounds.x(),
                        text_bounds.y(),
                        text_bounds.width(),
                        text_bounds.height(),
                        flags);

  if (is_multi_line_) {
    PaintFocusBorder(canvas);
  } else {
    // We'll draw the focus border ourselves, so it is around the text.
    if (HasFocus())
      canvas->DrawFocusRect(text_bounds.x(),
                            text_bounds.y(),
                            text_bounds.width(),
                            text_bounds.height());
  }
}

void Label::PaintBackground(ChromeCanvas* canvas) {
  const Background* bg = contains_mouse_ ? GetMouseOverBackground() : NULL;
  if (!bg)
    bg = background();
  if (bg)
    bg->Paint(canvas, this);
}

void Label::SetFont(const ChromeFont& font) {
  font_ = font;
  text_size_valid_ = false;
  SchedulePaint();
}

ChromeFont Label::GetFont() const {
  return font_;
}

void Label::SetText(const std::wstring& text) {
  text_ = text;
  url_set_ = false;
  text_size_valid_ = false;
  SchedulePaint();
}

void Label::SetURL(const GURL& url) {
  url_ = url;
  text_ = UTF8ToWide(url_.spec());
  url_set_ = true;
  text_size_valid_ = false;
  SchedulePaint();
}

const std::wstring Label::GetText() const {
  if (url_set_)
    return UTF8ToWide(url_.spec());
  else
    return text_;
}

const GURL Label::GetURL() const {
  if (url_set_)
    return url_;
  else
    return GURL(WideToUTF8(text_));
}

gfx::Size Label::GetTextSize() {
  if (!text_size_valid_) {
    text_size_.SetSize(font_.GetStringWidth(text_), font_.height());
    text_size_valid_ = true;
  }

  if (text_size_valid_)
    return text_size_;
  return gfx::Size();
}

int Label::GetHeightForWidth(int w) {
  if (is_multi_line_) {
    gfx::Insets insets = GetInsets();
    w = std::max<int>(0, w - insets.width());
    int h = 0;
    ChromeCanvas cc(0, 0, true);
    cc.SizeStringInt(text_, font_, &w, &h, ComputeMultiLineFlags());
    return h + insets.height();
  }

  return View::GetHeightForWidth(w);
}

std::string Label::GetClassName() const {
  return kViewClassName;
}

void Label::SetColor(const SkColor& color) {
  color_ = color;
}

const SkColor Label::GetColor() const {
  return color_;
}

void Label::SetHorizontalAlignment(Alignment a) {
  if (horiz_alignment_ != a) {

    // If the View's UI layout is right-to-left, we need to flip the alignment
    // so that the alignment settings take into account the text
    // directionality.
    if (UILayoutIsRightToLeft()) {
      if (a == ALIGN_LEFT)
        a = ALIGN_RIGHT;
      else if (a == ALIGN_RIGHT)
        a = ALIGN_LEFT;
    }
    horiz_alignment_ = a;
    SchedulePaint();
  }
}

Label::Alignment Label::GetHorizontalAlignment() const {
  return horiz_alignment_;
}

void Label::SetMultiLine(bool f) {
  if (f != is_multi_line_) {
    is_multi_line_ = f;
    SchedulePaint();
  }
}

bool Label::IsMultiLine() {
  return is_multi_line_;
}

void Label::SetTooltipText(const std::wstring& tooltip_text) {
  tooltip_text_ = tooltip_text;
}

bool Label::GetTooltipText(int x, int y, std::wstring* tooltip) {
  DCHECK(tooltip);

  // If a tooltip has been explicitly set, use it.
  if (!tooltip_text_.empty()) {
    tooltip->assign(tooltip_text_);
    return true;
  }

  // Show the full text if the text does not fit.
  if (!is_multi_line_ && font_.GetStringWidth(text_) > width()) {
    *tooltip = text_;
    return true;
  }
  return false;
}

void Label::OnMouseMoved(const MouseEvent& e) {
  UpdateContainsMouse(e);
}

void Label::OnMouseEntered(const MouseEvent& event) {
  UpdateContainsMouse(event);
}

void Label::OnMouseExited(const MouseEvent& event) {
  SetContainsMouse(false);
}

void Label::SetMouseOverBackground(Background* background) {
  mouse_over_background_.reset(background);
}

const Background* Label::GetMouseOverBackground() const {
  return mouse_over_background_.get();
}

void Label::SetEnabled(bool enabled) {
  if (enabled == enabled_)
    return;
  View::SetEnabled(enabled);
  SetColor(enabled ? kEnabledColor : kDisabledColor);
}

// static
ChromeFont Label::GetDefaultFont() {
  return ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont);
}

void Label::UpdateContainsMouse(const MouseEvent& event) {
  SetContainsMouse(GetTextBounds().Contains(event.x(), event.y()));
}

void Label::SetContainsMouse(bool contains_mouse) {
  if (contains_mouse_ == contains_mouse)
    return;
  contains_mouse_ = contains_mouse;
  if (GetMouseOverBackground())
    SchedulePaint();
}

gfx::Rect Label::GetTextBounds() {
  gfx::Size text_size = GetTextSize();
  gfx::Insets insets = GetInsets();
  int avail_width = width() - insets.width();
  // Respect the size set by the owner view
  text_size.set_width(std::min(avail_width, text_size.width()));

  int text_y = insets.top() +
      (height() - text_size.height() - insets.height()) / 2;
  int text_x;
  switch (horiz_alignment_) {
    case ALIGN_LEFT:
      text_x = insets.left();
      break;
    case ALIGN_CENTER:
      // We put any extra margin pixel on the left rather than the right, since
      // GetTextExtentPoint32() can report a value one too large on the right.
      text_x = insets.left() + (avail_width + 1 - text_size.width()) / 2;
      break;
    case ALIGN_RIGHT:
      text_x = width() - insets.right() - text_size.width();
      break;
    default:
      NOTREACHED();
      text_x = 0;
      break;
  }
  return gfx::Rect(text_x, text_y, text_size.width(), text_size.height());
}

void Label::SizeToFit(int max_width) {
  DCHECK(is_multi_line_);

  std::vector<std::wstring> lines;
  SplitString(text_, L'\n', &lines);

  int label_width = 0;
  for (std::vector<std::wstring>::const_iterator iter = lines.begin();
       iter != lines.end(); ++iter) {
    label_width = std::max(label_width, font_.GetStringWidth(*iter));
  }

  gfx::Insets insets = GetInsets();
  label_width += insets.width();

  if (max_width > 0)
    label_width = std::min(label_width, max_width);

  SetBounds(x(), y(), label_width, 0);
  SizeToPreferredSize();
}

#if defined(OS_WIN)
bool Label::GetAccessibleRole(VARIANT* role) {
  DCHECK(role);

  role->vt = VT_I4;
  role->lVal = ROLE_SYSTEM_TEXT;
  return true;
}

bool Label::GetAccessibleName(std::wstring* name) {
  *name = GetText();
  return true;
}

bool Label::GetAccessibleState(VARIANT* state) {
  DCHECK(state);

  state->lVal |= STATE_SYSTEM_READONLY;
  return true;
}
#endif  // defined(OS_WIN)

}  // namespace views
<|endoftext|>


<commit_before>#ifndef FX_SEGMENT_TREE_HPP
#define FX_SEGMENT_TREE_HPP

#include <vector>
#include <utility>

namespace fx {

template <typename T, typename Specification, typename Container=std::vector<T> >
class segment_tree
{
protected:
    // Types
    typedef T value_type;
    typedef Container container;
    typedef Specification specification;
    typedef typename Container::size_type size_type;
    typedef std::pair<size_type, size_type> size_type_pair;

public:
    // Constructors
    segment_tree() :
        cont_(),
        tree_cont_(),
        identity_(specification::get_identity())
    {
    }

    segment_tree(size_type n, const value_type& val = value_type()) :
        cont_(n, val),
        tree_cont_(),
        identity_(specification::get_identity())
    {
        build();
    }

    template<typename InputIterator>
    segment_tree(InputIterator first, InputIterator last) :
        cont_(first, last),
        tree_cont_(),
        identity_(specification::get_identity())
    {
        build();
    }

    segment_tree(const container& cont) :
        cont_(cont),
        tree_cont_(),
        identity_(specification::get_identity())
    {
        build();
    }

    // Public methods
    void build()
    {
        size_type_pair tree_size_height = tree_size(cont_.size());

        size_ = tree_size_height.first+1;
        height_ = tree_size_height.second;

        tree_cont_.resize(size_-1);

        if (!height_) return;

        size_type_pair range = range_for_depth(height_-1);
        size_type& start = range.first;
        size_type& end = range.second;

        // tree base level
        for (size_type k = 0; start+k < end; ++k)
            tree_cont_[start+k] = specification::fn(get_element(k<<1), get_element((k<<1)+1));

        // other levels
        for (size_type h = 1, depth = height_-2; h < height_; ++h, --depth)
        {
            range = range_for_depth(depth);
            size_type& start = range.first;
            size_type& end = range.second;

            for (size_type k = start; k < end; ++k)
                tree_cont_[k] = specification::fn(tree_cont_[(k<<1)+1], tree_cont_[(k<<1)+2]);
        }
    }

    const T& query(size_type start, size_type last) const
    {
        // check start < last <= cont_.size()
        return query_recursive(0, size_type_pair(0, size_), size_type_pair(start, last));
    }

    void update(size_type index, const T& val);

protected:
    // Data members
    container cont_;
    container tree_cont_;
    size_type height_;
    size_type size_;
    value_type identity_;

    // Query and update methods
    const T& query_recursive(size_type node, size_type_pair node_range, size_type_pair query_range) const
    {
        if (node_range.first >= query_range.first && node_range.second <= query_range.second)
            if (node_range.first + 1 == node_range.second)
                return get_element(node_range.first);
            else
                return tree_cont_[node];

        if (node_range.second <= query_range.first || query_range.second <= node_range.first)
            return identity_;

        const T * left_val = & query_recursive((node<<1)+1, size_type_pair(node_range.first, node_range.second<<1),
            query_range);

        const T * right_val = & query_recursive((node<<1)+2, size_type_pair(node_range.second<<1, node_range.second),
            query_range);

        return specification::fn(*left_val, *right_val);
    }

    // Util functions
    size_type_pair tree_size(size_type n) const
    {
        size_type height = 0;
        size_type size = 1;

        while (size < n) ++height, size <<= 1;

        return size_type_pair(size - 1, height);
    }

    inline size_type_pair range_for_depth(size_type depth) const
    {
        return size_type_pair((1<<depth)-1, (1<<(depth+1))-1);
    }

    inline const value_type& get_element(size_type index) const
    {
        return index < cont_.size() ? cont_[index] : identity_;
    }
}; // class segment_tree

} // namespace fx

#endif // FX_SEGMENT_TREE_HPP

<commit_msg>Implemented update function<commit_after>#ifndef FX_SEGMENT_TREE_HPP
#define FX_SEGMENT_TREE_HPP

#include <vector>
#include <utility>

namespace fx {

template <typename T, typename Specification, typename Container=std::vector<T> >
class segment_tree
{
protected:
    // Types
    typedef T value_type;
    typedef Container container;
    typedef Specification specification;
    typedef typename Container::size_type size_type;
    typedef std::pair<size_type, size_type> size_type_pair;

public:
    // Constructors
    segment_tree() :
        cont_(),
        tree_cont_(),
        identity_(specification::get_identity())
    {
    }

    segment_tree(size_type n, const value_type& val = value_type()) :
        cont_(n, val),
        tree_cont_(),
        identity_(specification::get_identity())
    {
        build();
    }

    template<typename InputIterator>
    segment_tree(InputIterator first, InputIterator last) :
        cont_(first, last),
        tree_cont_(),
        identity_(specification::get_identity())
    {
        build();
    }

    segment_tree(const container& cont) :
        cont_(cont),
        tree_cont_(),
        identity_(specification::get_identity())
    {
        build();
    }

    // Public methods
    void build()
    {
        size_type_pair tree_size_height = tree_size(cont_.size());

        size_ = tree_size_height.first+1;
        height_ = tree_size_height.second;

        tree_cont_.resize(size_-1);

        if (!height_) return;

        size_type_pair range = range_for_depth(height_-1);
        size_type& start = range.first;
        size_type& end = range.second;

        // tree base level
        for (size_type k = 0; start+k < end; ++k)
            tree_cont_[start+k] = specification::fn(get_element(k<<1), get_element((k<<1)+1));

        // other levels
        for (size_type h = 1, depth = height_-2; h < height_; ++h, --depth)
        {
            range = range_for_depth(depth);
            size_type& start = range.first;
            size_type& end = range.second;

            for (size_type k = start; k < end; ++k)
                tree_cont_[k] = specification::fn(tree_cont_[(k<<1)+1], tree_cont_[(k<<1)+2]);
        }
    }

    const T& query(size_type start, size_type last) const
    {
        // check start < last <= cont_.size()
        return query_recursive(0, size_type_pair(0, size_), size_type_pair(start, last));
    }

    void update(size_type index, const value_type& val)
    {
        // check index < cont_.size()
        update_recursive(0, size_type_pair(0, size_), index, val);
    }

protected:
    // Data members
    container cont_;
    container tree_cont_;
    size_type height_;
    size_type size_;
    value_type identity_;

    // Query and update methods
    const T& query_recursive(size_type node, size_type_pair node_range, size_type_pair query_range) const
    {
        if (node_range.first >= query_range.first && node_range.second <= query_range.second)
            if (node_range.first + 1 == node_range.second)
                return get_element(node_range.first);
            else
                return tree_cont_[node];

        if (node_range.second <= query_range.first || query_range.second <= node_range.first)
            return identity_;

        const T * left_val = & query_recursive((node<<1)+1, size_type_pair(node_range.first, node_range.second<<1),
            query_range);

        const T * right_val = & query_recursive((node<<1)+2, size_type_pair(node_range.second<<1, node_range.second),
            query_range);

        return specification::fn(*left_val, *right_val);
    }

    const T& update_recursive(size_type node, size_type_pair node_range, size_type index, const T& val)
    {
        if (node_range.first + 1 == node_range.second)
            return cont_[index] = val; // index must always be less than cont_.size()

        if (index < node_range.first || node_range.second <= index)
            if (node_range.first + 1 == node_range.second)
                return get_element(node_range.first);
            else
                return tree_cont_[node];

        const T * left_val = & update_recursive((node<<1)+1, size_type_pair(node_range.first, node_range.second<<1),
            index, val);

        const T * right_val = & update_recursive((node<<1)+2, size_type_pair(node_range.second<<1, node_range.second),
            index, val);

        return specification::fn(*left_val, *right_val);
    }

    // Util functions
    size_type_pair tree_size(size_type n) const
    {
        size_type height = 0;
        size_type size = 1;

        while (size < n) ++height, size <<= 1;

        return size_type_pair(size - 1, height);
    }

    inline size_type_pair range_for_depth(size_type depth) const
    {
        return size_type_pair((1<<depth)-1, (1<<(depth+1))-1);
    }

    inline const value_type& get_element(size_type index) const
    {
        return index < cont_.size() ? cont_[index] : identity_;
    }
}; // class segment_tree

} // namespace fx

#endif // FX_SEGMENT_TREE_HPP

<|endoftext|>


<commit_before>// Copyright (c) 2015, Baidu.com, Inc. All Rights Reserved
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.

#include <errno.h>
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <algorithm>
#include <set>
#include <iostream>
#include <sstream>

#include "hdfs.h"
#include "leveldb/env.h"
#include "leveldb/status.h"
#include "leveldb/env_dfs.h"
#include "leveldb/table_utils.h"
#include "nfs.h"
#include "util/mutexlock.h"
#include "../utils/counter.h"

namespace leveldb {

tera::Counter dfs_read_size_counter;
tera::Counter dfs_write_size_counter;

tera::Counter dfs_read_delay_counter;
tera::Counter dfs_write_delay_counter;

tera::Counter dfs_read_counter;
tera::Counter dfs_write_counter;
tera::Counter dfs_sync_counter;
tera::Counter dfs_flush_counter;
tera::Counter dfs_list_counter;
tera::Counter dfs_other_counter;
tera::Counter dfs_exists_counter;
tera::Counter dfs_open_counter;
tera::Counter dfs_close_counter;
tera::Counter dfs_delete_counter;
tera::Counter dfs_tell_counter;
tera::Counter dfs_info_counter;

tera::Counter dfs_read_hang_counter;
tera::Counter dfs_write_hang_counter;
tera::Counter dfs_sync_hang_counter;
tera::Counter dfs_flush_hang_counter;
tera::Counter dfs_list_hang_counter;
tera::Counter dfs_other_hang_counter;
tera::Counter dfs_exists_hang_counter;
tera::Counter dfs_open_hang_counter;
tera::Counter dfs_close_hang_counter;
tera::Counter dfs_delete_hang_counter;
tera::Counter dfs_tell_hang_counter;
tera::Counter dfs_info_hang_counter;

bool split_filename(const std::string filename,
        std::string* path, std::string* file)
{
    size_t pos = filename.rfind('/');
    if (pos == std::string::npos) {
        return false;
    }
    *path = filename.substr(0, pos);
    *file = filename.substr(pos + 1);
    return true;
}

char* get_time_str(char* p, size_t len)
{
    const uint64_t thread_id = DfsEnv::gettid();
    struct timeval now_tv;
    gettimeofday(&now_tv, NULL);
    const time_t seconds = now_tv.tv_sec;
    struct tm t;
    localtime_r(&seconds, &t);
    p += snprintf(p, len,
            "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llu",
            t.tm_year + 1900,
            t.tm_mon + 1,
            t.tm_mday,
            t.tm_hour,
            t.tm_min,
            t.tm_sec,
            static_cast<int>(now_tv.tv_usec),
            static_cast<long long unsigned int>(thread_id));
    return p;
}

// Log error message
static Status IOError(const std::string& context, int err_number)
{
    return Status::IOError(context, strerror(err_number));
}

class DfsReadableFile: virtual public SequentialFile, virtual public RandomAccessFile {
private:
    Dfs* fs_;
    std::string filename_;
    DfsFile* file_;
    mutable ssize_t now_pos;
    //mutable port::Mutex mu_;
public:
    DfsReadableFile(Dfs* fs, const std::string& fname)
        : fs_(fs), filename_(fname), file_(NULL),
          now_pos(-1) {
        file_ = fs->OpenFile(filename_, RDONLY);
        // assert(hfile_ != NULL);
        if (file_ == NULL) {
            fprintf(stderr, "[env_dfs]: open file fail: %s\n", filename_.c_str());
        }
        now_pos = 0;
    }

    virtual ~DfsReadableFile() {
        if (file_) {
            file_->CloseFile();
        }
        delete file_;
        file_ = NULL;
    }

    bool isValid() {
        return (file_ != NULL);
    }

    virtual Status Read(size_t n, Slice* result, char* scratch) {
        now_pos = -1;
        Status s;
        int32_t bytes_read = file_->Read(scratch, (int32_t)n);
        *result = Slice(scratch, (bytes_read < 0) ? 0 : bytes_read);
        if (bytes_read < static_cast<int32_t>(n)) {
            if (feof()) {
                // end of the file
            } else {
                s = IOError(filename_, errno);
            }
        }
        dfs_read_size_counter.Add(bytes_read);
        return Status::OK();
    }

    virtual Status Read(uint64_t offset, size_t n, Slice* result, char* scratch) const {
        Status s;
        int32_t bytes_read = file_->Pread(offset, scratch, n);
        *result = Slice(scratch, (bytes_read < 0) ? 0 : bytes_read);
        if (bytes_read < 0) {
            s = IOError(filename_, errno);
        }
        dfs_read_size_counter.Add(bytes_read);
        return s;
    }

    virtual Status Skip(uint64_t n) {
        int64_t current = file_->Tell();
        if (current < 0) {
            return IOError(filename_, errno);
        }
        // seek to new offset
        int64_t newoffset = current + n;
        int val = file_->Seek(newoffset);
        if (val < 0) {
            return IOError(filename_, errno);
        }
        return Status::OK();
    }

private:
    // at the end of file ?
    bool feof() {
        if (file_ && file_->Tell() == fileSize()) {
            return true;
        }
        return false;
    }
    // file size
    int64_t fileSize() {
        uint64_t size = 0;
        fs_->GetFileSize(filename_, &size);
        return size;
    }
};

// WritableFile
class DfsWritableFile: public WritableFile {
private:
    Dfs* fs_;
    std::string filename_;
    DfsFile* file_;
public:
    DfsWritableFile(Dfs* fs, const std::string& fname)
        : fs_(fs), filename_(fname) , file_(NULL) {
        fs_->Delete(filename_);
        file_ = fs_->OpenFile(filename_, WRONLY);
        if (file_ == NULL) {
            fprintf(stderr, "[env_dfs]: open file for write fail: %s\n", fname.c_str());
        }
    }
    virtual ~DfsWritableFile() {
        if (file_ != NULL) {
            file_->CloseFile();
        }
        delete file_;
    }

    bool isValid() {
        return file_ != NULL;
    }

    const std::string& getName() {
        return filename_;
    }

    virtual Status Append(const Slice& data) {
        const char* src = data.data();
        size_t left = data.size();
        int32_t ret = file_->Write(src, left);
        if (ret != static_cast<int32_t>(left)) {
            return IOError(filename_, errno);
        }
        dfs_write_size_counter.Add(ret);
        return Status::OK();
    }

    virtual Status Flush() {
        // dfs flush efficiency is too low, close it
        //if (file_->Flush() != 0) {
        //    return IOError(filename_, errno);
        //}
        return Status::OK();
    }

    virtual Status Sync() {
        Status s;
        uint64_t n = EnvDfs()->NowMicros();
        if (file_->Sync() == -1) {
            fprintf(stderr, "hdfs sync fail: %s\n", filename_.c_str());
            s = IOError(filename_, errno);
        }
        uint64_t diff = EnvDfs()->NowMicros() - n;
        if (diff > 2000000) {
            char buf[128];
            get_time_str(buf, 128);
            fprintf(stderr, "%s hdfs sync for %s use %.2fms\n",
                buf, filename_.c_str(), diff / 1000.0);
        }
        return s;
    }

    virtual Status Close() {
        Status result;
        if (file_ != NULL && file_->CloseFile() != 0) {
            result = IOError(filename_, errno);
        }
        delete file_;
        file_ = NULL;
        return result;
    }
};

DfsEnv::DfsEnv(Dfs* dfs)
  : EnvWrapper(Env::Default()), hdfs_(dfs) {
}

DfsEnv::~DfsEnv()
{
}

// SequentialFile
Status DfsEnv::NewSequentialFile(const std::string& fname, SequentialFile** result)
{
    DfsReadableFile* f = new DfsReadableFile(hdfs_, fname);
    if (!f->isValid()) {
        delete f;
        *result = NULL;
        return IOError(fname, errno);
    }
    *result = dynamic_cast<SequentialFile*>(f);
    return Status::OK();
}

// random read file
Status DfsEnv::NewRandomAccessFile(const std::string& fname, RandomAccessFile** result)
{
    DfsReadableFile* f = new DfsReadableFile(hdfs_, fname);
    if (f == NULL || !f->isValid()) {
        delete f;
        *result = NULL;
        return IOError(fname, errno);
    }
    *result = dynamic_cast<RandomAccessFile*>(f);
    return Status::OK();
}

// writable
Status DfsEnv::NewWritableFile(const std::string& fname,
        WritableFile** result)
{
    Status s;
    DfsWritableFile* f = new DfsWritableFile(hdfs_, fname);
    if (f == NULL || !f->isValid()) {
        delete f;
        *result = NULL;
        return IOError(fname, errno);
    }
    *result = dynamic_cast<WritableFile*>(f);
    return Status::OK();
}

// FileExists
bool DfsEnv::FileExists(const std::string& fname)
{
    return (0 == hdfs_->Exists(fname));
}

Status DfsEnv::CopyFile(const std::string& from, const std::string& to) {
    std::cerr << "HdfsEnv: " << from << " --> " << to << std::endl;
    if (from != to && hdfs_->Copy(from, to) != 0) {
        return Status::IOError("HDFS Copy", from);
    }
    return Status::OK();
}

Status DfsEnv::GetChildren(const std::string& path,
        std::vector<std::string>* result)
{
    if (0 != hdfs_->Exists(path)) {
        fprintf(stderr, "GetChildren call with path not exists: %s\n",
                path.data());
        return Status::IOError("Path not exist", path);
    } else if (0 != hdfs_->ListDirectory(path, result)) {
        abort();
    }
    return Status::OK();
}

bool DfsEnv::CheckDelete(const std::string& fname, std::vector<std::string>* flags)
{
    std::string path, file;
    bool r = split_filename(fname, &path, &file);
    assert(r);
    std::string prefix = file + "_del_";
    std::vector<std::string> files;
    hdfs_->ListDirectory(path, &files);
    size_t max_len = 0;
    size_t value = 0;
    for (size_t i = 0; i < files.size(); i++) {
        if (files[i].compare(0, prefix.size(), prefix) != 0) {
            continue;
        }
        flags->push_back(path + "/" + files[i]);
        std::string id_str = files[i].substr(prefix.size());
        if (id_str.size() > 64) {
            return false;
        }
        if (max_len < id_str.size()) {
            value <<= (id_str.size() - max_len);
            value ++;
            max_len = id_str.size();
        } else {
            value += (1ULL << (max_len - id_str.size()));
        }
    }
    return (value == (1ULL << max_len));
}

Status DfsEnv::DeleteFile(const std::string& fname)
{
    if (hdfs_->Delete(fname) == 0) {
        return Status::OK();
    }
    return IOError(fname, errno);
};

Status DfsEnv::CreateDir(const std::string& name)
{
    if (hdfs_->CreateDirectory(name) == 0) {
        return Status::OK();
    }
    return IOError(name, errno);
};

Status DfsEnv::DeleteDir(const std::string& name)
{
    if (hdfs_->DeleteDirectory(name) == 0) {
        return Status::OK();
    }
    return IOError(name, errno);
};

Status DfsEnv::ListDir(const std::string& name,
        std::vector<std::string>* result) {
    hdfs_->ListDirectory(name, result);
    return Status::OK();
}

Status DfsEnv::GetFileSize(const std::string& fname, uint64_t* size)
{
    *size = 0L;
    if (0 != hdfs_->GetFileSize(fname, size)) {
        return IOError(fname, errno);
    } else {
        return Status::OK();
    }
}

///
Status DfsEnv::RenameFile(const std::string& src, const std::string& target)
{
    DeleteFile(target);
    if (hdfs_->Rename(src, target) == 0) {

    }
    Status result;
    return result;
}

Status DfsEnv::LockFile(const std::string& fname, FileLock** lock)
{
    *lock = NULL;
    return Status::OK();
}

Status DfsEnv::UnlockFile(FileLock* lock)
{
    return Status::OK();
}

Status DfsEnv::NewLogger(const std::string& fname, Logger** result)
{
    return IOError(fname, errno);
}

static bool inited = false;
static port::Mutex mutex;
static Env* dfs_env;

void InitDfsEnv(const std::string& so_path, const std::string& conf) {
    MutexLock l(&mutex);
    if (inited) {
        return;
    }
    Dfs* dfs = Dfs::NewDfs(so_path, conf.c_str());
    if (dfs == NULL) {
        abort();
    }
    dfs_env = new DfsEnv(dfs);
    inited = true;
}

void InitHdfsEnv()
{
    MutexLock l(&mutex);
    if (inited) {
        return;
    }
    Dfs* dfs = new Hdfs();
    dfs_env = new DfsEnv(dfs);
    inited = true;
}

void InitHdfs2Env(const std::string& namenode_list)
{
    MutexLock l(&mutex);
    if (inited) {
        return;
    }
    Dfs* dfs = new Hdfs2(namenode_list);
    dfs_env = new DfsEnv(dfs);
    inited = true;
}

void InitNfsEnv(const std::string& mountpoint,
                const std::string& conf_path)
{
    MutexLock l(&mutex);
    if (inited) {
        return;
    }
    Nfs::Init(mountpoint, conf_path);
    Dfs* dfs = Nfs::GetInstance();
    dfs_env = new DfsEnv(dfs);
    inited = true;
}

Env* NewDfsEnv(Dfs* dfs)
{
    return new DfsEnv(dfs);
}

Env* EnvDfs()
{
    MutexLock l(&mutex);
    if (inited) {
        return dfs_env;
    }
    Dfs* dfs = new Hdfs();
    dfs_env = new DfsEnv(dfs);
    inited = true;
    return dfs_env;
}

}  // namespace leveldb

<commit_msg>Bugfix on InitDfsEnv<commit_after>// Copyright (c) 2015, Baidu.com, Inc. All Rights Reserved
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.

#include <errno.h>
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <algorithm>
#include <set>
#include <iostream>
#include <sstream>

#include "hdfs.h"
#include "leveldb/env.h"
#include "leveldb/status.h"
#include "leveldb/env_dfs.h"
#include "leveldb/table_utils.h"
#include "nfs.h"
#include "util/mutexlock.h"
#include "../utils/counter.h"

namespace leveldb {

tera::Counter dfs_read_size_counter;
tera::Counter dfs_write_size_counter;

tera::Counter dfs_read_delay_counter;
tera::Counter dfs_write_delay_counter;

tera::Counter dfs_read_counter;
tera::Counter dfs_write_counter;
tera::Counter dfs_sync_counter;
tera::Counter dfs_flush_counter;
tera::Counter dfs_list_counter;
tera::Counter dfs_other_counter;
tera::Counter dfs_exists_counter;
tera::Counter dfs_open_counter;
tera::Counter dfs_close_counter;
tera::Counter dfs_delete_counter;
tera::Counter dfs_tell_counter;
tera::Counter dfs_info_counter;

tera::Counter dfs_read_hang_counter;
tera::Counter dfs_write_hang_counter;
tera::Counter dfs_sync_hang_counter;
tera::Counter dfs_flush_hang_counter;
tera::Counter dfs_list_hang_counter;
tera::Counter dfs_other_hang_counter;
tera::Counter dfs_exists_hang_counter;
tera::Counter dfs_open_hang_counter;
tera::Counter dfs_close_hang_counter;
tera::Counter dfs_delete_hang_counter;
tera::Counter dfs_tell_hang_counter;
tera::Counter dfs_info_hang_counter;

bool split_filename(const std::string filename,
        std::string* path, std::string* file)
{
    size_t pos = filename.rfind('/');
    if (pos == std::string::npos) {
        return false;
    }
    *path = filename.substr(0, pos);
    *file = filename.substr(pos + 1);
    return true;
}

char* get_time_str(char* p, size_t len)
{
    const uint64_t thread_id = DfsEnv::gettid();
    struct timeval now_tv;
    gettimeofday(&now_tv, NULL);
    const time_t seconds = now_tv.tv_sec;
    struct tm t;
    localtime_r(&seconds, &t);
    p += snprintf(p, len,
            "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llu",
            t.tm_year + 1900,
            t.tm_mon + 1,
            t.tm_mday,
            t.tm_hour,
            t.tm_min,
            t.tm_sec,
            static_cast<int>(now_tv.tv_usec),
            static_cast<long long unsigned int>(thread_id));
    return p;
}

// Log error message
static Status IOError(const std::string& context, int err_number)
{
    return Status::IOError(context, strerror(err_number));
}

class DfsReadableFile: virtual public SequentialFile, virtual public RandomAccessFile {
private:
    Dfs* fs_;
    std::string filename_;
    DfsFile* file_;
    mutable ssize_t now_pos;
    //mutable port::Mutex mu_;
public:
    DfsReadableFile(Dfs* fs, const std::string& fname)
        : fs_(fs), filename_(fname), file_(NULL),
          now_pos(-1) {
        file_ = fs->OpenFile(filename_, RDONLY);
        // assert(hfile_ != NULL);
        if (file_ == NULL) {
            fprintf(stderr, "[env_dfs]: open file fail: %s\n", filename_.c_str());
        }
        now_pos = 0;
    }

    virtual ~DfsReadableFile() {
        if (file_) {
            file_->CloseFile();
        }
        delete file_;
        file_ = NULL;
    }

    bool isValid() {
        return (file_ != NULL);
    }

    virtual Status Read(size_t n, Slice* result, char* scratch) {
        now_pos = -1;
        Status s;
        int32_t bytes_read = file_->Read(scratch, (int32_t)n);
        *result = Slice(scratch, (bytes_read < 0) ? 0 : bytes_read);
        if (bytes_read < static_cast<int32_t>(n)) {
            if (feof()) {
                // end of the file
            } else {
                s = IOError(filename_, errno);
            }
        }
        dfs_read_size_counter.Add(bytes_read);
        return Status::OK();
    }

    virtual Status Read(uint64_t offset, size_t n, Slice* result, char* scratch) const {
        Status s;
        int32_t bytes_read = file_->Pread(offset, scratch, n);
        *result = Slice(scratch, (bytes_read < 0) ? 0 : bytes_read);
        if (bytes_read < 0) {
            s = IOError(filename_, errno);
        }
        dfs_read_size_counter.Add(bytes_read);
        return s;
    }

    virtual Status Skip(uint64_t n) {
        int64_t current = file_->Tell();
        if (current < 0) {
            return IOError(filename_, errno);
        }
        // seek to new offset
        int64_t newoffset = current + n;
        int val = file_->Seek(newoffset);
        if (val < 0) {
            return IOError(filename_, errno);
        }
        return Status::OK();
    }

private:
    // at the end of file ?
    bool feof() {
        if (file_ && file_->Tell() == fileSize()) {
            return true;
        }
        return false;
    }
    // file size
    int64_t fileSize() {
        uint64_t size = 0;
        fs_->GetFileSize(filename_, &size);
        return size;
    }
};

// WritableFile
class DfsWritableFile: public WritableFile {
private:
    Dfs* fs_;
    std::string filename_;
    DfsFile* file_;
public:
    DfsWritableFile(Dfs* fs, const std::string& fname)
        : fs_(fs), filename_(fname) , file_(NULL) {
        fs_->Delete(filename_);
        file_ = fs_->OpenFile(filename_, WRONLY);
        if (file_ == NULL) {
            fprintf(stderr, "[env_dfs]: open file for write fail: %s\n", fname.c_str());
        }
    }
    virtual ~DfsWritableFile() {
        if (file_ != NULL) {
            file_->CloseFile();
        }
        delete file_;
    }

    bool isValid() {
        return file_ != NULL;
    }

    const std::string& getName() {
        return filename_;
    }

    virtual Status Append(const Slice& data) {
        const char* src = data.data();
        size_t left = data.size();
        int32_t ret = file_->Write(src, left);
        if (ret != static_cast<int32_t>(left)) {
            return IOError(filename_, errno);
        }
        dfs_write_size_counter.Add(ret);
        return Status::OK();
    }

    virtual Status Flush() {
        // dfs flush efficiency is too low, close it
        //if (file_->Flush() != 0) {
        //    return IOError(filename_, errno);
        //}
        return Status::OK();
    }

    virtual Status Sync() {
        Status s;
        uint64_t n = EnvDfs()->NowMicros();
        if (file_->Sync() == -1) {
            fprintf(stderr, "hdfs sync fail: %s\n", filename_.c_str());
            s = IOError(filename_, errno);
        }
        uint64_t diff = EnvDfs()->NowMicros() - n;
        if (diff > 2000000) {
            char buf[128];
            get_time_str(buf, 128);
            fprintf(stderr, "%s hdfs sync for %s use %.2fms\n",
                buf, filename_.c_str(), diff / 1000.0);
        }
        return s;
    }

    virtual Status Close() {
        Status result;
        if (file_ != NULL && file_->CloseFile() != 0) {
            result = IOError(filename_, errno);
        }
        delete file_;
        file_ = NULL;
        return result;
    }
};

DfsEnv::DfsEnv(Dfs* dfs)
  : EnvWrapper(Env::Default()), hdfs_(dfs) {
}

DfsEnv::~DfsEnv()
{
}

// SequentialFile
Status DfsEnv::NewSequentialFile(const std::string& fname, SequentialFile** result)
{
    DfsReadableFile* f = new DfsReadableFile(hdfs_, fname);
    if (!f->isValid()) {
        delete f;
        *result = NULL;
        return IOError(fname, errno);
    }
    *result = dynamic_cast<SequentialFile*>(f);
    return Status::OK();
}

// random read file
Status DfsEnv::NewRandomAccessFile(const std::string& fname, RandomAccessFile** result)
{
    DfsReadableFile* f = new DfsReadableFile(hdfs_, fname);
    if (f == NULL || !f->isValid()) {
        delete f;
        *result = NULL;
        return IOError(fname, errno);
    }
    *result = dynamic_cast<RandomAccessFile*>(f);
    return Status::OK();
}

// writable
Status DfsEnv::NewWritableFile(const std::string& fname,
        WritableFile** result)
{
    Status s;
    DfsWritableFile* f = new DfsWritableFile(hdfs_, fname);
    if (f == NULL || !f->isValid()) {
        delete f;
        *result = NULL;
        return IOError(fname, errno);
    }
    *result = dynamic_cast<WritableFile*>(f);
    return Status::OK();
}

// FileExists
bool DfsEnv::FileExists(const std::string& fname)
{
    return (0 == hdfs_->Exists(fname));
}

Status DfsEnv::CopyFile(const std::string& from, const std::string& to) {
    std::cerr << "HdfsEnv: " << from << " --> " << to << std::endl;
    if (from != to && hdfs_->Copy(from, to) != 0) {
        return Status::IOError("HDFS Copy", from);
    }
    return Status::OK();
}

Status DfsEnv::GetChildren(const std::string& path,
        std::vector<std::string>* result)
{
    if (0 != hdfs_->Exists(path)) {
        fprintf(stderr, "GetChildren call with path not exists: %s\n",
                path.data());
        return Status::IOError("Path not exist", path);
    } else if (0 != hdfs_->ListDirectory(path, result)) {
        abort();
    }
    return Status::OK();
}

bool DfsEnv::CheckDelete(const std::string& fname, std::vector<std::string>* flags)
{
    std::string path, file;
    bool r = split_filename(fname, &path, &file);
    assert(r);
    std::string prefix = file + "_del_";
    std::vector<std::string> files;
    hdfs_->ListDirectory(path, &files);
    size_t max_len = 0;
    size_t value = 0;
    for (size_t i = 0; i < files.size(); i++) {
        if (files[i].compare(0, prefix.size(), prefix) != 0) {
            continue;
        }
        flags->push_back(path + "/" + files[i]);
        std::string id_str = files[i].substr(prefix.size());
        if (id_str.size() > 64) {
            return false;
        }
        if (max_len < id_str.size()) {
            value <<= (id_str.size() - max_len);
            value ++;
            max_len = id_str.size();
        } else {
            value += (1ULL << (max_len - id_str.size()));
        }
    }
    return (value == (1ULL << max_len));
}

Status DfsEnv::DeleteFile(const std::string& fname)
{
    if (hdfs_->Delete(fname) == 0) {
        return Status::OK();
    }
    return IOError(fname, errno);
};

Status DfsEnv::CreateDir(const std::string& name)
{
    if (hdfs_->CreateDirectory(name) == 0) {
        return Status::OK();
    }
    return IOError(name, errno);
};

Status DfsEnv::DeleteDir(const std::string& name)
{
    if (hdfs_->DeleteDirectory(name) == 0) {
        return Status::OK();
    }
    return IOError(name, errno);
};

Status DfsEnv::ListDir(const std::string& name,
        std::vector<std::string>* result) {
    hdfs_->ListDirectory(name, result);
    return Status::OK();
}

Status DfsEnv::GetFileSize(const std::string& fname, uint64_t* size)
{
    *size = 0L;
    if (0 != hdfs_->GetFileSize(fname, size)) {
        return IOError(fname, errno);
    } else {
        return Status::OK();
    }
}

///
Status DfsEnv::RenameFile(const std::string& src, const std::string& target)
{
    DeleteFile(target);
    if (hdfs_->Rename(src, target) == 0) {

    }
    Status result;
    return result;
}

Status DfsEnv::LockFile(const std::string& fname, FileLock** lock)
{
    *lock = NULL;
    return Status::OK();
}

Status DfsEnv::UnlockFile(FileLock* lock)
{
    return Status::OK();
}

Status DfsEnv::NewLogger(const std::string& fname, Logger** result)
{
    return IOError(fname, errno);
}

static bool inited = false;
static port::Mutex mutex;
static Env* dfs_env;

void InitDfsEnv(const std::string& so_path, const std::string& conf) {
    MutexLock l(&mutex);
    if (inited) {
        return;
    }
    Dfs* dfs = Dfs::NewDfs(so_path, conf);
    if (dfs == NULL) {
        abort();
    }
    dfs_env = new DfsEnv(dfs);
    inited = true;
}

void InitHdfsEnv()
{
    MutexLock l(&mutex);
    if (inited) {
        return;
    }
    Dfs* dfs = new Hdfs();
    dfs_env = new DfsEnv(dfs);
    inited = true;
}

void InitHdfs2Env(const std::string& namenode_list)
{
    MutexLock l(&mutex);
    if (inited) {
        return;
    }
    Dfs* dfs = new Hdfs2(namenode_list);
    dfs_env = new DfsEnv(dfs);
    inited = true;
}

void InitNfsEnv(const std::string& mountpoint,
                const std::string& conf_path)
{
    MutexLock l(&mutex);
    if (inited) {
        return;
    }
    Nfs::Init(mountpoint, conf_path);
    Dfs* dfs = Nfs::GetInstance();
    dfs_env = new DfsEnv(dfs);
    inited = true;
}

Env* NewDfsEnv(Dfs* dfs)
{
    return new DfsEnv(dfs);
}

Env* EnvDfs()
{
    MutexLock l(&mutex);
    if (inited) {
        return dfs_env;
    }
    Dfs* dfs = new Hdfs();
    dfs_env = new DfsEnv(dfs);
    inited = true;
    return dfs_env;
}

}  // namespace leveldb

<|endoftext|>


<commit_before>//===--------------------- TimelineView.cpp ---------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \brief
///
/// This file implements the TimelineView interface.
///
//===----------------------------------------------------------------------===//

#include "Views/TimelineView.h"

using namespace llvm;

namespace mca {

TimelineView::TimelineView(const MCSubtargetInfo &sti, MCInstPrinter &Printer,
                           const SourceMgr &S, unsigned MaxIterations,
                           unsigned Cycles)
    : STI(sti), MCIP(Printer), AsmSequence(S), CurrentCycle(0),
      MaxCycle(Cycles == 0 ? 80 : Cycles), LastCycle(0), WaitTime(S.size()),
      UsedBuffer(S.size()) {
  unsigned NumInstructions = AsmSequence.size();
  if (!MaxIterations)
    MaxIterations = DEFAULT_ITERATIONS;
  NumInstructions *= std::min(MaxIterations, AsmSequence.getNumIterations());
  Timeline.resize(NumInstructions);
  TimelineViewEntry InvalidTVEntry = {-1, 0, 0, 0};
  std::fill(Timeline.begin(), Timeline.end(), InvalidTVEntry);

  WaitTimeEntry NullWTEntry = {0, 0, 0};
  std::fill(WaitTime.begin(), WaitTime.end(), NullWTEntry);

  std::pair<unsigned, int> NullUsedBufferEntry = {/* Invalid resource ID*/ 0,
                                                  /* unknown buffer size */ -1};
  std::fill(UsedBuffer.begin(), UsedBuffer.end(), NullUsedBufferEntry);
}

void TimelineView::onReservedBuffers(const InstRef &IR,
                                     ArrayRef<unsigned> Buffers) {
  if (IR.getSourceIndex() >= AsmSequence.size())
    return;

  const MCSchedModel &SM = STI.getSchedModel();
  std::pair<unsigned, int> BufferInfo = {0, -1};
  for (const unsigned Buffer : Buffers) {
    const MCProcResourceDesc &MCDesc = *SM.getProcResource(Buffer);
    if (!BufferInfo.first || BufferInfo.second > MCDesc.BufferSize) {
      BufferInfo.first = Buffer;
      BufferInfo.second = MCDesc.BufferSize;
    }
  }

  UsedBuffer[IR.getSourceIndex()] = BufferInfo;
}

void TimelineView::onEvent(const HWInstructionEvent &Event) {
  const unsigned Index = Event.IR.getSourceIndex();
  if (Index >= Timeline.size())
    return;

  switch (Event.Type) {
  case HWInstructionEvent::Retired: {
    TimelineViewEntry &TVEntry = Timeline[Index];
    if (CurrentCycle < MaxCycle)
      TVEntry.CycleRetired = CurrentCycle;

    // Update the WaitTime entry which corresponds to this Index.
    assert(TVEntry.CycleDispatched >= 0 && "Invalid TVEntry found!");
    unsigned CycleDispatched = static_cast<unsigned>(TVEntry.CycleDispatched);
    WaitTimeEntry &WTEntry = WaitTime[Index % AsmSequence.size()];
    WTEntry.CyclesSpentInSchedulerQueue +=
        TVEntry.CycleIssued - CycleDispatched;
    assert(CycleDispatched <= TVEntry.CycleReady &&
           "Instruction cannot be ready if it hasn't been dispatched yet!");
    WTEntry.CyclesSpentInSQWhileReady +=
        TVEntry.CycleIssued - TVEntry.CycleReady;
    WTEntry.CyclesSpentAfterWBAndBeforeRetire +=
        (CurrentCycle - 1) - TVEntry.CycleExecuted;
    break;
  }
  case HWInstructionEvent::Ready:
    Timeline[Index].CycleReady = CurrentCycle;
    break;
  case HWInstructionEvent::Issued:
    Timeline[Index].CycleIssued = CurrentCycle;
    break;
  case HWInstructionEvent::Executed:
    Timeline[Index].CycleExecuted = CurrentCycle;
    break;
  case HWInstructionEvent::Dispatched:
    // There may be multiple dispatch events. Microcoded instructions that are
    // expanded into multiple uOps may require multiple dispatch cycles. Here,
    // we want to capture the first dispatch cycle.
    if (Timeline[Index].CycleDispatched == -1)
      Timeline[Index].CycleDispatched = static_cast<int>(CurrentCycle);
    break;
  default:
    return;
  }
  if (CurrentCycle < MaxCycle)
    LastCycle = std::max(LastCycle, CurrentCycle);
}

static raw_ostream::Colors chooseColor(unsigned CumulativeCycles,
                                       unsigned Executions, int BufferSize) {
  if (CumulativeCycles && BufferSize < 0)
    return raw_ostream::MAGENTA;
  unsigned Size = static_cast<unsigned>(BufferSize);
  if (CumulativeCycles >= Size * Executions)
    return raw_ostream::RED;
  if ((CumulativeCycles * 2) >= Size * Executions)
    return raw_ostream::YELLOW;
  return raw_ostream::SAVEDCOLOR;
}

static void tryChangeColor(raw_ostream &OS, unsigned Cycles,
                           unsigned Executions, int BufferSize) {
  if (!OS.has_colors())
    return;

  raw_ostream::Colors Color = chooseColor(Cycles, Executions, BufferSize);
  if (Color == raw_ostream::SAVEDCOLOR) {
    OS.resetColor();
    return;
  }
  OS.changeColor(Color, /* bold */ true, /* BG */ false);
}

void TimelineView::printWaitTimeEntry(formatted_raw_ostream &OS,
                                      const WaitTimeEntry &Entry,
                                      unsigned SourceIndex,
                                      unsigned Executions) const {
  OS << SourceIndex << '.';
  OS.PadToColumn(7);

  double AverageTime1, AverageTime2, AverageTime3;
  AverageTime1 = (double)Entry.CyclesSpentInSchedulerQueue / Executions;
  AverageTime2 = (double)Entry.CyclesSpentInSQWhileReady / Executions;
  AverageTime3 = (double)Entry.CyclesSpentAfterWBAndBeforeRetire / Executions;

  OS << Executions;
  OS.PadToColumn(13);
  int BufferSize = UsedBuffer[SourceIndex].second;
  tryChangeColor(OS, Entry.CyclesSpentInSchedulerQueue, Executions, BufferSize);
  OS << format("%.1f", floor((AverageTime1 * 10) + 0.5) / 10);
  OS.PadToColumn(20);
  tryChangeColor(OS, Entry.CyclesSpentInSQWhileReady, Executions, BufferSize);
  OS << format("%.1f", floor((AverageTime2 * 10) + 0.5) / 10);
  OS.PadToColumn(27);
  tryChangeColor(OS, Entry.CyclesSpentAfterWBAndBeforeRetire, Executions,
                 STI.getSchedModel().MicroOpBufferSize);
  OS << format("%.1f", floor((AverageTime3 * 10) + 0.5) / 10);

  if (OS.has_colors())
    OS.resetColor();
  OS.PadToColumn(34);
}

void TimelineView::printAverageWaitTimes(raw_ostream &OS) const {
  std::string Header =
      "\n\nAverage Wait times (based on the timeline view):\n"
      "[0]: Executions\n"
      "[1]: Average time spent waiting in a scheduler's queue\n"
      "[2]: Average time spent waiting in a scheduler's queue while ready\n"
      "[3]: Average time elapsed from WB until retire stage\n\n"
      "      [0]    [1]    [2]    [3]\n";
  OS << Header;

  // Use a different string stream for printing instructions.
  std::string Instruction;
  raw_string_ostream InstrStream(Instruction);

  formatted_raw_ostream FOS(OS);
  unsigned Executions = Timeline.size() / AsmSequence.size();
  for (unsigned I = 0, E = WaitTime.size(); I < E; ++I) {
    printWaitTimeEntry(FOS, WaitTime[I], I, Executions);
    // Append the instruction info at the end of the line.
    const MCInst &Inst = AsmSequence.getMCInstFromIndex(I);

    MCIP.printInst(&Inst, InstrStream, "", STI);
    InstrStream.flush();

    // Consume any tabs or spaces at the beginning of the string.
    StringRef Str(Instruction);
    Str = Str.ltrim();
    FOS << "   " << Str << '\n';
    FOS.flush();
    Instruction = "";
  }
}

void TimelineView::printTimelineViewEntry(formatted_raw_ostream &OS,
                                          const TimelineViewEntry &Entry,
                                          unsigned Iteration,
                                          unsigned SourceIndex) const {
  if (Iteration == 0 && SourceIndex == 0)
    OS << '\n';
  OS << '[' << Iteration << ',' << SourceIndex << ']';
  OS.PadToColumn(10);
  assert(Entry.CycleDispatched >= 0 && "Invalid TimelineViewEntry!");
  unsigned CycleDispatched = static_cast<unsigned>(Entry.CycleDispatched);
  for (unsigned I = 0, E = CycleDispatched; I < E; ++I)
    OS << ((I % 5 == 0) ? '.' : ' ');
  OS << TimelineView::DisplayChar::Dispatched;
  if (CycleDispatched != Entry.CycleExecuted) {
    // Zero latency instructions have the same value for CycleDispatched,
    // CycleIssued and CycleExecuted.
    for (unsigned I = CycleDispatched + 1, E = Entry.CycleIssued; I < E; ++I)
      OS << TimelineView::DisplayChar::Waiting;
    if (Entry.CycleIssued == Entry.CycleExecuted)
      OS << TimelineView::DisplayChar::DisplayChar::Executed;
    else {
      if (CycleDispatched != Entry.CycleIssued)
        OS << TimelineView::DisplayChar::Executing;
      for (unsigned I = Entry.CycleIssued + 1, E = Entry.CycleExecuted; I < E;
           ++I)
        OS << TimelineView::DisplayChar::Executing;
      OS << TimelineView::DisplayChar::Executed;
    }
  }

  for (unsigned I = Entry.CycleExecuted + 1, E = Entry.CycleRetired; I < E; ++I)
    OS << TimelineView::DisplayChar::RetireLag;
  OS << TimelineView::DisplayChar::Retired;

  // Skip other columns.
  for (unsigned I = Entry.CycleRetired + 1, E = LastCycle; I <= E; ++I)
    OS << ((I % 5 == 0 || I == LastCycle) ? '.' : ' ');
}

static void printTimelineHeader(formatted_raw_ostream &OS, unsigned Cycles) {
  OS << "\n\nTimeline view:\n";
  if (Cycles >= 10) {
    OS.PadToColumn(10);
    for (unsigned I = 0; I <= Cycles; ++I) {
      if (((I / 10) & 1) == 0)
        OS << ' ';
      else
        OS << I % 10;
    }
    OS << '\n';
  }

  OS << "Index";
  OS.PadToColumn(10);
  for (unsigned I = 0; I <= Cycles; ++I) {
    if (((I / 10) & 1) == 0)
      OS << I % 10;
    else
      OS << ' ';
  }
  OS << '\n';
}

void TimelineView::printTimeline(raw_ostream &OS) const {
  formatted_raw_ostream FOS(OS);
  printTimelineHeader(FOS, LastCycle);
  FOS.flush();

  // Use a different string stream for the instruction.
  std::string Instruction;
  raw_string_ostream InstrStream(Instruction);

  for (unsigned I = 0, E = Timeline.size(); I < E; ++I) {
    const TimelineViewEntry &Entry = Timeline[I];
    if (Entry.CycleRetired == 0)
      return;

    unsigned Iteration = I / AsmSequence.size();
    unsigned SourceIndex = I % AsmSequence.size();
    printTimelineViewEntry(FOS, Entry, Iteration, SourceIndex);
    // Append the instruction info at the end of the line.
    const MCInst &Inst = AsmSequence.getMCInstFromIndex(I);
    MCIP.printInst(&Inst, InstrStream, "", STI);
    InstrStream.flush();

    // Consume any tabs or spaces at the beginning of the string.
    StringRef Str(Instruction);
    Str = Str.ltrim();
    FOS << "   " << Str << '\n';
    FOS.flush();
    Instruction = "";
  }
}
} // namespace mca
<commit_msg>[llvm-mca] correctly initialize field 'CycleRetired' in the TimelineView.<commit_after>//===--------------------- TimelineView.cpp ---------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \brief
///
/// This file implements the TimelineView interface.
///
//===----------------------------------------------------------------------===//

#include "Views/TimelineView.h"

using namespace llvm;

namespace mca {

TimelineView::TimelineView(const MCSubtargetInfo &sti, MCInstPrinter &Printer,
                           const SourceMgr &S, unsigned MaxIterations,
                           unsigned Cycles)
    : STI(sti), MCIP(Printer), AsmSequence(S), CurrentCycle(0),
      MaxCycle(Cycles == 0 ? 80 : Cycles), LastCycle(0), WaitTime(S.size()),
      UsedBuffer(S.size()) {
  unsigned NumInstructions = AsmSequence.size();
  if (!MaxIterations)
    MaxIterations = DEFAULT_ITERATIONS;
  NumInstructions *= std::min(MaxIterations, AsmSequence.getNumIterations());
  Timeline.resize(NumInstructions);
  TimelineViewEntry InvalidTVEntry = {-1, 0, 0, 0, 0};
  std::fill(Timeline.begin(), Timeline.end(), InvalidTVEntry);

  WaitTimeEntry NullWTEntry = {0, 0, 0};
  std::fill(WaitTime.begin(), WaitTime.end(), NullWTEntry);

  std::pair<unsigned, int> NullUsedBufferEntry = {/* Invalid resource ID*/ 0,
                                                  /* unknown buffer size */ -1};
  std::fill(UsedBuffer.begin(), UsedBuffer.end(), NullUsedBufferEntry);
}

void TimelineView::onReservedBuffers(const InstRef &IR,
                                     ArrayRef<unsigned> Buffers) {
  if (IR.getSourceIndex() >= AsmSequence.size())
    return;

  const MCSchedModel &SM = STI.getSchedModel();
  std::pair<unsigned, int> BufferInfo = {0, -1};
  for (const unsigned Buffer : Buffers) {
    const MCProcResourceDesc &MCDesc = *SM.getProcResource(Buffer);
    if (!BufferInfo.first || BufferInfo.second > MCDesc.BufferSize) {
      BufferInfo.first = Buffer;
      BufferInfo.second = MCDesc.BufferSize;
    }
  }

  UsedBuffer[IR.getSourceIndex()] = BufferInfo;
}

void TimelineView::onEvent(const HWInstructionEvent &Event) {
  const unsigned Index = Event.IR.getSourceIndex();
  if (Index >= Timeline.size())
    return;

  switch (Event.Type) {
  case HWInstructionEvent::Retired: {
    TimelineViewEntry &TVEntry = Timeline[Index];
    if (CurrentCycle < MaxCycle)
      TVEntry.CycleRetired = CurrentCycle;

    // Update the WaitTime entry which corresponds to this Index.
    assert(TVEntry.CycleDispatched >= 0 && "Invalid TVEntry found!");
    unsigned CycleDispatched = static_cast<unsigned>(TVEntry.CycleDispatched);
    WaitTimeEntry &WTEntry = WaitTime[Index % AsmSequence.size()];
    WTEntry.CyclesSpentInSchedulerQueue +=
        TVEntry.CycleIssued - CycleDispatched;
    assert(CycleDispatched <= TVEntry.CycleReady &&
           "Instruction cannot be ready if it hasn't been dispatched yet!");
    WTEntry.CyclesSpentInSQWhileReady +=
        TVEntry.CycleIssued - TVEntry.CycleReady;
    WTEntry.CyclesSpentAfterWBAndBeforeRetire +=
        (CurrentCycle - 1) - TVEntry.CycleExecuted;
    break;
  }
  case HWInstructionEvent::Ready:
    Timeline[Index].CycleReady = CurrentCycle;
    break;
  case HWInstructionEvent::Issued:
    Timeline[Index].CycleIssued = CurrentCycle;
    break;
  case HWInstructionEvent::Executed:
    Timeline[Index].CycleExecuted = CurrentCycle;
    break;
  case HWInstructionEvent::Dispatched:
    // There may be multiple dispatch events. Microcoded instructions that are
    // expanded into multiple uOps may require multiple dispatch cycles. Here,
    // we want to capture the first dispatch cycle.
    if (Timeline[Index].CycleDispatched == -1)
      Timeline[Index].CycleDispatched = static_cast<int>(CurrentCycle);
    break;
  default:
    return;
  }
  if (CurrentCycle < MaxCycle)
    LastCycle = std::max(LastCycle, CurrentCycle);
}

static raw_ostream::Colors chooseColor(unsigned CumulativeCycles,
                                       unsigned Executions, int BufferSize) {
  if (CumulativeCycles && BufferSize < 0)
    return raw_ostream::MAGENTA;
  unsigned Size = static_cast<unsigned>(BufferSize);
  if (CumulativeCycles >= Size * Executions)
    return raw_ostream::RED;
  if ((CumulativeCycles * 2) >= Size * Executions)
    return raw_ostream::YELLOW;
  return raw_ostream::SAVEDCOLOR;
}

static void tryChangeColor(raw_ostream &OS, unsigned Cycles,
                           unsigned Executions, int BufferSize) {
  if (!OS.has_colors())
    return;

  raw_ostream::Colors Color = chooseColor(Cycles, Executions, BufferSize);
  if (Color == raw_ostream::SAVEDCOLOR) {
    OS.resetColor();
    return;
  }
  OS.changeColor(Color, /* bold */ true, /* BG */ false);
}

void TimelineView::printWaitTimeEntry(formatted_raw_ostream &OS,
                                      const WaitTimeEntry &Entry,
                                      unsigned SourceIndex,
                                      unsigned Executions) const {
  OS << SourceIndex << '.';
  OS.PadToColumn(7);

  double AverageTime1, AverageTime2, AverageTime3;
  AverageTime1 = (double)Entry.CyclesSpentInSchedulerQueue / Executions;
  AverageTime2 = (double)Entry.CyclesSpentInSQWhileReady / Executions;
  AverageTime3 = (double)Entry.CyclesSpentAfterWBAndBeforeRetire / Executions;

  OS << Executions;
  OS.PadToColumn(13);
  int BufferSize = UsedBuffer[SourceIndex].second;
  tryChangeColor(OS, Entry.CyclesSpentInSchedulerQueue, Executions, BufferSize);
  OS << format("%.1f", floor((AverageTime1 * 10) + 0.5) / 10);
  OS.PadToColumn(20);
  tryChangeColor(OS, Entry.CyclesSpentInSQWhileReady, Executions, BufferSize);
  OS << format("%.1f", floor((AverageTime2 * 10) + 0.5) / 10);
  OS.PadToColumn(27);
  tryChangeColor(OS, Entry.CyclesSpentAfterWBAndBeforeRetire, Executions,
                 STI.getSchedModel().MicroOpBufferSize);
  OS << format("%.1f", floor((AverageTime3 * 10) + 0.5) / 10);

  if (OS.has_colors())
    OS.resetColor();
  OS.PadToColumn(34);
}

void TimelineView::printAverageWaitTimes(raw_ostream &OS) const {
  std::string Header =
      "\n\nAverage Wait times (based on the timeline view):\n"
      "[0]: Executions\n"
      "[1]: Average time spent waiting in a scheduler's queue\n"
      "[2]: Average time spent waiting in a scheduler's queue while ready\n"
      "[3]: Average time elapsed from WB until retire stage\n\n"
      "      [0]    [1]    [2]    [3]\n";
  OS << Header;

  // Use a different string stream for printing instructions.
  std::string Instruction;
  raw_string_ostream InstrStream(Instruction);

  formatted_raw_ostream FOS(OS);
  unsigned Executions = Timeline.size() / AsmSequence.size();
  for (unsigned I = 0, E = WaitTime.size(); I < E; ++I) {
    printWaitTimeEntry(FOS, WaitTime[I], I, Executions);
    // Append the instruction info at the end of the line.
    const MCInst &Inst = AsmSequence.getMCInstFromIndex(I);

    MCIP.printInst(&Inst, InstrStream, "", STI);
    InstrStream.flush();

    // Consume any tabs or spaces at the beginning of the string.
    StringRef Str(Instruction);
    Str = Str.ltrim();
    FOS << "   " << Str << '\n';
    FOS.flush();
    Instruction = "";
  }
}

void TimelineView::printTimelineViewEntry(formatted_raw_ostream &OS,
                                          const TimelineViewEntry &Entry,
                                          unsigned Iteration,
                                          unsigned SourceIndex) const {
  if (Iteration == 0 && SourceIndex == 0)
    OS << '\n';
  OS << '[' << Iteration << ',' << SourceIndex << ']';
  OS.PadToColumn(10);
  assert(Entry.CycleDispatched >= 0 && "Invalid TimelineViewEntry!");
  unsigned CycleDispatched = static_cast<unsigned>(Entry.CycleDispatched);
  for (unsigned I = 0, E = CycleDispatched; I < E; ++I)
    OS << ((I % 5 == 0) ? '.' : ' ');
  OS << TimelineView::DisplayChar::Dispatched;
  if (CycleDispatched != Entry.CycleExecuted) {
    // Zero latency instructions have the same value for CycleDispatched,
    // CycleIssued and CycleExecuted.
    for (unsigned I = CycleDispatched + 1, E = Entry.CycleIssued; I < E; ++I)
      OS << TimelineView::DisplayChar::Waiting;
    if (Entry.CycleIssued == Entry.CycleExecuted)
      OS << TimelineView::DisplayChar::DisplayChar::Executed;
    else {
      if (CycleDispatched != Entry.CycleIssued)
        OS << TimelineView::DisplayChar::Executing;
      for (unsigned I = Entry.CycleIssued + 1, E = Entry.CycleExecuted; I < E;
           ++I)
        OS << TimelineView::DisplayChar::Executing;
      OS << TimelineView::DisplayChar::Executed;
    }
  }

  for (unsigned I = Entry.CycleExecuted + 1, E = Entry.CycleRetired; I < E; ++I)
    OS << TimelineView::DisplayChar::RetireLag;
  OS << TimelineView::DisplayChar::Retired;

  // Skip other columns.
  for (unsigned I = Entry.CycleRetired + 1, E = LastCycle; I <= E; ++I)
    OS << ((I % 5 == 0 || I == LastCycle) ? '.' : ' ');
}

static void printTimelineHeader(formatted_raw_ostream &OS, unsigned Cycles) {
  OS << "\n\nTimeline view:\n";
  if (Cycles >= 10) {
    OS.PadToColumn(10);
    for (unsigned I = 0; I <= Cycles; ++I) {
      if (((I / 10) & 1) == 0)
        OS << ' ';
      else
        OS << I % 10;
    }
    OS << '\n';
  }

  OS << "Index";
  OS.PadToColumn(10);
  for (unsigned I = 0; I <= Cycles; ++I) {
    if (((I / 10) & 1) == 0)
      OS << I % 10;
    else
      OS << ' ';
  }
  OS << '\n';
}

void TimelineView::printTimeline(raw_ostream &OS) const {
  formatted_raw_ostream FOS(OS);
  printTimelineHeader(FOS, LastCycle);
  FOS.flush();

  // Use a different string stream for the instruction.
  std::string Instruction;
  raw_string_ostream InstrStream(Instruction);

  for (unsigned I = 0, E = Timeline.size(); I < E; ++I) {
    const TimelineViewEntry &Entry = Timeline[I];
    if (Entry.CycleRetired == 0)
      return;

    unsigned Iteration = I / AsmSequence.size();
    unsigned SourceIndex = I % AsmSequence.size();
    printTimelineViewEntry(FOS, Entry, Iteration, SourceIndex);
    // Append the instruction info at the end of the line.
    const MCInst &Inst = AsmSequence.getMCInstFromIndex(I);
    MCIP.printInst(&Inst, InstrStream, "", STI);
    InstrStream.flush();

    // Consume any tabs or spaces at the beginning of the string.
    StringRef Str(Instruction);
    Str = Str.ltrim();
    FOS << "   " << Str << '\n';
    FOS.flush();
    Instruction = "";
  }
}
} // namespace mca
<|endoftext|>


<commit_before>// -----------------------------------------------------------------------
// pion-common: a collection of common libraries used by the Pion Platform
// -----------------------------------------------------------------------
// Copyright (C) 2007 Atomic Labs, Inc.  (http://www.atomiclabs.com)
//
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file COPYING or copy at http://www.boost.org/LICENSE_1_0.txt
//

#ifndef __PION_PIONLOGGER_HEADER__
#define __PION_PIONLOGGER_HEADER__

#include <pion/PionConfig.hpp>

#if defined(PION_HAVE_LOG4CXX)

	// unfortunately, the current version of log4cxx has many problems that
	// produce very annoying warnings

	// this disables warnings before preprocessing the log4cxx headers
	#if defined __GNUC__
		#pragma GCC system_header
	#elif defined __SUNPRO_CC
		#pragma disable_warn
	#elif defined _MSC_VER
		#pragma warning(push, 1)
	#endif

	// log4cxx headers
	#include <log4cxx/logger.h>
	#include <log4cxx/basicconfigurator.h>

	// this re-enables warnings
	#if defined __SUNPRO_CC
		#pragma enable_warn
	#elif defined _MSC_VER
		#pragma warning(pop)
	#endif

	#if defined _MSC_VER
		#if defined _DEBUG
			#pragma comment(lib, "log4cxxd")
			#pragma comment(lib, "aprd")
		#else
			#pragma comment(lib, "log4cxx")
			#pragma comment(lib, "apr")
		#endif
		#pragma comment(lib, "odbc32")
	#endif

	namespace pion {
		typedef log4cxx::LoggerPtr	PionLogger;
	}

	#define PION_LOG_CONFIG_BASIC	log4cxx::BasicConfigurator::configure();
	#define PION_GET_LOGGER(NAME)	log4cxx::Logger::getLogger(NAME)

	#define PION_LOG_SETLEVEL_DEBUG(LOG)	LOG->setLevel(log4cxx::Level::toLevel(log4cxx::Level::DEBUG_INT));
	#define PION_LOG_SETLEVEL_INFO(LOG)		LOG->setLevel(log4cxx::Level::toLevel(log4cxx::Level::INFO_INT));
	#define PION_LOG_SETLEVEL_WARN(LOG)		LOG->setLevel(log4cxx::Level::toLevel(log4cxx::Level::WARN_INT));
	#define PION_LOG_SETLEVEL_ERROR(LOG)	LOG->setLevel(log4cxx::Level::toLevel(log4cxx::Level::ERROR_INT));
	#define PION_LOG_SETLEVEL_FATAL(LOG)	LOG->setLevel(log4cxx::Level::toLevel(log4cxx::Level::FATAL_INT));

	#define PION_LOG_DEBUG	LOG4CXX_DEBUG
	#define PION_LOG_INFO	LOG4CXX_INFO
	#define PION_LOG_WARN	LOG4CXX_WARN
	#define PION_LOG_ERROR	LOG4CXX_ERROR
	#define PION_LOG_FATAL	LOG4CXX_FATAL

#elif defined(PION_HAVE_LOG4CPLUS)

	// log4cplus headers
	#include <log4cplus/logger.h>
	#include <log4cplus/configurator.h>

	namespace pion {
		typedef log4cplus::Logger	PionLogger;
	}

	#define PION_LOG_CONFIG_BASIC	log4cplus::BasicConfigurator::doConfigure();
	#define PION_GET_LOGGER(NAME)	log4cplus::Logger::getInstance(NAME)

	#define PION_LOG_SETLEVEL_DEBUG(LOG)	LOG.setLogLevel(log4cplus::DEBUG_LOG_LEVEL);
	#define PION_LOG_SETLEVEL_INFO(LOG)		LOG.setLogLevel(log4cplus::INFO_LOG_LEVEL);
	#define PION_LOG_SETLEVEL_WARN(LOG)		LOG.setLogLevel(log4cplus::WARN_LOG_LEVEL);
	#define PION_LOG_SETLEVEL_ERROR(LOG)	LOG.setLogLevel(log4cplus::ERROR_LOG_LEVEL);
	#define PION_LOG_SETLEVEL_FATAL(LOG)	LOG.setLogLevel(log4cplus::FATAL_LOG_LEVEL);

	#define PION_LOG_DEBUG	LOG4CPLUS_DEBUG
	#define PION_LOG_INFO	LOG4CPLUS_INFO
	#define PION_LOG_WARN	LOG4CPLUS_WARN
	#define PION_LOG_ERROR	LOG4CPLUS_ERROR
	#define PION_LOG_FATAL	LOG4CPLUS_FATAL

#elif defined(PION_HAVE_LOG4CPP)

	// log4cpp headers
	#include <log4cpp/Category.hh>
	#include <log4cpp/BasicLayout.hh>
	#include <log4cpp/OstreamAppender.hh>

	namespace pion {
		typedef log4cpp::Category*	PionLogger;
	}

	#define PION_LOG_CONFIG_BASIC	{ log4cpp::OstreamAppender *app = new log4cpp::OstreamAppender("cout", &std::cout); app->setLayout(new log4cpp::BasicLayout()); log4cpp::Category::getRoot().setAppender(app); }
	#define PION_GET_LOGGER(NAME)	(&log4cpp::Category::getInstance(NAME))

	#define PION_LOG_SETLEVEL_DEBUG(LOG)	{ LOG->setPriority(log4cpp::Priority::DEBUG); }
	#define PION_LOG_SETLEVEL_INFO(LOG)		{ LOG->setPriority(log4cpp::Priority::INFO); }
	#define PION_LOG_SETLEVEL_WARN(LOG)		{ LOG->setPriority(log4cpp::Priority::WARN); }
	#define PION_LOG_SETLEVEL_ERROR(LOG)	{ LOG->setPriority(log4cpp::Priority::ERROR); }
	#define PION_LOG_SETLEVEL_FATAL(LOG)	{ LOG->setPriority(log4cpp::Priority::FATAL); }

	#define PION_LOG_DEBUG(LOG, MSG)	if (LOG->getPriority()>=log4cpp::Priority::DEBUG) { LOG->debugStream() << MSG; }
	#define PION_LOG_INFO(LOG, MSG)		if (LOG->getPriority()>=log4cpp::Priority::INFO) { LOG->infoStream() << MSG; }
	#define PION_LOG_WARN(LOG, MSG)		if (LOG->getPriority()>=log4cpp::Priority::WARN) { LOG->warnStream() << MSG; }
	#define PION_LOG_ERROR(LOG, MSG)	if (LOG->getPriority()>=log4cpp::Priority::ERROR) { LOG->errorStream() << MSG; }
	#define PION_LOG_FATAL(LOG, MSG)	if (LOG->getPriority()>=log4cpp::Priority::FATAL) { LOG->fatalStream() << MSG; }

#elif defined(PION_HAVE_OSTREAM_LOGGING)

	// Logging uses std::cout and std::cerr
	#include <iostream>
	#include <string>
	#include <ctime>

	namespace pion {
		struct PionLogger {
			enum PionPriorityType {
				LOG_LEVEL_DEBUG, LOG_LEVEL_INFO, LOG_LEVEL_WARN,
				LOG_LEVEL_ERROR, LOG_LEVEL_FATAL
			};
			~PionLogger() {}
			PionLogger(void) : m_name("pion") {}
			PionLogger(const std::string& name) : m_name(name) {}
			PionLogger(const PionLogger& p) : m_name(p.m_name) {}
			std::string					m_name;
			static PionPriorityType		m_priority;
		};
	}

	#define PION_LOG_CONFIG_BASIC	{}
	#define PION_GET_LOGGER(NAME)	pion::PionLogger(NAME)

	#define PION_LOG_SETLEVEL_DEBUG(LOG)	{ LOG.m_priority = pion::PionLogger::LOG_LEVEL_DEBUG; }
	#define PION_LOG_SETLEVEL_INFO(LOG)		{ LOG.m_priority = pion::PionLogger::LOG_LEVEL_INFO; }
	#define PION_LOG_SETLEVEL_WARN(LOG)		{ LOG.m_priority = pion::PionLogger::LOG_LEVEL_WARN; }
	#define PION_LOG_SETLEVEL_ERROR(LOG)	{ LOG.m_priority = pion::PionLogger::LOG_LEVEL_ERROR; }
	#define PION_LOG_SETLEVEL_FATAL(LOG)	{ LOG.m_priority = pion::PionLogger::LOG_LEVEL_FATAL; }

	#define PION_LOG_DEBUG(LOG, MSG)	if (LOG.m_priority <= pion::PionLogger::LOG_LEVEL_DEBUG) { std::cout << time(NULL) << " DEBUG " << LOG.m_name << ' ' << MSG << std::endl; }
	#define PION_LOG_INFO(LOG, MSG)		if (LOG.m_priority <= pion::PionLogger::LOG_LEVEL_INFO) { std::cout << time(NULL) << " INFO " << LOG.m_name << ' ' << MSG << std::endl; }
	#define PION_LOG_WARN(LOG, MSG)		if (LOG.m_priority <= pion::PionLogger::LOG_LEVEL_WARN) { std::cerr << time(NULL) << " WARN " << LOG.m_name << ' ' << MSG << std::endl; }
	#define PION_LOG_ERROR(LOG, MSG)	if (LOG.m_priority <= pion::PionLogger::LOG_LEVEL_ERROR) { std::cerr << time(NULL) << " ERROR " << LOG.m_name << ' ' << MSG << std::endl; }
	#define PION_LOG_FATAL(LOG, MSG)	if (LOG.m_priority <= pion::PionLogger::LOG_LEVEL_FATAL) { std::cerr << time(NULL) << " FATAL " << LOG.m_name << ' ' << MSG << std::endl; }

#else

	// Logging is disabled -> add do-nothing stubs for logging
	namespace pion {
		typedef int		PionLogger;
	}

	#define PION_LOG_CONFIG_BASIC	{}
	#define PION_GET_LOGGER(NAME)	0

	// use "++LOG" to avoid warnings about LOG not being used
	#define PION_LOG_SETLEVEL_DEBUG(LOG)	{ if (false) ++LOG; }
	#define PION_LOG_SETLEVEL_INFO(LOG)		{ if (false) ++LOG; }
	#define PION_LOG_SETLEVEL_WARN(LOG)		{ if (false) ++LOG; }
	#define PION_LOG_SETLEVEL_ERROR(LOG)	{ if (false) ++LOG; }
	#define PION_LOG_SETLEVEL_FATAL(LOG)	{ if (false) ++LOG; }

	// use "++LOG" to avoid warnings about LOG not being used
	#define PION_LOG_DEBUG(LOG, MSG)	{ if (false) ++LOG; }
	#define PION_LOG_INFO(LOG, MSG)		{ if (false) ++LOG; }
	#define PION_LOG_WARN(LOG, MSG)		{ if (false) ++LOG; }
	#define PION_LOG_ERROR(LOG, MSG)	{ if (false) ++LOG; }
	#define PION_LOG_FATAL(LOG, MSG)	{ if (false) ++LOG; }

#endif

#endif
<commit_msg>Added PION_COMMON_API declaration to struct pion::PionLogger.<commit_after>// -----------------------------------------------------------------------
// pion-common: a collection of common libraries used by the Pion Platform
// -----------------------------------------------------------------------
// Copyright (C) 2007 Atomic Labs, Inc.  (http://www.atomiclabs.com)
//
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file COPYING or copy at http://www.boost.org/LICENSE_1_0.txt
//

#ifndef __PION_PIONLOGGER_HEADER__
#define __PION_PIONLOGGER_HEADER__

#include <pion/PionConfig.hpp>

#if defined(PION_HAVE_LOG4CXX)

	// unfortunately, the current version of log4cxx has many problems that
	// produce very annoying warnings

	// this disables warnings before preprocessing the log4cxx headers
	#if defined __GNUC__
		#pragma GCC system_header
	#elif defined __SUNPRO_CC
		#pragma disable_warn
	#elif defined _MSC_VER
		#pragma warning(push, 1)
	#endif

	// log4cxx headers
	#include <log4cxx/logger.h>
	#include <log4cxx/basicconfigurator.h>

	// this re-enables warnings
	#if defined __SUNPRO_CC
		#pragma enable_warn
	#elif defined _MSC_VER
		#pragma warning(pop)
	#endif

	#if defined _MSC_VER
		#if defined _DEBUG
			#pragma comment(lib, "log4cxxd")
			#pragma comment(lib, "aprd")
		#else
			#pragma comment(lib, "log4cxx")
			#pragma comment(lib, "apr")
		#endif
		#pragma comment(lib, "odbc32")
	#endif

	namespace pion {
		typedef log4cxx::LoggerPtr	PionLogger;
	}

	#define PION_LOG_CONFIG_BASIC	log4cxx::BasicConfigurator::configure();
	#define PION_GET_LOGGER(NAME)	log4cxx::Logger::getLogger(NAME)

	#define PION_LOG_SETLEVEL_DEBUG(LOG)	LOG->setLevel(log4cxx::Level::toLevel(log4cxx::Level::DEBUG_INT));
	#define PION_LOG_SETLEVEL_INFO(LOG)		LOG->setLevel(log4cxx::Level::toLevel(log4cxx::Level::INFO_INT));
	#define PION_LOG_SETLEVEL_WARN(LOG)		LOG->setLevel(log4cxx::Level::toLevel(log4cxx::Level::WARN_INT));
	#define PION_LOG_SETLEVEL_ERROR(LOG)	LOG->setLevel(log4cxx::Level::toLevel(log4cxx::Level::ERROR_INT));
	#define PION_LOG_SETLEVEL_FATAL(LOG)	LOG->setLevel(log4cxx::Level::toLevel(log4cxx::Level::FATAL_INT));

	#define PION_LOG_DEBUG	LOG4CXX_DEBUG
	#define PION_LOG_INFO	LOG4CXX_INFO
	#define PION_LOG_WARN	LOG4CXX_WARN
	#define PION_LOG_ERROR	LOG4CXX_ERROR
	#define PION_LOG_FATAL	LOG4CXX_FATAL

#elif defined(PION_HAVE_LOG4CPLUS)

	// log4cplus headers
	#include <log4cplus/logger.h>
	#include <log4cplus/configurator.h>

	namespace pion {
		typedef log4cplus::Logger	PionLogger;
	}

	#define PION_LOG_CONFIG_BASIC	log4cplus::BasicConfigurator::doConfigure();
	#define PION_GET_LOGGER(NAME)	log4cplus::Logger::getInstance(NAME)

	#define PION_LOG_SETLEVEL_DEBUG(LOG)	LOG.setLogLevel(log4cplus::DEBUG_LOG_LEVEL);
	#define PION_LOG_SETLEVEL_INFO(LOG)		LOG.setLogLevel(log4cplus::INFO_LOG_LEVEL);
	#define PION_LOG_SETLEVEL_WARN(LOG)		LOG.setLogLevel(log4cplus::WARN_LOG_LEVEL);
	#define PION_LOG_SETLEVEL_ERROR(LOG)	LOG.setLogLevel(log4cplus::ERROR_LOG_LEVEL);
	#define PION_LOG_SETLEVEL_FATAL(LOG)	LOG.setLogLevel(log4cplus::FATAL_LOG_LEVEL);

	#define PION_LOG_DEBUG	LOG4CPLUS_DEBUG
	#define PION_LOG_INFO	LOG4CPLUS_INFO
	#define PION_LOG_WARN	LOG4CPLUS_WARN
	#define PION_LOG_ERROR	LOG4CPLUS_ERROR
	#define PION_LOG_FATAL	LOG4CPLUS_FATAL

#elif defined(PION_HAVE_LOG4CPP)

	// log4cpp headers
	#include <log4cpp/Category.hh>
	#include <log4cpp/BasicLayout.hh>
	#include <log4cpp/OstreamAppender.hh>

	namespace pion {
		typedef log4cpp::Category*	PionLogger;
	}

	#define PION_LOG_CONFIG_BASIC	{ log4cpp::OstreamAppender *app = new log4cpp::OstreamAppender("cout", &std::cout); app->setLayout(new log4cpp::BasicLayout()); log4cpp::Category::getRoot().setAppender(app); }
	#define PION_GET_LOGGER(NAME)	(&log4cpp::Category::getInstance(NAME))

	#define PION_LOG_SETLEVEL_DEBUG(LOG)	{ LOG->setPriority(log4cpp::Priority::DEBUG); }
	#define PION_LOG_SETLEVEL_INFO(LOG)		{ LOG->setPriority(log4cpp::Priority::INFO); }
	#define PION_LOG_SETLEVEL_WARN(LOG)		{ LOG->setPriority(log4cpp::Priority::WARN); }
	#define PION_LOG_SETLEVEL_ERROR(LOG)	{ LOG->setPriority(log4cpp::Priority::ERROR); }
	#define PION_LOG_SETLEVEL_FATAL(LOG)	{ LOG->setPriority(log4cpp::Priority::FATAL); }

	#define PION_LOG_DEBUG(LOG, MSG)	if (LOG->getPriority()>=log4cpp::Priority::DEBUG) { LOG->debugStream() << MSG; }
	#define PION_LOG_INFO(LOG, MSG)		if (LOG->getPriority()>=log4cpp::Priority::INFO) { LOG->infoStream() << MSG; }
	#define PION_LOG_WARN(LOG, MSG)		if (LOG->getPriority()>=log4cpp::Priority::WARN) { LOG->warnStream() << MSG; }
	#define PION_LOG_ERROR(LOG, MSG)	if (LOG->getPriority()>=log4cpp::Priority::ERROR) { LOG->errorStream() << MSG; }
	#define PION_LOG_FATAL(LOG, MSG)	if (LOG->getPriority()>=log4cpp::Priority::FATAL) { LOG->fatalStream() << MSG; }

#elif defined(PION_HAVE_OSTREAM_LOGGING)

	// Logging uses std::cout and std::cerr
	#include <iostream>
	#include <string>
	#include <ctime>

	namespace pion {
		struct PION_COMMON_API PionLogger {
			enum PionPriorityType {
				LOG_LEVEL_DEBUG, LOG_LEVEL_INFO, LOG_LEVEL_WARN,
				LOG_LEVEL_ERROR, LOG_LEVEL_FATAL
			};
			~PionLogger() {}
			PionLogger(void) : m_name("pion") {}
			PionLogger(const std::string& name) : m_name(name) {}
			PionLogger(const PionLogger& p) : m_name(p.m_name) {}
			std::string					m_name;
			static PionPriorityType		m_priority;
		};
	}

	#define PION_LOG_CONFIG_BASIC	{}
	#define PION_GET_LOGGER(NAME)	pion::PionLogger(NAME)

	#define PION_LOG_SETLEVEL_DEBUG(LOG)	{ LOG.m_priority = pion::PionLogger::LOG_LEVEL_DEBUG; }
	#define PION_LOG_SETLEVEL_INFO(LOG)		{ LOG.m_priority = pion::PionLogger::LOG_LEVEL_INFO; }
	#define PION_LOG_SETLEVEL_WARN(LOG)		{ LOG.m_priority = pion::PionLogger::LOG_LEVEL_WARN; }
	#define PION_LOG_SETLEVEL_ERROR(LOG)	{ LOG.m_priority = pion::PionLogger::LOG_LEVEL_ERROR; }
	#define PION_LOG_SETLEVEL_FATAL(LOG)	{ LOG.m_priority = pion::PionLogger::LOG_LEVEL_FATAL; }

	#define PION_LOG_DEBUG(LOG, MSG)	if (LOG.m_priority <= pion::PionLogger::LOG_LEVEL_DEBUG) { std::cout << time(NULL) << " DEBUG " << LOG.m_name << ' ' << MSG << std::endl; }
	#define PION_LOG_INFO(LOG, MSG)		if (LOG.m_priority <= pion::PionLogger::LOG_LEVEL_INFO) { std::cout << time(NULL) << " INFO " << LOG.m_name << ' ' << MSG << std::endl; }
	#define PION_LOG_WARN(LOG, MSG)		if (LOG.m_priority <= pion::PionLogger::LOG_LEVEL_WARN) { std::cerr << time(NULL) << " WARN " << LOG.m_name << ' ' << MSG << std::endl; }
	#define PION_LOG_ERROR(LOG, MSG)	if (LOG.m_priority <= pion::PionLogger::LOG_LEVEL_ERROR) { std::cerr << time(NULL) << " ERROR " << LOG.m_name << ' ' << MSG << std::endl; }
	#define PION_LOG_FATAL(LOG, MSG)	if (LOG.m_priority <= pion::PionLogger::LOG_LEVEL_FATAL) { std::cerr << time(NULL) << " FATAL " << LOG.m_name << ' ' << MSG << std::endl; }

#else

	// Logging is disabled -> add do-nothing stubs for logging
	namespace pion {
		typedef int		PionLogger;
	}

	#define PION_LOG_CONFIG_BASIC	{}
	#define PION_GET_LOGGER(NAME)	0

	// use "++LOG" to avoid warnings about LOG not being used
	#define PION_LOG_SETLEVEL_DEBUG(LOG)	{ if (false) ++LOG; }
	#define PION_LOG_SETLEVEL_INFO(LOG)		{ if (false) ++LOG; }
	#define PION_LOG_SETLEVEL_WARN(LOG)		{ if (false) ++LOG; }
	#define PION_LOG_SETLEVEL_ERROR(LOG)	{ if (false) ++LOG; }
	#define PION_LOG_SETLEVEL_FATAL(LOG)	{ if (false) ++LOG; }

	// use "++LOG" to avoid warnings about LOG not being used
	#define PION_LOG_DEBUG(LOG, MSG)	{ if (false) ++LOG; }
	#define PION_LOG_INFO(LOG, MSG)		{ if (false) ++LOG; }
	#define PION_LOG_WARN(LOG, MSG)		{ if (false) ++LOG; }
	#define PION_LOG_ERROR(LOG, MSG)	{ if (false) ++LOG; }
	#define PION_LOG_FATAL(LOG, MSG)	{ if (false) ++LOG; }

#endif

#endif
<|endoftext|>