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

#include "chrome/common/extensions/extension_action.h"

#include <algorithm>

#include "app/resource_bundle.h"
#include "base/logging.h"
#include "base/utf_string_conversions.h"
#include "gfx/canvas_skia.h"
#include "gfx/font.h"
#include "gfx/rect.h"
#include "googleurl/src/gurl.h"
#include "grit/app_resources.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkTypeface.h"
#include "third_party/skia/include/effects/SkGradientShader.h"

namespace {

// Different platforms need slightly different constants to look good.
#if defined(OS_LINUX) && !defined(TOOLKIT_VIEWS)
const float kTextSize = 9.0;
const int kBottomMargin = 0;
const int kPadding = 2;
const int kTopTextPadding = 0;
#elif defined(OS_LINUX) && defined(TOOLKIT_VIEWS)
const float kTextSize = 8.0;
const int kBottomMargin = 5;
const int kPadding = 2;
const int kTopTextPadding = 1;
#elif defined(OS_MACOSX)
const float kTextSize = 9.0;
const int kBottomMargin = 5;
const int kPadding = 2;
const int kTopTextPadding = 0;
#else
const float kTextSize = 7.5;
const int kBottomMargin = 5;
const int kPadding = 2;
// The padding between the top of the badge and the top of the text.
const int kTopTextPadding = 1;
#endif

const int kBadgeHeight = 11;
const int kMaxTextWidth = 23;
// The minimum width for center-aligning the badge.
const int kCenterAlignThreshold = 20;

#if defined(OS_MACOSX)
const char kPreferredTypeface[] = "Helvetica Bold";
#else
const char kPreferredTypeface[] = "Arial";
#endif

SkPaint* GetTextPaint() {
  static SkPaint* text_paint = NULL;
  if (!text_paint) {
    text_paint = new SkPaint;
    text_paint->setAntiAlias(true);

    text_paint->setTextAlign(SkPaint::kLeft_Align);
    text_paint->setTextSize(SkFloatToScalar(kTextSize));

    SkTypeface* typeface = SkTypeface::CreateFromName(
        kPreferredTypeface, SkTypeface::kBold);
    // Skia doesn't do any font fallback---if the user is missing the font then
    // typeface will be NULL. If we don't do manual fallback then we'll crash.
    if (typeface) {
      text_paint->setFakeBoldText(true);
    } else {
      // Fall back to the system font. We don't bold it because we aren't sure
      // how it will look.
      // For the most part this code path will only be hit on Linux systems
      // that don't have Arial.
      ResourceBundle& rb = ResourceBundle::GetSharedInstance();
      const gfx::Font& base_font = rb.GetFont(ResourceBundle::BaseFont);
      typeface = SkTypeface::CreateFromName(
          WideToUTF8(base_font.GetFontName()).c_str(), SkTypeface::kNormal);
    }

    text_paint->setTypeface(typeface);
    // |text_paint| adds its own ref. Release the ref from CreateFontName.
    typeface->unref();
  }
  return text_paint;
}

}  // namespace

const int ExtensionAction::kDefaultTabId = -1;

ExtensionAction::ExtensionAction() {
}

ExtensionAction::~ExtensionAction() {
}

void ExtensionAction::SetPopupUrl(int tab_id, const GURL& url) {
  // We store |url| even if it is empty, rather than removing a URL from the
  // map.  If an extension has a default popup, and removes it for a tab via
  // the API, we must remember that there is no popup for that specific tab.
  // If we removed the tab's URL, GetPopupURL would incorrectly return the
  // default URL.
  SetValue(&popup_url_, tab_id, url);
}

bool ExtensionAction::HasPopup(int tab_id) {
  return !GetPopupUrl(tab_id).is_empty();
}

GURL ExtensionAction::GetPopupUrl(int tab_id) {
  return GetValue(&popup_url_, tab_id);
}

void ExtensionAction::SetIcon(int tab_id, const SkBitmap& bitmap) {
  SetValue(&icon_, tab_id, bitmap);
}

SkBitmap ExtensionAction::GetIcon(int tab_id) {
  return GetValue(&icon_, tab_id);
}

void ExtensionAction::SetIconIndex(int tab_id, int index) {
  if (static_cast<size_t>(index) >= icon_paths_.size()) {
    NOTREACHED();
    return;
  }
  SetValue(&icon_index_, tab_id, index);
}

void ExtensionAction::ClearAllValuesForTab(int tab_id) {
  title_.erase(tab_id);
  icon_.erase(tab_id);
  icon_index_.erase(tab_id);
  badge_text_.erase(tab_id);
  badge_text_color_.erase(tab_id);
  badge_background_color_.erase(tab_id);
  visible_.erase(tab_id);
  popup_url_.erase(tab_id);
}

void ExtensionAction::PaintBadge(gfx::Canvas* canvas,
                                 const gfx::Rect& bounds,
                                 int tab_id) {
  std::string text = GetBadgeText(tab_id);
  if (text.empty())
    return;

  SkColor text_color = GetBadgeTextColor(tab_id);
  SkColor background_color = GetBadgeBackgroundColor(tab_id);

  if (SkColorGetA(text_color) == 0x00)
    text_color = SK_ColorWHITE;

  if (SkColorGetA(background_color) == 0x00)
    background_color = SkColorSetARGB(255, 218, 0, 24);  // Default badge color.

  canvas->Save();

  SkPaint* text_paint = GetTextPaint();
  text_paint->setColor(text_color);

  // Calculate text width. We clamp it to a max size.
  SkScalar text_width = text_paint->measureText(text.c_str(), text.size());
  text_width = SkIntToScalar(
      std::min(kMaxTextWidth, SkScalarFloor(text_width)));

  // Calculate badge size. It is clamped to a min width just because it looks
  // silly if it is too skinny.
  int badge_width = SkScalarFloor(text_width) + kPadding * 2;
  int icon_width = GetIcon(tab_id).width();
  // Force the pixel width of badge to be either odd (if the icon width is odd)
  // or even otherwise. If there is a mismatch you get http://crbug.com/26400.
  if (icon_width != 0 && (badge_width % 2 != GetIcon(tab_id).width() % 2))
    badge_width += 1;
  badge_width = std::max(kBadgeHeight, badge_width);

  // Paint the badge background color in the right location. It is usually
  // right-aligned, but it can also be center-aligned if it is large.
  SkRect rect;
  rect.fBottom = SkIntToScalar(bounds.bottom() - kBottomMargin);
  rect.fTop = rect.fBottom - SkIntToScalar(kBadgeHeight);
  if (badge_width >= kCenterAlignThreshold) {
    rect.fLeft = SkIntToScalar(
                     SkScalarFloor(SkIntToScalar(bounds.x()) +
                                   SkIntToScalar(bounds.width() / 2.0) -
                                   SkIntToScalar(badge_width / 2.0)));
    rect.fRight = rect.fLeft + SkIntToScalar(badge_width);
  } else {
    rect.fRight = SkIntToScalar(bounds.right());
    rect.fLeft = rect.fRight - badge_width;
  }

  SkPaint rect_paint;
  rect_paint.setStyle(SkPaint::kFill_Style);
  rect_paint.setAntiAlias(true);
  rect_paint.setColor(background_color);
  canvas->AsCanvasSkia()->drawRoundRect(rect, SkIntToScalar(2),
                                        SkIntToScalar(2), rect_paint);

  // Overlay the gradient. It is stretchy, so we do this in three parts.
  ResourceBundle& resource_bundle = ResourceBundle::GetSharedInstance();
  SkBitmap* gradient_left = resource_bundle.GetBitmapNamed(
      IDR_BROWSER_ACTION_BADGE_LEFT);
  SkBitmap* gradient_right = resource_bundle.GetBitmapNamed(
      IDR_BROWSER_ACTION_BADGE_RIGHT);
  SkBitmap* gradient_center = resource_bundle.GetBitmapNamed(
      IDR_BROWSER_ACTION_BADGE_CENTER);

  canvas->AsCanvasSkia()->drawBitmap(*gradient_left, rect.fLeft, rect.fTop);
  canvas->TileImageInt(*gradient_center,
      SkScalarFloor(rect.fLeft) + gradient_left->width(),
      SkScalarFloor(rect.fTop),
      SkScalarFloor(rect.width()) - gradient_left->width() -
                    gradient_right->width(),
      SkScalarFloor(rect.height()));
  canvas->AsCanvasSkia()->drawBitmap(*gradient_right,
      rect.fRight - SkIntToScalar(gradient_right->width()), rect.fTop);

  // Finally, draw the text centered within the badge. We set a clip in case the
  // text was too large.
  rect.fLeft += kPadding;
  rect.fRight -= kPadding;
  canvas->AsCanvasSkia()->clipRect(rect);
  canvas->AsCanvasSkia()->drawText(text.c_str(), text.size(),
                                   rect.fLeft + (rect.width() - text_width) / 2,
                                   rect.fTop + kTextSize + kTopTextPadding,
                                   *text_paint);
  canvas->Restore();
}
<commit_msg>Fix the small badge text on windows. I don't have the time right now to figure out how to put in a good test, so I hope it doesn't break again.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/common/extensions/extension_action.h"

#include <algorithm>

#include "app/resource_bundle.h"
#include "base/logging.h"
#include "base/utf_string_conversions.h"
#include "gfx/canvas_skia.h"
#include "gfx/font.h"
#include "gfx/rect.h"
#include "googleurl/src/gurl.h"
#include "grit/app_resources.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkTypeface.h"
#include "third_party/skia/include/effects/SkGradientShader.h"

namespace {

// Different platforms need slightly different constants to look good.
#if defined(OS_LINUX) && !defined(TOOLKIT_VIEWS)
const float kTextSize = 9.0;
const int kBottomMargin = 0;
const int kPadding = 2;
const int kTopTextPadding = 0;
#elif defined(OS_LINUX) && defined(TOOLKIT_VIEWS)
const float kTextSize = 8.0;
const int kBottomMargin = 5;
const int kPadding = 2;
const int kTopTextPadding = 1;
#elif defined(OS_MACOSX)
const float kTextSize = 9.0;
const int kBottomMargin = 5;
const int kPadding = 2;
const int kTopTextPadding = 0;
#else
const float kTextSize = 10;
const int kBottomMargin = 5;
const int kPadding = 2;
// The padding between the top of the badge and the top of the text.
const int kTopTextPadding = -1;
#endif

const int kBadgeHeight = 11;
const int kMaxTextWidth = 23;
// The minimum width for center-aligning the badge.
const int kCenterAlignThreshold = 20;

#if defined(OS_MACOSX)
const char kPreferredTypeface[] = "Helvetica Bold";
#else
const char kPreferredTypeface[] = "Arial";
#endif

SkPaint* GetTextPaint() {
  static SkPaint* text_paint = NULL;
  if (!text_paint) {
    text_paint = new SkPaint;
    text_paint->setAntiAlias(true);

    text_paint->setTextAlign(SkPaint::kLeft_Align);
    text_paint->setTextSize(SkFloatToScalar(kTextSize));

    SkTypeface* typeface = SkTypeface::CreateFromName(
        kPreferredTypeface, SkTypeface::kBold);
    // Skia doesn't do any font fallback---if the user is missing the font then
    // typeface will be NULL. If we don't do manual fallback then we'll crash.
    if (typeface) {
      text_paint->setFakeBoldText(true);
    } else {
      // Fall back to the system font. We don't bold it because we aren't sure
      // how it will look.
      // For the most part this code path will only be hit on Linux systems
      // that don't have Arial.
      ResourceBundle& rb = ResourceBundle::GetSharedInstance();
      const gfx::Font& base_font = rb.GetFont(ResourceBundle::BaseFont);
      typeface = SkTypeface::CreateFromName(
          WideToUTF8(base_font.GetFontName()).c_str(), SkTypeface::kNormal);
    }

    text_paint->setTypeface(typeface);
    // |text_paint| adds its own ref. Release the ref from CreateFontName.
    typeface->unref();
  }
  return text_paint;
}

}  // namespace

const int ExtensionAction::kDefaultTabId = -1;

ExtensionAction::ExtensionAction() {
}

ExtensionAction::~ExtensionAction() {
}

void ExtensionAction::SetPopupUrl(int tab_id, const GURL& url) {
  // We store |url| even if it is empty, rather than removing a URL from the
  // map.  If an extension has a default popup, and removes it for a tab via
  // the API, we must remember that there is no popup for that specific tab.
  // If we removed the tab's URL, GetPopupURL would incorrectly return the
  // default URL.
  SetValue(&popup_url_, tab_id, url);
}

bool ExtensionAction::HasPopup(int tab_id) {
  return !GetPopupUrl(tab_id).is_empty();
}

GURL ExtensionAction::GetPopupUrl(int tab_id) {
  return GetValue(&popup_url_, tab_id);
}

void ExtensionAction::SetIcon(int tab_id, const SkBitmap& bitmap) {
  SetValue(&icon_, tab_id, bitmap);
}

SkBitmap ExtensionAction::GetIcon(int tab_id) {
  return GetValue(&icon_, tab_id);
}

void ExtensionAction::SetIconIndex(int tab_id, int index) {
  if (static_cast<size_t>(index) >= icon_paths_.size()) {
    NOTREACHED();
    return;
  }
  SetValue(&icon_index_, tab_id, index);
}

void ExtensionAction::ClearAllValuesForTab(int tab_id) {
  title_.erase(tab_id);
  icon_.erase(tab_id);
  icon_index_.erase(tab_id);
  badge_text_.erase(tab_id);
  badge_text_color_.erase(tab_id);
  badge_background_color_.erase(tab_id);
  visible_.erase(tab_id);
  popup_url_.erase(tab_id);
}

void ExtensionAction::PaintBadge(gfx::Canvas* canvas,
                                 const gfx::Rect& bounds,
                                 int tab_id) {
  std::string text = GetBadgeText(tab_id);
  if (text.empty())
    return;

  SkColor text_color = GetBadgeTextColor(tab_id);
  SkColor background_color = GetBadgeBackgroundColor(tab_id);

  if (SkColorGetA(text_color) == 0x00)
    text_color = SK_ColorWHITE;

  if (SkColorGetA(background_color) == 0x00)
    background_color = SkColorSetARGB(255, 218, 0, 24);  // Default badge color.

  canvas->Save();

  SkPaint* text_paint = GetTextPaint();
  text_paint->setColor(text_color);

  // Calculate text width. We clamp it to a max size.
  SkScalar text_width = text_paint->measureText(text.c_str(), text.size());
  text_width = SkIntToScalar(
      std::min(kMaxTextWidth, SkScalarFloor(text_width)));

  // Calculate badge size. It is clamped to a min width just because it looks
  // silly if it is too skinny.
  int badge_width = SkScalarFloor(text_width) + kPadding * 2;
  int icon_width = GetIcon(tab_id).width();
  // Force the pixel width of badge to be either odd (if the icon width is odd)
  // or even otherwise. If there is a mismatch you get http://crbug.com/26400.
  if (icon_width != 0 && (badge_width % 2 != GetIcon(tab_id).width() % 2))
    badge_width += 1;
  badge_width = std::max(kBadgeHeight, badge_width);

  // Paint the badge background color in the right location. It is usually
  // right-aligned, but it can also be center-aligned if it is large.
  SkRect rect;
  rect.fBottom = SkIntToScalar(bounds.bottom() - kBottomMargin);
  rect.fTop = rect.fBottom - SkIntToScalar(kBadgeHeight);
  if (badge_width >= kCenterAlignThreshold) {
    rect.fLeft = SkIntToScalar(
                     SkScalarFloor(SkIntToScalar(bounds.x()) +
                                   SkIntToScalar(bounds.width() / 2.0) -
                                   SkIntToScalar(badge_width / 2.0)));
    rect.fRight = rect.fLeft + SkIntToScalar(badge_width);
  } else {
    rect.fRight = SkIntToScalar(bounds.right());
    rect.fLeft = rect.fRight - badge_width;
  }

  SkPaint rect_paint;
  rect_paint.setStyle(SkPaint::kFill_Style);
  rect_paint.setAntiAlias(true);
  rect_paint.setColor(background_color);
  canvas->AsCanvasSkia()->drawRoundRect(rect, SkIntToScalar(2),
                                        SkIntToScalar(2), rect_paint);

  // Overlay the gradient. It is stretchy, so we do this in three parts.
  ResourceBundle& resource_bundle = ResourceBundle::GetSharedInstance();
  SkBitmap* gradient_left = resource_bundle.GetBitmapNamed(
      IDR_BROWSER_ACTION_BADGE_LEFT);
  SkBitmap* gradient_right = resource_bundle.GetBitmapNamed(
      IDR_BROWSER_ACTION_BADGE_RIGHT);
  SkBitmap* gradient_center = resource_bundle.GetBitmapNamed(
      IDR_BROWSER_ACTION_BADGE_CENTER);

  canvas->AsCanvasSkia()->drawBitmap(*gradient_left, rect.fLeft, rect.fTop);
  canvas->TileImageInt(*gradient_center,
      SkScalarFloor(rect.fLeft) + gradient_left->width(),
      SkScalarFloor(rect.fTop),
      SkScalarFloor(rect.width()) - gradient_left->width() -
                    gradient_right->width(),
      SkScalarFloor(rect.height()));
  canvas->AsCanvasSkia()->drawBitmap(*gradient_right,
      rect.fRight - SkIntToScalar(gradient_right->width()), rect.fTop);

  // Finally, draw the text centered within the badge. We set a clip in case the
  // text was too large.
  rect.fLeft += kPadding;
  rect.fRight -= kPadding;
  canvas->AsCanvasSkia()->clipRect(rect);
  canvas->AsCanvasSkia()->drawText(text.c_str(), text.size(),
                                   rect.fLeft + (rect.width() - text_width) / 2,
                                   rect.fTop + kTextSize + kTopTextPadding,
                                   *text_paint);
  canvas->Restore();
}
<|endoftext|>


<commit_before>/*
This file is part of Bohrium and copyright (c) 2012 the Bohrium
team <http://www.bh107.org>.

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

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

You should have received a copy of the
GNU Lesser General Public License along with Bohrium.

If not, see <http://www.gnu.org/licenses/>.
*/

#include <jitk/transformer.hpp>

using namespace std;

namespace bohrium {
namespace jitk {

vector<InstrPtr> swap_axis(const vector<InstrPtr> &instr_list, int64_t axis1, int64_t axis2) {
    vector<InstrPtr> ret;
    for (const InstrPtr &instr: instr_list) {
        bh_instruction tmp(*instr);
        tmp.transpose(axis1, axis2);
        ret.push_back(std::make_shared<bh_instruction>(tmp));
    }
    return ret;
}

vector<Block> swap_blocks(const LoopB &parent, const LoopB *child) {
    vector<Block> ret;
    for (const Block &b: parent._block_list) {
        LoopB loop;
        loop.rank = parent.rank;
        if (b.isInstr() or &b.getLoop() != child) {
            loop.size = parent.size;
            loop._block_list.push_back(b);
        } else {
            loop.size = child->size;
            const vector<InstrPtr> t = swap_axis(child->getAllInstr(), parent.rank, child->rank);
            loop._block_list.push_back(create_nested_block(t, child->rank, parent.size));
        }
        loop.metadata_update();
        ret.push_back(Block(std::move(loop)));
    }
    return ret;
}

const LoopB *find_swappable_sub_block(const LoopB &parent) {
    // For each sweep, we look for a sub-block that contains that sweep instructions.
    for (const InstrPtr sweep: parent._sweeps) {
        for (const Block &b: parent._block_list) {
            if (not b.isInstr()) {
                for (const Block &instr_block: b.getLoop()._block_list) {
                    if (instr_block.isInstr()) {
                        if (*instr_block.getInstr() == *sweep) {
                            return &b.getLoop();
                        }
                    }
                }
            }
        }
    }
    return NULL;
}

vector<Block> push_reductions_inwards(const vector<Block> &block_list) {
    vector<Block> block_list2(block_list);
    for(Block &b: block_list2) {
        if (not b.isInstr()) {
            b.getLoop()._block_list = push_reductions_inwards(b.getLoop()._block_list);
        }
    }
    vector<Block> ret;
    for(const Block &b: block_list2) {
        const LoopB *swappable;
        if (not b.isInstr() and (swappable = find_swappable_sub_block(b.getLoop())) != NULL)  {
            const vector<Block>tmp = swap_blocks(b.getLoop(), swappable);
            ret.insert(ret.end(), tmp.begin(), tmp.end());
        } else {
            ret.push_back(b);
        }
    }
    return ret;
}

vector<Block> split_for_threading(const vector<Block> &block_list, uint64_t min_threading, uint64_t cur_threading) {
    vector<Block> ret;

    for (const Block &block: block_list) {
        // For now, we cannot make an instruction or a sweeped block threadable
        if (block.isInstr() or block.getLoop()._sweeps.size() > 0) {
            ret.push_back(block);
            continue;
        }
        const LoopB &loop = block.getLoop();
        uint64_t max_nelem = 0; // The maximum number of element in loop, which tells use the best-case scenario
        for (const InstrPtr instr: loop.getAllInstr()) {
            if (bh_noperands(instr->opcode) > 0) {
                const uint64_t nelem = static_cast<uint64_t>(bh_nelements(instr->operand[0]));
                if (nelem > max_nelem)
                    max_nelem = nelem;
            }
        }
        if (loop._block_list.size() > 1 // We need minimum two blocks in order to split!
            and max_nelem > min_threading // Is it even possible to achieve our goal?
            and find_threaded_blocks(loop).second < min_threading-cur_threading) { // Is the goal already achieved?

            for (auto it = loop._block_list.begin(); it != loop._block_list.end(); ++it) {
                // First we will place all sub-blocks that cannot be threaded in a shared block
                {
                    LoopB newloop;
                    newloop.rank = loop.rank;
                    newloop.size = loop.size;
                    while (it != loop._block_list.end() and (it->isInstr() or it->getLoop()._sweeps.size() > 0)) {
                        assert(it->rank() == newloop.rank+1);
                        newloop._block_list.push_back(*it);
                        ++it;
                    }
                    newloop.metadata_update();
                    if (not newloop._block_list.empty()) {
                        ret.push_back(Block(std::move(newloop)));
                    }
                }
                // Then we place the highly threaded sub-block in its own block
                if (it != loop._block_list.end()) {
                    assert(not it->isInstr());
                    assert(it->getLoop()._sweeps.size() == 0);
                    LoopB newloop;
                    newloop.rank = loop.rank;
                    newloop.size = loop.size;
                    newloop._block_list.push_back(*it);
                    newloop.metadata_update();
                    ret.push_back(Block(std::move(newloop)));
                } else {
                    break;
                }
            }
        } else {
            ret.push_back(block);
        }
    }
    return ret;
}

// Help function that collapses 'axis' and 'axis+1' in all instructions within 'loop'
// Returns false if encountering a non-compatible instruction
static bool collapse_instr_axes(LoopB &loop, const int axis) {
    for (Block &block: loop._block_list) {
        if (block.isInstr()) {
            bh_instruction instr(*block.getInstr());
            const int sa = instr.sweep_axis();
            assert(sa != axis);
            assert(sa != axis+1);
            if (sa == axis or sa == axis+1) {
                return false;
            }
            const int nop = bh_noperands(instr.opcode);
            for (int i=0; i<nop; ++i) {
                bh_view &view = instr.operand[i];
                if (not bh_is_constant(&view)) {
                    int _axis = axis;
                    if (i==0 and bh_opcode_is_reduction(instr.opcode)) {
                        _axis = sa < _axis ? _axis-1 : _axis;
                    }
                    assert(view.ndim > _axis+1);
                    if (view.shape[_axis+1] * view.stride[_axis+1] != view.stride[_axis]) {
                        return false;
                    }
                    view.shape[_axis] *= view.shape[_axis+1];
                    view.stride[_axis] = view.stride[_axis+1];
                }
            }
            instr.remove_axis(axis+1);
            block.setInstr(instr);
        } else {
            --block.getLoop().rank;
            if (not collapse_instr_axes(block.getLoop(), axis)) {
                return false;
            }
        }
    }
    loop.metadata_update();
    assert(loop.validation());
    return true;
}

// Help function that collapses 'loop' with its child if possible
static bool collapse_loop_with_child(LoopB &loop) {
    // In order to be collapsable, 'loop' can only have one child, that child must be a loop, and both 'loop'
    // and the child cannot be sweeped
    if (loop._sweeps.empty() and loop._block_list.size() == 1) {
        Block &child = loop._block_list[0];
        if ((not child.isInstr()) and child.getLoop()._sweeps.empty()) {
            // Let's collapse with our single child
            loop.size *= loop._block_list[0].getLoop().size;
            // NB: we need the temporary step in order to avoid copying deleted data
            auto tmp = std::move(loop._block_list[0].getLoop()._block_list);
            loop._block_list = std::move(tmp);
            return collapse_instr_axes(loop, loop.rank);
        }
    }
    return false;
}

vector<Block> collapse_redundant_axes(const vector<Block> &block_list) {
    vector<Block> block_list2(block_list);
    for(Block &b: block_list2) {
        if (not b.isInstr()) {
            b.getLoop()._block_list = collapse_redundant_axes(b.getLoop()._block_list);
        }
    }
    vector<Block> ret;
    for (const Block &block: block_list) {
        if (not block.isInstr()) {
            Block b(block);
            if (collapse_loop_with_child(b.getLoop())) {
                ret.push_back(std::move(b));
            } else { // If it didn't succeeded, we just push the original block
                ret.push_back(block);
            }
        } else {
            ret.push_back(block);
        }
    }
    return ret;
}
} // jitk
} // bohrium

<commit_msg>Fixed opdate of empty block in split_for_threading()<commit_after>/*
This file is part of Bohrium and copyright (c) 2012 the Bohrium
team <http://www.bh107.org>.

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

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

You should have received a copy of the
GNU Lesser General Public License along with Bohrium.

If not, see <http://www.gnu.org/licenses/>.
*/

#include <jitk/transformer.hpp>

using namespace std;

namespace bohrium {
namespace jitk {

vector<InstrPtr> swap_axis(const vector<InstrPtr> &instr_list, int64_t axis1, int64_t axis2) {
    vector<InstrPtr> ret;
    for (const InstrPtr &instr: instr_list) {
        bh_instruction tmp(*instr);
        tmp.transpose(axis1, axis2);
        ret.push_back(std::make_shared<bh_instruction>(tmp));
    }
    return ret;
}

vector<Block> swap_blocks(const LoopB &parent, const LoopB *child) {
    vector<Block> ret;
    for (const Block &b: parent._block_list) {
        LoopB loop;
        loop.rank = parent.rank;
        if (b.isInstr() or &b.getLoop() != child) {
            loop.size = parent.size;
            loop._block_list.push_back(b);
        } else {
            loop.size = child->size;
            const vector<InstrPtr> t = swap_axis(child->getAllInstr(), parent.rank, child->rank);
            loop._block_list.push_back(create_nested_block(t, child->rank, parent.size));
        }
        loop.metadata_update();
        ret.push_back(Block(std::move(loop)));
    }
    return ret;
}

const LoopB *find_swappable_sub_block(const LoopB &parent) {
    // For each sweep, we look for a sub-block that contains that sweep instructions.
    for (const InstrPtr sweep: parent._sweeps) {
        for (const Block &b: parent._block_list) {
            if (not b.isInstr()) {
                for (const Block &instr_block: b.getLoop()._block_list) {
                    if (instr_block.isInstr()) {
                        if (*instr_block.getInstr() == *sweep) {
                            return &b.getLoop();
                        }
                    }
                }
            }
        }
    }
    return NULL;
}

vector<Block> push_reductions_inwards(const vector<Block> &block_list) {
    vector<Block> block_list2(block_list);
    for(Block &b: block_list2) {
        if (not b.isInstr()) {
            b.getLoop()._block_list = push_reductions_inwards(b.getLoop()._block_list);
        }
    }
    vector<Block> ret;
    for(const Block &b: block_list2) {
        const LoopB *swappable;
        if (not b.isInstr() and (swappable = find_swappable_sub_block(b.getLoop())) != NULL)  {
            const vector<Block>tmp = swap_blocks(b.getLoop(), swappable);
            ret.insert(ret.end(), tmp.begin(), tmp.end());
        } else {
            ret.push_back(b);
        }
    }
    return ret;
}

vector<Block> split_for_threading(const vector<Block> &block_list, uint64_t min_threading, uint64_t cur_threading) {
    vector<Block> ret;

    for (const Block &block: block_list) {
        // For now, we cannot make an instruction or a sweeped block threadable
        if (block.isInstr() or block.getLoop()._sweeps.size() > 0) {
            ret.push_back(block);
            continue;
        }
        const LoopB &loop = block.getLoop();
        uint64_t max_nelem = 0; // The maximum number of element in loop, which tells use the best-case scenario
        for (const InstrPtr instr: loop.getAllInstr()) {
            if (bh_noperands(instr->opcode) > 0) {
                const uint64_t nelem = static_cast<uint64_t>(bh_nelements(instr->operand[0]));
                if (nelem > max_nelem)
                    max_nelem = nelem;
            }
        }
        if (loop._block_list.size() > 1 // We need minimum two blocks in order to split!
            and max_nelem > min_threading // Is it even possible to achieve our goal?
            and find_threaded_blocks(loop).second < min_threading-cur_threading) { // Is the goal already achieved?

            for (auto it = loop._block_list.begin(); it != loop._block_list.end(); ++it) {
                // First we will place all sub-blocks that cannot be threaded in a shared block
                {
                    LoopB newloop;
                    newloop.rank = loop.rank;
                    newloop.size = loop.size;
                    while (it != loop._block_list.end() and (it->isInstr() or it->getLoop()._sweeps.size() > 0)) {
                        assert(it->rank() == newloop.rank+1);
                        newloop._block_list.push_back(*it);
                        ++it;
                    }
                    if (not newloop._block_list.empty()) {
                        newloop.metadata_update();
                        ret.push_back(Block(std::move(newloop)));
                    }
                }
                // Then we place the highly threaded sub-block in its own block
                if (it != loop._block_list.end()) {
                    assert(not it->isInstr());
                    assert(it->getLoop()._sweeps.size() == 0);
                    LoopB newloop;
                    newloop.rank = loop.rank;
                    newloop.size = loop.size;
                    newloop._block_list.push_back(*it);
                    newloop.metadata_update();
                    ret.push_back(Block(std::move(newloop)));
                } else {
                    break;
                }
            }
        } else {
            ret.push_back(block);
        }
    }
    return ret;
}

// Help function that collapses 'axis' and 'axis+1' in all instructions within 'loop'
// Returns false if encountering a non-compatible instruction
static bool collapse_instr_axes(LoopB &loop, const int axis) {
    for (Block &block: loop._block_list) {
        if (block.isInstr()) {
            bh_instruction instr(*block.getInstr());
            const int sa = instr.sweep_axis();
            assert(sa != axis);
            assert(sa != axis+1);
            if (sa == axis or sa == axis+1) {
                return false;
            }
            const int nop = bh_noperands(instr.opcode);
            for (int i=0; i<nop; ++i) {
                bh_view &view = instr.operand[i];
                if (not bh_is_constant(&view)) {
                    int _axis = axis;
                    if (i==0 and bh_opcode_is_reduction(instr.opcode)) {
                        _axis = sa < _axis ? _axis-1 : _axis;
                    }
                    assert(view.ndim > _axis+1);
                    if (view.shape[_axis+1] * view.stride[_axis+1] != view.stride[_axis]) {
                        return false;
                    }
                    view.shape[_axis] *= view.shape[_axis+1];
                    view.stride[_axis] = view.stride[_axis+1];
                }
            }
            instr.remove_axis(axis+1);
            block.setInstr(instr);
        } else {
            --block.getLoop().rank;
            if (not collapse_instr_axes(block.getLoop(), axis)) {
                return false;
            }
        }
    }
    loop.metadata_update();
    assert(loop.validation());
    return true;
}

// Help function that collapses 'loop' with its child if possible
static bool collapse_loop_with_child(LoopB &loop) {
    // In order to be collapsable, 'loop' can only have one child, that child must be a loop, and both 'loop'
    // and the child cannot be sweeped
    if (loop._sweeps.empty() and loop._block_list.size() == 1) {
        Block &child = loop._block_list[0];
        if ((not child.isInstr()) and child.getLoop()._sweeps.empty()) {
            // Let's collapse with our single child
            loop.size *= loop._block_list[0].getLoop().size;
            // NB: we need the temporary step in order to avoid copying deleted data
            auto tmp = std::move(loop._block_list[0].getLoop()._block_list);
            loop._block_list = std::move(tmp);
            return collapse_instr_axes(loop, loop.rank);
        }
    }
    return false;
}

vector<Block> collapse_redundant_axes(const vector<Block> &block_list) {
    vector<Block> block_list2(block_list);
    for(Block &b: block_list2) {
        if (not b.isInstr()) {
            b.getLoop()._block_list = collapse_redundant_axes(b.getLoop()._block_list);
        }
    }
    vector<Block> ret;
    for (const Block &block: block_list) {
        if (not block.isInstr()) {
            Block b(block);
            if (collapse_loop_with_child(b.getLoop())) {
                ret.push_back(std::move(b));
            } else { // If it didn't succeeded, we just push the original block
                ret.push_back(block);
            }
        } else {
            ret.push_back(block);
        }
    }
    return ret;
}
} // jitk
} // bohrium

<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Vassil Vassilev <vvasilev@cern.ch>
//------------------------------------------------------------------------------

#include "ASTNodeEraser.h"

#include "clang/AST/Decl.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/DependentDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/Sema.h"

using namespace clang;

namespace cling {

  ///\brief The class does the actual work of removing a declaration and
  /// resetting the internal structures of the compiler
  ///
  class DeclReverter : public DeclVisitor<DeclReverter, bool> {
  private:
    Sema* m_Sema;

  public:
    DeclReverter(Sema* S): m_Sema(S) {}

    ///\brief Function that contains common actions, done for every removal of
    /// declaration.
    ///
    /// For example: We must uncache the cached include, which brought that
    /// declaration in the AST.
    ///\param[in] D - A declaration.
    ///
    void PreVisitDecl(Decl* D);

    ///\brief If it falls back in the base class just remove the declaration
    /// only from the declaration context.
    /// @param[in] D - The declaration to be removed.
    ///
    ///\returns true on success.
    ///
    bool VisitDecl(Decl* D);

    ///\brief Removes the declaration from the lookup chains and from the
    /// declaration context.
    /// @param[in] ND - The declaration to be removed.
    ///
    ///\returns true on success.
    ///
    bool VisitNamedDecl(NamedDecl* ND);

    ///\brief Removes the declaration from the lookup chains and from the
    /// declaration context and it rebuilds the redeclaration chain.
    /// @param[in] VD - The declaration to be removed.
    ///
    ///\returns true on success.
    ///
    bool VisitVarDecl(VarDecl* VD);

    ///\brief Removes the declaration from the lookup chains and from the
    /// declaration context and it rebuilds the redeclaration chain.
    /// @param[in] FD - The declaration to be removed.
    ///
    ///\returns true on success.
    ///
    bool VisitFunctionDecl(FunctionDecl* FD);

    ///\brief Removes the enumerator and its enumerator constants.
    /// @param[in] ED - The declaration to be removed.
    ///
    ///\returns true on success.
    ///
    bool VisitEnumDecl(EnumDecl* ED);

    ///\brief Removes the namespace.
    /// @param[in] NSD - The declaration to be removed.
    ///
    ///\returns true on success.
    ///
    bool VisitNamespaceDecl(NamespaceDecl* NSD);

    /// @name Helpers
    /// @{

    ///\brief Checks whether the declaration was pushed onto the declaration
    /// chains. Returns
    /// @param[in] ND - The declaration that is being checked
    ///
    ///\returns true if the ND was found in the lookup chain.
    ///
    bool isOnScopeChains(clang::NamedDecl* ND);

    ///\brief Removes given declaration from the chain of redeclarations.
    /// Rebuilds the chain and sets properly first and last redeclaration.
    /// @param[in] R - The redeclarable, its chain to be rebuilt
    ///
    ///\returns the most recent redeclaration in the new chain.
    ///
    template <typename T>
    T* RemoveFromRedeclChain(clang::Redeclarable<T>* R) {
      llvm::SmallVector<T*, 4> PrevDecls;
      T* PrevDecl = 0;

      // [0]=>C [1]=>B [2]=>A ...
      while ((PrevDecl = R->getPreviousDecl())) {
        PrevDecls.push_back(PrevDecl);
        R = PrevDecl;
      }

      if (!PrevDecls.empty()) {
        // Put 0 in the end of the array so that the loop will reset the
        // pointer to latest redeclaration in the chain to itself.
        //
        PrevDecls.push_back(0);

        // 0 <- A <- B <- C
        for(unsigned i = PrevDecls.size() - 1; i > 0; --i) {
          PrevDecls[i-1]->setPreviousDeclaration(PrevDecls[i]);
        }
      }

      return PrevDecls.empty() ? 0 : PrevDecls[0]->getMostRecentDecl();
    }

    /// @}
  };

  void DeclReverter::PreVisitDecl(Decl *D) {
    //SourceLocation Loc = D->getLocStart();
    //SourceManager& SM = m_Sema->getSourceManager();
    //FileManager& FM = SM.getFileManager();
    //const FileEntry* OldEntry = SM.getFileEntryForID(SM.getFileID(Loc));
    //const FileEntry* NewEntry
    //  = FM.getFile(OldEntry->getName(), /*openFile*/ true);
    //std::string errStr = "";
    //SM.overrideFileContents(OldEntry, FM.getBufferForFile(NewEntry, &errStr));
  }

  // Gives us access to the protected members that we  need.
  class DeclContextExt : public DeclContext {
  public:
    static bool removeIfLast(DeclContext* DC, Decl* D) {
      if (!D->getNextDeclInContext()) {
        // Either last (remove!), or invalid (nothing to remove)
        if (((DeclContextExt*)DC)->LastDecl == D) {
          // Valid. Thus remove.
          DC->removeDecl(D);
          return true;
        }
      }
      else {
        DC->removeDecl(D);
        return true;
      }

      return false;
    }
  };

  bool DeclReverter::VisitDecl(Decl* D) {
    assert(D && "The Decl is null");
    PreVisitDecl(D);

    DeclContext* DC = D->getDeclContext();

    bool ExistsInDC = false;

    for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
         E !=I; ++I) {
      if (*I == D) {
        ExistsInDC = true;
        break;
      }
    }

    bool Successful = DeclContextExt::removeIfLast(DC, D);

    // ExistsInDC && Successful
    // true          false      -> false // In the context but cannot delete
    // false         false      -> true  // Not in the context cannot delete
    // true          true       -> true  // In the context and can delete
    // false         true       -> assert // Not in the context but can delete ?
    assert(!(!ExistsInDC && Successful) && \
           "Not in the context but can delete?!");
    if (ExistsInDC && !Successful)
      return false;
    else // in release we'd want the assert to fall into true
      return true;
  }

  bool DeclReverter::VisitNamedDecl(NamedDecl* ND) {
    bool Successful = VisitDecl(ND);

    DeclContext* DC = ND->getDeclContext();

    // If the decl was removed make sure that we fix the lookup
    if (Successful) {
      Scope* S = m_Sema->getScopeForContext(DC);
      if (S)
        S->RemoveDecl(ND);

      if (isOnScopeChains(ND))
        m_Sema->IdResolver.RemoveDecl(ND);

      return true;
    }

    return false;
  }

  bool DeclReverter::VisitVarDecl(VarDecl* VD) {
    bool Successful = VisitNamedDecl(VD);

    DeclContext* DC = VD->getDeclContext();
    Scope* S = m_Sema->getScopeForContext(DC);

    // Find other decls that the old one has replaced
    StoredDeclsMap *Map = DC->getPrimaryContext()->getLookupPtr();
    if (!Map)
      return false;
    StoredDeclsMap::iterator Pos = Map->find(VD->getDeclName());
    assert(Pos != Map->end() && "no lookup entry for decl");

    if (Pos->second.isNull())
      // We need to rewire the list of the redeclarations in order to exclude
      // the reverted one, because it gets found for example by
      // Sema::MergeVarDecl and ends up in the lookup
      //
      if (VarDecl* MostRecentVD = RemoveFromRedeclChain(VD)) {

        Pos->second.setOnlyValue(MostRecentVD);
        if (S)
          S->AddDecl(MostRecentVD);
        m_Sema->IdResolver.AddDecl(MostRecentVD);
      }

    return Successful;
  }

  bool DeclReverter::VisitFunctionDecl(FunctionDecl* FD) {
    bool Successful = true;

    DeclContext* DC = FD->getDeclContext();
    Scope* S = m_Sema->getScopeForContext(DC);

    // Template instantiation of templated function first creates a canonical
    // declaration and after the actual template specialization. For example:
    // template<typename T> T TemplatedF(T t);
    // template<> int TemplatedF(int i) { return i + 1; } creates:
    // 1. Canonical decl: int TemplatedF(int i);
    // 2. int TemplatedF(int i){ return i + 1; }
    //
    // The template specialization is attached to the list of specialization of
    // the templated function.
    // When TemplatedF is looked up it finds the templated function and the
    // lookup is extended by the templated function with its specializations.
    // In the end we don't need to remove the canonical decl because, it
    // doesn't end up in the lookup table.
    //
#if 0
    getSpecializations() now returns a FoldingSetVector which
    does not have an interface for removing nodes...
    class FunctionTemplateDeclExt : public FunctionTemplateDecl {
    public:
      static llvm::FoldingSet<FunctionTemplateSpecializationInfo>&
      getSpecializationsExt(FunctionTemplateDecl* FTD) {
        assert(FTD && "Cannot be null!");
        return ((FunctionTemplateDeclExt*) FTD)->getSpecializations();
      }
    };
#endif

    if (FD->isFunctionTemplateSpecialization()) {
#if 0
      // 1. Remove the canonical decl.
      // TODO: Can the canonical have another DeclContext and Scope, different
      // from the specialization's implementation?
      FunctionDecl* CanFD = FD->getCanonicalDecl();
      FunctionTemplateDecl* FTD
        = FD->getTemplateSpecializationInfo()->getTemplate();
      llvm::FoldingSet<FunctionTemplateSpecializationInfo> &FS
        = FunctionTemplateDeclExt::getSpecializationsExt(FTD);
      FS.RemoveNode(CanFD->getTemplateSpecializationInfo());
#endif
      assert("FunctionTemplateSpecialization not handled yet" && 0);
    }

    // Find other decls that the old one has replaced
    StoredDeclsMap *Map = DC->getPrimaryContext()->getLookupPtr();
    if (!Map)
      return false;
    StoredDeclsMap::iterator Pos = Map->find(FD->getDeclName());
    assert(Pos != Map->end() && "no lookup entry for decl");

    if (Pos->second.getAsDecl()) {
      Successful = VisitNamedDecl(FD) && Successful;

      Pos = Map->find(FD->getDeclName());
      assert(Pos != Map->end() && "no lookup entry for decl");

      if (Pos->second.isNull()) {
        // When we have template specialization we have to clean up
        if (FD->isFunctionTemplateSpecialization()) {
          while ((FD = FD->getPreviousDecl())) {
            Successful = VisitNamedDecl(FD) && Successful;
          }
          return true;
        }

        // We need to rewire the list of the redeclarations in order to exclude
        // the reverted one, because it gets found for example by
        // Sema::MergeVarDecl and ends up in the lookup
        //
        if (FunctionDecl* MostRecentFD = RemoveFromRedeclChain(FD)) {
          Pos->second.setOnlyValue(MostRecentFD);
          if (S)
            S->AddDecl(MostRecentFD);
          m_Sema->IdResolver.AddDecl(MostRecentFD);
        }
      }
    }
    else if (llvm::SmallVector<NamedDecl*, 4>* Decls
             = Pos->second.getAsVector()) {
      for(llvm::SmallVector<NamedDecl*, 4>::iterator I = Decls->begin();
          I != Decls->end(); ++I) {
        if ((*I) == FD) {
          if (FunctionDecl* MostRecentFD = RemoveFromRedeclChain(FD)) {
            Successful = VisitNamedDecl(*I) && Successful;
            Decls->insert(I, MostRecentFD);
          }
          else
            Decls->erase(I);
        }
      }
    }

    return Successful;
  }

  bool DeclReverter::VisitEnumDecl(EnumDecl* ED) {
    bool Successful = true;

    for (EnumDecl::enumerator_iterator I = ED->enumerator_begin(),
           E = ED->enumerator_end(); I != E; ++I) {
      assert(I->getDeclName() && "EnumConstantDecl with no name?");
      Successful = VisitNamedDecl(*I) && Successful;
    }

    Successful = VisitNamedDecl(ED) && Successful;

    return Successful;
  }

  bool DeclReverter::VisitNamespaceDecl(NamespaceDecl* NSD) {
    bool Successful = VisitNamedDecl(NSD);

    //DeclContext* DC = NSD->getPrimaryContext();
    DeclContext* DC = NSD->getDeclContext();
    Scope* S = m_Sema->getScopeForContext(DC);

    // Find other decls that the old one has replaced
    StoredDeclsMap *Map = DC->getPrimaryContext()->getLookupPtr();
    if (!Map)
      return false;
    StoredDeclsMap::iterator Pos = Map->find(NSD->getDeclName());
    assert(Pos != Map->end() && "no lookup entry for decl");

    if (Pos->second.isNull())
      if (NSD != NSD->getOriginalNamespace()) {
        NamespaceDecl* NewNSD = NSD->getOriginalNamespace();
        Pos->second.setOnlyValue(NewNSD);
        if (S)
          S->AddDecl(NewNSD);
        m_Sema->IdResolver.AddDecl(NewNSD);
      }

    return Successful;
  }

  // See Sema::PushOnScopeChains
  bool DeclReverter::isOnScopeChains(NamedDecl* ND) {

    // Named decls without name shouldn't be in. Eg: struct {int a};
    if (!ND->getDeclName())
      return false;

    // Out-of-line definitions shouldn't be pushed into scope in C++.
    // Out-of-line variable and function definitions shouldn't even in C.
    if ((isa<VarDecl>(ND) || isa<FunctionDecl>(ND)) && ND->isOutOfLine() &&
        !ND->getDeclContext()->getRedeclContext()->Equals(
                        ND->getLexicalDeclContext()->getRedeclContext()))
      return false;

    // Template instantiations should also not be pushed into scope.
    if (isa<FunctionDecl>(ND) &&
        cast<FunctionDecl>(ND)->isFunctionTemplateSpecialization())
      return false;

    IdentifierResolver::iterator
      IDRi = m_Sema->IdResolver.begin(ND->getDeclName()),
      IDRiEnd = m_Sema->IdResolver.end();

    for (; IDRi != IDRiEnd; ++IDRi) {
      if (ND == *IDRi)
        return true;
    }

    // Check if the declaration is template instantiation, which is not in
    // any DeclContext yet, because it came from
    // Sema::PerformPendingInstantiations
    // if (isa<FunctionDecl>(D) &&
    //     cast<FunctionDecl>(D)->getTemplateInstantiationPattern())
    //   return false;ye

    return false;
  }

  ASTNodeEraser::ASTNodeEraser(Sema* S) : m_Sema(S) {
    m_DeclReverter = new DeclReverter(S);
  }

  ASTNodeEraser::~ASTNodeEraser() {
    delete m_DeclReverter;
    m_DeclReverter = 0;
  }

  bool ASTNodeEraser::RevertDecl(Decl* D) {
    return m_DeclReverter->Visit(D);
  }

} // end namespace cling
<commit_msg>To the prev commit: don't forget to upload the code that uses the new clang functionality<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Vassil Vassilev <vvasilev@cern.ch>
//------------------------------------------------------------------------------

#include "ASTNodeEraser.h"

#include "clang/AST/Decl.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/DependentDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/Sema.h"

using namespace clang;

namespace cling {

  ///\brief The class does the actual work of removing a declaration and
  /// resetting the internal structures of the compiler
  ///
  class DeclReverter : public DeclVisitor<DeclReverter, bool> {
  private:
    Sema* m_Sema;

  public:
    DeclReverter(Sema* S): m_Sema(S) {}

    ///\brief Function that contains common actions, done for every removal of
    /// declaration.
    ///
    /// For example: We must uncache the cached include, which brought that
    /// declaration in the AST.
    ///\param[in] D - A declaration.
    ///
    void PreVisitDecl(Decl* D);

    ///\brief If it falls back in the base class just remove the declaration
    /// only from the declaration context.
    /// @param[in] D - The declaration to be removed.
    ///
    ///\returns true on success.
    ///
    bool VisitDecl(Decl* D);

    ///\brief Removes the declaration from the lookup chains and from the
    /// declaration context.
    /// @param[in] ND - The declaration to be removed.
    ///
    ///\returns true on success.
    ///
    bool VisitNamedDecl(NamedDecl* ND);

    ///\brief Removes the declaration from the lookup chains and from the
    /// declaration context and it rebuilds the redeclaration chain.
    /// @param[in] VD - The declaration to be removed.
    ///
    ///\returns true on success.
    ///
    bool VisitVarDecl(VarDecl* VD);

    ///\brief Removes the declaration from the lookup chains and from the
    /// declaration context and it rebuilds the redeclaration chain.
    /// @param[in] FD - The declaration to be removed.
    ///
    ///\returns true on success.
    ///
    bool VisitFunctionDecl(FunctionDecl* FD);

    ///\brief Removes the enumerator and its enumerator constants.
    /// @param[in] ED - The declaration to be removed.
    ///
    ///\returns true on success.
    ///
    bool VisitEnumDecl(EnumDecl* ED);

    ///\brief Removes the namespace.
    /// @param[in] NSD - The declaration to be removed.
    ///
    ///\returns true on success.
    ///
    bool VisitNamespaceDecl(NamespaceDecl* NSD);

    /// @name Helpers
    /// @{

    ///\brief Checks whether the declaration was pushed onto the declaration
    /// chains. Returns
    /// @param[in] ND - The declaration that is being checked
    ///
    ///\returns true if the ND was found in the lookup chain.
    ///
    bool isOnScopeChains(clang::NamedDecl* ND);

    ///\brief Removes given declaration from the chain of redeclarations.
    /// Rebuilds the chain and sets properly first and last redeclaration.
    /// @param[in] R - The redeclarable, its chain to be rebuilt
    ///
    ///\returns the most recent redeclaration in the new chain.
    ///
    template <typename T>
    T* RemoveFromRedeclChain(clang::Redeclarable<T>* R) {
      llvm::SmallVector<T*, 4> PrevDecls;
      T* PrevDecl = 0;

      // [0]=>C [1]=>B [2]=>A ...
      while ((PrevDecl = R->getPreviousDecl())) {
        PrevDecls.push_back(PrevDecl);
        R = PrevDecl;
      }

      if (!PrevDecls.empty()) {
        // Put 0 in the end of the array so that the loop will reset the
        // pointer to latest redeclaration in the chain to itself.
        //
        PrevDecls.push_back(0);

        // 0 <- A <- B <- C
        for(unsigned i = PrevDecls.size() - 1; i > 0; --i) {
          PrevDecls[i-1]->setPreviousDeclaration(PrevDecls[i]);
        }
      }

      return PrevDecls.empty() ? 0 : PrevDecls[0]->getMostRecentDecl();
    }

    /// @}
  };

  void DeclReverter::PreVisitDecl(Decl *D) {
    SourceLocation Loc = D->getLocStart();
    SourceManager& SM = m_Sema->getSourceManager();
    FileManager& FM = SM.getFileManager();
    const FileEntry* OldEntry = SM.getFileEntryForID(SM.getFileID(Loc));
    FM.InvalidateCache(OldEntry);
  }

  // Gives us access to the protected members that we  need.
  class DeclContextExt : public DeclContext {
  public:
    static bool removeIfLast(DeclContext* DC, Decl* D) {
      if (!D->getNextDeclInContext()) {
        // Either last (remove!), or invalid (nothing to remove)
        if (((DeclContextExt*)DC)->LastDecl == D) {
          // Valid. Thus remove.
          DC->removeDecl(D);
          return true;
        }
      }
      else {
        DC->removeDecl(D);
        return true;
      }

      return false;
    }
  };

  bool DeclReverter::VisitDecl(Decl* D) {
    assert(D && "The Decl is null");
    PreVisitDecl(D);

    DeclContext* DC = D->getDeclContext();

    bool ExistsInDC = false;

    for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
         E !=I; ++I) {
      if (*I == D) {
        ExistsInDC = true;
        break;
      }
    }

    bool Successful = DeclContextExt::removeIfLast(DC, D);

    // ExistsInDC && Successful
    // true          false      -> false // In the context but cannot delete
    // false         false      -> true  // Not in the context cannot delete
    // true          true       -> true  // In the context and can delete
    // false         true       -> assert // Not in the context but can delete ?
    assert(!(!ExistsInDC && Successful) && \
           "Not in the context but can delete?!");
    if (ExistsInDC && !Successful)
      return false;
    else // in release we'd want the assert to fall into true
      return true;
  }

  bool DeclReverter::VisitNamedDecl(NamedDecl* ND) {
    bool Successful = VisitDecl(ND);

    DeclContext* DC = ND->getDeclContext();

    // If the decl was removed make sure that we fix the lookup
    if (Successful) {
      Scope* S = m_Sema->getScopeForContext(DC);
      if (S)
        S->RemoveDecl(ND);

      if (isOnScopeChains(ND))
        m_Sema->IdResolver.RemoveDecl(ND);

      return true;
    }

    return false;
  }

  bool DeclReverter::VisitVarDecl(VarDecl* VD) {
    bool Successful = VisitNamedDecl(VD);

    DeclContext* DC = VD->getDeclContext();
    Scope* S = m_Sema->getScopeForContext(DC);

    // Find other decls that the old one has replaced
    StoredDeclsMap *Map = DC->getPrimaryContext()->getLookupPtr();
    if (!Map)
      return false;
    StoredDeclsMap::iterator Pos = Map->find(VD->getDeclName());
    assert(Pos != Map->end() && "no lookup entry for decl");

    if (Pos->second.isNull())
      // We need to rewire the list of the redeclarations in order to exclude
      // the reverted one, because it gets found for example by
      // Sema::MergeVarDecl and ends up in the lookup
      //
      if (VarDecl* MostRecentVD = RemoveFromRedeclChain(VD)) {

        Pos->second.setOnlyValue(MostRecentVD);
        if (S)
          S->AddDecl(MostRecentVD);
        m_Sema->IdResolver.AddDecl(MostRecentVD);
      }

    return Successful;
  }

  bool DeclReverter::VisitFunctionDecl(FunctionDecl* FD) {
    bool Successful = true;

    DeclContext* DC = FD->getDeclContext();
    Scope* S = m_Sema->getScopeForContext(DC);

    // Template instantiation of templated function first creates a canonical
    // declaration and after the actual template specialization. For example:
    // template<typename T> T TemplatedF(T t);
    // template<> int TemplatedF(int i) { return i + 1; } creates:
    // 1. Canonical decl: int TemplatedF(int i);
    // 2. int TemplatedF(int i){ return i + 1; }
    //
    // The template specialization is attached to the list of specialization of
    // the templated function.
    // When TemplatedF is looked up it finds the templated function and the
    // lookup is extended by the templated function with its specializations.
    // In the end we don't need to remove the canonical decl because, it
    // doesn't end up in the lookup table.
    //
#if 0
    getSpecializations() now returns a FoldingSetVector which
    does not have an interface for removing nodes...
    class FunctionTemplateDeclExt : public FunctionTemplateDecl {
    public:
      static llvm::FoldingSet<FunctionTemplateSpecializationInfo>&
      getSpecializationsExt(FunctionTemplateDecl* FTD) {
        assert(FTD && "Cannot be null!");
        return ((FunctionTemplateDeclExt*) FTD)->getSpecializations();
      }
    };
#endif

    if (FD->isFunctionTemplateSpecialization()) {
#if 0
      // 1. Remove the canonical decl.
      // TODO: Can the canonical have another DeclContext and Scope, different
      // from the specialization's implementation?
      FunctionDecl* CanFD = FD->getCanonicalDecl();
      FunctionTemplateDecl* FTD
        = FD->getTemplateSpecializationInfo()->getTemplate();
      llvm::FoldingSet<FunctionTemplateSpecializationInfo> &FS
        = FunctionTemplateDeclExt::getSpecializationsExt(FTD);
      FS.RemoveNode(CanFD->getTemplateSpecializationInfo());
#endif
      assert("FunctionTemplateSpecialization not handled yet" && 0);
    }

    // Find other decls that the old one has replaced
    StoredDeclsMap *Map = DC->getPrimaryContext()->getLookupPtr();
    if (!Map)
      return false;
    StoredDeclsMap::iterator Pos = Map->find(FD->getDeclName());
    assert(Pos != Map->end() && "no lookup entry for decl");

    if (Pos->second.getAsDecl()) {
      Successful = VisitNamedDecl(FD) && Successful;

      Pos = Map->find(FD->getDeclName());
      assert(Pos != Map->end() && "no lookup entry for decl");

      if (Pos->second.isNull()) {
        // When we have template specialization we have to clean up
        if (FD->isFunctionTemplateSpecialization()) {
          while ((FD = FD->getPreviousDecl())) {
            Successful = VisitNamedDecl(FD) && Successful;
          }
          return true;
        }

        // We need to rewire the list of the redeclarations in order to exclude
        // the reverted one, because it gets found for example by
        // Sema::MergeVarDecl and ends up in the lookup
        //
        if (FunctionDecl* MostRecentFD = RemoveFromRedeclChain(FD)) {
          Pos->second.setOnlyValue(MostRecentFD);
          if (S)
            S->AddDecl(MostRecentFD);
          m_Sema->IdResolver.AddDecl(MostRecentFD);
        }
      }
    }
    else if (llvm::SmallVector<NamedDecl*, 4>* Decls
             = Pos->second.getAsVector()) {
      for(llvm::SmallVector<NamedDecl*, 4>::iterator I = Decls->begin();
          I != Decls->end(); ++I) {
        if ((*I) == FD) {
          if (FunctionDecl* MostRecentFD = RemoveFromRedeclChain(FD)) {
            Successful = VisitNamedDecl(*I) && Successful;
            Decls->insert(I, MostRecentFD);
          }
          else
            Decls->erase(I);
        }
      }
    }

    return Successful;
  }

  bool DeclReverter::VisitEnumDecl(EnumDecl* ED) {
    bool Successful = true;

    for (EnumDecl::enumerator_iterator I = ED->enumerator_begin(),
           E = ED->enumerator_end(); I != E; ++I) {
      assert(I->getDeclName() && "EnumConstantDecl with no name?");
      Successful = VisitNamedDecl(*I) && Successful;
    }

    Successful = VisitNamedDecl(ED) && Successful;

    return Successful;
  }

  bool DeclReverter::VisitNamespaceDecl(NamespaceDecl* NSD) {
    bool Successful = VisitNamedDecl(NSD);

    //DeclContext* DC = NSD->getPrimaryContext();
    DeclContext* DC = NSD->getDeclContext();
    Scope* S = m_Sema->getScopeForContext(DC);

    // Find other decls that the old one has replaced
    StoredDeclsMap *Map = DC->getPrimaryContext()->getLookupPtr();
    if (!Map)
      return false;
    StoredDeclsMap::iterator Pos = Map->find(NSD->getDeclName());
    assert(Pos != Map->end() && "no lookup entry for decl");

    if (Pos->second.isNull())
      if (NSD != NSD->getOriginalNamespace()) {
        NamespaceDecl* NewNSD = NSD->getOriginalNamespace();
        Pos->second.setOnlyValue(NewNSD);
        if (S)
          S->AddDecl(NewNSD);
        m_Sema->IdResolver.AddDecl(NewNSD);
      }

    return Successful;
  }

  // See Sema::PushOnScopeChains
  bool DeclReverter::isOnScopeChains(NamedDecl* ND) {

    // Named decls without name shouldn't be in. Eg: struct {int a};
    if (!ND->getDeclName())
      return false;

    // Out-of-line definitions shouldn't be pushed into scope in C++.
    // Out-of-line variable and function definitions shouldn't even in C.
    if ((isa<VarDecl>(ND) || isa<FunctionDecl>(ND)) && ND->isOutOfLine() &&
        !ND->getDeclContext()->getRedeclContext()->Equals(
                        ND->getLexicalDeclContext()->getRedeclContext()))
      return false;

    // Template instantiations should also not be pushed into scope.
    if (isa<FunctionDecl>(ND) &&
        cast<FunctionDecl>(ND)->isFunctionTemplateSpecialization())
      return false;

    IdentifierResolver::iterator
      IDRi = m_Sema->IdResolver.begin(ND->getDeclName()),
      IDRiEnd = m_Sema->IdResolver.end();

    for (; IDRi != IDRiEnd; ++IDRi) {
      if (ND == *IDRi)
        return true;
    }

    // Check if the declaration is template instantiation, which is not in
    // any DeclContext yet, because it came from
    // Sema::PerformPendingInstantiations
    // if (isa<FunctionDecl>(D) &&
    //     cast<FunctionDecl>(D)->getTemplateInstantiationPattern())
    //   return false;ye

    return false;
  }

  ASTNodeEraser::ASTNodeEraser(Sema* S) : m_Sema(S) {
    m_DeclReverter = new DeclReverter(S);
  }

  ASTNodeEraser::~ASTNodeEraser() {
    delete m_DeclReverter;
    m_DeclReverter = 0;
  }

  bool ASTNodeEraser::RevertDecl(Decl* D) {
    return m_DeclReverter->Visit(D);
  }

} // end namespace cling
<|endoftext|>


<commit_before>#include "cppcheck.h"

#include <string>
#include <vector>

#include "log/log.h"
#include "config/settingsNode.h"
#include "core/task.h"
#include "core/patterns.h"
#include "core/execHelperOptions.h"

#include "pluginUtils.h"

using std::string;
using std::vector;

using execHelper::core::Task;
using execHelper::core::Options;
using execHelper::core::TaskCollection;
using execHelper::core::PatternKeys;
using execHelper::core::Command;
using execHelper::core::ExecHelperOptions;
using execHelper::core::PatternCombinations;
using execHelper::config::SettingsNode;

namespace {
    const string cppcheckCommand("cppcheck");
}

namespace execHelper { namespace plugins {
    bool Cppcheck::apply(const Command& command, Task& task, const Options& options) const noexcept {
        static string cppcheckKey("cppcheck");
        const SettingsNode& rootSettings = options.getSettings(cppcheckKey);
        task.append(cppcheckCommand);
        task.append(getEnabledChecks(command, rootSettings));

        const SettingsNode patternSettings = getContainingSettings(command, rootSettings, getPatternsKey());
        PatternKeys patterns;
        if(patternSettings.contains(getPatternsKey())) {
            patterns = patternSettings[getPatternsKey()].toStringCollection();
        }
        for(const auto& combination : options.makePatternPermutator(patterns)) {
            Task cppcheckTargetTask = task;
            cppcheckTargetTask.append(getCommandLine(command, rootSettings, combination));
            cppcheckTargetTask.append(getSourceDir(command, rootSettings, combination));
            registerTask(cppcheckTargetTask, options);
        }
        return true;
    }

    TaskCollection Cppcheck::getSourceDir(const Command& command, const SettingsNode& rootSettings, const PatternCombinations& patternCombinations) noexcept {
        static const string sourceDirKey("src-dir");
        static const string targetDirKey("target-path");

        string sourceDir;
        const SettingsNode sourceSettings = getContainingSettings(command, rootSettings, sourceDirKey);
        if(! sourceSettings.contains(sourceDirKey)) {
            sourceDir += ".";
        } else {
            TaskCollection sourceDirSettings = sourceSettings[sourceDirKey].toStringCollection();
            sourceDir += sourceDirSettings.back();
        }
        const SettingsNode targetSettings = getContainingSettings(command, rootSettings, targetDirKey);
        const SettingsNode patternSettings = getContainingSettings(command, rootSettings, getPatternsKey());
        sourceDir += "/" + targetSettings[targetDirKey].toStringCollection().back();
        TaskCollection sourceDirCollection({sourceDir});
        replacePatternCombinations(sourceDirCollection, patternCombinations);
        return sourceDirCollection;
    }

    TaskCollection Cppcheck::getEnabledChecks(const Command& command, const SettingsNode& rootSettings) noexcept {
        static const string enabledChecksKey("enable-checks");
        string enabledChecksOption("--enable=");

        TaskCollection result;
        const SettingsNode settings = getContainingSettings(command, rootSettings, enabledChecksKey);
        if(! settings.contains(enabledChecksKey)) {
            enabledChecksOption += "all";
            result.push_back(enabledChecksOption);
            return result;
        }

        vector<string> enabledChecks = settings[enabledChecksKey].toStringCollection();
        if(enabledChecks.empty()) {
            enabledChecksOption += "all";
            result.push_back(enabledChecksOption);
            return result;
        }

        enabledChecksOption += enabledChecks[0];
        for(size_t i = 1; i < enabledChecks.size(); ++i) {
            enabledChecksOption +=  "," + enabledChecks[i];
        }
        result.push_back(enabledChecksOption);
        return result;
    }
} }
<commit_msg>Fixed issues with cppcheck tests<commit_after>#include "cppcheck.h"

#include <string>
#include <vector>

#include "log/log.h"
#include "config/settingsNode.h"
#include "core/task.h"
#include "core/patterns.h"
#include "core/execHelperOptions.h"

#include "pluginUtils.h"

using std::string;
using std::vector;

using execHelper::core::Task;
using execHelper::core::Options;
using execHelper::core::TaskCollection;
using execHelper::core::PatternKeys;
using execHelper::core::Command;
using execHelper::core::ExecHelperOptions;
using execHelper::core::PatternCombinations;
using execHelper::config::SettingsNode;

namespace {
    const string cppcheckCommand("cppcheck");
}

namespace execHelper { namespace plugins {
    bool Cppcheck::apply(const Command& command, Task& task, const Options& options) const noexcept {
        static string cppcheckKey("cppcheck");
        const SettingsNode& rootSettings = options.getSettings(cppcheckKey);
        task.append(cppcheckCommand);
        task.append(getEnabledChecks(command, rootSettings));

        const SettingsNode patternSettings = getContainingSettings(command, rootSettings, getPatternsKey());
        PatternKeys patterns;
        if(patternSettings.contains(getPatternsKey())) {
            patterns = patternSettings[getPatternsKey()].toStringCollection();
        }
        for(const auto& combination : options.makePatternPermutator(patterns)) {
            Task cppcheckTargetTask = task;
            cppcheckTargetTask.append(getCommandLine(command, rootSettings, combination));
            cppcheckTargetTask.append(getSourceDir(command, rootSettings, combination));
            registerTask(cppcheckTargetTask, options);
        }
        return true;
    }

    TaskCollection Cppcheck::getSourceDir(const Command& command, const SettingsNode& rootSettings, const PatternCombinations& patternCombinations) noexcept {
        static const string sourceDirKey("src-dir");
        static const string targetDirKey("target-path");

        string sourceDir;
        const SettingsNode sourceSettings = getContainingSettings(command, rootSettings, sourceDirKey);
        if(! sourceSettings.contains(sourceDirKey)) {
            sourceDir += ".";
        } else {
            TaskCollection sourceDirSettings = sourceSettings[sourceDirKey].toStringCollection();
            sourceDir += sourceDirSettings.back();
        }
        const SettingsNode targetSettings = getContainingSettings(command, rootSettings, targetDirKey);
        const SettingsNode patternSettings = getContainingSettings(command, rootSettings, getPatternsKey());
        if(targetSettings.contains(targetDirKey)) {
            sourceDir += "/" + targetSettings[targetDirKey].toStringCollection().back();
        }
        TaskCollection sourceDirCollection({sourceDir});
        replacePatternCombinations(sourceDirCollection, patternCombinations);
        return sourceDirCollection;
    }

    TaskCollection Cppcheck::getEnabledChecks(const Command& command, const SettingsNode& rootSettings) noexcept {
        static const string enabledChecksKey("enable-checks");
        string enabledChecksOption("--enable=");

        TaskCollection result;
        const SettingsNode settings = getContainingSettings(command, rootSettings, enabledChecksKey);
        if(! settings.contains(enabledChecksKey)) {
            enabledChecksOption += "all";
            result.push_back(enabledChecksOption);
            return result;
        }

        vector<string> enabledChecks = settings[enabledChecksKey].toStringCollection();
        if(enabledChecks.empty()) {
            enabledChecksOption += "all";
            result.push_back(enabledChecksOption);
            return result;
        }

        enabledChecksOption += enabledChecks[0];
        for(size_t i = 1; i < enabledChecks.size(); ++i) {
            enabledChecksOption +=  "," + enabledChecks[i];
        }
        result.push_back(enabledChecksOption);
        return result;
    }
} }
<|endoftext|>


<commit_before>/*
  Copyright 2010 Larry Gritz and the other authors and contributors.
  All Rights Reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are
  met:
  * Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
  * Neither the name of the software's owners nor the names of its
    contributors may be used to endorse or promote products derived from
    this software without specific prior written permission.
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

  (This is the Modified BSD License)
*/

#include <string>
#include <fstream>
#include <cstdlib>

#include "export.h"
#include "filesystem.h"
#include "imageio.h"

OIIO_PLUGIN_NAMESPACE_BEGIN

class PNMInput : public ImageInput {
public:
    virtual const char* format_name (void) const { return "pnm"; }
    virtual bool open (const std::string &name, ImageSpec &newspec);
    virtual bool close ();
    virtual int current_subimage (void) const { return 0; }
    virtual bool read_native_scanline (int y, int z, void *data);

private:
    std::ifstream m_file;
    std::string m_current_line; ///< Buffer the image pixels
    const char * m_pos;
    unsigned int m_pnm_type, m_max_val;

    bool read_file_scanline (void * data);
    bool read_file_header ();
};

// Obligatory material to make this a recognizeable imageio plugin:
OIIO_PLUGIN_EXPORTS_BEGIN

    DLLEXPORT ImageInput* pnm_input_imageio_create () { return new PNMInput; }

    DLLEXPORT int pnm_imageio_version = OIIO_PLUGIN_VERSION;

    DLLEXPORT const char* pnm_input_extensions[] = {
        "ppm","pgm","pbm","pnm", NULL
    };

OIIO_PLUGIN_EXPORTS_END

inline bool
nextLine (std::ifstream &file, std::string &current_line, const char * &pos)
{
    if (!file.good())
        return false;
    getline (file, current_line);
    if (file.fail())
        return false;
    pos = current_line.c_str();
    return true;
}

inline const char *
nextToken (std::ifstream &file, std::string &current_line, const char * &pos)
{
    while (1) {
        while (isspace (*pos))
            pos++;
        if (*pos)
            break;
        else
            nextLine (file, current_line, pos);
    }
    return pos;
}

inline const char *
skipComments (std::ifstream &file, std::string &current_line,
              const char * & pos, char comment = '#')
{
    while (1) {
        nextToken (file, current_line, pos);
        if (*pos == comment)
            nextLine (file, current_line, pos);
        else
            break;
    }
    return pos;
}

inline bool
nextVal (std::ifstream & file, std::string &current_line,
         const char * &pos, int &val, char comment = '#')
{
    skipComments (file, current_line, pos, comment);
    if (!isdigit (*pos))
        return false;
    val = strtol (pos,(char**) &pos, 10);
    return true;
}

template <class T>
inline void
invert (const T *read, T *write, imagesize_t nvals)
{
    for (imagesize_t i=0; i < nvals; i++)
        write[i] = std::numeric_limits<T>::max() - read[i];
}

template <class T>
inline bool
ascii_to_raw (std::ifstream &file, std::string &current_line, const char * &pos,
              T *write, imagesize_t nvals, T max)
{
    if (max)
        for (imagesize_t i=0; i < nvals; i++) {
            int tmp;
            if (!nextVal (file, current_line, pos, tmp))
                return false;
            write[i] = std::min ((int)max, tmp) * std::numeric_limits<T>::max() / max;
        }
    else
        for (imagesize_t i=0; i < nvals; i++)
            write[i] = std::numeric_limits<T>::max();
    return true;
}

template <class T>
inline void
raw_to_raw (const T *read, T *write, imagesize_t nvals, T max)
{
    if (max)
        for (imagesize_t i=0; i < nvals; i++) {
            int tmp = read[i];
            write[i] = std::min ((int)max, tmp) * std::numeric_limits<T>::max() / max;
        }
    else
        for (imagesize_t i=0; i < nvals; i++)
            write[i] = std::numeric_limits<T>::max();
}

inline void
unpack (const unsigned char * read, unsigned char * write, imagesize_t size)
{
    imagesize_t w = 0, r = 0;
    unsigned char bit = 0x7, byte = 0;
    for (imagesize_t x = 0; x < size; x++) {
        if (bit == 0x7)
            byte = ~read[r++];
        write[w++] = 0 - ((byte & (1 << bit)) >> bit);//assign expanded bit
        bit = (bit - 1) & 0x7; // limit bit to [0; 8[
    }
}

template <class T>
inline bool
read_int (std::istream &in, T &dest, char comment='#')
{
    T ret;
    char c;
    while (!in.eof()) {
        in >> ret;
        if (!in.good()){
            in.clear();
            in >> c;
            if (c == comment)
                in.ignore (std::numeric_limits<std::streamsize>::max(), '\n');
            else
                return false;
        } else {
            dest = ret;
            return true;
        }
    }
    return false;
}

bool
PNMInput::read_file_scanline (void * data)
{
    try {

    std::vector<unsigned char> buf;
    bool good = true;
    if (!m_file.is_open())
        return false;
    int nsamples = m_spec.width * m_spec.nchannels;

    if (m_pnm_type >= 4 && m_pnm_type <= 6){
        int numbytes;
        if (m_pnm_type == 4)
            numbytes = (m_spec.width + 7) / 8;
        else
            numbytes = m_spec.scanline_bytes();
        buf.resize (numbytes);
        m_file.read ((char*)&buf[0], numbytes);
        if (!m_file.good())
            return false;
    }

    switch (m_pnm_type) {
        //Ascii
        case 1:
            good &= ascii_to_raw (m_file, m_current_line, m_pos, (unsigned char *) data,
                                  nsamples, (unsigned char)m_max_val);
            invert ((unsigned char *)data, (unsigned char *)data, nsamples);
            break;
        case 2:
        case 3:
            if (m_max_val > std::numeric_limits<unsigned char>::max())
                good &= ascii_to_raw (m_file, m_current_line, m_pos, (unsigned short *) data,
                                      nsamples, (unsigned short)m_max_val);
            else
                good &= ascii_to_raw (m_file, m_current_line, m_pos, (unsigned char *) data,
                                      nsamples, (unsigned char)m_max_val);
            break;
        //Raw
        case 4:
            unpack (&buf[0], (unsigned char *)data, nsamples);
            break;
        case 5:
        case 6:
            if (m_max_val > std::numeric_limits<unsigned char>::max())
                raw_to_raw ((unsigned short *)&buf[0], (unsigned short *) data,
                            nsamples, (unsigned short)m_max_val);
            else
                raw_to_raw ((unsigned char *)&buf[0], (unsigned char *) data,
                            nsamples, (unsigned char)m_max_val);
            break;
        default:
            return false;
    }
    return good;

    }
    catch (const std::exception &e) {
        error ("PNM exception: %s", e.what());
        return false;
    }
}

bool
PNMInput::read_file_header ()
{
    try {

    unsigned int width, height;
    char c;
    if (!m_file.is_open())
        return false;

    m_file >> c >> m_pnm_type;

    //MagicNumber
    if (c != 'P')
        return false;
    if (!(m_pnm_type >= 1 && m_pnm_type <= 6))
        return false;

    //Size
    if (!read_int (m_file, width))
        return false;
    if (!read_int (m_file, height))
        return false;

    //Max Val
    if (m_pnm_type != 1 && m_pnm_type != 4) {
        if (!read_int (m_file, m_max_val))
            return false;
    } else
        m_max_val = 1;

    //Space before content
    if (!(isspace (m_file.get()) && m_file.good()))
        return false;

    if (m_pnm_type == 3 || m_pnm_type == 6)
        m_spec =  ImageSpec (width, height, 3,
                (m_max_val > 255) ? TypeDesc::UINT16 : TypeDesc::UINT8);
    else
        m_spec =  ImageSpec (width, height, 1,
                (m_max_val > 255) ? TypeDesc::UINT16 : TypeDesc::UINT8);

    if (m_spec.nchannels == 1)
        m_spec.channelnames[0] = "I";
    else
        m_spec.default_channel_names();

    if (m_pnm_type >= 1 && m_pnm_type <= 3)
        m_spec.attribute ("pnm:binary", 0);
    else
        m_spec.attribute ("pnm:binary", 1);

    m_spec.attribute ("oiio:BitsPerSample", ceilf (logf (m_max_val + 1)/logf (2)));
    return true;
    }
    catch (const std::exception &e) {
        error ("PNM exception: %s", e.what());
        return false;
    }
}

bool
PNMInput::open (const std::string &name, ImageSpec &newspec)
{
    if (m_file.is_open()) //close previously opened file
        m_file.close();

    Filesystem::open (m_file, name);

    m_current_line = "";
    m_pos = m_current_line.c_str();

    if (!read_file_header())
        return false;

    newspec = m_spec;
    return true;
}

bool
PNMInput::close ()
{
    m_file.close();
    return true;
}

bool
PNMInput::read_native_scanline (int y, int z, void *data)
{
    if (z)
        return false;
    if (!read_file_scanline (data))
        return false;
    return true;
}

OIIO_PLUGIN_NAMESPACE_END
<commit_msg>Open PNM files in binary mode<commit_after>/*
  Copyright 2010 Larry Gritz and the other authors and contributors.
  All Rights Reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are
  met:
  * Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
  * Neither the name of the software's owners nor the names of its
    contributors may be used to endorse or promote products derived from
    this software without specific prior written permission.
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

  (This is the Modified BSD License)
*/

#include <string>
#include <fstream>
#include <cstdlib>

#include "export.h"
#include "filesystem.h"
#include "imageio.h"

OIIO_PLUGIN_NAMESPACE_BEGIN

class PNMInput : public ImageInput {
public:
    virtual const char* format_name (void) const { return "pnm"; }
    virtual bool open (const std::string &name, ImageSpec &newspec);
    virtual bool close ();
    virtual int current_subimage (void) const { return 0; }
    virtual bool read_native_scanline (int y, int z, void *data);

private:
    std::ifstream m_file;
    std::string m_current_line; ///< Buffer the image pixels
    const char * m_pos;
    unsigned int m_pnm_type, m_max_val;

    bool read_file_scanline (void * data);
    bool read_file_header ();
};

// Obligatory material to make this a recognizeable imageio plugin:
OIIO_PLUGIN_EXPORTS_BEGIN

    DLLEXPORT ImageInput* pnm_input_imageio_create () { return new PNMInput; }

    DLLEXPORT int pnm_imageio_version = OIIO_PLUGIN_VERSION;

    DLLEXPORT const char* pnm_input_extensions[] = {
        "ppm","pgm","pbm","pnm", NULL
    };

OIIO_PLUGIN_EXPORTS_END

inline bool
nextLine (std::ifstream &file, std::string &current_line, const char * &pos)
{
    if (!file.good())
        return false;
    getline (file, current_line);
    if (file.fail())
        return false;
    pos = current_line.c_str();
    return true;
}

inline const char *
nextToken (std::ifstream &file, std::string &current_line, const char * &pos)
{
    while (1) {
        while (isspace (*pos))
            pos++;
        if (*pos)
            break;
        else
            nextLine (file, current_line, pos);
    }
    return pos;
}

inline const char *
skipComments (std::ifstream &file, std::string &current_line,
              const char * & pos, char comment = '#')
{
    while (1) {
        nextToken (file, current_line, pos);
        if (*pos == comment)
            nextLine (file, current_line, pos);
        else
            break;
    }
    return pos;
}

inline bool
nextVal (std::ifstream & file, std::string &current_line,
         const char * &pos, int &val, char comment = '#')
{
    skipComments (file, current_line, pos, comment);
    if (!isdigit (*pos))
        return false;
    val = strtol (pos,(char**) &pos, 10);
    return true;
}

template <class T>
inline void
invert (const T *read, T *write, imagesize_t nvals)
{
    for (imagesize_t i=0; i < nvals; i++)
        write[i] = std::numeric_limits<T>::max() - read[i];
}

template <class T>
inline bool
ascii_to_raw (std::ifstream &file, std::string &current_line, const char * &pos,
              T *write, imagesize_t nvals, T max)
{
    if (max)
        for (imagesize_t i=0; i < nvals; i++) {
            int tmp;
            if (!nextVal (file, current_line, pos, tmp))
                return false;
            write[i] = std::min ((int)max, tmp) * std::numeric_limits<T>::max() / max;
        }
    else
        for (imagesize_t i=0; i < nvals; i++)
            write[i] = std::numeric_limits<T>::max();
    return true;
}

template <class T>
inline void
raw_to_raw (const T *read, T *write, imagesize_t nvals, T max)
{
    if (max)
        for (imagesize_t i=0; i < nvals; i++) {
            int tmp = read[i];
            write[i] = std::min ((int)max, tmp) * std::numeric_limits<T>::max() / max;
        }
    else
        for (imagesize_t i=0; i < nvals; i++)
            write[i] = std::numeric_limits<T>::max();
}

inline void
unpack (const unsigned char * read, unsigned char * write, imagesize_t size)
{
    imagesize_t w = 0, r = 0;
    unsigned char bit = 0x7, byte = 0;
    for (imagesize_t x = 0; x < size; x++) {
        if (bit == 0x7)
            byte = ~read[r++];
        write[w++] = 0 - ((byte & (1 << bit)) >> bit);//assign expanded bit
        bit = (bit - 1) & 0x7; // limit bit to [0; 8[
    }
}

template <class T>
inline bool
read_int (std::istream &in, T &dest, char comment='#')
{
    T ret;
    char c;
    while (!in.eof()) {
        in >> ret;
        if (!in.good()){
            in.clear();
            in >> c;
            if (c == comment)
                in.ignore (std::numeric_limits<std::streamsize>::max(), '\n');
            else
                return false;
        } else {
            dest = ret;
            return true;
        }
    }
    return false;
}

bool
PNMInput::read_file_scanline (void * data)
{
    try {

    std::vector<unsigned char> buf;
    bool good = true;
    if (!m_file.is_open())
        return false;
    int nsamples = m_spec.width * m_spec.nchannels;

    if (m_pnm_type >= 4 && m_pnm_type <= 6){
        int numbytes;
        if (m_pnm_type == 4)
            numbytes = (m_spec.width + 7) / 8;
        else
            numbytes = m_spec.scanline_bytes();
        buf.resize (numbytes);
        m_file.read ((char*)&buf[0], numbytes);
        if (!m_file.good())
            return false;
    }

    switch (m_pnm_type) {
        //Ascii
        case 1:
            good &= ascii_to_raw (m_file, m_current_line, m_pos, (unsigned char *) data,
                                  nsamples, (unsigned char)m_max_val);
            invert ((unsigned char *)data, (unsigned char *)data, nsamples);
            break;
        case 2:
        case 3:
            if (m_max_val > std::numeric_limits<unsigned char>::max())
                good &= ascii_to_raw (m_file, m_current_line, m_pos, (unsigned short *) data,
                                      nsamples, (unsigned short)m_max_val);
            else
                good &= ascii_to_raw (m_file, m_current_line, m_pos, (unsigned char *) data,
                                      nsamples, (unsigned char)m_max_val);
            break;
        //Raw
        case 4:
            unpack (&buf[0], (unsigned char *)data, nsamples);
            break;
        case 5:
        case 6:
            if (m_max_val > std::numeric_limits<unsigned char>::max())
                raw_to_raw ((unsigned short *)&buf[0], (unsigned short *) data,
                            nsamples, (unsigned short)m_max_val);
            else
                raw_to_raw ((unsigned char *)&buf[0], (unsigned char *) data,
                            nsamples, (unsigned char)m_max_val);
            break;
        default:
            return false;
    }
    return good;

    }
    catch (const std::exception &e) {
        error ("PNM exception: %s", e.what());
        return false;
    }
}

bool
PNMInput::read_file_header ()
{
    try {

    unsigned int width, height;
    char c;
    if (!m_file.is_open())
        return false;

    m_file >> c >> m_pnm_type;

    //MagicNumber
    if (c != 'P')
        return false;
    if (!(m_pnm_type >= 1 && m_pnm_type <= 6))
        return false;

    //Size
    if (!read_int (m_file, width))
        return false;
    if (!read_int (m_file, height))
        return false;

    //Max Val
    if (m_pnm_type != 1 && m_pnm_type != 4) {
        if (!read_int (m_file, m_max_val))
            return false;
    } else
        m_max_val = 1;

    //Space before content
    if (!(isspace (m_file.get()) && m_file.good()))
        return false;

    if (m_pnm_type == 3 || m_pnm_type == 6)
        m_spec =  ImageSpec (width, height, 3,
                (m_max_val > 255) ? TypeDesc::UINT16 : TypeDesc::UINT8);
    else
        m_spec =  ImageSpec (width, height, 1,
                (m_max_val > 255) ? TypeDesc::UINT16 : TypeDesc::UINT8);

    if (m_spec.nchannels == 1)
        m_spec.channelnames[0] = "I";
    else
        m_spec.default_channel_names();

    if (m_pnm_type >= 1 && m_pnm_type <= 3)
        m_spec.attribute ("pnm:binary", 0);
    else
        m_spec.attribute ("pnm:binary", 1);

    m_spec.attribute ("oiio:BitsPerSample", ceilf (logf (m_max_val + 1)/logf (2)));
    return true;
    }
    catch (const std::exception &e) {
        error ("PNM exception: %s", e.what());
        return false;
    }
}

bool
PNMInput::open (const std::string &name, ImageSpec &newspec)
{
    if (m_file.is_open()) //close previously opened file
        m_file.close();

    Filesystem::open (m_file, name, std::ios::in|std::ios::binary);

    m_current_line = "";
    m_pos = m_current_line.c_str();

    if (!read_file_header())
        return false;

    newspec = m_spec;
    return true;
}

bool
PNMInput::close ()
{
    m_file.close();
    return true;
}

bool
PNMInput::read_native_scanline (int y, int z, void *data)
{
    if (z)
        return false;
    if (!read_file_scanline (data))
        return false;
    return true;
}

OIIO_PLUGIN_NAMESPACE_END
<|endoftext|>


<commit_before><commit_msg>Debug info for pass compute and mesh shaders fixed<commit_after><|endoftext|>


<commit_before>#include "Variant.h"

using namespace std;
using namespace vcf;

int main(int argc, char** argv) {

    VariantCallFile variantFile;

    if (argc > 1) {
        string filename = argv[1];
        variantFile.open(filename);
    } else {
        variantFile.open(std::cin);
    }

    if (!variantFile.is_open()) {
        return 1;
    }
    // obtain all possible field names
    vector<string> infofields;
    vector<string> infoflags;

    for (map<string, string>::iterator i = variantFile.infoTypes.begin(); i != variantFile.infoTypes.end(); ++i) {
        if (i->second == "Flag") {
            infoflags.push_back(i->first);
        } else {
            infofields.push_back(i->first);
        }
    }

    // write header

    // defaults
    cout << "CHROM\tPOS\tID\tREF\tALT\tQUAL\tFILTER\t";

    // configurable info field
    for (vector<string>::iterator i = infofields.begin(); i != infofields.end(); ++i) {
        if (i != infofields.begin()) {
            cout << "\t";
        }
        cout << *i;
    }
    for (vector<string>::iterator i = infoflags.begin(); i != infoflags.end(); ++i) {
        cout << "\t" << *i;
    }
    cout << endl;

    Variant var(variantFile);
    while (variantFile.getNextVariant(var)) {

        cout << var.sequenceName << "\t"
             << var.position << "\t"
             << var.id << "\t"
             << var.ref << "\t";
        var.printAlt(cout);
        cout << "\t"
             << var.quality << "\t"
             << var.filter << "\t";

        for (vector<string>::iterator i = infofields.begin(); i != infofields.end(); ++i) {
            string value;
            string& name = *i;
            map<string, string>::iterator f = var.info.find(name);
            if (f != var.info.end()) {
                value = f->second;
            }
            cout << "\t" << value;
        }

        for (vector<string>::iterator i = infoflags.begin(); i != infoflags.end(); ++i) {
            string value;
            string& name = *i;
            map<string, bool>::iterator f = var.infoFlags.find(name);
            cout << "\t";
            if (f != var.infoFlags.end()) {
                cout << "TRUE";
            } else {
                cout << "FALSE";
            }
        }

        cout << endl;

    }

    return 0;

}

<commit_msg>fixed tab problem in vcf2tsv<commit_after>#include "Variant.h"

using namespace std;
using namespace vcf;

int main(int argc, char** argv) {

    VariantCallFile variantFile;

    if (argc > 1) {
        string filename = argv[1];
        variantFile.open(filename);
    } else {
        variantFile.open(std::cin);
    }

    if (!variantFile.is_open()) {
        return 1;
    }
    // obtain all possible field names
    vector<string> infofields;
    vector<string> infoflags;

    for (map<string, string>::iterator i = variantFile.infoTypes.begin(); i != variantFile.infoTypes.end(); ++i) {
        if (i->second == "Flag") {
            infoflags.push_back(i->first);
        } else {
            infofields.push_back(i->first);
        }
    }

    // write header

    // defaults
    cout << "CHROM\tPOS\tID\tREF\tALT\tQUAL\tFILTER\t";

    // configurable info field
    for (vector<string>::iterator i = infofields.begin(); i != infofields.end(); ++i) {
        if (i != infofields.begin()) {
            cout << "\t";
        }
        cout << *i;
    }
    for (vector<string>::iterator i = infoflags.begin(); i != infoflags.end(); ++i) {
        cout << "\t" << *i;
    }
    cout << endl;

    Variant var(variantFile);
    while (variantFile.getNextVariant(var)) {

        cout << var.sequenceName << "\t"
             << var.position << "\t"
             << var.id << "\t"
             << var.ref << "\t";
        var.printAlt(cout);
        cout << "\t"
             << var.quality << "\t"
             << var.filter;

        for (vector<string>::iterator i = infofields.begin(); i != infofields.end(); ++i) {
            string value;
            string& name = *i;
            map<string, string>::iterator f = var.info.find(name);
            if (f != var.info.end()) {
                value = f->second;
            }
            cout << "\t" << value;
        }

        for (vector<string>::iterator i = infoflags.begin(); i != infoflags.end(); ++i) {
            string value;
            string& name = *i;
            map<string, bool>::iterator f = var.infoFlags.find(name);
            cout << "\t";
            if (f != var.infoFlags.end()) {
                cout << "TRUE";
            } else {
                cout << "FALSE";
            }
        }

        cout << endl;

    }

    return 0;

}

<|endoftext|>