<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.2  2002/09/30 22:20:40  peiyongz
 * Build with ICU MsgLoader
 *
 * Revision 1.1.1.1  2002/02/01 22:22:19  peiyongz
 * sane_include
 *
 * Revision 1.7  2002/01/21 14:52:25  tng
 * [Bug 5847] ICUMsgLoader can't be compiled with gcc 3.0.3 and ICU2.  And also fix the memory leak introduced by Bug 2730 fix.
 *
 * Revision 1.6  2001/11/01 23:39:18  jasons
 * 2001-11-01  Jason E. Stewart  <jason@openinformatics.com>
 *
 * 	* src/util/MsgLoaders/ICU/ICUMsgLoader.hpp (Repository):
 * 	* src/util/MsgLoaders/ICU/ICUMsgLoader.cpp (Repository):
 * 	Updated to compile with ICU-1.8.1
 *
 * Revision 1.5  2000/03/02 19:55:14  roddey
 * This checkin includes many changes done while waiting for the
 * 1.1.0 code to be finished. I can't list them all here, but a list is
 * available elsewhere.
 *
 * Revision 1.4  2000/02/06 07:48:21  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.3  2000/01/19 00:58:38  roddey
 * Update to support new ICU 1.4 release.
 *
 * Revision 1.2  1999/11/19 21:24:03  aruna1
 * incorporated ICU 1.3.1 related changes int he file
 *
 * Revision 1.1.1.1  1999/11/09 01:07:23  twl
 * Initial checkin
 *
 * Revision 1.4  1999/11/08 20:45:26  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <xercesc/util/XercesDefs.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/XMLMsgLoader.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/XMLUniDefs.hpp>
#include "ICUMsgLoader.hpp"

#include "string.h"
#include <stdio.h>
#include <stdlib.h>

// ---------------------------------------------------------------------------
//  Local static methods
// ---------------------------------------------------------------------------

// ---------------------------------------------------------------------------
//  Public Constructors and Destructor
// ---------------------------------------------------------------------------
ICUMsgLoader::ICUMsgLoader(const XMLCh* const  msgDomain)
:fRootBundle(0)
,fDomainBundle(0)
{
    // validation on msgDomain
    if (XMLString::compareString(msgDomain, XMLUni::fgXMLErrDomain)
    &&  XMLString::compareString(msgDomain, XMLUni::fgExceptDomain)
    &&  XMLString::compareString(msgDomain, XMLUni::fgValidityDomain))
    {
        XMLPlatformUtils::panic(XMLPlatformUtils::Panic_UnknownMsgDomain);
    }

    //
    // we hardcode the path for "root.res" for now
    // assuming that Makefile would copy root.res from $ICUROOT/bin to $XERCESCROOT/bin
    //
    char tempBuf[1024];
    strcpy(tempBuf, getenv("XERCESCROOT"));
    strcat(tempBuf, "/bin/root.res");

    UErrorCode err = U_ZERO_ERROR;
    fRootBundle = ures_open(tempBuf, 0, &err);
    if (!U_SUCCESS(err) || fRootBundle == NULL)
    {
        XMLPlatformUtils::panic(XMLPlatformUtils::Panic_CantLoadMsgDomain);
    }

     //strip off path information, if any
     int   index = XMLString::lastIndexOf(msgDomain, chForwardSlash);
     char *domainName = XMLString::transcode(&(msgDomain[index + 1]));

     // get the resource bundle for the domain
     fDomainBundle = ures_getByKey(fRootBundle, domainName, NULL, &err);

     delete [] domainName;

     if (!U_SUCCESS(err) || fDomainBundle == NULL)
    {
        XMLPlatformUtils::panic(XMLPlatformUtils::Panic_CantLoadMsgDomain);
    }

}

ICUMsgLoader::~ICUMsgLoader()
{
    ures_close(fDomainBundle);
    ures_close(fRootBundle);
}

// ---------------------------------------------------------------------------
//  Implementation of the virtual message loader API
// ---------------------------------------------------------------------------
bool ICUMsgLoader::loadMsg( const   XMLMsgLoader::XMLMsgId  msgToLoad
                          ,         XMLCh* const            toFill
                          , const   unsigned int            maxChars)
{
    UErrorCode   err = U_ZERO_ERROR;
    int32_t      strLen = 0;

    // Assuming array format
    const UChar *name = ures_getStringByIndex(fDomainBundle, (int32_t)msgToLoad-1, &strLen, &err);

    if (!U_SUCCESS(err) || (name == NULL))
    {
        return false;
    }

    int retStrLen = strLen > maxChars ? maxChars : strLen;

    if (sizeof(UChar)==sizeof(XMLCh))
    {
        XMLString::moveChars(toFill, (XMLCh*)name, retStrLen);
        toFill[retStrLen] = (XMLCh) 0;
    }
    else
    {
        XMLCh* retStr = toFill;
        const UChar *srcPtr = name;

        while (retStrLen--)
           *retStr++ = *srcPtr++;

        *retStr = 0;
    }

    return true;
}

bool ICUMsgLoader::loadMsg( const   XMLMsgLoader::XMLMsgId  msgToLoad
                            ,       XMLCh* const            toFill
                            , const unsigned int           maxChars
                            , const XMLCh* const            repText1
                            , const XMLCh* const            repText2
                            , const XMLCh* const            repText3
                            , const XMLCh* const            repText4)
{
    // Call the other version to load up the message
    if (!loadMsg(msgToLoad, toFill, maxChars))
        return false;

    // And do the token replacement
    XMLString::replaceTokens(toFill, maxChars, repText1, repText2, repText3, repText4);
    return true;
}

bool ICUMsgLoader::loadMsg( const   XMLMsgLoader::XMLMsgId  msgToLoad
                            ,       XMLCh* const            toFill
                            , const unsigned int           maxChars
                            , const char* const             repText1
                            , const char* const             repText2
                            , const char* const             repText3
                            , const char* const             repText4)
{
    //
    //  Transcode the provided parameters and call the other version,
    //  which will do the replacement work.
    //
    XMLCh* tmp1 = 0;
    XMLCh* tmp2 = 0;
    XMLCh* tmp3 = 0;
    XMLCh* tmp4 = 0;

    bool bRet = false;
    if (repText1)
        tmp1 = XMLString::transcode(repText1);
    if (repText2)
        tmp2 = XMLString::transcode(repText2);
    if (repText3)
        tmp3 = XMLString::transcode(repText3);
    if (repText4)
        tmp4 = XMLString::transcode(repText4);

    bRet = loadMsg(msgToLoad, toFill, maxChars, tmp1, tmp2, tmp3, tmp4);

    if (tmp1)
        delete [] tmp1;
    if (tmp2)
        delete [] tmp2;
    if (tmp3)
        delete [] tmp3;
    if (tmp4)
        delete [] tmp4;

    return bRet;
}
<commit_msg>XMLString::equals() to replace XMLString::compareString()<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.3  2002/10/02 17:08:50  peiyongz
 * XMLString::equals() to replace XMLString::compareString()
 *
 * Revision 1.2  2002/09/30 22:20:40  peiyongz
 * Build with ICU MsgLoader
 *
 * Revision 1.1.1.1  2002/02/01 22:22:19  peiyongz
 * sane_include
 *
 * Revision 1.7  2002/01/21 14:52:25  tng
 * [Bug 5847] ICUMsgLoader can't be compiled with gcc 3.0.3 and ICU2.  And also fix the memory leak introduced by Bug 2730 fix.
 *
 * Revision 1.6  2001/11/01 23:39:18  jasons
 * 2001-11-01  Jason E. Stewart  <jason@openinformatics.com>
 *
 * 	* src/util/MsgLoaders/ICU/ICUMsgLoader.hpp (Repository):
 * 	* src/util/MsgLoaders/ICU/ICUMsgLoader.cpp (Repository):
 * 	Updated to compile with ICU-1.8.1
 *
 * Revision 1.5  2000/03/02 19:55:14  roddey
 * This checkin includes many changes done while waiting for the
 * 1.1.0 code to be finished. I can't list them all here, but a list is
 * available elsewhere.
 *
 * Revision 1.4  2000/02/06 07:48:21  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.3  2000/01/19 00:58:38  roddey
 * Update to support new ICU 1.4 release.
 *
 * Revision 1.2  1999/11/19 21:24:03  aruna1
 * incorporated ICU 1.3.1 related changes int he file
 *
 * Revision 1.1.1.1  1999/11/09 01:07:23  twl
 * Initial checkin
 *
 * Revision 1.4  1999/11/08 20:45:26  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <xercesc/util/XercesDefs.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/XMLMsgLoader.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/XMLUniDefs.hpp>
#include "ICUMsgLoader.hpp"

#include "string.h"
#include <stdio.h>
#include <stdlib.h>

// ---------------------------------------------------------------------------
//  Local static methods
// ---------------------------------------------------------------------------

// ---------------------------------------------------------------------------
//  Public Constructors and Destructor
// ---------------------------------------------------------------------------
ICUMsgLoader::ICUMsgLoader(const XMLCh* const  msgDomain)
:fRootBundle(0)
,fDomainBundle(0)
{
    // validation on msgDomain
    if (!XMLString::equals(msgDomain, XMLUni::fgXMLErrDomain)    &&
        !XMLString::equals(msgDomain, XMLUni::fgExceptDomain)    &&
        !XMLString::equals(msgDomain, XMLUni::fgValidityDomain)   )
    {
        XMLPlatformUtils::panic(XMLPlatformUtils::Panic_UnknownMsgDomain);
    }

    //
    // we hardcode the path for "root.res" for now
    // assuming that Makefile would copy root.res from $ICUROOT/bin to $XERCESCROOT/bin
    //
    char tempBuf[1024];
    strcpy(tempBuf, getenv("XERCESCROOT"));
    strcat(tempBuf, "/bin/root.res");

    UErrorCode err = U_ZERO_ERROR;
    fRootBundle = ures_open(tempBuf, 0, &err);
    if (!U_SUCCESS(err) || fRootBundle == NULL)
    {
        XMLPlatformUtils::panic(XMLPlatformUtils::Panic_CantLoadMsgDomain);
    }

     //strip off path information, if any
     int   index = XMLString::lastIndexOf(msgDomain, chForwardSlash);
     char *domainName = XMLString::transcode(&(msgDomain[index + 1]));

     // get the resource bundle for the domain
     fDomainBundle = ures_getByKey(fRootBundle, domainName, NULL, &err);

     delete [] domainName;

     if (!U_SUCCESS(err) || fDomainBundle == NULL)
    {
        XMLPlatformUtils::panic(XMLPlatformUtils::Panic_CantLoadMsgDomain);
    }

}

ICUMsgLoader::~ICUMsgLoader()
{
    ures_close(fDomainBundle);
    ures_close(fRootBundle);
}

// ---------------------------------------------------------------------------
//  Implementation of the virtual message loader API
// ---------------------------------------------------------------------------
bool ICUMsgLoader::loadMsg( const   XMLMsgLoader::XMLMsgId  msgToLoad
                          ,         XMLCh* const            toFill
                          , const   unsigned int            maxChars)
{
    UErrorCode   err = U_ZERO_ERROR;
    int32_t      strLen = 0;

    // Assuming array format
    const UChar *name = ures_getStringByIndex(fDomainBundle, (int32_t)msgToLoad-1, &strLen, &err);

    if (!U_SUCCESS(err) || (name == NULL))
    {
        return false;
    }

    int retStrLen = strLen > maxChars ? maxChars : strLen;

    if (sizeof(UChar)==sizeof(XMLCh))
    {
        XMLString::moveChars(toFill, (XMLCh*)name, retStrLen);
        toFill[retStrLen] = (XMLCh) 0;
    }
    else
    {
        XMLCh* retStr = toFill;
        const UChar *srcPtr = name;

        while (retStrLen--)
           *retStr++ = *srcPtr++;

        *retStr = 0;
    }

    return true;
}

bool ICUMsgLoader::loadMsg( const   XMLMsgLoader::XMLMsgId  msgToLoad
                            ,       XMLCh* const            toFill
                            , const unsigned int           maxChars
                            , const XMLCh* const            repText1
                            , const XMLCh* const            repText2
                            , const XMLCh* const            repText3
                            , const XMLCh* const            repText4)
{
    // Call the other version to load up the message
    if (!loadMsg(msgToLoad, toFill, maxChars))
        return false;

    // And do the token replacement
    XMLString::replaceTokens(toFill, maxChars, repText1, repText2, repText3, repText4);
    return true;
}

bool ICUMsgLoader::loadMsg( const   XMLMsgLoader::XMLMsgId  msgToLoad
                            ,       XMLCh* const            toFill
                            , const unsigned int           maxChars
                            , const char* const             repText1
                            , const char* const             repText2
                            , const char* const             repText3
                            , const char* const             repText4)
{
    //
    //  Transcode the provided parameters and call the other version,
    //  which will do the replacement work.
    //
    XMLCh* tmp1 = 0;
    XMLCh* tmp2 = 0;
    XMLCh* tmp3 = 0;
    XMLCh* tmp4 = 0;

    bool bRet = false;
    if (repText1)
        tmp1 = XMLString::transcode(repText1);
    if (repText2)
        tmp2 = XMLString::transcode(repText2);
    if (repText3)
        tmp3 = XMLString::transcode(repText3);
    if (repText4)
        tmp4 = XMLString::transcode(repText4);

    bRet = loadMsg(msgToLoad, toFill, maxChars, tmp1, tmp2, tmp3, tmp4);

    if (tmp1)
        delete [] tmp1;
    if (tmp2)
        delete [] tmp2;
    if (tmp3)
        delete [] tmp3;
    if (tmp4)
        delete [] tmp4;

    return bRet;
}
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_SCAL_PROB_NEG_BINOMIAL_2_LPMF_HPP
#define STAN_MATH_PRIM_SCAL_PROB_NEG_BINOMIAL_2_LPMF_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/scal/err/check_consistent_sizes.hpp>
#include <stan/math/prim/scal/err/check_positive_finite.hpp>
#include <stan/math/prim/scal/err/check_nonnegative.hpp>
#include <stan/math/prim/scal/fun/size_zero.hpp>
#include <stan/math/prim/scal/fun/multiply_log.hpp>
#include <stan/math/prim/scal/fun/digamma.hpp>
#include <stan/math/prim/scal/fun/lgamma.hpp>
#include <stan/math/prim/scal/fun/value_of.hpp>
#include <stan/math/prim/scal/prob/poisson_lpmf.hpp>
#include <cmath>

namespace stan {
namespace math {

namespace internal {
  //Exposing to let me us this in tests
  constexpr double neg_binomial_2_phi_cutoff = 1e5;
}

// NegBinomial(n|mu, phi)  [mu >= 0; phi > 0;  n >= 0]
template <bool propto, typename T_n, typename T_location, typename T_precision>
return_type_t<T_location, T_precision> neg_binomial_2_lpmf(
    const T_n& n, const T_location& mu, const T_precision& phi) {
  using T_partials_return = partials_return_t<T_n, T_location, T_precision>;

  static const char* function = "neg_binomial_2_lpmf";

  if (size_zero(n, mu, phi)) {
    return 0.0;
  }

  T_partials_return logp(0.0);
  check_nonnegative(function, "Failures variable", n);
  check_positive_finite(function, "Location parameter", mu);
  check_positive_finite(function, "Precision parameter", phi);
  check_consistent_sizes(function, "Failures variable", n, "Location parameter",
                         mu, "Precision parameter", phi);

  if (!include_summand<propto, T_location, T_precision>::value) {
    return 0.0;
  }

  using std::log;

  scalar_seq_view<T_n> n_vec(n);
  scalar_seq_view<T_location> mu_vec(mu);
  scalar_seq_view<T_precision> phi_vec(phi);
  size_t size = max_size(n, mu, phi);

  operands_and_partials<T_location, T_precision> ops_partials(mu, phi);

  size_t len_ep = max_size(mu, phi);
  size_t len_np = max_size(n, phi);

  VectorBuilder<true, T_partials_return, T_location> mu__(length(mu));
  for (size_t i = 0, size = length(mu); i < size; ++i) {
    mu__[i] = value_of(mu_vec[i]);
  }

  VectorBuilder<true, T_partials_return, T_precision> phi__(length(phi));
  for (size_t i = 0, size = length(phi); i < size; ++i) {
    phi__[i] = value_of(phi_vec[i]);
  }

  VectorBuilder<true, T_partials_return, T_precision> log_phi(length(phi));
  for (size_t i = 0, size = length(phi); i < size; ++i) {
    log_phi[i] = log(phi__[i]);
  }

  VectorBuilder<true, T_partials_return, T_location, T_precision>
      log_mu_plus_phi(len_ep);
  for (size_t i = 0; i < len_ep; ++i) {
    log_mu_plus_phi[i] = log(mu__[i] + phi__[i]);
  }

  VectorBuilder<true, T_partials_return, T_n, T_precision> n_plus_phi(len_np);
  for (size_t i = 0; i < len_np; ++i) {
    n_plus_phi[i] = n_vec[i] + phi__[i];
  }

  for (size_t i = 0; i < size; i++) {
    if (include_summand<propto>::value) {
      logp -= lgamma(n_vec[i] + 1.0);
    }
    if (include_summand<propto, T_precision>::value) {
      logp += multiply_log(phi__[i], phi__[i]) - lgamma(phi__[i]);
    }
    if (include_summand<propto, T_location, T_precision>::value) {
      logp -= (n_plus_phi[i]) * log_mu_plus_phi[i];
    }
    if (include_summand<propto, T_location>::value) {
      logp += multiply_log(n_vec[i], mu__[i]);
    }
    if (include_summand<propto, T_precision>::value) {
      logp += lgamma(n_plus_phi[i]);
    }

    // if phi is large we probably overflow, defer to Poisson:
    if (phi__[i] > internal::neg_binomial_2_phi_cutoff) {
      logp = poisson_lpmf(n_vec[i], mu__[i]);
    }

    if (!is_constant_all<T_location>::value) {
      ops_partials.edge1_.partials_[i]
          += n_vec[i] / mu__[i] - (n_vec[i] + phi__[i]) / (mu__[i] + phi__[i]);
    }
    if (!is_constant_all<T_precision>::value) {
      ops_partials.edge2_.partials_[i]
          += 1.0 - n_plus_phi[i] / (mu__[i] + phi__[i]) + log_phi[i]
             - log_mu_plus_phi[i] - digamma(phi__[i]) + digamma(n_plus_phi[i]);
    }
  }
  return ops_partials.build(logp);
}

template <typename T_n, typename T_location, typename T_precision>
inline return_type_t<T_location, T_precision> neg_binomial_2_lpmf(
    const T_n& n, const T_location& mu, const T_precision& phi) {
  return neg_binomial_2_lpmf<false>(n, mu, phi);
}

}  // namespace math
}  // namespace stan
#endif
<commit_msg>Phi cutoff no longer overrides logp accumulator<commit_after>#ifndef STAN_MATH_PRIM_SCAL_PROB_NEG_BINOMIAL_2_LPMF_HPP
#define STAN_MATH_PRIM_SCAL_PROB_NEG_BINOMIAL_2_LPMF_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/scal/err/check_consistent_sizes.hpp>
#include <stan/math/prim/scal/err/check_positive_finite.hpp>
#include <stan/math/prim/scal/err/check_nonnegative.hpp>
#include <stan/math/prim/scal/fun/size_zero.hpp>
#include <stan/math/prim/scal/fun/multiply_log.hpp>
#include <stan/math/prim/scal/fun/digamma.hpp>
#include <stan/math/prim/scal/fun/lgamma.hpp>
#include <stan/math/prim/scal/fun/value_of.hpp>
#include <stan/math/prim/scal/prob/poisson_lpmf.hpp>
#include <cmath>

namespace stan {
namespace math {

namespace internal {
  //Exposing to let me us this in tests
  constexpr double neg_binomial_2_phi_cutoff = 1e5;
}

// NegBinomial(n|mu, phi)  [mu >= 0; phi > 0;  n >= 0]
template <bool propto, typename T_n, typename T_location, typename T_precision>
return_type_t<T_location, T_precision> neg_binomial_2_lpmf(
    const T_n& n, const T_location& mu, const T_precision& phi) {
  using T_partials_return = partials_return_t<T_n, T_location, T_precision>;

  static const char* function = "neg_binomial_2_lpmf";

  if (size_zero(n, mu, phi)) {
    return 0.0;
  }

  T_partials_return logp(0.0);
  check_nonnegative(function, "Failures variable", n);
  check_positive_finite(function, "Location parameter", mu);
  check_positive_finite(function, "Precision parameter", phi);
  check_consistent_sizes(function, "Failures variable", n, "Location parameter",
                         mu, "Precision parameter", phi);

  if (!include_summand<propto, T_location, T_precision>::value) {
    return 0.0;
  }

  using std::log;

  scalar_seq_view<T_n> n_vec(n);
  scalar_seq_view<T_location> mu_vec(mu);
  scalar_seq_view<T_precision> phi_vec(phi);
  size_t size = max_size(n, mu, phi);

  operands_and_partials<T_location, T_precision> ops_partials(mu, phi);

  size_t len_ep = max_size(mu, phi);
  size_t len_np = max_size(n, phi);

  VectorBuilder<true, T_partials_return, T_location> mu__(length(mu));
  for (size_t i = 0, size = length(mu); i < size; ++i) {
    mu__[i] = value_of(mu_vec[i]);
  }

  VectorBuilder<true, T_partials_return, T_precision> phi__(length(phi));
  for (size_t i = 0, size = length(phi); i < size; ++i) {
    phi__[i] = value_of(phi_vec[i]);
  }

  VectorBuilder<true, T_partials_return, T_precision> log_phi(length(phi));
  for (size_t i = 0, size = length(phi); i < size; ++i) {
    log_phi[i] = log(phi__[i]);
  }

  VectorBuilder<true, T_partials_return, T_location, T_precision>
      log_mu_plus_phi(len_ep);
  for (size_t i = 0; i < len_ep; ++i) {
    log_mu_plus_phi[i] = log(mu__[i] + phi__[i]);
  }

  VectorBuilder<true, T_partials_return, T_n, T_precision> n_plus_phi(len_np);
  for (size_t i = 0; i < len_np; ++i) {
    n_plus_phi[i] = n_vec[i] + phi__[i];
  }

  for (size_t i = 0; i < size; i++) {
    // if phi is large we probably overflow, defer to Poisson:
    if (phi__[i] > internal::neg_binomial_2_phi_cutoff) {
      logp += poisson_lpmf(n_vec[i], mu__[i]);
      continue;
    }

    if (include_summand<propto>::value) {
      logp -= lgamma(n_vec[i] + 1.0);
    }
    if (include_summand<propto, T_precision>::value) {
      logp += multiply_log(phi__[i], phi__[i]) - lgamma(phi__[i]);
    }
    if (include_summand<propto, T_location, T_precision>::value) {
      logp -= (n_plus_phi[i]) * log_mu_plus_phi[i];
    }
    if (include_summand<propto, T_location>::value) {
      logp += multiply_log(n_vec[i], mu__[i]);
    }
    if (include_summand<propto, T_precision>::value) {
      logp += lgamma(n_plus_phi[i]);
    }

    if (!is_constant_all<T_location>::value) {
      ops_partials.edge1_.partials_[i]
          += n_vec[i] / mu__[i] - (n_vec[i] + phi__[i]) / (mu__[i] + phi__[i]);
    }
    if (!is_constant_all<T_precision>::value) {
      ops_partials.edge2_.partials_[i]
          += 1.0 - n_plus_phi[i] / (mu__[i] + phi__[i]) + log_phi[i]
             - log_mu_plus_phi[i] - digamma(phi__[i]) + digamma(n_plus_phi[i]);
    }
  }
  return ops_partials.build(logp);
}

template <typename T_n, typename T_location, typename T_precision>
inline return_type_t<T_location, T_precision> neg_binomial_2_lpmf(
    const T_n& n, const T_location& mu, const T_precision& phi) {
  return neg_binomial_2_lpmf<false>(n, mu, phi);
}

}  // namespace math
}  // namespace stan
#endif
<|endoftext|>


<commit_before>/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.

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

// Implementation for the DebugLog() function that prints to the UART on the
// SparkFun Edge microcontroller. The same should work for other targets using
// the Ambiq Apollo 3.

#include "tensorflow/lite/micro/debug_log.h"
#include "hx_drv_tflm.h"

extern "C" void DebugLog(const char* s) {
  static bool is_initialized = false;
  if (!is_initialized) {
    hx_drv_uart_initial();
    is_initialized = true;
  }

  hx_drv_uart_print("%s", s);
}
<commit_msg>remove unuse comment<commit_after>/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.

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 "tensorflow/lite/micro/debug_log.h"
#include "hx_drv_tflm.h"

extern "C" void DebugLog(const char* s) {
  static bool is_initialized = false;
  if (!is_initialized) {
    hx_drv_uart_initial();
    is_initialized = true;
  }

  hx_drv_uart_print("%s", s);
}
<|endoftext|>


<commit_before>#include "writer/verilog/axi/slave_controller.h"

#include "writer/verilog/axi/slave_port.h"
#include "writer/verilog/module.h"
#include "writer/verilog/ports.h"

namespace iroha {
namespace writer {
namespace verilog {
namespace axi {

SlaveController::SlaveController(const IResource &res,
				 bool reset_polarity)
  : AxiController(res, reset_polarity) {
  ports_.reset(new Ports);
}

SlaveController::~SlaveController() {
}

void SlaveController::Write(ostream &os) {
  string name = SlavePort::ControllerName(res_, reset_polarity_);
  os << "// slave controller: "
     << name << "\n";
  AddSramPorts();
  string initials;
  GenReadChannel(cfg_, false, nullptr, ports_.get(), &initials);
  GenWriteChannel(cfg_, false, nullptr, ports_.get(), &initials);
  os << "module " << name << "(";
  ports_->Output(Ports::PORT_NAME, os);
  os << ");\n";
  ports_->Output(Ports::PORT_TYPE, os);

  os << "  `define S_IDLE 0\n"
     << "  `define S_READ 1\n"
     << "  `define S_WRITE 2\n";
  os << "  reg [1:0] st;\n\n";
  os << "  reg [" << sram_addr_width_ << ":0] idx;\n\n";
  os << "  reg first_addr;";
  os << "  reg [1:0] rlen;\n\n";

  os << "  always @(posedge clk) begin\n"
     << "    if (" << (reset_polarity_ ? "" : "!")
     << ResetName(reset_polarity_) << ") begin\n"
     << "      st <= `S_IDLE;\n"
     << "      first_addr <= 0;\n"
     << "      rlen <= 0;\n";
  os << initials
     << "    end else begin\n";
  OutputFSM(os);
  os << "    end\n"
     << "  end\n"
     << "endmodule\n";
}

void SlaveController::AddPorts(const PortConfig &cfg, Module *mod, string *s) {
  Ports *ports = mod->GetPorts();
  GenWriteChannel(cfg, false, mod, ports, s);
  GenReadChannel(cfg, false, mod, ports, s);
}

void SlaveController::OutputFSM(ostream &os) {
  os << "      sram_wen <= (st == `S_WRITE && WVALID);\n"
     << "      RLAST <= (st == `S_READ && rlen == 0);\n";
  os << "      case (st)\n"
     << "        `S_IDLE: begin\n"
     << "          if (ARVALID) begin\n"
     << "            st <= `S_READ;\n"
     << "            ARREADY <= 1;\n"
     << "            sram_addr <= ARADDR[" << (sram_addr_width_ - 1) << ":0];\n"
     << "            rlen <= ARLEN;\n"
     << "          end else if (AWVALID) begin\n"
     << "            st <= `S_WRITE;\n"
     << "            AWREADY <= 1;\n"
     << "            first_addr <= 1;\n"
     << "            sram_addr <= AWADDR[" << (sram_addr_width_ - 1) << ":0];\n"
     << "            WREADY <= 1;\n"
     << "          end\n"
     << "        end\n"
     << "        `S_READ: begin\n"
     << "          ARREADY <= 0;\n"
     << "          RVALID <= 1;\n"
     << "          if (RREADY) begin\n"
     << "            sram_addr <= sram_addr + 1;\n"
     << "            rlen <= rlen - 1;\n"
     << "          end\n"
     << "          RDATA <= sram_rdata;\n"
     << "        end\n"
     << "        `S_WRITE: begin\n"
     << "          AWREADY <= 0;\n"
     << "          if (WVALID) begin\n"
     << "            sram_wdata <= WDATA;\n"
     << "            if (first_addr) begin\n"
     << "              first_addr <= 0;\n"
     << "            end else begin\n"
     << "              sram_addr <= sram_addr + 1;\n"
     << "            end\n"
     << "          end\n"
     << "          if (WLAST && WVALID) begin\n"
     << "            st <= `S_IDLE;\n"
     << "            WREADY <= 0;\n"
     << "          end\n"
     << "        end\n";
  os << "      endcase\n";
}

}  // namespace axi
}  // namespace verilog
}  // namespace writer
}  // namespace iroha
<commit_msg>Fix AXI read state to finish properly.<commit_after>#include "writer/verilog/axi/slave_controller.h"

#include "writer/verilog/axi/slave_port.h"
#include "writer/verilog/module.h"
#include "writer/verilog/ports.h"

namespace iroha {
namespace writer {
namespace verilog {
namespace axi {

SlaveController::SlaveController(const IResource &res,
				 bool reset_polarity)
  : AxiController(res, reset_polarity) {
  ports_.reset(new Ports);
}

SlaveController::~SlaveController() {
}

void SlaveController::Write(ostream &os) {
  string name = SlavePort::ControllerName(res_, reset_polarity_);
  os << "// slave controller: "
     << name << "\n";
  AddSramPorts();
  string initials;
  GenReadChannel(cfg_, false, nullptr, ports_.get(), &initials);
  GenWriteChannel(cfg_, false, nullptr, ports_.get(), &initials);
  os << "module " << name << "(";
  ports_->Output(Ports::PORT_NAME, os);
  os << ");\n";
  ports_->Output(Ports::PORT_TYPE, os);

  os << "  `define S_IDLE 0\n"
     << "  `define S_READ 1\n"
     << "  `define S_WRITE 2\n";
  os << "  reg [1:0] st;\n\n";
  os << "  reg [" << sram_addr_width_ << ":0] idx;\n\n";
  os << "  reg first_addr;";
  os << "  reg [7:0] rlen;\n\n";

  os << "  always @(posedge clk) begin\n"
     << "    if (" << (reset_polarity_ ? "" : "!")
     << ResetName(reset_polarity_) << ") begin\n"
     << "      st <= `S_IDLE;\n"
     << "      first_addr <= 0;\n"
     << "      rlen <= 0;\n";
  os << initials
     << "    end else begin\n";
  OutputFSM(os);
  os << "    end\n"
     << "  end\n"
     << "endmodule\n";
}

void SlaveController::AddPorts(const PortConfig &cfg, Module *mod, string *s) {
  Ports *ports = mod->GetPorts();
  GenWriteChannel(cfg, false, mod, ports, s);
  GenReadChannel(cfg, false, mod, ports, s);
}

void SlaveController::OutputFSM(ostream &os) {
  os << "      sram_wen <= (st == `S_WRITE && WVALID);\n"
     << "      RLAST <= (st == `S_READ && rlen == 0);\n";
  os << "      case (st)\n"
     << "        `S_IDLE: begin\n"
     << "          if (ARVALID) begin\n"
     << "            st <= `S_READ;\n"
     << "            ARREADY <= 1;\n"
     << "            sram_addr <= ARADDR[" << (sram_addr_width_ - 1) << ":0];\n"
     << "            rlen <= ARLEN;\n"
     << "          end else if (AWVALID) begin\n"
     << "            st <= `S_WRITE;\n"
     << "            AWREADY <= 1;\n"
     << "            first_addr <= 1;\n"
     << "            sram_addr <= AWADDR[" << (sram_addr_width_ - 1) << ":0];\n"
     << "            WREADY <= 1;\n"
     << "          end\n"
     << "        end\n"
     << "        `S_READ: begin\n"
     << "          ARREADY <= 0;\n"
     << "          RVALID <= 1;\n"
     << "          if (RREADY && RVALID) begin\n"
     << "            sram_addr <= sram_addr + 1;\n"
     << "            rlen <= rlen - 1;\n"
     << "            if (rlen == 0) begin\n"
     << "              st <= `S_IDLE;\n"
     << "            end\n"
     << "          end\n"
     << "          RDATA <= sram_rdata;\n"
     << "        end\n"
     << "        `S_WRITE: begin\n"
     << "          AWREADY <= 0;\n"
     << "          if (WVALID) begin\n"
     << "            sram_wdata <= WDATA;\n"
     << "            if (first_addr) begin\n"
     << "              first_addr <= 0;\n"
     << "            end else begin\n"
     << "              sram_addr <= sram_addr + 1;\n"
     << "            end\n"
     << "          end\n"
     << "          if (WLAST && WVALID) begin\n"
     << "            st <= `S_IDLE;\n"
     << "            WREADY <= 0;\n"
     << "          end\n"
     << "        end\n";
  os << "      endcase\n";
}

}  // namespace axi
}  // namespace verilog
}  // namespace writer
}  // namespace iroha
<|endoftext|>


<commit_before>#include "test.h"

static_BOX(box3, 1, sizeof(unsigned));

static unsigned sent;

static void proc3()
{
	unsigned received;
	unsigned event;

 	event = box_wait(box3, &received);           assert_success(event);
 	                                             assert(received == sent);
	event = box_give(box2, &received);           assert_success(event);
	        tsk_stop();
}

static void proc2()
{
	unsigned received;
	unsigned event;
		                                         assert_dead(tsk3);
	        tsk_startFrom(tsk3, proc3);
 	event = box_wait(box2, &received);           assert_success(event);
 	                                             assert(received == sent);
	event = box_give(box3, &received);           assert_success(event);
 	event = box_wait(box2, &received);           assert_success(event);
 	                                             assert(received == sent);
	event = box_give(box1, &received);           assert_success(event);
	event = tsk_join(tsk3);                      assert_success(event);
	        tsk_stop();
}

static void proc1()
{
	unsigned received;
	unsigned event;
		                                         assert_dead(tsk2);
	        tsk_startFrom(tsk2, proc2);
 	event = box_wait(box1, &received);           assert_success(event);
 	                                             assert(received == sent);
	event = box_give(box2, &received);           assert_success(event);
 	event = box_wait(box1, &received);           assert_success(event);
 	                                             assert(received == sent);
	event = box_give(&box0, &received);          assert_success(event);
	event = tsk_join(tsk2);                      assert_success(event);
	        tsk_stop();
}

static void proc0()
{
	unsigned received;
	unsigned event;
		                                         assert_dead(tsk1);
	        tsk_startFrom(tsk1, proc1);
	        sent = rand();
	event = box_give(box1, &sent);               assert_success(event);
 	event = box_wait(&box0, &received);          assert_success(event);
 	                                             assert(received == sent);
	event = tsk_join(tsk1);                      assert_success(event);
	        tsk_stop();
}

static void test()
{
	unsigned event;
		                                         assert_dead(&tsk0);
	        tsk_startFrom(&tsk0, proc0);
	event = tsk_join(&tsk0);                     assert_success(event);
}

extern "C"
void test_mailbox_queue_2()
{
	TEST_Notify();
	TEST_Call();
}
<commit_msg>Update test_mailbox_queue_2.cpp<commit_after>#include "test.h"

static_BOX(box3, 1, sizeof(unsigned));

static unsigned sent;

static void proc3()
{
	unsigned received;
	unsigned event;

 	event = box_wait(box3, &received);           assert_success(event);
 	                                             assert(received == sent);
	event = box_give(box2, &received);           assert_success(event);
	        tsk_stop();
}

static void proc2()
{
	unsigned received;
	unsigned event;
		                                         assert_dead(tsk3);
	        tsk_startFrom(tsk3, proc3);          assert_ready(tsk3);
 	event = box_wait(box2, &received);           assert_success(event);
 	                                             assert(received == sent);
	event = box_give(box3, &received);           assert_success(event);
 	event = box_wait(box2, &received);           assert_success(event);
 	                                             assert(received == sent);
	event = box_give(box1, &received);           assert_success(event);
	event = tsk_join(tsk3);                      assert_success(event);
	        tsk_stop();
}

static void proc1()
{
	unsigned received;
	unsigned event;
		                                         assert_dead(tsk2);
	        tsk_startFrom(tsk2, proc2);          assert_ready(tsk2);
 	event = box_wait(box1, &received);           assert_success(event);
 	                                             assert(received == sent);
	event = box_give(box2, &received);           assert_success(event);
 	event = box_wait(box1, &received);           assert_success(event);
 	                                             assert(received == sent);
	event = box_give(&box0, &received);          assert_success(event);
	event = tsk_join(tsk2);                      assert_success(event);
	        tsk_stop();
}

static void proc0()
{
	unsigned received;
	unsigned event;
		                                         assert_dead(tsk1);
	        tsk_startFrom(tsk1, proc1);          assert_ready(tsk1);
 	event = box_wait(&box0, &received);          assert_success(event);
 	                                             assert(received == sent);
	event = box_give(box1, &received);           assert_success(event);
 	event = box_wait(&box0, &received);          assert_success(event);
 	                                             assert(received == sent);
	event = tsk_join(tsk1);                      assert_success(event);
	        tsk_stop();
}

static void test()
{
	unsigned event;
		                                         assert_dead(&tsk0);
	        tsk_startFrom(&tsk0, proc0);         assert_ready(&tsk0);
	        tsk_yield();
	        tsk_yield();
	        sent = rand();
	event = box_give(&box0, &sent);              assert_success(event);
	event = tsk_join(&tsk0);                     assert_success(event);
}

extern "C"
void test_mailbox_queue_2()
{
	TEST_Notify();
	TEST_Call();
}
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_CORE_INIT_THREADPOOL_TBB_HPP
#define STAN_MATH_PRIM_CORE_INIT_THREADPOOL_TBB_HPP

#include <stan/math/prim/err/invalid_argument.hpp>

#include <boost/lexical_cast.hpp>

#include <tbb/tbb_stddef.h>

#if TBB_VERSION_MAJOR == 2020
#ifndef TBB_INTERFACE_NEW
#define TBB_INTERFACE_NEW
#endif
#endif

#ifdef TBB_INTERFACE_NEW
#include <tbb/global_control.h>
#include <tbb/task_arena.h>
#else
#include <tbb/task_scheduler_init.h>
#endif

#include <cstdlib>
#include <thread>

namespace stan {
namespace math {
namespace internal {

/**
 * Get number of threads to use. The function uses the environment
 * variable STAN_NUM_THREADS and follows these conventions:
 *
 * - STAN_NUM_THREADS is not defined => num_threads=1
 * - STAN_NUM_THREADS is positive => num_threads is set to the
 *   specified number
 * - STAN_NUM_THREADS is set to -1 => num_threads is the number of
 *   available cores on the machine
 * - STAN_NUM_THREADS < -1, STAN_NUM_THREADS = 0 or STAN_NUM_THREADS is
 *   not numeric => throws an exception
 *
 * @return number of threads to use
 * @throws std::invalid_argument if the value of STAN_NUM_THREADS env. variable
 * is invalid
 */
inline int get_num_threads() {
  int num_threads = 1;
  const char* env_stan_num_threads = std::getenv("STAN_NUM_THREADS");
  if (env_stan_num_threads != nullptr) {
    try {
      const int env_num_threads
          = boost::lexical_cast<int>(env_stan_num_threads);
      if (env_num_threads > 0) {
        num_threads = env_num_threads;
      } else if (env_num_threads == -1) {
        num_threads = std::thread::hardware_concurrency();
      } else {
        invalid_argument("get_num_threads(int)", "STAN_NUM_THREADS",
                         env_stan_num_threads,
                         "The STAN_NUM_THREADS environment variable is '",
                         "' but it must be positive or -1");
      }
    } catch (const boost::bad_lexical_cast&) {
      invalid_argument("get_num_threads(int)", "STAN_NUM_THREADS",
                       env_stan_num_threads,
                       "The STAN_NUM_THREADS environment variable is '",
                       "' but it must be a positive number or -1");
    }
  }
  return num_threads;
}

}  // namespace internal

#ifdef TBB_INTERFACE_NEW
/**
 * Initialize the Intel TBB threadpool and global scheduler through
 * the tbb::task_arena object. In case an instance of the
 * tbb::task_scheduler_object has been instantiated prior to calling
 * this function, then any subsequent initialization is ignored by the
 * Intel TBB.
 *
 * The maximal number of threads is read from the environment variable
 * STAN_NUM_THREADS using internal::get_num_threads. See conventions
 * of get_num_threads. The TBB scheduler will be activated by calling
 * this function.
 *
 * The function returns a reference to the static
 * tbb::global_control instance.
 *
 * @return reference to the static tbb::global_control
 * @throws std::runtime_error if the value of STAN_NUM_THREADS env. variable
 * is invalid
 */
inline tbb::task_arena& init_threadpool_tbb() {
  int tbb_max_threads = internal::get_num_threads();
  static tbb::global_control tbb_gc(
      tbb::global_control::max_allowed_parallelism, tbb_max_threads);

  static tbb::task_arena tbb_arena(tbb_max_threads, 1);
  tbb_arena.initialize();

  return tbb_arena;
}
#else
/**
 * Initialize the Intel TBB threadpool and global scheduler through
 * the tbb::task_scheduler_init object. In case an instance of the
 * tbb::task_scheduler_object has been instantiated prior to calling
 * this function, then any subsequent initialization is ignored by the
 * Intel TBB.
 *
 * The maximal number of threads is read from the environment variable
 * STAN_NUM_THREADS using internal::get_num_threads. See conventions
 * of get_num_threads. The TBB scheduler will be activated by calling
 * this function.
 *
 * The function returns a reference to the static
 * tbb::task_scheduler_init instance.
 *
 * @param stack_size sets the stack size of each thread; the default 0
 * let's the TBB choose the stack size
 * @return reference to the static tbb::task_scheduler_init
 * @throws std::runtime_error if the value of STAN_NUM_THREADS env. variable
 * is invalid
 */
inline tbb::task_scheduler_init& init_threadpool_tbb(
    tbb::stack_size_type stack_size = 0) {
  int tbb_max_threads = internal::get_num_threads();

  static tbb::task_scheduler_init tbb_scheduler(tbb_max_threads, stack_size);

  return tbb_scheduler;
}
#endif

}  // namespace math
}  // namespace stan

#endif
<commit_msg>use tbb version major macro for deciding to use new interface<commit_after>#ifndef STAN_MATH_PRIM_CORE_INIT_THREADPOOL_TBB_HPP
#define STAN_MATH_PRIM_CORE_INIT_THREADPOOL_TBB_HPP

#include <stan/math/prim/err/invalid_argument.hpp>

#include <boost/lexical_cast.hpp>

#include <tbb/tbb_stddef.h>

#if TBB_VERSION_MAJOR >= 2020
#ifndef TBB_INTERFACE_NEW
#define TBB_INTERFACE_NEW
#endif
#endif

#ifdef TBB_INTERFACE_NEW
#include <tbb/global_control.h>
#include <tbb/task_arena.h>
#else
#include <tbb/task_scheduler_init.h>
#endif

#include <cstdlib>
#include <thread>

namespace stan {
namespace math {
namespace internal {

/**
 * Get number of threads to use. The function uses the environment
 * variable STAN_NUM_THREADS and follows these conventions:
 *
 * - STAN_NUM_THREADS is not defined => num_threads=1
 * - STAN_NUM_THREADS is positive => num_threads is set to the
 *   specified number
 * - STAN_NUM_THREADS is set to -1 => num_threads is the number of
 *   available cores on the machine
 * - STAN_NUM_THREADS < -1, STAN_NUM_THREADS = 0 or STAN_NUM_THREADS is
 *   not numeric => throws an exception
 *
 * @return number of threads to use
 * @throws std::invalid_argument if the value of STAN_NUM_THREADS env. variable
 * is invalid
 */
inline int get_num_threads() {
  int num_threads = 1;
  const char* env_stan_num_threads = std::getenv("STAN_NUM_THREADS");
  if (env_stan_num_threads != nullptr) {
    try {
      const int env_num_threads
          = boost::lexical_cast<int>(env_stan_num_threads);
      if (env_num_threads > 0) {
        num_threads = env_num_threads;
      } else if (env_num_threads == -1) {
        num_threads = std::thread::hardware_concurrency();
      } else {
        invalid_argument("get_num_threads(int)", "STAN_NUM_THREADS",
                         env_stan_num_threads,
                         "The STAN_NUM_THREADS environment variable is '",
                         "' but it must be positive or -1");
      }
    } catch (const boost::bad_lexical_cast&) {
      invalid_argument("get_num_threads(int)", "STAN_NUM_THREADS",
                       env_stan_num_threads,
                       "The STAN_NUM_THREADS environment variable is '",
                       "' but it must be a positive number or -1");
    }
  }
  return num_threads;
}

}  // namespace internal

#ifdef TBB_INTERFACE_NEW
/**
 * Initialize the Intel TBB threadpool and global scheduler through
 * the tbb::task_arena object. In case an instance of the
 * tbb::task_scheduler_object has been instantiated prior to calling
 * this function, then any subsequent initialization is ignored by the
 * Intel TBB.
 *
 * The maximal number of threads is read from the environment variable
 * STAN_NUM_THREADS using internal::get_num_threads. See conventions
 * of get_num_threads. The TBB scheduler will be activated by calling
 * this function.
 *
 * The function returns a reference to the static
 * tbb::global_control instance.
 *
 * @return reference to the static tbb::global_control
 * @throws std::runtime_error if the value of STAN_NUM_THREADS env. variable
 * is invalid
 */
inline tbb::task_arena& init_threadpool_tbb() {
  int tbb_max_threads = internal::get_num_threads();
  static tbb::global_control tbb_gc(
      tbb::global_control::max_allowed_parallelism, tbb_max_threads);

  static tbb::task_arena tbb_arena(tbb_max_threads, 1);
  tbb_arena.initialize();

  return tbb_arena;
}
#else
/**
 * Initialize the Intel TBB threadpool and global scheduler through
 * the tbb::task_scheduler_init object. In case an instance of the
 * tbb::task_scheduler_object has been instantiated prior to calling
 * this function, then any subsequent initialization is ignored by the
 * Intel TBB.
 *
 * The maximal number of threads is read from the environment variable
 * STAN_NUM_THREADS using internal::get_num_threads. See conventions
 * of get_num_threads. The TBB scheduler will be activated by calling
 * this function.
 *
 * The function returns a reference to the static
 * tbb::task_scheduler_init instance.
 *
 * @param stack_size sets the stack size of each thread; the default 0
 * let's the TBB choose the stack size
 * @return reference to the static tbb::task_scheduler_init
 * @throws std::runtime_error if the value of STAN_NUM_THREADS env. variable
 * is invalid
 */
inline tbb::task_scheduler_init& init_threadpool_tbb(
    tbb::stack_size_type stack_size = 0) {
  int tbb_max_threads = internal::get_num_threads();

  static tbb::task_scheduler_init tbb_scheduler(tbb_max_threads, stack_size);

  return tbb_scheduler;
}
#endif

}  // namespace math
}  // namespace stan

#endif
<|endoftext|>


<commit_before>#include <cmath>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <unistd.h>

#include "Hydro.hpp"

using namespace std;

const int W = 200, H = 200;

void dump (string fn, Hydro &sim) {
  ofstream ofs (fn.c_str());
  for (int iy = 0; iy < H; ++iy) {
    for (int ix = 0; ix < W; ++ix) {
      double x = sim.dR0() * (ix+0.5);
      double y = sim.dR0() * (iy+0.5);
      int i = W * iy + ix;
      ofs << x << " " << y << " "
          << sim.density()[i] << " "
          << sim.velocity0()[i] << " "
          << sim.velocity1()[i] << " "
          << sim.pressure()[i] << endl;
    }
  }
}

int main () {
  Hydro sim(W, H);
  sim.time() = 0;
  sim.extent0() = 1.0;
  sim.extent1() = 1.0;
  sim.dR0() = sim.extent0() / W;
  sim.dR1() = sim.extent1() / H;
  sim.init_kh();
  dump("begin.txt", sim);
  for (;;) {
    cerr << sim.time() << endl;
    sim.proceed();
    if (sim.time() >1.0) break;
  }
  dump("end.txt", sim);
}
<commit_msg>Anime generator .<commit_after>#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <unistd.h>

#include "Hydro.hpp"

using namespace std;

const int W = 200, H = 200;

void dump (string fn, Hydro &sim) {
  ofstream ofs (fn.c_str());
  for (int iy = 0; iy < H; ++iy) {
    for (int ix = 0; ix < W; ++ix) {
      double x = sim.dR0() * (ix+0.5);
      double y = sim.dR0() * (iy+0.5);
      int i = W * iy + ix;
      ofs << x << " " << y << " "
          << sim.density()[i] << " "
          << sim.velocity0()[i] << " "
          << sim.velocity1()[i] << " "
          << sim.pressure()[i] << endl;
    }
  }
}

int main () {
  Hydro sim(W, H);
  sim.time() = 0;
  sim.extent0() = 1.0;
  sim.extent1() = 1.0;
  sim.dR0() = sim.extent0() / W;
  sim.dR1() = sim.extent1() / H;
  sim.init_kh();
  int ctr = 0;
  system("mkdir -p output");
  while (ctr <= 100) {
    cerr << sim.time() << endl;
    sim.proceed();
    if (sim.time() > 0.1 * ctr) {
      char buf[256];
      sprintf(buf, "output/snapshot%04d", ctr);
      dump(buf, sim);
      ++ctr;
    }
  }
}
<|endoftext|>


<commit_before>/*
 * ngtcp2
 *
 * Copyright (c) 2017 ngtcp2 contributors
 *
 * 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 "crypto.h"

#if !defined(OPENSSL_IS_BORINGSSL)

#  include <cassert>

#  include <openssl/evp.h>
#  include <openssl/kdf.h>

#  include "template.h"

namespace ngtcp2 {

namespace crypto {

int negotiated_prf(Context &ctx, SSL *ssl) {
  switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) {
  case 0x03001301u: // TLS_AES_128_GCM_SHA256
  case 0x03001303u: // TLS_CHACHA20_POLY1305_SHA256
    ctx.prf = EVP_sha256();
    return 0;
  case 0x03001302u: // TLS_AES_256_GCM_SHA384
    ctx.prf = EVP_sha384();
    return 0;
  default:
    return -1;
  }
}

int negotiated_aead(Context &ctx, SSL *ssl) {
  switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) {
  case 0x03001301u: // TLS_AES_128_GCM_SHA256
    ctx.aead = EVP_aes_128_gcm();
    ctx.hp = EVP_aes_128_ecb();
    return 0;
  case 0x03001302u: // TLS_AES_256_GCM_SHA384
    ctx.aead = EVP_aes_256_gcm();
    ctx.hp = EVP_aes_256_ecb();
    return 0;
  case 0x03001303u: // TLS_CHACHA20_POLY1305_SHA256
    ctx.aead = EVP_chacha20_poly1305();
    ctx.hp = EVP_chacha20();
    return 0;
  default:
    return -1;
  }
}

static size_t aead_tag_length(const Context &ctx) {
  if (ctx.aead == EVP_aes_128_gcm() || ctx.aead == EVP_aes_256_gcm()) {
    return EVP_GCM_TLS_TAG_LEN;
  }
  if (ctx.aead == EVP_chacha20_poly1305()) {
    return EVP_CHACHAPOLY_TLS_TAG_LEN;
  }
  assert(0);
}

ssize_t encrypt(uint8_t *dest, size_t destlen, const uint8_t *plaintext,
                size_t plaintextlen, const Context &ctx, const uint8_t *key,
                size_t keylen, const uint8_t *nonce, size_t noncelen,
                const uint8_t *ad, size_t adlen) {
  auto taglen = aead_tag_length(ctx);

  if (destlen < plaintextlen + taglen) {
    return -1;
  }

  auto actx = EVP_CIPHER_CTX_new();
  if (actx == nullptr) {
    return -1;
  }

  auto actx_d = defer(EVP_CIPHER_CTX_free, actx);

  if (EVP_EncryptInit_ex(actx, ctx.aead, nullptr, nullptr, nullptr) != 1) {
    return -1;
  }

  if (EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_IVLEN, noncelen, nullptr) !=
      1) {
    return -1;
  }

  if (EVP_EncryptInit_ex(actx, nullptr, nullptr, key, nonce) != 1) {
    return -1;
  }

  size_t outlen = 0;
  int len;

  if (EVP_EncryptUpdate(actx, nullptr, &len, ad, adlen) != 1) {
    return -1;
  }

  if (EVP_EncryptUpdate(actx, dest, &len, plaintext, plaintextlen) != 1) {
    return -1;
  }

  outlen = len;

  if (EVP_EncryptFinal_ex(actx, dest + outlen, &len) != 1) {
    return -1;
  }

  outlen += len;

  assert(outlen + taglen <= destlen);

  if (EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_GET_TAG, taglen, dest + outlen) !=
      1) {
    return -1;
  }

  outlen += taglen;

  return outlen;
}

ssize_t decrypt(uint8_t *dest, size_t destlen, const uint8_t *ciphertext,
                size_t ciphertextlen, const Context &ctx, const uint8_t *key,
                size_t keylen, const uint8_t *nonce, size_t noncelen,
                const uint8_t *ad, size_t adlen) {
  auto taglen = aead_tag_length(ctx);

  if (taglen > ciphertextlen || destlen + taglen < ciphertextlen) {
    return -1;
  }

  ciphertextlen -= taglen;
  auto tag = ciphertext + ciphertextlen;

  auto actx = EVP_CIPHER_CTX_new();
  if (actx == nullptr) {
    return -1;
  }

  auto actx_d = defer(EVP_CIPHER_CTX_free, actx);

  if (EVP_DecryptInit_ex(actx, ctx.aead, nullptr, nullptr, nullptr) != 1) {
    return -1;
  }

  if (EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_IVLEN, noncelen, nullptr) !=
      1) {
    return -1;
  }

  if (EVP_DecryptInit_ex(actx, nullptr, nullptr, key, nonce) != 1) {
    return -1;
  }

  size_t outlen;
  int len;

  if (EVP_DecryptUpdate(actx, nullptr, &len, ad, adlen) != 1) {
    return -1;
  }

  if (EVP_DecryptUpdate(actx, dest, &len, ciphertext, ciphertextlen) != 1) {
    return -1;
  }

  outlen = len;

  if (EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_TAG, taglen,
                          const_cast<uint8_t *>(tag)) != 1) {
    return -1;
  }

  if (EVP_DecryptFinal_ex(actx, dest + outlen, &len) != 1) {
    return -1;
  }

  outlen += len;

  return outlen;
}

size_t aead_max_overhead(const Context &ctx) { return aead_tag_length(ctx); }

size_t aead_key_length(const Context &ctx) {
  return EVP_CIPHER_key_length(ctx.aead);
}

size_t aead_nonce_length(const Context &ctx) {
  return EVP_CIPHER_iv_length(ctx.aead);
}

ssize_t hp_mask(uint8_t *dest, size_t destlen, const Context &ctx,
                const uint8_t *key, size_t keylen, const uint8_t *sample,
                size_t samplelen) {
  static constexpr uint8_t CHACHA_INPUT[] = "\x00\x00\x00\x00\x00";
  const uint8_t *iv = nullptr;
  const uint8_t *plaintext;
  size_t plaintextlen;

  auto actx = EVP_CIPHER_CTX_new();
  if (actx == nullptr) {
    return -1;
  }

  auto actx_d = defer(EVP_CIPHER_CTX_free, actx);

  if (ctx.hp == EVP_chacha20()) {
    iv = sample;
    plaintext = CHACHA_INPUT;
    plaintextlen = sizeof(CHACHA_INPUT) - 1;
  } else {
    plaintext = sample;
    plaintextlen = samplelen;
  }

  if (EVP_EncryptInit_ex(actx, ctx.hp, nullptr, key, iv) != 1) {
    return -1;
  }
  if (EVP_CIPHER_CTX_set_padding(actx, 0) != 1) {
    return -1;
  }

  size_t outlen = 0;
  int len;

  if (EVP_EncryptUpdate(actx, dest, &len, plaintext, plaintextlen) != 1) {
    return -1;
  }

  assert(len > 0);

  outlen = len;

  if (EVP_EncryptFinal_ex(actx, dest + outlen, &len) != 1) {
    return -1;
  }

  assert(len == 0);

  return outlen;
}

int hkdf_expand(uint8_t *dest, size_t destlen, const uint8_t *secret,
                size_t secretlen, const uint8_t *info, size_t infolen,
                const Context &ctx) {
  auto pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr);
  if (pctx == nullptr) {
    return -1;
  }

  auto pctx_d = defer(EVP_PKEY_CTX_free, pctx);

  if (EVP_PKEY_derive_init(pctx) != 1) {
    return -1;
  }

  if (EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY) != 1) {
    return -1;
  }

  if (EVP_PKEY_CTX_set_hkdf_md(pctx, ctx.prf) != 1) {
    return -1;
  }

  if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, "", 0) != 1) {
    return -1;
  }

  if (EVP_PKEY_CTX_set1_hkdf_key(pctx, secret, secretlen) != 1) {
    return -1;
  }

  if (EVP_PKEY_CTX_add1_hkdf_info(pctx, info, infolen) != 1) {
    return -1;
  }

  if (EVP_PKEY_derive(pctx, dest, &destlen) != 1) {
    return -1;
  }

  return 0;
}

int hkdf_extract(uint8_t *dest, size_t destlen, const uint8_t *secret,
                 size_t secretlen, const uint8_t *salt, size_t saltlen,
                 const Context &ctx) {
  auto pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr);
  if (pctx == nullptr) {
    return -1;
  }

  auto pctx_d = defer(EVP_PKEY_CTX_free, pctx);

  if (EVP_PKEY_derive_init(pctx) != 1) {
    return -1;
  }

  if (EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY) != 1) {
    return -1;
  }

  if (EVP_PKEY_CTX_set_hkdf_md(pctx, ctx.prf) != 1) {
    return -1;
  }

  if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, salt, saltlen) != 1) {
    return -1;
  }

  if (EVP_PKEY_CTX_set1_hkdf_key(pctx, secret, secretlen) != 1) {
    return -1;
  }

  if (EVP_PKEY_derive(pctx, dest, &destlen) != 1) {
    return -1;
  }

  return 0;
}

void prf_sha256(Context &ctx) { ctx.prf = EVP_sha256(); }

void aead_aes_128_gcm(Context &ctx) {
  ctx.aead = EVP_aes_128_gcm();
  ctx.hp = EVP_aes_128_ecb();
}

int message_digest(uint8_t *res, const EVP_MD *meth, const uint8_t *data,
                   size_t len) {
  int rv;

  auto ctx = EVP_MD_CTX_new();
  if (ctx == nullptr) {
    return -1;
  }

  auto ctx_deleter = defer(EVP_MD_CTX_free, ctx);

  rv = EVP_DigestInit_ex(ctx, meth, nullptr);
  if (rv != 1) {
    return -1;
  }

  rv = EVP_DigestUpdate(ctx, data, len);
  if (rv != 1) {
    return -1;
  }

  unsigned int mdlen = EVP_MD_size(meth);

  rv = EVP_DigestFinal_ex(ctx, res, &mdlen);
  if (rv != 1) {
    return -1;
  }

  return 0;
}

} // namespace crypto

} // namespace ngtcp2

#endif // !defined(OPENSSL_IS_BORINGSSL)
<commit_msg>Just use AES-CTR for simplicity<commit_after>/*
 * ngtcp2
 *
 * Copyright (c) 2017 ngtcp2 contributors
 *
 * 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 "crypto.h"

#if !defined(OPENSSL_IS_BORINGSSL)

#  include <cassert>

#  include <openssl/evp.h>
#  include <openssl/kdf.h>

#  include "template.h"

namespace ngtcp2 {

namespace crypto {

int negotiated_prf(Context &ctx, SSL *ssl) {
  switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) {
  case 0x03001301u: // TLS_AES_128_GCM_SHA256
  case 0x03001303u: // TLS_CHACHA20_POLY1305_SHA256
    ctx.prf = EVP_sha256();
    return 0;
  case 0x03001302u: // TLS_AES_256_GCM_SHA384
    ctx.prf = EVP_sha384();
    return 0;
  default:
    return -1;
  }
}

int negotiated_aead(Context &ctx, SSL *ssl) {
  switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) {
  case 0x03001301u: // TLS_AES_128_GCM_SHA256
    ctx.aead = EVP_aes_128_gcm();
    ctx.hp = EVP_aes_128_ctr();
    return 0;
  case 0x03001302u: // TLS_AES_256_GCM_SHA384
    ctx.aead = EVP_aes_256_gcm();
    ctx.hp = EVP_aes_256_ctr();
    return 0;
  case 0x03001303u: // TLS_CHACHA20_POLY1305_SHA256
    ctx.aead = EVP_chacha20_poly1305();
    ctx.hp = EVP_chacha20();
    return 0;
  default:
    return -1;
  }
}

static size_t aead_tag_length(const Context &ctx) {
  if (ctx.aead == EVP_aes_128_gcm() || ctx.aead == EVP_aes_256_gcm()) {
    return EVP_GCM_TLS_TAG_LEN;
  }
  if (ctx.aead == EVP_chacha20_poly1305()) {
    return EVP_CHACHAPOLY_TLS_TAG_LEN;
  }
  assert(0);
}

ssize_t encrypt(uint8_t *dest, size_t destlen, const uint8_t *plaintext,
                size_t plaintextlen, const Context &ctx, const uint8_t *key,
                size_t keylen, const uint8_t *nonce, size_t noncelen,
                const uint8_t *ad, size_t adlen) {
  auto taglen = aead_tag_length(ctx);

  if (destlen < plaintextlen + taglen) {
    return -1;
  }

  auto actx = EVP_CIPHER_CTX_new();
  if (actx == nullptr) {
    return -1;
  }

  auto actx_d = defer(EVP_CIPHER_CTX_free, actx);

  if (EVP_EncryptInit_ex(actx, ctx.aead, nullptr, nullptr, nullptr) != 1) {
    return -1;
  }

  if (EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_IVLEN, noncelen, nullptr) !=
      1) {
    return -1;
  }

  if (EVP_EncryptInit_ex(actx, nullptr, nullptr, key, nonce) != 1) {
    return -1;
  }

  size_t outlen = 0;
  int len;

  if (EVP_EncryptUpdate(actx, nullptr, &len, ad, adlen) != 1) {
    return -1;
  }

  if (EVP_EncryptUpdate(actx, dest, &len, plaintext, plaintextlen) != 1) {
    return -1;
  }

  outlen = len;

  if (EVP_EncryptFinal_ex(actx, dest + outlen, &len) != 1) {
    return -1;
  }

  outlen += len;

  assert(outlen + taglen <= destlen);

  if (EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_GET_TAG, taglen, dest + outlen) !=
      1) {
    return -1;
  }

  outlen += taglen;

  return outlen;
}

ssize_t decrypt(uint8_t *dest, size_t destlen, const uint8_t *ciphertext,
                size_t ciphertextlen, const Context &ctx, const uint8_t *key,
                size_t keylen, const uint8_t *nonce, size_t noncelen,
                const uint8_t *ad, size_t adlen) {
  auto taglen = aead_tag_length(ctx);

  if (taglen > ciphertextlen || destlen + taglen < ciphertextlen) {
    return -1;
  }

  ciphertextlen -= taglen;
  auto tag = ciphertext + ciphertextlen;

  auto actx = EVP_CIPHER_CTX_new();
  if (actx == nullptr) {
    return -1;
  }

  auto actx_d = defer(EVP_CIPHER_CTX_free, actx);

  if (EVP_DecryptInit_ex(actx, ctx.aead, nullptr, nullptr, nullptr) != 1) {
    return -1;
  }

  if (EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_IVLEN, noncelen, nullptr) !=
      1) {
    return -1;
  }

  if (EVP_DecryptInit_ex(actx, nullptr, nullptr, key, nonce) != 1) {
    return -1;
  }

  size_t outlen;
  int len;

  if (EVP_DecryptUpdate(actx, nullptr, &len, ad, adlen) != 1) {
    return -1;
  }

  if (EVP_DecryptUpdate(actx, dest, &len, ciphertext, ciphertextlen) != 1) {
    return -1;
  }

  outlen = len;

  if (EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_TAG, taglen,
                          const_cast<uint8_t *>(tag)) != 1) {
    return -1;
  }

  if (EVP_DecryptFinal_ex(actx, dest + outlen, &len) != 1) {
    return -1;
  }

  outlen += len;

  return outlen;
}

size_t aead_max_overhead(const Context &ctx) { return aead_tag_length(ctx); }

size_t aead_key_length(const Context &ctx) {
  return EVP_CIPHER_key_length(ctx.aead);
}

size_t aead_nonce_length(const Context &ctx) {
  return EVP_CIPHER_iv_length(ctx.aead);
}

ssize_t hp_mask(uint8_t *dest, size_t destlen, const Context &ctx,
                const uint8_t *key, size_t keylen, const uint8_t *sample,
                size_t samplelen) {
  static constexpr uint8_t PLAINTEXT[] = "\x00\x00\x00\x00\x00";

  auto actx = EVP_CIPHER_CTX_new();
  if (actx == nullptr) {
    return -1;
  }

  auto actx_d = defer(EVP_CIPHER_CTX_free, actx);

  if (EVP_EncryptInit_ex(actx, ctx.hp, nullptr, key, sample) != 1) {
    return -1;
  }

  size_t outlen = 0;
  int len;

  if (EVP_EncryptUpdate(actx, dest, &len, PLAINTEXT, str_size(PLAINTEXT)) !=
      1) {
    return -1;
  }

  assert(len == 5);

  outlen = len;

  if (EVP_EncryptFinal_ex(actx, dest + outlen, &len) != 1) {
    return -1;
  }

  assert(len == 0);

  return outlen;
}

int hkdf_expand(uint8_t *dest, size_t destlen, const uint8_t *secret,
                size_t secretlen, const uint8_t *info, size_t infolen,
                const Context &ctx) {
  auto pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr);
  if (pctx == nullptr) {
    return -1;
  }

  auto pctx_d = defer(EVP_PKEY_CTX_free, pctx);

  if (EVP_PKEY_derive_init(pctx) != 1) {
    return -1;
  }

  if (EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY) != 1) {
    return -1;
  }

  if (EVP_PKEY_CTX_set_hkdf_md(pctx, ctx.prf) != 1) {
    return -1;
  }

  if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, "", 0) != 1) {
    return -1;
  }

  if (EVP_PKEY_CTX_set1_hkdf_key(pctx, secret, secretlen) != 1) {
    return -1;
  }

  if (EVP_PKEY_CTX_add1_hkdf_info(pctx, info, infolen) != 1) {
    return -1;
  }

  if (EVP_PKEY_derive(pctx, dest, &destlen) != 1) {
    return -1;
  }

  return 0;
}

int hkdf_extract(uint8_t *dest, size_t destlen, const uint8_t *secret,
                 size_t secretlen, const uint8_t *salt, size_t saltlen,
                 const Context &ctx) {
  auto pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr);
  if (pctx == nullptr) {
    return -1;
  }

  auto pctx_d = defer(EVP_PKEY_CTX_free, pctx);

  if (EVP_PKEY_derive_init(pctx) != 1) {
    return -1;
  }

  if (EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY) != 1) {
    return -1;
  }

  if (EVP_PKEY_CTX_set_hkdf_md(pctx, ctx.prf) != 1) {
    return -1;
  }

  if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, salt, saltlen) != 1) {
    return -1;
  }

  if (EVP_PKEY_CTX_set1_hkdf_key(pctx, secret, secretlen) != 1) {
    return -1;
  }

  if (EVP_PKEY_derive(pctx, dest, &destlen) != 1) {
    return -1;
  }

  return 0;
}

void prf_sha256(Context &ctx) { ctx.prf = EVP_sha256(); }

void aead_aes_128_gcm(Context &ctx) {
  ctx.aead = EVP_aes_128_gcm();
  ctx.hp = EVP_aes_128_ctr();
}

int message_digest(uint8_t *res, const EVP_MD *meth, const uint8_t *data,
                   size_t len) {
  int rv;

  auto ctx = EVP_MD_CTX_new();
  if (ctx == nullptr) {
    return -1;
  }

  auto ctx_deleter = defer(EVP_MD_CTX_free, ctx);

  rv = EVP_DigestInit_ex(ctx, meth, nullptr);
  if (rv != 1) {
    return -1;
  }

  rv = EVP_DigestUpdate(ctx, data, len);
  if (rv != 1) {
    return -1;
  }

  unsigned int mdlen = EVP_MD_size(meth);

  rv = EVP_DigestFinal_ex(ctx, res, &mdlen);
  if (rv != 1) {
    return -1;
  }

  return 0;
}

} // namespace crypto

} // namespace ngtcp2

#endif // !defined(OPENSSL_IS_BORINGSSL)
<|endoftext|>


<commit_before>/*
    Copyright (C) 2016  P.L. Lucas <selairi@gmail.com>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "brightnesssettings.h"
#include "outputwidget.h"
#include <QMessageBox>
#include <QPushButton>

BrightnessSettings::BrightnessSettings(QWidget *parent):QDialog(parent)
{
    ui = new Ui::BrightnessSettings();
    ui->setupUi(this);

    mBrightness = new XRandrBrightness();
    mMonitors = mBrightness->getMonitorsInfo();
    mBacklight = new LXQt::Backlight(this);

    ui->backlightSlider->setEnabled(mBacklight->isBacklightAvailable());
    if(mBacklight->isBacklightAvailable()) {
        ui->backlightSlider->setMaximum(mBacklight->getMaxBacklight());
        ui->backlightSlider->setValue(mLastBacklightValue = mBacklight->getBacklight());
        connect(ui->backlightSlider, &QSlider::valueChanged, this, &BrightnessSettings::setBacklight);
    }

    for(const MonitorInfo &monitor: qAsConst(mMonitors))
    {
        OutputWidget *output = new OutputWidget(monitor, this);
        ui->layout->addWidget(output);
        output->show();
        connect(output, SIGNAL(changed(MonitorInfo)), this, SLOT(monitorSettingsChanged(MonitorInfo)));
        connect(this, &BrightnessSettings::monitorReverted, output, &OutputWidget::setRevertedValues);
    }

    mConfirmRequestTimer.setSingleShot(true);
    mConfirmRequestTimer.setInterval(1000);
    connect(&mConfirmRequestTimer, &QTimer::timeout, this, &BrightnessSettings::requestConfirmation);

}

void BrightnessSettings::setBacklight(int value)
{
    mBacklight->setBacklight(value);
    mConfirmRequestTimer.start();
}

void BrightnessSettings::monitorSettingsChanged(MonitorInfo monitor)
{
    mBrightness->setMonitorsSettings(QList<MonitorInfo>{}  << monitor);
    if (ui->confirmCB->isChecked())
    {
        mConfirmRequestTimer.start();
    } else
    {
        for (auto & m : mMonitors)
        {
            if (m.id() == monitor.id() && m.name() == monitor.name())
            {
                m.setBacklight(monitor.backlight());
                m.setBrightness(monitor.brightness());
            }
        }
    }
}

void BrightnessSettings::requestConfirmation()
{
    QMessageBox msg{QMessageBox::Question, tr("Brightness settings changed")
        , tr("Confirmation required. Are the settings correct?")
        , QMessageBox::Yes | QMessageBox::No};
    int timeout = 5; // seconds
    QString no_text = msg.button(QMessageBox::No)->text();
    no_text += QStringLiteral("(%1)");
    msg.setButtonText(QMessageBox::No, no_text.arg(timeout));
    msg.setDefaultButton(QMessageBox::No);

    QTimer timeoutTimer;
    timeoutTimer.setSingleShot(false);
    timeoutTimer.setInterval(1000);
    connect(&timeoutTimer, &QTimer::timeout, [&] {
        msg.setButtonText(QMessageBox::No, no_text.arg(--timeout));
        if (timeout == 0)
        {
            timeoutTimer.stop();
            msg.reject();
        }
    });
    timeoutTimer.start();

    if (QMessageBox::Yes == msg.exec())
    {
        // re-read current values
        if(mBacklight->isBacklightAvailable())
            mLastBacklightValue = mBacklight->getBacklight();

        mMonitors = mBrightness->getMonitorsInfo();
    } else
    {
        // revert the changes
        if(mBacklight->isBacklightAvailable()) {
            mBacklight->setBacklight(mLastBacklightValue);
            ui->backlightSlider->setValue(mLastBacklightValue);
        }

        mBrightness->setMonitorsSettings(mMonitors);
        for (const auto & monitor : qAsConst(mMonitors))
            emit monitorReverted(monitor);
    }
}
<commit_msg>Backlight can not be under 2%.<commit_after>/*
    Copyright (C) 2016  P.L. Lucas <selairi@gmail.com>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "brightnesssettings.h"
#include "outputwidget.h"
#include <QMessageBox>
#include <QPushButton>

BrightnessSettings::BrightnessSettings(QWidget *parent):QDialog(parent)
{
    ui = new Ui::BrightnessSettings();
    ui->setupUi(this);

    mBrightness = new XRandrBrightness();
    mMonitors = mBrightness->getMonitorsInfo();
    mBacklight = new LXQt::Backlight(this);

    ui->backlightSlider->setEnabled(mBacklight->isBacklightAvailable());
    if(mBacklight->isBacklightAvailable()) {
        ui->backlightSlider->setMaximum(mBacklight->getMaxBacklight());
        ui->backlightSlider->setMinimum((float)(mBacklight->getMaxBacklight())*0.02);
        ui->backlightSlider->setValue(mLastBacklightValue = mBacklight->getBacklight());
        connect(ui->backlightSlider, &QSlider::valueChanged, this, &BrightnessSettings::setBacklight);
    }

    for(const MonitorInfo &monitor: qAsConst(mMonitors))
    {
        OutputWidget *output = new OutputWidget(monitor, this);
        ui->layout->addWidget(output);
        output->show();
        connect(output, SIGNAL(changed(MonitorInfo)), this, SLOT(monitorSettingsChanged(MonitorInfo)));
        connect(this, &BrightnessSettings::monitorReverted, output, &OutputWidget::setRevertedValues);
    }

    mConfirmRequestTimer.setSingleShot(true);
    mConfirmRequestTimer.setInterval(1000);
    connect(&mConfirmRequestTimer, &QTimer::timeout, this, &BrightnessSettings::requestConfirmation);

}

void BrightnessSettings::setBacklight(int value)
{
    mBacklight->setBacklight(value);
    mConfirmRequestTimer.start();
}

void BrightnessSettings::monitorSettingsChanged(MonitorInfo monitor)
{
    mBrightness->setMonitorsSettings(QList<MonitorInfo>{}  << monitor);
    if (ui->confirmCB->isChecked())
    {
        mConfirmRequestTimer.start();
    } else
    {
        for (auto & m : mMonitors)
        {
            if (m.id() == monitor.id() && m.name() == monitor.name())
            {
                m.setBacklight(monitor.backlight());
                m.setBrightness(monitor.brightness());
            }
        }
    }
}

void BrightnessSettings::requestConfirmation()
{
    QMessageBox msg{QMessageBox::Question, tr("Brightness settings changed")
        , tr("Confirmation required. Are the settings correct?")
        , QMessageBox::Yes | QMessageBox::No};
    int timeout = 5; // seconds
    QString no_text = msg.button(QMessageBox::No)->text();
    no_text += QStringLiteral("(%1)");
    msg.setButtonText(QMessageBox::No, no_text.arg(timeout));
    msg.setDefaultButton(QMessageBox::No);

    QTimer timeoutTimer;
    timeoutTimer.setSingleShot(false);
    timeoutTimer.setInterval(1000);
    connect(&timeoutTimer, &QTimer::timeout, [&] {
        msg.setButtonText(QMessageBox::No, no_text.arg(--timeout));
        if (timeout == 0)
        {
            timeoutTimer.stop();
            msg.reject();
        }
    });
    timeoutTimer.start();

    if (QMessageBox::Yes == msg.exec())
    {
        // re-read current values
        if(mBacklight->isBacklightAvailable())
            mLastBacklightValue = mBacklight->getBacklight();

        mMonitors = mBrightness->getMonitorsInfo();
    } else
    {
        // revert the changes
        if(mBacklight->isBacklightAvailable()) {
            disconnect(ui->backlightSlider, &QSlider::valueChanged, this, &BrightnessSettings::setBacklight);
            mBacklight->setBacklight(mLastBacklightValue);
            ui->backlightSlider->setValue(mLastBacklightValue);
            connect(ui->backlightSlider, &QSlider::valueChanged, this, &BrightnessSettings::setBacklight);
        }

        mBrightness->setMonitorsSettings(mMonitors);
        for (const auto & monitor : qAsConst(mMonitors))
            emit monitorReverted(monitor);
    }
}
<|endoftext|>


<commit_before>#include <stingraykit/string/regex.h>

#ifdef PLATFORM_POSIX
#	include <regex.h>
#else
#	warning No regex support on nonposix systems!
#endif

#include <stingraykit/exception.h>
#include <stingraykit/string/StringUtils.h>
#include <stingraykit/string/ToString.h>
#include <stingraykit/variant.h>

namespace stingray
{

	struct RegexMatch
	{
		int	Begin;
		int	End;

		RegexMatch() : Begin(0), End(0) { }

		int GetLength() const
		{
			int len = End - Begin;
			STINGRAYKIT_CHECK(len > 0, "Submatch length is negative!");
			return len;
		}

		std::string ToString() const { return StringBuilder() % "(" % Begin % ", " % End % ")"; }
	};

	typedef std::vector<RegexMatch>						RegexMatchVec;

	typedef variant<TypeList<std::string, int>::type>	ReplacementEntry;
	typedef std::vector<ReplacementEntry>				ReplacementEntryVec;

	class ReplacementEntryVisitor : public static_visitor<std::string>
	{
	private:
		const char*				_srcString;
		const RegexMatchVec&	_matches;

	public:
		ReplacementEntryVisitor(const char* srcString, const RegexMatchVec& matches)
			: _srcString(srcString), _matches(matches)
		{ }

		std::string operator () (int matchNumber) const
		{
			int i = matchNumber;
			STINGRAYKIT_CHECK(i >= 0 && i < (int)_matches.size(), IndexOutOfRangeException(i, _matches.size()));
			std::string res = std::string(_srcString + _matches[i].Begin, _matches[i].GetLength());
			return res;
		}

		std::string operator () (const std::string& str) const
		{ return str; }
	};

	template < typename PlatformRegex >
	class BasicRegexImpl : public PlatformRegex
	{
	public:
		BasicRegexImpl(const std::string& str)
			: PlatformRegex(str)
		{ }

		bool Search(const std::string& str, smatch& m, regex_constants::match_flag_type flags)
		{
			m._results.clear();
			m._positions.clear();

			STINGRAYKIT_CHECK(flags == regex_constants::match_default, NotImplementedException());

			RegexMatchVec matches;
			if (!this->DoMatch(str.c_str(), matches))
				return false;

			for (size_t i = 0; i < matches.size(); ++i)
			{
				RegexMatch& submatch = matches[i];
				m._results.push_back(str.substr(submatch.Begin, submatch.GetLength()));
				m._positions.push_back(submatch.Begin);
			}
			return true;
		}

		std::string Replace(const std::string& str, const regex& re, const std::string& replacement, regex_constants::match_flag_type flags)
		{
			STINGRAYKIT_CHECK((flags & ~regex_constants::format_first_only) == 0, NotImplementedException());

			ReplacementEntryVec replacement_entries;
			PlatformRegex group_regex("\\\\(\\d+)"); // TODO: cache this somewhere
			RegexMatchVec group_matches;

			size_t replacement_begin = 0;
			do
			{
				if (!group_regex.DoMatch(replacement.c_str() + replacement_begin, group_matches))
				{
					if (replacement_begin < replacement.size())
						replacement_entries.push_back(replacement.substr(replacement_begin));
					break;
				}

				if (group_matches.at(0).Begin > 0)
					replacement_entries.push_back(replacement.substr(replacement_begin, group_matches.at(0).Begin));
				replacement_entries.push_back(FromString<int>(replacement.substr(group_matches.at(1).Begin, group_matches.at(1).GetLength())));
				replacement_begin += group_matches.at(0).End;
			} while (true);

			int begin = 0;
			std::string result;

			RegexMatchVec matches;
			do
			{
				if (!this->DoMatch(str.c_str() + begin, matches))
				{
					result += str.substr(begin);
					break;
				}

				ReplacementEntryVisitor visitor(str.c_str() + begin, matches);

				result += str.substr(begin, matches.at(0).Begin);
				for (ReplacementEntryVec::const_iterator it = replacement_entries.begin(); it != replacement_entries.end(); ++it)
					result += apply_visitor(visitor, *it);
				begin += matches.at(0).End;
			} while (true);

			return result;
		}
	};

#ifdef PLATFORM_POSIX
	class PosixRegexImpl
	{
	private:
		std::string	_str;
		regex_t		_regex;

	public:
		PosixRegexImpl(const std::string& str)
			: _str(str)
		{
			ReplaceAll(_str, "\\d", "[0-9]");
			ReplaceAll(_str, "\\w", "[a-zA-Z0-9_]");

			int ret = regcomp(&_regex, _str.c_str(), REG_EXTENDED);
			STINGRAYKIT_CHECK(ret == 0, StringBuilder() % "Could not compile regex '" % _str % "', ret = " % ret % "\n" % GetRegexError(_regex, ret));
		}

		~PosixRegexImpl()
		{ regfree(&_regex); }

		bool DoMatch(const char* str, RegexMatchVec& matches) const
		{
			std::vector<regmatch_t> posix_matches(32);
			int ret = regexec(&_regex, str, posix_matches.size(), posix_matches.data(), 0);

			if (ret == REG_NOMATCH)
				return false;

			if (ret != 0)
				STINGRAYKIT_THROW(StringBuilder() % "Could not execute regex '" % _str % "' for string '" % str % "', ret = " % ret % "\n" % GetRegexError(_regex, ret));

			int count = 0;
			while (posix_matches[count].rm_so >= 0)
				++count;

			matches.resize(count);
			for (int i = 0; i < count; ++i)
			{
				matches[i].Begin = posix_matches[i].rm_so;
				matches[i].End = posix_matches[i].rm_eo;
			}
			return true;
		}

	private:
		static std::string GetRegexError(const regex_t& regex, int errCode)
		{
			std::string result(256, '~');
			result.resize(regerror(errCode, &regex, &result[0], result.size()));
			return result;
		}
	};

	typedef PosixRegexImpl	PlatformRegexImpl;
#endif

	class regex::Impl : public BasicRegexImpl<PlatformRegexImpl>
	{
	public:
		Impl(const std::string& str) : BasicRegexImpl<PlatformRegexImpl>(str) { }
	};

	regex::regex(const std::string& str)
		: _impl(new Impl(str))
	{ }

	regex::regex(const regex& other)
		: _impl(other._impl)
	{ }

	regex::~regex()
	{ }

	regex& regex::operator = (const regex& other)
	{
		_impl = other._impl;
		return *this;
	}

	bool regex_search(const std::string& str, smatch& m, const regex& re, regex_constants::match_flag_type flags)
	{
		return re._impl->Search(str, m, flags);
	}

	std::string regex_replace(const std::string& str, const regex& re, const std::string& replacement, regex_constants::match_flag_type flags)
	{
		return re._impl->Replace(str, re, replacement, flags);
	}

}
<commit_msg>fix submatch length comparison<commit_after>#include <stingraykit/string/regex.h>

#ifdef PLATFORM_POSIX
#	include <regex.h>
#else
#	warning No regex support on nonposix systems!
#endif

#include <stingraykit/exception.h>
#include <stingraykit/string/StringUtils.h>
#include <stingraykit/string/ToString.h>
#include <stingraykit/variant.h>

namespace stingray
{

	struct RegexMatch
	{
		int	Begin;
		int	End;

		RegexMatch() : Begin(0), End(0) { }

		int GetLength() const
		{
			int len = End - Begin;
			STINGRAYKIT_CHECK(len >= 0, "Submatch length is negative!");
			return len;
		}

		std::string ToString() const { return StringBuilder() % "(" % Begin % ", " % End % ")"; }
	};

	typedef std::vector<RegexMatch>						RegexMatchVec;

	typedef variant<TypeList<std::string, int>::type>	ReplacementEntry;
	typedef std::vector<ReplacementEntry>				ReplacementEntryVec;

	class ReplacementEntryVisitor : public static_visitor<std::string>
	{
	private:
		const char*				_srcString;
		const RegexMatchVec&	_matches;

	public:
		ReplacementEntryVisitor(const char* srcString, const RegexMatchVec& matches)
			: _srcString(srcString), _matches(matches)
		{ }

		std::string operator () (int matchNumber) const
		{
			int i = matchNumber;
			STINGRAYKIT_CHECK(i >= 0 && i < (int)_matches.size(), IndexOutOfRangeException(i, _matches.size()));
			std::string res = std::string(_srcString + _matches[i].Begin, _matches[i].GetLength());
			return res;
		}

		std::string operator () (const std::string& str) const
		{ return str; }
	};

	template < typename PlatformRegex >
	class BasicRegexImpl : public PlatformRegex
	{
	public:
		BasicRegexImpl(const std::string& str)
			: PlatformRegex(str)
		{ }

		bool Search(const std::string& str, smatch& m, regex_constants::match_flag_type flags)
		{
			m._results.clear();
			m._positions.clear();

			STINGRAYKIT_CHECK(flags == regex_constants::match_default, NotImplementedException());

			RegexMatchVec matches;
			if (!this->DoMatch(str.c_str(), matches))
				return false;

			for (size_t i = 0; i < matches.size(); ++i)
			{
				RegexMatch& submatch = matches[i];
				m._results.push_back(str.substr(submatch.Begin, submatch.GetLength()));
				m._positions.push_back(submatch.Begin);
			}
			return true;
		}

		std::string Replace(const std::string& str, const regex& re, const std::string& replacement, regex_constants::match_flag_type flags)
		{
			STINGRAYKIT_CHECK((flags & ~regex_constants::format_first_only) == 0, NotImplementedException());

			ReplacementEntryVec replacement_entries;
			PlatformRegex group_regex("\\\\(\\d+)"); // TODO: cache this somewhere
			RegexMatchVec group_matches;

			size_t replacement_begin = 0;
			do
			{
				if (!group_regex.DoMatch(replacement.c_str() + replacement_begin, group_matches))
				{
					if (replacement_begin < replacement.size())
						replacement_entries.push_back(replacement.substr(replacement_begin));
					break;
				}

				if (group_matches.at(0).Begin > 0)
					replacement_entries.push_back(replacement.substr(replacement_begin, group_matches.at(0).Begin));
				replacement_entries.push_back(FromString<int>(replacement.substr(group_matches.at(1).Begin, group_matches.at(1).GetLength())));
				replacement_begin += group_matches.at(0).End;
			} while (true);

			int begin = 0;
			std::string result;

			RegexMatchVec matches;
			do
			{
				if (!this->DoMatch(str.c_str() + begin, matches))
				{
					result += str.substr(begin);
					break;
				}

				ReplacementEntryVisitor visitor(str.c_str() + begin, matches);

				result += str.substr(begin, matches.at(0).Begin);
				for (ReplacementEntryVec::const_iterator it = replacement_entries.begin(); it != replacement_entries.end(); ++it)
					result += apply_visitor(visitor, *it);
				begin += matches.at(0).End;
			} while (true);

			return result;
		}
	};

#ifdef PLATFORM_POSIX
	class PosixRegexImpl
	{
	private:
		std::string	_str;
		regex_t		_regex;

	public:
		PosixRegexImpl(const std::string& str)
			: _str(str)
		{
			ReplaceAll(_str, "\\d", "[0-9]");
			ReplaceAll(_str, "\\w", "[a-zA-Z0-9_]");

			int ret = regcomp(&_regex, _str.c_str(), REG_EXTENDED);
			STINGRAYKIT_CHECK(ret == 0, StringBuilder() % "Could not compile regex '" % _str % "', ret = " % ret % "\n" % GetRegexError(_regex, ret));
		}

		~PosixRegexImpl()
		{ regfree(&_regex); }

		bool DoMatch(const char* str, RegexMatchVec& matches) const
		{
			std::vector<regmatch_t> posix_matches(32);
			int ret = regexec(&_regex, str, posix_matches.size(), posix_matches.data(), 0);

			if (ret == REG_NOMATCH)
				return false;

			if (ret != 0)
				STINGRAYKIT_THROW(StringBuilder() % "Could not execute regex '" % _str % "' for string '" % str % "', ret = " % ret % "\n" % GetRegexError(_regex, ret));

			int count = 0;
			while (posix_matches[count].rm_so >= 0)
				++count;

			matches.resize(count);
			for (int i = 0; i < count; ++i)
			{
				matches[i].Begin = posix_matches[i].rm_so;
				matches[i].End = posix_matches[i].rm_eo;
			}
			return true;
		}

	private:
		static std::string GetRegexError(const regex_t& regex, int errCode)
		{
			std::string result(256, '~');
			result.resize(regerror(errCode, &regex, &result[0], result.size()));
			return result;
		}
	};

	typedef PosixRegexImpl	PlatformRegexImpl;
#endif

	class regex::Impl : public BasicRegexImpl<PlatformRegexImpl>
	{
	public:
		Impl(const std::string& str) : BasicRegexImpl<PlatformRegexImpl>(str) { }
	};

	regex::regex(const std::string& str)
		: _impl(new Impl(str))
	{ }

	regex::regex(const regex& other)
		: _impl(other._impl)
	{ }

	regex::~regex()
	{ }

	regex& regex::operator = (const regex& other)
	{
		_impl = other._impl;
		return *this;
	}

	bool regex_search(const std::string& str, smatch& m, const regex& re, regex_constants::match_flag_type flags)
	{
		return re._impl->Search(str, m, flags);
	}

	std::string regex_replace(const std::string& str, const regex& re, const std::string& replacement, regex_constants::match_flag_type flags)
	{
		return re._impl->Replace(str, re, replacement, flags);
	}

}
<|endoftext|>