<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008 Aristid Breitkreuz, Ruediger Sonderfeld

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "flusspferd/blob.hpp"
#include "flusspferd/local_root_scope.hpp"
#include "flusspferd/exception.hpp"
#include "flusspferd/string.hpp"
#include <limits>
#include <cstring>

using namespace flusspferd;

blob::blob(object const &obj, unsigned char const *data, std::size_t length)
  : native_object_base(obj), data(data, data+length)
{
  init();
}

blob::blob(object const &obj, call_context &x)
  : native_object_base(obj)
{
  init();

  local_root_scope scope;
  if (x.arg[0].is_int()) {
    std::size_t length = x.arg[0].get_int();
    data.resize(length);
    return;
  } else if (x.arg[0].is_object()) {
    object data = x.arg[0].get_object();
    if (data.is_array()) {
      array arr = data;
      std::size_t length = arr.get_length();
      this->data.reserve(length);
      for (std::size_t i = 0; i < length; ++i)
        this->data.push_back(el_from_value(arr.get_element(i)));
      return;
    }
  }
  throw exception("Could not create Blob");
}

unsigned char blob::el_from_value(value const &v) {
  if (!v.is_int())
    throw exception("Value cannot be a Blob element");
  int x = v.get_int();
  if (x < 0 || x > std::numeric_limits<unsigned char>::max())
    // TODO: Make this a RangeError once we have error type
    throw exception("Value cannot be a Blob element");
  return (unsigned char) x;
}

void blob::class_info::augment_constructor(object &ctor) {
  create_native_function(ctor, "fromUtf8", &blob::from_utf8);
}

void blob::init() {
  unsigned const RW = permanent_shared_property;

  define_native_property("length", RW, &blob::prop_length);

  register_native_method("append", &blob::append);
  register_native_method("toArray", &blob::to_array);
  register_native_method("copy", &blob::copy);
  register_native_method("slice", &blob::slice);
  register_native_method("asUtf8", &blob::as_utf8);
}

blob::~blob() {}

object blob::class_info::create_prototype() {
  object proto = create_object();

  create_native_method(proto, "append", 1);
  create_native_method(proto, "toArray", 0);
  create_native_method(proto, "copy", 0);
  create_native_method(proto, "slice", 2);
  create_native_method(proto, "asUtf8", 0);

  return proto;
}

void blob::prop_length(property_mode mode, value &data) {
  switch (mode) {
  case property_set:
  {
    int new_len = data.get_int();
    if (new_len < 0)
      new_len = 0;
    this->data.resize(new_len);
    data = new_len;
    break;
  }
  case property_get:
    data = (int)this->data.size();
    break;
  default: break;
  }
}

// TODO: Could really do with an enumerate to go with this
bool blob::property_resolve(value const &id, unsigned ) {
  if (!id.is_number())
    return false;

  // Dont support anything larger than 2**30 in a blob. 1gig limit seems sane
  int uid = id.to_integral_number(30, false);

  if ((size_t)uid > data.size())
    return false;

  value v = int(data[uid]);
  define_property(string(uid), v, permanent_shared_property);
  return true;
}

void blob::property_op(property_mode mode, value const &id, value &x) {
  if (id.is_int()) {
    int index = id.get_int();
    if (index < 0 || std::size_t(index) >= data.size())
      throw exception("Out of bounds of Blob");
    switch (mode) {
    case property_get:
      x = int(data[index]);
      break;
    case property_set:
      data[index] = el_from_value(x);
      break;
    default: break;
    };
    return;
  }
  this->native_object_base::property_op(mode, id, x);
}

void blob::append(blob const &o) {
  data.reserve(data.size() + o.data.size());
  data.insert(data.end(), o.data.begin(), o.data.end());
}

object blob::to_array() {
  array arr = create_array(data.size());
  for (std::size_t i = 0; i < data.size(); ++i)
    arr.set_element(i, int(data[i]));
  return arr;
}

object blob::slice(int from, boost::optional<int> to_) {
  int n = data.size();

  if (from < 0)
    from = n + from;

  int to = to_.get_value_or(n);
  if (to < 0)
    to = n + to;

  if (from > n)
    from = n;
  if (to > n)
    to = n;

  if (to < from)
    to = from;

  return create_native_object<blob>(get_prototype(), &data[from], to-from);
}

object blob::copy() {
  return create_native_object<blob>(get_prototype(), &data[0], data.size());
}

string blob::as_utf8() {
  std::size_t strlen = 0;
  for (; strlen < data.size(); ++strlen)
    if (!data[strlen])
      break;
  return string((char*) get_data(), strlen);
}

object blob::from_utf8(string const &text) {
  char const *str = text.c_str();
  return create_native_object<blob>(
    object(), (unsigned char const *) str, std::strlen(str));
}
<commit_msg>Core: check Blob.length is set to an integer<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008 Aristid Breitkreuz, Ruediger Sonderfeld

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "flusspferd/blob.hpp"
#include "flusspferd/local_root_scope.hpp"
#include "flusspferd/exception.hpp"
#include "flusspferd/string.hpp"
#include <limits>
#include <cstring>

using namespace flusspferd;

blob::blob(object const &obj, unsigned char const *data, std::size_t length)
  : native_object_base(obj), data(data, data+length)
{
  init();
}

blob::blob(object const &obj, call_context &x)
  : native_object_base(obj)
{
  init();

  local_root_scope scope;
  if (x.arg[0].is_int()) {
    std::size_t length = x.arg[0].get_int();
    data.resize(length);
    return;
  } else if (x.arg[0].is_object()) {
    object data = x.arg[0].get_object();
    if (data.is_array()) {
      array arr = data;
      std::size_t length = arr.get_length();
      this->data.reserve(length);
      for (std::size_t i = 0; i < length; ++i)
        this->data.push_back(el_from_value(arr.get_element(i)));
      return;
    }
  }
  throw exception("Could not create Blob");
}

unsigned char blob::el_from_value(value const &v) {
  if (!v.is_int())
    throw exception("Value cannot be a Blob element");
  int x = v.get_int();
  if (x < 0 || x > std::numeric_limits<unsigned char>::max())
    // TODO: Make this a RangeError once we have error type
    throw exception("Value cannot be a Blob element");
  return (unsigned char) x;
}

void blob::class_info::augment_constructor(object &ctor) {
  create_native_function(ctor, "fromUtf8", &blob::from_utf8);
}

void blob::init() {
  unsigned const RW = permanent_shared_property;

  define_native_property("length", RW, &blob::prop_length);

  register_native_method("append", &blob::append);
  register_native_method("toArray", &blob::to_array);
  register_native_method("copy", &blob::copy);
  register_native_method("slice", &blob::slice);
  register_native_method("asUtf8", &blob::as_utf8);
}

blob::~blob() {}

object blob::class_info::create_prototype() {
  object proto = create_object();

  create_native_method(proto, "append", 1);
  create_native_method(proto, "toArray", 0);
  create_native_method(proto, "copy", 0);
  create_native_method(proto, "slice", 2);
  create_native_method(proto, "asUtf8", 0);

  return proto;
}

void blob::prop_length(property_mode mode, value &data) {
  switch (mode) {
  case property_set:
  {
    if (!data.is_int())
      // TODO: make this a RangeError
      throw exception("Blob.length out of range");
    int new_len = data.get_int();
    if (new_len < 0)
      new_len = 0;
    this->data.resize(new_len);
    data = new_len;
    break;
  }
  case property_get:
    data = (int)this->data.size();
    break;
  default: break;
  }
}

// TODO: Could really do with an enumerate to go with this
bool blob::property_resolve(value const &id, unsigned ) {
  if (!id.is_number())
    return false;

  // Dont support anything larger than 2**30 in a blob. 1gig limit seems sane
  int uid = id.to_integral_number(30, false);

  if ((size_t)uid > data.size())
    return false;

  value v = int(data[uid]);
  define_property(string(uid), v, permanent_shared_property);
  return true;
}

void blob::property_op(property_mode mode, value const &id, value &x) {
  if (id.is_int()) {
    int index = id.get_int();
    if (index < 0 || std::size_t(index) >= data.size())
      throw exception("Out of bounds of Blob");
    switch (mode) {
    case property_get:
      x = int(data[index]);
      break;
    case property_set:
      data[index] = el_from_value(x);
      break;
    default: break;
    };
    return;
  }
  this->native_object_base::property_op(mode, id, x);
}

void blob::append(blob const &o) {
  data.reserve(data.size() + o.data.size());
  data.insert(data.end(), o.data.begin(), o.data.end());
}

object blob::to_array() {
  array arr = create_array(data.size());
  for (std::size_t i = 0; i < data.size(); ++i)
    arr.set_element(i, int(data[i]));
  return arr;
}

object blob::slice(int from, boost::optional<int> to_) {
  int n = data.size();

  if (from < 0)
    from = n + from;

  int to = to_.get_value_or(n);
  if (to < 0)
    to = n + to;

  if (from > n)
    from = n;
  if (to > n)
    to = n;

  if (to < from)
    to = from;

  return create_native_object<blob>(get_prototype(), &data[from], to-from);
}

object blob::copy() {
  return create_native_object<blob>(get_prototype(), &data[0], data.size());
}

string blob::as_utf8() {
  std::size_t strlen = 0;
  for (; strlen < data.size(); ++strlen)
    if (!data[strlen])
      break;
  return string((char*) get_data(), strlen);
}

object blob::from_utf8(string const &text) {
  char const *str = text.c_str();
  return create_native_object<blob>(
    object(), (unsigned char const *) str, std::strlen(str));
}
<|endoftext|>


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

#include <znc/FileUtils.h>
#include <znc/Server.h>
#include <znc/IRCNetwork.h>
#include <znc/User.h>
#include <znc/ZNCDebug.h>

class CAdminDebugMod : public CModule {
  private:
      CString m_sEnabledBy;

  public:
    MODCONSTRUCTOR(CAdminDebugMod) {
        AddHelpCommand();
        AddCommand("Enable", "", t_d("Enable Debug Mode"),
                   [=](const CString& sLine) { CommandEnable(sLine); });
        AddCommand("Disable", "", t_d("Disable Debug Mode"),
                   [=](const CString& sLine) { CommandDisable(sLine); });
        AddCommand("Status", "", t_d("Show the Debug Mode status"),
                   [=](const CString& sLine) { CommandStatus(sLine); });
    }

    void CommandEnable(const CString& sCommand) {
        if (!GetUser()->IsAdmin()) {
            PutModule(t_s("Access denied!"));
            return;
        }

        ToggleDebug(true, GetUser()->GetNick());
    }

    void CommandDisable(const CString& sCommand) {
        if (!GetUser()->IsAdmin()) {
            PutModule(t_s("Access denied!"));
            return;
        }

        ToggleDebug(false, m_sEnabledBy);
    }

    bool ToggleDebug(bool bEnable, const CString& sEnabledBy) {
        if (!CDebug::StdoutIsTTY()) {
            PutModule(t_s("Failure. We need to be running with a TTY. (is ZNC running with --foreground?)"));
            return false;
        }

        bool bValue = CDebug::Debug();

        if (bEnable == bValue) {
            if (bEnable) {
                PutModule(t_s("Already enabled."));
            } else {
                PutModule(t_s("Already disabled."));
            }
            return false;
        }

        CDebug::SetDebug(bEnable);
        CString sEnabled = bEnable ? "on" : "off";
        CZNC::Get().Broadcast(
            "An administrator has just turned Debug Mode \02" + sEnabled +
            "\02. It was enabled by \02" + sEnabledBy + "\02.");
        if (bEnable) {
            CZNC::Get().Broadcast(
                "Messages, credentials, and other sensitive data may become "
                "exposed to the host during this period.");
            m_sEnabledBy = sEnabledBy;
        } else {
            m_sEnabledBy = "";
        }

        return true;
    }

    void CommandStatus(const CString& sCommand) {
        if (CDebug::Debug()) {
            PutModule(t_s("Debugging mode is \02on\02."));
        } else {
             PutModule(t_s("Debugging mode is \02off\02."));
        }
        PutModule(t_s("Logging to: \02stdout\02."));
    }
};

template <>
void TModInfo<CAdminDebugMod>(CModInfo& Info) {
    Info.SetWikiPage("admindebug");
}

GLOBALMODULEDEFS(CAdminDebugMod, t_s("Enable Debug mode dynamically."))
<commit_msg>admindebug: use \n instead of \r\n<commit_after>/*
 * Copyright (C) 2004-2018 ZNC, see the NOTICE file for details.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <znc/FileUtils.h>
#include <znc/Server.h>
#include <znc/IRCNetwork.h>
#include <znc/User.h>
#include <znc/ZNCDebug.h>

class CAdminDebugMod : public CModule {
  private:
      CString m_sEnabledBy;

  public:
    MODCONSTRUCTOR(CAdminDebugMod) {
        AddHelpCommand();
        AddCommand("Enable", "", t_d("Enable Debug Mode"),
                   [=](const CString& sLine) { CommandEnable(sLine); });
        AddCommand("Disable", "", t_d("Disable Debug Mode"),
                   [=](const CString& sLine) { CommandDisable(sLine); });
        AddCommand("Status", "", t_d("Show the Debug Mode status"),
                   [=](const CString& sLine) { CommandStatus(sLine); });
    }

    void CommandEnable(const CString& sCommand) {
        if (!GetUser()->IsAdmin()) {
            PutModule(t_s("Access denied!"));
            return;
        }

        ToggleDebug(true, GetUser()->GetNick());
    }

    void CommandDisable(const CString& sCommand) {
        if (!GetUser()->IsAdmin()) {
            PutModule(t_s("Access denied!"));
            return;
        }

        ToggleDebug(false, m_sEnabledBy);
    }

    bool ToggleDebug(bool bEnable, const CString& sEnabledBy) {
        if (!CDebug::StdoutIsTTY()) {
            PutModule(t_s("Failure. We need to be running with a TTY. (is ZNC running with --foreground?)"));
            return false;
        }

        bool bValue = CDebug::Debug();

        if (bEnable == bValue) {
            if (bEnable) {
                PutModule(t_s("Already enabled."));
            } else {
                PutModule(t_s("Already disabled."));
            }
            return false;
        }

        CDebug::SetDebug(bEnable);
        CString sEnabled = bEnable ? "on" : "off";
        CZNC::Get().Broadcast(
            "An administrator has just turned Debug Mode \02" + sEnabled +
            "\02. It was enabled by \02" + sEnabledBy + "\02.");
        if (bEnable) {
            CZNC::Get().Broadcast(
                "Messages, credentials, and other sensitive data may become "
                "exposed to the host during this period.");
            m_sEnabledBy = sEnabledBy;
        } else {
            m_sEnabledBy = "";
        }

        return true;
    }

    void CommandStatus(const CString& sCommand) {
        if (CDebug::Debug()) {
            PutModule(t_s("Debugging mode is \02on\02."));
        } else {
             PutModule(t_s("Debugging mode is \02off\02."));
        }
        PutModule(t_s("Logging to: \02stdout\02."));
    }
};

template <>
void TModInfo<CAdminDebugMod>(CModInfo& Info) {
    Info.SetWikiPage("admindebug");
}

GLOBALMODULEDEFS(CAdminDebugMod, t_s("Enable Debug mode dynamically."))
<|endoftext|>


<commit_before>/* Rapicorn
 * Copyright (C) 2008 Tim Janik
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * A copy of the GNU Lesser General Public License should ship along
 * with this library; if not, see http://www.gnu.org/copyleft/.
 */
#include "types.hh"

namespace Rapicorn {

#define IS_RAPICORN_TYPE_STORAGE(strg)  (strchr (RAPICORN_TYPE_STORAGE_CHARS, strg))

const char*
Type::type_name (Type::Storage storage)
{
  switch (storage)
    {
    case Type::NUM:             return "NUM";
    case Type::FLOAT:           return "FLOAT";
    case Type::STRING:          return "STRING";
    case Type::ARRAY:           return "ARRAY";
    case Type::STRING_VECTOR:   return "STRING_VECTOR";
    case Type::OBJECT:          return "OBJECT";
    }
  return NULL;
}

static const char*
parse_hexnum (const char *input,
              uint       &pos,
              int64      &result,
              uint        n_digits)
{
  static const char *NFE = "hexnum parse error";
  result = 0;
  while (n_digits--)
    {
      if (!strchr ("ABCDEFabcdef0123456789", input[pos]))
        return NFE;
      result <<= 4;
      result += input[pos] >= 'a' ? input[pos] - 'a' + 10 : input[pos] >= 'A' ? input[pos] - 'A' + 10 : input[pos] > '0' ? input[pos] - '0' : 0;
      pos++;
    }
  return NULL;
}

static const char*
parse_string (const char *input,
              uint       &pos,
              String     &result,
              uint        n_digits)
{
  static const char *SSE = "short string encountered";
  int64 n;
  const char *err = parse_hexnum (input, pos, n, n_digits);
  if (err)
    return err;
  while (n--)
    {
      if (!input[pos])
        return SSE;
      result += input[pos++];
    }
  return NULL;
}

static const char*
parse_assignment (const char *assignment,
                  uint       *offset)
{
  static const char *IKA = "invalid key=value assignment syntax";
  if (!((assignment[0] >= 'A' && assignment[0] <= 'Z') ||
        (assignment[0] >= 'a' && assignment[0] <= 'z') ||
        (assignment[0] >= '0' && assignment[0] <= '9') ||
        assignment[0] == '_'))
    return IKA;
  uint i = 1;
  while (strchr ("abcdefghijklmnopqrstuvwxyz0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ", assignment[i]))
    i++;
  if (assignment[i] != '=')
    return IKA;
  *offset = i + 1;
  return NULL;
}

static const char*
type_parser (char const *input,
             Type::Info &ti)
{
  static const char *ITD = "format error";
  /* format:
   * <StorageChar>US
   */
  uint pos = 0;
  // parse magic indicator
  if (input[pos++] != 'R')
    return ITD;
  if (input[pos++] != 'c')
    return ITD;
  if (input[pos++] != 'T')
    return ITD;
  if (input[pos++] != 'i')
    return ITD;
  if (input[pos++] != ';')
    return ITD;
  // parse type name
  const char *err = parse_string (input, pos, ti.name, 4);
  if (err)
    return err;
  if (input[pos++] != ';')
    return ITD;
  // parse storage type
  ti.storage = Type::Storage (input[pos++]);
  if (!ti.storage || !IS_RAPICORN_TYPE_STORAGE (ti.storage))
    return ITD;
  if (input[pos++] != ';')
    return ITD;
  // parse aux data
  while (input[pos] && input[pos] != ';')
    {
      uint offset = 0;
      String astr;
      err = parse_string (input, pos, astr, 4);
      if (err)
        return err;
      err = parse_assignment (astr.c_str(), &offset);
      if (err)
        return err;
      String name = String (astr, 0, offset - 1);
      String value = String (astr, offset);
      ti.auxdata.push_back (name + "=" + value);
    }
  if (input[pos++] != ';')
    return ITD;
  return NULL;
}

Type::Type (char const *_typedef) :
  m_info()
{
  const char *err = type_parser (_typedef, m_info);
  if (err)
    RAPICORN_ERROR ("invalid type definition (%s): \"%s\"", err, string_to_cquote (_typedef).c_str());
}

String
Type::ident () const
{
  return m_info.name;
}

String
Type::label () const
{
  String l = aux_string ("label");
  if (l.size() == 0)
    return ident();
  return l;
}

String
Type::blurb () const
{
  return aux_string ("blurb");
}

String
Type::hints () const
{
  String h = aux_string ("hints");
  if (h.size() == 0 || h[0] != ':')
    h = ":" + h;
  if (h[h.size()-1] != ':')
    h = h + ":";
  return h;
}

Type::Storage
Type::storage () const
{
  return m_info.storage;
}

String
Type::aux_string (const String &auxname) const
{
  if (!strchr (auxname.c_str(), '='))
    {
      String prefix = auxname + "=";
      for (vector<String>::const_iterator it = m_info.auxdata.begin(); it != m_info.auxdata.end(); it++)
        if ((*it).compare (0, prefix.size(), prefix) == 0)
          return (*it).c_str() + prefix.size();
    }
  return "";
}

long double
Type::aux_float (const String &auxname) const
{
  return string_to_double (aux_string (auxname));
}

int64
Type::aux_num (const String &auxname) const
{
  return string_to_int (aux_string (auxname));
}

#define return_if(cond,string)     do { if (cond) return string; } while (0)

struct TypeInfo : public virtual ReferenceCountImpl {
  const char   *type_string;
  uint          type_string_length;
  Typ2::Storage type_storage;
  uint          name_offset, name_length;
  vector<uint>  auxdata_offsets; // last member points after last aux key
};

struct Typ2::Info : public TypeInfo {
  String type_string_mem;
};

static String
parse_int (const char **tsp,
           const char  *boundary,
           uint        *ui)
{
  return_if (*tsp + 4 > boundary, "premature end");
  uint8 *us = (uint8*) *tsp, u0 = us[0], u1 = us[1], u2 = us[2], u3 = us[3];
  if (u0 < 128 || u1 < 128 || u2 < 128 || u3 < 128)
    return "invalid integer encoding";
  *ui = (u3 & 0x7f) + ((u2 & 0x7f) >> 1) + ((u1 & 0x7f) >> 2) + ((u0 & 0x7f) >> 3);
  *tsp += 4;
  return "";
}

static String
parse_strings (uint          count,
               const char   *tstart,
               const char  **tsp,
               const char   *boundary,
               vector<uint> *offsets,
               const String &errpart)
{
  // Parse: xxxx XString yyyy YString zzzz ZString
  // Store: ^            ^            ^            ^ (i.e. count + 1 offsets)
  uint ui = 0;
  for (uint i = 0; i < count; i++)
    {
      offsets->push_back (*tsp - tstart);
      String err = parse_int (tsp, boundary, &ui);
      return_if (err != "", string_printf ("%s while parsing %s", err.c_str(), errpart.c_str()));
      return_if (*tsp + ui > boundary, string_printf ("premature end while parsing %s", errpart.c_str()));
      *tsp += ui;
    }
  offsets->push_back (*tsp - tstart);
  assert (offsets->size() == count + 1); // paranoid
  return "";
}

static String
parse_type_info (TypeInfo    &self,
                 const char  *type_string_start,
                 const char **tsp,
                 const char  *boundary)
{
  /* parse type info:
   * - LLLL                   // length of upcoming type info data
   * - ___?                   // storage type
   * - xxxx                   // number of aux entries
   * - [ llll AuxEntry ]*     // xxxx times aux entry strings
   * - CHOICE:    yyyy [ llll Ident llll Label llll Blurb ]+
   * - RECORD:    yyyy [ llll FieldName _TYPE_INFO_ ]+
   * - SEQUENCE:  yyyy FieldName _TYPE_INFO_
   * - INTERFACE: yyyy [ llll InterfaceTypeName ]+
   */
  String err;
  uint ui = 0;
  // type length
  err = parse_int (tsp, boundary, &ui);
  return_if (err != "", err + " in type info length");
  return_if (*tsp + ui > boundary, "type info data too short");
  boundary = MIN (*tsp + ui, boundary);
  // storage type
  return_if (*tsp + 4 > boundary, "premature end at storage type");
  if (strncmp (*tsp, "___", 3) != 0 || !strchr (RAPICORN_TYP2_STORAGE_CHARS, (*tsp)[3]))
    return "invalid storage type";
  self.type_storage = Typ2::Storage ((*tsp)[3]);
  *tsp += 4;
  // number of aux entries
  err = parse_int (tsp, boundary, &ui);
  return_if (err != "", err + " at aux entries");
  return_if (*tsp + ui * (4 + 1) > boundary, "premature end in aux data");
  // parse aux info
  self.auxdata_offsets.clear();
  if (ui)
    {
      err = parse_strings (ui, type_string_start, tsp, boundary, &self.auxdata_offsets, "aux infos");
      return_if (err != "", err);
    }
  // skip across unrecognized type data
  *tsp = boundary;
  // FIXME: 0xfe00000 0x1fc000 0x3f80 0x7f
  return "";
}

static String
parse_offsets (TypeInfo    &self,
               const char *ts,
               uint        _tsl)
{
  /* parse a type definition like:
   * - GTyp e001              // magic
   * - llll TypeNameString    // type name with length
   * - LLLL TypeInfo_data     // main type info with length
   */
  self.type_string = ts;
  self.type_string_length = _tsl;
  const char *tb = ts + _tsl;
  String err;
  if (!self.type_string || self.type_string_length == 0 || self.type_string[0] == 0)
    return "Empty type string";
  if (ts + 24 > tb)
    return "type info string too short";
  // check magic
  if (strncmp (self.type_string, "GType001", 8) != 0)
    return "Invalid/unknown type info string";
  ts += 8;
  // type name
  vector<uint> svo;
  err = parse_strings (1, self.type_string, &ts, tb, &svo, "type name");
  return_if (err != "", err);
  self.name_offset = svo[0] + 4;
  self.name_length = svo[1] - self.name_offset;
  return_if (self.name_length < 1, "Invalid type name");
  // parse main type info
  err = parse_type_info (self, self.type_string, &ts, tb);
  return_if (err != "", err);
  // done
  return "";
}

String
Typ2::name () const
{
  return String (m_info->type_string + m_info->name_offset, m_info->name_length);
}

Typ2::Storage
Typ2::storage () const
{
  return m_info->type_storage;
}

String
Typ2::aux_string (const String &auxname) const
{
  String key = auxname + "=";
  uint kl = key.size();
  for (uint ui = 0; ui + 1 < m_info->auxdata_offsets.size(); ui++)
    {
      uint kb = m_info->auxdata_offsets[ui] + 4;
      uint ke = m_info->auxdata_offsets[ui + 1];
      if (ke - kb >= kl && m_info->type_string[kb + kl - 1] == '=' &&
          strncmp (m_info->type_string + kb, key.c_str(), kl - 1) == 0)
        return String (m_info->type_string + kb + kl, ke - kb - kl);
    }
  return "";
}

double
Typ2::aux_float (const String &auxname) const
{
  return string_to_double (aux_string (auxname));
}

int64
Typ2::aux_num (const String &auxname) const
{
  return string_to_int (aux_string (auxname));
}

String
Typ2::label () const
{
  String str = aux_string ("label");
  return str.size() == 0 ? ident() : str;
}

String
Typ2::hints () const
{
  String str = aux_string ("hints");
  if (str.size() == 0 || str[0] != ':')
    str = ":" + str;
  if (str[str.size() - 1] != ':')
    str = str + ":";
  return str;
}

Typ2::Typ2 (Info &tinfo) :
  m_info (ref (&tinfo))
{}

Typ2::Typ2 (const Typ2 &src) :
  m_info (ref (src.m_info))
{}

Typ2::~Typ2 ()
{
  Info *old_info = m_info;
  m_info = NULL;
  if (old_info)
    unref (old_info);
}

Typ2
Typ2::from_type_info (const char *rom_type_info_string,
                      uint        type_info_string_length)
{
  Typ2::Info *type_info = new Typ2::Info();
  ref_sink (type_info);
  /* we rely on caller owned memory to stay around
   * // type_info.type_string_mem = String (rom_type_info_string, type_info_string_length);
   */
  String err = parse_offsets (*type_info, rom_type_info_string, type_info_string_length);
  if (err != "")
    error ("%s: %s", STRFUNC, err.c_str());
  Typ2 type (*type_info);
  unref (type_info);
  return type;
}

Typ2* // caller owns Typ2*
Typ2::from_type_info (const String &type_info_string,
                      String       &error)
{
  Typ2::Info *type_info = new Typ2::Info();
  ref_sink (type_info);
  type_info->type_string_mem = type_info_string; // copy and save type_info_string
  error = parse_offsets (*type_info, type_info->type_string_mem.data(), type_info->type_string_mem.size());
  Typ2 *tp = NULL;
  if (error == "")
    tp = new Typ2 (*type_info);
  return tp;
}

} // Rapicorn
<commit_msg>rapicorn-core/types.cc: amend type info comments about parsing structure<commit_after>/* Rapicorn
 * Copyright (C) 2008 Tim Janik
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * A copy of the GNU Lesser General Public License should ship along
 * with this library; if not, see http://www.gnu.org/copyleft/.
 */
#include "types.hh"

namespace Rapicorn {

#define IS_RAPICORN_TYPE_STORAGE(strg)  (strchr (RAPICORN_TYPE_STORAGE_CHARS, strg))

const char*
Type::type_name (Type::Storage storage)
{
  switch (storage)
    {
    case Type::NUM:             return "NUM";
    case Type::FLOAT:           return "FLOAT";
    case Type::STRING:          return "STRING";
    case Type::ARRAY:           return "ARRAY";
    case Type::STRING_VECTOR:   return "STRING_VECTOR";
    case Type::OBJECT:          return "OBJECT";
    }
  return NULL;
}

static const char*
parse_hexnum (const char *input,
              uint       &pos,
              int64      &result,
              uint        n_digits)
{
  static const char *NFE = "hexnum parse error";
  result = 0;
  while (n_digits--)
    {
      if (!strchr ("ABCDEFabcdef0123456789", input[pos]))
        return NFE;
      result <<= 4;
      result += input[pos] >= 'a' ? input[pos] - 'a' + 10 : input[pos] >= 'A' ? input[pos] - 'A' + 10 : input[pos] > '0' ? input[pos] - '0' : 0;
      pos++;
    }
  return NULL;
}

static const char*
parse_string (const char *input,
              uint       &pos,
              String     &result,
              uint        n_digits)
{
  static const char *SSE = "short string encountered";
  int64 n;
  const char *err = parse_hexnum (input, pos, n, n_digits);
  if (err)
    return err;
  while (n--)
    {
      if (!input[pos])
        return SSE;
      result += input[pos++];
    }
  return NULL;
}

static const char*
parse_assignment (const char *assignment,
                  uint       *offset)
{
  static const char *IKA = "invalid key=value assignment syntax";
  if (!((assignment[0] >= 'A' && assignment[0] <= 'Z') ||
        (assignment[0] >= 'a' && assignment[0] <= 'z') ||
        (assignment[0] >= '0' && assignment[0] <= '9') ||
        assignment[0] == '_'))
    return IKA;
  uint i = 1;
  while (strchr ("abcdefghijklmnopqrstuvwxyz0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ", assignment[i]))
    i++;
  if (assignment[i] != '=')
    return IKA;
  *offset = i + 1;
  return NULL;
}

static const char*
type_parser (char const *input,
             Type::Info &ti)
{
  static const char *ITD = "format error";
  /* format:
   * <StorageChar>US
   */
  uint pos = 0;
  // parse magic indicator
  if (input[pos++] != 'R')
    return ITD;
  if (input[pos++] != 'c')
    return ITD;
  if (input[pos++] != 'T')
    return ITD;
  if (input[pos++] != 'i')
    return ITD;
  if (input[pos++] != ';')
    return ITD;
  // parse type name
  const char *err = parse_string (input, pos, ti.name, 4);
  if (err)
    return err;
  if (input[pos++] != ';')
    return ITD;
  // parse storage type
  ti.storage = Type::Storage (input[pos++]);
  if (!ti.storage || !IS_RAPICORN_TYPE_STORAGE (ti.storage))
    return ITD;
  if (input[pos++] != ';')
    return ITD;
  // parse aux data
  while (input[pos] && input[pos] != ';')
    {
      uint offset = 0;
      String astr;
      err = parse_string (input, pos, astr, 4);
      if (err)
        return err;
      err = parse_assignment (astr.c_str(), &offset);
      if (err)
        return err;
      String name = String (astr, 0, offset - 1);
      String value = String (astr, offset);
      ti.auxdata.push_back (name + "=" + value);
    }
  if (input[pos++] != ';')
    return ITD;
  return NULL;
}

Type::Type (char const *_typedef) :
  m_info()
{
  const char *err = type_parser (_typedef, m_info);
  if (err)
    RAPICORN_ERROR ("invalid type definition (%s): \"%s\"", err, string_to_cquote (_typedef).c_str());
}

String
Type::ident () const
{
  return m_info.name;
}

String
Type::label () const
{
  String l = aux_string ("label");
  if (l.size() == 0)
    return ident();
  return l;
}

String
Type::blurb () const
{
  return aux_string ("blurb");
}

String
Type::hints () const
{
  String h = aux_string ("hints");
  if (h.size() == 0 || h[0] != ':')
    h = ":" + h;
  if (h[h.size()-1] != ':')
    h = h + ":";
  return h;
}

Type::Storage
Type::storage () const
{
  return m_info.storage;
}

String
Type::aux_string (const String &auxname) const
{
  if (!strchr (auxname.c_str(), '='))
    {
      String prefix = auxname + "=";
      for (vector<String>::const_iterator it = m_info.auxdata.begin(); it != m_info.auxdata.end(); it++)
        if ((*it).compare (0, prefix.size(), prefix) == 0)
          return (*it).c_str() + prefix.size();
    }
  return "";
}

long double
Type::aux_float (const String &auxname) const
{
  return string_to_double (aux_string (auxname));
}

int64
Type::aux_num (const String &auxname) const
{
  return string_to_int (aux_string (auxname));
}

#define return_if(cond,string)     do { if (cond) return string; } while (0)

struct TypeInfo : public virtual ReferenceCountImpl {
  const char   *type_string;
  uint          type_string_length;
  Typ2::Storage type_storage;
  uint          name_offset, name_length;
  vector<uint>  auxdata_offsets; // last member points after last aux key
};

struct Typ2::Info : public TypeInfo {
  String type_string_mem;
};

static String
parse_int (const char **tsp,
           const char  *boundary,
           uint        *ui)
{
  return_if (*tsp + 4 > boundary, "premature end");
  uint8 *us = (uint8*) *tsp, u0 = us[0], u1 = us[1], u2 = us[2], u3 = us[3];
  if (u0 < 128 || u1 < 128 || u2 < 128 || u3 < 128)
    return "invalid integer encoding";
  *ui = (u3 & 0x7f) + ((u2 & 0x7f) >> 1) + ((u1 & 0x7f) >> 2) + ((u0 & 0x7f) >> 3);
  *tsp += 4;
  return "";
}

static String
parse_strings (uint          count,
               const char   *tstart,
               const char  **tsp,
               const char   *boundary,
               vector<uint> *offsets,
               const String &errpart)
{
  // Parse: xxxx XString yyyy YString zzzz ZString
  // Store: ^            ^            ^            ^ (i.e. count + 1 offsets)
  uint ui = 0;
  for (uint i = 0; i < count; i++)
    {
      offsets->push_back (*tsp - tstart);
      String err = parse_int (tsp, boundary, &ui);
      return_if (err != "", string_printf ("%s while parsing %s", err.c_str(), errpart.c_str()));
      return_if (*tsp + ui > boundary, string_printf ("premature end while parsing %s", errpart.c_str()));
      *tsp += ui;
    }
  offsets->push_back (*tsp - tstart);
  assert (offsets->size() == count + 1); // paranoid
  return "";
}

static String
parse_type_info (TypeInfo    &self,
                 const char  *type_string_start,
                 const char **tsp,
                 const char  *boundary)
{
  /* parse type info:
   * - LLLL                   // length of upcoming type info data
   * - ___?                   // storage type
   * - kkkk                   // number of aux entries
   * - [ llll AuxEntry ]*     // kkkk times aux entry strings
   * - REFERENCE: llll TypeName
   * - CHOICE:    nnnn [ llll Ident llll Label llll Blurb ]+
   * - RECORD:    nnnn [ llll FieldName _TYPE_INFO_ ]+
   * - SEQUENCE:  llll FieldName _TYPE_INFO_
   * - INTERFACE: nnnn [ llll InterfaceTypeName ]+
   */
  String err;
  uint ui = 0;
  // type length
  err = parse_int (tsp, boundary, &ui);
  return_if (err != "", err + " in type info length");
  return_if (*tsp + ui > boundary, "type info data too short");
  boundary = MIN (*tsp + ui, boundary);
  // storage type
  return_if (*tsp + 4 > boundary, "premature end at storage type");
  if (strncmp (*tsp, "___", 3) != 0 || !strchr (RAPICORN_TYP2_STORAGE_CHARS, (*tsp)[3]))
    return "invalid storage type";
  self.type_storage = Typ2::Storage ((*tsp)[3]);
  *tsp += 4;
  // number of aux entries
  err = parse_int (tsp, boundary, &ui);
  return_if (err != "", err + " at aux entries");
  return_if (*tsp + ui * (4 + 1) > boundary, "premature end in aux data");
  // parse aux info
  self.auxdata_offsets.clear();
  if (ui)
    {
      err = parse_strings (ui, type_string_start, tsp, boundary, &self.auxdata_offsets, "aux infos");
      return_if (err != "", err);
    }
  // skip across unrecognized type data
  *tsp = boundary;
  // FIXME: 0xfe00000 0x1fc000 0x3f80 0x7f
  return "";
}

static String
parse_offsets (TypeInfo    &self,
               const char *ts,
               uint        _tsl)
{
  /* parse a type definition like:
   * - GTyp e001              // magic
   * - llll TypeNameString    // type name with length
   * - LLLL TypeInfo_data     // main type info with length
   */
  self.type_string = ts;
  self.type_string_length = _tsl;
  const char *tb = ts + _tsl;
  String err;
  if (!self.type_string || self.type_string_length == 0 || self.type_string[0] == 0)
    return "Empty type string";
  if (ts + 24 > tb)
    return "type info string too short";
  // check magic
  if (strncmp (self.type_string, "GType001", 8) != 0)
    return "Invalid/unknown type info string";
  ts += 8;
  // type name
  vector<uint> svo;
  err = parse_strings (1, self.type_string, &ts, tb, &svo, "type name");
  return_if (err != "", err);
  self.name_offset = svo[0] + 4;
  self.name_length = svo[1] - self.name_offset;
  return_if (self.name_length < 1, "Invalid type name");
  // parse main type info
  err = parse_type_info (self, self.type_string, &ts, tb);
  return_if (err != "", err);
  // done
  return "";
}

String
Typ2::name () const
{
  return String (m_info->type_string + m_info->name_offset, m_info->name_length);
}

Typ2::Storage
Typ2::storage () const
{
  return m_info->type_storage;
}

String
Typ2::aux_string (const String &auxname) const
{
  String key = auxname + "=";
  uint kl = key.size();
  for (uint ui = 0; ui + 1 < m_info->auxdata_offsets.size(); ui++)
    {
      uint kb = m_info->auxdata_offsets[ui] + 4;
      uint ke = m_info->auxdata_offsets[ui + 1];
      if (ke - kb >= kl && m_info->type_string[kb + kl - 1] == '=' &&
          strncmp (m_info->type_string + kb, key.c_str(), kl - 1) == 0)
        return String (m_info->type_string + kb + kl, ke - kb - kl);
    }
  return "";
}

double
Typ2::aux_float (const String &auxname) const
{
  return string_to_double (aux_string (auxname));
}

int64
Typ2::aux_num (const String &auxname) const
{
  return string_to_int (aux_string (auxname));
}

String
Typ2::label () const
{
  String str = aux_string ("label");
  return str.size() == 0 ? ident() : str;
}

String
Typ2::hints () const
{
  String str = aux_string ("hints");
  if (str.size() == 0 || str[0] != ':')
    str = ":" + str;
  if (str[str.size() - 1] != ':')
    str = str + ":";
  return str;
}

Typ2::Typ2 (Info &tinfo) :
  m_info (ref (&tinfo))
{}

Typ2::Typ2 (const Typ2 &src) :
  m_info (ref (src.m_info))
{}

Typ2::~Typ2 ()
{
  Info *old_info = m_info;
  m_info = NULL;
  if (old_info)
    unref (old_info);
}

Typ2
Typ2::from_type_info (const char *rom_type_info_string,
                      uint        type_info_string_length)
{
  Typ2::Info *type_info = new Typ2::Info();
  ref_sink (type_info);
  /* we rely on caller owned memory to stay around
   * // type_info.type_string_mem = String (rom_type_info_string, type_info_string_length);
   */
  String err = parse_offsets (*type_info, rom_type_info_string, type_info_string_length);
  if (err != "")
    error ("%s: %s", STRFUNC, err.c_str());
  Typ2 type (*type_info);
  unref (type_info);
  return type;
}

Typ2* // caller owns Typ2*
Typ2::from_type_info (const String &type_info_string,
                      String       &error)
{
  Typ2::Info *type_info = new Typ2::Info();
  ref_sink (type_info);
  type_info->type_string_mem = type_info_string; // copy and save type_info_string
  error = parse_offsets (*type_info, type_info->type_string_mem.data(), type_info->type_string_mem.size());
  Typ2 *tp = NULL;
  if (error == "")
    tp = new Typ2 (*type_info);
  return tp;
}

} // Rapicorn
<|endoftext|>


<commit_before>// Copyright (c) 2015, Matthew Malensek.
// Distributed under the BSD 2-Clause License (see LICENSE.txt for details)

#include "LayeredWnd.h"

#include <dwmapi.h>
#pragma comment(lib, "dwmapi.lib")
#include <VersionHelpers.h>

#include "../D3DDevice.h"
#include "../DisplayManager.h"
#include "../Error.h"

LayeredWnd::LayeredWnd(LPCWSTR className, LPCWSTR title, HINSTANCE hInstance,
    Gdiplus::Bitmap *bitmap, DWORD exStyles) :
Window(className, title, hInstance,
    CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL,
    WS_POPUP, WS_EX_LAYERED | exStyles),
_transparency(255),
_visible(false) {

    Bitmap(bitmap);
}

LayeredWnd::~LayeredWnd() {
    delete _d3dDevice;
}

void LayeredWnd::UpdateWindow(RECT *dirtyRect) {
    BLENDFUNCTION bFunc;
    bFunc.AlphaFormat = AC_SRC_ALPHA;
    bFunc.BlendFlags = 0;
    bFunc.BlendOp = AC_SRC_OVER;
    bFunc.SourceConstantAlpha = _transparency;

    HDC screenDc = GetDC(GetDesktopWindow());
    HDC sourceDc = CreateCompatibleDC(screenDc);

    HBITMAP hBmp;
    _bitmap->GetHBITMAP(Gdiplus::Color(0, 0, 0, 0), &hBmp);
    HGDIOBJ hReplaced = SelectObject(sourceDc, hBmp);

    POINT pt = { 0, 0 };
    SIZE size = {
        static_cast<LONG>(_bitmap->GetWidth()),
        static_cast<LONG>(_bitmap->GetHeight())
    };

    UPDATELAYEREDWINDOWINFO lwInfo;
    lwInfo.cbSize = sizeof(UPDATELAYEREDWINDOWINFO);
    lwInfo.crKey = 0;
    lwInfo.dwFlags = ULW_ALPHA;
    lwInfo.hdcDst = screenDc;
    lwInfo.hdcSrc = sourceDc;
    lwInfo.pblend = &bFunc;
    lwInfo.pptDst = &_location;
    lwInfo.pptSrc = &pt;
    lwInfo.prcDirty = dirtyRect;
    lwInfo.psize = &size;

    UpdateLayeredWindowIndirect(Window::Handle(), &lwInfo);

    SelectObject(sourceDc, hReplaced);
    DeleteDC(sourceDc);
    DeleteObject(hBmp);
    ReleaseDC(GetDesktopWindow(), screenDc);
}

void LayeredWnd::UpdateTransparency() {
    BLENDFUNCTION bFunc;
    bFunc.AlphaFormat = AC_SRC_ALPHA;
    bFunc.BlendFlags = 0;
    bFunc.BlendOp = AC_SRC_OVER;
    bFunc.SourceConstantAlpha = _transparency;

    UPDATELAYEREDWINDOWINFO lwInfo;
    lwInfo.cbSize = sizeof(UPDATELAYEREDWINDOWINFO);
    lwInfo.crKey = 0;
    lwInfo.dwFlags = ULW_ALPHA;
    lwInfo.hdcDst = NULL;
    lwInfo.hdcSrc = NULL;
    lwInfo.pblend = &bFunc;
    lwInfo.pptDst = NULL;
    lwInfo.pptSrc = NULL;
    lwInfo.prcDirty = NULL;
    lwInfo.psize = NULL;

    UpdateLayeredWindowIndirect(Window::Handle(), &lwInfo);
}

bool LayeredWnd::EnableGlass(Gdiplus::Bitmap *mask) {
    if (mask == NULL) {
        return false;
    }

    /* Disable for Windows 8+ */
    if (IsWindows8OrGreater()) {
        return false;
    }

    /* Disable for Windows XP */
    if (IsWindowsXPOrGreater() == true && IsWindowsVistaOrGreater() == false) {
        return false;
    }

    _glassMask = mask;

    using namespace Gdiplus;
    ARGB searchArgb = 0xFF000000;

    unsigned int height = _glassMask->GetHeight();
    unsigned int width = _glassMask->GetWidth();

    Region glassRegion;
    glassRegion.MakeEmpty();
    bool match = false;

    /* One row of pixels is scanned at a time, so the height is 1. */
    Rect rec(0, 0, 0, 1);

    for (unsigned int y = 0; y < height; ++y) {
        for (unsigned int x = 0; x < width; ++x) {
            Color pixelColor;
            _glassMask->GetPixel(x, y, &pixelColor);
            ARGB pixelArgb = pixelColor.GetValue();

            if (searchArgb == pixelArgb && (x + 1 != width)) {
                if (match) {
                    continue;
                }

                match = true;
                rec.X = x;
                rec.Y = y;
            } else if (match) {
                /* Reached the end of a matching line */
                match = false;
                rec.Width = x - rec.X;
                glassRegion.Union(rec);
            }
        }
    }

    DWM_BLURBEHIND blurBehind = { 0 };
    blurBehind.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
    blurBehind.fEnable = TRUE;

    Graphics g(_glassMask);
    blurBehind.hRgnBlur = glassRegion.GetHRGN(&g);

    HRESULT hr = DwmEnableBlurBehindWindow(Window::Handle(), &blurBehind);
    return SUCCEEDED(hr);
}

bool LayeredWnd::DisableGlass() {
    DWM_BLURBEHIND blurBehind = { 0 };
    blurBehind.dwFlags = DWM_BB_ENABLE;
    blurBehind.fEnable = FALSE;
    HRESULT hr = DwmEnableBlurBehindWindow(Window::Handle(), &blurBehind);
    return SUCCEEDED(hr);
}

bool LayeredWnd::NoShowFullscreen() {
    return _noShowFull;
}

void LayeredWnd::NoShowFullscreen(bool enable) {
    _noShowFull = enable;
}

bool LayeredWnd::NoShowD3DOccluded() {
    return _noShowD3D;
}

void LayeredWnd::NoShowD3DOccluded(bool enable) {
    if (enable == true) {
        if (_d3dDevice == nullptr) {
            _d3dDevice = new D3DDevice(Window::Handle());
        }
    } else {
        if (_d3dDevice != nullptr) {
            delete _d3dDevice;
        }
    }
    _noShowD3D = enable;
}

void LayeredWnd::UpdateWindowPosition() {
    MoveWindow(Window::Handle(),
        _location.x, _location.y, _size.cx, _size.cy, FALSE);
}

void LayeredWnd::Show() {
    if (_visible == true) {
        return;
    }

    if (_noShowFull == true && DisplayManager::IsFullscreen(Window::Handle())) {
        return;
    }

    if (_noShowD3D == true && _d3dDevice->Occluded() == true) {
        return;
    }

    UpdateWindow();
    ShowWindow(Window::Handle(), SW_SHOW);
    _visible = true;
}

void LayeredWnd::Hide() {
    if (_visible == false) {
        return;
    }

    ShowWindow(Window::Handle(), SW_HIDE);
    _visible = false;
}

Gdiplus::Bitmap *LayeredWnd::Bitmap() {
    return _bitmap;
}

void LayeredWnd::Bitmap(Gdiplus::Bitmap *bitmap) {
    if (bitmap == NULL) {
        return;
    }

    _bitmap = bitmap;
    _size.cx = bitmap->GetWidth();
    _size.cy = bitmap->GetHeight();
    UpdateWindow();
}

bool LayeredWnd::AlwaysOnTop() {
    return (GetWindowLong(Window::Handle(), GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
}

void LayeredWnd::AlwaysOnTop(bool onTop) {
    if (onTop) {
        SetWindowPos(Window::Handle(), HWND_TOPMOST,
            X(), Y(), Width(), Height(), NULL);
    } else {
        SetWindowPos(Window::Handle(), HWND_NOTOPMOST,
            X(), Y(), Width(), Height(), NULL);
    }
}

byte LayeredWnd::Transparency() {
    return _transparency;
}

void LayeredWnd::Transparency(byte transparency) {
    _transparency = transparency;
    UpdateTransparency();
}

int LayeredWnd::X() {
    return _location.x;
}

void LayeredWnd::X(int x) {
    _location.x = x;
}

int LayeredWnd::Y() {
    return _location.y;
}

void LayeredWnd::Y(int y) {
    _location.y = y;
}

int LayeredWnd::Width() {
    return _size.cx;
}

int LayeredWnd::Height() {
    return _size.cy;
}

POINT LayeredWnd::Position() {
    return _location;
}

void LayeredWnd::Position(int x, int y) {
    _location.x = x;
    _location.y = y;
    UpdateWindowPosition();
}

LRESULT LayeredWnd::WndProc(
        HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {

    if (_glassMask && message == WM_DWMCOMPOSITIONCHANGED) {
        BOOL compositionEnabled = FALSE;
        HRESULT hr = DwmIsCompositionEnabled(&compositionEnabled);

        if (SUCCEEDED(hr)) {
            if (compositionEnabled) {
                EnableGlass(_glassMask);
            } else {
                DisableGlass();
            }
        }
    }

    return Window::WndProc(hWnd, message, wParam, lParam);
}<commit_msg>Add log messages for Show() overrides<commit_after>// Copyright (c) 2015, Matthew Malensek.
// Distributed under the BSD 2-Clause License (see LICENSE.txt for details)

#include "LayeredWnd.h"

#include <dwmapi.h>
#pragma comment(lib, "dwmapi.lib")
#include <VersionHelpers.h>

#include "../D3DDevice.h"
#include "../DisplayManager.h"
#include "../Error.h"
#include "../Logger.h"

LayeredWnd::LayeredWnd(LPCWSTR className, LPCWSTR title, HINSTANCE hInstance,
    Gdiplus::Bitmap *bitmap, DWORD exStyles) :
Window(className, title, hInstance,
    CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL,
    WS_POPUP, WS_EX_LAYERED | exStyles),
_transparency(255),
_visible(false) {

    Bitmap(bitmap);
}

LayeredWnd::~LayeredWnd() {
    delete _d3dDevice;
}

void LayeredWnd::UpdateWindow(RECT *dirtyRect) {
    BLENDFUNCTION bFunc;
    bFunc.AlphaFormat = AC_SRC_ALPHA;
    bFunc.BlendFlags = 0;
    bFunc.BlendOp = AC_SRC_OVER;
    bFunc.SourceConstantAlpha = _transparency;

    HDC screenDc = GetDC(GetDesktopWindow());
    HDC sourceDc = CreateCompatibleDC(screenDc);

    HBITMAP hBmp;
    _bitmap->GetHBITMAP(Gdiplus::Color(0, 0, 0, 0), &hBmp);
    HGDIOBJ hReplaced = SelectObject(sourceDc, hBmp);

    POINT pt = { 0, 0 };
    SIZE size = {
        static_cast<LONG>(_bitmap->GetWidth()),
        static_cast<LONG>(_bitmap->GetHeight())
    };

    UPDATELAYEREDWINDOWINFO lwInfo;
    lwInfo.cbSize = sizeof(UPDATELAYEREDWINDOWINFO);
    lwInfo.crKey = 0;
    lwInfo.dwFlags = ULW_ALPHA;
    lwInfo.hdcDst = screenDc;
    lwInfo.hdcSrc = sourceDc;
    lwInfo.pblend = &bFunc;
    lwInfo.pptDst = &_location;
    lwInfo.pptSrc = &pt;
    lwInfo.prcDirty = dirtyRect;
    lwInfo.psize = &size;

    UpdateLayeredWindowIndirect(Window::Handle(), &lwInfo);

    SelectObject(sourceDc, hReplaced);
    DeleteDC(sourceDc);
    DeleteObject(hBmp);
    ReleaseDC(GetDesktopWindow(), screenDc);
}

void LayeredWnd::UpdateTransparency() {
    BLENDFUNCTION bFunc;
    bFunc.AlphaFormat = AC_SRC_ALPHA;
    bFunc.BlendFlags = 0;
    bFunc.BlendOp = AC_SRC_OVER;
    bFunc.SourceConstantAlpha = _transparency;

    UPDATELAYEREDWINDOWINFO lwInfo;
    lwInfo.cbSize = sizeof(UPDATELAYEREDWINDOWINFO);
    lwInfo.crKey = 0;
    lwInfo.dwFlags = ULW_ALPHA;
    lwInfo.hdcDst = NULL;
    lwInfo.hdcSrc = NULL;
    lwInfo.pblend = &bFunc;
    lwInfo.pptDst = NULL;
    lwInfo.pptSrc = NULL;
    lwInfo.prcDirty = NULL;
    lwInfo.psize = NULL;

    UpdateLayeredWindowIndirect(Window::Handle(), &lwInfo);
}

bool LayeredWnd::EnableGlass(Gdiplus::Bitmap *mask) {
    if (mask == NULL) {
        return false;
    }

    /* Disable for Windows 8+ */
    if (IsWindows8OrGreater()) {
        return false;
    }

    /* Disable for Windows XP */
    if (IsWindowsXPOrGreater() == true && IsWindowsVistaOrGreater() == false) {
        return false;
    }

    _glassMask = mask;

    using namespace Gdiplus;
    ARGB searchArgb = 0xFF000000;

    unsigned int height = _glassMask->GetHeight();
    unsigned int width = _glassMask->GetWidth();

    Region glassRegion;
    glassRegion.MakeEmpty();
    bool match = false;

    /* One row of pixels is scanned at a time, so the height is 1. */
    Rect rec(0, 0, 0, 1);

    for (unsigned int y = 0; y < height; ++y) {
        for (unsigned int x = 0; x < width; ++x) {
            Color pixelColor;
            _glassMask->GetPixel(x, y, &pixelColor);
            ARGB pixelArgb = pixelColor.GetValue();

            if (searchArgb == pixelArgb && (x + 1 != width)) {
                if (match) {
                    continue;
                }

                match = true;
                rec.X = x;
                rec.Y = y;
            } else if (match) {
                /* Reached the end of a matching line */
                match = false;
                rec.Width = x - rec.X;
                glassRegion.Union(rec);
            }
        }
    }

    DWM_BLURBEHIND blurBehind = { 0 };
    blurBehind.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
    blurBehind.fEnable = TRUE;

    Graphics g(_glassMask);
    blurBehind.hRgnBlur = glassRegion.GetHRGN(&g);

    HRESULT hr = DwmEnableBlurBehindWindow(Window::Handle(), &blurBehind);
    return SUCCEEDED(hr);
}

bool LayeredWnd::DisableGlass() {
    DWM_BLURBEHIND blurBehind = { 0 };
    blurBehind.dwFlags = DWM_BB_ENABLE;
    blurBehind.fEnable = FALSE;
    HRESULT hr = DwmEnableBlurBehindWindow(Window::Handle(), &blurBehind);
    return SUCCEEDED(hr);
}

bool LayeredWnd::NoShowFullscreen() {
    return _noShowFull;
}

void LayeredWnd::NoShowFullscreen(bool enable) {
    _noShowFull = enable;
}

bool LayeredWnd::NoShowD3DOccluded() {
    return _noShowD3D;
}

void LayeredWnd::NoShowD3DOccluded(bool enable) {
    if (enable == true) {
        if (_d3dDevice == nullptr) {
            _d3dDevice = new D3DDevice(Window::Handle());
        }
    } else {
        if (_d3dDevice != nullptr) {
            delete _d3dDevice;
        }
    }
    _noShowD3D = enable;
}

void LayeredWnd::UpdateWindowPosition() {
    MoveWindow(Window::Handle(),
        _location.x, _location.y, _size.cx, _size.cy, FALSE);
}

void LayeredWnd::Show() {
    if (_visible == true) {
        return;
    }

    if (_noShowFull == true && DisplayManager::IsFullscreen(Window::Handle())) {
        CLOG(L"Not showing; fullscreen detected");
        return;
    }

    if (_noShowD3D == true && _d3dDevice->Occluded() == true) {
        CLOG(L"Not showing; D3D occlusion detected");
        return;
    }

    UpdateWindow();
    ShowWindow(Window::Handle(), SW_SHOW);
    _visible = true;
}

void LayeredWnd::Hide() {
    if (_visible == false) {
        return;
    }

    ShowWindow(Window::Handle(), SW_HIDE);
    _visible = false;
}

Gdiplus::Bitmap *LayeredWnd::Bitmap() {
    return _bitmap;
}

void LayeredWnd::Bitmap(Gdiplus::Bitmap *bitmap) {
    if (bitmap == NULL) {
        return;
    }

    _bitmap = bitmap;
    _size.cx = bitmap->GetWidth();
    _size.cy = bitmap->GetHeight();
    UpdateWindow();
}

bool LayeredWnd::AlwaysOnTop() {
    return (GetWindowLong(Window::Handle(), GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
}

void LayeredWnd::AlwaysOnTop(bool onTop) {
    if (onTop) {
        SetWindowPos(Window::Handle(), HWND_TOPMOST,
            X(), Y(), Width(), Height(), NULL);
    } else {
        SetWindowPos(Window::Handle(), HWND_NOTOPMOST,
            X(), Y(), Width(), Height(), NULL);
    }
}

byte LayeredWnd::Transparency() {
    return _transparency;
}

void LayeredWnd::Transparency(byte transparency) {
    _transparency = transparency;
    UpdateTransparency();
}

int LayeredWnd::X() {
    return _location.x;
}

void LayeredWnd::X(int x) {
    _location.x = x;
}

int LayeredWnd::Y() {
    return _location.y;
}

void LayeredWnd::Y(int y) {
    _location.y = y;
}

int LayeredWnd::Width() {
    return _size.cx;
}

int LayeredWnd::Height() {
    return _size.cy;
}

POINT LayeredWnd::Position() {
    return _location;
}

void LayeredWnd::Position(int x, int y) {
    _location.x = x;
    _location.y = y;
    UpdateWindowPosition();
}

LRESULT LayeredWnd::WndProc(
        HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {

    if (_glassMask && message == WM_DWMCOMPOSITIONCHANGED) {
        BOOL compositionEnabled = FALSE;
        HRESULT hr = DwmIsCompositionEnabled(&compositionEnabled);

        if (SUCCEEDED(hr)) {
            if (compositionEnabled) {
                EnableGlass(_glassMask);
            } else {
                DisableGlass();
            }
        }
    }

    return Window::WndProc(hWnd, message, wParam, lParam);
}<|endoftext|>


<commit_before>// This file is part of the dune-hdd project:
//   http://users.dune-project.org/projects/dune-hdd
// Copyright holders: Felix Albrecht
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_HDD_LINEARELLIPTIC_PROBLEMS_OS2014_HH
#define DUNE_HDD_LINEARELLIPTIC_PROBLEMS_OS2014_HH

#include <memory>

#include <dune/stuff/functions/constant.hh>
#include <dune/stuff/functions/expression.hh>

#include <dune/pymor/functions/default.hh>

#include "../../../linearelliptic/problems/default.hh"

namespace Dune {
namespace HDD {
namespace LinearElliptic {
namespace Problems {

template< class EntityImp, class DomainFieldImp, int domainDim, class RangeFieldImp, int rangeDim = 1 >
class OS2014
{
  static_assert(AlwaysFalse< EntityImp >::value, "Not available for dimRange > 1!");
};

template< class EntityImp, class DomainFieldImp, class RangeFieldImp >
class OS2014< EntityImp, DomainFieldImp, 2, RangeFieldImp, 1 >
  : public Default< EntityImp, DomainFieldImp, 2, RangeFieldImp, 1 >
{
  typedef Default< EntityImp, DomainFieldImp, 2, RangeFieldImp, 1 > BaseType;
  typedef OS2014< EntityImp, DomainFieldImp, 2, RangeFieldImp, 1 >  ThisType;

  typedef Stuff::Functions::Constant< EntityImp, DomainFieldImp, 2, RangeFieldImp, 1 >    ConstantScalarFunctionType;
  typedef Stuff::Functions::Constant< EntityImp, DomainFieldImp, 2, RangeFieldImp, 2, 2 > ConstantMatrixFunctionType;
  typedef Pymor::Function::NonparametricDefault< EntityImp, DomainFieldImp, 2, RangeFieldImp, 1 >
      ParametricScalarFunctionType;
  typedef Pymor::Function::NonparametricDefault< EntityImp, DomainFieldImp, 2, RangeFieldImp, 2, 2 >
      ParametricMatrixFunctionType;

  typedef Stuff::Functions::Expression< EntityImp, DomainFieldImp, 2, RangeFieldImp, 1 > ExpressionFunctionType;
  typedef Pymor::Function::AffinelyDecomposableDefault< EntityImp, DomainFieldImp, 2, RangeFieldImp, 1 >
      DefaultParametricFunctionType;

  typedef typename ConstantMatrixFunctionType::RangeType MatrixType;

public:
  static std::string static_id()
  {
    return BaseType::BaseType::static_id() + ".OS2014";
  }

  static Stuff::Common::ConfigTree default_config(const std::string sub_name = "")
  {
    Stuff::Common::ConfigTree config("integration_order", "3");
    if (sub_name.empty())
      return config;
    else {
      Stuff::Common::ConfigTree tmp;
      tmp.add(config, sub_name);
      return tmp;
    }
  } // ... default_config(...)

  static std::unique_ptr< ThisType > create(const Stuff::Common::ConfigTree config = default_config(),
                                            const std::string sub_name = static_id())
  {
    const Stuff::Common::ConfigTree cfg = config.has_sub(sub_name) ? config.sub(sub_name) : config;
    return Stuff::Common::make_unique< ThisType >(cfg.get("integration_order",
                                                          default_config().get< size_t >("integration_order")));
  } // ... create(...)

  OS2014(const size_t integration_order = default_config().get< size_t >("integration_order"))
    : BaseType(create_diffusion_factor_(integration_order),
               std::make_shared< ParametricMatrixFunctionType >(new ConstantMatrixFunctionType(unit_matrix_(),
                                                                                "diffusion_tensor")),
               std::make_shared< ParametricScalarFunctionType >(new ConstantScalarFunctionType(1, "force")),
               std::make_shared< ParametricScalarFunctionType >(new ConstantScalarFunctionType(0, "dirichlet")),
               std::make_shared< ParametricScalarFunctionType >(new ConstantScalarFunctionType(0, "neumann")))
  {}

  virtual std::string type() const DS_OVERRIDE
  {
    return BaseType::BaseType::static_id() + ".OS2014";
  }

private:
  static MatrixType unit_matrix_()
  {
    MatrixType matrix(RangeFieldImp(0));
    matrix[0][0] = RangeFieldImp(1);
    matrix[1][1] = RangeFieldImp(1);
    return matrix;
  }

  static std::shared_ptr< DefaultParametricFunctionType > create_diffusion_factor_(const size_t integration_order)
  {
    auto ret = std::make_shared< DefaultParametricFunctionType >(new ExpressionFunctionType(
                                                                   "x",
                                                                   "1+sin(2*pi*x[0])*sin(2*pi*x[1])",
                                                                   integration_order,
                                                                   "affine_part"));
    ret->register_component(new ExpressionFunctionType("x",
                                                       "-sin(2*pi*x[0])*sin(2*pi*x[1])",
                                                       integration_order,
                                                       "component_0"),
                            new Pymor::ParameterFunctional("mu", 1, "mu"));
    return ret;
  } // ... create_diffusion_factor_(...)
}; // class OS2014< ..., 1 >

} // namespace Problems
} // namespace LinearElliptic
} // namespace HDD
} // namespace Dune

#endif // DUNE_HDD_LINEARELLIPTIC_PROBLEMS_OS2014_HH
<commit_msg>[linearelliptic.problems.OS2014] updated data functions<commit_after>// This file is part of the dune-hdd project:
//   http://users.dune-project.org/projects/dune-hdd
// Copyright holders: Felix Albrecht
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_HDD_LINEARELLIPTIC_PROBLEMS_OS2014_HH
#define DUNE_HDD_LINEARELLIPTIC_PROBLEMS_OS2014_HH

#include <memory>

#include <dune/stuff/functions/constant.hh>
#include <dune/stuff/functions/expression.hh>
#include <dune/stuff/functions/ESV2007.hh>

#include <dune/pymor/functions/default.hh>

#include "../../../linearelliptic/problems/default.hh"

namespace Dune {
namespace HDD {
namespace LinearElliptic {
namespace Problems {

template< class EntityImp, class DomainFieldImp, int domainDim, class RangeFieldImp, int rangeDim = 1 >
class OS2014
{
  static_assert(AlwaysFalse< EntityImp >::value, "Not available for dimRange > 1!");
};

template< class EntityImp, class DomainFieldImp, class RangeFieldImp >
class OS2014< EntityImp, DomainFieldImp, 2, RangeFieldImp, 1 >
  : public Default< EntityImp, DomainFieldImp, 2, RangeFieldImp, 1 >
{
  typedef Default< EntityImp, DomainFieldImp, 2, RangeFieldImp, 1 > BaseType;
  typedef OS2014< EntityImp, DomainFieldImp, 2, RangeFieldImp, 1 >  ThisType;

  typedef Stuff::Functions::Constant< EntityImp, DomainFieldImp, 2, RangeFieldImp, 1 >    ConstantScalarFunctionType;
  typedef Stuff::Functions::Constant< EntityImp, DomainFieldImp, 2, RangeFieldImp, 2, 2 > ConstantMatrixFunctionType;
  typedef Pymor::Function::NonparametricDefault< EntityImp, DomainFieldImp, 2, RangeFieldImp, 1 >
      ParametricScalarFunctionType;
  typedef Pymor::Function::NonparametricDefault< EntityImp, DomainFieldImp, 2, RangeFieldImp, 2, 2 >
      ParametricMatrixFunctionType;

  typedef Stuff::Functions::ESV2007::Testcase1Force< EntityImp, DomainFieldImp, 2, RangeFieldImp, 1 > ForceType;
  typedef Stuff::Functions::Expression< EntityImp, DomainFieldImp, 2, RangeFieldImp, 1 > ExpressionFunctionType;
  typedef Pymor::Function::AffinelyDecomposableDefault< EntityImp, DomainFieldImp, 2, RangeFieldImp, 1 >
      DefaultParametricFunctionType;

  typedef typename ConstantMatrixFunctionType::RangeType MatrixType;

public:
  static std::string static_id()
  {
    return BaseType::BaseType::static_id() + ".OS2014";
  }

  static Stuff::Common::ConfigTree default_config(const std::string sub_name = "")
  {
    Stuff::Common::ConfigTree config("integration_order", "3");
    if (sub_name.empty())
      return config;
    else {
      Stuff::Common::ConfigTree tmp;
      tmp.add(config, sub_name);
      return tmp;
    }
  } // ... default_config(...)

  static std::unique_ptr< ThisType > create(const Stuff::Common::ConfigTree config = default_config(),
                                            const std::string sub_name = static_id())
  {
    const Stuff::Common::ConfigTree cfg = config.has_sub(sub_name) ? config.sub(sub_name) : config;
    return Stuff::Common::make_unique< ThisType >(cfg.get("integration_order",
                                                          default_config().get< size_t >("integration_order")));
  } // ... create(...)

  OS2014(const size_t integration_order = default_config().get< size_t >("integration_order"))
    : BaseType(create_diffusion_factor_(integration_order),
               std::make_shared< ParametricMatrixFunctionType >(new ConstantMatrixFunctionType(unit_matrix_(),
                                                                                "diffusion_tensor")),
               std::make_shared< ParametricScalarFunctionType >(new ForceType(integration_order,  "force")),
               std::make_shared< ParametricScalarFunctionType >(new ConstantScalarFunctionType(0, "dirichlet")),
               std::make_shared< ParametricScalarFunctionType >(new ConstantScalarFunctionType(0, "neumann")))
  {}

  virtual std::string type() const DS_OVERRIDE
  {
    return BaseType::BaseType::static_id() + ".OS2014";
  }

private:
  static MatrixType unit_matrix_()
  {
    MatrixType matrix(RangeFieldImp(0));
    matrix[0][0] = RangeFieldImp(1);
    matrix[1][1] = RangeFieldImp(1);
    return matrix;
  }

  static std::shared_ptr< DefaultParametricFunctionType > create_diffusion_factor_(const size_t integration_order)
  {
    auto ret = std::make_shared< DefaultParametricFunctionType >(new ExpressionFunctionType(
                                                                   "x",
                                                                   "1+0.75*(sin(4*pi*(x[0]+0.5*x[1])))",
                                                                   integration_order,
                                                                   "affine_part"));
    ret->register_component(new ExpressionFunctionType("x",
                                                       "-0.75*(sin(4*pi*(x[0]+0.5*x[1])))",
                                                       integration_order,
                                                       "component_0"),
                            new Pymor::ParameterFunctional("mu", 1, "mu"));
    return ret;
  } // ... create_diffusion_factor_(...)
}; // class OS2014< ..., 2, ..., 1 >

} // namespace Problems
} // namespace LinearElliptic
} // namespace HDD
} // namespace Dune

#endif // DUNE_HDD_LINEARELLIPTIC_PROBLEMS_OS2014_HH
<|endoftext|>


<commit_before>/**
 *  \file
 *  \remark This file is part of VITA.
 *
 *  \copyright Copyright (C) 2013-2016 EOS di Manlio Morini.
 *
 *  \license
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this file,
 *  You can obtain one at http://mozilla.org/MPL/2.0/
 */

#if !defined(VITA_EVOLUTION_H)
#  error "Don't include this file directly, include the specific .h instead"
#endif

#if !defined(VITA_EVOLUTION_TCC)
#define      VITA_EVOLUTION_TCC

namespace term
{
///
/// \return `true` when the user press the '.' key.
///
inline bool user_stop()
{
  const bool stop(kbhit() && std::cin.get() == '.');

  if (stop)
    print.info("Stopping evolution...");

  return stop;
}

///
/// Resets the term and restores the default signal handlers.
///
inline void reset()
{
  std::signal(SIGABRT, SIG_DFL);
  std::signal(SIGINT, SIG_DFL);
  std::signal(SIGTERM, SIG_DFL);

  term_raw_mode(false);
}

///
/// If the program receives a SIGABRT / SIGINT / SIGTERM, it must handle
/// the signal and reset the terminal to the initial state.
///
inline void signal_handler(int signum)
{
  term::reset();

  std::raise(signum);
}

///
/// Sets the term in raw mode and handles the interrupt signals.
///
inline void set()
{
  // Install our signal handler.
  std::signal(SIGABRT, term::signal_handler);
  std::signal(SIGINT, term::signal_handler);
  std::signal(SIGTERM, term::signal_handler);

  term_raw_mode(true);
}
}  // namespace term

///
/// \param[in] e environment (mostly used for population initialization).
/// \param[in] eva evaluator used during the evolution.
///
template<class T, template<class> class ES>
evolution<T, ES>::evolution(const environment &e, evaluator<T> &eva)
  : pop_(e), eva_(eva), es_(pop_, eva, &stats_)
{
  Expects(e.sset);
  Ensures(debug());
}

///
/// \param[in] s an up to date evolution summary.
/// \return `true` when evolution should be interrupted.
///
template<class T, template<class> class ES>
bool evolution<T, ES>::stop_condition(const summary<T> &s) const
{
  Expects(env().generations);

  // Check the number of generations.
  if (s.gen > env().generations)
    return true;

  if (term::user_stop())
    return true;

  // Check strategy specific stop conditions.
  return es_.stop_condition();
}

///
/// \return statistical informations about the elements of the population.
///
template<class T, template<class> class ES>
analyzer<T> evolution<T, ES>::get_stats() const
{
  analyzer<T> az;

  for (auto it(pop_.begin()), end(pop_.end()); it != end; ++it)
    az.add(*it, eva_(*it), it.layer());

  return az;
}

///
/// \param[in] run_count run number.
///
/// Saves working / statistical informations in a log file.
/// Data are written in a CSV-like fashion and are partitioned in blocks
/// separated by two blank lines:
/// [BLOCK_1]\n\n
/// [BLOCK_2]\n\n
/// ...
/// [BLOCK_x]
/// where each block is a set of line like this:
///   data_1 [space] data_2 [space] ... [space] data_n
/// We use this format, instead of XML, because statistics are produced
/// incrementally and so it's simple and fast to append new data to a
/// CSV-like file. Note also that data sets are ready to be plotted by
/// GNUPlot.
///
template<class T, template<class> class ES>
void evolution<T, ES>::log(unsigned run_count) const
{
  static unsigned last_run(0);

  auto fullpath = [this](const std::string &f)
                  {
                    return env().stat.dir + "/" + f;
                  };

  if (env().stat.dynamic)
  {
    std::ofstream f_dyn(fullpath(env().stat.dyn_name), std::ios_base::app);
    if (f_dyn.good())
    {
      if (last_run != run_count)
        f_dyn << "\n\n";

      f_dyn << run_count << ' ' << stats_.gen;

      if (stats_.best.solution.empty())
        f_dyn << " ?";
      else
        f_dyn << ' ' << stats_.best.score.fitness[0];

      f_dyn << ' ' << stats_.az.fit_dist().mean()[0]
            << ' ' << stats_.az.fit_dist().standard_deviation()[0]
            << ' ' << stats_.az.fit_dist().entropy()
            << ' ' << stats_.az.fit_dist().min()[0]
            << ' ' << static_cast<unsigned>(stats_.az.length_dist().mean())
            << ' ' << stats_.az.length_dist().standard_deviation()
            << ' ' << static_cast<unsigned>(stats_.az.length_dist().max())
            << ' ' << stats_.mutations
            << ' ' << stats_.crossovers
            << ' ' << stats_.az.functions(0)
            << ' ' << stats_.az.terminals(0)
            << ' ' << stats_.az.functions(1)
            << ' ' << stats_.az.terminals(1);

      for (unsigned active(0); active <= 1; ++active)
        for (const auto &symb_stat : stats_.az)
          f_dyn << ' ' << (symb_stat.first)->display()
                << ' ' << symb_stat.second.counter[active];

      f_dyn << " \"";
      if (!stats_.best.solution.empty())
        stats_.best.solution.in_line(f_dyn);
      f_dyn << "\"\n";
    }
  }

  if (env().stat.population)
  {
    std::ofstream f_pop(fullpath(env().stat.pop_name), std::ios_base::app);
    if (f_pop.good())
    {
      if (last_run != run_count)
        f_pop << "\n\n";

      for (const auto &f : stats_.az.fit_dist().seen())
        // f.first: value, f.second: frequency
        f_pop << run_count << ' ' << stats_.gen << ' '
              << std::fixed << std::scientific
              << std::setprecision(
                   std::numeric_limits<fitness_t::value_type>::digits10 + 2)
              << f.first[0] << ' ' << f.second << '\n';
    }
  }

  es_.log(last_run, run_count);

  if (last_run != run_count)
    last_run = run_count;
}

///
/// \param[in] k current generation.
/// \param[in] run_count total number of runs planned.
/// \param[in] status if `true` print a run/generation/fitness status line.
/// \param[in] from_last_msg time elapsed from the last message.
///
/// Print evolution informations (if `environment::log_level >= OUTPUT`).
///
template<class T, template<class> class ES>
void evolution<T, ES>::print_progress(unsigned k, unsigned run_count,
                                      bool status, timer *from_last_msg) const
{
  if (print.verbosity() >= log::L_OUTPUT)
  {
    const unsigned perc(100 * k / pop_.individuals());
    if (status)
      std::cout << "Run " << run_count << '.' << std::setw(6)
                << stats_.gen << " (" << std::setw(3)
                << perc << "%): fitness " << stats_.best.score.fitness
                << '\n';
    else
      std::cout << "Crunching " << run_count << '.' << stats_.gen << " ("
                << std::setw(3) << perc << "%)\r";

    std::cout << std::flush;

    from_last_msg->restart();
  }
}

///
/// \param[in] run_count run number (used for printing and logging).
/// \param[in] shake the "shake data" function. It's used to alter the training
///                  set so that evolution would take place in a dynamic
///                  environment.
/// \return a partial summary of the search (see notes).
///
/// The genetic programming loop:
///
/// * select the individual(s) to participate (default algorithm: tournament
///   selection) in the genetic operation;
/// * perform genetic operation creating a new offspring individual;
/// * place the offspring into the original population (steady state)
///   replacing a bad individual.
///
/// This whole process repeats until the termination criteria is satisfied.
/// With any luck, it will produce an individual that solves the problem at
/// hand.
///
/// \note
/// The return value is a partial summary: the `measurement` section is only
/// partially filled (fitness) since many metrics are expensive to calculate
/// and not significative for all kind of problems (e.g. f1-score for a
/// symbolic regression problem). The src_search class has a simple scheme to
/// request the computation of additional metrics.
///
template<class T, template<class> class ES>
template<class S>
const summary<T> &evolution<T, ES>::run(unsigned run_count, S shake)
{
  stats_.clear();
  stats_.best.solution = pop_[{0, 0}];
  stats_.best.score.fitness = eva_(stats_.best.solution);

  timer measure;
  timer from_last_msg;

  bool stop(false);
  term::set();

#if defined(CLONE_SCALING)
  eva_.clear(evaluator<T>::stats);
#endif

  es_.pre_bookkeeping();  // hook for strategy-specific preliminary bookkeeping

  for (stats_.gen = 0; !stop_condition(stats_) && !stop;  ++stats_.gen)
  {
    if (shake(stats_.gen))
    {
      // If we 'shake' the data, fitness values and the statistics picked so
      // far have to be cleared (the best individual and its fitness refer to
      // the previous training set).
      eva_.clear(evaluator<T>::all);

      assert(!stats_.best.solution.empty());
      stats_.best.score.fitness = eva_(stats_.best.solution);

      print_progress(0, run_count, true, &from_last_msg);
    }

    stats_.az = get_stats();
    log(run_count);

    for (unsigned k(0); k < pop_.individuals() && !stop; ++k)
    {
      if (from_last_msg.elapsed() > std::chrono::seconds(2))
      {
        print_progress(k, run_count, false, &from_last_msg);

        stop = term::user_stop();
      }

      // --------- SELECTION ---------
      auto parents(es_.selection.run());

      // --------- CROSSOVER / MUTATION ---------
      auto off(es_.recombination.run(parents));

      // --------- REPLACEMENT --------
      const auto before(stats_.best.score.fitness);
      es_.replacement.run(parents, off, &stats_);

      if (stats_.best.score.fitness != before)
        print_progress(k, run_count, true, &from_last_msg);
    }

    stats_.elapsed = measure.elapsed();

    es_.post_bookkeeping();  // hook for strategy-specific final bookkeeping
  }

  print.info("Elapsed time: ",
             std::chrono::duration<double>(stats_.elapsed).count(),
             "s", std::string(10, ' '));

  term::reset();
  return stats_;
}

///
/// \brief A shortcut to call the `run` method without a shake function.
///
template<class T, template<class> class ES>
const summary<T> &evolution<T, ES>::run(unsigned run_count)
{
  return run(run_count, [](unsigned) { return false; });
}

///
/// \param[in] verbose if `true` prints error messages to `std::cerr`.
/// \return true if object passes the internal consistency check.
///
template<class T, template<class> class ES>
bool evolution<T, ES>::debug() const
{
  return pop_.debug();
}
#endif  // Include guard
<commit_msg>[DOC][FIX] Doxygen warnings<commit_after>/**
 *  \file
 *  \remark This file is part of VITA.
 *
 *  \copyright Copyright (C) 2013-2016 EOS di Manlio Morini.
 *
 *  \license
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this file,
 *  You can obtain one at http://mozilla.org/MPL/2.0/
 */

#if !defined(VITA_EVOLUTION_H)
#  error "Don't include this file directly, include the specific .h instead"
#endif

#if !defined(VITA_EVOLUTION_TCC)
#define      VITA_EVOLUTION_TCC

namespace term
{
///
/// \return `true` when the user press the '.' key.
///
inline bool user_stop()
{
  const bool stop(kbhit() && std::cin.get() == '.');

  if (stop)
    print.info("Stopping evolution...");

  return stop;
}

///
/// Resets the term and restores the default signal handlers.
///
inline void reset()
{
  std::signal(SIGABRT, SIG_DFL);
  std::signal(SIGINT, SIG_DFL);
  std::signal(SIGTERM, SIG_DFL);

  term_raw_mode(false);
}

///
/// If the program receives a SIGABRT / SIGINT / SIGTERM, it must handle
/// the signal and reset the terminal to the initial state.
///
inline void signal_handler(int signum)
{
  term::reset();

  std::raise(signum);
}

///
/// Sets the term in raw mode and handles the interrupt signals.
///
inline void set()
{
  // Install our signal handler.
  std::signal(SIGABRT, term::signal_handler);
  std::signal(SIGINT, term::signal_handler);
  std::signal(SIGTERM, term::signal_handler);

  term_raw_mode(true);
}
}  // namespace term

///
/// \param[in] e environment (mostly used for population initialization).
/// \param[in] eva evaluator used during the evolution.
///
template<class T, template<class> class ES>
evolution<T, ES>::evolution(const environment &e, evaluator<T> &eva)
  : pop_(e), eva_(eva), es_(pop_, eva, &stats_)
{
  Expects(e.sset);
  Ensures(debug());
}

///
/// \param[in] s an up to date evolution summary.
/// \return `true` when evolution should be interrupted.
///
template<class T, template<class> class ES>
bool evolution<T, ES>::stop_condition(const summary<T> &s) const
{
  Expects(env().generations);

  // Check the number of generations.
  if (s.gen > env().generations)
    return true;

  if (term::user_stop())
    return true;

  // Check strategy specific stop conditions.
  return es_.stop_condition();
}

///
/// \return statistical informations about the elements of the population.
///
template<class T, template<class> class ES>
analyzer<T> evolution<T, ES>::get_stats() const
{
  analyzer<T> az;

  for (auto it(pop_.begin()), end(pop_.end()); it != end; ++it)
    az.add(*it, eva_(*it), it.layer());

  return az;
}

///
/// \param[in] run_count run number.
///
/// Saves working / statistical informations in a log file.
/// Data are written in a CSV-like fashion and are partitioned in blocks
/// separated by two blank lines:
/// [BLOCK_1]\n\n
/// [BLOCK_2]\n\n
/// ...
/// [BLOCK_x]
/// where each block is a set of line like this:
///   data_1 [space] data_2 [space] ... [space] data_n
/// We use this format, instead of XML, because statistics are produced
/// incrementally and so it's simple and fast to append new data to a
/// CSV-like file. Note also that data sets are ready to be plotted by
/// GNUPlot.
///
template<class T, template<class> class ES>
void evolution<T, ES>::log(unsigned run_count) const
{
  static unsigned last_run(0);

  auto fullpath = [this](const std::string &f)
                  {
                    return env().stat.dir + "/" + f;
                  };

  if (env().stat.dynamic)
  {
    std::ofstream f_dyn(fullpath(env().stat.dyn_name), std::ios_base::app);
    if (f_dyn.good())
    {
      if (last_run != run_count)
        f_dyn << "\n\n";

      f_dyn << run_count << ' ' << stats_.gen;

      if (stats_.best.solution.empty())
        f_dyn << " ?";
      else
        f_dyn << ' ' << stats_.best.score.fitness[0];

      f_dyn << ' ' << stats_.az.fit_dist().mean()[0]
            << ' ' << stats_.az.fit_dist().standard_deviation()[0]
            << ' ' << stats_.az.fit_dist().entropy()
            << ' ' << stats_.az.fit_dist().min()[0]
            << ' ' << static_cast<unsigned>(stats_.az.length_dist().mean())
            << ' ' << stats_.az.length_dist().standard_deviation()
            << ' ' << static_cast<unsigned>(stats_.az.length_dist().max())
            << ' ' << stats_.mutations
            << ' ' << stats_.crossovers
            << ' ' << stats_.az.functions(0)
            << ' ' << stats_.az.terminals(0)
            << ' ' << stats_.az.functions(1)
            << ' ' << stats_.az.terminals(1);

      for (unsigned active(0); active <= 1; ++active)
        for (const auto &symb_stat : stats_.az)
          f_dyn << ' ' << (symb_stat.first)->display()
                << ' ' << symb_stat.second.counter[active];

      f_dyn << " \"";
      if (!stats_.best.solution.empty())
        stats_.best.solution.in_line(f_dyn);
      f_dyn << "\"\n";
    }
  }

  if (env().stat.population)
  {
    std::ofstream f_pop(fullpath(env().stat.pop_name), std::ios_base::app);
    if (f_pop.good())
    {
      if (last_run != run_count)
        f_pop << "\n\n";

      for (const auto &f : stats_.az.fit_dist().seen())
        // f.first: value, f.second: frequency
        f_pop << run_count << ' ' << stats_.gen << ' '
              << std::fixed << std::scientific
              << std::setprecision(
                   std::numeric_limits<fitness_t::value_type>::digits10 + 2)
              << f.first[0] << ' ' << f.second << '\n';
    }
  }

  es_.log(last_run, run_count);

  if (last_run != run_count)
    last_run = run_count;
}

///
/// \param[in] k current generation.
/// \param[in] run_count total number of runs planned.
/// \param[in] status if `true` print a run/generation/fitness status line.
/// \param[in] from_last_msg time elapsed from the last message.
///
/// Print evolution informations (if `environment::log_level >= OUTPUT`).
///
template<class T, template<class> class ES>
void evolution<T, ES>::print_progress(unsigned k, unsigned run_count,
                                      bool status, timer *from_last_msg) const
{
  if (print.verbosity() >= log::L_OUTPUT)
  {
    const unsigned perc(100 * k / pop_.individuals());
    if (status)
      std::cout << "Run " << run_count << '.' << std::setw(6)
                << stats_.gen << " (" << std::setw(3)
                << perc << "%): fitness " << stats_.best.score.fitness
                << '\n';
    else
      std::cout << "Crunching " << run_count << '.' << stats_.gen << " ("
                << std::setw(3) << perc << "%)\r";

    std::cout << std::flush;

    from_last_msg->restart();
  }
}

///
/// \param[in] run_count run number (used for printing and logging).
/// \param[in] shake the "shake data" function. It's used to alter the training
///                  set so that evolution would take place in a dynamic
///                  environment.
/// \return a partial summary of the search (see notes).
///
/// The genetic programming loop:
///
/// * select the individual(s) to participate (default algorithm: tournament
///   selection) in the genetic operation;
/// * perform genetic operation creating a new offspring individual;
/// * place the offspring into the original population (steady state)
///   replacing a bad individual.
///
/// This whole process repeats until the termination criteria is satisfied.
/// With any luck, it will produce an individual that solves the problem at
/// hand.
///
/// \note
/// The return value is a partial summary: the `measurement` section is only
/// partially filled (fitness) since many metrics are expensive to calculate
/// and not significative for all kind of problems (e.g. f1-score for a
/// symbolic regression problem). The src_search class has a simple scheme to
/// request the computation of additional metrics.
///
template<class T, template<class> class ES>
template<class S>
const summary<T> &evolution<T, ES>::run(unsigned run_count, S shake)
{
  stats_.clear();
  stats_.best.solution = pop_[{0, 0}];
  stats_.best.score.fitness = eva_(stats_.best.solution);

  timer measure;
  timer from_last_msg;

  bool stop(false);
  term::set();

#if defined(CLONE_SCALING)
  eva_.clear(evaluator<T>::stats);
#endif

  es_.pre_bookkeeping();  // hook for strategy-specific preliminary bookkeeping

  for (stats_.gen = 0; !stop_condition(stats_) && !stop;  ++stats_.gen)
  {
    if (shake(stats_.gen))
    {
      // If we 'shake' the data, fitness values and the statistics picked so
      // far have to be cleared (the best individual and its fitness refer to
      // the previous training set).
      eva_.clear(evaluator<T>::all);

      assert(!stats_.best.solution.empty());
      stats_.best.score.fitness = eva_(stats_.best.solution);

      print_progress(0, run_count, true, &from_last_msg);
    }

    stats_.az = get_stats();
    log(run_count);

    for (unsigned k(0); k < pop_.individuals() && !stop; ++k)
    {
      if (from_last_msg.elapsed() > std::chrono::seconds(2))
      {
        print_progress(k, run_count, false, &from_last_msg);

        stop = term::user_stop();
      }

      // --------- SELECTION ---------
      auto parents(es_.selection.run());

      // --------- CROSSOVER / MUTATION ---------
      auto off(es_.recombination.run(parents));

      // --------- REPLACEMENT --------
      const auto before(stats_.best.score.fitness);
      es_.replacement.run(parents, off, &stats_);

      if (stats_.best.score.fitness != before)
        print_progress(k, run_count, true, &from_last_msg);
    }

    stats_.elapsed = measure.elapsed();

    es_.post_bookkeeping();  // hook for strategy-specific final bookkeeping
  }

  print.info("Elapsed time: ",
             std::chrono::duration<double>(stats_.elapsed).count(),
             "s", std::string(10, ' '));

  term::reset();
  return stats_;
}

///
/// \brief A shortcut to call the `run` method without a shake function.
///
template<class T, template<class> class ES>
const summary<T> &evolution<T, ES>::run(unsigned run_count)
{
  return run(run_count, [](unsigned) { return false; });
}

///
/// \return true if object passes the internal consistency check.
///
template<class T, template<class> class ES>
bool evolution<T, ES>::debug() const
{
  return pop_.debug();
}
#endif  // Include guard
<|endoftext|>


<commit_before>/*
 * graphanalysis.cc
 *
 *  Created on: Sep 12, 2014
 *      Author: leeopop
 */

#include <nba/core/bitmap.hh>
#include <nba/framework/graphanalysis.hh>
#include <nba/framework/datablock.hh>
#include <unordered_set>
#include <vector>
#include <unordered_map>
#include <stack>
#include <cassert>
using std::unordered_set;
using std::stack;
using std::vector;
using L::Bitmap;
namespace nba
{

GraphMetaData::GraphMetaData()
{
	this->linear_group = -1;
}

GraphMetaData::~GraphMetaData()
{

}

void GraphMetaData::link(GraphMetaData* child)
{
	this->outEdge.insert(child);
	child->inEdge.insert(this);
}

int GraphMetaData::getLinearGroup()
{
	return linear_group;
}

void GraphAnalysis::analyze(ParseInfo* info)
{
	unordered_set<GraphMetaData*> visited;
	int linear_group_id = 0;
	int total_modules = click_num_module(info);
	int total_roots = click_num_root(info);
	vector<vector<GraphMetaData*> > linear_group_set;

	for(int root_id = 0; root_id < total_roots; root_id++)
	{
		//for all root elements
		GraphMetaData * root = (GraphMetaData*)click_get_root(info, root_id);
		stack<GraphMetaData*> dfsStack;
		dfsStack.push(root);

		while(!dfsStack.empty())
		{
			GraphMetaData * current = dfsStack.top();
			dfsStack.pop();
			visited.insert(current);

			for(GraphMetaData* child : current->outEdge)
			{
				if(visited.find(child) == visited.end())
					dfsStack.push(child);
			}

			if(current->inEdge.size() == 1)
			{
				GraphMetaData* parent = 0;
				for(GraphMetaData* temp : current->inEdge)
					parent = temp;
				assert(parent);
				if(parent->outEdge.size() == 1)
					current->linear_group = parent->linear_group;
			}

			if(current->outEdge.size() == 1)
			{
				if(current->linear_group == -1)
				{
					current->linear_group = linear_group_id++;
					linear_group_set.push_back(vector<GraphMetaData*>());
					assert((int)linear_group_set.size() == linear_group_id);
				}
			}
			if(current->linear_group != -1)
				linear_group_set[current->linear_group].push_back(current);
		}
	}

	for(size_t group_id = 0; group_id < linear_group_set.size(); group_id++)
	{
		vector<GraphMetaData*> linear_group = linear_group_set[group_id];
		printf("Traveling linear group_id %lu with size(%lu):\n", group_id, linear_group.size());

		size_t before = 0;
		size_t next = 1;
		Bitmap write_bitmap(2048); //corruption map
		while(next < linear_group.size())
		{
			GraphMetaData* before_data = linear_group[before];
			GraphMetaData* next_data = linear_group[next];

			for(size_t dbIndex=0; dbIndex < before_data->dbIndex.size(); dbIndex++)
			{
				write_bitmap.merge(before_data->dbWriteBitmap[dbIndex]);
				for(size_t dbIndex2=0; dbIndex2 < next_data->dbIndex.size(); dbIndex2++)
				{
					Bitmap read_bitmap = before_data->dbReadBitmap[dbIndex];

					if(!write_bitmap.isCollide(read_bitmap))
					{
						printf("Datablock %s -> %s do not collide.\n", datablock_names[dbIndex], datablock_names[dbIndex2]);
					}
					else
					{
						printf("Datablock %s -> %s collide.\n", datablock_names[dbIndex], datablock_names[dbIndex2]);
						Bitmap collision(2048);
						collision.clear();
						collision.merge(read_bitmap);
						collision.intersect(write_bitmap);
						collision.print();
					}
				}
			}

			before++;
			next++;
		}
	}
}

void GraphMetaData::addROI(int dbIndex, const L::Bitmap& read, const L::Bitmap& write)
{
	this->dbIndex.push_back(dbIndex);
	this->dbReadBitmap.push_back(read);
	this->dbWriteBitmap.push_back(write);
}

}
<commit_msg>Whitespace clean up.<commit_after>/*
 * graphanalysis.cc
 *
 *  Created on: Sep 12, 2014
 *      Author: leeopop
 */

#include <nba/core/bitmap.hh>
#include <nba/framework/graphanalysis.hh>
#include <nba/framework/datablock.hh>
#include <unordered_set>
#include <vector>
#include <unordered_map>
#include <stack>
#include <cassert>
using std::unordered_set;
using std::stack;
using std::vector;
using L::Bitmap;
namespace nba
{

GraphMetaData::GraphMetaData()
{
    this->linear_group = -1;
}

GraphMetaData::~GraphMetaData()
{

}

void GraphMetaData::link(GraphMetaData* child)
{
    this->outEdge.insert(child);
    child->inEdge.insert(this);
}

int GraphMetaData::getLinearGroup()
{
    return linear_group;
}

void GraphAnalysis::analyze(ParseInfo* info)
{
    unordered_set<GraphMetaData*> visited;
    int linear_group_id = 0;
    int total_modules = click_num_module(info);
    int total_roots = click_num_root(info);
    vector<vector<GraphMetaData*> > linear_group_set;

    for (int root_id = 0; root_id < total_roots; root_id++)
    {
        //for all root elements
        GraphMetaData * root = (GraphMetaData*)click_get_root(info, root_id);
        stack<GraphMetaData*> dfsStack;
        dfsStack.push(root);

        while (!dfsStack.empty())
        {
            GraphMetaData * current = dfsStack.top();
            dfsStack.pop();
            visited.insert(current);

            for (GraphMetaData* child : current->outEdge)
            {
                if (visited.find(child) == visited.end())
                    dfsStack.push(child);
            }

            if (current->inEdge.size() == 1)
            {
                GraphMetaData* parent = 0;
                for (GraphMetaData* temp : current->inEdge)
                    parent = temp;
                assert(parent);
                if (parent->outEdge.size() == 1)
                    current->linear_group = parent->linear_group;
            }

            if (current->outEdge.size() == 1)
            {
                if (current->linear_group == -1)
                {
                    current->linear_group = linear_group_id++;
                    linear_group_set.push_back(vector<GraphMetaData*>());
                    assert((int)linear_group_set.size() == linear_group_id);
                }
            }
            if (current->linear_group != -1)
                linear_group_set[current->linear_group].push_back(current);
        }
    }

    for (size_t group_id = 0; group_id < linear_group_set.size(); group_id++)
    {
        vector<GraphMetaData*> linear_group = linear_group_set[group_id];
        printf("Traveling linear group_id %lu with size(%lu):\n", group_id, linear_group.size());

        size_t before = 0;
        size_t next = 1;
        Bitmap write_bitmap(2048); //corruption map
        while (next < linear_group.size())
        {
            GraphMetaData* before_data = linear_group[before];
            GraphMetaData* next_data = linear_group[next];

            for (size_t dbIndex = 0; dbIndex < before_data->dbIndex.size(); dbIndex++)
            {
                write_bitmap.merge(before_data->dbWriteBitmap[dbIndex]);
                for (size_t dbIndex2 = 0; dbIndex2 < next_data->dbIndex.size(); dbIndex2++)
                {
                    Bitmap read_bitmap = before_data->dbReadBitmap[dbIndex];

                    if (!write_bitmap.isCollide(read_bitmap))
                    {
                        printf("Datablock %s -> %s do not collide.\n", datablock_names[dbIndex], datablock_names[dbIndex2]);
                    }
                    else
                    {
                        printf("Datablock %s -> %s collide.\n", datablock_names[dbIndex], datablock_names[dbIndex2]);
                        Bitmap collision(2048);
                        collision.clear();
                        collision.merge(read_bitmap);
                        collision.intersect(write_bitmap);
                        collision.print();
                    }
                }
            }

            before++;
            next++;
        }
    }
}

void GraphMetaData::addROI(int dbIndex, const L::Bitmap& read, const L::Bitmap& write)
{
    this->dbIndex.push_back(dbIndex);
    this->dbReadBitmap.push_back(read);
    this->dbWriteBitmap.push_back(write);
}

}

/* vim: set ts=8 sts=4 sw=4 et: */
<|endoftext|>