<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/renderer_host/gtk_key_bindings_handler.h"

#include <gdk/gdkkeysyms.h>
#include <string>
#include <utility>
#include <vector>

#include "base/basictypes.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/edit_command.h"
#include "chrome/common/native_web_keyboard_event.h"
#include "testing/gtest/include/gtest/gtest.h"

class GtkKeyBindingsHandlerTest : public testing::Test {
 protected:
  struct EditCommand {
    const char* name;
    const char* value;
  };

  GtkKeyBindingsHandlerTest()
      : window_(gtk_window_new(GTK_WINDOW_TOPLEVEL)),
        handler_(NULL) {
    FilePath gtkrc;
    PathService::Get(chrome::DIR_TEST_DATA, &gtkrc);
    gtkrc = gtkrc.AppendASCII("gtk_key_bindings_test_gtkrc");
    CHECK(file_util::PathExists(gtkrc)) << gtkrc.value();

    gtk_rc_parse(gtkrc.value().c_str());

    GtkWidget* fixed = gtk_fixed_new();
    handler_ = new GtkKeyBindingsHandler(fixed);
    gtk_container_add(GTK_CONTAINER(window_), fixed);
    gtk_widget_show(fixed);
    gtk_widget_show(window_);
  }
  ~GtkKeyBindingsHandlerTest() {
    gtk_widget_destroy(window_);
    delete handler_;
  }

  NativeWebKeyboardEvent NewNativeWebKeyboardEvent(guint keyval, guint state) {
    GdkKeymap* keymap =
        gdk_keymap_get_for_display(gtk_widget_get_display(window_));
    CHECK(keymap != NULL);

    GdkKeymapKey *keys = NULL;
    gint n_keys = 0;
    if (gdk_keymap_get_entries_for_keyval(keymap, keyval, &keys, &n_keys)) {
      GdkEventKey event;
      event.type = GDK_KEY_PRESS;
      event.window = NULL;
      event.send_event = 0;
      event.time = 0;
      event.state = state;
      event.keyval = keyval;
      event.length = 0;
      event.string = NULL;
      event.hardware_keycode = keys[0].keycode;
      event.group = keys[0].group;
      event.is_modifier = 0;
      g_free(keys);
      LOG(INFO) << "Create key event: keyval:" << keyval
                << " hardware_keycode:" << event.hardware_keycode
                << " group:" << static_cast<unsigned int>(event.group);
      return NativeWebKeyboardEvent(&event);
    }
    CHECK(false) << "Failed to create key event for keyval:" << keyval;
    return NativeWebKeyboardEvent();
  }

  void TestKeyBinding(const NativeWebKeyboardEvent& event,
                      const EditCommand expected_result[],
                      size_t size) {
    EditCommands result;
    ASSERT_TRUE(handler_->Match(event, &result));
    ASSERT_EQ(size, result.size());
    for (size_t i = 0; i < size; ++i) {
      ASSERT_STREQ(expected_result[i].name, result[i].name.c_str());
      ASSERT_STREQ(expected_result[i].value, result[i].value.c_str());
    }
  }

 protected:
  GtkWidget* window_;
  GtkKeyBindingsHandler* handler_;
};

// Does not work in a chroot. See bug 60363.
TEST_F(GtkKeyBindingsHandlerTest, FAILS_MoveCursor) {
  static const EditCommand kEditCommands[] = {
    // "move-cursor" (logical-positions, -2, 0)
    { "MoveBackward", "" },
    { "MoveBackward", "" },
    // "move-cursor" (logical-positions, 2, 0)
    { "MoveForward", "" },
    { "MoveForward", "" },
    // "move-cursor" (visual-positions, -1, 1)
    { "MoveLeftAndModifySelection", "" },
    // "move-cursor" (visual-positions, 1, 1)
    { "MoveRightAndModifySelection", "" },
    // "move-cursor" (words, -1, 0)
    { "MoveWordBackward", "" },
    // "move-cursor" (words, 1, 0)
    { "MoveWordForward", "" },
    // "move-cursor" (display-lines, -1, 0)
    { "MoveUp", "" },
    // "move-cursor" (display-lines, 1, 0)
    { "MoveDown", "" },
    // "move-cursor" (display-line-ends, -1, 0)
    { "MoveToBeginningOfLine", "" },
    // "move-cursor" (display-line-ends, 1, 0)
    { "MoveToEndOfLine", "" },
    // "move-cursor" (paragraph-ends, -1, 0)
    { "MoveToBeginningOfParagraph", "" },
    // "move-cursor" (paragraph-ends, 1, 0)
    { "MoveToEndOfParagraph", "" },
    // "move-cursor" (pages, -1, 0)
    { "MovePageUp", "" },
    // "move-cursor" (pages, 1, 0)
    { "MovePageDown", "" },
    // "move-cursor" (buffer-ends, -1, 0)
    { "MoveToBeginningOfDocument", "" },
    // "move-cursor" (buffer-ends, 1, 0)
    { "MoveToEndOfDocument", "" }
  };

  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_1, GDK_CONTROL_MASK),
                 kEditCommands, arraysize(kEditCommands));
}

// Does not work in a chroot. See bug 60363.
TEST_F(GtkKeyBindingsHandlerTest, FAILS_DeleteFromCursor) {
  static const EditCommand kEditCommands[] = {
    // "delete-from-cursor" (chars, -2)
    { "DeleteBackward", "" },
    { "DeleteBackward", "" },
    // "delete-from-cursor" (chars, 2)
    { "DeleteForward", "" },
    { "DeleteForward", "" },
    // "delete-from-cursor" (word-ends, -1)
    { "DeleteWordBackward", "" },
    // "delete-from-cursor" (word-ends, 1)
    { "DeleteWordForward", "" },
    // "delete-from-cursor" (words, -1)
    { "MoveWordBackward", "" },
    { "DeleteWordForward", "" },
    // "delete-from-cursor" (words, 1)
    { "MoveWordForward", "" },
    { "DeleteWordBackward", "" },
    // "delete-from-cursor" (display-lines, -1)
    { "MoveToBeginningOfLine", "" },
    { "DeleteToEndOfLine", "" },
    // "delete-from-cursor" (display-lines, 1)
    { "MoveToBeginningOfLine", "" },
    { "DeleteToEndOfLine", "" },
    // "delete-from-cursor" (display-line-ends, -1)
    { "DeleteToBeginningOfLine", "" },
    // "delete-from-cursor" (display-line-ends, 1)
    { "DeleteToEndOfLine", "" },
    // "delete-from-cursor" (paragraph-ends, -1)
    { "DeleteToBeginningOfParagraph", "" },
    // "delete-from-cursor" (paragraph-ends, 1)
    { "DeleteToEndOfParagraph", "" },
    // "delete-from-cursor" (paragraphs, -1)
    { "MoveToBeginningOfParagraph", "" },
    { "DeleteToEndOfParagraph", "" },
    // "delete-from-cursor" (paragraphs, 1)
    { "MoveToBeginningOfParagraph", "" },
    { "DeleteToEndOfParagraph", "" },
  };

  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_2, GDK_CONTROL_MASK),
                 kEditCommands, arraysize(kEditCommands));
}

// Does not work in a chroot. See bug 60363.
TEST_F(GtkKeyBindingsHandlerTest, FAILS_OtherActions) {
  static const EditCommand kBackspace[] = {
    { "DeleteBackward", "" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_3, GDK_CONTROL_MASK),
                 kBackspace, arraysize(kBackspace));

  static const EditCommand kCopyClipboard[] = {
    { "Copy", "" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_4, GDK_CONTROL_MASK),
                 kCopyClipboard, arraysize(kCopyClipboard));

  static const EditCommand kCutClipboard[] = {
    { "Cut", "" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_5, GDK_CONTROL_MASK),
                 kCutClipboard, arraysize(kCutClipboard));

  static const EditCommand kInsertAtCursor[] = {
    { "InsertText", "hello" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_6, GDK_CONTROL_MASK),
                 kInsertAtCursor, arraysize(kInsertAtCursor));

  static const EditCommand kPasteClipboard[] = {
    { "Paste", "" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_7, GDK_CONTROL_MASK),
                 kPasteClipboard, arraysize(kPasteClipboard));

  static const EditCommand kSelectAll[] = {
    { "Unselect", "" },
    { "SelectAll", "" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_8, GDK_CONTROL_MASK),
                 kSelectAll, arraysize(kSelectAll));

  static const EditCommand kSetAnchor[] = {
    { "SetMark", "" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_9, GDK_CONTROL_MASK),
                 kSetAnchor, arraysize(kSetAnchor));
}
<commit_msg>Remove all CHECK() in gtk_key_bindings_handler_unittest.cc<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/renderer_host/gtk_key_bindings_handler.h"

#include <gdk/gdkkeysyms.h>
#include <string>
#include <utility>
#include <vector>

#include "base/basictypes.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/edit_command.h"
#include "chrome/common/native_web_keyboard_event.h"
#include "testing/gtest/include/gtest/gtest.h"

class GtkKeyBindingsHandlerTest : public testing::Test {
 protected:
  struct EditCommand {
    const char* name;
    const char* value;
  };

  GtkKeyBindingsHandlerTest()
      : window_(gtk_window_new(GTK_WINDOW_TOPLEVEL)),
        handler_(NULL) {
    FilePath gtkrc;
    PathService::Get(chrome::DIR_TEST_DATA, &gtkrc);
    gtkrc = gtkrc.AppendASCII("gtk_key_bindings_test_gtkrc");

    gtk_rc_parse(gtkrc.value().c_str());

    GtkWidget* fixed = gtk_fixed_new();
    handler_ = new GtkKeyBindingsHandler(fixed);
    gtk_container_add(GTK_CONTAINER(window_), fixed);
    gtk_widget_show(fixed);
    gtk_widget_show(window_);
  }
  ~GtkKeyBindingsHandlerTest() {
    gtk_widget_destroy(window_);
    delete handler_;
  }

  NativeWebKeyboardEvent NewNativeWebKeyboardEvent(guint keyval, guint state) {
    GdkKeymap* keymap =
        gdk_keymap_get_for_display(gtk_widget_get_display(window_));

    GdkKeymapKey *keys = NULL;
    gint n_keys = 0;
    if (gdk_keymap_get_entries_for_keyval(keymap, keyval, &keys, &n_keys)) {
      GdkEventKey event;
      event.type = GDK_KEY_PRESS;
      event.window = NULL;
      event.send_event = 0;
      event.time = 0;
      event.state = state;
      event.keyval = keyval;
      event.length = 0;
      event.string = NULL;
      event.hardware_keycode = keys[0].keycode;
      event.group = keys[0].group;
      event.is_modifier = 0;
      g_free(keys);
      return NativeWebKeyboardEvent(&event);
    }
    LOG(ERROR) << "Failed to create key event for keyval:" << keyval;
    return NativeWebKeyboardEvent();
  }

  void TestKeyBinding(const NativeWebKeyboardEvent& event,
                      const EditCommand expected_result[],
                      size_t size) {
    EditCommands result;
    ASSERT_TRUE(handler_->Match(event, &result));
    ASSERT_EQ(size, result.size());
    for (size_t i = 0; i < size; ++i) {
      ASSERT_STREQ(expected_result[i].name, result[i].name.c_str());
      ASSERT_STREQ(expected_result[i].value, result[i].value.c_str());
    }
  }

 protected:
  GtkWidget* window_;
  GtkKeyBindingsHandler* handler_;
};

// Does not work in a chroot. See bug 60363.
TEST_F(GtkKeyBindingsHandlerTest, FAILS_MoveCursor) {
  static const EditCommand kEditCommands[] = {
    // "move-cursor" (logical-positions, -2, 0)
    { "MoveBackward", "" },
    { "MoveBackward", "" },
    // "move-cursor" (logical-positions, 2, 0)
    { "MoveForward", "" },
    { "MoveForward", "" },
    // "move-cursor" (visual-positions, -1, 1)
    { "MoveLeftAndModifySelection", "" },
    // "move-cursor" (visual-positions, 1, 1)
    { "MoveRightAndModifySelection", "" },
    // "move-cursor" (words, -1, 0)
    { "MoveWordBackward", "" },
    // "move-cursor" (words, 1, 0)
    { "MoveWordForward", "" },
    // "move-cursor" (display-lines, -1, 0)
    { "MoveUp", "" },
    // "move-cursor" (display-lines, 1, 0)
    { "MoveDown", "" },
    // "move-cursor" (display-line-ends, -1, 0)
    { "MoveToBeginningOfLine", "" },
    // "move-cursor" (display-line-ends, 1, 0)
    { "MoveToEndOfLine", "" },
    // "move-cursor" (paragraph-ends, -1, 0)
    { "MoveToBeginningOfParagraph", "" },
    // "move-cursor" (paragraph-ends, 1, 0)
    { "MoveToEndOfParagraph", "" },
    // "move-cursor" (pages, -1, 0)
    { "MovePageUp", "" },
    // "move-cursor" (pages, 1, 0)
    { "MovePageDown", "" },
    // "move-cursor" (buffer-ends, -1, 0)
    { "MoveToBeginningOfDocument", "" },
    // "move-cursor" (buffer-ends, 1, 0)
    { "MoveToEndOfDocument", "" }
  };

  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_1, GDK_CONTROL_MASK),
                 kEditCommands, arraysize(kEditCommands));
}

// Does not work in a chroot. See bug 60363.
TEST_F(GtkKeyBindingsHandlerTest, FAILS_DeleteFromCursor) {
  static const EditCommand kEditCommands[] = {
    // "delete-from-cursor" (chars, -2)
    { "DeleteBackward", "" },
    { "DeleteBackward", "" },
    // "delete-from-cursor" (chars, 2)
    { "DeleteForward", "" },
    { "DeleteForward", "" },
    // "delete-from-cursor" (word-ends, -1)
    { "DeleteWordBackward", "" },
    // "delete-from-cursor" (word-ends, 1)
    { "DeleteWordForward", "" },
    // "delete-from-cursor" (words, -1)
    { "MoveWordBackward", "" },
    { "DeleteWordForward", "" },
    // "delete-from-cursor" (words, 1)
    { "MoveWordForward", "" },
    { "DeleteWordBackward", "" },
    // "delete-from-cursor" (display-lines, -1)
    { "MoveToBeginningOfLine", "" },
    { "DeleteToEndOfLine", "" },
    // "delete-from-cursor" (display-lines, 1)
    { "MoveToBeginningOfLine", "" },
    { "DeleteToEndOfLine", "" },
    // "delete-from-cursor" (display-line-ends, -1)
    { "DeleteToBeginningOfLine", "" },
    // "delete-from-cursor" (display-line-ends, 1)
    { "DeleteToEndOfLine", "" },
    // "delete-from-cursor" (paragraph-ends, -1)
    { "DeleteToBeginningOfParagraph", "" },
    // "delete-from-cursor" (paragraph-ends, 1)
    { "DeleteToEndOfParagraph", "" },
    // "delete-from-cursor" (paragraphs, -1)
    { "MoveToBeginningOfParagraph", "" },
    { "DeleteToEndOfParagraph", "" },
    // "delete-from-cursor" (paragraphs, 1)
    { "MoveToBeginningOfParagraph", "" },
    { "DeleteToEndOfParagraph", "" },
  };

  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_2, GDK_CONTROL_MASK),
                 kEditCommands, arraysize(kEditCommands));
}

// Does not work in a chroot. See bug 60363.
TEST_F(GtkKeyBindingsHandlerTest, FAILS_OtherActions) {
  static const EditCommand kBackspace[] = {
    { "DeleteBackward", "" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_3, GDK_CONTROL_MASK),
                 kBackspace, arraysize(kBackspace));

  static const EditCommand kCopyClipboard[] = {
    { "Copy", "" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_4, GDK_CONTROL_MASK),
                 kCopyClipboard, arraysize(kCopyClipboard));

  static const EditCommand kCutClipboard[] = {
    { "Cut", "" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_5, GDK_CONTROL_MASK),
                 kCutClipboard, arraysize(kCutClipboard));

  static const EditCommand kInsertAtCursor[] = {
    { "InsertText", "hello" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_6, GDK_CONTROL_MASK),
                 kInsertAtCursor, arraysize(kInsertAtCursor));

  static const EditCommand kPasteClipboard[] = {
    { "Paste", "" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_7, GDK_CONTROL_MASK),
                 kPasteClipboard, arraysize(kPasteClipboard));

  static const EditCommand kSelectAll[] = {
    { "Unselect", "" },
    { "SelectAll", "" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_8, GDK_CONTROL_MASK),
                 kSelectAll, arraysize(kSelectAll));

  static const EditCommand kSetAnchor[] = {
    { "SetMark", "" }
  };
  TestKeyBinding(NewNativeWebKeyboardEvent(GDK_9, GDK_CONTROL_MASK),
                 kSetAnchor, arraysize(kSetAnchor));
}
<|endoftext|>


<commit_before>// Copyright 2010 Google Inc. All Rights Reserved.
// Author: jacobsa@google.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// A driver for Google JS Test test. Looks for a file named
// "*-gjstest-scripts.binarypb" in the directory identified by TEST_SRCDIR, and
// runs its scripts and then any tests that its scripts registered.
//
// TODO(jacobsa): These should probably be changed into flags that the user
// gives explicitly. Maybe this should be combined with the compiler tool too.

#include <string>
#include <vector>

#include <gflags/gflags.h>

#include "base/integral_types.h"
#include "base/logging.h"
#include "file/file_utils.h"
#include "gjstest/internal/compiler/compiler.pb.h"
#include "gjstest/internal/driver/cpp/driver.h"
#include "strings/strutil.h"

DEFINE_string(filter, "", "Regular expression for test names to run.");

namespace gjstest {

// Look for a file with the given suffix in the supplied directory, crashing if
// there is not exactly one such file. Return the path to the single file.
static string FindSingleFileWithSuffix(
    const string& directory,
    const string& suffix) {
  vector<string> files;
  FindFiles(directory, &files);

  string result;
  for (uint32 i = 0; i < files.size(); ++i) {
    const string& path = files[i];
    if (HasSuffixString(path, suffix)) {
      CHECK(result.empty())
          << "Duplicate match for suffix: " << suffix << "\n"
          << "1st match: " << result << "\n"
          << "2nd match: " << path << "\n";

      result = path;
    }
  }

  CHECK(!result.empty()) << "Couldn't find file with suffix: " << suffix;

  return result;
}

static bool Run() {
  // Find the file containing the scripts to be run, and load its contents.
  const string scripts_path =
      FindSingleFileWithSuffix(
          StringFromEnv("TEST_SRCDIR", ""),
          "-gjstest-scripts.binarypb");

  NamedScripts scripts;
  CHECK(scripts.ParseFromString(ReadFileOrDie(scripts_path)))
      << "Couldn't parse NamedScripts proto.";

  // Run the tests.
  string output;
  string xml;
  const bool success = RunTests(scripts, FLAGS_filter, &output, &xml);

  // Log the output.
  LOG(ERROR) << output;

  // Write out the XML file to the appropriate place.
  const string xml_path = StringFromEnv("XML_OUTPUT_FILE", "");
  WriteStringToFileOrDie(xml, xml_path);

  return success;
}

}  // namespace gjstest

int main(int argc, char** argv) {
  // TODO(jacobsa): Initialize flags and logging.

  // Turn off timestamp and file number junk in the output of LOG().
  FLAGS_log_prefix = false;

  return gjstest::Run() ? 0 : 1;
}
<commit_msg>Fixed more errors.<commit_after>// Copyright 2010 Google Inc. All Rights Reserved.
// Author: jacobsa@google.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// A driver for Google JS Test test. Looks for a file named
// "*-gjstest-scripts.binarypb" in the directory identified by TEST_SRCDIR, and
// runs its scripts and then any tests that its scripts registered.
//
// TODO(jacobsa): These should probably be changed into flags that the user
// gives explicitly. Maybe this should be combined with the compiler tool too.

#include <string>
#include <vector>

#include <gflags/gflags.h>

#include "base/integral_types.h"
#include "base/logging.h"
#include "file/file_utils.h"
#include "gjstest/internal/compiler/compiler.pb.h"
#include "gjstest/internal/driver/cpp/driver.h"
#include "strings/strutil.h"

DEFINE_string(filter, "", "Regular expression for test names to run.");

namespace gjstest {

// Look for a file with the given suffix in the supplied directory, crashing if
// there is not exactly one such file. Return the path to the single file.
static string FindSingleFileWithSuffix(
    const string& directory,
    const string& suffix) {
  vector<string> files;
  FindFiles(directory, &files);

  string result;
  for (uint32 i = 0; i < files.size(); ++i) {
    const string& path = files[i];
    if (HasSuffixString(path, suffix)) {
      CHECK(result.empty())
          << "Duplicate match for suffix: " << suffix << "\n"
          << "1st match: " << result << "\n"
          << "2nd match: " << path << "\n";

      result = path;
    }
  }

  CHECK(!result.empty()) << "Couldn't find file with suffix: " << suffix;

  return result;
}

static bool Run() {
  // Find the file containing the scripts to be run, and load its contents.
  const string scripts_path =
      FindSingleFileWithSuffix(
          google::StringFromEnv("TEST_SRCDIR", ""),
          "-gjstest-scripts.binarypb");

  NamedScripts scripts;
  CHECK(scripts.ParseFromString(ReadFileOrDie(scripts_path)))
      << "Couldn't parse NamedScripts proto.";

  // Run the tests.
  string output;
  string xml;
  const bool success = RunTests(scripts, FLAGS_filter, &output, &xml);

  // Log the output.
  LOG(ERROR) << output;

  // Write out the XML file to the appropriate place.
  const string xml_path = google::StringFromEnv("XML_OUTPUT_FILE", "");
  WriteStringToFileOrDie(xml, xml_path);

  return success;
}

}  // namespace gjstest

int main(int argc, char** argv) {
  // TODO(jacobsa): Initialize flags and logging.

  // Turn off timestamp and file number junk in the output of LOG().
  FLAGS_log_prefix = false;

  return gjstest::Run() ? 0 : 1;
}
<|endoftext|>


<commit_before>#include "model_item.h"
#include <QDebug>

/////////////////////////////////////////////////////////

void ModelItem::init(bool isFolder) {
    names = 0;
    childItems = QList<ModelItem*>();

    if (isFolder) {
        state = new ModelItemState(STATE_UNPROCESSED);
        state -> setProceed();
        folders = new QHash<QString, ModelItem *>();
    } else {
        folders = 0;
    }
}

void ModelItem::rootItemInit() {
    path = QString();
    name = QString("--(O_o)--");
    extension = QString();
}

ModelItem::ModelItem() {
    init(true);
    rootItemInit();
    parentItem = 0;
}

ModelItem::ModelItem(QJsonObject * attrs, ModelItem *parent) {
    init(true);
    parentItem = parent;

    if (attrs -> contains("p")) {
        name = path = attrs -> value("p").toString();

        if (parent != 0)
            parent -> folders -> insert(name, this);
    } else {
        name = attrs -> value("n").toString();
        state = new ModelItemState(attrs -> value("s").toInt());
        extension = attrs -> value("e").toString();
    }

    if (attrs -> contains("c")) {
        QJsonArray ar = attrs -> value("c").toArray();
        QJsonObject iter_obj;

        foreach(QJsonValue obj, ar) {
            iter_obj = obj.toObject();
            new ModelItem(&iter_obj, this);
        }
    }

    if (parent != 0) {
        parent -> appendChild(this);
    } else {
        rootItemInit();
    }
}

ModelItem::ModelItem(QString file_path, ModelItem *parent, int init_state) {
    state = new ModelItemState(init_state);
    parentItem = parent;

    if (!state -> isUnprocessed()) {
        init(false);
        path = file_path.section('/', 0, -2);
        name = file_path.section('/', -1, -1);
        extension = name.section('.', -1, -1);
        name = name.section('.', 0, -2);
    } else {
        init(true);
        name = path = file_path;
        extension = QString();

        if (parent != 0)
            parent -> folders -> insert(name, this);
    }

    if (parent != 0) { parent -> appendChild(this);}
}

ModelItem::~ModelItem() {
    qDeleteAll(childItems);

    delete state;

    if (folders != 0) {
        delete folders;
    }

    if (names != 0)
        delete names;

    if (parentItem != 0)
        delete parentItem;
}

/////////////////////////////////////////////////////////

ModelItem *ModelItem::parent() {
    return parentItem;
}

/////////////////////////////////////////////////////////

ModelItem *ModelItem::child(int row) {
    return childItems.value(row);
}

int ModelItem::childCount() const {
    return childItems.count();
}

void ModelItem::appendChild(ModelItem *item) {
    childItems.append(item);
}

bool ModelItem::insertChildren(int position, int count, int /*columns*/) {
    if (position < 0 || position > childItems.size())
        return false;

    for (int row = 0; row < count; ++row) {
//        QVector<QVariant> data(columns);
//        ModelItem *item = new ModelItem(data, this);
        ModelItem *item = new ModelItem(QString("BLA"), this);
        childItems.insert(position, item);
    }

    return true;
}

bool ModelItem::removeChildren(int position, int count)
{
    if (position < 0 || position + count > childItems.size())
        return false;

    for (int row = 0; row < count; ++row)
        delete childItems.takeAt(position);

    return true;
}

/////////////////////////////////////////////////////////

int ModelItem::column() const {
     return 0;
}

int ModelItem::columnCount() const {
     return 1;
//    if (parentItem == 0)
//        return 0;
//    else
//        return 1;
}

bool ModelItem::removeColumns(int /*position*/, int /*columns*/) {
//    if (position < 0 || position + columns > itemData.size())
//        return false;

//    for (int column = 0; column < columns; ++column)
//        itemData.remove(position);

//    foreach (TreeItem *child, childItems)
//        child->removeColumns(position, columns);

    return true;
}

bool ModelItem::insertColumns(int /*position*/, int /*columns*/) {
//    if (position < 0 || position > itemData.size())
//        return false;

//    for (int column = 0; column < columns; ++column)
//        itemData.insert(position, QVariant());

//    foreach (TreeItem *child, childItems)
//        child->insertColumns(position, columns);

    return true;
}

/////////////////////////////////////////////////////////

int ModelItem::row() const {
     if (parentItem)
         return parentItem->childItems.indexOf(const_cast<ModelItem*>(this));

     return 0;
}

/////////////////////////////////////////////////////////

QVariant ModelItem::data(int column) const {
    switch(column) {
        case NAMEUID: return name;
        case EXTENSIONUID: return extension;
        case PATHUID: return path;
        default: return QVariant();
    }
}

bool ModelItem::setData(int column, const QVariant &value) {
    if (column < 0 || column >= 2)
//    if (column < 0 || column >= itemData.size())
        return false;

//    itemData[column] = value;

    switch(column) {
        case NAMEUID: name = value.toString();
        case EXTENSIONUID: extension = value.toString();
        case PATHUID: path = value.toString();
    }

//    itemData[column] = value;

    return true;
}

/////////////////////////////////////////////////////////

QString ModelItem::fullpath() const {
    ModelItem * curr = parentItem;
    QString path_buff = "";

    while(curr != 0) {
        path_buff = curr -> path + '/' + path_buff;
        curr = curr -> parentItem;
    }

    return path_buff.mid(1) + name + '.' + extension;
}

//////////////////////////properties///////////////////////////////

ModelItemState * ModelItem::getState() const {
    return state;
}

void ModelItem::setState(int new_state, bool append_to_library) {
    if (state -> setBit(new_state) && append_to_library) {
        if (state -> isListened())
            Library::instance() -> addItem(this, STATE_LISTENED);
        else if (state -> isLiked())
            Library::instance() -> addItem(this, STATE_LIKED);
    }
}

///////////////////////////////////////////////////////

QJsonObject ModelItem::toJSON() {
    // TODO: logic build needed
    QJsonObject root = QJsonObject();

    if (childItems.length() > 0) {
        QJsonArray ar = QJsonArray();
        for(int i=0; i < childItems.length(); i++)
            ar.append(childItems.at(i)->toJSON());

        root["c"] = ar;
    }

    if (state -> isUnprocessed())
        root["p"] = path;
    else {
        root["n"] = name;
        root["s"] = state -> getFuncValue();
        root["e"] = extension;
    }

    return root;
}

//TODO: add list of extensions for extension serialization to extension index in list
<commit_msg>fix item deleting<commit_after>#include "model_item.h"
#include <QDebug>

/////////////////////////////////////////////////////////

void ModelItem::init(bool isFolder) {
    names = 0;
    childItems = QList<ModelItem*>();

    if (isFolder) {
        state = new ModelItemState(STATE_UNPROCESSED);
        state -> setProceed();
        folders = new QHash<QString, ModelItem *>();
    } else {
        folders = 0;
    }
}

void ModelItem::rootItemInit() {
    path = QString();
    name = QString("--(O_o)--");
    extension = QString();
}

ModelItem::ModelItem() {
    init(true);
    rootItemInit();
    parentItem = 0;
}

ModelItem::ModelItem(QJsonObject * attrs, ModelItem *parent) {
    init(true);
    parentItem = parent;

    if (attrs -> contains("p")) {
        name = path = attrs -> value("p").toString();

        if (parent != 0)
            parent -> folders -> insert(name, this);
    } else {
        name = attrs -> value("n").toString();
        state = new ModelItemState(attrs -> value("s").toInt());
        extension = attrs -> value("e").toString();
    }

    if (attrs -> contains("c")) {
        QJsonArray ar = attrs -> value("c").toArray();
        QJsonObject iter_obj;

        foreach(QJsonValue obj, ar) {
            iter_obj = obj.toObject();
            new ModelItem(&iter_obj, this);
        }
    }

    if (parent != 0) {
        parent -> appendChild(this);
    } else {
        rootItemInit();
    }
}

ModelItem::ModelItem(QString file_path, ModelItem *parent, int init_state) {
    state = new ModelItemState(init_state);
    parentItem = parent;

    if (!state -> isUnprocessed()) {
        init(false);
        path = file_path.section('/', 0, -2);
        name = file_path.section('/', -1, -1);
        extension = name.section('.', -1, -1);
        name = name.section('.', 0, -2);
    } else {
        init(true);
        name = path = file_path;
        extension = QString();

        if (parent != 0)
            parent -> folders -> insert(name, this);
    }

    if (parent != 0) { parent -> appendChild(this);}
}

ModelItem::~ModelItem() {
    qDeleteAll(childItems);

    delete state;

    delete folders;

    delete names;
}

/////////////////////////////////////////////////////////

ModelItem *ModelItem::parent() {
    return parentItem;
}

/////////////////////////////////////////////////////////

ModelItem *ModelItem::child(int row) {
    return childItems.value(row);
}

int ModelItem::childCount() const {
    return childItems.count();
}

void ModelItem::appendChild(ModelItem *item) {
    childItems.append(item);
}

bool ModelItem::insertChildren(int position, int count, int /*columns*/) {
    if (position < 0 || position > childItems.size())
        return false;

    for (int row = 0; row < count; ++row) {
//        QVector<QVariant> data(columns);
//        ModelItem *item = new ModelItem(data, this);
        ModelItem *item = new ModelItem(QString("BLA"), this);
        childItems.insert(position, item);
    }

    return true;
}

bool ModelItem::removeChildren(int position, int count)
{
    if (position < 0 || position + count > childItems.size())
        return false;

    for (int row = 0; row < count; ++row)
        delete childItems.takeAt(position);

    return true;
}

/////////////////////////////////////////////////////////

int ModelItem::column() const {
     return 0;
}

int ModelItem::columnCount() const {
     return 1;
//    if (parentItem == 0)
//        return 0;
//    else
//        return 1;
}

bool ModelItem::removeColumns(int /*position*/, int /*columns*/) {
//    if (position < 0 || position + columns > itemData.size())
//        return false;

//    for (int column = 0; column < columns; ++column)
//        itemData.remove(position);

//    foreach (TreeItem *child, childItems)
//        child->removeColumns(position, columns);

    return true;
}

bool ModelItem::insertColumns(int /*position*/, int /*columns*/) {
//    if (position < 0 || position > itemData.size())
//        return false;

//    for (int column = 0; column < columns; ++column)
//        itemData.insert(position, QVariant());

//    foreach (TreeItem *child, childItems)
//        child->insertColumns(position, columns);

    return true;
}

/////////////////////////////////////////////////////////

int ModelItem::row() const {
     if (parentItem)
         return parentItem->childItems.indexOf(const_cast<ModelItem*>(this));

     return 0;
}

/////////////////////////////////////////////////////////

QVariant ModelItem::data(int column) const {
    switch(column) {
        case NAMEUID: return name;
        case EXTENSIONUID: return extension;
        case PATHUID: return path;
        default: return QVariant();
    }
}

bool ModelItem::setData(int column, const QVariant &value) {
    if (column < 0 || column >= 2)
//    if (column < 0 || column >= itemData.size())
        return false;

//    itemData[column] = value;

    switch(column) {
        case NAMEUID: name = value.toString();
        case EXTENSIONUID: extension = value.toString();
        case PATHUID: path = value.toString();
    }

//    itemData[column] = value;

    return true;
}

/////////////////////////////////////////////////////////

QString ModelItem::fullpath() const {
    ModelItem * curr = parentItem;
    QString path_buff = "";

    while(curr != 0) {
        path_buff = curr -> path + '/' + path_buff;
        curr = curr -> parentItem;
    }

    return path_buff.mid(1) + name + '.' + extension;
}

//////////////////////////properties///////////////////////////////

ModelItemState * ModelItem::getState() const {
    return state;
}

void ModelItem::setState(int new_state, bool append_to_library) {
    if (state -> setBit(new_state) && append_to_library) {
        if (state -> isListened())
            Library::instance() -> addItem(this, STATE_LISTENED);
        else if (state -> isLiked())
            Library::instance() -> addItem(this, STATE_LIKED);
    }
}

///////////////////////////////////////////////////////

QJsonObject ModelItem::toJSON() {
    // TODO: logic build needed
    QJsonObject root = QJsonObject();

    if (childItems.length() > 0) {
        QJsonArray ar = QJsonArray();
        for(int i=0; i < childItems.length(); i++)
            ar.append(childItems.at(i)->toJSON());

        root["c"] = ar;
    }

    if (state -> isUnprocessed())
        root["p"] = path;
    else {
        root["n"] = name;
        root["s"] = state -> getFuncValue();
        root["e"] = extension;
    }

    return root;
}

//TODO: add list of extensions for extension serialization to extension index in list
<|endoftext|>


<commit_before>#include "envoy/common/exception.h"
#include "envoy/type/matcher/v3/regex.pb.h"

#include "common/common/regex.h"

#include "test/test_common/logging.h"
#include "test/test_common/test_runtime.h"
#include "test/test_common/utility.h"

#include "gtest/gtest.h"

namespace Envoy {
namespace Regex {
namespace {

TEST(Utility, ParseStdRegex) {
  EXPECT_THROW_WITH_REGEX(Utility::parseStdRegex("(+invalid)"), EnvoyException,
                          "Invalid regex '\\(\\+invalid\\)': .+");

  EXPECT_THROW_WITH_REGEX(Utility::parseStdRegexAsCompiledMatcher("(+invalid)"), EnvoyException,
                          "Invalid regex '\\(\\+invalid\\)': .+");

  {
    std::regex regex = Utility::parseStdRegex("x*");
    EXPECT_NE(0, regex.flags() & std::regex::optimize);
  }

  {
    std::regex regex = Utility::parseStdRegex("x*", std::regex::icase);
    EXPECT_NE(0, regex.flags() & std::regex::icase);
    EXPECT_EQ(0, regex.flags() & std::regex::optimize);
  }

  {
    // Regression test to cover high-complexity regular expressions that throw on std::regex_match.
    // Note that not all std::regex_match implementations will throw when matching against the
    // expression below, but at least clang 9.0.0 under linux does.
    auto matcher = Utility::parseStdRegexAsCompiledMatcher(
        "|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||");
    EXPECT_FALSE(matcher->match("0"));
  }
}

TEST(Utility, ParseRegex) {
  {
    envoy::type::matcher::v3::RegexMatcher matcher;
    matcher.mutable_google_re2();
    matcher.set_regex("(+invalid)");
    EXPECT_THROW_WITH_MESSAGE(Utility::parseRegex(matcher), EnvoyException,
                              "no argument for repetition operator: +");
  }

  // Regression test for https://github.com/envoyproxy/envoy/issues/7728
  {
    envoy::type::matcher::v3::RegexMatcher matcher;
    matcher.mutable_google_re2();
    matcher.set_regex("/asdf/.*");
    const auto compiled_matcher = Utility::parseRegex(matcher);
    const std::string long_string = "/asdf/" + std::string(50 * 1024, 'a');
    EXPECT_TRUE(compiled_matcher->match(long_string));
  }

  // Positive case to ensure no max program size is enforced.
  {
    TestScopedRuntime scoped_runtime;
    envoy::type::matcher::v3::RegexMatcher matcher;
    matcher.set_regex("/asdf/.*");
    matcher.mutable_google_re2();
    EXPECT_NO_THROW(Utility::parseRegex(matcher));
  }

  // Verify max program size with the deprecated field codepath plus runtime.
  // The deprecated field codepath precedes any runtime settings.
  {
    TestScopedRuntime scoped_runtime;
    Runtime::LoaderSingleton::getExisting()->mergeValues(
        {{"re2.max_program_size.error_level", "3"}});
    envoy::type::matcher::v3::RegexMatcher matcher;
    matcher.set_regex("/asdf/.*");
    matcher.mutable_google_re2()->mutable_max_program_size()->set_value(1);
#ifndef GTEST_USES_SIMPLE_RE
    EXPECT_THROW_WITH_REGEX(Utility::parseRegex(matcher), EnvoyException,
                            "RE2 program size of [0-9]+ > max program size of 1\\.");
#else
    EXPECT_THROW_WITH_REGEX(Utility::parseRegex(matcher), EnvoyException,
                            "RE2 program size of \\d+ > max program size of 1\\.");
#endif
  }

  // Verify that an exception is thrown for the error level max program size.
  {
    TestScopedRuntime scoped_runtime;
    Runtime::LoaderSingleton::getExisting()->mergeValues(
        {{"re2.max_program_size.error_level", "1"}});
    envoy::type::matcher::v3::RegexMatcher matcher;
    matcher.set_regex("/asdf/.*");
    matcher.mutable_google_re2();
#ifndef GTEST_USES_SIMPLE_RE
    EXPECT_THROW_WITH_REGEX(
        Utility::parseRegex(matcher), EnvoyException,
        "RE2 program size of [0-9]+ > max program size of 1 set for the error level threshold\\.");
#else
    EXPECT_THROW_WITH_REGEX(
        Utility::parseRegex(matcher), EnvoyException,
        "RE2 program size of \\d+ > max program size of 1 set for the error level threshold\\.");
#endif
  }

  // Verify that the error level max program size defaults to 100 if not set by runtime.
  {
    TestScopedRuntime scoped_runtime;
    envoy::type::matcher::v3::RegexMatcher matcher;
    matcher.set_regex(
        "/asdf/.*/asdf/.*/asdf/.*/asdf/.*/asdf/.*/asdf/.*/asdf/.*/asdf/.*/asdf/.*/asdf/.*");
    matcher.mutable_google_re2();
#ifndef GTEST_USES_SIMPLE_RE
    EXPECT_THROW_WITH_REGEX(Utility::parseRegex(matcher), EnvoyException,
                            "RE2 program size of [0-9]+ > max program size of 100 set for the "
                            "error level threshold\\.");
#else
    EXPECT_THROW_WITH_REGEX(
        Utility::parseRegex(matcher), EnvoyException,
        "RE2 program size of \\d+ > max program size of 100 set for the error level threshold\\.");
#endif
  }

  // Verify that a warning is logged for the warn level max program size.
  {
    TestScopedRuntime scoped_runtime;
    Envoy::Stats::Counter& warn_count =
        Runtime::LoaderSingleton::getExisting()->getRootScope().counterFromString(
            "re2.exceeded_warn_level");
    Runtime::LoaderSingleton::getExisting()->mergeValues(
        {{"re2.max_program_size.warn_level", "1"}});
    envoy::type::matcher::v3::RegexMatcher matcher;
    matcher.set_regex("/asdf/.*");
    matcher.mutable_google_re2();
    EXPECT_NO_THROW(Utility::parseRegex(matcher));
    EXPECT_EQ(1, warn_count.value());
    EXPECT_LOG_CONTAINS("warn", "> max program size of 1 set for the warn level threshold",
                        Utility::parseRegex(matcher));
    EXPECT_EQ(2, warn_count.value());
  }

  // Verify that no check is performed if the warn level max program size is not set by runtime.
  {
    TestScopedRuntime scoped_runtime;
    Envoy::Stats::Counter& warn_count =
        Runtime::LoaderSingleton::getExisting()->getRootScope().counterFromString(
            "re2.exceeded_warn_level");
    envoy::type::matcher::v3::RegexMatcher matcher;
    matcher.set_regex("/asdf/.*");
    matcher.mutable_google_re2();
    EXPECT_NO_THROW(Utility::parseRegex(matcher));
    EXPECT_LOG_NOT_CONTAINS("warn", "> max program size", Utility::parseRegex(matcher));
    EXPECT_EQ(0, warn_count.value());
  }
}

} // namespace
} // namespace Regex
} // namespace Envoy
<commit_msg>route: adding tests (#15931)<commit_after>#include "envoy/common/exception.h"
#include "envoy/type/matcher/v3/regex.pb.h"

#include "common/common/regex.h"

#include "test/test_common/logging.h"
#include "test/test_common/test_runtime.h"
#include "test/test_common/utility.h"

#include "gtest/gtest.h"

namespace Envoy {
namespace Regex {
namespace {

TEST(Utility, ParseStdRegex) {
  EXPECT_THROW_WITH_REGEX(Utility::parseStdRegex("(+invalid)"), EnvoyException,
                          "Invalid regex '\\(\\+invalid\\)': .+");

  EXPECT_THROW_WITH_REGEX(Utility::parseStdRegexAsCompiledMatcher("(+invalid)"), EnvoyException,
                          "Invalid regex '\\(\\+invalid\\)': .+");

  {
    std::regex regex = Utility::parseStdRegex("x*");
    EXPECT_NE(0, regex.flags() & std::regex::optimize);
  }

  {
    std::regex regex = Utility::parseStdRegex("x*", std::regex::icase);
    EXPECT_NE(0, regex.flags() & std::regex::icase);
    EXPECT_EQ(0, regex.flags() & std::regex::optimize);
  }

  {
    // Regression test to cover high-complexity regular expressions that throw on std::regex_match.
    // Note that not all std::regex_match implementations will throw when matching against the
    // expression below, but at least clang 9.0.0 under linux does.
    auto matcher = Utility::parseStdRegexAsCompiledMatcher(
        "|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||");
    EXPECT_FALSE(matcher->match("0"));
  }
}

TEST(Utility, ParseRegex) {
  {
    envoy::type::matcher::v3::RegexMatcher matcher;
    matcher.mutable_google_re2();
    matcher.set_regex("(+invalid)");
    EXPECT_THROW_WITH_MESSAGE(Utility::parseRegex(matcher), EnvoyException,
                              "no argument for repetition operator: +");
  }

  // Regression test for https://github.com/envoyproxy/envoy/issues/7728
  {
    envoy::type::matcher::v3::RegexMatcher matcher;
    matcher.mutable_google_re2();
    matcher.set_regex("/asdf/.*");
    const auto compiled_matcher = Utility::parseRegex(matcher);
    const std::string long_string = "/asdf/" + std::string(50 * 1024, 'a');
    EXPECT_TRUE(compiled_matcher->match(long_string));
  }

  // Regression test for https://github.com/envoyproxy/envoy/issues/15826
  {
    envoy::type::matcher::v3::RegexMatcher matcher;
    matcher.mutable_google_re2();
    matcher.set_regex("/status/200(/.*)?$");
    const auto compiled_matcher = Utility::parseRegex(matcher);
    EXPECT_TRUE(compiled_matcher->match("/status/200"));
    EXPECT_TRUE(compiled_matcher->match("/status/200/"));
    EXPECT_TRUE(compiled_matcher->match("/status/200/foo"));
    EXPECT_FALSE(compiled_matcher->match("/status/200foo"));
  }

  // Positive case to ensure no max program size is enforced.
  {
    TestScopedRuntime scoped_runtime;
    envoy::type::matcher::v3::RegexMatcher matcher;
    matcher.set_regex("/asdf/.*");
    matcher.mutable_google_re2();
    EXPECT_NO_THROW(Utility::parseRegex(matcher));
  }

  // Verify max program size with the deprecated field codepath plus runtime.
  // The deprecated field codepath precedes any runtime settings.
  {
    TestScopedRuntime scoped_runtime;
    Runtime::LoaderSingleton::getExisting()->mergeValues(
        {{"re2.max_program_size.error_level", "3"}});
    envoy::type::matcher::v3::RegexMatcher matcher;
    matcher.set_regex("/asdf/.*");
    matcher.mutable_google_re2()->mutable_max_program_size()->set_value(1);
#ifndef GTEST_USES_SIMPLE_RE
    EXPECT_THROW_WITH_REGEX(Utility::parseRegex(matcher), EnvoyException,
                            "RE2 program size of [0-9]+ > max program size of 1\\.");
#else
    EXPECT_THROW_WITH_REGEX(Utility::parseRegex(matcher), EnvoyException,
                            "RE2 program size of \\d+ > max program size of 1\\.");
#endif
  }

  // Verify that an exception is thrown for the error level max program size.
  {
    TestScopedRuntime scoped_runtime;
    Runtime::LoaderSingleton::getExisting()->mergeValues(
        {{"re2.max_program_size.error_level", "1"}});
    envoy::type::matcher::v3::RegexMatcher matcher;
    matcher.set_regex("/asdf/.*");
    matcher.mutable_google_re2();
#ifndef GTEST_USES_SIMPLE_RE
    EXPECT_THROW_WITH_REGEX(
        Utility::parseRegex(matcher), EnvoyException,
        "RE2 program size of [0-9]+ > max program size of 1 set for the error level threshold\\.");
#else
    EXPECT_THROW_WITH_REGEX(
        Utility::parseRegex(matcher), EnvoyException,
        "RE2 program size of \\d+ > max program size of 1 set for the error level threshold\\.");
#endif
  }

  // Verify that the error level max program size defaults to 100 if not set by runtime.
  {
    TestScopedRuntime scoped_runtime;
    envoy::type::matcher::v3::RegexMatcher matcher;
    matcher.set_regex(
        "/asdf/.*/asdf/.*/asdf/.*/asdf/.*/asdf/.*/asdf/.*/asdf/.*/asdf/.*/asdf/.*/asdf/.*");
    matcher.mutable_google_re2();
#ifndef GTEST_USES_SIMPLE_RE
    EXPECT_THROW_WITH_REGEX(Utility::parseRegex(matcher), EnvoyException,
                            "RE2 program size of [0-9]+ > max program size of 100 set for the "
                            "error level threshold\\.");
#else
    EXPECT_THROW_WITH_REGEX(
        Utility::parseRegex(matcher), EnvoyException,
        "RE2 program size of \\d+ > max program size of 100 set for the error level threshold\\.");
#endif
  }

  // Verify that a warning is logged for the warn level max program size.
  {
    TestScopedRuntime scoped_runtime;
    Envoy::Stats::Counter& warn_count =
        Runtime::LoaderSingleton::getExisting()->getRootScope().counterFromString(
            "re2.exceeded_warn_level");
    Runtime::LoaderSingleton::getExisting()->mergeValues(
        {{"re2.max_program_size.warn_level", "1"}});
    envoy::type::matcher::v3::RegexMatcher matcher;
    matcher.set_regex("/asdf/.*");
    matcher.mutable_google_re2();
    EXPECT_NO_THROW(Utility::parseRegex(matcher));
    EXPECT_EQ(1, warn_count.value());
    EXPECT_LOG_CONTAINS("warn", "> max program size of 1 set for the warn level threshold",
                        Utility::parseRegex(matcher));
    EXPECT_EQ(2, warn_count.value());
  }

  // Verify that no check is performed if the warn level max program size is not set by runtime.
  {
    TestScopedRuntime scoped_runtime;
    Envoy::Stats::Counter& warn_count =
        Runtime::LoaderSingleton::getExisting()->getRootScope().counterFromString(
            "re2.exceeded_warn_level");
    envoy::type::matcher::v3::RegexMatcher matcher;
    matcher.set_regex("/asdf/.*");
    matcher.mutable_google_re2();
    EXPECT_NO_THROW(Utility::parseRegex(matcher));
    EXPECT_LOG_NOT_CONTAINS("warn", "> max program size", Utility::parseRegex(matcher));
    EXPECT_EQ(0, warn_count.value());
  }
}

} // namespace
} // namespace Regex
} // namespace Envoy
<|endoftext|>


<commit_before>#include "patterns.h"
#include <iostream>
#include <cstdlib>
#include "tbb/tbb.h"

namespace {
using std::string;
using std::cout;
using std::endl;
using std::to_string;
using tbb::parallel_for;
using tbb::blocked_range;

int add_five(const int num) {
  return num + 5;
}

template <typename T>
void print_array(T* array, const size_t size) {
  string outstr = "{";
  for(int i = 0, end = size; i != end; ++i)
    outstr += to_string(array[i]) + ", ";
  outstr.erase(outstr.size() - 2);
  outstr += "}";
  cout << outstr << endl;
}

template <typename T>
T sum_array(T* array, const size_t len) {
  T sum = 0;
  for(size_t i = 0, end = len; i != end; ++i)
    sum += array[i];
  return sum;
}

/// body for tbb::parallel_scan
/// used by scan()
class Body {
  int result;
  int* const y;
  const int* const z;
public:

  Body(int y_[], const int z_[]) : result(0), z(z_), y(y_) {}
  Body(Body& b) : z(b.z), y(b.y), result(0) {}
  Body(Body& b, tbb::split) : z(b.z), y(b.y), result(0) {}
  void assign(Body& b, tbb::split) {result = b.result;}
  void assign(Body& b) {result = b.result;}
  void reverse_join(Body& a) {result = a.result;}
  int get_result() const {return result;}
  template<typename Tag>
  void operator()(const blocked_range<int>& r, Tag) {
    int temp = result;
    for(int i = r.begin(); i < r.end(); ++i) {
      temp = temp + z[i];
      if(Tag::is_final_scan())
        y[i] = temp;
    }
    result = temp;
  }
};

}

namespace patterns {

void map() {
  cout << "map pattern" << endl;
  cout << "-----------" << endl;
  cout << "mapping add_five() onto each element of ";

  const int size = 10;
  int input[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
  print_array(input, size);

  int output[size];
  parallel_for(0, size, 1, [input, &output](int i) {
      output[i] = add_five(input[i]);
  });
  cout << "output: ";
  print_array(output, size);
  cout << endl;
}

void stencil() {
  cout << "stencil pattern" << endl;
  cout << "---------------" << endl;
  cout << "summing each element with its neighbors, of ";

  const int size = 10;
  int input[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
  print_array(input, size);

  int output[size] = {0};
  output[0] = sum_array(input, 2);
  output[size-1] = sum_array(&input[size-2], 2);
  parallel_for(1, size-1, 1, [input, &output](int i) {
      output[i] = sum_array((int*)&input[i-1], 3);
  });

  cout << "output: ";
  print_array(output, size);
  cout << endl;
}

void reduce() {
  cout << "reduce pattern" << endl;
  cout << "--------------" << endl;
  cout << "multiplying each element of ";

  const int size = 10;
  int input[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  print_array(input, size);

  auto multFunc = [](int x, int y) -> int {
    return x * y;
  };

  auto combineFunc = [](const blocked_range<int*>& r, int init) -> int {
    for(int* i = r.begin(); i != r.end(); ++i)
      init *= *i;
    return init;
  };

  const int product = parallel_reduce(blocked_range<int*>(input, input+size), 1, combineFunc, multFunc);

  cout << "product: " << product << endl;
}

void scan() {
  using namespace tbb; //debug

  cout << "scan pattern (aka parallel prefix)" << endl;
  cout << "----------------------------------" << endl;
  cout << "computing the sum of each previous element in ";

  const int size = 10;
  int input[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  print_array(input, size);

  int output[size] = {0};
  Body body(output, input);
  parallel_scan(blocked_range<int>(0, size), body);

  cout << "output: ";
  print_array(output, size);
  cout << endl;
}

} // namespace patterns
<commit_msg>fixed missing double newline from reduce output<commit_after>#include "patterns.h"
#include <iostream>
#include <cstdlib>
#include "tbb/tbb.h"

namespace {
using std::string;
using std::cout;
using std::endl;
using std::to_string;
using tbb::parallel_for;
using tbb::blocked_range;

int add_five(const int num) {
  return num + 5;
}

template <typename T>
void print_array(T* array, const size_t size) {
  string outstr = "{";
  for(int i = 0, end = size; i != end; ++i)
    outstr += to_string(array[i]) + ", ";
  outstr.erase(outstr.size() - 2);
  outstr += "}";
  cout << outstr << endl;
}

template <typename T>
T sum_array(T* array, const size_t len) {
  T sum = 0;
  for(size_t i = 0, end = len; i != end; ++i)
    sum += array[i];
  return sum;
}

/// body for tbb::parallel_scan
/// used by scan()
class Body {
  int result;
  int* const y;
  const int* const z;
public:

  Body(int y_[], const int z_[]) : result(0), z(z_), y(y_) {}
  Body(Body& b) : z(b.z), y(b.y), result(0) {}
  Body(Body& b, tbb::split) : z(b.z), y(b.y), result(0) {}
  void assign(Body& b, tbb::split) {result = b.result;}
  void assign(Body& b) {result = b.result;}
  void reverse_join(Body& a) {result = a.result;}
  int get_result() const {return result;}
  template<typename Tag>
  void operator()(const blocked_range<int>& r, Tag) {
    int temp = result;
    for(int i = r.begin(); i < r.end(); ++i) {
      temp = temp + z[i];
      if(Tag::is_final_scan())
        y[i] = temp;
    }
    result = temp;
  }
};

}

namespace patterns {

void map() {
  cout << "map pattern" << endl;
  cout << "-----------" << endl;
  cout << "mapping add_five() onto each element of ";

  const int size = 10;
  int input[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
  print_array(input, size);

  int output[size];
  parallel_for(0, size, 1, [input, &output](int i) {
      output[i] = add_five(input[i]);
  });
  cout << "output: ";
  print_array(output, size);
  cout << endl;
}

void stencil() {
  cout << "stencil pattern" << endl;
  cout << "---------------" << endl;
  cout << "summing each element with its neighbors, of ";

  const int size = 10;
  int input[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
  print_array(input, size);

  int output[size] = {0};
  output[0] = sum_array(input, 2);
  output[size-1] = sum_array(&input[size-2], 2);
  parallel_for(1, size-1, 1, [input, &output](int i) {
      output[i] = sum_array((int*)&input[i-1], 3);
  });

  cout << "output: ";
  print_array(output, size);
  cout << endl;
}

void reduce() {
  cout << "reduce pattern" << endl;
  cout << "--------------" << endl;
  cout << "multiplying each element of ";

  const int size = 10;
  int input[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  print_array(input, size);

  auto multFunc = [](int x, int y) -> int {
    return x * y;
  };

  auto combineFunc = [](const blocked_range<int*>& r, int init) -> int {
    for(int* i = r.begin(); i != r.end(); ++i)
      init *= *i;
    return init;
  };

  const int product = parallel_reduce(blocked_range<int*>(input, input+size), 1, combineFunc, multFunc);

  cout << "product: " << product << endl << endl;
}

void scan() {
  using namespace tbb; //debug

  cout << "scan pattern (aka parallel prefix)" << endl;
  cout << "----------------------------------" << endl;
  cout << "computing the sum of each previous element in ";

  const int size = 10;
  int input[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  print_array(input, size);

  int output[size] = {0};
  Body body(output, input);
  parallel_scan(blocked_range<int>(0, size), body);

  cout << "output: ";
  print_array(output, size);
  cout << endl;
}

} // namespace patterns
<|endoftext|>


<commit_before>#include <stdlib.h>
#include <time.h>
#include <cstdlib>
#include <ctime>

#include "MyBot.h"

MyBot::MyBot()
{
	srand(time(NULL));
	std::cout.sync_with_stdio(0);

	getInit(my_tag, present_map);
	sendInitResponse("CppBot" + std::to_string(my_tag));

	// FOR DEBUGGING PURPOSES. Clears the test file
	std::ofstream ofs;
	ofs.open(std::to_string(my_tag) +".log", std::ofstream::out | std::ofstream::trunc);
	ofs.close();
}

void MyBot::run()
{
	while(true)
	{
		moves.clear();
		messagesFromMe.clear();

		hlt::Message exampleMessage;
		exampleMessage.type = hlt::MessageType::ATTACK;
		exampleMessage.senderID = my_tag;
		exampleMessage.recipientID = my_tag != 1 ? 1 : 2;
		exampleMessage.targetID = my_tag;
		messagesFromMe.push_back(exampleMessage);

		getFrame(present_map, messagesToMe);

		for(unsigned short a = 0; a < present_map.map_height; a++)
		{
			for(unsigned short b = 0; b < present_map.map_width; b++)
			{
				if (present_map.getSite({b, a}, STILL).owner == my_tag)
				{
					if (float(rand()) / RAND_MAX > .20)
					{
						moves.insert({ { b, a }, (unsigned char)(rand() % 5) });
					}
					else moves.insert({ { b, a }, (unsigned char)(STILL) });
				}
			}
		}
		sendFrame(moves, messagesFromMe);
	}
}

int main()
{
  srand(time(NULL));

  MyBot r = MyBot();
  r.run();

  return 0;
}
<commit_msg>Wierd merge #2<commit_after>#include <stdlib.h>
#include <time.h>
#include <cstdlib>
#include <ctime>

#include "MyBot.h"

MyBot::MyBot()
{
	srand(time(NULL));
	std::cout.sync_with_stdio(0);

	getInit(my_tag, present_map);
	sendInitResponse("CppBot" + std::to_string(my_tag));

	// FOR DEBUGGING PURPOSES. Clears the test file
	std::ofstream ofs;
	ofs.open(std::to_string(my_tag) +".log", std::ofstream::out | std::ofstream::trunc);
	ofs.close();
}

void MyBot::run()
{
	while(true)
	{
		moves.clear();
		messagesFromMe.clear();
<<<<<<< HEAD

		hlt::Message exampleMessage;
		exampleMessage.type = hlt::MessageType::ATTACK;
		exampleMessage.senderID = my_tag;
		exampleMessage.recipientID = my_tag != 1 ? 1 : 2;
		exampleMessage.targetID = my_tag;
		messagesFromMe.push_back(exampleMessage);

=======

		hlt::Message exampleMessage;
		exampleMessage.type = hlt::MessageType::ATTACK;
		exampleMessage.senderID = my_tag;
		exampleMessage.recipientID = my_tag != 1 ? 1 : 2;
		exampleMessage.targetID = my_tag;
		messagesFromMe.push_back(exampleMessage);

>>>>>>> ab8c458... Fix merges
		getFrame(present_map, messagesToMe);

		for(unsigned short a = 0; a < present_map.map_height; a++)
		{
			for(unsigned short b = 0; b < present_map.map_width; b++)
			{
				if (present_map.getSite({b, a}, STILL).owner == my_tag)
				{
					if (float(rand()) / RAND_MAX > .20)
					{
						moves.insert({ { b, a }, (unsigned char)(rand() % 5) });
					}
					else moves.insert({ { b, a }, (unsigned char)(STILL) });
				}
			}
		}
		sendFrame(moves, messagesFromMe);
	}
}

int main()
{
	srand(time(NULL));

	MyBot r = MyBot();
	r.run();

	return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2013, Matthew Harvey. All rights reserved.

#include "amalgamated_budget.hpp"
#include "account.hpp"
#include "account_impl.hpp"
#include "account_type.hpp"
#include "budget_item_reader.hpp"
#include "draft_journal.hpp"
#include "entry.hpp"
#include "frequency.hpp"
#include "interval_type.hpp"
#include "phatbooks_exceptions.hpp"
#include "repeater.hpp"
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/static_assert.hpp>
#include <jewel/decimal.hpp>
#include <sqloxx/sql_statement.hpp>
#include <algorithm>
#include <cassert>
#include <numeric>
#include <ostream>
#include <utility>
#include <vector>

using boost::scoped_ptr;
using jewel::Decimal;
using sqloxx::SQLStatement;
using std::accumulate;
using std::ostream;
using std::pair;
using std::vector;

namespace gregorian = boost::gregorian;

// For debugging only
#include <jewel/debug_log.hpp>
#include <iostream>
using std::endl;
// End debugging stuff

namespace phatbooks
{

BOOST_STATIC_ASSERT((boost::is_same<Account::Id, AccountImpl::Id>::value));

void
AmalgamatedBudget::setup_tables(PhatbooksDatabaseConnection& dbc)
{
	dbc.execute_sql
	(	"create index budget_item_account_index on budget_items(account_id)"
	);
	// NOTE UserDraftJournalReader has knowledge of this schema. Ensure
	// any changes to the schema are also reflected there, as appropriate.
	dbc.execute_sql
	(	"create table amalgamated_budget_data"
		"("
			"journal_id integer unique not null "
			"references draft_journal_detail, "
			"balancing_account_id integer unique not null "
			"references accounts"
		")"
	);
	DraftJournal instrument(dbc);
	instrument.set_name("AMALGAMATED BUDGET JOURNAL");
	instrument.set_whether_actual(false);
	instrument.set_comment("");
	Repeater repeater(dbc);
	repeater.set_frequency(Frequency(1, interval_type::days));
	repeater.set_next_date(gregorian::day_clock::local_day());
	instrument.push_repeater(repeater);
	instrument.save();

	Account balancing_account(dbc);
	balancing_account.set_account_type(account_type::pure_envelope);
	balancing_account.set_name("BUDGET IMBALANCE");
	balancing_account.set_description("");
	Commodity const balancing_account_commodity = dbc.default_commodity();
	balancing_account.set_commodity(balancing_account_commodity);
	balancing_account.save();

	SQLStatement statement
	(	dbc,
		"insert into amalgamated_budget_data"
		"(journal_id, balancing_account_id) "
		"values(:journal_id, :balancing_account_id)"
	);
	statement.bind(":journal_id", instrument.id());
	statement.bind(":balancing_account_id", balancing_account.id());
	statement.step_final();

	return;
}

AmalgamatedBudget::AmalgamatedBudget
(	PhatbooksDatabaseConnection& p_database_connection
):
	m_is_loaded(false),
	m_database_connection(p_database_connection),
	m_frequency(1, interval_type::days),
	m_map(new Map),
	m_instrument(0),
	m_balancing_account(0)
{
}

AmalgamatedBudget::~AmalgamatedBudget()
{
	delete m_instrument;
	m_instrument = 0;

	delete m_balancing_account;
	m_balancing_account = 0;
}

void
AmalgamatedBudget::load() const
{
	if (m_is_loaded)
	{
		return;
	}
	assert (!m_is_loaded);
	load_balancing_account();
	load_instrument();
	load_map();
	m_is_loaded = true;
	return;
}

Frequency
AmalgamatedBudget::frequency() const
{
	load();
	assert (m_frequency.num_steps() == 1);
	return m_frequency;
}

void
AmalgamatedBudget::set_frequency(Frequency const& p_frequency)
{
	load();
	m_frequency = p_frequency;
	regenerate();
	return;
}

Decimal
AmalgamatedBudget::budget(AccountImpl::Id p_account_id) const
{
	load();
	Map::const_iterator it = m_map->find(p_account_id);
	assert (it != m_map->end());
	return it->second;
}

namespace
{
	Decimal map_entry_accumulation_aux
	(	Decimal const& dec,
		pair<AccountImpl::Id, Decimal> const& rhs
	)
	{
		return dec + rhs.second;
	}

}  // end anonymous namespace

Decimal
AmalgamatedBudget::balance() const
{
	load();
	return accumulate
	(	m_map->begin(),
		m_map->end(),
		Decimal(0, 0),
		map_entry_accumulation_aux
	);
}

void
AmalgamatedBudget::generate_supported_frequencies(vector<Frequency>& vec)
{
	// NOTE This is co-dependent with the function
	// AmalgamatedBudget::supports_frequency. If this
	// changes, that must change too.
	vec.reserve(10);
	vec.push_back(Frequency(1, interval_type::days));
	vec.push_back(Frequency(1, interval_type::weeks));
	vec.push_back(Frequency(2, interval_type::weeks));
	vec.push_back(Frequency(4, interval_type::weeks));
	vec.push_back(Frequency(1, interval_type::months));
	vec.push_back(Frequency(2, interval_type::months));
	vec.push_back(Frequency(3, interval_type::months));
	vec.push_back(Frequency(4, interval_type::months));
	vec.push_back(Frequency(6, interval_type::months));
	vec.push_back(Frequency(12, interval_type::months));
	return;
}

bool
AmalgamatedBudget::supports_frequency(Frequency const& p_frequency)
{
	// NOTE This is co-dependent with the function
	// AmalgamatedBudget::supported_frequencies. If this changes,
	// that must change too.
	switch (p_frequency.step_type())
	{
	case interval_type::days:
		return p_frequency.num_steps() == 1;
	case interval_type::weeks:
		switch (p_frequency.num_steps())
		{
		case 1: case 2:	return true;
		case 3:			return false;
		case 4:			return true;
		default: 		return false;
		}
	case interval_type::months:
		switch (p_frequency.num_steps())
		{
		case 1: case 2: case 3: case 4:				return true;
		case 5:										return false;
		case 6:										return true;
		case 7: case 8: case 9: case 10: case 11:	return false;
		case 12:									return true;
		default:									return false;
		}
	case interval_type::month_ends:
		return false;
	default:
		assert (false);
	}
}

Account
AmalgamatedBudget::balancing_account() const
{
	load();
	assert (m_balancing_account != 0);
	return *m_balancing_account;
}

DraftJournal
AmalgamatedBudget::instrument() const
{
	load();
	return *m_instrument;
}

void
AmalgamatedBudget::regenerate()
{
	// If amalgamated_budget_data has not yet been populated, then
	// proceeding here would cause the program to crash, as
	// we wouldn't be able to load the balancing account id, etc..
	// So if amalgamated_budget_data has not been created yet,
	// we simply return. It is expected this will only happen on
	// initial setup of the database (due to calling of
	// regenerate() by hook in AccountImpl saving method, when
	// balancing account is first saved).
	SQLStatement statement
	(	m_database_connection,
		"select * from amalgamated_budget_data"
	);
	if (statement.step())
	{
		load();
		regenerate_map();
		regenerate_instrument();
		statement.step_final();
	}
	return;
}

void
AmalgamatedBudget::load_map() const
{
	assert (!m_is_loaded);
	assert (m_map->empty());
	generate_map();
	return;
}

void
AmalgamatedBudget::generate_map() const
{
	scoped_ptr<Map> map_elect(new Map);
	assert (map_elect->empty());

	SQLStatement account_selector
	(	m_database_connection,
		"select account_id from accounts"
	);
	while (account_selector.step())
	{
		AccountImpl::Id const account_id =
			account_selector.extract<AccountImpl::Id>(0);
		Account const account(m_database_connection, account_id);
		(*map_elect)[account_id] =
			Decimal(0, account.commodity().precision());
	}
	BudgetItemReader budget_item_reader(m_database_connection);
	BudgetItemReader::const_iterator const beg = budget_item_reader.begin();
	BudgetItemReader::const_iterator const end = budget_item_reader.end();

	// First we calculate budgets amalgamated on the basis of
	// the canonical frequency
	BudgetItemReader::const_iterator it = beg;
	for ( ; it != end; ++it)
	{
		Frequency const raw_frequency = it->frequency();
		if (!AmalgamatedBudget::supports_frequency(raw_frequency))
		{
			throw InvalidFrequencyException
			(	"Frequency not supported by AmalgamatedBudget."
			);
		}
		AccountImpl::Id const account_id = it->account().id();
		jewel::Decimal const raw_amount = it->amount();
		jewel::Decimal const canonical_amount = convert_to_canonical
		(	raw_frequency,
			raw_amount
		);
		Map::iterator tmit = map_elect->find(account_id);
		assert (tmit != map_elect->end());
		tmit->second += canonical_amount;
	}
	// Now convert to desired frequency
	for
	(	Map::iterator mit = map_elect->begin(), mend = map_elect->end();
		mit != mend;
		++mit
	)
	{
		mit->second = round
		(	convert_from_canonical(m_frequency, mit->second),
			Account(m_database_connection, mit->first).commodity().precision()
		);
	}
	using std::swap;
	swap(m_map, map_elect);

	return;
}

void
AmalgamatedBudget::regenerate_map()
{
	load();
	generate_map();
	return;
}

void
AmalgamatedBudget::regenerate_instrument()
{
	load();

	DraftJournal fresh_journal(m_database_connection);
	fresh_journal.mimic(*m_instrument);
	reflect_entries(fresh_journal);
	reflect_repeater(fresh_journal);

	// Deal with imbalance
	Decimal const imbalance = fresh_journal.balance();
	if (imbalance != Decimal(0, 0))
	{
		Account const ba = balancing_account();
		Entry balancing_entry(m_database_connection);
		balancing_entry.set_account(ba);
		balancing_entry.set_comment("");
		balancing_entry.set_whether_reconciled(false);
		balancing_entry.set_amount
		(	-round(imbalance, ba.commodity().precision())
		);
		fresh_journal.push_entry(balancing_entry);
		assert (fresh_journal.is_balanced());
	}
	m_instrument->mimic(fresh_journal);
	m_instrument->save();

	return;
}

void
AmalgamatedBudget::load_balancing_account() const
{
	SQLStatement statement
	(	m_database_connection,
		"select balancing_account_id from amalgamated_budget_data"
	);
	bool check = statement.step();
	assert (check);
	if (m_balancing_account)
	{
		delete m_balancing_account;
		m_balancing_account = 0;
	}
	m_balancing_account = new Account
	(	m_database_connection,
		statement.extract<Account::Id>(0)
	);
	statement.step_final();
	return;
}

void
AmalgamatedBudget::load_instrument() const
{
	// Set the instrument (the DraftJournal that carries out
	// the AmalgamatedBudget)
	SQLStatement statement
	(	m_database_connection,
		"select journal_id from amalgamated_budget_data"
	);
	statement.step();
	if (m_instrument)
	{
		delete m_instrument;
		m_instrument = 0;
	}
	m_instrument = new DraftJournal
	(	m_database_connection,
		statement.extract<DraftJournal::Id>(0)
	);
	statement.step_final();
	return;
}

void
AmalgamatedBudget::reflect_entries(DraftJournal& p_journal)
{
	load();
	p_journal.clear_entries();
	Map const& map = *m_map;
	for
	(	Map::const_iterator it = map.begin(), end = map.end();
		it != end;
		++it
	)
	{
		if (it->second != Decimal(0, 0))
		{
			Entry entry(m_database_connection);
			entry.set_account
			(	Account(m_database_connection, it->first)
			);
			entry.set_comment("");
			entry.set_amount(-(it->second));
			entry.set_whether_reconciled(false);
			p_journal.push_entry(entry);
		}
	}
	return;
}

void
AmalgamatedBudget::reflect_repeater(DraftJournal& p_journal)
{
	load();
	vector<Repeater> const& old_repeaters = p_journal.repeaters();
	if (old_repeaters.size() == 1)
	{
		Frequency const old_frequency = old_repeaters[0].frequency();
		if
		(	old_frequency.step_type() == m_frequency.step_type() &&
			old_frequency.num_steps() == m_frequency.num_steps()
		)
		{
			return;
		}
	}
	p_journal.clear_repeaters();
	Repeater new_repeater(m_database_connection);
	new_repeater.set_frequency(m_frequency);
	new_repeater.set_next_date(gregorian::day_clock::local_day());
	assert (p_journal.repeaters().empty());
	p_journal.push_repeater(new_repeater);
	return;
}

}  // namespace phatbooks

<commit_msg>Changed name of "system generated" Account, "BUDGET IMBALANCE", to "Budget imbalance" - easier on the eyes.<commit_after>// Copyright (c) 2013, Matthew Harvey. All rights reserved.

#include "amalgamated_budget.hpp"
#include "account.hpp"
#include "account_impl.hpp"
#include "account_type.hpp"
#include "budget_item_reader.hpp"
#include "draft_journal.hpp"
#include "entry.hpp"
#include "frequency.hpp"
#include "interval_type.hpp"
#include "phatbooks_exceptions.hpp"
#include "repeater.hpp"
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/static_assert.hpp>
#include <jewel/decimal.hpp>
#include <sqloxx/sql_statement.hpp>
#include <algorithm>
#include <cassert>
#include <numeric>
#include <ostream>
#include <utility>
#include <vector>

using boost::scoped_ptr;
using jewel::Decimal;
using sqloxx::SQLStatement;
using std::accumulate;
using std::ostream;
using std::pair;
using std::vector;

namespace gregorian = boost::gregorian;

// For debugging only
#include <jewel/debug_log.hpp>
#include <iostream>
using std::endl;
// End debugging stuff

namespace phatbooks
{

BOOST_STATIC_ASSERT((boost::is_same<Account::Id, AccountImpl::Id>::value));

void
AmalgamatedBudget::setup_tables(PhatbooksDatabaseConnection& dbc)
{
	dbc.execute_sql
	(	"create index budget_item_account_index on budget_items(account_id)"
	);
	// NOTE UserDraftJournalReader has knowledge of this schema. Ensure
	// any changes to the schema are also reflected there, as appropriate.
	dbc.execute_sql
	(	"create table amalgamated_budget_data"
		"("
			"journal_id integer unique not null "
			"references draft_journal_detail, "
			"balancing_account_id integer unique not null "
			"references accounts"
		")"
	);
	DraftJournal instrument(dbc);
	instrument.set_name("AMALGAMATED BUDGET JOURNAL");
	instrument.set_whether_actual(false);
	instrument.set_comment("");
	Repeater repeater(dbc);
	repeater.set_frequency(Frequency(1, interval_type::days));
	repeater.set_next_date(gregorian::day_clock::local_day());
	instrument.push_repeater(repeater);
	instrument.save();

	Account balancing_account(dbc);
	balancing_account.set_account_type(account_type::pure_envelope);
	balancing_account.set_name("Budget imbalance");
	balancing_account.set_description("");
	Commodity const balancing_account_commodity = dbc.default_commodity();
	balancing_account.set_commodity(balancing_account_commodity);
	balancing_account.save();

	SQLStatement statement
	(	dbc,
		"insert into amalgamated_budget_data"
		"(journal_id, balancing_account_id) "
		"values(:journal_id, :balancing_account_id)"
	);
	statement.bind(":journal_id", instrument.id());
	statement.bind(":balancing_account_id", balancing_account.id());
	statement.step_final();

	return;
}

AmalgamatedBudget::AmalgamatedBudget
(	PhatbooksDatabaseConnection& p_database_connection
):
	m_is_loaded(false),
	m_database_connection(p_database_connection),
	m_frequency(1, interval_type::days),
	m_map(new Map),
	m_instrument(0),
	m_balancing_account(0)
{
}

AmalgamatedBudget::~AmalgamatedBudget()
{
	delete m_instrument;
	m_instrument = 0;

	delete m_balancing_account;
	m_balancing_account = 0;
}

void
AmalgamatedBudget::load() const
{
	if (m_is_loaded)
	{
		return;
	}
	assert (!m_is_loaded);
	load_balancing_account();
	load_instrument();
	load_map();
	m_is_loaded = true;
	return;
}

Frequency
AmalgamatedBudget::frequency() const
{
	load();
	assert (m_frequency.num_steps() == 1);
	return m_frequency;
}

void
AmalgamatedBudget::set_frequency(Frequency const& p_frequency)
{
	load();
	m_frequency = p_frequency;
	regenerate();
	return;
}

Decimal
AmalgamatedBudget::budget(AccountImpl::Id p_account_id) const
{
	load();
	Map::const_iterator it = m_map->find(p_account_id);
	assert (it != m_map->end());
	return it->second;
}

namespace
{
	Decimal map_entry_accumulation_aux
	(	Decimal const& dec,
		pair<AccountImpl::Id, Decimal> const& rhs
	)
	{
		return dec + rhs.second;
	}

}  // end anonymous namespace

Decimal
AmalgamatedBudget::balance() const
{
	load();
	return accumulate
	(	m_map->begin(),
		m_map->end(),
		Decimal(0, 0),
		map_entry_accumulation_aux
	);
}

void
AmalgamatedBudget::generate_supported_frequencies(vector<Frequency>& vec)
{
	// NOTE This is co-dependent with the function
	// AmalgamatedBudget::supports_frequency. If this
	// changes, that must change too.
	vec.reserve(10);
	vec.push_back(Frequency(1, interval_type::days));
	vec.push_back(Frequency(1, interval_type::weeks));
	vec.push_back(Frequency(2, interval_type::weeks));
	vec.push_back(Frequency(4, interval_type::weeks));
	vec.push_back(Frequency(1, interval_type::months));
	vec.push_back(Frequency(2, interval_type::months));
	vec.push_back(Frequency(3, interval_type::months));
	vec.push_back(Frequency(4, interval_type::months));
	vec.push_back(Frequency(6, interval_type::months));
	vec.push_back(Frequency(12, interval_type::months));
	return;
}

bool
AmalgamatedBudget::supports_frequency(Frequency const& p_frequency)
{
	// NOTE This is co-dependent with the function
	// AmalgamatedBudget::supported_frequencies. If this changes,
	// that must change too.
	switch (p_frequency.step_type())
	{
	case interval_type::days:
		return p_frequency.num_steps() == 1;
	case interval_type::weeks:
		switch (p_frequency.num_steps())
		{
		case 1: case 2:	return true;
		case 3:			return false;
		case 4:			return true;
		default: 		return false;
		}
	case interval_type::months:
		switch (p_frequency.num_steps())
		{
		case 1: case 2: case 3: case 4:				return true;
		case 5:										return false;
		case 6:										return true;
		case 7: case 8: case 9: case 10: case 11:	return false;
		case 12:									return true;
		default:									return false;
		}
	case interval_type::month_ends:
		return false;
	default:
		assert (false);
	}
}

Account
AmalgamatedBudget::balancing_account() const
{
	load();
	assert (m_balancing_account != 0);
	return *m_balancing_account;
}

DraftJournal
AmalgamatedBudget::instrument() const
{
	load();
	return *m_instrument;
}

void
AmalgamatedBudget::regenerate()
{
	// If amalgamated_budget_data has not yet been populated, then
	// proceeding here would cause the program to crash, as
	// we wouldn't be able to load the balancing account id, etc..
	// So if amalgamated_budget_data has not been created yet,
	// we simply return. It is expected this will only happen on
	// initial setup of the database (due to calling of
	// regenerate() by hook in AccountImpl saving method, when
	// balancing account is first saved).
	SQLStatement statement
	(	m_database_connection,
		"select * from amalgamated_budget_data"
	);
	if (statement.step())
	{
		load();
		regenerate_map();
		regenerate_instrument();
		statement.step_final();
	}
	return;
}

void
AmalgamatedBudget::load_map() const
{
	assert (!m_is_loaded);
	assert (m_map->empty());
	generate_map();
	return;
}

void
AmalgamatedBudget::generate_map() const
{
	scoped_ptr<Map> map_elect(new Map);
	assert (map_elect->empty());

	SQLStatement account_selector
	(	m_database_connection,
		"select account_id from accounts"
	);
	while (account_selector.step())
	{
		AccountImpl::Id const account_id =
			account_selector.extract<AccountImpl::Id>(0);
		Account const account(m_database_connection, account_id);
		(*map_elect)[account_id] =
			Decimal(0, account.commodity().precision());
	}
	BudgetItemReader budget_item_reader(m_database_connection);
	BudgetItemReader::const_iterator const beg = budget_item_reader.begin();
	BudgetItemReader::const_iterator const end = budget_item_reader.end();

	// First we calculate budgets amalgamated on the basis of
	// the canonical frequency
	BudgetItemReader::const_iterator it = beg;
	for ( ; it != end; ++it)
	{
		Frequency const raw_frequency = it->frequency();
		if (!AmalgamatedBudget::supports_frequency(raw_frequency))
		{
			throw InvalidFrequencyException
			(	"Frequency not supported by AmalgamatedBudget."
			);
		}
		AccountImpl::Id const account_id = it->account().id();
		jewel::Decimal const raw_amount = it->amount();
		jewel::Decimal const canonical_amount = convert_to_canonical
		(	raw_frequency,
			raw_amount
		);
		Map::iterator tmit = map_elect->find(account_id);
		assert (tmit != map_elect->end());
		tmit->second += canonical_amount;
	}
	// Now convert to desired frequency
	for
	(	Map::iterator mit = map_elect->begin(), mend = map_elect->end();
		mit != mend;
		++mit
	)
	{
		mit->second = round
		(	convert_from_canonical(m_frequency, mit->second),
			Account(m_database_connection, mit->first).commodity().precision()
		);
	}
	using std::swap;
	swap(m_map, map_elect);

	return;
}

void
AmalgamatedBudget::regenerate_map()
{
	load();
	generate_map();
	return;
}

void
AmalgamatedBudget::regenerate_instrument()
{
	load();

	DraftJournal fresh_journal(m_database_connection);
	fresh_journal.mimic(*m_instrument);
	reflect_entries(fresh_journal);
	reflect_repeater(fresh_journal);

	// Deal with imbalance
	Decimal const imbalance = fresh_journal.balance();
	if (imbalance != Decimal(0, 0))
	{
		Account const ba = balancing_account();
		Entry balancing_entry(m_database_connection);
		balancing_entry.set_account(ba);
		balancing_entry.set_comment("");
		balancing_entry.set_whether_reconciled(false);
		balancing_entry.set_amount
		(	-round(imbalance, ba.commodity().precision())
		);
		fresh_journal.push_entry(balancing_entry);
		assert (fresh_journal.is_balanced());
	}
	m_instrument->mimic(fresh_journal);
	m_instrument->save();

	return;
}

void
AmalgamatedBudget::load_balancing_account() const
{
	SQLStatement statement
	(	m_database_connection,
		"select balancing_account_id from amalgamated_budget_data"
	);
	bool check = statement.step();
	assert (check);
	if (m_balancing_account)
	{
		delete m_balancing_account;
		m_balancing_account = 0;
	}
	m_balancing_account = new Account
	(	m_database_connection,
		statement.extract<Account::Id>(0)
	);
	statement.step_final();
	return;
}

void
AmalgamatedBudget::load_instrument() const
{
	// Set the instrument (the DraftJournal that carries out
	// the AmalgamatedBudget)
	SQLStatement statement
	(	m_database_connection,
		"select journal_id from amalgamated_budget_data"
	);
	statement.step();
	if (m_instrument)
	{
		delete m_instrument;
		m_instrument = 0;
	}
	m_instrument = new DraftJournal
	(	m_database_connection,
		statement.extract<DraftJournal::Id>(0)
	);
	statement.step_final();
	return;
}

void
AmalgamatedBudget::reflect_entries(DraftJournal& p_journal)
{
	load();
	p_journal.clear_entries();
	Map const& map = *m_map;
	for
	(	Map::const_iterator it = map.begin(), end = map.end();
		it != end;
		++it
	)
	{
		if (it->second != Decimal(0, 0))
		{
			Entry entry(m_database_connection);
			entry.set_account
			(	Account(m_database_connection, it->first)
			);
			entry.set_comment("");
			entry.set_amount(-(it->second));
			entry.set_whether_reconciled(false);
			p_journal.push_entry(entry);
		}
	}
	return;
}

void
AmalgamatedBudget::reflect_repeater(DraftJournal& p_journal)
{
	load();
	vector<Repeater> const& old_repeaters = p_journal.repeaters();
	if (old_repeaters.size() == 1)
	{
		Frequency const old_frequency = old_repeaters[0].frequency();
		if
		(	old_frequency.step_type() == m_frequency.step_type() &&
			old_frequency.num_steps() == m_frequency.num_steps()
		)
		{
			return;
		}
	}
	p_journal.clear_repeaters();
	Repeater new_repeater(m_database_connection);
	new_repeater.set_frequency(m_frequency);
	new_repeater.set_next_date(gregorian::day_clock::local_day());
	assert (p_journal.repeaters().empty());
	p_journal.push_repeater(new_repeater);
	return;
}

}  // namespace phatbooks

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016, 2018 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * 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 copyright holders 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.
 */

#ifndef __SIM_POWER_POWER_MODEL_HH__
#define __SIM_POWER_POWER_MODEL_HH__

#include "base/statistics.hh"
#include "enums/PMType.hh"
#include "params/PowerModel.hh"
#include "params/PowerModelState.hh"
#include "sim/probe/probe.hh"

class SimObject;
class ClockedObject;

/**
 * A PowerModelState is an abstract class used as interface to get power
 * figures out of SimObjects
 */
class PowerModelState : public SimObject
{
  public:

    typedef PowerModelStateParams Params;
    PowerModelState(const Params *p);

    /**
     * Get the dynamic power consumption.
     *
     * @return Power (Watts) consumed by this object (dynamic component)
     */
    virtual double getDynamicPower() const = 0;

    /**
     * Get the static power consumption.
     *
     * @return Power (Watts) consumed by this object (static component)
     */
    virtual double getStaticPower() const = 0;

    /**
     * Temperature update.
     *
     * @param temp Current temperature of the HW part (Celsius)
     */
    virtual void setTemperature(double temp) { _temp = temp; }

    void setClockedObject(ClockedObject * clkobj) {
        clocked_object = clkobj;
    }

    void regStats() {
        dynamicPower
          .method(this, &PowerModelState::getDynamicPower)
          .name(params()->name + ".dynamic_power")
          .desc("Dynamic power for this object (Watts)")
        ;

        staticPower
          .method(this, &PowerModelState::getStaticPower)
          .name(params()->name + ".static_power")
          .desc("Static power for this object (Watts)")
        ;
    }

  protected:
    Stats::Value dynamicPower, staticPower;

    /** Current temperature */
    double _temp;

    /** The clocked object we belong to */
    ClockedObject * clocked_object;
};

/**
 * @sa \ref gem5PowerModel "gem5 Power Model"
 *
 * A PowerModel is a class containing a power model for a SimObject.
 * The PM describes the power consumption for every power state.
 */
class PowerModel : public SimObject
{
  public:

    typedef PowerModelParams Params;
    PowerModel(const Params *p);

    /**
     * Get the dynamic power consumption.
     *
     * @return Power (Watts) consumed by this object (dynamic component)
     */
    double getDynamicPower() const;

    /**
     * Get the static power consumption.
     *
     * @return Power (Watts) consumed by this object (static component)
     */
    double getStaticPower() const;

    void regStats() {
        dynamicPower
          .method(this, &PowerModel::getDynamicPower)
          .name(params()->name + ".dynamic_power")
          .desc("Dynamic power for this power state")
        ;

        staticPower
          .method(this, &PowerModel::getStaticPower)
          .name(params()->name + ".static_power")
          .desc("Static power for this power state")
        ;
    }

    void setClockedObject(ClockedObject *clkobj);

    virtual void regProbePoints();

    void thermalUpdateCallback(const double & temp);

  protected:
    /** Listener class to catch thermal events */
    class ThermalProbeListener : public ProbeListenerArgBase<double>
    {
      public:
        ThermalProbeListener(PowerModel &_pm, ProbeManager *pm,
                      const std::string &name)
            : ProbeListenerArgBase(pm, name), pm(_pm) {}

        void notify(const double &temp)
        {
            pm.thermalUpdateCallback(temp);
        }

      protected:
        PowerModel ±
    };

    Stats::Value dynamicPower, staticPower;

    /** Actual power models (one per power state) */
    std::vector<PowerModelState*> states_pm;

    /** Listener to catch temperature changes in the SubSystem */
    std::unique_ptr<ThermalProbeListener> thermalListener;

    /** The subsystem this power model belongs to */
    SubSystem * subsystem;

    /** The clocked object we belong to */
    ClockedObject * clocked_object;

    /** The type of power model - collects all power, static or dynamic only */
    Enums::PMType power_model_type;
};

#endif
<commit_msg>power: Fix regStats for PowerModel and PowerModelState<commit_after>/*
 * Copyright (c) 2016, 2018 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * 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 copyright holders 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.
 */

#ifndef __SIM_POWER_POWER_MODEL_HH__
#define __SIM_POWER_POWER_MODEL_HH__

#include "base/statistics.hh"
#include "enums/PMType.hh"
#include "params/PowerModel.hh"
#include "params/PowerModelState.hh"
#include "sim/probe/probe.hh"

class SimObject;
class ClockedObject;

/**
 * A PowerModelState is an abstract class used as interface to get power
 * figures out of SimObjects
 */
class PowerModelState : public SimObject
{
  public:

    typedef PowerModelStateParams Params;
    PowerModelState(const Params *p);

    /**
     * Get the dynamic power consumption.
     *
     * @return Power (Watts) consumed by this object (dynamic component)
     */
    virtual double getDynamicPower() const = 0;

    /**
     * Get the static power consumption.
     *
     * @return Power (Watts) consumed by this object (static component)
     */
    virtual double getStaticPower() const = 0;

    /**
     * Temperature update.
     *
     * @param temp Current temperature of the HW part (Celsius)
     */
    virtual void setTemperature(double temp) { _temp = temp; }

    void setClockedObject(ClockedObject * clkobj) {
        clocked_object = clkobj;
    }

    void regStats() {
        SimObject::regStats();

        dynamicPower
          .method(this, &PowerModelState::getDynamicPower)
          .name(params()->name + ".dynamic_power")
          .desc("Dynamic power for this object (Watts)")
        ;

        staticPower
          .method(this, &PowerModelState::getStaticPower)
          .name(params()->name + ".static_power")
          .desc("Static power for this object (Watts)")
        ;
    }

  protected:
    Stats::Value dynamicPower, staticPower;

    /** Current temperature */
    double _temp;

    /** The clocked object we belong to */
    ClockedObject * clocked_object;
};

/**
 * @sa \ref gem5PowerModel "gem5 Power Model"
 *
 * A PowerModel is a class containing a power model for a SimObject.
 * The PM describes the power consumption for every power state.
 */
class PowerModel : public SimObject
{
  public:

    typedef PowerModelParams Params;
    PowerModel(const Params *p);

    /**
     * Get the dynamic power consumption.
     *
     * @return Power (Watts) consumed by this object (dynamic component)
     */
    double getDynamicPower() const;

    /**
     * Get the static power consumption.
     *
     * @return Power (Watts) consumed by this object (static component)
     */
    double getStaticPower() const;

    void regStats() {
        SimObject::regStats();

        dynamicPower
          .method(this, &PowerModel::getDynamicPower)
          .name(params()->name + ".dynamic_power")
          .desc("Dynamic power for this power state")
        ;

        staticPower
          .method(this, &PowerModel::getStaticPower)
          .name(params()->name + ".static_power")
          .desc("Static power for this power state")
        ;
    }

    void setClockedObject(ClockedObject *clkobj);

    virtual void regProbePoints();

    void thermalUpdateCallback(const double & temp);

  protected:
    /** Listener class to catch thermal events */
    class ThermalProbeListener : public ProbeListenerArgBase<double>
    {
      public:
        ThermalProbeListener(PowerModel &_pm, ProbeManager *pm,
                      const std::string &name)
            : ProbeListenerArgBase(pm, name), pm(_pm) {}

        void notify(const double &temp)
        {
            pm.thermalUpdateCallback(temp);
        }

      protected:
        PowerModel ±
    };

    Stats::Value dynamicPower, staticPower;

    /** Actual power models (one per power state) */
    std::vector<PowerModelState*> states_pm;

    /** Listener to catch temperature changes in the SubSystem */
    std::unique_ptr<ThermalProbeListener> thermalListener;

    /** The subsystem this power model belongs to */
    SubSystem * subsystem;

    /** The clocked object we belong to */
    ClockedObject * clocked_object;

    /** The type of power model - collects all power, static or dynamic only */
    Enums::PMType power_model_type;
};

#endif
<|endoftext|>