<commit_before>#include "stdafx.h"
#include "Python.h"
#include "SQFReader.h"

using namespace std;

#define THROW_PARSEERROR(_msg_) \
{\
    throw ParseException(_msg_ + std::string(" near: ") + std::string(*start), *start);\
}

namespace SQFReader
{
    /*
    Note on reference counting in this parser:
    Because you can have arrays containing other python objects (which may
    themselves also be arrays, etc...), and the resulting object will be
    directly passed to Python code, these functions are operating on Python
    objects that have to have the reference counting handled manually instead
    of wrapping them into refcounting classes.
    */
    PyObject *decode_part(const char **start);

    // Returns a new PyObject reference
    inline PyObject *try_parse_number(const char **start)
    {
        const char *end = *start;
        char isFloat = false;

        if (*end == '-')
        {
            end++;
            if (*end == '-')
            {
                // Uhhh... "--5"?
                THROW_PARSEERROR("Error when parsing number");
            }
        }

        while ((*end >= '0' && *end <= '9') || *end == '.')
        {
            if (*end == '.')
            {
                if (isFloat)
                {
                    // '.' is present twice!
                    THROW_PARSEERROR("Error when parsing number");
                }
                isFloat = true;
            }
            end++;
        }

        std::string tmp_value(*start, end - *start);
        PyObject *number;
        if (!isFloat)
        {
            number = PyLong_FromString(tmp_value.c_str(), nullptr, 10);
        }
        else
        {
            double cDouble = atof(tmp_value.c_str());
            number = PyFloat_FromDouble(cDouble);
        }

        if (number == nullptr)
        {
            THROW_PARSEERROR("Error when parsing number");
        }

        *start = end;
        return number;
    }

    // Returns a new PyObject reference
    inline PyObject *try_parse_string_noescape(const char **start)
    {
        (*start)++;
        const char *end = *start;

        while (*end != '\'')
            end++;

        PyObject *retval = PyUnicode_FromStringAndSize(*start, end - *start);
        if (retval == nullptr)
        {
            THROW_PARSEERROR("Error when parsing single-quoted string");
        }

        *start = end + 1;
        return retval;
    }

    // Returns a new PyObject reference
    inline PyObject *try_parse_string_escape(const char **start)
    {
        (*start)++;
        int escapedCount = 0;
        const char *end = *start;

        // Compute the length of the real string
        for (;;end++)
        {
            if (*end == '\0')
            {
                THROW_PARSEERROR("Error when parsing double-quoted string: premature end");
            }

            if (*end == '"')
            {
                if (end[1] != '"')
                {
                    // End of SQF string
                    break;
                }
                escapedCount++;
                end++;
            }
        }

        std::ptrdiff_t realStringLength = end - *start - escapedCount;
        char *realString = new char[realStringLength + 1];
        char* rp = realString;

        // Unescape the string
        for (const char *p = *start;; p++, rp++)
        {
            if (*p == '"')
            {
                if (p[1] != '"')
                {
                    break;
                }
                p++;
            }
            *rp = *p;
        }
        realString[realStringLength] = '\0';

        std::ptrdiff_t len = rp - realString;
        PyObject *retval = PyUnicode_FromStringAndSize(realString, rp - realString);
        delete[] realString;

        if (retval == nullptr)
        {
            THROW_PARSEERROR("Error when parsing double-quoted string");
        }

        *start = end + 1;
        return retval;
    }

    // Returns a new PyObject reference
    inline PyObject *try_parse_true(const char **start)
    {
        if (((*start)[1] == 'R' || (*start)[1] == 'r') &&
            ((*start)[2] == 'U' || (*start)[2] == 'u') &&
            ((*start)[3] == 'E' || (*start)[3] == 'e'))
        {
            *start += 4;
            Py_RETURN_TRUE;
        }

        THROW_PARSEERROR("Error when parsing boolean");
    }

    // Returns a new PyObject reference
    inline PyObject *try_parse_false(const char **start)
    {
        if (((*start)[1] == 'A' || (*start)[1] == 'a') &&
            ((*start)[2] == 'L' || (*start)[2] == 'l') &&
            ((*start)[3] == 'S' || (*start)[3] == 's') &&
            ((*start)[4] == 'E' || (*start)[4] == 'e'))
        {
            *start += 5;
            Py_RETURN_FALSE;
        }

        THROW_PARSEERROR("Error when parsing boolean");
    }

    // Returns a new PyObject reference
    inline PyObject *try_parse_array(const char **start)
    {
        (*start)++;

        PyObject* list = PyList_New(0);
        if (list == nullptr)
        {
            THROW_PARSEERROR("Internal error when creating a list");
        }

        while(true)
        {
            if (**start == ']')
            {
                (*start)++;
                return list;
            }

            PyObject *obj;
            try
            {
                obj = decode_part(start);
            }
            catch (...)
            {
                Py_DECREF(list); // garbage-collect the list and its contents
                throw;
            }

            int retval = PyList_Append(list, obj); // Increases obj's refcount
            Py_DECREF(obj);
            if (retval != 0)
            {
                // The docs say that this raises a Python exception
                // Not sure how to act here
                Py_DECREF(list); // garbage-collect the list and its contents
                THROW_PARSEERROR("Internal error when appending to list");
            }

            while (**start == ' ')
                (*start)++;

            if (**start == ',')
            {
                (*start)++;
            }
            else if (**start != ']')
            {
                Py_DECREF(list); // garbage-collect the list and its contents
                THROW_PARSEERROR("Expected end of array");
            }
        }
    }

    // Returns a new PyObject reference
    PyObject *decode_part(const char **start)
    {
        // Drop whitespaces
        while (**start == ' ')
            (*start)++;

        if ((**start >= '0' && **start <= '9') || **start == '-')
        {
            return try_parse_number(start);
        }
        else if (**start == '[')
        {
            return try_parse_array(start);
        }
        else if (**start == '"')
        {
            return try_parse_string_escape(start);
        }
        else if (**start == '\'')
        {
            return try_parse_string_noescape(start);
        }
        else if (**start == 'T' || **start == 't')
        {
            return try_parse_true(start);
        }
        else if (**start == 'F' || **start == 'f')
        {
            return try_parse_false(start);
        }

        THROW_PARSEERROR("Unexpected character");
    }

    // Returns a new PyObject reference
    // IMPORTANT: The object MUST be Py_DECREF'ed after use to prevent leakage
    // Throws std::runtime_error on parse error with an explanation
    PyObject *decode(const char *sqf)
    {
        const char **start = &sqf;
        try
        {
            PyObject *obj = decode_part(start);

            // Check that the buffer is empty
            while (**start == ' ')
                (*start)++;

            if (**start != '\0')
            {
                Py_DECREF(obj);
                THROW_PARSEERROR("Unexpected character");
            }
            return obj;
        }
        catch (ParseException ex)
        {
            throw; // Rethrow. Prevents from being caught by (...) below
        }
        catch (...)
        {
            THROW_PARSEERROR("Unknown parse error");
        }
    }
}
<commit_msg>SQF parsing fix<commit_after>#include "stdafx.h"
#include "Python.h"
#include "SQFReader.h"

using namespace std;

#define THROW_PARSEERROR(_msg_) \
{\
    throw ParseException(_msg_ + std::string(" near: ") + std::string(*start), *start);\
}

namespace SQFReader
{
    /*
    Note on reference counting in this parser:
    Because you can have arrays containing other python objects (which may
    themselves also be arrays, etc...), and the resulting object will be
    directly passed to Python code, these functions are operating on Python
    objects that have to have the reference counting handled manually instead
    of wrapping them into refcounting classes.
    */
    PyObject *decode_part(const char **start);

    // Returns a new PyObject reference
    inline PyObject *try_parse_number(const char **start)
    {
        const char *end = *start;
        char isFloat = false;

        if (*end == '-')
        {
            end++;
            if (*end == '-')
            {
                // Uhhh... "--5"?
                THROW_PARSEERROR("Error when parsing number");
            }
        }

        while ((*end >= '0' && *end <= '9') || *end == '.')
        {
            if (*end == '.')
            {
                if (isFloat)
                {
                    // '.' is present twice!
                    THROW_PARSEERROR("Error when parsing number");
                }
                isFloat = true;
            }
            end++;
        }

        std::string tmp_value(*start, end - *start);
        PyObject *number;
        if (!isFloat)
        {
            number = PyLong_FromString(tmp_value.c_str(), nullptr, 10);
        }
        else
        {
            double cDouble = atof(tmp_value.c_str());
            number = PyFloat_FromDouble(cDouble);
        }

        if (number == nullptr)
        {
            THROW_PARSEERROR("Error when parsing number");
        }

        *start = end;
        return number;
    }

    // Returns a new PyObject reference
    inline PyObject *try_parse_string_noescape(const char **start)
    {
        (*start)++;
        const char *end = *start;

        while (*end != '\'')
            end++;

        PyObject *retval = PyUnicode_FromStringAndSize(*start, end - *start);
        if (retval == nullptr)
        {
            THROW_PARSEERROR("Error when parsing single-quoted string");
        }

        *start = end + 1;
        return retval;
    }

    // Returns a new PyObject reference
    inline PyObject *try_parse_string_escape(const char **start)
    {
        (*start)++;
        int escapedCount = 0;
        const char *end = *start;

        // Compute the length of the real string
        for (;;end++)
        {
            if (*end == '\0')
            {
                THROW_PARSEERROR("Error when parsing double-quoted string: premature end");
            }

            if (*end == '"')
            {
                if (end[1] != '"')
                {
                    // End of SQF string
                    break;
                }
                escapedCount++;
                end++;
            }
        }

        std::ptrdiff_t realStringLength = end - *start - escapedCount;
        char *realString = new char[realStringLength + 1];
        char* rp = realString;

        // Unescape the string
        for (const char *p = *start;; p++, rp++)
        {
            if (*p == '"')
            {
                if (p[1] != '"')
                {
                    break;
                }
                p++;
            }
            *rp = *p;
        }
        realString[realStringLength] = '\0';

        std::ptrdiff_t len = rp - realString;
        PyObject *retval = PyUnicode_FromStringAndSize(realString, rp - realString);
        delete[] realString;

        if (retval == nullptr)
        {
            THROW_PARSEERROR("Error when parsing double-quoted string");
        }

        *start = end + 1;
        return retval;
    }

    // Returns a new PyObject reference
    inline PyObject *try_parse_true(const char **start)
    {
        if (((*start)[1] == 'R' || (*start)[1] == 'r') &&
            ((*start)[2] == 'U' || (*start)[2] == 'u') &&
            ((*start)[3] == 'E' || (*start)[3] == 'e'))
        {
            *start += 4;
            Py_RETURN_TRUE;
        }

        THROW_PARSEERROR("Error when parsing boolean");
    }

    // Returns a new PyObject reference
    inline PyObject *try_parse_false(const char **start)
    {
        if (((*start)[1] == 'A' || (*start)[1] == 'a') &&
            ((*start)[2] == 'L' || (*start)[2] == 'l') &&
            ((*start)[3] == 'S' || (*start)[3] == 's') &&
            ((*start)[4] == 'E' || (*start)[4] == 'e'))
        {
            *start += 5;
            Py_RETURN_FALSE;
        }

        THROW_PARSEERROR("Error when parsing boolean");
    }

    // Returns a new PyObject reference
    inline PyObject *try_parse_array(const char **start)
    {
        (*start)++;

        PyObject* list = PyList_New(0);
        if (list == nullptr)
        {
            THROW_PARSEERROR("Internal error when creating a list");
        }

        while(true)
        {
            if (**start == ']')
            {
                (*start)++;
                return list;
            }

            PyObject *obj;
            try
            {
                obj = decode_part(start);
            }
            catch (...)
            {
                Py_DECREF(list); // garbage-collect the list and its contents
                throw;
            }

            int retval = PyList_Append(list, obj); // Increases obj's refcount (only if successful!)
            if (retval != 0)
            {
                // The docs say that this raises a Python exception
                // Not sure how to act here
                Py_DECREF(list); // garbage-collect the list and its contents
                THROW_PARSEERROR("Internal error when appending to list");
            }
            Py_DECREF(obj);

            while (**start == ' ')
                (*start)++;

            if (**start == ',')
            {
                (*start)++;
            }
            else if (**start != ']')
            {
                Py_DECREF(list); // garbage-collect the list and its contents
                THROW_PARSEERROR("Expected end of array");
            }
        }
    }

    // Returns a new PyObject reference
    PyObject *decode_part(const char **start)
    {
        // Drop whitespaces
        while (**start == ' ')
            (*start)++;

        if ((**start >= '0' && **start <= '9') || **start == '-')
        {
            return try_parse_number(start);
        }
        else if (**start == '[')
        {
            return try_parse_array(start);
        }
        else if (**start == '"')
        {
            return try_parse_string_escape(start);
        }
        else if (**start == '\'')
        {
            return try_parse_string_noescape(start);
        }
        else if (**start == 'T' || **start == 't')
        {
            return try_parse_true(start);
        }
        else if (**start == 'F' || **start == 'f')
        {
            return try_parse_false(start);
        }

        THROW_PARSEERROR("Unexpected character");
    }

    // Returns a new PyObject reference
    // IMPORTANT: The object MUST be Py_DECREF'ed after use to prevent leakage
    // Throws std::runtime_error on parse error with an explanation
    PyObject *decode(const char *sqf)
    {
        const char **start = &sqf;
        try
        {
            PyObject *obj = decode_part(start);

            // Check that the buffer is empty
            while (**start == ' ')
                (*start)++;

            if (**start != '\0')
            {
                Py_DECREF(obj);
                THROW_PARSEERROR("Unexpected character");
            }
            return obj;
        }
        catch (ParseException ex)
        {
            throw; // Rethrow. Prevents from being caught by (...) below
        }
        catch (...)
        {
            THROW_PARSEERROR("Unknown parse error");
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 Open Source Robotics Foundation
 *
 * 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 <string>
#include "ignition/transport/TopicUtils.hh"

using namespace ignition;
using namespace transport;

//////////////////////////////////////////////////
bool TopicUtils::IsValidTopic(const std::string &_topic)
{
  return IsValidNamespace(_topic) && (_topic != "");
}

//////////////////////////////////////////////////
bool TopicUtils::IsValidNamespace(const std::string &_ns)
{
  // The empty string or "/" are not valid.
  if (_ns == "/")
    return false;

 if (_ns.find("~") != std::string::npos)
    return false;

  // If the topic name has a white space is not valid.
  if (_ns.find(" ") != std::string::npos)
    return false;

  // It is not allowed to have two consecutive slashes.
  if (_ns.find("//") != std::string::npos)
    return false;

  return true;
}

//////////////////////////////////////////////////
bool TopicUtils::GetScopedName(const std::string &_ns,
  const std::string &_topic, std::string &_scoped)
{
  // Sanity check, first things first.
  if (!IsValidNamespace(_ns) || !IsValidTopic(_topic))
    return false;

  std::string ns = _ns;
  std::string topic = _topic;

  // If the namespace does not contain a trailing slash, append it.
  if (ns.back() != '/')
    ns.push_back('/');

  // If the namespace does not start with slash, add it.
  if (ns.front() != '/')
    ns.insert(0, 1, '/');

  // If the topic ends in "/", remove it.
  if (topic.back() == '/')
    topic.pop_back();

  // If the topic does starts with '/' is considered an absolute topic and the
  // namespace will not be prefixed.
  if (topic.front() == '/')
    _scoped = topic;
  else
    _scoped = ns + topic;

  return true;
}
<commit_msg>Fix spacing.<commit_after>/*
 * Copyright (C) 2014 Open Source Robotics Foundation
 *
 * 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 <string>
#include "ignition/transport/TopicUtils.hh"

using namespace ignition;
using namespace transport;

//////////////////////////////////////////////////
bool TopicUtils::IsValidTopic(const std::string &_topic)
{
  return IsValidNamespace(_topic) && (_topic != "");
}

//////////////////////////////////////////////////
bool TopicUtils::IsValidNamespace(const std::string &_ns)
{
  // The empty string or "/" are not valid.
  if (_ns == "/")
    return false;

  if (_ns.find("~") != std::string::npos)
    return false;

  // If the topic name has a white space is not valid.
  if (_ns.find(" ") != std::string::npos)
    return false;

  // It is not allowed to have two consecutive slashes.
  if (_ns.find("//") != std::string::npos)
    return false;

  return true;
}

//////////////////////////////////////////////////
bool TopicUtils::GetScopedName(const std::string &_ns,
  const std::string &_topic, std::string &_scoped)
{
  // Sanity check, first things first.
  if (!IsValidNamespace(_ns) || !IsValidTopic(_topic))
    return false;

  std::string ns = _ns;
  std::string topic = _topic;

  // If the namespace does not contain a trailing slash, append it.
  if (ns.back() != '/')
    ns.push_back('/');

  // If the namespace does not start with slash, add it.
  if (ns.front() != '/')
    ns.insert(0, 1, '/');

  // If the topic ends in "/", remove it.
  if (topic.back() == '/')
    topic.pop_back();

  // If the topic does starts with '/' is considered an absolute topic and the
  // namespace will not be prefixed.
  if (topic.front() == '/')
    _scoped = topic;
  else
    _scoped = ns + topic;

  return true;
}
<|endoftext|>


<commit_before>/**
 * @copyright
 * ====================================================================
 *    Licensed to the Apache Software Foundation (ASF) under one
 *    or more contributor license agreements.  See the NOTICE file
 *    distributed with this work for additional information
 *    regarding copyright ownership.  The ASF licenses this file
 *    to you 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.
 * ====================================================================
 * @endcopyright
 *
 * @file CopySources.cpp
 * @brief Implementation of the class CopySources
 */

#include <apr_pools.h>
#include "svn_client.h"

#include "Pool.h"
#include "JNIUtil.h"
#include "JNIStringHolder.h"
#include "Revision.h"
#include "CopySources.h"

CopySources::CopySources(Array &copySources)
    : m_copySources(copySources)
{
}

CopySources::~CopySources()
{
}

jobject
CopySources::makeJCopySource(const char *path, svn_revnum_t rev, SVN::Pool &pool)
{
  JNIEnv *env = JNIUtil::getEnv();

  // Create a local frame for our references
  env->PushLocalFrame(LOCAL_FRAME_SIZE);
  if (JNIUtil::isJavaExceptionThrown())
    return NULL;

  jobject jpath = JNIUtil::makeJString(path);
  if (JNIUtil::isJavaExceptionThrown())
    POP_AND_RETURN_NULL;

  jobject jrevision = Revision::makeJRevision(rev);
  if (JNIUtil::isJavaExceptionThrown())
    POP_AND_RETURN_NULL;

  jclass clazz = env->FindClass(JAVA_PACKAGE "/types/CopySource");
  if (JNIUtil::isJavaExceptionThrown())
    POP_AND_RETURN_NULL;

  static jmethodID ctor = 0;
  if (ctor == 0)
    {
      ctor = env->GetMethodID(clazz, "<init>",
                              "(Ljava/lang/String;"
                              "L" JAVA_PACKAGE "/types/Revision;"
                              "L" JAVA_PACKAGE "/types/Revision;)V");
      if (JNIUtil::isExceptionThrown())
        POP_AND_RETURN_NULL;
    }

  jobject jcopySource = env->NewObject(clazz, ctor, jpath, jrevision, NULL);
  if (JNIUtil::isJavaExceptionThrown())
    POP_AND_RETURN_NULL;

  return env->PopLocalFrame(jcopySource);
}

apr_array_header_t *
CopySources::array(SVN::Pool &pool)
{
  apr_pool_t *p = pool.getPool();

  JNIEnv *env = JNIUtil::getEnv();
  jclass clazz = env->FindClass(JAVA_PACKAGE "/types/CopySource");
  if (JNIUtil::isJavaExceptionThrown())
    return NULL;

  std::vector<jobject> sources = m_copySources.vector();

  apr_array_header_t *copySources =
    apr_array_make(p, static_cast<int>(sources.size()),
                   sizeof(svn_client_copy_source_t *));
  for (std::vector<jobject>::const_iterator it = sources.begin();
        it < sources.end(); ++it)
    {
      svn_client_copy_source_t *src =
        reinterpret_cast<svn_client_copy_source_t *>(apr_palloc(p, sizeof(*src)));

      // Extract the path or URL from the copy source.
      static jmethodID getPath = 0;
      if (getPath == 0)
        {
          getPath = env->GetMethodID(clazz, "getPath",
                                     "()Ljava/lang/String;");
          if (JNIUtil::isJavaExceptionThrown() || getPath == 0)
            return NULL;
        }
      jstring jpath = (jstring)
        env->CallObjectMethod(*it, getPath);
      if (JNIUtil::isJavaExceptionThrown())
        return NULL;

      const char *path = env->GetStringUTFChars(jpath, NULL);
      if (JNIUtil::isJavaExceptionThrown())
        return NULL;

      src->path = apr_pstrdup(p, path);
      env->ReleaseStringUTFChars(jpath, path);
      SVN_JNI_ERR(JNIUtil::preprocessPath(src->path, pool.getPool()),
                  NULL);
      env->DeleteLocalRef(jpath);

      // Extract source revision from the copy source.
      static jmethodID getRevision = 0;
      if (getRevision == 0)
        {
          getRevision = env->GetMethodID(clazz, "getRevision",
                                         "()L"JAVA_PACKAGE"/types/Revision;");
          if (JNIUtil::isJavaExceptionThrown() || getRevision == 0)
            return NULL;
        }
      jobject jrev = env->CallObjectMethod(*it, getRevision);
      if (JNIUtil::isJavaExceptionThrown())
        return NULL;

      // TODO: Default this to svn_opt_revision_undefined (or HEAD)
      Revision rev(jrev);
      src->revision = reinterpret_cast<const svn_opt_revision_t *>
        (apr_palloc(p, sizeof(*src->revision)));
      memcpy(const_cast<svn_opt_revision_t *>(src->revision),
             rev.revision(),
             sizeof(*src->revision));
      env->DeleteLocalRef(jrev);

      // Extract pegRevision from the copy source.
      static jmethodID getPegRevision = 0;
      if (getPegRevision == 0)
        {
          getPegRevision = env->GetMethodID(clazz, "getPegRevision",
                                            "()L"JAVA_PACKAGE"/types/Revision;");
          if (JNIUtil::isJavaExceptionThrown() || getPegRevision == 0)
            return NULL;
        }
      jobject jPegRev = env->CallObjectMethod(*it, getPegRevision);
      if (JNIUtil::isJavaExceptionThrown())
        return NULL;

      Revision pegRev(jPegRev, true);
      src->peg_revision = reinterpret_cast<const svn_opt_revision_t *>
        (apr_palloc(p, sizeof(*src->peg_revision)));
      memcpy(const_cast<svn_opt_revision_t *>(src->peg_revision),
             pegRev.revision(),
             sizeof(*src->peg_revision));
      env->DeleteLocalRef(jPegRev);

      APR_ARRAY_PUSH(copySources, svn_client_copy_source_t *) = src;
    }

  env->DeleteLocalRef(clazz);

  return copySources;
}
<commit_msg>* subversion/bindings/javahl/native/CopySources.cpp   (array): Simplify, simplify.<commit_after>/**
 * @copyright
 * ====================================================================
 *    Licensed to the Apache Software Foundation (ASF) under one
 *    or more contributor license agreements.  See the NOTICE file
 *    distributed with this work for additional information
 *    regarding copyright ownership.  The ASF licenses this file
 *    to you 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.
 * ====================================================================
 * @endcopyright
 *
 * @file CopySources.cpp
 * @brief Implementation of the class CopySources
 */

#include <apr_pools.h>
#include "svn_client.h"

#include "Pool.h"
#include "JNIUtil.h"
#include "JNIStringHolder.h"
#include "Revision.h"
#include "CopySources.h"

CopySources::CopySources(Array &copySources)
    : m_copySources(copySources)
{
}

CopySources::~CopySources()
{
}

jobject
CopySources::makeJCopySource(const char *path, svn_revnum_t rev, SVN::Pool &pool)
{
  JNIEnv *env = JNIUtil::getEnv();

  // Create a local frame for our references
  env->PushLocalFrame(LOCAL_FRAME_SIZE);
  if (JNIUtil::isJavaExceptionThrown())
    return NULL;

  jobject jpath = JNIUtil::makeJString(path);
  if (JNIUtil::isJavaExceptionThrown())
    POP_AND_RETURN_NULL;

  jobject jrevision = Revision::makeJRevision(rev);
  if (JNIUtil::isJavaExceptionThrown())
    POP_AND_RETURN_NULL;

  jclass clazz = env->FindClass(JAVA_PACKAGE "/types/CopySource");
  if (JNIUtil::isJavaExceptionThrown())
    POP_AND_RETURN_NULL;

  static jmethodID ctor = 0;
  if (ctor == 0)
    {
      ctor = env->GetMethodID(clazz, "<init>",
                              "(Ljava/lang/String;"
                              "L" JAVA_PACKAGE "/types/Revision;"
                              "L" JAVA_PACKAGE "/types/Revision;)V");
      if (JNIUtil::isExceptionThrown())
        POP_AND_RETURN_NULL;
    }

  jobject jcopySource = env->NewObject(clazz, ctor, jpath, jrevision, NULL);
  if (JNIUtil::isJavaExceptionThrown())
    POP_AND_RETURN_NULL;

  return env->PopLocalFrame(jcopySource);
}

apr_array_header_t *
CopySources::array(SVN::Pool &pool)
{
  apr_pool_t *p = pool.getPool();

  JNIEnv *env = JNIUtil::getEnv();
  jclass clazz = env->FindClass(JAVA_PACKAGE "/types/CopySource");
  if (JNIUtil::isJavaExceptionThrown())
    return NULL;

  std::vector<jobject> sources = m_copySources.vector();

  apr_array_header_t *copySources =
    apr_array_make(p, static_cast<int>(sources.size()),
                   sizeof(svn_client_copy_source_t *));
  for (std::vector<jobject>::const_iterator it = sources.begin();
        it < sources.end(); ++it)
    {
      svn_client_copy_source_t *src =
        reinterpret_cast<svn_client_copy_source_t *>(apr_palloc(p, sizeof(*src)));

      // Extract the path or URL from the copy source.
      static jmethodID getPath = 0;
      if (getPath == 0)
        {
          getPath = env->GetMethodID(clazz, "getPath",
                                     "()Ljava/lang/String;");
          if (JNIUtil::isJavaExceptionThrown() || getPath == 0)
            return NULL;
        }
      jstring jpath = (jstring)
        env->CallObjectMethod(*it, getPath);
      if (JNIUtil::isJavaExceptionThrown())
        return NULL;

      const char *path = env->GetStringUTFChars(jpath, NULL);
      if (JNIUtil::isJavaExceptionThrown())
        return NULL;

      src->path = apr_pstrdup(p, path);
      env->ReleaseStringUTFChars(jpath, path);
      SVN_JNI_ERR(JNIUtil::preprocessPath(src->path, pool.getPool()),
                  NULL);
      env->DeleteLocalRef(jpath);

      // Extract source revision from the copy source.
      static jmethodID getRevision = 0;
      if (getRevision == 0)
        {
          getRevision = env->GetMethodID(clazz, "getRevision",
                                         "()L"JAVA_PACKAGE"/types/Revision;");
          if (JNIUtil::isJavaExceptionThrown() || getRevision == 0)
            return NULL;
        }
      jobject jrev = env->CallObjectMethod(*it, getRevision);
      if (JNIUtil::isJavaExceptionThrown())
        return NULL;

      // TODO: Default this to svn_opt_revision_undefined (or HEAD)
      Revision rev(jrev);
      src->revision = reinterpret_cast<const svn_opt_revision_t *>
        (apr_pmemdup(p, rev.revision(), sizeof(*src->revision)));
      env->DeleteLocalRef(jrev);

      // Extract pegRevision from the copy source.
      static jmethodID getPegRevision = 0;
      if (getPegRevision == 0)
        {
          getPegRevision = env->GetMethodID(clazz, "getPegRevision",
                                            "()L"JAVA_PACKAGE"/types/Revision;");
          if (JNIUtil::isJavaExceptionThrown() || getPegRevision == 0)
            return NULL;
        }
      jobject jPegRev = env->CallObjectMethod(*it, getPegRevision);
      if (JNIUtil::isJavaExceptionThrown())
        return NULL;

      Revision pegRev(jPegRev, true);
      src->peg_revision = reinterpret_cast<const svn_opt_revision_t *>
        (apr_pmemdup(p, pegRev.revision(), sizeof(*src->peg_revision)));
      env->DeleteLocalRef(jPegRev);

      APR_ARRAY_PUSH(copySources, svn_client_copy_source_t *) = src;
    }

  env->DeleteLocalRef(clazz);

  return copySources;
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2009-2013, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/allocator.hpp"
#include "libtorrent/config.hpp"
#include "libtorrent/assert.hpp"

#if defined TORRENT_BEOS
#include <kernel/OS.h>
#include <stdlib.h> // malloc/free
#elif !defined TORRENT_WINDOWS
#include <stdlib.h> // valloc/free
#include <unistd.h> // _SC_PAGESIZE
#endif

#if TORRENT_USE_MEMALIGN || TORRENT_USE_POSIX_MEMALIGN || defined TORRENT_WINDOWS
#include <malloc.h> // memalign and _aligned_malloc
#include <stdlib.h> // _aligned_malloc on mingw
#endif

#ifdef TORRENT_WINDOWS
// windows.h must be included after stdlib.h under mingw
#include <windows.h>
#endif

#ifdef TORRENT_MINGW
#define _aligned_malloc __mingw_aligned_malloc
#define _aligned_free __mingw_aligned_free
#endif

#ifdef TORRENT_DEBUG_BUFFERS
#ifndef TORRENT_WINDOWS
#include <sys/mman.h>
#endif
#include "libtorrent/size_type.hpp"

struct alloc_header
{
	libtorrent::size_type size;
	int magic;
	char stack[3072];
};

#endif

namespace libtorrent
{

	int page_size()
	{
		static int s = 0;
		if (s != 0) return s;

#ifdef TORRENT_WINDOWS
		SYSTEM_INFO si;
		GetSystemInfo(&si);
		s = si.dwPageSize;
#elif defined TORRENT_BEOS
		s = B_PAGE_SIZE;
#else
		s = sysconf(_SC_PAGESIZE);
#endif
		// assume the page size is 4 kiB if we
		// fail to query it
		if (s <= 0) s = 4096;
		return s;
	}

	char* page_aligned_allocator::malloc(size_type bytes)
	{
		TORRENT_ASSERT(bytes >= page_size());
#ifdef TORRENT_DEBUG_BUFFERS
		int page = page_size();
		int num_pages = (bytes + (page-1)) / page + 2;
		char* ret = (char*)valloc(num_pages * page);
		// make the two surrounding pages non-readable and -writable
		alloc_header* h = (alloc_header*)ret;
		h->size = bytes;
		h->magic = 0x1337;
#if defined __linux__ || (defined __APPLE__ && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)
		print_backtrace(h->stack, sizeof(h->stack));
#endif

#ifdef TORRENT_WINDOWS
#define mprotect(buf, size, prot) VirtualProtect(buf, size, prot, NULK)
#define PROT_READ PAGE_READONLY
#endif
		mprotect(ret, page, PROT_READ);
		mprotect(ret + (num_pages-1) * page, page, PROT_READ);

#ifdef TORRENT_WINDOWS
#undef mprotect
#undef PROT_READ
#endif
//		fprintf(stderr, "malloc: %p head: %p tail: %p size: %d\n", ret + page, ret, ret + page + bytes, int(bytes));

		return ret + page;
#endif

#if TORRENT_USE_POSIX_MEMALIGN
		void* ret;
		if (posix_memalign(&ret, page_size(), bytes) != 0) ret = 0;
		return (char*)ret;
#elif TORRENT_USE_MEMALIGN
		return (char*)memalign(page_size(), bytes);
#elif defined TORRENT_WINDOWS
		return (char*)_aligned_malloc(bytes, page_size());
#elif defined TORRENT_BEOS
		void* ret = 0;
		area_id id = create_area("", &ret, B_ANY_ADDRESS
			, (bytes + page_size() - 1) & (page_size()-1), B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
		if (id < B_OK) return 0;
		return (char*)ret;
#else
		return (char*)valloc(bytes);
#endif
	}

	void page_aligned_allocator::free(char* const block)
	{

#ifdef TORRENT_DEBUG_BUFFERS

#ifdef TORRENT_WINDOWS
#define mprotect(buf, size, prot) VirtualProtect(buf, size, prot, NULK)
#define PROT_READ PAGE_READONLY
#define PROT_WRITE PAGE_READWRITE
#endif
		int page = page_size();
		// make the two surrounding pages non-readable and -writable
		mprotect(block - page, page, PROT_READ | PROT_WRITE);
		alloc_header* h = (alloc_header*)(block - page);
		int num_pages = (h->size + (page-1)) / page + 2;
		TORRENT_ASSERT(h->magic == 0x1337);
		mprotect(block + (num_pages-2) * page, page, PROT_READ | PROT_WRITE);
//		fprintf(stderr, "free: %p head: %p tail: %p size: %d\n", block, block - page, block + h->size, int(h->size));
		h->magic = 0;

#ifdef TORRENT_WINDOWS
#undef mprotect
#undef PROT_READ
#undef PROT_WRITE
#endif

#if defined __linux__ || (defined __APPLE__ && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)
		print_backtrace(h->stack, sizeof(h->stack));
#endif
		::free(block - page);
		return;
#endif // TORRENT_DEBUG_BUFFERS

#ifdef TORRENT_WINDOWS
		_aligned_free(block);
#elif defined TORRENT_BEOS
		area_id id = area_for(block);
		if (id < B_OK) return;
		delete_area(id);
#else
		::free(block);
#endif // TORRENT_WINDOWS
	}

}

<commit_msg>fix build with allocator debugging<commit_after>/*

Copyright (c) 2009-2013, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/allocator.hpp"
#include "libtorrent/config.hpp"
#include "libtorrent/assert.hpp"

#if defined TORRENT_BEOS
#include <kernel/OS.h>
#include <stdlib.h> // malloc/free
#elif !defined TORRENT_WINDOWS
#include <stdlib.h> // valloc/free
#include <unistd.h> // _SC_PAGESIZE
#endif

#if TORRENT_USE_MEMALIGN || TORRENT_USE_POSIX_MEMALIGN || defined TORRENT_WINDOWS
#include <malloc.h> // memalign and _aligned_malloc
#include <stdlib.h> // _aligned_malloc on mingw
#endif

#ifdef TORRENT_WINDOWS
// windows.h must be included after stdlib.h under mingw
#include <windows.h>
#endif

#ifdef TORRENT_MINGW
#define _aligned_malloc __mingw_aligned_malloc
#define _aligned_free __mingw_aligned_free
#endif

#ifdef TORRENT_DEBUG_BUFFERS
#ifndef TORRENT_WINDOWS
#include <sys/mman.h>
#endif
#include "libtorrent/size_type.hpp"

struct alloc_header
{
	libtorrent::size_type size;
	int magic;
	char stack[3072];
};

#endif

namespace libtorrent
{

	int page_size()
	{
		static int s = 0;
		if (s != 0) return s;

#ifdef TORRENT_WINDOWS
		SYSTEM_INFO si;
		GetSystemInfo(&si);
		s = si.dwPageSize;
#elif defined TORRENT_BEOS
		s = B_PAGE_SIZE;
#else
		s = sysconf(_SC_PAGESIZE);
#endif
		// assume the page size is 4 kiB if we
		// fail to query it
		if (s <= 0) s = 4096;
		return s;
	}

	char* page_aligned_allocator::malloc(size_type bytes)
	{
		TORRENT_ASSERT(bytes >= page_size());
#ifdef TORRENT_DEBUG_BUFFERS
		int page = page_size();
		int num_pages = (bytes + (page-1)) / page + 2;
		char* ret = (char*)valloc(num_pages * page);
		// make the two surrounding pages non-readable and -writable
		alloc_header* h = (alloc_header*)ret;
		h->size = bytes;
		h->magic = 0x1337;
#if defined __linux__ || (defined __APPLE__ && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)
		print_backtrace(h->stack, sizeof(h->stack));
#endif

#ifdef TORRENT_WINDOWS
#define mprotect(buf, size, prot) VirtualProtect(buf, size, prot, NULK)
#define PROT_READ PAGE_READONLY
#endif
		mprotect(ret, page, PROT_READ);
		mprotect(ret + (num_pages-1) * page, page, PROT_READ);

#ifdef TORRENT_WINDOWS
#undef mprotect
#undef PROT_READ
#endif
//		fprintf(stderr, "malloc: %p head: %p tail: %p size: %d\n", ret + page, ret, ret + page + bytes, int(bytes));

		return ret + page;
#else

#if TORRENT_USE_POSIX_MEMALIGN
		void* ret;
		if (posix_memalign(&ret, page_size(), bytes) != 0) ret = 0;
		return (char*)ret;
#elif TORRENT_USE_MEMALIGN
		return (char*)memalign(page_size(), bytes);
#elif defined TORRENT_WINDOWS
		return (char*)_aligned_malloc(bytes, page_size());
#elif defined TORRENT_BEOS
		void* ret = 0;
		area_id id = create_area("", &ret, B_ANY_ADDRESS
			, (bytes + page_size() - 1) & (page_size()-1), B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
		if (id < B_OK) return 0;
		return (char*)ret;
#else
		return (char*)valloc(bytes);
#endif
#endif // TORRENT_DEBUG_BUFFERS
	}

	void page_aligned_allocator::free(char* const block)
	{

#ifdef TORRENT_DEBUG_BUFFERS

#ifdef TORRENT_WINDOWS
#define mprotect(buf, size, prot) VirtualProtect(buf, size, prot, NULK)
#define PROT_READ PAGE_READONLY
#define PROT_WRITE PAGE_READWRITE
#endif
		int page = page_size();
		// make the two surrounding pages non-readable and -writable
		mprotect(block - page, page, PROT_READ | PROT_WRITE);
		alloc_header* h = (alloc_header*)(block - page);
		int num_pages = (h->size + (page-1)) / page + 2;
		TORRENT_ASSERT(h->magic == 0x1337);
		mprotect(block + (num_pages-2) * page, page, PROT_READ | PROT_WRITE);
//		fprintf(stderr, "free: %p head: %p tail: %p size: %d\n", block, block - page, block + h->size, int(h->size));
		h->magic = 0;

#ifdef TORRENT_WINDOWS
#undef mprotect
#undef PROT_READ
#undef PROT_WRITE
#endif

#if defined __linux__ || (defined __APPLE__ && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)
		print_backtrace(h->stack, sizeof(h->stack));
#endif
		::free(block - page);
		return;
#endif // TORRENT_DEBUG_BUFFERS

#ifdef TORRENT_WINDOWS
		_aligned_free(block);
#elif defined TORRENT_BEOS
		area_id id = area_for(block);
		if (id < B_OK) return;
		delete_area(id);
#else
		::free(block);
#endif // TORRENT_WINDOWS
	}

}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015-2018 dubalu.com LLC. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <string>             // for string
#include <stdlib.h>           // for getenv

#include "static_str.hh"

#define ESC "\033"

template <int N, int num, char... a>
struct explode : explode<N + 1, num / 10, ('0' + num % 10), a...> { };

template <int N, char... a>
struct explode<N, 0, a...> {
	constexpr static const char value[N + 1]{a..., 0};
};

template <unsigned num>
struct to_string : explode<0, num> { };

template <>
struct to_string<0> : explode<1, 0, '0'> { };

// Ansi colors:
template <int red, int green, int blue, bool bold = false>
class ansi_color {
	static constexpr uint8_t r = red < 0 ? 0 : red > 255 ? 255 : red;
	static constexpr uint8_t g = green < 0 ? 0 : green > 255 ? 255 : green;
	static constexpr uint8_t b = blue < 0 ? 0 : blue > 255 ? 255 : blue;

	static constexpr auto noColor() {
		return static_str::literal(ESC "[0m");
	}

	static constexpr auto trueColor() {
		return (
			static_str::literal(ESC "[") +
			to_string<bold>::value +
			";38;2;" +
			to_string<r>::value + ";" +
			to_string<g>::value + ";" +
			to_string<b>::value +
			"m"
		);
	}

	static constexpr auto standard256() {
		constexpr uint8_t color = static_cast<uint8_t>((r == g && g == b) ? (
			r < 6 ? 16 :
			r > 249 ? 231 :
			231 + static_cast<int>((r * 25.0f / 255.0f) + 0.5f)
		) : (
			16 +
			(static_cast<int>(r / 255.0f * 5.0f + 0.5f) * 36) +
			(static_cast<int>(g / 255.0f * 5.0f + 0.5f) * 6) +
			(static_cast<int>(b / 255.0f * 5.0f + 0.5f))
		));
		return (
			static_str::literal(ESC "[") +
			to_string<bold>::value +
			";38;5;" +
			to_string<color>::value +
			"m"
		);
	}

	static constexpr auto standard16() {
		constexpr auto _min = r < g ? r : g;
		constexpr auto min = _min < b ? _min : b;
		constexpr auto _max = r > g ? r : g;
		constexpr auto max = _max > b ? _max : b;
		constexpr uint8_t color = static_cast<uint8_t>((r == g && g == b) ? (
			r > 192 ? 15 :
			r > 128 ? 7 :
			r > 32 ? 8 :
			0
		) : (
			(max <= 32) ? (
				0
			) : (
				(
					((static_cast<int>((b - min) * 255.0f / (max - min) + 0.5f) > 128 ? 1 : 0) << 2) |
					((static_cast<int>((g - min) * 255.0f / (max - min) + 0.5f) > 128 ? 1 : 0) << 1) |
					((static_cast<int>((r - min) * 255.0f / (max - min) + 0.5f) > 128 ? 1 : 0))
				) + (max > 192 ? 8 : 0)
			)
		));
		return (
			static_str::literal(ESC "[") +
			to_string<bold>::value +
			";38;5;" +
			to_string<color>::value +
			"m"
		);
	}

public:
	static const auto& col() {
		constexpr auto _ = (
			trueColor() +
			standard256() +
			standard16()
		);
		static std::string __ = _;
		return __;
	}

	static const auto& no_col() {
		constexpr auto _ = (
			noColor() +
			noColor() +
			noColor()
		);
		static std::string __ = _;
		return __;
	}
};

#define rgb(r, g, b)      ansi_color<static_cast<int>(r), static_cast<int>(g), static_cast<int>(b)>::col()
#define rgba(r, g, b, a)  ansi_color<static_cast<int>(r * a + 0.5f), static_cast<int>(g * a + 0.5f), static_cast<int>(b * a + 0.5f)>::col()
#define brgb(r, g, b)     ansi_color<static_cast<int>(r), static_cast<int>(g), static_cast<int>(b), true>::col()
#define brgba(r, g, b, a) ansi_color<static_cast<int>(r * a + 0.5f), static_cast<int>(g * a + 0.5f), static_cast<int>(b * a + 0.5f), true>::col()
#define no_col()          ansi_color<0, 0, 0>::no_col()
<commit_msg>ansi_color: col() returning static_str constexpr<commit_after>/*
 * Copyright (C) 2015-2018 dubalu.com LLC. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <string>             // for string
#include <stdlib.h>           // for getenv

#include "static_str.hh"

#define ESC "\033"

template <int N, int num, char... a>
struct explode : explode<N + 1, num / 10, ('0' + num % 10), a...> { };

template <int N, char... a>
struct explode<N, 0, a...> {
	constexpr static const char value[N + 1]{a..., 0};
};

template <unsigned num>
struct to_string : explode<0, num> { };

template <>
struct to_string<0> : explode<1, 0, '0'> { };

// Ansi colors:
template <int red, int green, int blue, bool bold = false>
class ansi_color {
	static constexpr uint8_t r = red < 0 ? 0 : red > 255 ? 255 : red;
	static constexpr uint8_t g = green < 0 ? 0 : green > 255 ? 255 : green;
	static constexpr uint8_t b = blue < 0 ? 0 : blue > 255 ? 255 : blue;

	static constexpr auto noColor() {
		constexpr auto noColor = static_str::literal(ESC "[0m");
		return noColor;
	}

	static constexpr auto trueColor() {
		constexpr auto trueColor = (
			static_str::literal(ESC "[") +
			to_string<bold>::value +
			";38;2;" +
			to_string<r>::value + ";" +
			to_string<g>::value + ";" +
			to_string<b>::value +
			"m"
		);
		return trueColor;
	}

	static constexpr auto standard256() {
		constexpr uint8_t color = static_cast<uint8_t>((r == g && g == b) ? (
			r < 6 ? 16 :
			r > 249 ? 231 :
			231 + static_cast<int>((r * 25.0f / 255.0f) + 0.5f)
		) : (
			16 +
			(static_cast<int>(r / 255.0f * 5.0f + 0.5f) * 36) +
			(static_cast<int>(g / 255.0f * 5.0f + 0.5f) * 6) +
			(static_cast<int>(b / 255.0f * 5.0f + 0.5f))
		));
		constexpr auto standard256 = (
			static_str::literal(ESC "[") +
			to_string<bold>::value +
			";38;5;" +
			to_string<color>::value +
			"m"
		);
		return standard256;
	}

	static constexpr auto standard16() {
		constexpr auto _min = r < g ? r : g;
		constexpr auto min = _min < b ? _min : b;
		constexpr auto _max = r > g ? r : g;
		constexpr auto max = _max > b ? _max : b;
		constexpr uint8_t color = static_cast<uint8_t>((r == g && g == b) ? (
			r > 192 ? 15 :
			r > 128 ? 7 :
			r > 32 ? 8 :
			0
		) : (
			(max <= 32) ? (
				0
			) : (
				(
					((static_cast<int>((b - min) * 255.0f / (max - min) + 0.5f) > 128 ? 1 : 0) << 2) |
					((static_cast<int>((g - min) * 255.0f / (max - min) + 0.5f) > 128 ? 1 : 0) << 1) |
					((static_cast<int>((r - min) * 255.0f / (max - min) + 0.5f) > 128 ? 1 : 0))
				) + (max > 192 ? 8 : 0)
			)
		));
		constexpr auto standard16 = (
			static_str::literal(ESC "[") +
			to_string<bold>::value +
			";38;5;" +
			to_string<color>::value +
			"m"
		);
		return standard16;
	}

public:
	static constexpr auto col() {
		constexpr auto col = (
			trueColor() +
			standard256() +
			standard16()
		);
		return col;
	}

	static constexpr auto no_col() {
		constexpr auto no_col = (
			noColor() +
			noColor() +
			noColor()
		);
		return no_col;
	}
};

#define rgb(r, g, b)      ansi_color<static_cast<int>(r), static_cast<int>(g), static_cast<int>(b)>::col()
#define rgba(r, g, b, a)  ansi_color<static_cast<int>(r * a + 0.5f), static_cast<int>(g * a + 0.5f), static_cast<int>(b * a + 0.5f)>::col()
#define brgb(r, g, b)     ansi_color<static_cast<int>(r), static_cast<int>(g), static_cast<int>(b), true>::col()
#define brgba(r, g, b, a) ansi_color<static_cast<int>(r * a + 0.5f), static_cast<int>(g * a + 0.5f), static_cast<int>(b * a + 0.5f), true>::col()
#define no_col()          ansi_color<0, 0, 0>::no_col()
<|endoftext|>


<commit_before>#ifndef MY_LITTLE_ARG_PARSER_H
#define MY_LITTLE_ARG_PARSER_H

#include <unordered_map>

namespace mylittleparser
{
    class ParseEntry
    {
    public:

        ParseEntry () : data_ (nullptr), size_ (0), nargs_ (0) { }

        ~ParseEntry () { if (data_) delete[] data_; }

        template<typename T>
        inline T get (int idx)
        {
            /*!
                \note This only provide basic type safety, we still don't have
                      the capability to know the type of the stored data.
            */
            if (sizeof (T) != size_ || 0 > idx || (int) nargs_ <= idx)
                throw this;
            return reinterpret_cast<T*>(data_)[idx];
        }

    private:

        friend class ArgumentParser;

        template<typename T, int nargs> inline void resize ()
        {
            size_ = sizeof (T);
            nargs_ = nargs;
            if (data_) delete[] data_;
            data_ = new unsigned char[size_ * nargs_] ();
        }

        template<typename T> inline void set (int idx, const T& val)
        {
            reinterpret_cast<T*>(data_)[idx] = val;
        }

        unsigned char* data_;
        size_t size_;
        size_t nargs_;
    };

    typedef std::unordered_map<std::string, ParseEntry> ParseArgs;

    class ArgumentParser
    {
    private:

        template<int type> struct ParseType;

        // base type
        template<typename T, int nargs = 0, class enable = void> struct TypeId
        {
            static const int value = -1;
        };

        // bool type
        template<int nargs>
        struct TypeId <bool, nargs, typename std::enable_if<nargs == 0>::type>
        {
            static const int value = 0;
        };

        // int type
        template<int nargs>
        struct TypeId <int, nargs, typename std::enable_if<nargs >= 1>::type>
        {
            static const int value = 1;
        };

        // c style string type
        template<int nargs>
        struct TypeId <char *, nargs, typename std::enable_if<nargs >= 1>::type>
        {
            static const int value = 2;
        };

        // c style const string type
        template<int nargs>
        struct TypeId <const char *, nargs,
            typename std::enable_if<nargs >= 1>::type>
        {
            static const int value = 3;
        };

        template<bool required> int search (const char* name, const char* abbr);

        template<typename U, int nargs> void parse (const char* name, int idx);

        int argc_;                                  //!< arguments count
        char** argv_;                               //!< arguments values
        std::unordered_map<std::string, int> argi_; //!< arguments indices
        bool help_;
        ParseArgs parse_args_;

    public:

        ArgumentParser (int argc = __argc, char** argv = __argv)
            : argc_ (argc), argv_ (argv), help_ (false)
        {
            for (int i = 0; i < argc; ++i) argi_[argv[i]] = i;
            help_ = search<false> ("--help", "-h") != argc_;
        }

        ~ArgumentParser () { }

        template <typename T, int nargs = 0, bool required = false>
        typename std::enable_if <
            TypeId<typename std::remove_cv<T>::type, nargs>::value >= 0>::type
            add_argument (const char* name,
                          const char* help,
                          const char* abbr = nullptr)
        {
            typedef typename std::remove_cv<T>::type U;

            parse<U, nargs> (name, search<required> (name, abbr));
        }

        ParseArgs parse_args ()
        {
            if (help_) exit (0);
            return parse_args_;
        }

    };

    template<> struct ArgumentParser::ParseType<
        ArgumentParser::TypeId<bool, 0>::value>
    {
        static bool parse (const char* str) { return true; }
    };

    template<>
    struct ArgumentParser::ParseType<ArgumentParser::TypeId<int, 1>::value>
    {
        static int parse (const char* str) { return std::atoi (str); }
    };

    template<> struct ArgumentParser::ParseType<
        ArgumentParser::TypeId<char*, 1>::value>
    {
        static char *parse (const char *str)
        {
            return const_cast<char*>(str);
        }
    };

    template<> struct ArgumentParser::ParseType<
        ArgumentParser::TypeId<const char*, 1>::value>
    {
        static const char *parse (const char *str) { return str; }
    };

    template<bool required>
    int ArgumentParser::search (const char* name, const char* abbr)
    {
        return argi_.find (name) != argi_.end () ? argi_.at (name) : argc_;
    }

    template<>
    int ArgumentParser::search<true> (const char* name, const char* abbr)
    {
        if (argi_.find (name) == argi_.end ()) throw this;
        return argi_.at (name);
    }

    template<typename U, int nargs>
    inline void ArgumentParser::parse (const char* name, int idx)
    {
        parse_args_[name].resize<U, nargs> ();
        for (int i = 1; i <= nargs && idx + i < argc_; ++i)
            parse_args_[name].set<U> (
                i - 1,
                ParseType <TypeId<U, nargs>::value>::parse (
                    argv_[idx + i]));
    }

    template<>
    inline void ArgumentParser::parse<bool, 0> (const char* name, int idx)
    {
        parse_args_[name].resize<bool, 1> ();
        parse_args_[name].set<bool> (0, idx < argc_);
    }
}

#endif
<commit_msg>Updated help<commit_after>/*
MIT License

Copyright (c) 2017 cnocobot

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 MY_LITTLE_ARG_PARSER_H
#define MY_LITTLE_ARG_PARSER_H

#include <assert.h>
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <unordered_map>

namespace mylittleparser
{
    class ArgEntry
    {
    public:

        ArgEntry () : data_ (nullptr), size_ (0), nargs_ (0) { }

        ArgEntry (const ArgEntry& other)
            : size_ (other.size_), nargs_ (other.nargs_)
        {
            data_ = new unsigned char[size_ * nargs_];
            std::memcpy (data_, other.data_, size_ * nargs_);
        }

        ~ArgEntry () { if (data_ != nullptr) delete[] data_; }

        struct ArgProxy
        {
        public:

            template<typename T> operator T() { return entry_->get<T> (idx_); }

        private:

            friend class ArgEntry;

            ArgProxy (const ArgEntry* entry, int idx)
                : entry_ (entry), idx_ (idx) { }

            const ArgEntry* entry_;
            int idx_;
        };

        ArgProxy operator[](int idx) const { return ArgProxy (this, idx); }

        template<typename T>
        inline T get (int idx = 0) const
        {
            /*!
                \note This only provide basic type safety, we still don't have
                      the capability to know the type of the stored data.
            */
            assert (sizeof (T) == size_ && 0 <= idx && (int) nargs_ > idx);
            return *(reinterpret_cast<T*>(data_) + idx);
        }

    private:

        friend class ArgumentParser;

        template<typename T, int nargs> inline void resize ()
        {
            size_ = sizeof (T);
            nargs_ = nargs;
            if (data_) delete[] data_;
            data_ = new unsigned char[nargs_ * size_];
        }

        template<typename T> inline void set (int idx, const T& val)
        {
            *(reinterpret_cast<T*>(data_) + idx) = val;
        }

        unsigned char* data_;
        size_t size_;
        size_t nargs_;
    };

    typedef std::unordered_map<std::string, ArgEntry> ParseArgs;

    class ArgumentParser
    {
    private:

        template<int type> struct ParseTy;

        // base type
        template<typename T, int nargs = 0, class enable = void> struct TyId
        {
            static const int value = -1;
        };

        // bool type
        template<int nargs>
        struct TyId <bool, nargs, typename std::enable_if<nargs == 0>::type>
        {
            static const int value = 0;
        };

        // int type
        template<int nargs>
        struct TyId <int, nargs, typename std::enable_if<nargs >= 1>::type>
        {
            static const int value = 1;
        };

        // c style string type
        template<int nargs>
        struct TyId <char *, nargs, typename std::enable_if<nargs >= 1>::type>
        {
            static const int value = 2;
        };

        // c style const string type
        template<int nargs>
        struct TyId <const char *, nargs,
            typename std::enable_if<nargs >= 1>::type>
        {
            static const int value = 3;
        };

        inline int search (const char* key)
        {
            return key && argi_.find (key) != argi_.end () ?
                argi_[key] : argc_;
        }
        template<bool required>
        inline int search (const char* name, const char* abbr);

        template<typename U, int nargs> void parse (const char* name, int idx);

        void show_help () const
        {
            std::cout << "Usage ";
            for (std::pair<std::string, description_t> d : argd_)
                std::cout << d.second.name << " ";
            std::cout << "\n" << std::endl;
            for (std::pair<std::string, description_t> d : argd_)
            {
                std::cout << std::left << std::setw (12) << d.second.name << " ";
                if (d.second.abbr)
                    std::cout << std::left << std::setw (8) << d.second.abbr;
                else std::cout << std::setw (8) << "none ";
                if (d.second.help)
                    std::cout << std::left << d.second.help;
                std::cout << std::endl;
            }
            exit (0);
        }

    public:

        ArgumentParser (int argc = __argc, char** argv = __argv)
            : argc_ (argc), argv_ (argv), showh_ (false)
        {
            for (int i = 1; i < argc; ++i)
                if (argi_.find (argv[i]) == argi_.end ()) argi_[argv[i]] = i;
            if ((showh_ = search<false> ("--help", "-h") != argc_))
                argd_["--help"] = description_t ("--help",
                                                 "Show this message and exit",
                                                 "-h");
        }

        ~ArgumentParser () { }

        template <typename T, int nargs = 0, bool required = false>
        typename std::enable_if <
            TyId<typename std::remove_cv<T>::type, nargs>::value >= 0>::type
            add_argument (const char* name,
                          const char* help,
                          const char* abbr = nullptr)
        {
            typedef typename std::remove_cv<T>::type U;
            if (showh_)
                argd_[name] = description_t (name, help, abbr);
            else
                parse<U, nargs> (name, search<required> (name, abbr));
        }

        const ParseArgs& parse_args () const
        {
            if (showh_) show_help ();
            return parse_args_;
        }

    private:

        typedef struct description
        {
            description () { }
            description (const char* name,
                         const char* help,
                         const char* abbr = nullptr)
                : name (name), help (help), abbr (abbr)
            { }
            const char* name;
            const char* help;
            const char* abbr;
        } description_t;
        std::map<std::string, description_t> argd_;

        int argc_;                                  //!< arguments count
        char** argv_;                               //!< arguments values
        std::unordered_map<std::string, int> argi_; //!< arguments indices

        bool showh_;
        ParseArgs parse_args_;
    };

    /*!
        \note Useless placeholder here.
    */
    template<> struct ArgumentParser::ParseTy<
        ArgumentParser::TyId<bool, 0>::value>
    {
        static bool parse (const char*) { return true; }
    };

    template<>
    struct ArgumentParser::ParseTy<ArgumentParser::TyId<int, 1>::value>
    {
        static int parse (const char* str) { return std::atoi (str); }
    };

    template<> struct ArgumentParser::ParseTy<
        ArgumentParser::TyId<char*, 1>::value>
    {
        static char *parse (const char *str)
        {
            return const_cast<char*>(str);
        }
    };

    template<> struct ArgumentParser::ParseTy<
        ArgumentParser::TyId<const char*, 1>::value>
    {
        static const char *parse (const char *str) { return str; }
    };

    template<bool required>
    inline int ArgumentParser::search (const char* name, const char* abbr)
    {
        return std::min (search (name), search (abbr));
    }

    template<>
    inline int ArgumentParser::search<true> (const char* name, const char* abbr)
    {
        int i = search<false> (name, abbr); assert (argc_ > i);
        return i;
    }

    template<typename U, int nargs>
    inline void ArgumentParser::parse (const char* name, int idx)
    {
        parse_args_[name].resize<U, nargs> ();
        for (int i = 1; i <= nargs && idx + i < argc_; ++i)
            parse_args_[name].set<U> (
                i - 1,
                ParseTy <TyId<U, nargs>::value>::parse (argv_[idx + i]));
    }

    template<>
    inline void ArgumentParser::parse<bool, 0> (const char* name, int idx)
    {
        parse_args_[name].resize<bool, 1> ();
        parse_args_[name].set<bool> (0, idx < argc_);
    }
}

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2020 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include "harness.hh"
#include "lexer.hh"

TADPOLE_TEST(TadpoleLexer) {
  using TK = tadpole::TokenKind;
#define TEST_EQ(k)  TADPOLE_CHECK_EQ(lex.next_token().kind(), k)
#define DUMP_LEX()  do {\
    for (;;) {\
      auto t = lex.next_token();\
      std::fprintf(stdout, "%-24s | %-32s | %d\n",\
          tadpole::get_kind_name(t.kind()),\
          t.as_cstring(),\
          t.lineno());\
      if (t.kind() == TK::TK_EOF)\
        break;\
    }\
  } while (false)

  {
    std::string s =
      "print(\"Welcome to Tadpole!!!\"); var v = 45 * 34 / 23.67 + 33 - (45.4 - 56.2);";
    tadpole::Lexer lex(s);
    DUMP_LEX();
  }

  {
    std::string s = "var a = 34;";
    tadpole::Lexer lex(s);
    TEST_EQ(TK::KW_VAR);
    TEST_EQ(TK::TK_IDENTIFIER);
    TEST_EQ(TK::TK_EQ);
    TEST_EQ(TK::TK_NUMERIC);
    TEST_EQ(TK::TK_SEMI);
    TEST_EQ(TK::TK_EOF);
  }

  {
    std::string s = "print(\"34 + 56 =\", 34 + 56);";
    tadpole::Lexer lex(s);
    TEST_EQ(TK::TK_IDENTIFIER);
    TEST_EQ(TK::TK_LPAREN);
    TEST_EQ(TK::TK_STRING);
    TEST_EQ(TK::TK_COMMA);
    TEST_EQ(TK::TK_NUMERIC);
    TEST_EQ(TK::TK_PLUS);
    TEST_EQ(TK::TK_NUMERIC);
    TEST_EQ(TK::TK_RPAREN);
    TEST_EQ(TK::TK_SEMI);
    TEST_EQ(TK::TK_EOF);
  }

  {
    std::string s = "fn show(msg) { print(msg); }";
    tadpole::Lexer lex(s);
    TEST_EQ(TK::KW_FN);
    TEST_EQ(TK::TK_IDENTIFIER);
    TEST_EQ(TK::TK_LPAREN);
    TEST_EQ(TK::TK_IDENTIFIER);
    TEST_EQ(TK::TK_RPAREN);
    TEST_EQ(TK::TK_LBRACE);
    TEST_EQ(TK::TK_IDENTIFIER);
    TEST_EQ(TK::TK_LPAREN);
    TEST_EQ(TK::TK_IDENTIFIER);
    TEST_EQ(TK::TK_RPAREN);
    TEST_EQ(TK::TK_SEMI);
    TEST_EQ(TK::TK_RBRACE);
    TEST_EQ(TK::TK_EOF);
  }

  {
    std::string s = "print(45 + 56 * 22 / 8.9 - 200);";
    tadpole::Lexer lex(s);
    TEST_EQ(TK::TK_IDENTIFIER);
    TEST_EQ(TK::TK_LPAREN);
    TEST_EQ(TK::TK_NUMERIC);
    TEST_EQ(TK::TK_PLUS);
    TEST_EQ(TK::TK_NUMERIC);
    TEST_EQ(TK::TK_STAR);
    TEST_EQ(TK::TK_NUMERIC);
    TEST_EQ(TK::TK_SLASH);
    TEST_EQ(TK::TK_NUMERIC);
    TEST_EQ(TK::TK_MINUS);
    TEST_EQ(TK::TK_NUMERIC);
    TEST_EQ(TK::TK_RPAREN);
    TEST_EQ(TK::TK_SEMI);
    TEST_EQ(TK::TK_EOF);
  }

  {
    std::string s = "var a = nil; print(a, true, false);";
    tadpole::Lexer lex(s);
    TEST_EQ(TK::KW_VAR);
    TEST_EQ(TK::TK_IDENTIFIER);
    TEST_EQ(TK::TK_EQ);
    TEST_EQ(TK::KW_NIL);
    TEST_EQ(TK::TK_SEMI);
    TEST_EQ(TK::TK_IDENTIFIER);
    TEST_EQ(TK::TK_LPAREN);
    TEST_EQ(TK::TK_IDENTIFIER);
    TEST_EQ(TK::TK_COMMA);
    TEST_EQ(TK::KW_TRUE);
    TEST_EQ(TK::TK_COMMA);
    TEST_EQ(TK::KW_FALSE);
    TEST_EQ(TK::TK_RPAREN);
    TEST_EQ(TK::TK_SEMI);
    TEST_EQ(TK::TK_EOF);
  }

#undef DUMP_LEX
#undef TEST_EQ
}
<commit_msg>:white_check_mark: test(lexer): updated the test for lexer<commit_after>// Copyright (c) 2020 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include "harness.hh"
#include "lexer.hh"

TADPOLE_TEST(TadpoleLexer) {
  using TK = tadpole::TokenKind;
#define TEST_EQ(k)  TADPOLE_CHECK_EQ(lex.next_token().kind(), k)
#define DUMP_LEX()  do {\
    for (;;) {\
      auto t = lex.next_token();\
      std::fprintf(stdout, "%-24s | %-32s | %d\n",\
          tadpole::get_kind_name(t.kind()),\
          t.as_cstring(),\
          t.lineno());\
      if (t.kind() == TK::TK_EOF)\
        break;\
    }\
  } while (false)

  {
    std::string s =
      "print(\"Welcome to Tadpole!!!\"); var v = 45 * 34 / 23.67 + 33 - (45.4 - 56.2);";
    tadpole::Lexer lex(s);
    DUMP_LEX();
  }

  {
    std::string s = "var a = 34;";
    tadpole::Lexer lex(s);
    TEST_EQ(TK::KW_VAR);
    TEST_EQ(TK::TK_IDENTIFIER);
    TEST_EQ(TK::TK_EQ);
    TEST_EQ(TK::TK_NUMERIC);
    TEST_EQ(TK::TK_SEMI);
    TEST_EQ(TK::TK_EOF);
  }

  {
    std::string s = "print(\"34 + 56 =\", 34 + 56);";
    tadpole::Lexer lex(s);
    TEST_EQ(TK::TK_IDENTIFIER);
    TEST_EQ(TK::TK_LPAREN);
    TEST_EQ(TK::TK_STRING);
    TEST_EQ(TK::TK_COMMA);
    TEST_EQ(TK::TK_NUMERIC);
    TEST_EQ(TK::TK_PLUS);
    TEST_EQ(TK::TK_NUMERIC);
    TEST_EQ(TK::TK_RPAREN);
    TEST_EQ(TK::TK_SEMI);
    TEST_EQ(TK::TK_EOF);
  }

  {
    std::string s = "fn show(msg) { print(msg); }";
    tadpole::Lexer lex(s);
    TEST_EQ(TK::KW_FN);
    TEST_EQ(TK::TK_IDENTIFIER);
    TEST_EQ(TK::TK_LPAREN);
    TEST_EQ(TK::TK_IDENTIFIER);
    TEST_EQ(TK::TK_RPAREN);
    TEST_EQ(TK::TK_LBRACE);
    TEST_EQ(TK::TK_IDENTIFIER);
    TEST_EQ(TK::TK_LPAREN);
    TEST_EQ(TK::TK_IDENTIFIER);
    TEST_EQ(TK::TK_RPAREN);
    TEST_EQ(TK::TK_SEMI);
    TEST_EQ(TK::TK_RBRACE);
    TEST_EQ(TK::TK_EOF);
  }

  {
    std::string s = "print(45 + 56 * 22 / 8.9 - 200);";
    tadpole::Lexer lex(s);
    TEST_EQ(TK::TK_IDENTIFIER);
    TEST_EQ(TK::TK_LPAREN);
    TEST_EQ(TK::TK_NUMERIC);
    TEST_EQ(TK::TK_PLUS);
    TEST_EQ(TK::TK_NUMERIC);
    TEST_EQ(TK::TK_STAR);
    TEST_EQ(TK::TK_NUMERIC);
    TEST_EQ(TK::TK_SLASH);
    TEST_EQ(TK::TK_NUMERIC);
    TEST_EQ(TK::TK_MINUS);
    TEST_EQ(TK::TK_NUMERIC);
    TEST_EQ(TK::TK_RPAREN);
    TEST_EQ(TK::TK_SEMI);
    TEST_EQ(TK::TK_EOF);
  }

  {
    std::string s = "var a = nil; print(a, true, false);";
    tadpole::Lexer lex(s);
    TEST_EQ(TK::KW_VAR);
    TEST_EQ(TK::TK_IDENTIFIER);
    TEST_EQ(TK::TK_EQ);
    TEST_EQ(TK::KW_NIL);
    TEST_EQ(TK::TK_SEMI);
    TEST_EQ(TK::TK_IDENTIFIER);
    TEST_EQ(TK::TK_LPAREN);
    TEST_EQ(TK::TK_IDENTIFIER);
    TEST_EQ(TK::TK_COMMA);
    TEST_EQ(TK::KW_TRUE);
    TEST_EQ(TK::TK_COMMA);
    TEST_EQ(TK::KW_FALSE);
    TEST_EQ(TK::TK_RPAREN);
    TEST_EQ(TK::TK_SEMI);
    TEST_EQ(TK::TK_EOF);
  }

  {
    std::string s = "var a = \"ERROR";
    tadpole::Lexer lex(s);
    TEST_EQ(TK::KW_VAR);
    TEST_EQ(TK::TK_IDENTIFIER);
    TEST_EQ(TK::TK_EQ);
    TEST_EQ(TK::TK_ERR);
    TEST_EQ(TK::TK_EOF);
  }

#undef DUMP_LEX
#undef TEST_EQ
}
<|endoftext|>


<commit_before>// Copyright (c) 2018-2019 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <bench/bench.h>
#include <random.h>
#include <bls/bls_worker.h>
#include <utiltime.h>

#include <iostream>

CBLSWorker blsWorker;

void InitBLSTests()
{
    blsWorker.Start();
}

void CleanupBLSTests()
{
    blsWorker.Stop();
}

static void BuildTestVectors(size_t count, size_t invalidCount,
                             BLSPublicKeyVector& pubKeys, BLSSecretKeyVector& secKeys, BLSSignatureVector& sigs,
                             std::vector<uint256>& msgHashes,
                             std::vector<bool>& invalid)
{
    secKeys.resize(count);
    pubKeys.resize(count);
    sigs.resize(count);
    msgHashes.resize(count);

    invalid.resize(count);
    for (size_t i = 0; i < invalidCount; i++) {
        invalid[i] = true;
    }
    std::random_shuffle(invalid.begin(), invalid.end());

    for (size_t i = 0; i < count; i++) {
        secKeys[i].MakeNewKey();
        pubKeys[i] = secKeys[i].GetPublicKey();
        msgHashes[i] = GetRandHash();
        sigs[i] = secKeys[i].Sign(msgHashes[i]);

        if (invalid[i]) {
            CBLSSecretKey s;
            s.MakeNewKey();
            sigs[i] = s.Sign(msgHashes[i]);
        }
    }
}

static void BLSPubKeyAggregate_Normal(benchmark::State& state)
{
    CBLSSecretKey secKey1, secKey2;
    secKey1.MakeNewKey();
    secKey2.MakeNewKey();
    CBLSPublicKey pubKey1 = secKey1.GetPublicKey();
    CBLSPublicKey pubKey2 = secKey2.GetPublicKey();

    // Benchmark.
    while (state.KeepRunning()) {
        CBLSPublicKey k(pubKey1);
        k.AggregateInsecure(pubKey2);
    }
}

static void BLSSecKeyAggregate_Normal(benchmark::State& state)
{
    CBLSSecretKey secKey1, secKey2;
    secKey1.MakeNewKey();
    secKey2.MakeNewKey();
    CBLSPublicKey pubKey1 = secKey1.GetPublicKey();
    CBLSPublicKey pubKey2 = secKey2.GetPublicKey();

    // Benchmark.
    while (state.KeepRunning()) {
        CBLSSecretKey k(secKey1);
        k.AggregateInsecure(secKey2);
    }
}

static void BLSSign_Normal(benchmark::State& state)
{
    CBLSSecretKey secKey;
    secKey.MakeNewKey();
    CBLSPublicKey pubKey = secKey.GetPublicKey();

    // Benchmark.
    while (state.KeepRunning()) {
        uint256 hash = GetRandHash();
        secKey.Sign(hash);
    }
}

static void BLSVerify_Normal(benchmark::State& state)
{
    BLSPublicKeyVector pubKeys;
    BLSSecretKeyVector secKeys;
    BLSSignatureVector sigs;
    std::vector<uint256> msgHashes;
    std::vector<bool> invalid;
    BuildTestVectors(1000, 10, pubKeys, secKeys, sigs, msgHashes, invalid);

    // Benchmark.
    size_t i = 0;
    while (state.KeepRunning()) {
        bool valid = sigs[i].VerifyInsecure(pubKeys[i], msgHashes[i]);
        if (valid && invalid[i]) {
            std::cout << "expected invalid but it is valid" << std::endl;
            assert(false);
        } else if (!valid && !invalid[i]) {
            std::cout << "expected valid but it is invalid" << std::endl;
            assert(false);
        }
        i = (i + 1) % pubKeys.size();
    }
}

static void BLSVerify_LargeBlock(size_t txCount, benchmark::State& state)
{
    BLSPublicKeyVector pubKeys;
    BLSSecretKeyVector secKeys;
    BLSSignatureVector sigs;
    std::vector<uint256> msgHashes;
    std::vector<bool> invalid;
    BuildTestVectors(txCount, 0, pubKeys, secKeys, sigs, msgHashes, invalid);

    // Benchmark.
    while (state.KeepRunning()) {
        for (size_t i = 0; i < pubKeys.size(); i++) {
            sigs[i].VerifyInsecure(pubKeys[i], msgHashes[i]);
        }
    }
}

static void BLSVerify_LargeBlock1000(benchmark::State& state)
{
    BLSVerify_LargeBlock(1000, state);
}

static void BLSVerify_LargeBlock10000(benchmark::State& state)
{
    BLSVerify_LargeBlock(10000, state);
}

static void BLSVerify_LargeBlockSelfAggregated(size_t txCount, benchmark::State& state)
{
    BLSPublicKeyVector pubKeys;
    BLSSecretKeyVector secKeys;
    BLSSignatureVector sigs;
    std::vector<uint256> msgHashes;
    std::vector<bool> invalid;
    BuildTestVectors(txCount, 0, pubKeys, secKeys, sigs, msgHashes, invalid);

    // Benchmark.
    while (state.KeepRunning()) {
        CBLSSignature aggSig = CBLSSignature::AggregateInsecure(sigs);
        aggSig.VerifyInsecureAggregated(pubKeys, msgHashes);
    }
}

static void BLSVerify_LargeBlockSelfAggregated1000(benchmark::State& state)
{
    BLSVerify_LargeBlockSelfAggregated(1000, state);
}

static void BLSVerify_LargeBlockSelfAggregated10000(benchmark::State& state)
{
    BLSVerify_LargeBlockSelfAggregated(10000, state);
}

static void BLSVerify_LargeAggregatedBlock(size_t txCount, benchmark::State& state)
{
    BLSPublicKeyVector pubKeys;
    BLSSecretKeyVector secKeys;
    BLSSignatureVector sigs;
    std::vector<uint256> msgHashes;
    std::vector<bool> invalid;
    BuildTestVectors(txCount, 0, pubKeys, secKeys, sigs, msgHashes, invalid);

    CBLSSignature aggSig = CBLSSignature::AggregateInsecure(sigs);

    // Benchmark.
    while (state.KeepRunning()) {
        aggSig.VerifyInsecureAggregated(pubKeys, msgHashes);
    }
}

static void BLSVerify_LargeAggregatedBlock1000(benchmark::State& state)
{
    BLSVerify_LargeAggregatedBlock(1000, state);
}

static void BLSVerify_LargeAggregatedBlock10000(benchmark::State& state)
{
    BLSVerify_LargeAggregatedBlock(10000, state);
}

static void BLSVerify_LargeAggregatedBlock1000PreVerified(benchmark::State& state)
{
    BLSPublicKeyVector pubKeys;
    BLSSecretKeyVector secKeys;
    BLSSignatureVector sigs;
    std::vector<uint256> msgHashes;
    std::vector<bool> invalid;
    BuildTestVectors(1000, 0, pubKeys, secKeys, sigs, msgHashes, invalid);

    CBLSSignature aggSig = CBLSSignature::AggregateInsecure(sigs);

    std::set<size_t> prevalidated;

    while (prevalidated.size() < 900) {
        int idx = GetRandInt((int)pubKeys.size());
        if (prevalidated.count((size_t)idx)) {
            continue;
        }
        prevalidated.emplace((size_t)idx);
    }

    // Benchmark.
    while (state.KeepRunning()) {
        BLSPublicKeyVector nonvalidatedPubKeys;
        std::vector<uint256> nonvalidatedHashes;
        nonvalidatedPubKeys.reserve(pubKeys.size());
        nonvalidatedHashes.reserve(msgHashes.size());

        for (size_t i = 0; i < sigs.size(); i++) {
            if (prevalidated.count(i)) {
                continue;
            }
            nonvalidatedPubKeys.emplace_back(pubKeys[i]);
            nonvalidatedHashes.emplace_back(msgHashes[i]);
        }

        CBLSSignature aggSigCopy = aggSig;
        for (auto idx : prevalidated) {
            aggSigCopy.SubInsecure(sigs[idx]);
        }

        bool valid = aggSigCopy.VerifyInsecureAggregated(nonvalidatedPubKeys, nonvalidatedHashes);
        assert(valid);
    }
}

static void BLSVerify_Batched(benchmark::State& state)
{
    BLSPublicKeyVector pubKeys;
    BLSSecretKeyVector secKeys;
    BLSSignatureVector sigs;
    std::vector<uint256> msgHashes;
    std::vector<bool> invalid;
    BuildTestVectors(1000, 10, pubKeys, secKeys, sigs, msgHashes, invalid);

    // Benchmark.
    size_t i = 0;
    size_t j = 0;
    size_t batchSize = 16;
    while (state.KeepRunning()) {
        j++;
        if ((j % batchSize) != 0) {
            continue;
        }

        BLSPublicKeyVector testPubKeys;
        BLSSignatureVector testSigs;
        std::vector<uint256> testMsgHashes;
        testPubKeys.reserve(batchSize);
        testSigs.reserve(batchSize);
        testMsgHashes.reserve(batchSize);
        size_t startI = i;
        for (size_t k = 0; k < batchSize; k++) {
            testPubKeys.emplace_back(pubKeys[i]);
            testSigs.emplace_back(sigs[i]);
            testMsgHashes.emplace_back(msgHashes[i]);
            i = (i + 1) % pubKeys.size();
        }

        CBLSSignature batchSig = CBLSSignature::AggregateInsecure(testSigs);
        bool batchValid = batchSig.VerifyInsecureAggregated(testPubKeys, testMsgHashes);
        std::vector<bool> valid;
        if (batchValid) {
            valid.assign(batchSize, true);
        } else {
            for (size_t k = 0; k < batchSize; k++) {
                bool valid1 = testSigs[k].VerifyInsecure(testPubKeys[k], testMsgHashes[k]);
                valid.emplace_back(valid1);
            }
        }
        for (size_t k = 0; k < batchSize; k++) {
            if (valid[k] && invalid[(startI + k) % pubKeys.size()]) {
                std::cout << "expected invalid but it is valid" << std::endl;
                assert(false);
            } else if (!valid[k] && !invalid[(startI + k) % pubKeys.size()]) {
                std::cout << "expected valid but it is invalid" << std::endl;
                assert(false);
            }
        }
    }
}

static void BLSVerify_BatchedParallel(benchmark::State& state)
{
    BLSPublicKeyVector pubKeys;
    BLSSecretKeyVector secKeys;
    BLSSignatureVector sigs;
    std::vector<uint256> msgHashes;
    std::vector<bool> invalid;
    BuildTestVectors(1000, 10, pubKeys, secKeys, sigs, msgHashes, invalid);

    std::list<std::pair<size_t, std::future<bool>>> futures;

    volatile bool cancel = false;
    auto cancelCond = [&]() {
        return cancel;
    };

    // Benchmark.
    size_t i = 0;
    while (state.KeepRunning()) {
        if (futures.size() < 100) {
            while (futures.size() < 10000) {
                auto f = blsWorker.AsyncVerifySig(sigs[i], pubKeys[i], msgHashes[i], cancelCond);
                futures.emplace_back(std::make_pair(i, std::move(f)));
                i = (i + 1) % pubKeys.size();
            }
        }

        auto fp = std::move(futures.front());
        futures.pop_front();

        size_t j = fp.first;
        bool valid = fp.second.get();

        if (valid && invalid[j]) {
            std::cout << "expected invalid but it is valid" << std::endl;
            assert(false);
        } else if (!valid && !invalid[j]) {
            std::cout << "expected valid but it is invalid" << std::endl;
            assert(false);
        }
    }
    cancel = true;
    while (blsWorker.IsAsyncVerifyInProgress()) {
        MilliSleep(100);
    }
}

BENCHMARK(BLSPubKeyAggregate_Normal, 300 * 1000)
BENCHMARK(BLSSecKeyAggregate_Normal, 700 * 1000)
BENCHMARK(BLSSign_Normal, 600)
BENCHMARK(BLSVerify_Normal, 350)
BENCHMARK(BLSVerify_LargeBlock1000, 1)
BENCHMARK(BLSVerify_LargeBlockSelfAggregated1000, 1)
BENCHMARK(BLSVerify_LargeBlockSelfAggregated10000, 1)
BENCHMARK(BLSVerify_LargeAggregatedBlock1000, 1)
BENCHMARK(BLSVerify_LargeAggregatedBlock10000, 1)
BENCHMARK(BLSVerify_LargeAggregatedBlock1000PreVerified, 5)
BENCHMARK(BLSVerify_Batched, 500)
BENCHMARK(BLSVerify_BatchedParallel, 1000)
<commit_msg>scripted-diff: Rename bls benchmarks (#3855)<commit_after>// Copyright (c) 2018-2019 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <bench/bench.h>
#include <random.h>
#include <bls/bls_worker.h>
#include <utiltime.h>

#include <iostream>

CBLSWorker blsWorker;

void InitBLSTests()
{
    blsWorker.Start();
}

void CleanupBLSTests()
{
    blsWorker.Stop();
}

static void BuildTestVectors(size_t count, size_t invalidCount,
                             BLSPublicKeyVector& pubKeys, BLSSecretKeyVector& secKeys, BLSSignatureVector& sigs,
                             std::vector<uint256>& msgHashes,
                             std::vector<bool>& invalid)
{
    secKeys.resize(count);
    pubKeys.resize(count);
    sigs.resize(count);
    msgHashes.resize(count);

    invalid.resize(count);
    for (size_t i = 0; i < invalidCount; i++) {
        invalid[i] = true;
    }
    std::random_shuffle(invalid.begin(), invalid.end());

    for (size_t i = 0; i < count; i++) {
        secKeys[i].MakeNewKey();
        pubKeys[i] = secKeys[i].GetPublicKey();
        msgHashes[i] = GetRandHash();
        sigs[i] = secKeys[i].Sign(msgHashes[i]);

        if (invalid[i]) {
            CBLSSecretKey s;
            s.MakeNewKey();
            sigs[i] = s.Sign(msgHashes[i]);
        }
    }
}

static void BLS_PubKeyAggregate_Normal(benchmark::State& state)
{
    CBLSSecretKey secKey1, secKey2;
    secKey1.MakeNewKey();
    secKey2.MakeNewKey();
    CBLSPublicKey pubKey1 = secKey1.GetPublicKey();
    CBLSPublicKey pubKey2 = secKey2.GetPublicKey();

    // Benchmark.
    while (state.KeepRunning()) {
        CBLSPublicKey k(pubKey1);
        k.AggregateInsecure(pubKey2);
    }
}

static void BLS_SecKeyAggregate_Normal(benchmark::State& state)
{
    CBLSSecretKey secKey1, secKey2;
    secKey1.MakeNewKey();
    secKey2.MakeNewKey();
    CBLSPublicKey pubKey1 = secKey1.GetPublicKey();
    CBLSPublicKey pubKey2 = secKey2.GetPublicKey();

    // Benchmark.
    while (state.KeepRunning()) {
        CBLSSecretKey k(secKey1);
        k.AggregateInsecure(secKey2);
    }
}

static void BLS_Sign_Normal(benchmark::State& state)
{
    CBLSSecretKey secKey;
    secKey.MakeNewKey();
    CBLSPublicKey pubKey = secKey.GetPublicKey();

    // Benchmark.
    while (state.KeepRunning()) {
        uint256 hash = GetRandHash();
        secKey.Sign(hash);
    }
}

static void BLS_Verify_Normal(benchmark::State& state)
{
    BLSPublicKeyVector pubKeys;
    BLSSecretKeyVector secKeys;
    BLSSignatureVector sigs;
    std::vector<uint256> msgHashes;
    std::vector<bool> invalid;
    BuildTestVectors(1000, 10, pubKeys, secKeys, sigs, msgHashes, invalid);

    // Benchmark.
    size_t i = 0;
    while (state.KeepRunning()) {
        bool valid = sigs[i].VerifyInsecure(pubKeys[i], msgHashes[i]);
        if (valid && invalid[i]) {
            std::cout << "expected invalid but it is valid" << std::endl;
            assert(false);
        } else if (!valid && !invalid[i]) {
            std::cout << "expected valid but it is invalid" << std::endl;
            assert(false);
        }
        i = (i + 1) % pubKeys.size();
    }
}

static void BLS_Verify_LargeBlock(size_t txCount, benchmark::State& state)
{
    BLSPublicKeyVector pubKeys;
    BLSSecretKeyVector secKeys;
    BLSSignatureVector sigs;
    std::vector<uint256> msgHashes;
    std::vector<bool> invalid;
    BuildTestVectors(txCount, 0, pubKeys, secKeys, sigs, msgHashes, invalid);

    // Benchmark.
    while (state.KeepRunning()) {
        for (size_t i = 0; i < pubKeys.size(); i++) {
            sigs[i].VerifyInsecure(pubKeys[i], msgHashes[i]);
        }
    }
}

static void BLS_Verify_LargeBlock1000(benchmark::State& state)
{
    BLS_Verify_LargeBlock(1000, state);
}

static void BLS_Verify_LargeBlock10000(benchmark::State& state)
{
    BLS_Verify_LargeBlock(10000, state);
}

static void BLS_Verify_LargeBlockSelfAggregated(size_t txCount, benchmark::State& state)
{
    BLSPublicKeyVector pubKeys;
    BLSSecretKeyVector secKeys;
    BLSSignatureVector sigs;
    std::vector<uint256> msgHashes;
    std::vector<bool> invalid;
    BuildTestVectors(txCount, 0, pubKeys, secKeys, sigs, msgHashes, invalid);

    // Benchmark.
    while (state.KeepRunning()) {
        CBLSSignature aggSig = CBLSSignature::AggregateInsecure(sigs);
        aggSig.VerifyInsecureAggregated(pubKeys, msgHashes);
    }
}

static void BLS_Verify_LargeBlockSelfAggregated1000(benchmark::State& state)
{
    BLS_Verify_LargeBlockSelfAggregated(1000, state);
}

static void BLS_Verify_LargeBlockSelfAggregated10000(benchmark::State& state)
{
    BLS_Verify_LargeBlockSelfAggregated(10000, state);
}

static void BLS_Verify_LargeAggregatedBlock(size_t txCount, benchmark::State& state)
{
    BLSPublicKeyVector pubKeys;
    BLSSecretKeyVector secKeys;
    BLSSignatureVector sigs;
    std::vector<uint256> msgHashes;
    std::vector<bool> invalid;
    BuildTestVectors(txCount, 0, pubKeys, secKeys, sigs, msgHashes, invalid);

    CBLSSignature aggSig = CBLSSignature::AggregateInsecure(sigs);

    // Benchmark.
    while (state.KeepRunning()) {
        aggSig.VerifyInsecureAggregated(pubKeys, msgHashes);
    }
}

static void BLS_Verify_LargeAggregatedBlock1000(benchmark::State& state)
{
    BLS_Verify_LargeAggregatedBlock(1000, state);
}

static void BLS_Verify_LargeAggregatedBlock10000(benchmark::State& state)
{
    BLS_Verify_LargeAggregatedBlock(10000, state);
}

static void BLS_Verify_LargeAggregatedBlock1000PreVerified(benchmark::State& state)
{
    BLSPublicKeyVector pubKeys;
    BLSSecretKeyVector secKeys;
    BLSSignatureVector sigs;
    std::vector<uint256> msgHashes;
    std::vector<bool> invalid;
    BuildTestVectors(1000, 0, pubKeys, secKeys, sigs, msgHashes, invalid);

    CBLSSignature aggSig = CBLSSignature::AggregateInsecure(sigs);

    std::set<size_t> prevalidated;

    while (prevalidated.size() < 900) {
        int idx = GetRandInt((int)pubKeys.size());
        if (prevalidated.count((size_t)idx)) {
            continue;
        }
        prevalidated.emplace((size_t)idx);
    }

    // Benchmark.
    while (state.KeepRunning()) {
        BLSPublicKeyVector nonvalidatedPubKeys;
        std::vector<uint256> nonvalidatedHashes;
        nonvalidatedPubKeys.reserve(pubKeys.size());
        nonvalidatedHashes.reserve(msgHashes.size());

        for (size_t i = 0; i < sigs.size(); i++) {
            if (prevalidated.count(i)) {
                continue;
            }
            nonvalidatedPubKeys.emplace_back(pubKeys[i]);
            nonvalidatedHashes.emplace_back(msgHashes[i]);
        }

        CBLSSignature aggSigCopy = aggSig;
        for (auto idx : prevalidated) {
            aggSigCopy.SubInsecure(sigs[idx]);
        }

        bool valid = aggSigCopy.VerifyInsecureAggregated(nonvalidatedPubKeys, nonvalidatedHashes);
        assert(valid);
    }
}

static void BLS_Verify_Batched(benchmark::State& state)
{
    BLSPublicKeyVector pubKeys;
    BLSSecretKeyVector secKeys;
    BLSSignatureVector sigs;
    std::vector<uint256> msgHashes;
    std::vector<bool> invalid;
    BuildTestVectors(1000, 10, pubKeys, secKeys, sigs, msgHashes, invalid);

    // Benchmark.
    size_t i = 0;
    size_t j = 0;
    size_t batchSize = 16;
    while (state.KeepRunning()) {
        j++;
        if ((j % batchSize) != 0) {
            continue;
        }

        BLSPublicKeyVector testPubKeys;
        BLSSignatureVector testSigs;
        std::vector<uint256> testMsgHashes;
        testPubKeys.reserve(batchSize);
        testSigs.reserve(batchSize);
        testMsgHashes.reserve(batchSize);
        size_t startI = i;
        for (size_t k = 0; k < batchSize; k++) {
            testPubKeys.emplace_back(pubKeys[i]);
            testSigs.emplace_back(sigs[i]);
            testMsgHashes.emplace_back(msgHashes[i]);
            i = (i + 1) % pubKeys.size();
        }

        CBLSSignature batchSig = CBLSSignature::AggregateInsecure(testSigs);
        bool batchValid = batchSig.VerifyInsecureAggregated(testPubKeys, testMsgHashes);
        std::vector<bool> valid;
        if (batchValid) {
            valid.assign(batchSize, true);
        } else {
            for (size_t k = 0; k < batchSize; k++) {
                bool valid1 = testSigs[k].VerifyInsecure(testPubKeys[k], testMsgHashes[k]);
                valid.emplace_back(valid1);
            }
        }
        for (size_t k = 0; k < batchSize; k++) {
            if (valid[k] && invalid[(startI + k) % pubKeys.size()]) {
                std::cout << "expected invalid but it is valid" << std::endl;
                assert(false);
            } else if (!valid[k] && !invalid[(startI + k) % pubKeys.size()]) {
                std::cout << "expected valid but it is invalid" << std::endl;
                assert(false);
            }
        }
    }
}

static void BLS_Verify_BatchedParallel(benchmark::State& state)
{
    BLSPublicKeyVector pubKeys;
    BLSSecretKeyVector secKeys;
    BLSSignatureVector sigs;
    std::vector<uint256> msgHashes;
    std::vector<bool> invalid;
    BuildTestVectors(1000, 10, pubKeys, secKeys, sigs, msgHashes, invalid);

    std::list<std::pair<size_t, std::future<bool>>> futures;

    volatile bool cancel = false;
    auto cancelCond = [&]() {
        return cancel;
    };

    // Benchmark.
    size_t i = 0;
    while (state.KeepRunning()) {
        if (futures.size() < 100) {
            while (futures.size() < 10000) {
                auto f = blsWorker.AsyncVerifySig(sigs[i], pubKeys[i], msgHashes[i], cancelCond);
                futures.emplace_back(std::make_pair(i, std::move(f)));
                i = (i + 1) % pubKeys.size();
            }
        }

        auto fp = std::move(futures.front());
        futures.pop_front();

        size_t j = fp.first;
        bool valid = fp.second.get();

        if (valid && invalid[j]) {
            std::cout << "expected invalid but it is valid" << std::endl;
            assert(false);
        } else if (!valid && !invalid[j]) {
            std::cout << "expected valid but it is invalid" << std::endl;
            assert(false);
        }
    }
    cancel = true;
    while (blsWorker.IsAsyncVerifyInProgress()) {
        MilliSleep(100);
    }
}

BENCHMARK(BLS_PubKeyAggregate_Normal, 300 * 1000)
BENCHMARK(BLS_SecKeyAggregate_Normal, 700 * 1000)
BENCHMARK(BLS_Sign_Normal, 600)
BENCHMARK(BLS_Verify_Normal, 350)
BENCHMARK(BLS_Verify_LargeBlock1000, 1)
BENCHMARK(BLS_Verify_LargeBlockSelfAggregated1000, 1)
BENCHMARK(BLS_Verify_LargeBlockSelfAggregated10000, 1)
BENCHMARK(BLS_Verify_LargeAggregatedBlock1000, 1)
BENCHMARK(BLS_Verify_LargeAggregatedBlock10000, 1)
BENCHMARK(BLS_Verify_LargeAggregatedBlock1000PreVerified, 5)
BENCHMARK(BLS_Verify_Batched, 500)
BENCHMARK(BLS_Verify_BatchedParallel, 1000)
<|endoftext|>