<commit_before>// Copyright 2016 Alex Silva Torres
//
// 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 "lexer.h"

#include <sstream>
#include <codecvt>

namespace shpp {
namespace internal {

void Lexer::SkipSingleLineComment() {
  Advance();
  while (c_ != kEndOfInput && c_ != '\n'){
    Advance();
  }

  Advance();
}

void Lexer::ErrorMsg(const boost::format& fmt_msg) {
  Message msg(Message::Severity::ERR, fmt_msg, line_, line_pos_);
  msgs_.Push(std::move(msg));
  nerror_++;
}

char Lexer::ScanAnsiEscapeCode() {
  std::string number = "";
  while (IsOctalChar(c_)) {
    number += c_;
    Advance();
  }

  Back();

  return static_cast<char>(std::stoi(number,nullptr,8));
}

std::string Lexer::ScanUnicodeEscapeCode() {
  Advance();

  std::string number = "";
  while (IsHexChar(c_)) {
    number += c_;
    Advance();
  }

  Back();

  uint32_t hex_number = static_cast<uint32_t>(std::stoi(number,nullptr,16));

  // initialize wstring with 1 wchar_t
  std::wstring str_hex(1, static_cast<wchar_t>(hex_number));

  //setup converter from wstring to string
  using convert_type = std::codecvt_utf8<wchar_t>;
  std::wstring_convert<convert_type, wchar_t> converter;

  return converter.to_bytes(str_hex);
}

std::string Lexer::ScanStringEscape() {
  Advance();

  char c = c_;

  // Handle special char on string
  switch (c) {
    case '\'':  // fall through
    case '"' :  // fall through
    case '\\': break;

    case '0' :
      if (IsOctalChar(PeekAhead())) {
        c = ScanAnsiEscapeCode();
      } else {
        c = '\0';
      }
      break;

    case 'u':
      if (IsHexChar(PeekAhead())) {
        return ScanUnicodeEscapeCode();
      } else {
        return "\\u";
      }
      break;

    case 'b' : c = '\b'; break;
    case 'f' : c = '\f'; break;
    case 'n' : c = '\n'; break;
    case 'r' : c = '\r'; break;
    case 't' : c = '\t'; break;
  }

  // construct a string with 1 char c
  return std::string(1, c);
}

char Lexer::ScanWordEscape() {
  start_pos_ = line_pos_;
  Advance();

  char c = c_;

  switch (c) {
    case ' ' : c = ' '; break;
    case 'b' : c = '\b'; break;
    case 'f' : c = '\f'; break;
    case 'n' : c = '\n'; break;
    case 'r' : c = '\r'; break;
    case 't' : c = '\t'; break;
  }

  return c;
}

Token Lexer::ScanString() {
  std::string str = "";
  start_pos_ = line_pos_;

  Advance();

  while(true) {
    if (c_ == kEndOfInput) {
      ErrorMsg(boost::format("string literal not terminated"));
      break;
    }

    if (c_ == '"') {
      Advance();
      break;
    }

    if (c_ == '\\') {
       str += ScanStringEscape();
       Advance();
       continue;
    }

    str += c_;
    Advance();
  }

  // Check blank char after string
  char check_blank = c_;
  return GetToken(TokenKind::STRING_LITERAL, str, check_blank);
}

Token Lexer::ScanIdentifier() {
  std::string id = "";
  start_pos_ = line_pos_;

  if (IsIdentifierStart(c_)) {
    id += c_;
    Advance();

    while (IsLetter(c_) || c_ == '_' || IsDigit(c_)) {
      id += c_;
      Advance();
    }

    TokenKind token_kind;
    bool res;
    std::tie(token_kind, res) = Token::IsKeyWord(id);

    // Check blank char after identifier
    char check_blank = c_;

    if (res) {
      return GetToken(token_kind, check_blank);
    } else {
      return GetToken(TokenKind::IDENTIFIER, id, check_blank);
    }
  }

  return GetToken(TokenKind::UNKNOWN);
}

Token Lexer::ScanNumber() {
  std::string str_num = "";
  size_t point_num = 0;
  start_pos_ = line_pos_;

  if (IsDigit(c_)) {
    str_num += c_;
    Advance();
    while (IsDigit(c_) || c_ == '.') {
      if (c_ == '.') {
        point_num++;

        if (point_num > 1) {
          return ScanWord(str_num);
        }
      }

      str_num += c_;
      Advance();
    }
  }

  // Check blank char after number
  char check_blank = c_;

  if (point_num == 0) {
    int v;
    std::istringstream ss(str_num);
    ss >> v;
    return GetToken(TokenKind::INT_LITERAL, v, check_blank);
  } else {
    float v;
    std::istringstream ss(str_num);
    ss >> v;
    return GetToken(TokenKind::REAL_LITERAL, v, check_blank);
  }
}

Token Lexer::ScanWord(const std::string& prestr) {
  std::string word = prestr;
  start_pos_ = line_pos_;

  while (IsSpecialChar(c_)) {
    if (c_ == '\\') {
      word += ScanWordEscape();
      Advance();
      continue;
    }

    word += c_;
    Advance();
  }

  // Check blank char after word
  char check_blank = c_;
  return GetToken(TokenKind::WORD, word, check_blank);
}

TokenStream Lexer::Scanner() {
  TokenStream ts;
  char check_blank = c_;

  while (true) {
    start_pos_ = line_pos_;
    bool whitespace = false;
    Token&& token = GetToken(TokenKind::UNKNOWN);
    switch (c_) {
      case '#':
        SkipSingleLineComment();
        whitespace = true;
        break;

      case ' ':
      case '\t':
        Advance();
        whitespace = true;
        break;

      case '\n':
        token = Select(TokenKind::NWL);
        break;

      case '"':
        token = ScanString();
        break;

      case '<':
        // < <= <& << <<= <<<
        Advance();
        check_blank = c_;
        if (c_ == '=') {
          token = Select(TokenKind::LESS_EQ);
        } else if (c_ == '&') {
          token = Select(TokenKind::LESS_AND);
        } else if (c_ == '<') {
          Advance();
          if (c_ == '=') {
            token = Select(TokenKind::ASSIGN_SHL);
          } else if (c_ == '<') {
            token = Select(TokenKind::SSHL);
          } else {
            token = GetToken(TokenKind::SHL);
          }
        } else {
          token = GetToken(TokenKind::LESS_THAN, check_blank);
        }
        break;

      case '>':
        // > >= >& >> >>= >>>
        Advance();
        check_blank = c_;
        if (c_ == '=') {
          token = Select(TokenKind::GREATER_EQ);
        } else if (c_ == '&') {
          token = Select(TokenKind::GREAT_AND);
        } else if (c_ == '>') {
          Advance();
          if (c_ == '=') {
            token = Select(TokenKind::ASSIGN_SAR);
          } else if (c_ == '>') {
            token = Select(TokenKind::SSAR);
          } else {
            token = GetToken(TokenKind::SAR);
          }
        } else {
          token = GetToken(TokenKind::GREATER_THAN, check_blank);
        }
        break;

      case '=':
        // = ==
        Advance();
        if (c_ == '=') {
          token = Select(TokenKind::EQUAL);
        } else {
          token = GetToken(TokenKind::ASSIGN);
        }
        break;

      case '!':
        // ! !=
        Advance();
        if (c_ == '=') {
          token = Select(TokenKind::NOT_EQUAL);
        } else {
          token = GetToken(TokenKind::EXCL_NOT);
        }
        break;

      case '+':
        // + +=
        Advance();
        if (c_ == '=') {
          token = Select(TokenKind::ASSIGN_ADD);
        } else {
          token = GetToken(TokenKind::ADD);
        }
        break;

      case '-':
        // - -= ->
        Advance();
        if (c_ == '=') {
          token = Select(TokenKind::ASSIGN_SUB);
        } else if (c_ == '>') {
          token = Select(TokenKind::ARROW);
        } else {
          token = GetToken(TokenKind::SUB);
        }
        break;

      case '*':
        // * *=
        Advance();
        if (c_ == '=') {
          token = Select(TokenKind::ASSIGN_MUL);
        } else {
          token = GetToken(TokenKind::MUL);
        }
        break;

      case '/':
        // / /=
        Advance();
        if (c_ == '=') {
          token = Select(TokenKind::ASSIGN_DIV);
        } else {
          token = GetToken(TokenKind::DIV);
        }
        break;

      case '%':
        // % %=
        Advance();
        if (c_ == '=') {
          token = Select(TokenKind::ASSIGN_MOD);
        } else if (c_ == '%') {
          token = Select(TokenKind::RGLOB);
        } else {
          token = GetToken(TokenKind::MOD);
        }
        break;

      case '&':
        // & &= &&
        Advance();
        if (c_ == '=') {
          token = Select(TokenKind::ASSIGN_BIT_AND);
        } else if (c_ == '&') {
          token = Select(TokenKind::AND);
        } else {
          token = GetToken(TokenKind::BIT_AND);
        }
        break;

      case '|':
        // | |= ||
        Advance();
        if (c_ == '=') {
          token = Select(TokenKind::ASSIGN_BIT_OR);
        } else if (c_ == '|') {
          token = Select(TokenKind::OR);
        } else {
          token = GetToken(TokenKind::BIT_OR);
        }
        break;

      case '^':
        // ^ ^=
        Advance();
        if (c_ == '=') {
          token = Select(TokenKind::ASSIGN_BIT_XOR);
        } else {
          token = GetToken(TokenKind::BIT_XOR);
        }
        break;

      case '~':
        token = Select(TokenKind::BIT_NOT);
        break;

      case ';':
        token = Select(TokenKind::SEMI_COLON);
        break;

      case ':':
        // : ::
        Advance();
        if (c_ == ':') {
          token = Select(TokenKind::SCOPE);
        } else {
          token = GetToken(TokenKind::COLON);
        }
        break;

      case ',':
        token = Select(TokenKind::COMMA);
        break;

      case '$': {
        // $ $( ${
        Advance();
        std::string  pre_word = "$";
        if (c_ == '(') {
          token = Select(TokenKind::DOLLAR_LPAREN);
        } else if (c_ == '{') {
          token = Select(TokenKind::DOLLAR_LBRACE);
        } else if (c_ == '@') {
          pre_word += "@";
          Advance();
          if (c_ == '{') {
            token = Select(TokenKind::DOLLAR_AT_LBRACE);
          } else {
            token = ScanWord(pre_word);
          }
        } else {
          token = GetToken(TokenKind::DOLLAR);
        }
      } break;

      case '(':
        token = Select(TokenKind::LPAREN);
        break;

      case ')':
        token = Select(TokenKind::RPAREN);
        break;

      case '{':
        token = Select(TokenKind::LBRACE);
        break;

      case '}':
        token = Select(TokenKind::RBRACE);
        break;

      case '[':
        token = Select(TokenKind::LBRACKET);
        break;

      case ']':
        token = Select(TokenKind::RBRACKET);
        break;

      case '.': {
        // . ...
        std::string  pre_word = ".";
        Advance();
        if (c_ == '.') {
          pre_word += '.';
          Advance();
          if (c_ == '.') {
            token = Select(TokenKind::ELLIPSIS);
          } else {
            token = ScanWord(pre_word);
          }
        } else {
          token = GetToken(TokenKind::DOT);
        }
      } break;

      case '@':
        token = Select(TokenKind::AT_SIGN);
        break;

      default:
        if (c_ == kEndOfInput) {
          // End of the file, break the loop
          token = Select(TokenKind::EOS);
          ts.PushToken(std::move(token));
          return ts;
        } else if (IsIdentifierStart(c_)) {
          token = ScanIdentifier();
        } else if (IsDigit(c_)) {
          token = ScanNumber();
        } else if (c_ == '\\') {
          // Allows insert newline without insert a token
          if (PeekAhead() == '\n'){
            // advance char '\'
            Advance();
            // advace char '\n'
            Advance();
            whitespace = true;
          } else {
            std::string c;
            c = ScanWordEscape();
            token = Select(TokenKind::WORD, c);
          }
        } else {
          token = ScanWord();
        }
    }

    if (!whitespace) {
      ts.PushToken(std::move(token));
    }
  }

  return ts;
}

}
}
<commit_msg>fix comment lexer<commit_after>// Copyright 2016 Alex Silva Torres
//
// 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 "lexer.h"

#include <sstream>
#include <codecvt>

namespace shpp {
namespace internal {

void Lexer::SkipSingleLineComment() {
  Advance();
  while (c_ != kEndOfInput && c_ != '\n'){
    Advance();
  }
}

void Lexer::ErrorMsg(const boost::format& fmt_msg) {
  Message msg(Message::Severity::ERR, fmt_msg, line_, line_pos_);
  msgs_.Push(std::move(msg));
  nerror_++;
}

char Lexer::ScanAnsiEscapeCode() {
  std::string number = "";
  while (IsOctalChar(c_)) {
    number += c_;
    Advance();
  }

  Back();

  return static_cast<char>(std::stoi(number,nullptr,8));
}

std::string Lexer::ScanUnicodeEscapeCode() {
  Advance();

  std::string number = "";
  while (IsHexChar(c_)) {
    number += c_;
    Advance();
  }

  Back();

  uint32_t hex_number = static_cast<uint32_t>(std::stoi(number,nullptr,16));

  // initialize wstring with 1 wchar_t
  std::wstring str_hex(1, static_cast<wchar_t>(hex_number));

  //setup converter from wstring to string
  using convert_type = std::codecvt_utf8<wchar_t>;
  std::wstring_convert<convert_type, wchar_t> converter;

  return converter.to_bytes(str_hex);
}

std::string Lexer::ScanStringEscape() {
  Advance();

  char c = c_;

  // Handle special char on string
  switch (c) {
    case '\'':  // fall through
    case '"' :  // fall through
    case '\\': break;

    case '0' :
      if (IsOctalChar(PeekAhead())) {
        c = ScanAnsiEscapeCode();
      } else {
        c = '\0';
      }
      break;

    case 'u':
      if (IsHexChar(PeekAhead())) {
        return ScanUnicodeEscapeCode();
      } else {
        return "\\u";
      }
      break;

    case 'b' : c = '\b'; break;
    case 'f' : c = '\f'; break;
    case 'n' : c = '\n'; break;
    case 'r' : c = '\r'; break;
    case 't' : c = '\t'; break;
  }

  // construct a string with 1 char c
  return std::string(1, c);
}

char Lexer::ScanWordEscape() {
  start_pos_ = line_pos_;
  Advance();

  char c = c_;

  switch (c) {
    case ' ' : c = ' '; break;
    case 'b' : c = '\b'; break;
    case 'f' : c = '\f'; break;
    case 'n' : c = '\n'; break;
    case 'r' : c = '\r'; break;
    case 't' : c = '\t'; break;
  }

  return c;
}

Token Lexer::ScanString() {
  std::string str = "";
  start_pos_ = line_pos_;

  Advance();

  while(true) {
    if (c_ == kEndOfInput) {
      ErrorMsg(boost::format("string literal not terminated"));
      break;
    }

    if (c_ == '"') {
      Advance();
      break;
    }

    if (c_ == '\\') {
       str += ScanStringEscape();
       Advance();
       continue;
    }

    str += c_;
    Advance();
  }

  // Check blank char after string
  char check_blank = c_;
  return GetToken(TokenKind::STRING_LITERAL, str, check_blank);
}

Token Lexer::ScanIdentifier() {
  std::string id = "";
  start_pos_ = line_pos_;

  if (IsIdentifierStart(c_)) {
    id += c_;
    Advance();

    while (IsLetter(c_) || c_ == '_' || IsDigit(c_)) {
      id += c_;
      Advance();
    }

    TokenKind token_kind;
    bool res;
    std::tie(token_kind, res) = Token::IsKeyWord(id);

    // Check blank char after identifier
    char check_blank = c_;

    if (res) {
      return GetToken(token_kind, check_blank);
    } else {
      return GetToken(TokenKind::IDENTIFIER, id, check_blank);
    }
  }

  return GetToken(TokenKind::UNKNOWN);
}

Token Lexer::ScanNumber() {
  std::string str_num = "";
  size_t point_num = 0;
  start_pos_ = line_pos_;

  if (IsDigit(c_)) {
    str_num += c_;
    Advance();
    while (IsDigit(c_) || c_ == '.') {
      if (c_ == '.') {
        point_num++;

        if (point_num > 1) {
          return ScanWord(str_num);
        }
      }

      str_num += c_;
      Advance();
    }
  }

  // Check blank char after number
  char check_blank = c_;

  if (point_num == 0) {
    int v;
    std::istringstream ss(str_num);
    ss >> v;
    return GetToken(TokenKind::INT_LITERAL, v, check_blank);
  } else {
    float v;
    std::istringstream ss(str_num);
    ss >> v;
    return GetToken(TokenKind::REAL_LITERAL, v, check_blank);
  }
}

Token Lexer::ScanWord(const std::string& prestr) {
  std::string word = prestr;
  start_pos_ = line_pos_;

  while (IsSpecialChar(c_)) {
    if (c_ == '\\') {
      word += ScanWordEscape();
      Advance();
      continue;
    }

    word += c_;
    Advance();
  }

  // Check blank char after word
  char check_blank = c_;
  return GetToken(TokenKind::WORD, word, check_blank);
}

TokenStream Lexer::Scanner() {
  TokenStream ts;
  char check_blank = c_;

  while (true) {
    start_pos_ = line_pos_;
    bool whitespace = false;
    Token&& token = GetToken(TokenKind::UNKNOWN);
    switch (c_) {
      case '#':
        SkipSingleLineComment();
        whitespace = true;
        break;

      case ' ':
      case '\t':
        Advance();
        whitespace = true;
        break;

      case '\n':
        token = Select(TokenKind::NWL);
        break;

      case '"':
        token = ScanString();
        break;

      case '<':
        // < <= <& << <<= <<<
        Advance();
        check_blank = c_;
        if (c_ == '=') {
          token = Select(TokenKind::LESS_EQ);
        } else if (c_ == '&') {
          token = Select(TokenKind::LESS_AND);
        } else if (c_ == '<') {
          Advance();
          if (c_ == '=') {
            token = Select(TokenKind::ASSIGN_SHL);
          } else if (c_ == '<') {
            token = Select(TokenKind::SSHL);
          } else {
            token = GetToken(TokenKind::SHL);
          }
        } else {
          token = GetToken(TokenKind::LESS_THAN, check_blank);
        }
        break;

      case '>':
        // > >= >& >> >>= >>>
        Advance();
        check_blank = c_;
        if (c_ == '=') {
          token = Select(TokenKind::GREATER_EQ);
        } else if (c_ == '&') {
          token = Select(TokenKind::GREAT_AND);
        } else if (c_ == '>') {
          Advance();
          if (c_ == '=') {
            token = Select(TokenKind::ASSIGN_SAR);
          } else if (c_ == '>') {
            token = Select(TokenKind::SSAR);
          } else {
            token = GetToken(TokenKind::SAR);
          }
        } else {
          token = GetToken(TokenKind::GREATER_THAN, check_blank);
        }
        break;

      case '=':
        // = ==
        Advance();
        if (c_ == '=') {
          token = Select(TokenKind::EQUAL);
        } else {
          token = GetToken(TokenKind::ASSIGN);
        }
        break;

      case '!':
        // ! !=
        Advance();
        if (c_ == '=') {
          token = Select(TokenKind::NOT_EQUAL);
        } else {
          token = GetToken(TokenKind::EXCL_NOT);
        }
        break;

      case '+':
        // + +=
        Advance();
        if (c_ == '=') {
          token = Select(TokenKind::ASSIGN_ADD);
        } else {
          token = GetToken(TokenKind::ADD);
        }
        break;

      case '-':
        // - -= ->
        Advance();
        if (c_ == '=') {
          token = Select(TokenKind::ASSIGN_SUB);
        } else if (c_ == '>') {
          token = Select(TokenKind::ARROW);
        } else {
          token = GetToken(TokenKind::SUB);
        }
        break;

      case '*':
        // * *=
        Advance();
        if (c_ == '=') {
          token = Select(TokenKind::ASSIGN_MUL);
        } else {
          token = GetToken(TokenKind::MUL);
        }
        break;

      case '/':
        // / /=
        Advance();
        if (c_ == '=') {
          token = Select(TokenKind::ASSIGN_DIV);
        } else {
          token = GetToken(TokenKind::DIV);
        }
        break;

      case '%':
        // % %=
        Advance();
        if (c_ == '=') {
          token = Select(TokenKind::ASSIGN_MOD);
        } else if (c_ == '%') {
          token = Select(TokenKind::RGLOB);
        } else {
          token = GetToken(TokenKind::MOD);
        }
        break;

      case '&':
        // & &= &&
        Advance();
        if (c_ == '=') {
          token = Select(TokenKind::ASSIGN_BIT_AND);
        } else if (c_ == '&') {
          token = Select(TokenKind::AND);
        } else {
          token = GetToken(TokenKind::BIT_AND);
        }
        break;

      case '|':
        // | |= ||
        Advance();
        if (c_ == '=') {
          token = Select(TokenKind::ASSIGN_BIT_OR);
        } else if (c_ == '|') {
          token = Select(TokenKind::OR);
        } else {
          token = GetToken(TokenKind::BIT_OR);
        }
        break;

      case '^':
        // ^ ^=
        Advance();
        if (c_ == '=') {
          token = Select(TokenKind::ASSIGN_BIT_XOR);
        } else {
          token = GetToken(TokenKind::BIT_XOR);
        }
        break;

      case '~':
        token = Select(TokenKind::BIT_NOT);
        break;

      case ';':
        token = Select(TokenKind::SEMI_COLON);
        break;

      case ':':
        // : ::
        Advance();
        if (c_ == ':') {
          token = Select(TokenKind::SCOPE);
        } else {
          token = GetToken(TokenKind::COLON);
        }
        break;

      case ',':
        token = Select(TokenKind::COMMA);
        break;

      case '$': {
        // $ $( ${
        Advance();
        std::string  pre_word = "$";
        if (c_ == '(') {
          token = Select(TokenKind::DOLLAR_LPAREN);
        } else if (c_ == '{') {
          token = Select(TokenKind::DOLLAR_LBRACE);
        } else if (c_ == '@') {
          pre_word += "@";
          Advance();
          if (c_ == '{') {
            token = Select(TokenKind::DOLLAR_AT_LBRACE);
          } else {
            token = ScanWord(pre_word);
          }
        } else {
          token = GetToken(TokenKind::DOLLAR);
        }
      } break;

      case '(':
        token = Select(TokenKind::LPAREN);
        break;

      case ')':
        token = Select(TokenKind::RPAREN);
        break;

      case '{':
        token = Select(TokenKind::LBRACE);
        break;

      case '}':
        token = Select(TokenKind::RBRACE);
        break;

      case '[':
        token = Select(TokenKind::LBRACKET);
        break;

      case ']':
        token = Select(TokenKind::RBRACKET);
        break;

      case '.': {
        // . ...
        std::string  pre_word = ".";
        Advance();
        if (c_ == '.') {
          pre_word += '.';
          Advance();
          if (c_ == '.') {
            token = Select(TokenKind::ELLIPSIS);
          } else {
            token = ScanWord(pre_word);
          }
        } else {
          token = GetToken(TokenKind::DOT);
        }
      } break;

      case '@':
        token = Select(TokenKind::AT_SIGN);
        break;

      default:
        if (c_ == kEndOfInput) {
          // End of the file, break the loop
          token = Select(TokenKind::EOS);
          ts.PushToken(std::move(token));
          return ts;
        } else if (IsIdentifierStart(c_)) {
          token = ScanIdentifier();
        } else if (IsDigit(c_)) {
          token = ScanNumber();
        } else if (c_ == '\\') {
          // Allows insert newline without insert a token
          if (PeekAhead() == '\n'){
            // advance char '\'
            Advance();
            // advace char '\n'
            Advance();
            whitespace = true;
          } else {
            std::string c;
            c = ScanWordEscape();
            token = Select(TokenKind::WORD, c);
          }
        } else {
          token = ScanWord();
        }
    }

    if (!whitespace) {
      ts.PushToken(std::move(token));
    }
  }

  return ts;
}

}
}
<|endoftext|>


<commit_before>/*
 * Copyright 2015 WebAssembly Community Group participants
 *
 * 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 <chrono>

#include <pass.h>

namespace wasm {

// PassRegistry

PassRegistry* PassRegistry::get() {
  static PassRegistry* manager = nullptr;
  if (!manager) {
    manager = new PassRegistry();
  }
  return manager;
}

void PassRegistry::registerPass(const char* name, const char *description, Creator create) {
  assert(passInfos.find(name) == passInfos.end());
  passInfos[name] = PassInfo(description, create);
}

Pass* PassRegistry::createPass(std::string name) {
  if (passInfos.find(name) == passInfos.end()) return nullptr;
  auto ret = passInfos[name].create();
  ret->name = name;
  return ret;
}

std::vector<std::string> PassRegistry::getRegisteredNames() {
  std::vector<std::string> ret;
  for (auto pair : passInfos) {
    ret.push_back(pair.first);
  }
  return ret;
}

std::string PassRegistry::getPassDescription(std::string name) {
  assert(passInfos.find(name) != passInfos.end());
  return passInfos[name].description;
}

// PassRunner

void PassRunner::addDefaultOptimizationPasses() {
  add("remove-unused-brs");
  add("remove-unused-names");
  add("optimize-instructions");
  add("simplify-locals");
  add("coalesce-locals");
  add("merge-blocks");
  add("reorder-locals");
  add("vacuum");
  add("optimize-instructions");
}

void PassRunner::run() {
  std::chrono::high_resolution_clock::time_point beforeEverything;
  size_t padding = 0;
  if (debug) {
    std::cerr << "[PassRunner] running passes..." << std::endl;
    beforeEverything = std::chrono::high_resolution_clock::now();
    for (auto pass : passes) {
      padding = std::max(padding, pass->name.size());
    }
  }
  for (auto pass : passes) {
    currPass = pass;
    std::chrono::high_resolution_clock::time_point before;
    if (debug) {
      std::cerr << "[PassRunner]   running pass: " << pass->name << "... ";
      for (size_t i = 0; i < padding - pass->name.size(); i++) {
        std::cerr << ' ';
      }
      before = std::chrono::high_resolution_clock::now();
    }
    pass->run(this, wasm);
    if (debug) {
      auto after = std::chrono::high_resolution_clock::now();
      std::chrono::duration<double> diff = after - before;
      std::cerr << diff.count() << " seconds." << std::endl;
    }
  }
  if (debug) {
    auto after = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double> diff = after - beforeEverything;
    std::cerr << "[PassRunner] passes took " << diff.count() << " seconds." << std::endl;
  }
}

template<class P>
P* PassRunner::getLast() {
  bool found = false;
  P* ret;
  for (int i = passes.size() - 1; i >= 0; i--) {
    if (found && (ret = dynamic_cast<P*>(passes[i]))) {
      return ret;
    }
    if (passes[i] == currPass) {
      found = true;
    }
  }
  return nullptr;
}

PassRunner::~PassRunner() {
  for (auto pass : passes) {
    delete pass;
  }
}

} // namespace wasm
<commit_msg>run merge-blocks after vacuum<commit_after>/*
 * Copyright 2015 WebAssembly Community Group participants
 *
 * 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 <chrono>

#include <pass.h>

namespace wasm {

// PassRegistry

PassRegistry* PassRegistry::get() {
  static PassRegistry* manager = nullptr;
  if (!manager) {
    manager = new PassRegistry();
  }
  return manager;
}

void PassRegistry::registerPass(const char* name, const char *description, Creator create) {
  assert(passInfos.find(name) == passInfos.end());
  passInfos[name] = PassInfo(description, create);
}

Pass* PassRegistry::createPass(std::string name) {
  if (passInfos.find(name) == passInfos.end()) return nullptr;
  auto ret = passInfos[name].create();
  ret->name = name;
  return ret;
}

std::vector<std::string> PassRegistry::getRegisteredNames() {
  std::vector<std::string> ret;
  for (auto pair : passInfos) {
    ret.push_back(pair.first);
  }
  return ret;
}

std::string PassRegistry::getPassDescription(std::string name) {
  assert(passInfos.find(name) != passInfos.end());
  return passInfos[name].description;
}

// PassRunner

void PassRunner::addDefaultOptimizationPasses() {
  add("remove-unused-brs");
  add("remove-unused-names");
  add("optimize-instructions");
  add("simplify-locals");
  add("coalesce-locals");
  add("reorder-locals");
  add("vacuum");
  add("merge-blocks");
  add("optimize-instructions");
}

void PassRunner::run() {
  std::chrono::high_resolution_clock::time_point beforeEverything;
  size_t padding = 0;
  if (debug) {
    std::cerr << "[PassRunner] running passes..." << std::endl;
    beforeEverything = std::chrono::high_resolution_clock::now();
    for (auto pass : passes) {
      padding = std::max(padding, pass->name.size());
    }
  }
  for (auto pass : passes) {
    currPass = pass;
    std::chrono::high_resolution_clock::time_point before;
    if (debug) {
      std::cerr << "[PassRunner]   running pass: " << pass->name << "... ";
      for (size_t i = 0; i < padding - pass->name.size(); i++) {
        std::cerr << ' ';
      }
      before = std::chrono::high_resolution_clock::now();
    }
    pass->run(this, wasm);
    if (debug) {
      auto after = std::chrono::high_resolution_clock::now();
      std::chrono::duration<double> diff = after - before;
      std::cerr << diff.count() << " seconds." << std::endl;
    }
  }
  if (debug) {
    auto after = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double> diff = after - beforeEverything;
    std::cerr << "[PassRunner] passes took " << diff.count() << " seconds." << std::endl;
  }
}

template<class P>
P* PassRunner::getLast() {
  bool found = false;
  P* ret;
  for (int i = passes.size() - 1; i >= 0; i--) {
    if (found && (ret = dynamic_cast<P*>(passes[i]))) {
      return ret;
    }
    if (passes[i] == currPass) {
      found = true;
    }
  }
  return nullptr;
}

PassRunner::~PassRunner() {
  for (auto pass : passes) {
    delete pass;
  }
}

} // namespace wasm
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
//  LocalFileSystemTest.cc
//------------------------------------------------------------------------------
#include "Pre.h"
#include "UnitTest++/src/UnitTest++.h"
#include "Core/Core.h"
#include "Core/String/StringBuilder.h"
#include "IO/IO.h"
#include "LocalFS/LocalFileSystem.h"
#include "LocalFS/Core/fsWrapper.h"

using namespace Oryol;

static void
wait(const Ptr<IOProtocol::Request>& msg) {
    while (!msg->Handled()) {
        Core::PreRunLoop()->Run();
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        Core::PostRunLoop()->Run();
    }
}

TEST(LocalFileSystemTest) {

    Core::Setup();
    IOSetup ioSetup;
    ioSetup.Assigns.Add("bla:", "root:bla/");
    ioSetup.Assigns.Add("blub:", "cwd:blub/");
    ioSetup.FileSystems.Add("file", LocalFileSystem::Creator());
    IO::Setup(ioSetup);

    // check whether assigns have been set
    StringBuilder strBuilder;
    strBuilder.Format(4096, "file:///%sbla/test.txt", _priv::fsWrapper::getExecutableDir().AsCStr());
    String bla = strBuilder.GetString();
    strBuilder.Format(4096, "file:///%sblub/test.txt", _priv::fsWrapper::getCwd().AsCStr());
    String blub = strBuilder.GetString();
    CHECK(bla == IO::ResolveAssigns("bla:test.txt"));
    CHECK(blub == IO::ResolveAssigns("blub:test.txt"));

    // write a file
    const String hello("Hello World!");
    auto write = IOProtocol::Write::Create();
    write->Url = "root:test.txt";
    write->Data.Add((const uint8*)hello.AsCStr(), hello.Length());
    IO::Put(write);
    wait(write);
    CHECK(write->Status == IOStatus::OK);

    // read the file back
    auto read = IOProtocol::Read::Create();
    read->Url = "root:test.txt";
    IO::Put(read);
    wait(read);
    CHECK(read->Status == IOStatus::OK);
    CHECK(!read->Data.Empty());
    CHECK(read->Data.Size() == 12);
    String readStr((const char*)read->Data.Data(), 0, read->Data.Size());
    CHECK(readStr == "Hello World!");

    // read from offset to end of file
    read = IOProtocol::Read::Create();
    read->Url = "root:test.txt";
    read->StartOffset = 6;
    IO::Put(read);
    wait(read);
    CHECK(read->Status == IOStatus::OK);
    CHECK(!read->Data.Empty());
    CHECK(read->Data.Size() == 6);
    readStr.Assign((const char*)read->Data.Data(), 0, read->Data.Size());
    CHECK(readStr == "World!");

    // read partial data
    read = IOProtocol::Read::Create();
    read->Url = "root:test.txt";
    read->StartOffset = 6;
    read->EndOffset = 11;
    IO::Put(read);
    wait(read);
    CHECK(read->Status == IOStatus::OK);
    CHECK(!read->Data.Empty());
    CHECK(read->Data.Size() == 5);
    readStr.Assign((const char*)read->Data.Data(), 0, read->Data.Size());
    CHECK(readStr == "World");

    IO::Discard();
    Core::Discard();
}

<commit_msg>Added a new LocalFS test<commit_after>//------------------------------------------------------------------------------
//  LocalFileSystemTest.cc
//------------------------------------------------------------------------------
#include "Pre.h"
#include "UnitTest++/src/UnitTest++.h"
#include "Core/Core.h"
#include "Core/String/StringBuilder.h"
#include "IO/IO.h"
#include "LocalFS/LocalFileSystem.h"
#include "LocalFS/Core/fsWrapper.h"

using namespace Oryol;

static void
wait(const Ptr<IOProtocol::Request>& msg) {
    while (!msg->Handled()) {
        Core::PreRunLoop()->Run();
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        Core::PostRunLoop()->Run();
    }
}

TEST(LocalFileSystemTest) {

    Core::Setup();
    IOSetup ioSetup;
    ioSetup.Assigns.Add("bla:", "root:bla/");
    ioSetup.Assigns.Add("blub:", "cwd:blub/");
    ioSetup.FileSystems.Add("file", LocalFileSystem::Creator());
    IO::Setup(ioSetup);

    // check whether assigns have been set
    StringBuilder strBuilder;
    strBuilder.Format(4096, "file:///%sbla/test.txt", _priv::fsWrapper::getExecutableDir().AsCStr());
    String bla = strBuilder.GetString();
    strBuilder.Format(4096, "file:///%sblub/test.txt", _priv::fsWrapper::getCwd().AsCStr());
    String blub = strBuilder.GetString();
    CHECK(bla == IO::ResolveAssigns("bla:test.txt"));
    CHECK(blub == IO::ResolveAssigns("blub:test.txt"));

    // write a file
    const String hello("Hello World!");
    auto write = IOProtocol::Write::Create();
    write->Url = "root:test.txt";
    write->Data.Add((const uint8*)hello.AsCStr(), hello.Length());
    IO::Put(write);
    wait(write);
    CHECK(write->Status == IOStatus::OK);

    // read the file back
    auto read = IOProtocol::Read::Create();
    read->Url = "root:test.txt";
    IO::Put(read);
    wait(read);
    CHECK(read->Status == IOStatus::OK);
    CHECK(!read->Data.Empty());
    CHECK(read->Data.Size() == 12);
    String readStr((const char*)read->Data.Data(), 0, read->Data.Size());
    CHECK(readStr == "Hello World!");

    // read from offset to end of file
    read = IOProtocol::Read::Create();
    read->Url = "root:test.txt";
    read->StartOffset = 6;
    IO::Put(read);
    wait(read);
    CHECK(read->Status == IOStatus::OK);
    CHECK(!read->Data.Empty());
    CHECK(read->Data.Size() == 6);
    readStr.Assign((const char*)read->Data.Data(), 0, read->Data.Size());
    CHECK(readStr == "World!");

    // read partial data
    read = IOProtocol::Read::Create();
    read->Url = "root:test.txt";
    read->StartOffset = 6;
    read->EndOffset = 11;
    IO::Put(read);
    wait(read);
    CHECK(read->Status == IOStatus::OK);
    CHECK(!read->Data.Empty());
    CHECK(read->Data.Size() == 5);
    readStr.Assign((const char*)read->Data.Data(), 0, read->Data.Size());
    CHECK(readStr == "World");

    IO::Discard();
    Core::Discard();
}

TEST(SameExtensionTest) {
    Core::Setup();
    IOSetup ioSetup;
    ioSetup.FileSystems.Add("file", LocalFileSystem::Creator());
    IO::Setup(ioSetup);

    // write 2 files with the same extension
    const String helloJSON("Hello JSON! Bla bla bla bla");
    const String helloDDS("Hello DDS! Dupdidum");
    auto writeJSON = IOProtocol::Write::Create();
    writeJSON->Url = "root:hello.json";
    writeJSON->Data.Add((const uint8*)helloJSON.AsCStr(), helloJSON.Length());
    IO::Put(writeJSON);
    wait(writeJSON);
    auto writeDDS = IOProtocol::Write::Create();
    writeDDS->Url = "root:hello.dds";
    writeDDS->Data.Add((const uint8*)helloDDS.AsCStr(), helloDDS.Length());
    IO::Put(writeDDS);
    wait(writeDDS);

    // read the 2 files back, using the
    bool jsonDone = false, jsonSuccess = false;
    bool ddsDone = false, ddsSuccess = false;
    IO::Load("root:hello.dds",
        // success?
        [&ddsDone, &ddsSuccess](IO::LoadResult res) {
            String payload((const char*)res.Data.Data(), 0, res.Data.Size());
            Log::Info("1: Successfully loaded '%s': '%s'!\n", res.Url.Path().AsCStr(), payload.AsCStr());
            ddsDone = ddsSuccess = true;
        },
        // failure
        [&ddsDone](const URL& url, IOStatus::Code ioStatus) {
            Log::Info("1: Failed to load '%s' with '%s!\n", url.Path().AsCStr(), IOStatus::ToString(ioStatus));
            ddsDone = true;
        });
    IO::Load("root:hello.json",
        // success?
        [&jsonDone, &jsonSuccess](IO::LoadResult res) {
            String payload((const char*)res.Data.Data(), 0, res.Data.Size());
            Log::Info("1: Successfully loaded '%s': '%s'!\n", res.Url.Path().AsCStr(), payload.AsCStr());
            jsonDone = jsonSuccess = true;
        },
        // failure?
        [&jsonDone](const URL& url, IOStatus::Code ioStatus) {
            Log::Info("1: Failed to load '%s' with '%s!\n", url.Path().AsCStr(), IOStatus::ToString(ioStatus));
            jsonDone = true;
        });

    // pump the runloop until both files are loaded (or have failed)
    while (!(ddsDone && jsonDone)) {
        Core::PreRunLoop()->Run();
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        Core::PostRunLoop()->Run();
    }
    CHECK(ddsSuccess);
    CHECK(jsonSuccess);

    // and the same sequentially
    ddsDone = false; ddsSuccess = false;
    IO::Load("root:hello.dds",
        // success?
        [&ddsDone, &ddsSuccess](IO::LoadResult res) {
            String payload((const char*)res.Data.Data(), 0, res.Data.Size());
            Log::Info("2: Successfully loaded '%s': '%s'!\n", res.Url.Path().AsCStr(), payload.AsCStr());
            ddsDone = ddsSuccess = true;
        },
        // failure
        [&ddsDone](const URL& url, IOStatus::Code ioStatus) {
            Log::Info("2: Failed to load '%s' with '%s!\n", url.Path().AsCStr(), IOStatus::ToString(ioStatus));
            ddsDone = true;
        });
    while (!ddsDone) {
        Core::PreRunLoop()->Run();
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        Core::PostRunLoop()->Run();
    }
    CHECK(ddsSuccess);

    jsonDone = false; jsonSuccess = false;
    IO::Load("root:hello.json",
        // success?
        [&jsonDone, &jsonSuccess](IO::LoadResult res) {
            String payload((const char*)res.Data.Data(), 0, res.Data.Size());
            Log::Info("2: Successfully loaded '%s': '%s'!\n", res.Url.Path().AsCStr(), payload.AsCStr());
            jsonDone = jsonSuccess = true;
        },
        // failure?
        [&jsonDone](const URL& url, IOStatus::Code ioStatus) {
            Log::Info("2: Failed to load '%s' with '%s!\n", url.Path().AsCStr(), IOStatus::ToString(ioStatus));
            jsonDone = true;
        });
    // pump the runloop until both files are loaded (or have failed)
    while (!jsonDone) {
        Core::PreRunLoop()->Run();
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        Core::PostRunLoop()->Run();
    }
    CHECK(jsonSuccess);

    IO::Discard();
    Core::Discard();
}

<|endoftext|>


<commit_before>#include <random>
#include <algorithm>
#include <cmath>
#include <string>
#include <fstream>
#include <sstream>
#include <chrono>

#include "bch.h"
#include "iterative.h"
#include "util.h"

static double sigma(const double eb_n0, const double R) {
  return sqrt(1.0f / (2 * R * pow(10, eb_n0 / 10.0)));
}

using decoder_t =
    std::function<std::tuple<std::vector<int>, std::vector<float>, unsigned>(
        std::vector<float>)>;

std::string generate_overview(std::mt19937 &generator, const decoder_t &decoder,
                              const size_t samples, const float eb_n0) {
  constexpr int fk = 3;
  constexpr size_t length = 31;
  constexpr float R = 16.0 / length;

  std::vector<float> b(length);

  std::normal_distribution<float> random(1.0, sigma(eb_n0, R));
  auto noise_gen = std::bind(std::ref(random), std::ref(generator));

  unsigned reconstruction_failures = 0;
  unsigned reconstruction_errors = 0;
  unsigned fk_corr = 0;
  unsigned bit_errors = 0;

  for (size_t sample = 0; sample < samples; sample++) {
    std::generate(std::begin(b), std::end(b), noise_gen);
    try {
      auto result = decoder(b);
      const auto &b_corr = std::get<0>(result);
      auto wrong_bits = std::count_if(std::cbegin(b_corr), std::cend(b_corr),
                                      [](const auto &bit) { return bit != 0; });
      if (wrong_bits) {
        reconstruction_errors++;
        bit_errors += wrong_bits;
      } else {
        auto d = std::count_if(std::cbegin(b), std::cend(b),
                               [](const auto &bit) { return bit < 0; });
        if (d > fk)
          fk_corr++;
      }
    }
    catch (...) {
      reconstruction_failures++;
    }
  }
  /* word error rate */
  std::ostringstream os;
  os << std::scientific;
  const double samples_ = samples;
  os << std::setprecision(12) << reconstruction_failures / samples_ << " ";
  os << std::setprecision(12) << reconstruction_errors / samples_ << " ";
  const auto wrong_words = reconstruction_failures + reconstruction_errors;
  os << std::setprecision(12) << wrong_words / samples_ << " ";
  os << std::setprecision(12) << fk_corr / samples_ << " ";
  os << std::setprecision(12) << bit_errors / (samples_ * length);

  return os.str();
}

std::tuple<std::vector<int>, std::vector<float>, unsigned>
pzg_wrapper(const bch &code, const std::vector<float> &b) {
  std::vector<int> hard;
  hard.reserve(b.size());
  std::transform(std::cbegin(b), std::cend(b), std::back_inserter(hard),
                 [](const auto &bit) { return -2 * bit + 1; });
  auto b_corr = code.correct_peterson(hard);
  return std::make_tuple(b_corr, std::vector<float>(), 0);
}

int main(int argc, const char *const argv[]) {
  constexpr size_t max_iterations = 50;
  constexpr float eb_no_max = 10;
  constexpr float eb_no_step = 0.1f;
  constexpr unsigned base_trials = 10000;

  bch code(5, 0x25, 7);
  std::mt19937 generator(
      std::chrono::high_resolution_clock::now().time_since_epoch().count());

  std::vector<std::pair<std::string, decoder_t> > algorithms;
  algorithms.emplace_back("ms", std::bind(min_sum<max_iterations, float, float>,
                                          std::cref(code.H()),
                                          std::placeholders::_1));
  algorithms.emplace_back(
      "scms1", std::bind(scms1<max_iterations, float, float>,
                         std::cref(code.H()), std::placeholders::_1));
  algorithms.emplace_back(
      "scms2", std::bind(scms2<max_iterations, float, float>,
                         std::cref(code.H()), std::placeholders::_1));
  algorithms.emplace_back(
      "scms3", std::bind(scms3<max_iterations, float, float>,
                         std::cref(code.H()), std::placeholders::_1));
  algorithms.emplace_back(
      "pzg", std::bind(pzg_wrapper, std::cref(code), std::placeholders::_1));

  auto num_samples = [=](const double eb_no) {
    return std::min(base_trials * pow(10, eb_no / 3), 10e6);
  };

  auto run_algorithm = [&](const auto &algorithm) {
    const auto &name = algorithm.first;
    const auto &decoder = algorithm.second;

    if (file_exists(name)) {
      std::cout << "File " << name << " already exists." << std::endl;
      return;
    }

    std::ofstream file(name.c_str(), std::ofstream::out);
    file << "eb_no "
         << "reconstruction_failures "
         << "reconstruction_errors "
         << "wer "
         << "fk_rate "
         << "ber" << std::endl;
    for (double eb_no = 0; eb_no < eb_no_max; eb_no += eb_no_step) {
      auto samples = num_samples(eb_no);
      std::cout << "Calculating for E_b/N_0 = " << eb_no << " with " << samples
                << " … ";
      std::cout.flush();
      auto start = std::chrono::high_resolution_clock::now();

      file << eb_no << " ";
      file << generate_overview(generator, decoder, samples, eb_no);
      file << std::endl;

      auto end = std::chrono::high_resolution_clock::now();
      auto seconds =
          std::chrono::duration_cast<std::chrono::seconds>(end - start).count();

      std::cout << seconds << " s" << std::endl;
    }
  };

  if (argc < 2) {
    std::cout << "Running all algorithms" << std::endl;
    for (const auto &algorithm : algorithms) {
      run_algorithm(algorithm);
    }
  } else {
    for (int arg = 1; arg < argc; arg++) {
      unsigned long index = strtoul(argv[arg], nullptr, 0);
      if (index < algorithms.size()) {
        std::cout << "Running algorithm " << algorithms.at(index).first
                  << std::endl;
        run_algorithm(algorithms.at(index));
      } else {
        unsigned index = 0;
        std::cout << "Index " << index
                  << " is out of range. Choose from:" << std::endl;
        for (const auto &algorithm : algorithms)
          std::cout << "[" << index++ << "] " << algorithm.first << std::endl;
      }
    }
  }
}
<commit_msg>Adapt upper limit on trials again<commit_after>#include <random>
#include <algorithm>
#include <cmath>
#include <string>
#include <fstream>
#include <sstream>
#include <chrono>

#include "bch.h"
#include "iterative.h"
#include "util.h"

static double sigma(const double eb_n0, const double R) {
  return sqrt(1.0f / (2 * R * pow(10, eb_n0 / 10.0)));
}

using decoder_t =
    std::function<std::tuple<std::vector<int>, std::vector<float>, unsigned>(
        std::vector<float>)>;

std::string generate_overview(std::mt19937 &generator, const decoder_t &decoder,
                              const size_t samples, const float eb_n0) {
  constexpr int fk = 3;
  constexpr size_t length = 31;
  constexpr float R = 16.0 / length;

  std::vector<float> b(length);

  std::normal_distribution<float> random(1.0, sigma(eb_n0, R));
  auto noise_gen = std::bind(std::ref(random), std::ref(generator));

  unsigned reconstruction_failures = 0;
  unsigned reconstruction_errors = 0;
  unsigned fk_corr = 0;
  unsigned bit_errors = 0;

  for (size_t sample = 0; sample < samples; sample++) {
    std::generate(std::begin(b), std::end(b), noise_gen);
    try {
      auto result = decoder(b);
      const auto &b_corr = std::get<0>(result);
      auto wrong_bits = std::count_if(std::cbegin(b_corr), std::cend(b_corr),
                                      [](const auto &bit) { return bit != 0; });
      if (wrong_bits) {
        reconstruction_errors++;
        bit_errors += wrong_bits;
      } else {
        auto d = std::count_if(std::cbegin(b), std::cend(b),
                               [](const auto &bit) { return bit < 0; });
        if (d > fk)
          fk_corr++;
      }
    }
    catch (...) {
      reconstruction_failures++;
    }
  }
  /* word error rate */
  std::ostringstream os;
  os << std::scientific;
  const double samples_ = samples;
  os << std::setprecision(12) << reconstruction_failures / samples_ << " ";
  os << std::setprecision(12) << reconstruction_errors / samples_ << " ";
  const auto wrong_words = reconstruction_failures + reconstruction_errors;
  os << std::setprecision(12) << wrong_words / samples_ << " ";
  os << std::setprecision(12) << fk_corr / samples_ << " ";
  os << std::setprecision(12) << bit_errors / (samples_ * length);

  return os.str();
}

std::tuple<std::vector<int>, std::vector<float>, unsigned>
pzg_wrapper(const bch &code, const std::vector<float> &b) {
  std::vector<int> hard;
  hard.reserve(b.size());
  std::transform(std::cbegin(b), std::cend(b), std::back_inserter(hard),
                 [](const auto &bit) { return -2 * bit + 1; });
  auto b_corr = code.correct_peterson(hard);
  return std::make_tuple(b_corr, std::vector<float>(), 0);
}

int main(int argc, const char *const argv[]) {
  constexpr size_t max_iterations = 50;
  constexpr float eb_no_max = 10;
  constexpr float eb_no_step = 0.1f;
  constexpr unsigned base_trials = 10000;

  bch code(5, 0x25, 7);
  std::mt19937 generator(
      std::chrono::high_resolution_clock::now().time_since_epoch().count());

  std::vector<std::pair<std::string, decoder_t> > algorithms;
  algorithms.emplace_back("ms", std::bind(min_sum<max_iterations, float, float>,
                                          std::cref(code.H()),
                                          std::placeholders::_1));
  algorithms.emplace_back(
      "scms1", std::bind(scms1<max_iterations, float, float>,
                         std::cref(code.H()), std::placeholders::_1));
  algorithms.emplace_back(
      "scms2", std::bind(scms2<max_iterations, float, float>,
                         std::cref(code.H()), std::placeholders::_1));
  algorithms.emplace_back(
      "scms3", std::bind(scms3<max_iterations, float, float>,
                         std::cref(code.H()), std::placeholders::_1));
  algorithms.emplace_back(
      "pzg", std::bind(pzg_wrapper, std::cref(code), std::placeholders::_1));

  auto num_samples = [=](const double eb_no) {
    return std::min(base_trials * pow(10, eb_no / 2), 10e6);
  };

  auto run_algorithm = [&](const auto &algorithm) {
    const auto &name = algorithm.first;
    const auto &decoder = algorithm.second;

    if (file_exists(name)) {
      std::cout << "File " << name << " already exists." << std::endl;
      return;
    }

    std::ofstream file(name.c_str(), std::ofstream::out);
    file << "eb_no "
         << "reconstruction_failures "
         << "reconstruction_errors "
         << "wer "
         << "fk_rate "
         << "ber" << std::endl;
    for (double eb_no = 0; eb_no < eb_no_max; eb_no += eb_no_step) {
      auto samples = num_samples(eb_no);
      std::cout << "Calculating for E_b/N_0 = " << eb_no << " with " << samples
                << " … ";
      std::cout.flush();
      auto start = std::chrono::high_resolution_clock::now();

      file << eb_no << " ";
      file << generate_overview(generator, decoder, samples, eb_no);
      file << std::endl;

      auto end = std::chrono::high_resolution_clock::now();
      auto seconds =
          std::chrono::duration_cast<std::chrono::seconds>(end - start).count();

      std::cout << seconds << " s" << std::endl;
    }
  };

  if (argc < 2) {
    std::cout << "Running all algorithms" << std::endl;
    for (const auto &algorithm : algorithms) {
      run_algorithm(algorithm);
    }
  } else {
    for (int arg = 1; arg < argc; arg++) {
      unsigned long index = strtoul(argv[arg], nullptr, 0);
      if (index < algorithms.size()) {
        std::cout << "Running algorithm " << algorithms.at(index).first
                  << std::endl;
        run_algorithm(algorithms.at(index));
      } else {
        unsigned index = 0;
        std::cout << "Index " << index
                  << " is out of range. Choose from:" << std::endl;
        for (const auto &algorithm : algorithms)
          std::cout << "[" << index++ << "] " << algorithm.first << std::endl;
      }
    }
  }
}
<|endoftext|>


<commit_before>#ifndef PYTHONIC_UTILS_BROADCAST_COPY_HPP
#define PYTHONIC_UTILS_BROADCAST_COPY_HPP

#include "pythonic/include/utils/broadcast_copy.hpp"

#include "pythonic/types/tuple.hpp"

#ifdef _OPENMP
#include <omp.h>

// as a macro so that an enlightened user can modify this variable :-)
#ifndef PYTHRAN_OPENMP_MIN_ITERATION_COUNT
#define PYTHRAN_OPENMP_MIN_ITERATION_COUNT 1000
#endif

#endif

namespace pythonic
{

  namespace utils
  {

    /* helper for specialization of the broadcasting, vectorizing copy operator
     * due to expression templates, this may also triggers a lot of
     *computations!
     *
     * ``vector_form'' is set to true if the operation can be done using
     *Boost.SIMD
     *
     * the call operator has four template parameters:
     *
     * template <class E, class F, size_t N>
     * void operator()(E &&self, F const &other, utils::int_<N>, utils::int_<M>)
     *
     * ``E'' is the type of the object to which the data are copied
     *
     * ``F'' is the type of the object from which the data are copied
     *
     * ``N'' is the depth of the loop nest. When it reaches ``1'', we have a raw
     *loop
     *       that may be vectorizable
     *
     * ``D'' is the delta between the number of dimensions of E and F. When set
     *to a
     *       value greater than ``0'', some broadcasting is needed
     */

    template <typename vector_form, size_t N, size_t D>
    struct _broadcast_copy;

    template <size_t N, class vectorizer>
    struct _broadcast_copy<vectorizer, N, 0> {
      template <class E, class F>
      void operator()(E &&self, F const &other)
      {
        long self_size = std::distance(self.begin(), self.end()),
             other_size = std::distance(other.begin(), other.end());
        if (other_size > 0) // empty array sometimes happen when filtering
        {
#ifdef _OPENMP
          if (other_size >= PYTHRAN_OPENMP_MIN_ITERATION_COUNT) {
            auto siter = self.begin();
            auto oiter = other.begin();
#pragma omp parallel for
            for (long i = 0; i < other_size; ++i)
              *(siter + i) = *(oiter + i);
          } else
#endif
            std::copy(other.begin(), other.end(), self.begin());

// eventually repeat the pattern
#ifdef _OPENMP
          if (self_size >= PYTHRAN_OPENMP_MIN_ITERATION_COUNT * other_size)
#pragma omp parallel for
            for (size_t i = other_size; i < self_size; i += other_size)
              std::copy_n(self.begin(), other_size, self.begin() + i);
          else
#endif
            for (size_t i = other_size; i < self_size; i += other_size)
              std::copy_n(self.begin(), other_size, self.begin() + i);
        }
      }
    };

    // ``D'' is not ``0'' so we should broadcast
    template <class vectorizer, size_t N, size_t D>
    struct _broadcast_copy {
      template <class E, class F>
      void operator()(E &&self, F const &other)
      {
        auto sfirst = self.begin();
        auto siter = sfirst;
        *sfirst = other;
#ifdef _OPENMP
        long n = self.shape()[0];
        if (n >= PYTHRAN_OPENMP_MIN_ITERATION_COUNT)
#pragma omp parallel for
          for (long i = 1; i < n; ++i)
            *(siter + i) = *sfirst;
        else
#endif
          std::fill(self.begin() + 1, self.end(), *sfirst);
      }
    };

#ifdef USE_BOOST_SIMD
    // specialize for SIMD only if available
    // otherwise use the std::copy fallback
    template <class vectorizer, class E, class F>
    void vbroadcast_copy(E &&self, F const &other)
    {
      using T = typename F::dtype;
      using vT = typename boost::simd::pack<T>;
      long self_size = std::distance(self.begin(), self.end()),
           other_size = std::distance(other.begin(), other.end());
      if (other_size > 0) // empty array sometimes happen when filtering
      {
        static const std::size_t vN = vT::static_size;
        auto oiter = vectorizer::vbegin(other);
        const long bound =
            std::distance(vectorizer::vbegin(other), vectorizer::vend(other));

#ifdef _OPENMP
        if (bound >= PYTHRAN_OPENMP_MIN_ITERATION_COUNT)
#pragma omp parallel for
          for (long i = 0; i < bound; ++i) {
            self.store(*(oiter + i), i * vN);
          }
        else
#endif
          for (long i = 0; i < bound * vN; i += vN, ++oiter)
            self.store(*oiter, i);
        // tail
        {
          auto siter = self.begin();
          auto oiter = other.begin();
          for (long i = bound * vN; i < other_size; ++i)
            *(siter + i) = *(oiter + i);
        }

#ifdef _OPENMP
        if (self_size >= PYTHRAN_OPENMP_MIN_ITERATION_COUNT * other_size)
#pragma omp parallel for
          for (size_t i = other_size; i < self_size; i += other_size)
            std::copy_n(self.begin(), other_size, self.begin() + i);
        else
#endif
          for (size_t i = other_size; i < self_size; i += other_size)
            std::copy_n(self.begin(), other_size, self.begin() + i);
      }
    }

    template <>
    struct _broadcast_copy<types::vectorizer, 1, 0> {
      template <class E, class F>
      void operator()(E &&self, F const &other)
      {
        return vbroadcast_copy<types::vectorizer>(std::forward<E>(self), other);
      }
    };
    template <>
    struct _broadcast_copy<types::vectorizer_nobroadcast, 1, 0> {
      template <class E, class F>
      void operator()(E &&self, F const &other)
      {
        return vbroadcast_copy<types::vectorizer_nobroadcast>(
            std::forward<E>(self), other);
      }
    };

#endif
    template <class E, class F, size_t N, size_t D, bool vector_form>
    struct broadcast_copy_dispatcher;

    template <class E, class F, size_t N, size_t D>
    struct broadcast_copy_dispatcher<E, F, N, D, false> {
      void operator()(E &self, F const &other)
      {
        if (utils::no_broadcast(other))
          _broadcast_copy<types::novectorize, N, D>{}(
              self, types::make_fast_range(other));
        else
          _broadcast_copy<types::novectorize, N, D>{}(self, other);
      }
    };
    template <class E, class F, size_t N, size_t D>
    struct broadcast_copy_dispatcher<E, F, N, D, true> {
      void operator()(E &self, F const &other)
      {
        if (utils::no_broadcast(other))
          _broadcast_copy<types::vectorizer_nobroadcast, N, D>{}(self, other);
        else
          _broadcast_copy<types::vectorizer, N, D>{}(self, other);
      }
    };

    template <class E, class F, size_t N, size_t D, bool vector_form>
    E &broadcast_copy(E &self, F const &other)
    {
      broadcast_copy_dispatcher<E, F, N, D, vector_form>{}(self, other);
      return self;
    }

    /* update
     */
    // ``D'' is not ``0'' so we should broadcast
    template <class Op, typename vector_form, size_t N, size_t D>
    struct _broadcast_update {

      template <class E, class F>
      void operator()(E &&self, F const &other)
      {
        long n = self.shape()[0];
        auto siter = self.begin();
#ifdef _OPENMP
        if (n >= PYTHRAN_OPENMP_MIN_ITERATION_COUNT)
#pragma omp parallel for
          for (long i = 0; i < n; ++i)
            Op{}(*(siter + i), other);
        else
#endif
          for (long i = 0; i < n; ++i)
            Op{}(*(siter + i), other);
      }
    };

    template <class Op, size_t N, class vector_form>
    struct _broadcast_update<Op, vector_form, N, 0> {
      template <class E, class F>
      void operator()(E &&self, F const &other)
      {
        long other_size = std::distance(other.begin(), other.end());
        if (other_size > 0) // empty array sometimes happen when filtering
        {
          auto siter = self.begin();
          auto oiter = other.begin();
#ifdef _OPENMP
          if (other_size >= PYTHRAN_OPENMP_MIN_ITERATION_COUNT)
#pragma omp parallel for
            for (long i = 0; i < other_size; ++i)
              Op{}(*(siter + i), *(oiter + i));
          else
#endif
              if (other_size == 1) {
            auto value = *oiter;
            for (auto send = self.end(); siter != send; ++siter)
              Op{}(*siter, value);
          } else
            for (auto send = self.end(); siter != send; siter += other_size)
              std::transform(siter, siter + other_size, oiter, siter, Op{});
        }
      }

      template <class E, class F0, class F1>
      void operator()(E &&self, types::broadcast<F0, F1> const &other)
      {
        auto value = *other.begin();
        for (auto siter = self.begin(), send = self.end(); siter != send;
             ++siter)
          Op{}(*siter, value);
      }

      template <class E, class F>
      void operator()(E &&self, types::broadcasted<F> const &other)
      {
        auto value = *other.end();
        for (auto siter = self.begin(), send = self.end(); siter != send;
             ++siter)
          Op{}(*siter, value);
      }
    };

#ifdef USE_BOOST_SIMD
    // specialize for SIMD only if available
    // otherwise use the std::copy fallback
    template <class Op, class vectorizer, class E, class F>
    void vbroadcast_update(E &&self, F const &other)
    {
      using T = typename F::dtype;
      using vT = typename boost::simd::pack<T>;
      long self_size = std::distance(self.begin(), self.end()),
           other_size = std::distance(other.begin(), other.end());

      if (other_size > 0) // empty array sometimes happen when filtering
      {
        static const std::size_t vN = vT::static_size;
        auto oiter = vectorizer::vbegin(other);
        const long bound =
            std::distance(vectorizer::vbegin(other), vectorizer::vend(other));

#ifdef _OPENMP
        if (bound >= PYTHRAN_OPENMP_MIN_ITERATION_COUNT)
#pragma omp parallel for
          for (long i = 0; i < bound * vN; i += vN) {
            self.store(Op{}(self.load(i), *(oiter + i)), i);
          }
        else
#endif
          for (long i = 0; i < bound * vN; i += vN, ++oiter)
            self.store(Op{}(self.load(i), *oiter), i);
        // tail
        {
          auto siter = self.begin();
          auto oiter = other.begin();
          for (long i = bound * vN; i < other_size; ++i)
            *(siter + i) = Op{}(*(siter + i), *(oiter + i));
        }
      }
    }

    template <class Op, class vectorizer, class E, class F0, class F1>
    void vbroadcast_update(E &&self, types::broadcast<F0, F1> const &other)
    {
      auto value = *other.begin();
      for (auto siter = self.begin(), send = self.end(); siter != send; ++siter)
        Op{}(*siter, value);
    }

    template <class Op, class vectorizer, class E, class F>
    void vbroadcast_update(E &&self, types::broadcasted<F> const &other)
    {
      auto value = *other.end();
      for (auto siter = self.begin(), send = self.end(); siter != send; ++siter)
        Op{}(*siter, value);
    }

    template <class Op>
    struct _broadcast_update<Op, types::vectorizer, 1, 0> {
      template <class... Args>
      void operator()(Args &&... args)
      {
        vbroadcast_update<Op, types::vectorizer>(std::forward<Args>(args)...);
      }
    };
    template <class Op>
    struct _broadcast_update<Op, types::vectorizer_nobroadcast, 1, 0> {
      template <class... Args>
      void operator()(Args &&... args)
      {
        vbroadcast_update<Op, types::vectorizer_nobroadcast>(
            std::forward<Args>(args)...);
      }
    };

#endif
    template <class Op, bool vector_form, class E, class F, size_t N, size_t D>
    struct broadcast_update_dispatcher;

    template <class Op, class E, class F, size_t N, size_t D>
    struct broadcast_update_dispatcher<Op, false, E, F, N, D> {
      void operator()(E &self, F const &other)
      {
        _broadcast_update<Op, types::novectorize, N, D>{}(self, other);
      }
    };
    template <class Op, class E, class F, size_t N, size_t D>
    struct broadcast_update_dispatcher<Op, true, E, F, N, D> {
      void operator()(E &self, F const &other)
      {
        if (utils::no_broadcast(other))
          _broadcast_update<Op, types::vectorizer_nobroadcast, N, D>{}(self,
                                                                       other);
        else
          _broadcast_update<Op, types::vectorizer, N, D>{}(self, other);
      }
    };

    template <class Op, class E, class F, size_t N, size_t D, bool vector_form>
    E &broadcast_update(E &self, F const &other)
    {
      broadcast_update_dispatcher<Op, vector_form, E, F, N, D>{}(self, other);
      return self;
    }
  }
}

#endif
<commit_msg>Remove useless test in loop engine<commit_after>#ifndef PYTHONIC_UTILS_BROADCAST_COPY_HPP
#define PYTHONIC_UTILS_BROADCAST_COPY_HPP

#include "pythonic/include/utils/broadcast_copy.hpp"

#include "pythonic/types/tuple.hpp"

#ifdef _OPENMP
#include <omp.h>

// as a macro so that an enlightened user can modify this variable :-)
#ifndef PYTHRAN_OPENMP_MIN_ITERATION_COUNT
#define PYTHRAN_OPENMP_MIN_ITERATION_COUNT 1000
#endif

#endif

namespace pythonic
{

  namespace utils
  {

    /* helper for specialization of the broadcasting, vectorizing copy operator
     * due to expression templates, this may also triggers a lot of
     *computations!
     *
     * ``vector_form'' is set to true if the operation can be done using
     *Boost.SIMD
     *
     * the call operator has four template parameters:
     *
     * template <class E, class F, size_t N>
     * void operator()(E &&self, F const &other, utils::int_<N>, utils::int_<M>)
     *
     * ``E'' is the type of the object to which the data are copied
     *
     * ``F'' is the type of the object from which the data are copied
     *
     * ``N'' is the depth of the loop nest. When it reaches ``1'', we have a raw
     *loop
     *       that may be vectorizable
     *
     * ``D'' is the delta between the number of dimensions of E and F. When set
     *to a
     *       value greater than ``0'', some broadcasting is needed
     */

    template <typename vector_form, size_t N, size_t D>
    struct _broadcast_copy;

    template <size_t N, class vectorizer>
    struct _broadcast_copy<vectorizer, N, 0> {
      template <class E, class F>
      void operator()(E &&self, F const &other)
      {
        long self_size = std::distance(self.begin(), self.end()),
             other_size = std::distance(other.begin(), other.end());
#ifdef _OPENMP
        if (other_size >= PYTHRAN_OPENMP_MIN_ITERATION_COUNT) {
          auto siter = self.begin();
          auto oiter = other.begin();
#pragma omp parallel for
          for (long i = 0; i < other_size; ++i)
            *(siter + i) = *(oiter + i);
        } else
#endif
          std::copy(other.begin(), other.end(), self.begin());

// eventually repeat the pattern
#ifdef _OPENMP
        if (self_size >= PYTHRAN_OPENMP_MIN_ITERATION_COUNT * other_size)
#pragma omp parallel for
          for (size_t i = other_size; i < self_size; i += other_size)
            std::copy_n(self.begin(), other_size, self.begin() + i);
        else
#endif
          for (size_t i = other_size; i < self_size; i += other_size)
            std::copy_n(self.begin(), other_size, self.begin() + i);
      }
    };

    // ``D'' is not ``0'' so we should broadcast
    template <class vectorizer, size_t N, size_t D>
    struct _broadcast_copy {
      template <class E, class F>
      void operator()(E &&self, F const &other)
      {
        auto sfirst = self.begin();
        auto siter = sfirst;
        *sfirst = other;
#ifdef _OPENMP
        long n = self.shape()[0];
        if (n >= PYTHRAN_OPENMP_MIN_ITERATION_COUNT)
#pragma omp parallel for
          for (long i = 1; i < n; ++i)
            *(siter + i) = *sfirst;
        else
#endif
          std::fill(self.begin() + 1, self.end(), *sfirst);
      }
    };

#ifdef USE_BOOST_SIMD
    // specialize for SIMD only if available
    // otherwise use the std::copy fallback
    template <class vectorizer, class E, class F>
    void vbroadcast_copy(E &&self, F const &other)
    {
      using T = typename F::dtype;
      using vT = typename boost::simd::pack<T>;
      long self_size = std::distance(self.begin(), self.end()),
           other_size = std::distance(other.begin(), other.end());
        static const std::size_t vN = vT::static_size;
        auto oiter = vectorizer::vbegin(other);
        const long bound =
            std::distance(vectorizer::vbegin(other), vectorizer::vend(other));

#ifdef _OPENMP
      if (bound >= PYTHRAN_OPENMP_MIN_ITERATION_COUNT)
#pragma omp parallel for
        for (long i = 0; i < bound; ++i) {
          self.store(*(oiter + i), i * vN);
        }
      else
#endif
        for (long i = 0; i < bound * vN; i += vN, ++oiter)
          self.store(*oiter, i);
      // tail
      {
        auto siter = self.begin();
        auto oiter = other.begin();
        for (long i = bound * vN; i < other_size; ++i)
          *(siter + i) = *(oiter + i);
      }

#ifdef _OPENMP
      if (self_size >= PYTHRAN_OPENMP_MIN_ITERATION_COUNT * other_size)
#pragma omp parallel for
        for (size_t i = other_size; i < self_size; i += other_size)
          std::copy_n(self.begin(), other_size, self.begin() + i);
      else
#endif
        for (size_t i = other_size; i < self_size; i += other_size)
          std::copy_n(self.begin(), other_size, self.begin() + i);
    }

    template <>
    struct _broadcast_copy<types::vectorizer, 1, 0> {
      template <class E, class F>
      void operator()(E &&self, F const &other)
      {
        return vbroadcast_copy<types::vectorizer>(std::forward<E>(self), other);
      }
    };
    template <>
    struct _broadcast_copy<types::vectorizer_nobroadcast, 1, 0> {
      template <class E, class F>
      void operator()(E &&self, F const &other)
      {
        return vbroadcast_copy<types::vectorizer_nobroadcast>(
            std::forward<E>(self), other);
      }
    };

#endif
    template <class E, class F, size_t N, size_t D, bool vector_form>
    struct broadcast_copy_dispatcher;

    template <class E, class F, size_t N, size_t D>
    struct broadcast_copy_dispatcher<E, F, N, D, false> {
      void operator()(E &self, F const &other)
      {
        if (utils::no_broadcast(other))
          _broadcast_copy<types::novectorize, N, D>{}(
              self, types::make_fast_range(other));
        else
          _broadcast_copy<types::novectorize, N, D>{}(self, other);
      }
    };
    template <class E, class F, size_t N, size_t D>
    struct broadcast_copy_dispatcher<E, F, N, D, true> {
      void operator()(E &self, F const &other)
      {
        if (utils::no_broadcast(other))
          _broadcast_copy<types::vectorizer_nobroadcast, N, D>{}(self, other);
        else
          _broadcast_copy<types::vectorizer, N, D>{}(self, other);
      }
    };

    template <class E, class F, size_t N, size_t D, bool vector_form>
    E &broadcast_copy(E &self, F const &other)
    {
      broadcast_copy_dispatcher<E, F, N, D, vector_form>{}(self, other);
      return self;
    }

    /* update
     */
    // ``D'' is not ``0'' so we should broadcast
    template <class Op, typename vector_form, size_t N, size_t D>
    struct _broadcast_update {

      template <class E, class F>
      void operator()(E &&self, F const &other)
      {
        long n = self.shape()[0];
        auto siter = self.begin();
#ifdef _OPENMP
        if (n >= PYTHRAN_OPENMP_MIN_ITERATION_COUNT)
#pragma omp parallel for
          for (long i = 0; i < n; ++i)
            Op{}(*(siter + i), other);
        else
#endif
          for (long i = 0; i < n; ++i)
            Op{}(*(siter + i), other);
      }
    };

    template <class Op, size_t N, class vector_form>
    struct _broadcast_update<Op, vector_form, N, 0> {
      template <class E, class F>
      void operator()(E &&self, F const &other)
      {
        long other_size = std::distance(other.begin(), other.end());
        auto siter = self.begin();
        auto oiter = other.begin();
#ifdef _OPENMP
        if (other_size >= PYTHRAN_OPENMP_MIN_ITERATION_COUNT)
#pragma omp parallel for
          for (long i = 0; i < other_size; ++i)
            Op{}(*(siter + i), *(oiter + i));
        else
#endif
        if (other_size == 1) {
          auto value = *oiter;
          for (auto send = self.end(); siter != send; ++siter)
            Op{}(*siter, value);
        } else
          for (auto send = self.end(); siter != send; siter += other_size)
            std::transform(siter, siter + other_size, oiter, siter, Op{});
      }

      template <class E, class F0, class F1>
      void operator()(E &&self, types::broadcast<F0, F1> const &other)
      {
        auto value = *other.begin();
        for (auto siter = self.begin(), send = self.end(); siter != send;
             ++siter)
          Op{}(*siter, value);
      }

      template <class E, class F>
      void operator()(E &&self, types::broadcasted<F> const &other)
      {
        auto value = *other.end();
        for (auto siter = self.begin(), send = self.end(); siter != send;
             ++siter)
          Op{}(*siter, value);
      }
    };

#ifdef USE_BOOST_SIMD
    // specialize for SIMD only if available
    // otherwise use the std::copy fallback
    template <class Op, class vectorizer, class E, class F>
    void vbroadcast_update(E &&self, F const &other)
    {
      using T = typename F::dtype;
      using vT = typename boost::simd::pack<T>;
      long self_size = std::distance(self.begin(), self.end()),
           other_size = std::distance(other.begin(), other.end());

      static const std::size_t vN = vT::static_size;
      auto oiter = vectorizer::vbegin(other);
      const long bound =
          std::distance(vectorizer::vbegin(other), vectorizer::vend(other));

#ifdef _OPENMP
      if (bound >= PYTHRAN_OPENMP_MIN_ITERATION_COUNT)
#pragma omp parallel for
        for (long i = 0; i < bound * vN; i += vN) {
          self.store(Op{}(self.load(i), *(oiter + i)), i);
        }
      else
#endif
        for (long i = 0; i < bound * vN; i += vN, ++oiter)
          self.store(Op{}(self.load(i), *oiter), i);
      // tail
      {
        auto siter = self.begin();
        auto oiter = other.begin();
        for (long i = bound * vN; i < other_size; ++i)
          *(siter + i) = Op{}(*(siter + i), *(oiter + i));
      }
    }

    template <class Op, class vectorizer, class E, class F0, class F1>
    void vbroadcast_update(E &&self, types::broadcast<F0, F1> const &other)
    {
      auto value = *other.begin();
      for (auto siter = self.begin(), send = self.end(); siter != send; ++siter)
        Op{}(*siter, value);
    }

    template <class Op, class vectorizer, class E, class F>
    void vbroadcast_update(E &&self, types::broadcasted<F> const &other)
    {
      auto value = *other.end();
      for (auto siter = self.begin(), send = self.end(); siter != send; ++siter)
        Op{}(*siter, value);
    }

    template <class Op>
    struct _broadcast_update<Op, types::vectorizer, 1, 0> {
      template <class... Args>
      void operator()(Args &&... args)
      {
        vbroadcast_update<Op, types::vectorizer>(std::forward<Args>(args)...);
      }
    };
    template <class Op>
    struct _broadcast_update<Op, types::vectorizer_nobroadcast, 1, 0> {
      template <class... Args>
      void operator()(Args &&... args)
      {
        vbroadcast_update<Op, types::vectorizer_nobroadcast>(
            std::forward<Args>(args)...);
      }
    };

#endif
    template <class Op, bool vector_form, class E, class F, size_t N, size_t D>
    struct broadcast_update_dispatcher;

    template <class Op, class E, class F, size_t N, size_t D>
    struct broadcast_update_dispatcher<Op, false, E, F, N, D> {
      void operator()(E &self, F const &other)
      {
        _broadcast_update<Op, types::novectorize, N, D>{}(self, other);
      }
    };
    template <class Op, class E, class F, size_t N, size_t D>
    struct broadcast_update_dispatcher<Op, true, E, F, N, D> {
      void operator()(E &self, F const &other)
      {
        if (utils::no_broadcast(other))
          _broadcast_update<Op, types::vectorizer_nobroadcast, N, D>{}(self,
                                                                       other);
        else
          _broadcast_update<Op, types::vectorizer, N, D>{}(self, other);
      }
    };

    template <class Op, class E, class F, size_t N, size_t D, bool vector_form>
    E &broadcast_update(E &self, F const &other)
    {
      broadcast_update_dispatcher<Op, vector_form, E, F, N, D>{}(self, other);
      return self;
    }
  }
}

#endif
<|endoftext|>


<commit_before>#include "mainwindow.h"
#include "ui_mainwindow.h"

#include "razornotification.h"
#include <QDebug>
#include <QColorDialog>
#include <QDesktopWidget>

namespace
{
    const QString g_scRazorSettingsName ="razorqt-notify";

    const QString g_scNotificationSize = "notification_size";
    const QString g_scNotificationPosition = "notification_position";
    const QString g_scNotificationOpacity = "notification_opacity";
    const QString g_scNotificationBckColor = "notification_backgroundColor";
}

MainWindow::MainWindow(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MainWindow),
    m_settings( g_scRazorSettingsName ),
    m_notificationId(0)
{
    ui->setupUi(this);
    connect(ui->showNotificationButton, SIGNAL(pressed()), this, SLOT(showNotification()));

    QPoint size = m_settings.value(g_scNotificationSize).toPoint();
    QPoint pos = m_settings.value(g_scNotificationPosition).toPoint();

    QDesktopWidget* pDesktop = QApplication::desktop();

    qint32 maxX = 0 , maxY = 0 ;
    for ( int i=0;i< pDesktop->screenCount();++i)
    {
        maxX += pDesktop->screenGeometry(i).width();
        maxY = qMax(maxY, pDesktop->screenGeometry(i).height());
    }
    qDebug() << maxX ;
    qDebug() << maxY ;

    ui->sizeXspinBox->setMaximum(400);
    ui->sizeXspinBox->setMinimum(200);
    ui->sizeYspinBox->setMaximum(300);// maximum
    ui->sizeYspinBox->setMinimum(100); //minimum height value

    ui->PositionXBox->setMaximum(maxX);
    ui->PositionXBox->setMinimum(0);
    ui->PositionYBox->setMaximum(maxY);
    ui->PositionYBox->setMinimum(0);

    ui->sizeXspinBox->setValue(size.x());
    ui->sizeYspinBox->setValue(size.y());

    ui->PositionXBox->setValue(pos.x());
    ui->PositionYBox->setValue(pos.y());

    ui->opacitySlider->setMinimum(0);
    ui->opacitySlider->setMaximum(100);

    qreal opacityValue = m_settings.value(g_scNotificationOpacity).toReal();
    ui->opacitySlider->setValue(100* opacityValue);

    connect( ui->PositionXBox, SIGNAL(valueChanged(int)) , this , SLOT(positionChanged()) );
    connect( ui->PositionYBox, SIGNAL(valueChanged(int)) , this , SLOT(positionChanged()) );

    connect( ui->sizeXspinBox, SIGNAL(valueChanged(int)) , this , SLOT(sizeChanged()) );
    connect( ui->sizeYspinBox, SIGNAL(valueChanged(int)) , this , SLOT(sizeChanged()) );

    connect( ui->opacitySlider, SIGNAL(valueChanged(int)) , this , SLOT(opacityChanged(int)) );
    connect( ui->colorPickerButton, SIGNAL(pressed()), this, SLOT(colorPickerClicked()));
}

MainWindow::~MainWindow()
{
    RazorNotification::closeNotification(m_notificationId);
    delete ui;
}

void MainWindow::showNotification()
{
    m_notificationId = RazorNotification::notify(tr("A testing application"),
                                                 "razor-logo.png",
                                                 tr("Notification Summary"),
                                                 tr("Notification Body") + "
Lorem ipsim dolor sir amet...");
}

void MainWindow::positionChanged()
{
    QPoint newPos ;
    newPos.setX(ui->PositionXBox->value());
    newPos.setY(ui->PositionYBox->value());
    m_settings.setValue(g_scNotificationPosition, newPos);

    m_settings.sync();
}

void MainWindow::sizeChanged()
{
    QPoint newSize ;
    newSize.setX(ui->sizeXspinBox->value());
    newSize.setY(ui->sizeYspinBox->value());
    m_settings.setValue(g_scNotificationSize, newSize);

    m_settings.sync();
}

void MainWindow::opacityChanged(int value)
{
    qreal newVal = static_cast<qreal>(value) / static_cast<qreal>(100);
    qDebug() << "Opacity changed" << value << " newVal=" << newVal;
    m_settings.setValue(g_scNotificationOpacity, newVal);

    m_settings.sync();
}

void MainWindow::colorPickerClicked()
{
    QColor init = m_settings.value(g_scNotificationBckColor).value<QColor>();
    QColor c = QColorDialog::getColor(init,this);
    if ( c.isValid() )
    {
        m_settings.setValue(g_scNotificationBckColor, c);
    }
}

<commit_msg>add module names to includes<commit_after>#include "mainwindow.h"
#include "ui_mainwindow.h"

#include "razornotification.h"
#include <QtCore/QDebug>
#include <QtGui/QColorDialog>
#include <QtGui/QDesktopWidget>

namespace
{
    const QString g_scRazorSettingsName ="razorqt-notify";

    const QString g_scNotificationSize = "notification_size";
    const QString g_scNotificationPosition = "notification_position";
    const QString g_scNotificationOpacity = "notification_opacity";
    const QString g_scNotificationBckColor = "notification_backgroundColor";
}

MainWindow::MainWindow(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MainWindow),
    m_settings( g_scRazorSettingsName ),
    m_notificationId(0)
{
    ui->setupUi(this);
    connect(ui->showNotificationButton, SIGNAL(pressed()), this, SLOT(showNotification()));

    QPoint size = m_settings.value(g_scNotificationSize).toPoint();
    QPoint pos = m_settings.value(g_scNotificationPosition).toPoint();

    QDesktopWidget* pDesktop = QApplication::desktop();

    qint32 maxX = 0 , maxY = 0 ;
    for ( int i=0;i< pDesktop->screenCount();++i)
    {
        maxX += pDesktop->screenGeometry(i).width();
        maxY = qMax(maxY, pDesktop->screenGeometry(i).height());
    }
    qDebug() << maxX ;
    qDebug() << maxY ;

    ui->sizeXspinBox->setMaximum(400);
    ui->sizeXspinBox->setMinimum(200);
    ui->sizeYspinBox->setMaximum(300);// maximum
    ui->sizeYspinBox->setMinimum(100); //minimum height value

    ui->PositionXBox->setMaximum(maxX);
    ui->PositionXBox->setMinimum(0);
    ui->PositionYBox->setMaximum(maxY);
    ui->PositionYBox->setMinimum(0);

    ui->sizeXspinBox->setValue(size.x());
    ui->sizeYspinBox->setValue(size.y());

    ui->PositionXBox->setValue(pos.x());
    ui->PositionYBox->setValue(pos.y());

    ui->opacitySlider->setMinimum(0);
    ui->opacitySlider->setMaximum(100);

    qreal opacityValue = m_settings.value(g_scNotificationOpacity).toReal();
    ui->opacitySlider->setValue(100* opacityValue);

    connect( ui->PositionXBox, SIGNAL(valueChanged(int)) , this , SLOT(positionChanged()) );
    connect( ui->PositionYBox, SIGNAL(valueChanged(int)) , this , SLOT(positionChanged()) );

    connect( ui->sizeXspinBox, SIGNAL(valueChanged(int)) , this , SLOT(sizeChanged()) );
    connect( ui->sizeYspinBox, SIGNAL(valueChanged(int)) , this , SLOT(sizeChanged()) );

    connect( ui->opacitySlider, SIGNAL(valueChanged(int)) , this , SLOT(opacityChanged(int)) );
    connect( ui->colorPickerButton, SIGNAL(pressed()), this, SLOT(colorPickerClicked()));
}

MainWindow::~MainWindow()
{
    RazorNotification::closeNotification(m_notificationId);
    delete ui;
}

void MainWindow::showNotification()
{
    m_notificationId = RazorNotification::notify(tr("A testing application"),
                                                 "razor-logo.png",
                                                 tr("Notification Summary"),
                                                 tr("Notification Body") + "
Lorem ipsim dolor sir amet...");
}

void MainWindow::positionChanged()
{
    QPoint newPos ;
    newPos.setX(ui->PositionXBox->value());
    newPos.setY(ui->PositionYBox->value());
    m_settings.setValue(g_scNotificationPosition, newPos);

    m_settings.sync();
}

void MainWindow::sizeChanged()
{
    QPoint newSize ;
    newSize.setX(ui->sizeXspinBox->value());
    newSize.setY(ui->sizeYspinBox->value());
    m_settings.setValue(g_scNotificationSize, newSize);

    m_settings.sync();
}

void MainWindow::opacityChanged(int value)
{
    qreal newVal = static_cast<qreal>(value) / static_cast<qreal>(100);
    qDebug() << "Opacity changed" << value << " newVal=" << newVal;
    m_settings.setValue(g_scNotificationOpacity, newVal);

    m_settings.sync();
}

void MainWindow::colorPickerClicked()
{
    QColor init = m_settings.value(g_scNotificationBckColor).value<QColor>();
    QColor c = QColorDialog::getColor(init,this);
    if ( c.isValid() )
    {
        m_settings.setValue(g_scNotificationBckColor, c);
    }
}

<|endoftext|>