<commit_before>/****************************************************************************
**
** Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Script Generator project on Qt Labs.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "shellheadergenerator.h"
#include "fileout.h"

#include <QtCore/QDir>

#include <qdebug.h>

QString ShellHeaderGenerator::fileNameForClass(const AbstractMetaClass *meta_class) const
{
  return QString("PythonQtWrapper_%1.h").arg(meta_class->name());
}

void ShellHeaderGenerator::writeFieldAccessors(QTextStream &s, const AbstractMetaField *field)
{
  const AbstractMetaFunction *setter = field->setter();
  const AbstractMetaFunction *getter = field->getter();

  // static fields are not supported (yet?)
  if (setter->isStatic()) return;

  // Uuid data4 did not work (TODO: move to typesystem...(
  if (field->enclosingClass()->name()=="QUuid" &&  setter->name()=="data4") return;
  if (field->enclosingClass()->name()=="QIPv6Address") return;

  if (!field->type()->isConstant()) {
    writeFunctionSignature(s, setter, 0, QString(),
                           Option(ConvertReferenceToPtr | FirstArgIsWrappedObject| IncludeDefaultExpression | ShowStatic | UnderscoreSpaces));
    s << "{ theWrappedObject->" << field->name() << " = " << setter->arguments()[0]->argumentName() << "; }\n";
  }

  writeFunctionSignature(s, getter, 0, QString(),
                         Option(ConvertReferenceToPtr | FirstArgIsWrappedObject| IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces));
  s << "{ return theWrappedObject->" << field->name() << "; }\n";
}

static bool enum_lessThan(const AbstractMetaEnum *a, const AbstractMetaEnum *b)
{
  return a->name() < b->name();
}

static bool field_lessThan(const AbstractMetaField *a, const AbstractMetaField *b)
{
  return a->name() < b->name();
}

void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_class)
{
  QString builtIn = ShellGenerator::isBuiltIn(meta_class->name())?"_builtin":"";
  QString pro_file_name = meta_class->package().replace(".", "_") + builtIn + "/" + meta_class->package().replace(".", "_") + builtIn + ".pri";
  priGenerator->addHeader(pro_file_name, fileNameForClass(meta_class));
  setupGenerator->addClass(meta_class->package().replace(".", "_") + builtIn, meta_class);

  QString include_block = "PYTHONQTWRAPPER_" + meta_class->name().toUpper() + "_H";

  s << "#ifndef " << include_block << endl
    << "#define " << include_block << endl << endl;

  Include inc = meta_class->typeEntry()->include();
  ShellGenerator::writeInclude(s, inc);

  s << "#include <QObject>" << endl << endl;
  s << "#include <PythonQt.h>" << endl << endl;

  IncludeList list = meta_class->typeEntry()->extraIncludes();
  qSort(list.begin(), list.end());
  foreach (const Include &inc, list) {
    ShellGenerator::writeInclude(s, inc);
  }
  s << endl;

  AbstractMetaFunctionList ctors = meta_class->queryFunctions(AbstractMetaClass::Constructors
    | AbstractMetaClass::WasVisible
    | AbstractMetaClass::NotRemovedFromTargetLang);

  if (meta_class->qualifiedCppName().contains("Ssl")) {
    s << "#ifndef QT_NO_OPENSSL"  << endl;
  }

  // Shell-------------------------------------------------------------------
  if (meta_class->generateShellClass() && !ctors.isEmpty()) {

    AbstractMetaFunctionList virtualsForShell = getVirtualFunctionsForShell(meta_class);

    s << "class " << shellClassName(meta_class)
      << " : public " << meta_class->qualifiedCppName() << endl << "{" << endl;
    s << "public:" << endl;
    foreach(AbstractMetaFunction* fun, ctors) {
      s << "    ";
      writeFunctionSignature(s, fun, 0,"PythonQtShell_",
        Option(IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces));
      s << ":" << meta_class->qualifiedCppName() << "(";
      QString scriptFunctionName = fun->originalName();
      AbstractMetaArgumentList args = fun->arguments();
      for (int i = 0; i < args.size(); ++i) {
        if (i > 0)
          s << ", ";
        s << args.at(i)->argumentName();
      }
      s << "),_wrapper(NULL) { ";
      writeInjectedCode(s, meta_class, TypeSystem::PyInheritShellConstructorCode, true);
      s << " };" << endl;
    }
    s << endl;
    s << "   ~" << shellClassName(meta_class) << "();" << endl;
    s << endl;

    foreach(AbstractMetaFunction* fun, virtualsForShell) {
      s << "virtual ";
      writeFunctionSignature(s, fun, 0, QString(),
        Option(IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces));
      s << ";" << endl;
    }
    s << endl;
    writeInjectedCode(s, meta_class, TypeSystem::PyShellDeclaration);
    writeInjectedCode(s, meta_class, TypeSystem::PyInheritShellDeclaration, true);
    s << "  PythonQtInstanceWrapper* _wrapper; " << endl;

    s << "};" << endl << endl;
  }

  // Promoter-------------------------------------------------------------------
  AbstractMetaFunctionList promoteFunctions;
  if (meta_class->typeEntry()->shouldCreatePromoter()) {
    promoteFunctions = getProtectedFunctionsThatNeedPromotion(meta_class);
  }
  if (!promoteFunctions.isEmpty()) {
    s << "class " << promoterClassName(meta_class)
      << " : public " << meta_class->qualifiedCppName() << endl << "{ public:" << endl;

    AbstractMetaEnumList enums1 = meta_class->enums();
    qSort(enums1.begin(), enums1.end(), enum_lessThan);
    foreach(AbstractMetaEnum* enum1, enums1) {
      if (enum1->wasProtected()) {
        s << "enum " << enum1->name() << "{" << endl;
        bool first = true;
        QString scope = meta_class->qualifiedCppName();
        foreach(AbstractMetaEnumValue* value, enum1->values()) {
          if (first) { first = false; }
          else { s << ", "; }
          s << "  " << value->name() << " = " << scope << "::" << value->name();
        }
        s << "};" << endl;
      }
    }

    foreach(AbstractMetaFunction* fun, promoteFunctions) {
      if (fun->isStatic()) {
        s << "static ";
      }
      s << "inline ";
      writeFunctionSignature(s, fun, 0, "promoted_",
        Option(IncludeDefaultExpression | OriginalName | UnderscoreSpaces | ProtectedEnumAsInts));
      s << " { ";
      QString scriptFunctionName = fun->originalName();
      AbstractMetaArgumentList args = fun->arguments();
      if (fun->type()) {
        s << "return ";
      }
      if (!fun->isAbstract()) {
        s << meta_class->qualifiedCppName() << "::";
      }
      s << fun->originalName() << "(";
      for (int i = 0; i < args.size(); ++i) {
        if (i > 0) {
          s << ", ";
        }
        if (args.at(i)->type()->isEnum()) {
          AbstractMetaEnum* enumType = m_classes.findEnum((EnumTypeEntry *)args.at(i)->type()->typeEntry());
          if (enumType && enumType->wasProtected()) {
            s << "(" << enumType->typeEntry()->qualifiedCppName() << ")";
          }
        }
        s << args.at(i)->argumentName();
      }
      s << "); }" << endl;
    }

    s << "};" << endl << endl;
  }

  // Wrapper-------------------------------------------------------------------

  s << "class " << wrapperClassName(meta_class)
    << " : public QObject" << endl
    << "{ Q_OBJECT" << endl;

  s << "public:" << endl;

  AbstractMetaEnumList enums1 = meta_class->enums();
  qSort(enums1.begin(), enums1.end(), enum_lessThan);
  AbstractMetaEnumList enums;
  QList<FlagsTypeEntry*> flags;
  foreach(AbstractMetaEnum* enum1, enums1) {
    // catch gadgets and enums that are not exported on QObjects...
    if ((enum1->wasProtected() || enum1->wasPublic()) && (!meta_class->isQObject() || !enum1->hasQEnumsDeclaration())) {
      enums << enum1;
      if (enum1->typeEntry()->flags()) {
        flags << enum1->typeEntry()->flags();
      }
    }
  }
  if (enums.count()) {
    s << "Q_ENUMS(";
    foreach(AbstractMetaEnum* enum1, enums) {
      s << enum1->name() << " ";
    }
    s << ")" << endl;

    if (flags.count()) {
      s << "Q_FLAGS(";
      foreach(FlagsTypeEntry* flag1, flags) {
        QString origName = flag1->originalName();
        int idx = origName.lastIndexOf("::");
        if (idx!= -1) {
          origName = origName.mid(idx+2);
        }
        s << origName << " ";
      }
      s << ")" << endl;
    }

    foreach(AbstractMetaEnum* enum1, enums) {
      s << "enum " << enum1->name() << "{" << endl;
      bool first = true;
      QString scope = enum1->wasProtected() ? promoterClassName(meta_class) : meta_class->qualifiedCppName();

      foreach(AbstractMetaEnumValue* value, enum1->values()) {
        if (first) { first = false; }
        else { s << ", "; }
        s << "  " << value->name() << " = " << scope << "::" << value->name();
      }
      s << "};" << endl;
    }
    if (flags.count()) {
      foreach(AbstractMetaEnum* enum1, enums) {
        if (enum1->typeEntry()->flags()) {
          QString origName = enum1->typeEntry()->flags()->originalName();
          int idx = origName.lastIndexOf("::");
          if (idx!= -1) {
            origName = origName.mid(idx+2);
          }
          s << "Q_DECLARE_FLAGS("<< origName << ", " << enum1->name() <<")"<<endl;
        }
      }
    }
  }
  s << "public slots:" << endl;
  if (meta_class->generateShellClass() || !meta_class->isAbstract()) {

    bool copyConstructorSeen = false;
    bool defaultConstructorSeen = false;
    foreach (const AbstractMetaFunction *fun, ctors) {
      if (fun->isAbstract() || (!meta_class->generateShellClass() && !fun->isPublic())) { continue; }

      s << meta_class->qualifiedCppName() << "* ";
      writeFunctionSignature(s, fun, 0, "new_",
        Option(IncludeDefaultExpression | OriginalName | ShowStatic));
      s << ";" << endl;
      if (fun->arguments().size()==1 && meta_class->qualifiedCppName() == fun->arguments().at(0)->type()->typeEntry()->qualifiedCppName()) {
        copyConstructorSeen = true;
      }
      if (fun->arguments().size()==0) {
        defaultConstructorSeen = true;
      }
    }

    if (meta_class->typeEntry()->isValue()
        && !copyConstructorSeen && defaultConstructorSeen) {
      QString className = meta_class->generateShellClass()?shellClassName(meta_class):meta_class->qualifiedCppName();
      s << meta_class->qualifiedCppName() << "* new_" << meta_class->name() << "(const " << meta_class->qualifiedCppName() << "& other) {" << endl;
      s << className << "* a = new " << className << "();" << endl;
      s << "*((" << meta_class->qualifiedCppName() << "*)a) = other;" << endl;
      s << "return a; }" << endl;
    }
  }
  if (meta_class->hasPublicDestructor() && !meta_class->isNamespace()) {
    s << "void delete_" << meta_class->name() << "(" << meta_class->qualifiedCppName() << "* obj) { delete obj; } ";
    s << endl;
  }

  AbstractMetaFunctionList functions = getFunctionsToWrap(meta_class);

  foreach (const AbstractMetaFunction *function, functions) {
    if (!function->isSlot() || function->isVirtual()) {

      // for debugging:
      functionHasNonConstReferences(function);

      s << "   ";
      writeFunctionSignature(s, function, 0, QString(),
        Option(ConvertReferenceToPtr | FirstArgIsWrappedObject | IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces | ProtectedEnumAsInts));
      s << ";" << endl;
    }
  }
  if (meta_class->hasDefaultToStringFunction() || meta_class->hasToStringCapability()) {
    s << "    QString py_toString(" << meta_class->qualifiedCppName() << "*);" << endl;
  }
  if (meta_class->hasDefaultIsNull()) {
    s << "    bool __nonzero__(" << meta_class->qualifiedCppName() << "* obj) { return !obj->isNull(); }" << endl;
  }

  AbstractMetaFieldList fields = meta_class->fields();
  qSort(fields.begin(), fields.end(), field_lessThan);

  // TODO: move "So" check to typesystem, e.g. allow star in rejection...
  // Field accessors
  foreach (const AbstractMetaField *field, fields ) {
    if (field->isPublic() && !field->type()->name().startsWith("So")) {
      writeFieldAccessors(s, field);
    }
  }

  writeInjectedCode(s, meta_class, TypeSystem::PyWrapperDeclaration);

  s  << "};" << endl << endl;
  if (meta_class->qualifiedCppName().contains("Ssl")) {
    s << "#endif"  << endl << endl;
  }

  s  << "#endif // " << include_block << endl;

}

void ShellHeaderGenerator::writeInjectedCode(QTextStream &s, const AbstractMetaClass *meta_class, int type, bool recursive)
{
  const AbstractMetaClass *cls = meta_class;
  do {
    CodeSnipList code_snips = cls->typeEntry()->codeSnips();
    foreach(const CodeSnip &cs, code_snips) {
      if (cs.language == type) {
        s << cs.code() << endl;
      }
    }
    cls = cls->baseClass();
  } while (recursive && cls);
}
<commit_msg>added special field accessors for Inventor<commit_after>/****************************************************************************
**
** Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Script Generator project on Qt Labs.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "shellheadergenerator.h"
#include "fileout.h"

#include <QtCore/QDir>

#include <qdebug.h>

QString ShellHeaderGenerator::fileNameForClass(const AbstractMetaClass *meta_class) const
{
  return QString("PythonQtWrapper_%1.h").arg(meta_class->name());
}

void ShellHeaderGenerator::writeFieldAccessors(QTextStream &s, const AbstractMetaField *field)
{
  const AbstractMetaFunction *setter = field->setter();
  const AbstractMetaFunction *getter = field->getter();

  // static fields are not supported (yet?)
  if (setter->isStatic()) return;

  // Uuid data4 did not work (TODO: move to typesystem...(
  if (field->enclosingClass()->name()=="QUuid" &&  setter->name()=="data4") return;
  if (field->enclosingClass()->name()=="QIPv6Address") return;

  bool isInventorField = field->type()->name().startsWith("So");

  if (!isInventorField && !field->type()->isConstant()) {
    writeFunctionSignature(s, setter, 0, QString(),
                           Option(ConvertReferenceToPtr | FirstArgIsWrappedObject| IncludeDefaultExpression | ShowStatic | UnderscoreSpaces));
    s << "{ theWrappedObject->" << field->name() << " = " << setter->arguments()[0]->argumentName() << "; }\n";
  }

  bool addIndirection = false;
  if (isInventorField && getter->type()->indirections() == 0) {
    // make it a field ptr:
    getter->type()->setIndirections(1);
    addIndirection = true;
  }
  writeFunctionSignature(s, getter, 0, QString(),
                         Option(ConvertReferenceToPtr | FirstArgIsWrappedObject| IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces));
  s << "{ return ";
  if (addIndirection) {
    s << "&";
  }
  s << "theWrappedObject->" << field->name() << "; }\n";
}

static bool enum_lessThan(const AbstractMetaEnum *a, const AbstractMetaEnum *b)
{
  return a->name() < b->name();
}

static bool field_lessThan(const AbstractMetaField *a, const AbstractMetaField *b)
{
  return a->name() < b->name();
}

void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_class)
{
  QString builtIn = ShellGenerator::isBuiltIn(meta_class->name())?"_builtin":"";
  QString pro_file_name = meta_class->package().replace(".", "_") + builtIn + "/" + meta_class->package().replace(".", "_") + builtIn + ".pri";
  priGenerator->addHeader(pro_file_name, fileNameForClass(meta_class));
  setupGenerator->addClass(meta_class->package().replace(".", "_") + builtIn, meta_class);

  QString include_block = "PYTHONQTWRAPPER_" + meta_class->name().toUpper() + "_H";

  s << "#ifndef " << include_block << endl
    << "#define " << include_block << endl << endl;

  Include inc = meta_class->typeEntry()->include();
  ShellGenerator::writeInclude(s, inc);

  s << "#include <QObject>" << endl << endl;
  s << "#include <PythonQt.h>" << endl << endl;

  IncludeList list = meta_class->typeEntry()->extraIncludes();
  qSort(list.begin(), list.end());
  foreach (const Include &inc, list) {
    ShellGenerator::writeInclude(s, inc);
  }
  s << endl;

  AbstractMetaFunctionList ctors = meta_class->queryFunctions(AbstractMetaClass::Constructors
    | AbstractMetaClass::WasVisible
    | AbstractMetaClass::NotRemovedFromTargetLang);

  if (meta_class->qualifiedCppName().contains("Ssl")) {
    s << "#ifndef QT_NO_OPENSSL"  << endl;
  }

  // Shell-------------------------------------------------------------------
  if (meta_class->generateShellClass() && !ctors.isEmpty()) {

    AbstractMetaFunctionList virtualsForShell = getVirtualFunctionsForShell(meta_class);

    s << "class " << shellClassName(meta_class)
      << " : public " << meta_class->qualifiedCppName() << endl << "{" << endl;
    s << "public:" << endl;
    foreach(AbstractMetaFunction* fun, ctors) {
      s << "    ";
      writeFunctionSignature(s, fun, 0,"PythonQtShell_",
        Option(IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces));
      s << ":" << meta_class->qualifiedCppName() << "(";
      QString scriptFunctionName = fun->originalName();
      AbstractMetaArgumentList args = fun->arguments();
      for (int i = 0; i < args.size(); ++i) {
        if (i > 0)
          s << ", ";
        s << args.at(i)->argumentName();
      }
      s << "),_wrapper(NULL) { ";
      writeInjectedCode(s, meta_class, TypeSystem::PyInheritShellConstructorCode, true);
      s << " };" << endl;
    }
    s << endl;
    s << "   ~" << shellClassName(meta_class) << "();" << endl;
    s << endl;

    foreach(AbstractMetaFunction* fun, virtualsForShell) {
      s << "virtual ";
      writeFunctionSignature(s, fun, 0, QString(),
        Option(IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces));
      s << ";" << endl;
    }
    s << endl;
    writeInjectedCode(s, meta_class, TypeSystem::PyShellDeclaration);
    writeInjectedCode(s, meta_class, TypeSystem::PyInheritShellDeclaration, true);
    s << "  PythonQtInstanceWrapper* _wrapper; " << endl;

    s << "};" << endl << endl;
  }

  // Promoter-------------------------------------------------------------------
  AbstractMetaFunctionList promoteFunctions;
  if (meta_class->typeEntry()->shouldCreatePromoter()) {
    promoteFunctions = getProtectedFunctionsThatNeedPromotion(meta_class);
  }
  if (!promoteFunctions.isEmpty()) {
    s << "class " << promoterClassName(meta_class)
      << " : public " << meta_class->qualifiedCppName() << endl << "{ public:" << endl;

    AbstractMetaEnumList enums1 = meta_class->enums();
    qSort(enums1.begin(), enums1.end(), enum_lessThan);
    foreach(AbstractMetaEnum* enum1, enums1) {
      if (enum1->wasProtected()) {
        s << "enum " << enum1->name() << "{" << endl;
        bool first = true;
        QString scope = meta_class->qualifiedCppName();
        foreach(AbstractMetaEnumValue* value, enum1->values()) {
          if (first) { first = false; }
          else { s << ", "; }
          s << "  " << value->name() << " = " << scope << "::" << value->name();
        }
        s << "};" << endl;
      }
    }

    foreach(AbstractMetaFunction* fun, promoteFunctions) {
      if (fun->isStatic()) {
        s << "static ";
      }
      s << "inline ";
      writeFunctionSignature(s, fun, 0, "promoted_",
        Option(IncludeDefaultExpression | OriginalName | UnderscoreSpaces | ProtectedEnumAsInts));
      s << " { ";
      QString scriptFunctionName = fun->originalName();
      AbstractMetaArgumentList args = fun->arguments();
      if (fun->type()) {
        s << "return ";
      }
      if (!fun->isAbstract()) {
        s << meta_class->qualifiedCppName() << "::";
      }
      s << fun->originalName() << "(";
      for (int i = 0; i < args.size(); ++i) {
        if (i > 0) {
          s << ", ";
        }
        if (args.at(i)->type()->isEnum()) {
          AbstractMetaEnum* enumType = m_classes.findEnum((EnumTypeEntry *)args.at(i)->type()->typeEntry());
          if (enumType && enumType->wasProtected()) {
            s << "(" << enumType->typeEntry()->qualifiedCppName() << ")";
          }
        }
        s << args.at(i)->argumentName();
      }
      s << "); }" << endl;
    }

    s << "};" << endl << endl;
  }

  // Wrapper-------------------------------------------------------------------

  s << "class " << wrapperClassName(meta_class)
    << " : public QObject" << endl
    << "{ Q_OBJECT" << endl;

  s << "public:" << endl;

  AbstractMetaEnumList enums1 = meta_class->enums();
  qSort(enums1.begin(), enums1.end(), enum_lessThan);
  AbstractMetaEnumList enums;
  QList<FlagsTypeEntry*> flags;
  foreach(AbstractMetaEnum* enum1, enums1) {
    // catch gadgets and enums that are not exported on QObjects...
    if ((enum1->wasProtected() || enum1->wasPublic()) && (!meta_class->isQObject() || !enum1->hasQEnumsDeclaration())) {
      enums << enum1;
      if (enum1->typeEntry()->flags()) {
        flags << enum1->typeEntry()->flags();
      }
    }
  }
  if (enums.count()) {
    s << "Q_ENUMS(";
    foreach(AbstractMetaEnum* enum1, enums) {
      s << enum1->name() << " ";
    }
    s << ")" << endl;

    if (flags.count()) {
      s << "Q_FLAGS(";
      foreach(FlagsTypeEntry* flag1, flags) {
        QString origName = flag1->originalName();
        int idx = origName.lastIndexOf("::");
        if (idx!= -1) {
          origName = origName.mid(idx+2);
        }
        s << origName << " ";
      }
      s << ")" << endl;
    }

    foreach(AbstractMetaEnum* enum1, enums) {
      s << "enum " << enum1->name() << "{" << endl;
      bool first = true;
      QString scope = enum1->wasProtected() ? promoterClassName(meta_class) : meta_class->qualifiedCppName();

      foreach(AbstractMetaEnumValue* value, enum1->values()) {
        if (first) { first = false; }
        else { s << ", "; }
        s << "  " << value->name() << " = " << scope << "::" << value->name();
      }
      s << "};" << endl;
    }
    if (flags.count()) {
      foreach(AbstractMetaEnum* enum1, enums) {
        if (enum1->typeEntry()->flags()) {
          QString origName = enum1->typeEntry()->flags()->originalName();
          int idx = origName.lastIndexOf("::");
          if (idx!= -1) {
            origName = origName.mid(idx+2);
          }
          s << "Q_DECLARE_FLAGS("<< origName << ", " << enum1->name() <<")"<<endl;
        }
      }
    }
  }
  s << "public slots:" << endl;
  if (meta_class->generateShellClass() || !meta_class->isAbstract()) {

    bool copyConstructorSeen = false;
    bool defaultConstructorSeen = false;
    foreach (const AbstractMetaFunction *fun, ctors) {
      if (fun->isAbstract() || (!meta_class->generateShellClass() && !fun->isPublic())) { continue; }

      s << meta_class->qualifiedCppName() << "* ";
      writeFunctionSignature(s, fun, 0, "new_",
        Option(IncludeDefaultExpression | OriginalName | ShowStatic));
      s << ";" << endl;
      if (fun->arguments().size()==1 && meta_class->qualifiedCppName() == fun->arguments().at(0)->type()->typeEntry()->qualifiedCppName()) {
        copyConstructorSeen = true;
      }
      if (fun->arguments().size()==0) {
        defaultConstructorSeen = true;
      }
    }

    if (meta_class->typeEntry()->isValue()
        && !copyConstructorSeen && defaultConstructorSeen) {
      QString className = meta_class->generateShellClass()?shellClassName(meta_class):meta_class->qualifiedCppName();
      s << meta_class->qualifiedCppName() << "* new_" << meta_class->name() << "(const " << meta_class->qualifiedCppName() << "& other) {" << endl;
      s << className << "* a = new " << className << "();" << endl;
      s << "*((" << meta_class->qualifiedCppName() << "*)a) = other;" << endl;
      s << "return a; }" << endl;
    }
  }
  if (meta_class->hasPublicDestructor() && !meta_class->isNamespace()) {
    s << "void delete_" << meta_class->name() << "(" << meta_class->qualifiedCppName() << "* obj) { delete obj; } ";
    s << endl;
  }

  AbstractMetaFunctionList functions = getFunctionsToWrap(meta_class);

  foreach (const AbstractMetaFunction *function, functions) {
    if (!function->isSlot() || function->isVirtual()) {

      // for debugging:
      functionHasNonConstReferences(function);

      s << "   ";
      writeFunctionSignature(s, function, 0, QString(),
        Option(ConvertReferenceToPtr | FirstArgIsWrappedObject | IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces | ProtectedEnumAsInts));
      s << ";" << endl;
    }
  }
  if (meta_class->hasDefaultToStringFunction() || meta_class->hasToStringCapability()) {
    s << "    QString py_toString(" << meta_class->qualifiedCppName() << "*);" << endl;
  }
  if (meta_class->hasDefaultIsNull()) {
    s << "    bool __nonzero__(" << meta_class->qualifiedCppName() << "* obj) { return !obj->isNull(); }" << endl;
  }

  AbstractMetaFieldList fields = meta_class->fields();
  qSort(fields.begin(), fields.end(), field_lessThan);

  // TODO: move "So" check to typesystem, e.g. allow star in rejection...
  // Field accessors
  foreach (const AbstractMetaField *field, fields ) {
    if (field->isPublic()) {
      writeFieldAccessors(s, field);
    }
  }

  writeInjectedCode(s, meta_class, TypeSystem::PyWrapperDeclaration);

  s  << "};" << endl << endl;
  if (meta_class->qualifiedCppName().contains("Ssl")) {
    s << "#endif"  << endl << endl;
  }

  s  << "#endif // " << include_block << endl;

}

void ShellHeaderGenerator::writeInjectedCode(QTextStream &s, const AbstractMetaClass *meta_class, int type, bool recursive)
{
  const AbstractMetaClass *cls = meta_class;
  do {
    CodeSnipList code_snips = cls->typeEntry()->codeSnips();
    foreach(const CodeSnip &cs, code_snips) {
      if (cs.language == type) {
        s << cs.code() << endl;
      }
    }
    cls = cls->baseClass();
  } while (recursive && cls);
}
<|endoftext|>


<commit_before>//
// Created by Vadim N. on 16/03/2016.
//

#include "benchutils.h"

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

    if (argc < 2) {
      std::cout << "Please re-run the script with the data folder path supplied." << std::endl;
      return 1;
    }

    std::chrono::system_clock::time_point tp1, tp2;

    std::vector< std::pair<std::string, size_t> > timepoints;

    std::vector<prob_t> logLvec;

    // std::string temp_str;

    // time_t vj_single_parse, vdj_single_parse,
    //         vj_single_prob, vj_single_meta,
    //         vj_single_infer, vdj_single_prob,
    //         vdj_single_meta, vdj_single_infer;

    // time_t vj_good_parse, vdj_good_parse,
    //         vj_good_prob, vj_good_meta,
    //         vj_good_infer, vdj_good_prob,
    //         vdj_good_meta, vdj_good_infer;

    std::string BENCH_DATA_FOLDER = argv[1];

    std::cout << "Data folder:\t[" << BENCH_DATA_FOLDER << "]" << endl;

    //
    // TCR alpha chain repertoire - VJ recombination
    //
    VDJRecombinationGenes vj_single_genes("Vgene",
                                          BENCH_DATA_FOLDER + "trav.txt",
                                          "Jgene",
                                          BENCH_DATA_FOLDER + "traj.txt");

    VDJRecombinationGenes vj_single_genes2;
    vj_single_genes2 = vj_single_genes;

    string input_alpha_file = "alpha.250k.txt";
    string input_beta_file = "beta.250k.txt";

    CDR3NucParser parser;
    Cloneset cloneset_vj;

    YMIR_BENCHMARK("Parsing VJ",
                   parser.openAndParse(BENCH_DATA_FOLDER + input_alpha_file,
                                       &cloneset_vj,
                                       vj_single_genes,
                                       NUCLEOTIDE,
                                       VJ_RECOMB,
                                       AlignmentColumnOptions(AlignmentColumnOptions::OVERWRITE, AlignmentColumnOptions::OVERWRITE),
                                       VDJAlignerParameters(2)))

    //
    // TCR beta chain repertoire - VDJ recombination
    //
//    VDJRecombinationGenes vdj_single_genes("Vgene",
//                                    BENCH_DATA_FOLDER + "trbv.txt",
//                                    "Jgene",
//                                    BENCH_DATA_FOLDER + "trbj.txt",
//                                    "Dgene",
//                                    BENCH_DATA_FOLDER + "trbd.txt");
//
//    Cloneset cloneset_vdj;
//    YMIR_BENCHMARK("Parsing VDJ",
//                   parser.openAndParse(BENCH_DATA_FOLDER + input_beta_file,
//                                       &cloneset_vdj,
//                                       vdj_single_genes,
//                                       NUCLEOTIDE,
//                                       VDJ_RECOMB,
//                                       AlignmentColumnOptions()
//                                               .setV(AlignmentColumnOptions::USE_PROVIDED)
//                                               .setD(AlignmentColumnOptions::OVERWRITE)
//                                               .setJ(AlignmentColumnOptions::USE_PROVIDED),
//                                       VDJAlignerParameters(3)))

    //
    // VJ MAAG
    //
    ProbabilisticAssemblingModel vj_single_model(BENCH_DATA_FOLDER + "../../models/hTRA", EMPTY);

    //
    // VDJ MAAG
    //
//    ProbabilisticAssemblingModel vdj_single_model(BENCH_DATA_FOLDER + "../../models/hTRB", EMPTY);

    //
    // Inference
    //
    vector<int> vec_sample = {10000, 25000, 50000, 100000, 150000};
    vec_sample = { 100000 };
    vector<int> vec_block = {500, 1000, 2000, 5000, 10000}; //, 2000, 5000, 10000};
//    vec_block = {2000, 5000, 10000};
    vec_block = { std::stoi(argv[2]) };
    vector<double> vec_alpha = {.5, .6, .7, .8, .9};
    vec_alpha = { std::stof(argv[3]) };
    vector<double> vec_beta =  {.1, .5, 1, 3};
    vec_beta = { std::stof(argv[4]) };
    vector<double> vec_K =     {1, 2, 3};
    vec_K = { std::stod(argv[5]) };
    ErrorMode error_mode = COMPUTE_ERRORS;

//    int niter, sample, block;
//    double alpha;
//    niter = 10;
//    int sample = 10000;

//    RUN_EM_INFERENCE(string("vj"), cloneset_vj, vj_single_model, niter, sample, error_mode)
//    RUN_EM_INFERENCE(string("vdj"), cloneset_vdj, vdj_single_model, niter, sample, error_mode)
//    for(auto val_sample: vec_sample) {
//        RUN_EM_INFERENCE(string("vj"), cloneset_vj, vj_single_model, 40, val_sample, error_mode)
//    }

//    ModelParameterVector new_param_vec = vj_single_model.event_probabilities();
//    new_param_vec.fill(1);
//    new_param_vec.normaliseEventFamilies();
//    vj_single_model.updateModelParameterVector(new_param_vec);
//
//    auto rep_nonc = cloneset_vj.noncoding().sample(2500);
//    auto maag_rep = vj_single_model.buildGraphs(rep_nonc, SAVE_METADATA, error_mode, NUCLEOTIDE, true);
//    vector<prob_t> prob_vec(maag_rep.size(), 0);
//
//    vector<bool> good_clonotypes(maag_rep.size(), true);
//    for (size_t i = 0; i < maag_rep.size(); ++i) {
//        if (rep_nonc[i].is_good()) {
//            prob_vec[i] = maag_rep[i].fullProbability();
//            if (std::isnan(prob_vec[i]) || prob_vec[i] == 0) {
//                good_clonotypes[i] = false;
//            }
//        } else {
//            good_clonotypes[i] = false;
//        }
//    }

    for(auto val_sample: vec_sample) {
        for(auto val_block: vec_block) {
            for (auto val_alpha: vec_alpha) {
                for (auto val_beta: vec_beta) {
                    for (auto val_K: vec_K) {
                        RUN_SG_INFERENCE(string("vj"), cloneset_vj, vj_single_model, 40, val_block, val_alpha, val_beta, val_K, val_sample, error_mode)
                    }
                }
            }
        }
    }

}
<commit_msg>debug<commit_after>//
// Created by Vadim N. on 16/03/2016.
//

#include "benchutils.h"

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

    if (argc < 2) {
      std::cout << "Please re-run the script with the data folder path supplied." << std::endl;
      return 1;
    }

    std::chrono::system_clock::time_point tp1, tp2;

    std::vector< std::pair<std::string, size_t> > timepoints;

    std::vector<prob_t> logLvec;

    std::string temp_str;

    // time_t vj_single_parse, vdj_single_parse,
    //         vj_single_prob, vj_single_meta,
    //         vj_single_infer, vdj_single_prob,
    //         vdj_single_meta, vdj_single_infer;

    // time_t vj_good_parse, vdj_good_parse,
    //         vj_good_prob, vj_good_meta,
    //         vj_good_infer, vdj_good_prob,
    //         vdj_good_meta, vdj_good_infer;

    std::string BENCH_DATA_FOLDER = argv[1];

    std::cout << "Data folder:\t[" << BENCH_DATA_FOLDER << "]" << endl;

    //
    // TCR alpha chain repertoire - VJ recombination
    //
    VDJRecombinationGenes vj_single_genes("Vgene",
                                          BENCH_DATA_FOLDER + "trav.txt",
                                          "Jgene",
                                          BENCH_DATA_FOLDER + "traj.txt");

    VDJRecombinationGenes vj_single_genes2;
    vj_single_genes2 = vj_single_genes;

    string input_alpha_file = "alpha.250k.txt";
    string input_beta_file = "beta.250k.txt";

    CDR3NucParser parser;
    Cloneset cloneset_vj;

    YMIR_BENCHMARK("Parsing VJ",
                   parser.openAndParse(BENCH_DATA_FOLDER + input_alpha_file,
                                       &cloneset_vj,
                                       vj_single_genes,
                                       NUCLEOTIDE,
                                       VJ_RECOMB,
                                       AlignmentColumnOptions(AlignmentColumnOptions::OVERWRITE, AlignmentColumnOptions::OVERWRITE),
                                       VDJAlignerParameters(2)))

    //
    // TCR beta chain repertoire - VDJ recombination
    //
//    VDJRecombinationGenes vdj_single_genes("Vgene",
//                                    BENCH_DATA_FOLDER + "trbv.txt",
//                                    "Jgene",
//                                    BENCH_DATA_FOLDER + "trbj.txt",
//                                    "Dgene",
//                                    BENCH_DATA_FOLDER + "trbd.txt");
//
//    Cloneset cloneset_vdj;
//    YMIR_BENCHMARK("Parsing VDJ",
//                   parser.openAndParse(BENCH_DATA_FOLDER + input_beta_file,
//                                       &cloneset_vdj,
//                                       vdj_single_genes,
//                                       NUCLEOTIDE,
//                                       VDJ_RECOMB,
//                                       AlignmentColumnOptions()
//                                               .setV(AlignmentColumnOptions::USE_PROVIDED)
//                                               .setD(AlignmentColumnOptions::OVERWRITE)
//                                               .setJ(AlignmentColumnOptions::USE_PROVIDED),
//                                       VDJAlignerParameters(3)))

    //
    // VJ MAAG
    //
    ProbabilisticAssemblingModel vj_single_model(BENCH_DATA_FOLDER + "../../models/hTRA", EMPTY);

    //
    // VDJ MAAG
    //
//    ProbabilisticAssemblingModel vdj_single_model(BENCH_DATA_FOLDER + "../../models/hTRB", EMPTY);

    //
    // Inference
    //
    vector<int> vec_sample = {10000, 25000, 50000, 100000, 150000};
    vec_sample = { 100000 };
    vector<int> vec_block = {500, 1000, 2000, 5000, 10000}; //, 2000, 5000, 10000};
//    vec_block = {2000, 5000, 10000};
    vec_block = { std::stoi(argv[2]) };
    vector<double> vec_alpha = {.5, .6, .7, .8, .9};
    vec_alpha = { std::stof(argv[3]) };
    vector<double> vec_beta =  {.1, .5, 1, 3};
    vec_beta = { std::stof(argv[4]) };
    vector<double> vec_K =     {1, 2, 3};
    vec_K = { std::stod(argv[5]) };
    ErrorMode error_mode = COMPUTE_ERRORS;

//    int niter, sample, block;
//    double alpha;
//    niter = 10;
//    int sample = 10000;

//    RUN_EM_INFERENCE(string("vj"), cloneset_vj, vj_single_model, niter, sample, error_mode)
//    RUN_EM_INFERENCE(string("vdj"), cloneset_vdj, vdj_single_model, niter, sample, error_mode)
//    for(auto val_sample: vec_sample) {
//        RUN_EM_INFERENCE(string("vj"), cloneset_vj, vj_single_model, 40, val_sample, error_mode)
//    }

//    ModelParameterVector new_param_vec = vj_single_model.event_probabilities();
//    new_param_vec.fill(1);
//    new_param_vec.normaliseEventFamilies();
//    vj_single_model.updateModelParameterVector(new_param_vec);
//
//    auto rep_nonc = cloneset_vj.noncoding().sample(2500);
//    auto maag_rep = vj_single_model.buildGraphs(rep_nonc, SAVE_METADATA, error_mode, NUCLEOTIDE, true);
//    vector<prob_t> prob_vec(maag_rep.size(), 0);
//
//    vector<bool> good_clonotypes(maag_rep.size(), true);
//    for (size_t i = 0; i < maag_rep.size(); ++i) {
//        if (rep_nonc[i].is_good()) {
//            prob_vec[i] = maag_rep[i].fullProbability();
//            if (std::isnan(prob_vec[i]) || prob_vec[i] == 0) {
//                good_clonotypes[i] = false;
//            }
//        } else {
//            good_clonotypes[i] = false;
//        }
//    }

    for(auto val_sample: vec_sample) {
        for(auto val_block: vec_block) {
            for (auto val_alpha: vec_alpha) {
                for (auto val_beta: vec_beta) {
                    for (auto val_K: vec_K) {
                        RUN_SG_INFERENCE(string("vj"), cloneset_vj, vj_single_model, 40, val_block, val_alpha, val_beta, val_K, val_sample, error_mode)
                    }
                }
            }
        }
    }

}
<|endoftext|>


<commit_before>#include <jios/istream_ij.hpp>

#include <boost/throw_exception.hpp>
#include <boost/core/null_deleter.hpp>

using namespace std;

namespace jios {

// istream_facade

istream_facade::istream_facade(shared_ptr<istream> const& p_is)
  : p_is_(p_is)
  , buf_(4096)
  , bytes_avail_(0)
{
  if (!p_is_) {
    BOOST_THROW_EXCEPTION(bad_alloc());
  }
}

istream_facade::istream_facade(istream & is)
  : p_is_(&is, boost::null_deleter())
  , buf_(4096)
  , bytes_avail_(0)
{
}

streamsize istream_facade::avail()
{
  if (!bytes_avail_ && p_is_->good()) {
    bytes_avail_ = p_is_->readsome(buf_.data(), buf_.size());
  }
  return bytes_avail_;
}

void istream_facade::eat_whitespace()
{
  istream & is = *p_is_;
  if (!bytes_avail_ && is.good()) {
    bytes_avail_ = is.readsome(buf_.data(), buf_.size());
  }
  char const* it = buf_.data();
  while (bytes_avail_ > 0 && ::isspace(*it)) {
    ++it;
    --bytes_avail_;
    if (!bytes_avail_ && is.good()) {
      bytes_avail_ = is.readsome(buf_.data(), buf_.size());
      it = buf_.data();
    }
  }
  if (bytes_avail_ > 0 && it != buf_.data()) {
    copy(it, it + bytes_avail_, buf_.data());
  }
}

void istream_facade::remove(streamsize n)
{
  BOOST_ASSERT( n <= bytes_avail_ );
  if (n > bytes_avail_) { n = bytes_avail_; }
  bytes_avail_ -= n;
  if (bytes_avail_ > 0) {
    char const* rest = buf_.data() + n;
    copy(rest, rest + bytes_avail_, buf_.data());
  }
}

void istream_facade::remove_until(const char * it)
{
  remove(it - buf_.data());
}

// istream_ijsource

class istream_ijsource : public ijsource
{
public:
  istream_ijsource(shared_ptr<istream_facade> const& p_is,
                   shared_ptr<istream_parser> const& p_p)
    : p_is_(p_is)
    , p_parser_(p_p)
  {
    if (!p_is_ || !p_parser_) {
      BOOST_THROW_EXCEPTION(bad_alloc());
    }
  }

private:
  void induce();

  ijstate & do_state() override { return *p_is_; }
  ijstate const& do_state() const override { return *p_is_; }

  ijpair & do_ref() override { induce(); return p_parser_->result(); }

  bool do_is_terminator() override { induce(); return !p_parser_->is_parsed(); }

  void do_advance() override { induce(); p_parser_->clear(); }

  bool do_expecting() override;

  shared_ptr<istream_facade> p_is_;
  shared_ptr<istream_parser> p_parser_;
};

void istream_ijsource::induce()
{
  while (this->expecting()) {
    p_is_->peek();
  }
}

bool istream_ijsource::do_expecting()
{
  p_parser_->parse(p_is_);
  return !p_parser_->is_parsed() && p_is_->good();
}

shared_ptr<ijsource>
    make_stream_ijsource(shared_ptr<istream_facade> const& p_is,
                         shared_ptr<istream_parser> const& p_p)
{
  return make_shared<istream_ijsource>(p_is, p_p);
}

// streaming_node

class streaming_node : public ijpair
{
public:
  streaming_node(shared_ptr<istream_facade> const& p_is,
                 shared_ptr<istream_parser> const& p_p)
    : p_is_(p_is)
    , p_parser_(p_p)
  {
    if (!p_is_ || !p_parser_) {
      BOOST_THROW_EXCEPTION(bad_alloc());
    }
  }

private:
  ijstate & do_state() override { return *p_is_; }
  ijstate const& do_state() const override { return *p_is_; }

  json_type do_type() const override { return json_type::jarray; }

  void do_parse(int64_t &) override { failout(); }
  void do_parse(double &) override { failout(); }
  void do_parse(bool &) override { failout(); }
  void do_parse(std::string &) override { failout(); }
  void do_parse(buffer_iterator) override { failout(); }

  ijarray do_begin_array() override;
  ijobject do_begin_object() { failout(); return ijobject(); }

  std::string do_key() const { BOOST_ASSERT(false); return ""; }

  void failout() { this->set_failbit(); }

  shared_ptr<istream_facade> p_is_;
public:
  shared_ptr<istream_parser> p_parser_;
};

ijarray streaming_node::do_begin_array()
{
  return p_parser_->result().array();
}

// streaming_parser

class streaming_parser : public istream_parser
{
public:
    streaming_parser(shared_ptr<istream_facade> const& p_is,
                     istream_parser_factory const& fallback)
      : node_(p_is, factory(p_is))
    {}

private:
  void do_clear() override;
  void do_parse(std::shared_ptr<istream_facade> const& p_is) override;
  bool do_is_parsed() const override;
  ijpair & do_result() override;

  streaming_node node_;
};

void streaming_parser::do_clear()
{
  node_.p_parser_->clear();
}

void streaming_parser::do_parse(std::shared_ptr<istream_facade> const& p_is)
{
  node_.p_parser_->parse(p_is);
}

bool streaming_parser::do_is_parsed() const
{
  return node_.p_parser_->is_parsed();
}

ijpair & streaming_parser::do_result()
{
  return node_;
}

shared_ptr<istream_parser>
    make_streaming_parser(shared_ptr<istream_facade> const& p_is,
                          istream_parser_factory const& fallback)
{
  return make_shared<streaming_parser>(p_is, fallback);
}

} // namespace

<commit_msg>missing modifications<commit_after>#include <jios/istream_ij.hpp>

#include <boost/throw_exception.hpp>
#include <boost/core/null_deleter.hpp>

using namespace std;

namespace jios {

// istream_facade

istream_facade::istream_facade(shared_ptr<istream> const& p_is)
  : p_is_(p_is)
  , buf_(4096)
  , bytes_avail_(0)
{
  if (!p_is_) {
    BOOST_THROW_EXCEPTION(bad_alloc());
  }
}

istream_facade::istream_facade(istream & is)
  : p_is_(&is, boost::null_deleter())
  , buf_(4096)
  , bytes_avail_(0)
{
}

streamsize istream_facade::avail()
{
  if (!bytes_avail_ && p_is_->good()) {
    bytes_avail_ = p_is_->readsome(buf_.data(), buf_.size());
  }
  return bytes_avail_;
}

void istream_facade::eat_whitespace()
{
  istream & is = *p_is_;
  if (!bytes_avail_ && is.good()) {
    bytes_avail_ = is.readsome(buf_.data(), buf_.size());
  }
  char const* it = buf_.data();
  while (bytes_avail_ > 0 && ::isspace(*it)) {
    ++it;
    --bytes_avail_;
    if (!bytes_avail_ && is.good()) {
      bytes_avail_ = is.readsome(buf_.data(), buf_.size());
      it = buf_.data();
    }
  }
  if (bytes_avail_ > 0 && it != buf_.data()) {
    copy(it, it + bytes_avail_, buf_.data());
  }
}

void istream_facade::remove(streamsize n)
{
  BOOST_ASSERT( n <= bytes_avail_ );
  if (n > bytes_avail_) { n = bytes_avail_; }
  bytes_avail_ -= n;
  if (bytes_avail_ > 0) {
    char const* rest = buf_.data() + n;
    copy(rest, rest + bytes_avail_, buf_.data());
  }
}

void istream_facade::remove_until(const char * it)
{
  remove(it - buf_.data());
}

// istream_ijsource

class istream_ijsource : public ijsource
{
public:
  istream_ijsource(shared_ptr<istream_facade> const& p_is,
                   shared_ptr<istream_parser> const& p_p)
    : p_is_(p_is)
    , p_parser_(p_p)
  {
    if (!p_is_ || !p_parser_) {
      BOOST_THROW_EXCEPTION(bad_alloc());
    }
  }

private:
  void induce();

  ijstate & do_state() override { return *p_is_; }
  ijstate const& do_state() const override { return *p_is_; }

  ijpair & do_ref() override { induce(); return p_parser_->result(); }

  bool do_is_terminator() override { induce(); return !p_parser_->is_parsed(); }

  void do_advance() override { induce(); p_parser_->clear(); }

  bool do_expecting() override;

  shared_ptr<istream_facade> p_is_;
  shared_ptr<istream_parser> p_parser_;
};

void istream_ijsource::induce()
{
  while (this->expecting()) {
    p_is_->peek();
  }
}

bool istream_ijsource::do_expecting()
{
  p_parser_->parse(p_is_);
  return !p_parser_->is_parsed() && p_is_->good();
}

shared_ptr<ijsource>
    make_stream_ijsource(shared_ptr<istream_facade> const& p_is,
                         shared_ptr<istream_parser> const& p_p)
{
  return make_shared<istream_ijsource>(p_is, p_p);
}

// streaming_node

class streaming_node : public ijpair
{
public:
  streaming_node(shared_ptr<istream_facade> const& p_is,
                 shared_ptr<istream_parser> const& p_p)
    : p_is_(p_is)
    , p_parser_(p_p)
  {
    if (!p_is_ || !p_parser_) {
      BOOST_THROW_EXCEPTION(bad_alloc());
    }
  }

private:
  ijstate & do_state() override { return *p_is_; }
  ijstate const& do_state() const override { return *p_is_; }

  json_type do_type() const override { return json_type::jarray; }

  void do_parse(int64_t &) override { failout(); }
  void do_parse(double &) override { failout(); }
  void do_parse(bool &) override { failout(); }
  void do_parse(std::string &) override { failout(); }
  void do_parse(buffer_iterator) override { failout(); }

  ijarray do_begin_array() override;
  ijobject do_begin_object() { failout(); return ijobject(); }

  std::string do_key() const { BOOST_ASSERT(false); return ""; }

  void failout() { this->set_failbit(); }

  shared_ptr<istream_facade> p_is_;
public:
  shared_ptr<istream_parser> p_parser_;
};

ijarray streaming_node::do_begin_array()
{
  return p_parser_->result().array();
}

// streaming_parser

class streaming_parser : public istream_parser
{
public:
    streaming_parser(shared_ptr<istream_facade> const& p_is,
                     istream_parser_factory const& fallback)
      : node_(p_is, fallback(p_is))
    {}

private:
  void do_clear() override;
  void do_parse(std::shared_ptr<istream_facade> const& p_is) override;
  bool do_is_parsed() const override;
  ijpair & do_result() override;

  streaming_node node_;
};

void streaming_parser::do_clear()
{
  node_.p_parser_->clear();
}

void streaming_parser::do_parse(std::shared_ptr<istream_facade> const& p_is)
{
  node_.p_parser_->parse(p_is);
}

bool streaming_parser::do_is_parsed() const
{
  return node_.p_parser_->is_parsed();
}

ijpair & streaming_parser::do_result()
{
  return node_;
}

shared_ptr<istream_parser>
    make_streaming_parser(shared_ptr<istream_facade> const& p_is,
                          istream_parser_factory const& fallback)
{
  return make_shared<streaming_parser>(p_is, fallback);
}

} // namespace

<|endoftext|>


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

#include "base/message_pump_libevent.h"

#include <errno.h>
#include <fcntl.h>

#include "base/logging.h"
#include "base/scoped_nsautorelease_pool.h"
#include "base/time.h"
#include "third_party/libevent/event.h"

namespace base {

// Return 0 on success
// Too small a function to bother putting in a library?
static int SetNonBlocking(int fd) {
  int flags = fcntl(fd, F_GETFL, 0);
  if (flags == -1)
    flags = 0;
  return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}

MessagePumpLibevent::FileDescriptorWatcher::FileDescriptorWatcher()
    : is_persistent_(false),
      event_(NULL) {
}

MessagePumpLibevent::FileDescriptorWatcher::~FileDescriptorWatcher() {
  if (event_.get()) {
    StopWatchingFileDescriptor();
  }
}

void MessagePumpLibevent::FileDescriptorWatcher::Init(event *e,
                                                      bool is_persistent) {
  DCHECK(e);
  DCHECK(event_.get() == NULL);

  is_persistent_ = is_persistent;
  event_.reset(e);
}

event *MessagePumpLibevent::FileDescriptorWatcher::ReleaseEvent() {
  return event_.release();
}

bool MessagePumpLibevent::FileDescriptorWatcher::StopWatchingFileDescriptor() {
  if (event_.get() == NULL) {
    return true;
  }

  // event_del() is a no-op of the event isn't active.
  return (event_del(event_.get()) == 0);
}

// Called if a byte is received on the wakeup pipe.
void MessagePumpLibevent::OnWakeup(int socket, short flags, void* context) {
  base::MessagePumpLibevent* that =
              static_cast<base::MessagePumpLibevent*>(context);
  DCHECK(that->wakeup_pipe_out_ == socket);

  // Remove and discard the wakeup byte.
  char buf;
  int nread = read(socket, &buf, 1);
  DCHECK(nread == 1);
  // Tell libevent to break out of inner loop.
  event_base_loopbreak(that->event_base_);
}

MessagePumpLibevent::MessagePumpLibevent()
    : keep_running_(true),
      in_run_(false),
      event_base_(event_base_new()),
      wakeup_pipe_in_(-1),
      wakeup_pipe_out_(-1) {
  if (!Init())
     NOTREACHED();
}

bool MessagePumpLibevent::Init() {
  int fds[2];
  if (pipe(fds)) {
    DLOG(ERROR) << "pipe() failed, errno: " << errno;
    return false;
  }
  if (SetNonBlocking(fds[0])) {
    DLOG(ERROR) << "SetNonBlocking for pipe fd[0] failed, errno: " << errno;
    return false;
  }
  if (SetNonBlocking(fds[1])) {
    DLOG(ERROR) << "SetNonBlocking for pipe fd[1] failed, errno: " << errno;
    return false;
  }
  wakeup_pipe_out_ = fds[0];
  wakeup_pipe_in_ = fds[1];

  wakeup_event_ = new event;
  event_set(wakeup_event_, wakeup_pipe_out_, EV_READ | EV_PERSIST,
            OnWakeup, this);
  event_base_set(event_base_, wakeup_event_);

  if (event_add(wakeup_event_, 0))
    return false;
  return true;
}

MessagePumpLibevent::~MessagePumpLibevent() {
  DCHECK(wakeup_event_);
  DCHECK(event_base_);
  event_del(wakeup_event_);
  delete wakeup_event_;
  if (wakeup_pipe_in_ >= 0)
    close(wakeup_pipe_in_);
  if (wakeup_pipe_out_ >= 0)
    close(wakeup_pipe_out_);
  event_base_free(event_base_);
}

bool MessagePumpLibevent::WatchFileDescriptor(int fd,
                                              bool persistent,
                                              Mode mode,
                                              FileDescriptorWatcher *controller,
                                              Watcher *delegate) {
  DCHECK(fd > 0);
  DCHECK(controller);
  DCHECK(delegate);
  DCHECK(mode == WATCH_READ || mode == WATCH_WRITE || mode == WATCH_READ_WRITE);

  int event_mask = persistent ? EV_PERSIST : 0;
  if ((mode & WATCH_READ) != 0) {
    event_mask |= EV_READ;
  }
  if ((mode & WATCH_WRITE) != 0) {
    event_mask |= EV_WRITE;
  }

  // |should_delete_event| is true if we're modifying an event that's currently
  // active in |controller|.
  // If we're modifying an existing event and there's an error then we need to
  // tell libevent to clean it up via event_delete() before returning.
  bool should_delete_event = true;
  scoped_ptr<event> evt(controller->ReleaseEvent());
  if (evt.get() == NULL) {
    should_delete_event = false;
    // Ownership is transferred to the controller.
    evt.reset(new event);
  }

  // Set current interest mask and message pump for this event.
  event_set(evt.get(), fd, event_mask, OnLibeventNotification,
            delegate);

  // Tell libevent which message pump this socket will belong to when we add it.
  if (event_base_set(event_base_, evt.get()) != 0) {
    if (should_delete_event) {
      event_del(evt.get());
    }
    return false;
  }

  // Add this socket to the list of monitored sockets.
  if (event_add(evt.get(), NULL) != 0) {
    if (should_delete_event) {
      event_del(evt.get());
    }
    return false;
  }

  // Transfer ownership of e to controller.
  controller->Init(evt.release(), persistent);
  return true;
}

void MessagePumpLibevent::OnLibeventNotification(int fd, short flags,
                                                 void* context) {
  Watcher* watcher = static_cast<Watcher*>(context);

  if (flags & EV_WRITE) {
    watcher->OnFileCanWriteWithoutBlocking(fd);
  }
  if (flags & EV_READ) {
    watcher->OnFileCanReadWithoutBlocking(fd);
  }
}

// Reentrant!
void MessagePumpLibevent::Run(Delegate* delegate) {
  DCHECK(keep_running_) << "Quit must have been called outside of Run!";

  bool old_in_run = in_run_;
  in_run_ = true;

  for (;;) {
    ScopedNSAutoreleasePool autorelease_pool;

    bool did_work = delegate->DoWork();
    if (!keep_running_)
      break;

    did_work |= delegate->DoDelayedWork(&delayed_work_time_);
    if (!keep_running_)
      break;

    if (did_work)
      continue;

    did_work = delegate->DoIdleWork();
    if (!keep_running_)
      break;

    if (did_work)
      continue;

    // EVLOOP_ONCE tells libevent to only block once,
    // but to service all pending events when it wakes up.
    if (delayed_work_time_.is_null()) {
      event_base_loop(event_base_, EVLOOP_ONCE);
    } else {
      TimeDelta delay = delayed_work_time_ - Time::Now();
      if (delay > TimeDelta()) {
        struct timeval poll_tv;
        poll_tv.tv_sec = delay.InSeconds();
        poll_tv.tv_usec = delay.InMicroseconds() % Time::kMicrosecondsPerSecond;
        event_base_loopexit(event_base_, &poll_tv);
        event_base_loop(event_base_, EVLOOP_ONCE);
      } else {
        // It looks like delayed_work_time_ indicates a time in the past, so we
        // need to call DoDelayedWork now.
        delayed_work_time_ = Time();
      }
    }
  }

  keep_running_ = true;
  in_run_ = old_in_run;
}

void MessagePumpLibevent::Quit() {
  DCHECK(in_run_);
  // Tell both libevent and Run that they should break out of their loops.
  keep_running_ = false;
  ScheduleWork();
}

void MessagePumpLibevent::ScheduleWork() {
  // Tell libevent (in a threadsafe way) that it should break out of its loop.
  char buf = 0;
  int nwrite = write(wakeup_pipe_in_, &buf, 1);
  DCHECK(nwrite == 1);
}

void MessagePumpLibevent::ScheduleDelayedWork(const Time& delayed_work_time) {
  // We know that we can't be blocked on Wait right now since this method can
  // only be called on the same thread as Run, so we only need to update our
  // record of how long to sleep when we do sleep.
  delayed_work_time_ = delayed_work_time;
}

}  // namespace base
<commit_msg>Minor DCHECK cleanups in libevent. DCHECK=>DCHECK_EQ where possible. Change a DCHECK not to fire on write() returning -1 && errno==EAGAIN, since this happens normally under heavy load. Review URL: http://codereview.chromium.org/42295<commit_after>// Copyright (c) 2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/message_pump_libevent.h"

#include <errno.h>
#include <fcntl.h>

#include "base/logging.h"
#include "base/scoped_nsautorelease_pool.h"
#include "base/time.h"
#include "third_party/libevent/event.h"

namespace base {

// Return 0 on success
// Too small a function to bother putting in a library?
static int SetNonBlocking(int fd) {
  int flags = fcntl(fd, F_GETFL, 0);
  if (flags == -1)
    flags = 0;
  return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}

MessagePumpLibevent::FileDescriptorWatcher::FileDescriptorWatcher()
    : is_persistent_(false),
      event_(NULL) {
}

MessagePumpLibevent::FileDescriptorWatcher::~FileDescriptorWatcher() {
  if (event_.get()) {
    StopWatchingFileDescriptor();
  }
}

void MessagePumpLibevent::FileDescriptorWatcher::Init(event *e,
                                                      bool is_persistent) {
  DCHECK(e);
  DCHECK(event_.get() == NULL);

  is_persistent_ = is_persistent;
  event_.reset(e);
}

event *MessagePumpLibevent::FileDescriptorWatcher::ReleaseEvent() {
  return event_.release();
}

bool MessagePumpLibevent::FileDescriptorWatcher::StopWatchingFileDescriptor() {
  if (event_.get() == NULL) {
    return true;
  }

  // event_del() is a no-op of the event isn't active.
  return (event_del(event_.get()) == 0);
}

// Called if a byte is received on the wakeup pipe.
void MessagePumpLibevent::OnWakeup(int socket, short flags, void* context) {
  base::MessagePumpLibevent* that =
              static_cast<base::MessagePumpLibevent*>(context);
  DCHECK(that->wakeup_pipe_out_ == socket);

  // Remove and discard the wakeup byte.
  char buf;
  int nread = read(socket, &buf, 1);
  DCHECK_EQ(nread, 1);
  // Tell libevent to break out of inner loop.
  event_base_loopbreak(that->event_base_);
}

MessagePumpLibevent::MessagePumpLibevent()
    : keep_running_(true),
      in_run_(false),
      event_base_(event_base_new()),
      wakeup_pipe_in_(-1),
      wakeup_pipe_out_(-1) {
  if (!Init())
     NOTREACHED();
}

bool MessagePumpLibevent::Init() {
  int fds[2];
  if (pipe(fds)) {
    DLOG(ERROR) << "pipe() failed, errno: " << errno;
    return false;
  }
  if (SetNonBlocking(fds[0])) {
    DLOG(ERROR) << "SetNonBlocking for pipe fd[0] failed, errno: " << errno;
    return false;
  }
  if (SetNonBlocking(fds[1])) {
    DLOG(ERROR) << "SetNonBlocking for pipe fd[1] failed, errno: " << errno;
    return false;
  }
  wakeup_pipe_out_ = fds[0];
  wakeup_pipe_in_ = fds[1];

  wakeup_event_ = new event;
  event_set(wakeup_event_, wakeup_pipe_out_, EV_READ | EV_PERSIST,
            OnWakeup, this);
  event_base_set(event_base_, wakeup_event_);

  if (event_add(wakeup_event_, 0))
    return false;
  return true;
}

MessagePumpLibevent::~MessagePumpLibevent() {
  DCHECK(wakeup_event_);
  DCHECK(event_base_);
  event_del(wakeup_event_);
  delete wakeup_event_;
  if (wakeup_pipe_in_ >= 0)
    close(wakeup_pipe_in_);
  if (wakeup_pipe_out_ >= 0)
    close(wakeup_pipe_out_);
  event_base_free(event_base_);
}

bool MessagePumpLibevent::WatchFileDescriptor(int fd,
                                              bool persistent,
                                              Mode mode,
                                              FileDescriptorWatcher *controller,
                                              Watcher *delegate) {
  DCHECK(fd > 0);
  DCHECK(controller);
  DCHECK(delegate);
  DCHECK(mode == WATCH_READ || mode == WATCH_WRITE || mode == WATCH_READ_WRITE);

  int event_mask = persistent ? EV_PERSIST : 0;
  if ((mode & WATCH_READ) != 0) {
    event_mask |= EV_READ;
  }
  if ((mode & WATCH_WRITE) != 0) {
    event_mask |= EV_WRITE;
  }

  // |should_delete_event| is true if we're modifying an event that's currently
  // active in |controller|.
  // If we're modifying an existing event and there's an error then we need to
  // tell libevent to clean it up via event_delete() before returning.
  bool should_delete_event = true;
  scoped_ptr<event> evt(controller->ReleaseEvent());
  if (evt.get() == NULL) {
    should_delete_event = false;
    // Ownership is transferred to the controller.
    evt.reset(new event);
  }

  // Set current interest mask and message pump for this event.
  event_set(evt.get(), fd, event_mask, OnLibeventNotification,
            delegate);

  // Tell libevent which message pump this socket will belong to when we add it.
  if (event_base_set(event_base_, evt.get()) != 0) {
    if (should_delete_event) {
      event_del(evt.get());
    }
    return false;
  }

  // Add this socket to the list of monitored sockets.
  if (event_add(evt.get(), NULL) != 0) {
    if (should_delete_event) {
      event_del(evt.get());
    }
    return false;
  }

  // Transfer ownership of e to controller.
  controller->Init(evt.release(), persistent);
  return true;
}

void MessagePumpLibevent::OnLibeventNotification(int fd, short flags,
                                                 void* context) {
  Watcher* watcher = static_cast<Watcher*>(context);

  if (flags & EV_WRITE) {
    watcher->OnFileCanWriteWithoutBlocking(fd);
  }
  if (flags & EV_READ) {
    watcher->OnFileCanReadWithoutBlocking(fd);
  }
}

// Reentrant!
void MessagePumpLibevent::Run(Delegate* delegate) {
  DCHECK(keep_running_) << "Quit must have been called outside of Run!";

  bool old_in_run = in_run_;
  in_run_ = true;

  for (;;) {
    ScopedNSAutoreleasePool autorelease_pool;

    bool did_work = delegate->DoWork();
    if (!keep_running_)
      break;

    did_work |= delegate->DoDelayedWork(&delayed_work_time_);
    if (!keep_running_)
      break;

    if (did_work)
      continue;

    did_work = delegate->DoIdleWork();
    if (!keep_running_)
      break;

    if (did_work)
      continue;

    // EVLOOP_ONCE tells libevent to only block once,
    // but to service all pending events when it wakes up.
    if (delayed_work_time_.is_null()) {
      event_base_loop(event_base_, EVLOOP_ONCE);
    } else {
      TimeDelta delay = delayed_work_time_ - Time::Now();
      if (delay > TimeDelta()) {
        struct timeval poll_tv;
        poll_tv.tv_sec = delay.InSeconds();
        poll_tv.tv_usec = delay.InMicroseconds() % Time::kMicrosecondsPerSecond;
        event_base_loopexit(event_base_, &poll_tv);
        event_base_loop(event_base_, EVLOOP_ONCE);
      } else {
        // It looks like delayed_work_time_ indicates a time in the past, so we
        // need to call DoDelayedWork now.
        delayed_work_time_ = Time();
      }
    }
  }

  keep_running_ = true;
  in_run_ = old_in_run;
}

void MessagePumpLibevent::Quit() {
  DCHECK(in_run_);
  // Tell both libevent and Run that they should break out of their loops.
  keep_running_ = false;
  ScheduleWork();
}

void MessagePumpLibevent::ScheduleWork() {
  // Tell libevent (in a threadsafe way) that it should break out of its loop.
  char buf = 0;
  int nwrite = write(wakeup_pipe_in_, &buf, 1);
  DCHECK(nwrite == 1 || errno == EAGAIN)
      << "[nwrite:" << nwrite << "] [errno:" << errno << "]";
}

void MessagePumpLibevent::ScheduleDelayedWork(const Time& delayed_work_time) {
  // We know that we can't be blocked on Wait right now since this method can
  // only be called on the same thread as Run, so we only need to update our
  // record of how long to sleep when we do sleep.
  delayed_work_time_ = delayed_work_time;
}

}  // namespace base
<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2014 Rapptz

// 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.

#ifndef JSONPP_PARSER_HPP
#define JSONPP_PARSER_HPP

#include "error.hpp"
#include "value.hpp"
#include <cstring>
#include <iosfwd>

namespace json {
inline namespace v1 {
struct parser {
private:
    unsigned line = 1;
    unsigned column = 1;

    const char* skip_white_space(const char* str) {
        while(*str && isspace(*str)) {
            ++str;
            ++column;
            if(*str == '\n') {
                ++line;
                column = 0;
            }
        }
        return str;
    }

    const char* parse_value(const char* str, value& v) {
        const char* s = skip_white_space(str);
        if(!s) {
            throw parser_error("unexpected EOF found", line, column);
        }

        if(isdigit(*s) || *s == '+' || *s == '-') {
            s = parse_number(s, v);
        }
        else {
            switch(*s) {
            case 'n':
                s = parse_null(s, v);
                break;
            case '"':
                s = parse_string(s, v);
                break;
            case 't':
            case 'f':
                s = parse_bool(s, v);
                break;
            case '[':
                s = parse_array(s, v);
                break;
            case '{':
                s = parse_object(s, v);
                break;
            }
        }

        return skip_white_space(s);
    }

    const char* parse_null(const char* str, value& v) {
        static const char null_str[] = "null";
        if(!str) {
            throw parser_error("expected null, received EOF instead", line, column);
        }

        if(std::strncmp(str, null_str, sizeof(null_str) - 1) != 0) {
            throw parser_error("expected null not found", line, column);
        }

        v = nullptr;
        str = str + sizeof(null_str) - 1;
        column += sizeof(null_str);
        return str;
    }

    const char* parse_number(const char* str, value& v) {
        static const std::string lookup = "0123456789eE+-.";
        const char* begin = str;
        if(!begin) {
            throw parser_error("expected number, received EOF instead", line, column);
        }

        while(lookup.find(*str) != std::string::npos) {
            ++str;
        }

        double val = 0.0;
        try {
            std::string temp(begin, str);
            val = std::stod(temp);
            column += temp.size() + 1;
        }
        catch(const std::exception& e) {
            throw parser_error("number could not be parsed properly", line, column);
        }

        v = val;
        return str;
    }

    template<typename Value>
    const char* parse_string(const char* str, Value& v) {
        const char* end = str + 1;
        if(!end) {
            throw parser_error("expected string, received EOF instead", line, column);
        }

        while(*end && *end != '"') {
            ++end;
        }

        if(!end) {
            throw parser_error("unescaped string sequence found", line, column);
        }

        auto&& temp = std::string(str + 1, end);
        column += temp.size() + 1;
        v = temp;
        ++end;
        return end;
    }

    const char* parse_bool(const char* str, value& v) {
        if(!str) {
            throw parser_error("expected boolean, received EOF instead", line, column);
        }

        bool expected_true = *str == 't';
        const char* boolean = expected_true ? "true" : "false";
        const size_t len = expected_true ? 4 : 5;

        if(std::strncmp(str, boolean, len) != 0) {
            throw parser_error("expected boolean not found", line, column);
        }

        v = expected_true;
        str = str + len;
        column += len;
        return str;
    }

    const char* parse_array(const char* str, value& v) {
        const char *s = str + 1;
        array arr;
        value elem;

        while (*s && *s != ']') {
            s = parse_value(s, elem);
            if(*s != ',') {
                if(*s != ']') {
                    throw parser_error("missing comma", line, column);
                }
            }
            else if(*s == ',') {
                ++s;
            }

            arr.push_back(elem);
        }
        v = arr;
        return *s == ']' ? s + 1 : s;
    }

    const char* parse_object(const char* str, value& v) {
        const char* s = str + 1;
        object obj;
        std::string key;
        value elem;

        while(*s && *s != '}') {
            s = skip_white_space(s);
            if(*s != '"') {
                throw parser_error("expected string as key not found", line, column);
            }
            s = parse_string(s, key);
            s = skip_white_space(s);

            if(*s != ':') {
                throw parser_error("missing semicolon", line, column);
            }
            ++s;
            s = parse_value(s, elem);

            if(*s != ',') {
                if(*s != '}') {
                    throw parser_error("missing comma", line, column);
                }
            }
            ++s;
            obj.emplace(key, elem);
        }

        v = obj;
        return *s == '}' ? s + 1 : s;
    }
public:
    parser() = default;
    parser(const std::string& str, value& v) {
        parse(str, v);
    }

    template<typename IStream, DisableIf<is_string<IStream>> = 0>
    parser(IStream& in, value& v) {
        parse(in, v);
    }

    void parse(const std::string& str, value& v) {
        line = 1;
        column = 1;
        parse_value(str.c_str(), v);
    }

    template<typename IStream, DisableIf<is_string<IStream>> = 0>
    void parse(IStream& in, value& v) {
        static_assert(std::is_base_of<std::istream, IStream>::value, "Input stream passed must inherit from std::istream");
        if(in) {
            in.seekg(0, in.end);
            auto size = in.tellg();
            in.seekg(0, in.beg);
            std::string str;
            str.resize(size);
            in.read(&str[0], size);
            parse(str, v);
        }
    }
};
} // v1
} // json

#endif // JSONPP_PARSER_HPP
<commit_msg>Fix parsing error with objects. Add unexpected token diagnostics.<commit_after>// The MIT License (MIT)

// Copyright (c) 2014 Rapptz

// 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.

#ifndef JSONPP_PARSER_HPP
#define JSONPP_PARSER_HPP

#include "error.hpp"
#include "value.hpp"
#include <cstring>
#include <iosfwd>

namespace json {
inline namespace v1 {
struct parser {
private:
    unsigned line = 1;
    unsigned column = 1;

    const char* skip_white_space(const char* str) {
        while(*str && isspace(*str)) {
            ++str;
            ++column;
            if(*str == '\n') {
                ++line;
                column = 0;
            }
        }
        return str;
    }

    const char* parse_value(const char* str, value& v) {
        const char* s = skip_white_space(str);
        if(!s) {
            throw parser_error("unexpected EOF found", line, column);
        }

        if(isdigit(*s) || *s == '+' || *s == '-') {
            s = parse_number(s, v);
        }
        else {
            switch(*s) {
            case 'n':
                s = parse_null(s, v);
                break;
            case '"':
                s = parse_string(s, v);
                break;
            case 't':
            case 'f':
                s = parse_bool(s, v);
                break;
            case '[':
                s = parse_array(s, v);
                break;
            case '{':
                s = parse_object(s, v);
                break;
            default:
                throw parser_error("unexpected token found", line, column);
                break;
            }
        }

        static const std::string accepted_characters = ",[]{}:";
        s = skip_white_space(s);
        if(*s && accepted_characters.find(*s) == std::string::npos) {
            throw parser_error("unexpected token found", line, column);
        }

        return s;
    }

    const char* parse_null(const char* str, value& v) {
        static const char null_str[] = "null";
        if(!str) {
            throw parser_error("expected null, received EOF instead", line, column);
        }

        if(std::strncmp(str, null_str, sizeof(null_str) - 1) != 0) {
            throw parser_error("expected null not found", line, column);
        }

        v = nullptr;
        str = str + sizeof(null_str) - 1;
        column += sizeof(null_str);
        return str;
    }

    const char* parse_number(const char* str, value& v) {
        static const std::string lookup = "0123456789eE+-.";
        const char* begin = str;
        if(!begin) {
            throw parser_error("expected number, received EOF instead", line, column);
        }

        while(lookup.find(*str) != std::string::npos) {
            ++str;
        }

        double val = 0.0;
        try {
            std::string temp(begin, str);
            val = std::stod(temp);
            column += temp.size() + 1;
        }
        catch(const std::exception& e) {
            throw parser_error("number could not be parsed properly", line, column);
        }

        v = val;
        return str;
    }

    template<typename Value>
    const char* parse_string(const char* str, Value& v) {
        const char* end = str + 1;
        if(!end) {
            throw parser_error("expected string, received EOF instead", line, column);
        }

        while(*end && *end != '"') {
            ++end;
        }

        if(!end) {
            throw parser_error("unescaped string sequence found", line, column);
        }

        auto&& temp = std::string(str + 1, end);
        column += temp.size() + 1;
        v = temp;
        ++end;
        return end;
    }

    const char* parse_bool(const char* str, value& v) {
        if(!str) {
            throw parser_error("expected boolean, received EOF instead", line, column);
        }

        bool expected_true = *str == 't';
        const char* boolean = expected_true ? "true" : "false";
        const size_t len = expected_true ? 4 : 5;

        if(std::strncmp(str, boolean, len) != 0) {
            throw parser_error("expected boolean not found", line, column);
        }

        v = expected_true;
        str = str + len;
        column += len;
        return str;
    }

    const char* parse_array(const char* str, value& v) {
        const char *s = str + 1;
        array arr;
        value elem;

        while (*s && *s != ']') {
            s = parse_value(s, elem);
            if(*s != ',') {
                if(*s != ']') {
                    throw parser_error("missing comma", line, column);
                }
            }
            else if(*s == ',') {
                ++s;
            }

            arr.push_back(elem);
        }
        v = arr;
        return *s == ']' ? s + 1 : s;
    }

    const char* parse_object(const char* str, value& v) {
        const char* s = str + 1;
        object obj;
        std::string key;
        value elem;

        while(*s) {
            s = skip_white_space(s);

            // empty object
            if(*s == '}') {
                break;
            }

            if(*s != '"') {
                throw parser_error("expected string as key not found", line, column);
            }
            s = parse_string(s, key);
            s = skip_white_space(s);

            if(*s != ':') {
                throw parser_error("missing semicolon", line, column);
            }
            ++s;
            s = parse_value(s, elem);

            if(*s != ',') {
                if(*s != '}') {
                    throw parser_error("missing comma", line, column);
                }
            }
            else if(*s == ',') {
                ++s;
            }
            obj.emplace(key, elem);
        }

        v = obj;
        return *s == '}' ? s + 1 : s;
    }
public:
    parser() = default;
    parser(const std::string& str, value& v) {
        parse(str, v);
    }

    template<typename IStream, DisableIf<is_string<IStream>> = 0>
    parser(IStream& in, value& v) {
        parse(in, v);
    }

    void parse(const std::string& str, value& v) {
        line = 1;
        column = 1;
        parse_value(str.c_str(), v);
    }

    template<typename IStream, DisableIf<is_string<IStream>> = 0>
    void parse(IStream& in, value& v) {
        static_assert(std::is_base_of<std::istream, IStream>::value, "Input stream passed must inherit from std::istream");
        if(in) {
            in.seekg(0, in.end);
            auto size = in.tellg();
            in.seekg(0, in.beg);
            std::string str;
            str.resize(size);
            in.read(&str[0], size);
            parse(str, v);
        }
    }
};
} // v1
} // json

#endif // JSONPP_PARSER_HPP
<|endoftext|>