<commit_before>/*
 * =====================================================================================
 *
 *       Filename:  WebSocketConn.cpp
 *
 *    Description:
 *
 *        Version:  1.0
 *        Created:  06/23/16 09:59:19
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  YOUR NAME (),
 *   Organization:
 *
 * =====================================================================================
 */
#include <WebSocketConn.h>

void WebSocketConn::OnRead()
{
    if(m_socket_type == NORMALSOCKET) {
        MsgConn::OnRead();
        return;
    }
    for (;;)
    {
        uint32_t free_buf_len = m_in_buf.GetAllocSize() - m_in_buf.GetWriteOffset();
        if (free_buf_len < READ_BUF_SIZE)
            m_in_buf.Extend(READ_BUF_SIZE);
        int ret = netlib_recv(m_handle, m_in_buf.GetBuffer() + m_in_buf.GetWriteOffset(), READ_BUF_SIZE);
        if (ret <= 0)
            break;
        m_recv_bytes += ret;
        m_in_buf.IncWriteOffset(ret);
        m_last_recv_tick = get_tick_count();
    }
/*
    if(m_websocket == NULL)
    {
        m_websocket = new WebSocket;
    }
*/

    WebSocket websocket;
    if(m_websocket_inited)
    {
        CImPdu *pPdu = NULL;

        int data_size = m_in_buf.GetWriteOffset();
        unsigned char *dataBuffer = (unsigned char*)malloc(data_size);
        try{
            int data_length = 0;
            int use_length = 0;
            int read_count = 0;
            WebSocketFrameType frameType = websocket.getFrame(m_in_buf.GetBuffer() ,m_in_buf.GetWriteOffset() ,dataBuffer ,data_size, data_length,use_length);
            //log("len:%d use:%d",m_in_buf.GetWriteOffset(),use_length);
            while(frameType == BINARY_FRAME || frameType == TEXT_FRAME)
            {
                read_count = read_count + use_length;
                while((pPdu = CImPdu::ReadPdu((uchar_t*)dataBuffer,data_length)))
                {
                    uint32_t pdu_len = pPdu->GetLength();
                    HandlePdu(pPdu);
                    delete pPdu;
                    pPdu = NULL;
                    break;
                }
                m_in_buf.Read(NULL, use_length);
                if(read_count >= data_size) {
                    break;
                }
                data_length = 0;
                use_length = 0;
                frameType = websocket.getFrame(m_in_buf.GetBuffer(),m_in_buf.GetWriteOffset() ,dataBuffer ,data_size, data_length,use_length);
            }

            //m_in_buf.~CSimpleBuffer();
        }catch(CPduException& ex)
        {

        }
        free(dataBuffer);

    }else
    {
        WebSocketFrameType type = websocket.parseHandshake(m_in_buf.GetBuffer(),m_in_buf.GetWriteOffset());
        if(type == OPENING_FRAME) {
            string answer = websocket.answerHandshake();
            CMsgConn::Send((void *)answer.c_str(), answer.size());
            m_in_buf.Read(NULL, m_in_buf.GetWriteOffset());
          //  m_in_buf.~CSimpleBuffer();
            m_websocket_inited = true;
        }else {
            m_socket_type = NORMALSOCKET;
            CImPdu *pPdu = NULL;
            try
            {
                while ((pPdu = CImPdu::ReadPdu(m_in_buf.GetBuffer(), m_in_buf.GetWriteOffset())))
                {
                    uint32_t pdu_len = pPdu->GetLength();
                    HandlePdu(pPdu);
                    m_in_buf.Read(NULL, pdu_len);
                    delete pPdu;
                    pPdu = NULL;
                }
            } catch (CPduException& ex) {
                log("!!!catch exception, sid=%u, cid=%u, err_code=%u, err_msg=%s, close the connection ",
                    ex.GetServiceId(), ex.GetCommandId(), ex.GetErrorCode(), ex.GetErrorMsg());
                if (pPdu) {
                    delete pPdu;
                    pPdu = NULL;
                }
                OnClose();
            }
            //OnClose();
        }
    }
}

int WebSocketConn::Send(void *data, int len)
{
    if(m_socket_type == NORMALSOCKET){
        return CMsgConn::Send(data ,len);
    }
    WebSocket websocket;
    unsigned char* outData = (unsigned char*)malloc(len + 14);
    int out_len = websocket.makeFrame(BINARY_FRAME, (unsigned char*)data,len,outData ,len + 14);
    int result =  CMsgConn::Send(outData ,out_len);
    free(outData);
    return result;
}
<commit_msg>update code<commit_after>/*
 * =====================================================================================
 *
 *       Filename:  WebSocketConn.cpp
 *
 *    Description:
 *
 *        Version:  1.0
 *        Created:  06/23/16 09:59:19
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  YOUR NAME (),
 *   Organization:
 *
 * =====================================================================================
 */
#include <WebSocketConn.h>

void WebSocketConn::OnRead()
{
    if(m_socket_type == NORMALSOCKET) {
        CMsgConn::OnRead();
        return;
    }
    for (;;)
    {
        uint32_t free_buf_len = m_in_buf.GetAllocSize() - m_in_buf.GetWriteOffset();
        if (free_buf_len < READ_BUF_SIZE)
            m_in_buf.Extend(READ_BUF_SIZE);
        int ret = netlib_recv(m_handle, m_in_buf.GetBuffer() + m_in_buf.GetWriteOffset(), READ_BUF_SIZE);
        if (ret <= 0)
            break;
        m_recv_bytes += ret;
        m_in_buf.IncWriteOffset(ret);
        m_last_recv_tick = get_tick_count();
    }
/*
    if(m_websocket == NULL)
    {
        m_websocket = new WebSocket;
    }
*/

    WebSocket websocket;
    if(m_websocket_inited)
    {
        CImPdu *pPdu = NULL;

        int data_size = m_in_buf.GetWriteOffset();
        unsigned char *dataBuffer = (unsigned char*)malloc(data_size);
        try{
            int data_length = 0;
            int use_length = 0;
            int read_count = 0;
            WebSocketFrameType frameType = websocket.getFrame(m_in_buf.GetBuffer() ,m_in_buf.GetWriteOffset() ,dataBuffer ,data_size, data_length,use_length);
            //log("len:%d use:%d",m_in_buf.GetWriteOffset(),use_length);
            while(frameType == BINARY_FRAME || frameType == TEXT_FRAME)
            {
                read_count = read_count + use_length;
                while((pPdu = CImPdu::ReadPdu((uchar_t*)dataBuffer,data_length)))
                {
                    uint32_t pdu_len = pPdu->GetLength();
                    HandlePdu(pPdu);
                    delete pPdu;
                    pPdu = NULL;
                    break;
                }
                m_in_buf.Read(NULL, use_length);
                if(read_count >= data_size) {
                    break;
                }
                data_length = 0;
                use_length = 0;
                frameType = websocket.getFrame(m_in_buf.GetBuffer(),m_in_buf.GetWriteOffset() ,dataBuffer ,data_size, data_length,use_length);
            }

            //m_in_buf.~CSimpleBuffer();
        }catch(CPduException& ex)
        {

        }
        free(dataBuffer);

    }else
    {
        WebSocketFrameType type = websocket.parseHandshake(m_in_buf.GetBuffer(),m_in_buf.GetWriteOffset());
        if(type == OPENING_FRAME) {
            string answer = websocket.answerHandshake();
            CMsgConn::Send((void *)answer.c_str(), answer.size());
            m_in_buf.Read(NULL, m_in_buf.GetWriteOffset());
          //  m_in_buf.~CSimpleBuffer();
            m_websocket_inited = true;
        }else {
            m_socket_type = NORMALSOCKET;
            CImPdu *pPdu = NULL;
            try
            {
                while ((pPdu = CImPdu::ReadPdu(m_in_buf.GetBuffer(), m_in_buf.GetWriteOffset())))
                {
                    uint32_t pdu_len = pPdu->GetLength();
                    HandlePdu(pPdu);
                    m_in_buf.Read(NULL, pdu_len);
                    delete pPdu;
                    pPdu = NULL;
                }
            } catch (CPduException& ex) {
                log("!!!catch exception, sid=%u, cid=%u, err_code=%u, err_msg=%s, close the connection ",
                    ex.GetServiceId(), ex.GetCommandId(), ex.GetErrorCode(), ex.GetErrorMsg());
                if (pPdu) {
                    delete pPdu;
                    pPdu = NULL;
                }
                OnClose();
            }
            //OnClose();
        }
    }
}

int WebSocketConn::Send(void *data, int len)
{
    if(m_socket_type == NORMALSOCKET){
        return CMsgConn::Send(data ,len);
    }
    WebSocket websocket;
    unsigned char* outData = (unsigned char*)malloc(len + 14);
    int out_len = websocket.makeFrame(BINARY_FRAME, (unsigned char*)data,len,outData ,len + 14);
    int result =  CMsgConn::Send(outData ,out_len);
    free(outData);
    return result;
}
<|endoftext|>


<commit_before>/* libvisio
 * Copyright (C) 2011 Fridrich Strba <fridrich.strba@bluewin.ch>
 * Copyright (C) 2011 Eilidh McAdam <tibbylickle@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02111-1301 USA
 */

#include <libwpd-stream/libwpd-stream.h>
#include <locale.h>
#include <sstream>
#include <string>
#include "libvisio_utils.h"
#include "VSD6Parser.h"
#include "VSDInternalStream.h"
#include "VSDXDocumentStructure.h"
#include "VSDXContentCollector.h"
#include "VSDXStylesCollector.h"

libvisio::VSD6Parser::VSD6Parser(WPXInputStream *input, libwpg::WPGPaintInterface *painter)
  : VSDXParser(input, painter)
{}

libvisio::VSD6Parser::~VSD6Parser()
{}

bool libvisio::VSD6Parser::getChunkHeader(WPXInputStream *input)
{
  unsigned char tmpChar = 0;
  while (!input->atEOS() && !tmpChar)
    tmpChar = readU8(input);

  if (input->atEOS())
    return false;
  else
    input->seek(-1, WPX_SEEK_CUR);

  m_header.chunkType = readU32(input);
  m_header.id = readU32(input);
  m_header.list = readU32(input);

   // Certain chunk types seem to always have a trailer
  m_header.trailer = 0;
  if (m_header.list != 0 || m_header.chunkType == 0x71 || m_header.chunkType == 0x70 ||
      m_header.chunkType == 0x6b || m_header.chunkType == 0x6a || m_header.chunkType == 0x69 ||
      m_header.chunkType == 0x66 || m_header.chunkType == 0x65 || m_header.chunkType == 0x2c)
    m_header.trailer += 8; // 8 byte trailer

  m_header.dataLength = readU32(input);
  m_header.level = readU16(input);
  m_header.unknown = readU8(input);

  // 0x1f (OLE data) and 0xc9 (Name ID) never have trailer
  if (m_header.chunkType == 0x1f || m_header.chunkType == 0xc9)
  {
    m_header.trailer = 0;
  }
  return true;
}

void libvisio::VSD6Parser::readText(WPXInputStream *input)
{
  input->seek(8, WPX_SEEK_CUR);
  std::vector<uint8_t> textStream;

  for (unsigned bytesRead = 8; bytesRead < m_header.dataLength-1; bytesRead++)
    textStream.push_back(readU8(input));

  m_collector->collectText(m_header.id, m_header.level, textStream, VSD_TEXT_ANSI);
}

void libvisio::VSD6Parser::readCharIX(WPXInputStream *input)
{
  WPXString fontFace = "Arial";
  unsigned charCount = readU32(input);
  unsigned short fontID = readU16(input);
  input->seek(1, WPX_SEEK_CUR);  // Color ID
  Colour fontColour;            // Font Colour
  fontColour.r = readU8(input);
  fontColour.g = readU8(input);
  fontColour.b = readU8(input);
  fontColour.a = readU8(input);

  unsigned short fontMod = readU8(input);
  bool bold = false; bool italic = false; bool underline = false;
  if (fontMod & 1) bold = true;
  if (fontMod & 2) italic = true;
  if (fontMod & 4) underline = true;

  input->seek(6, WPX_SEEK_CUR);
  double fontSize = readDouble(input);

  input->seek(43, WPX_SEEK_CUR);
  unsigned langId = readU32(input);

  m_charList->addCharIX(m_header.id, m_header.level, charCount, fontID, fontColour, langId, fontSize, bold, italic, underline, fontFace);

}

void libvisio::VSD6Parser::readFillAndShadow(WPXInputStream *input)
{
  unsigned int colourIndexFG = readU8(input);
  input->seek(3, WPX_SEEK_CUR);
  unsigned int fillFGTransparency = readU8(input);
  unsigned int colourIndexBG = readU8(input);
  input->seek(3, WPX_SEEK_CUR);
  unsigned int fillBGTransparency = readU8(input);
  unsigned fillPattern = readU8(input);
  input->seek(1, WPX_SEEK_CUR);
  Colour shfgc;            // Shadow Foreground Colour
  shfgc.r = readU8(input);
  shfgc.g = readU8(input);
  shfgc.b = readU8(input);
  shfgc.a = readU8(input);
  input->seek(5, WPX_SEEK_CUR);  // Shadow Background Colour skipped
  unsigned shadowPattern = readU8(input);

  if (m_isStencilStarted)
  {
    if (m_stencilShape.fillStyle == 0) m_stencilShape.fillStyle = new VSDXFillStyle(colourIndexFG, colourIndexBG, fillPattern, fillFGTransparency, fillBGTransparency, shfgc, shadowPattern, m_currentStencil->shadowOffsetX, m_currentStencil->shadowOffsetY);
  }
  else
    m_collector->collectFillAndShadow(m_header.id, m_header.level, colourIndexFG, colourIndexBG, fillPattern, fillFGTransparency, fillBGTransparency, shadowPattern, shfgc);
}

void libvisio::VSD6Parser::readFillStyle(WPXInputStream *input)
{
  unsigned int colourIndexFG = readU8(input);
  input->seek(3, WPX_SEEK_CUR);
  unsigned int fillFGTransparency = readU8(input);
  unsigned int colourIndexBG = readU8(input);
  input->seek(3, WPX_SEEK_CUR);
  unsigned int fillBGTransparency = readU8(input);
  unsigned fillPattern = readU8(input);
  input->seek(1, WPX_SEEK_CUR);
  Colour shfgc;            // Shadow Foreground Colour
  shfgc.r = readU8(input);
  shfgc.g = readU8(input);
  shfgc.b = readU8(input);
  shfgc.a = readU8(input);
  input->seek(5, WPX_SEEK_CUR);  // Shadow Background Colour skipped
  unsigned shadowPattern = readU8(input);

  m_collector->collectFillStyle(m_header.id, m_header.level, colourIndexFG, colourIndexBG, fillPattern, fillFGTransparency, fillBGTransparency, shadowPattern, shfgc);
}
<commit_msg>Add more list chunks for trailer in ver6.<commit_after>/* libvisio
 * Copyright (C) 2011 Fridrich Strba <fridrich.strba@bluewin.ch>
 * Copyright (C) 2011 Eilidh McAdam <tibbylickle@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02111-1301 USA
 */

#include <libwpd-stream/libwpd-stream.h>
#include <locale.h>
#include <sstream>
#include <string>
#include "libvisio_utils.h"
#include "VSD6Parser.h"
#include "VSDInternalStream.h"
#include "VSDXDocumentStructure.h"
#include "VSDXContentCollector.h"
#include "VSDXStylesCollector.h"

libvisio::VSD6Parser::VSD6Parser(WPXInputStream *input, libwpg::WPGPaintInterface *painter)
  : VSDXParser(input, painter)
{}

libvisio::VSD6Parser::~VSD6Parser()
{}

bool libvisio::VSD6Parser::getChunkHeader(WPXInputStream *input)
{
  unsigned char tmpChar = 0;
  while (!input->atEOS() && !tmpChar)
    tmpChar = readU8(input);

  if (input->atEOS())
    return false;
  else
    input->seek(-1, WPX_SEEK_CUR);

  m_header.chunkType = readU32(input);
  m_header.id = readU32(input);
  m_header.list = readU32(input);

   // Certain chunk types seem to always have a trailer
  m_header.trailer = 0;
  if (m_header.list != 0 || m_header.chunkType == 0x76 || m_header.chunkType == 0x73 ||
      m_header.chunkType == 0x72 || m_header.chunkType == 0x71 || m_header.chunkType == 0x70 ||
      m_header.chunkType == 0x6f || m_header.chunkType == 0x6e || m_header.chunkType == 0x6d ||
      m_header.chunkType == 0x6c || m_header.chunkType == 0x6b || m_header.chunkType == 0x6a ||
      m_header.chunkType == 0x69 || m_header.chunkType == 0x68 || m_header.chunkType == 0x67 ||
      m_header.chunkType == 0x66 || m_header.chunkType == 0x65 || m_header.chunkType == 0x64 ||
      m_header.chunkType == 0x2c || m_header.chunkType == 0xd)
    m_header.trailer += 8; // 8 byte trailer

  m_header.dataLength = readU32(input);
  m_header.level = readU16(input);
  m_header.unknown = readU8(input);

  // 0x1f (OLE data) and 0xc9 (Name ID) never have trailer
  if (m_header.chunkType == 0x1f || m_header.chunkType == 0xc9)
  {
    m_header.trailer = 0;
  }
  return true;
}

void libvisio::VSD6Parser::readText(WPXInputStream *input)
{
  input->seek(8, WPX_SEEK_CUR);
  std::vector<uint8_t> textStream;

  for (unsigned bytesRead = 8; bytesRead < m_header.dataLength-1; bytesRead++)
    textStream.push_back(readU8(input));

  m_collector->collectText(m_header.id, m_header.level, textStream, VSD_TEXT_ANSI);
}

void libvisio::VSD6Parser::readCharIX(WPXInputStream *input)
{
  WPXString fontFace = "Arial";
  unsigned charCount = readU32(input);
  unsigned short fontID = readU16(input);
  input->seek(1, WPX_SEEK_CUR);  // Color ID
  Colour fontColour;            // Font Colour
  fontColour.r = readU8(input);
  fontColour.g = readU8(input);
  fontColour.b = readU8(input);
  fontColour.a = readU8(input);

  unsigned short fontMod = readU8(input);
  bool bold = false; bool italic = false; bool underline = false;
  if (fontMod & 1) bold = true;
  if (fontMod & 2) italic = true;
  if (fontMod & 4) underline = true;

  input->seek(6, WPX_SEEK_CUR);
  double fontSize = readDouble(input);

  input->seek(43, WPX_SEEK_CUR);
  unsigned langId = readU32(input);

  m_charList->addCharIX(m_header.id, m_header.level, charCount, fontID, fontColour, langId, fontSize, bold, italic, underline, fontFace);

}

void libvisio::VSD6Parser::readFillAndShadow(WPXInputStream *input)
{
  unsigned int colourIndexFG = readU8(input);
  input->seek(3, WPX_SEEK_CUR);
  unsigned int fillFGTransparency = readU8(input);
  unsigned int colourIndexBG = readU8(input);
  input->seek(3, WPX_SEEK_CUR);
  unsigned int fillBGTransparency = readU8(input);
  unsigned fillPattern = readU8(input);
  input->seek(1, WPX_SEEK_CUR);
  Colour shfgc;            // Shadow Foreground Colour
  shfgc.r = readU8(input);
  shfgc.g = readU8(input);
  shfgc.b = readU8(input);
  shfgc.a = readU8(input);
  input->seek(5, WPX_SEEK_CUR);  // Shadow Background Colour skipped
  unsigned shadowPattern = readU8(input);

  if (m_isStencilStarted)
  {
    if (m_stencilShape.fillStyle == 0) m_stencilShape.fillStyle = new VSDXFillStyle(colourIndexFG, colourIndexBG, fillPattern, fillFGTransparency, fillBGTransparency, shfgc, shadowPattern, m_currentStencil->shadowOffsetX, m_currentStencil->shadowOffsetY);
  }
  else
    m_collector->collectFillAndShadow(m_header.id, m_header.level, colourIndexFG, colourIndexBG, fillPattern, fillFGTransparency, fillBGTransparency, shadowPattern, shfgc);
}

void libvisio::VSD6Parser::readFillStyle(WPXInputStream *input)
{
  unsigned int colourIndexFG = readU8(input);
  input->seek(3, WPX_SEEK_CUR);
  unsigned int fillFGTransparency = readU8(input);
  unsigned int colourIndexBG = readU8(input);
  input->seek(3, WPX_SEEK_CUR);
  unsigned int fillBGTransparency = readU8(input);
  unsigned fillPattern = readU8(input);
  input->seek(1, WPX_SEEK_CUR);
  Colour shfgc;            // Shadow Foreground Colour
  shfgc.r = readU8(input);
  shfgc.g = readU8(input);
  shfgc.b = readU8(input);
  shfgc.a = readU8(input);
  input->seek(5, WPX_SEEK_CUR);  // Shadow Background Colour skipped
  unsigned shadowPattern = readU8(input);

  m_collector->collectFillStyle(m_header.id, m_header.level, colourIndexFG, colourIndexBG, fillPattern, fillFGTransparency, fillBGTransparency, shadowPattern, shfgc);
}
<|endoftext|>


<commit_before>/* Steepest Descent optimizer for unconstrained problems*/

#include "ComputeSD.h"
#include "finiteDifferences.h"

struct fit_functional {
	GradientOptimizerContext &goc;

	fit_functional(GradientOptimizerContext &goc) : goc(goc) {};

	template <typename T1>
	double operator()(Eigen::MatrixBase<T1>& x) const {
		int mode = 0;
		return goc.solFun(x.derived().data(), &mode);
	}
};

void omxSD(GradientOptimizerContext &rf)
{
	int maxIter = rf.maxMajorIterations;
	if (maxIter == -1) maxIter = 50000;

	FitContext *fc = rf.fc;
    int iter = 0;
	double priorSpeed = 1.0, shrinkage = 0.7;
    rf.setupSimpleBounds();
    rf.informOut = INFORM_UNINITIALIZED;

    int mode = 0;
    rf.solFun(fc->est, &mode);
    if (mode == -1) {
	    rf.informOut = INFORM_STARTING_VALUES_INFEASIBLE;
	    return;
    }
    double refFit = fc->fit;

    fc->grad.resize(fc->numParam);

    fit_functional ff(rf);
    Eigen::Map< Eigen::VectorXd > currEst(fc->est, fc->numParam);

    while(iter < maxIter && !isErrorRaised()) {
	    fc->iterations += 1;
	    Eigen::VectorXd majorEst = currEst;
	    gradient_with_ref(rf.gradientAlgo, rf.gradientIterations, rf.gradientStepSize,
			      ff, refFit, majorEst, fc->grad);

	    if (rf.verbose >= 3) mxPrintMat("grad", fc->grad);

        if(fc->grad.norm() == 0)
        {
            rf.informOut = INFORM_CONVERGED_OPTIMUM;
            if(rf.verbose >= 2) mxLog("After %i iterations, gradient achieves zero!", iter);
            break;
        }

        int retries = 300;
        double speed = priorSpeed;
	bool foundBetter = false;
	Eigen::VectorXd prevEst(currEst.size());
	prevEst.setConstant(nan("uninit"));
        while (--retries > 0 && !isErrorRaised()){
		Eigen::VectorXd &searchDir = fc->grad;
		Eigen::VectorXd nextEst = majorEst - speed * searchDir / searchDir.norm();
		nextEst = nextEst.cwiseMax(rf.solLB).cwiseMin(rf.solUB);

		if (nextEst == prevEst) break;
		prevEst = nextEst;

		rf.checkActiveBoxConstraints(nextEst);

		int mode = 0;
		double fit = rf.solFun(nextEst.data(), &mode);
		if (fit < refFit) {
			foundBetter = true;
			refFit = fc->fit;
			priorSpeed = speed * 1.1;
			iter++;
			break;
		}
		speed *= shrinkage;
        }
        if (!foundBetter) {
            rf.informOut = INFORM_CONVERGED_OPTIMUM;
            if(rf.verbose >= 2) mxLog("After %i iterations, cannot find better estimation along the gradient direction", iter);
            break;
        }
    }
    if ((fc->grad.array().abs() > 0.1).any()) {
	    rf.informOut = INFORM_NOT_AT_OPTIMUM;
    }
    if (iter >= maxIter - 1) {
            rf.informOut = INFORM_ITERATION_LIMIT;
            if(rf.verbose >= 2) mxLog("Maximum iteration achieved!");
    }
    if(rf.verbose >= 1) mxLog("Status code : %i", rf.informOut);
}

/* Steepest Descent optimizer for constrained problems */

template <typename T1, typename T2>
static void SD_AL(GradientOptimizerContext &rf, double rho,
			Eigen::MatrixBase<T1> &lambda, Eigen::MatrixBase<T2> &mu)
{
    rf.fc->copyParamToModel();
    ComputeFit("SD_AL", rf.fitMatrix, FF_COMPUTE_FIT, rf.fc);

    rf.solEqBFun();
    rf.myineqFun();

    for (size_t i = 0; i < unsigned(rf.equality.size()); ++i)
    {
        rf.fc->fit += 0.5 * rho * (rf.equality[i] + lambda[i] / rho) * (rf.equality[i] + lambda[i] / rho);
    }

    for (size_t i = 0; i < unsigned(rf.inequality.size()); ++i)
    {
        rf.fc->fit += 0.5 * rho * std::max(0.0,(rf.inequality[i] + mu[i] / rho)) * std::max(0.0,(rf.inequality[i] + mu[i] / rho));
    }
    return;
}

template <typename T1, typename T2>
static void SD_grad_AL(GradientOptimizerContext &rf, double eps, double rho,
		       Eigen::MatrixBase<T1> &lambda, Eigen::MatrixBase<T2> &mu)
{
    SD_AL(rf, rho, lambda, mu);
    const double refFit = rf.fc->fit;

    Eigen::Map< Eigen::VectorXd > p1(rf.fc->est, rf.fc->numParam);
    Eigen::VectorXd p2 = p1;
    Eigen::VectorXd grad(rf.fc->numParam);

    for (int px = 0; px < int(rf.fc->numParam); px++) {
        p1[px] += eps;
        SD_AL(rf, rho, lambda, mu);
        grad[px] = (rf.fc->fit - refFit) / eps;
        p1 = p2;
    }
    rf.fc->fit = refFit;
    rf.fc->grad = grad;
}

//Armijo's Rule implemented
template <typename T1, typename T2>
static void omxSD_AR(GradientOptimizerContext &rf, int maxIter, double rho,
			Eigen::MatrixBase<T1> &lambda, Eigen::MatrixBase<T2> &mu, double &alpha)
{
	int iter = 0;
	double epsilon = 0.2, eta = 2, eps_grad = 1e-9, grad_tol = 1e-3;
    rf.setupSimpleBounds();
    rf.informOut = INFORM_UNINITIALIZED;
    rf.fc->copyParamToModel();

    SD_grad_AL(rf, eps_grad, rho, lambda, mu);

	while(iter < maxIter && !isErrorRaised())
	{
        alpha = std::min(1.0, alpha);
        iter++;
        SD_grad_AL(rf, eps_grad, rho, lambda, mu);
        Eigen::VectorXd searchDir = rf.fc->grad;

        if (std::isnan(rf.fc->fit))
        {
            rf.informOut = INFORM_STARTING_VALUES_INFEASIBLE;
            break;
        }

        if(rf.fc->grad.norm() < grad_tol)
        {
            rf.informOut = INFORM_CONVERGED_OPTIMUM;
            if(rf.verbose >= 2) mxLog("After %i iterations, gradient achieves zero!", iter);
            break;
        }

        Eigen::Map< Eigen::VectorXd > currEst(rf.fc->est, rf.fc->numParam);
        Eigen::VectorXd prevEst = currEst;

        currEst = prevEst - alpha * searchDir / searchDir.norm();
        currEst = currEst.cwiseMax(rf.solLB).cwiseMin(rf.solUB);
        if(rf.verbose >= 2){
            for(int index = 0; index < int(rf.fc->numParam); index++)
            {
                if(currEst[index] == rf.solLB[index])
                    mxLog("paramter %i hit lower bound %f", index, rf.solLB[index]);
                if(currEst[index] == rf.solUB[index])
                    mxLog("paramter %i hit upper bound %f", index, rf.solUB[index]);
            }
        }

        SD_AL(rf, rho, lambda, mu);
        double phi = rf.fc->fit;

        currEst = prevEst;
        SD_AL(rf, rho, lambda, mu);
        double dashline = rf.fc->fit - epsilon * alpha * searchDir.norm();

        if(phi <= dashline)
        {
            do{
                alpha *= eta;
                currEst = prevEst;
                SD_AL(rf, rho, lambda, mu);
                dashline = rf.fc->fit - epsilon * alpha * searchDir.norm();

                currEst = prevEst - alpha * searchDir / searchDir.norm();
                currEst = currEst.cwiseMax(rf.solLB).cwiseMin(rf.solUB);

		rf.checkActiveBoxConstraints(currEst);

                SD_AL(rf, rho, lambda, mu);
                phi = rf.fc->fit;
            }while(phi <= dashline);
            currEst = prevEst - alpha / eta * searchDir / searchDir.norm();
            currEst = currEst.cwiseMax(rf.solLB).cwiseMin(rf.solUB);
            SD_AL(rf, rho, lambda, mu);
        }
        else
        {
            do{
                alpha /= eta;
                currEst = prevEst;
                SD_AL(rf, rho, lambda, mu);
                dashline = rf.fc->fit - epsilon * alpha * searchDir.norm();

                currEst = prevEst - alpha * searchDir / searchDir.norm();
                currEst = currEst.cwiseMax(rf.solLB).cwiseMin(rf.solUB);

		rf.checkActiveBoxConstraints(currEst);

                SD_AL(rf, rho, lambda, mu);
                phi = rf.fc->fit;
            }while(phi > dashline);
        }

        if (iter == maxIter - 1)
        {
            rf.informOut = INFORM_ITERATION_LIMIT;
            if(rf.verbose >= 2) mxLog("Maximum iteration achieved!");
            break;
        }

    }
    if(rf.verbose >= 1) mxLog("Status code : %i", rf.informOut);
    return;
}

void omxSD_AL(GradientOptimizerContext &rf)
{
	int maxIter = rf.maxMajorIterations;
	if (maxIter == -1) maxIter = 50000;

    double ICM = HUGE_VAL;
    /* magic parameters from Birgin & Martinez */
    const double tau = 0.5, gam = 10;
    const double lam_min = -1e20, lam_max = 1e20, mu_max = 1e20;
    double alpha = 1;

    rf.fc->copyParamToModel();
    ComputeFit("SD_AL", rf.fitMatrix, FF_COMPUTE_FIT, rf.fc);
    rf.solEqBFun();
    rf.myineqFun();

    size_t ineq_size = rf.inequality.size(), eq_size = rf.equality.size();

    // initialize penalty parameter rho and the Lagrange multipliers lambda and mu
    double eq_norm = 0, ineq_norm = 0;

    for(size_t i = 0; i < eq_size; i++)
    {
      eq_norm += rf.equality[i] * rf.equality[i];
    }

    for(size_t i = 0; i < ineq_size; i++)
    {
      ineq_norm += std::max(0.0, rf.inequality[i]) * std::max(0.0, rf.inequality[i]);
    }

    double rho = std::max(1e-6, std::min(10.0, (2 * std::abs(rf.fc->fit) / (eq_norm + ineq_norm))));

    Eigen::VectorXd lambda(eq_size);
    lambda.setZero();
    Eigen::VectorXd mu(ineq_size);
    mu.setZero();
    int iter = 0, minorIter = 1000;
    Eigen::VectorXd V(ineq_size);

    while (1) {
        iter++;
        double ICM_tol = 1e-4;
        double prev_ICM = ICM;
        ICM = 0;

        omxSD_AR(rf, minorIter, rho, lambda, mu, alpha);

        if(rf.informOut == INFORM_STARTING_VALUES_INFEASIBLE) return;

        rf.fc->copyParamToModel();
        rf.solEqBFun();
        rf.myineqFun();

        for(size_t i = 0; i < eq_size; i++){
            lambda[i] = std::min(std::max(lam_min, (lambda[i] + rho * rf.equality[i])), lam_max);
            ICM = std::max(ICM, std::abs(rf.equality[i]));
        }

        for(size_t i = 0; i < ineq_size; i++){
            mu[i] = std::min(std::max(0.0, (mu[i] + rho * rf.inequality[i])),mu_max);
        }

        for(size_t i = 0; i < ineq_size; i++){
            V[i] = std::max(rf.inequality[i], (-mu[i] / rho));
            ICM = std::max(ICM, std::abs(V[i]));
        }

        if(!(iter == 1 || ICM <= tau * prev_ICM))
        {
            rho *= gam;
        }

        if(ICM < ICM_tol)
        {
            if(rf.verbose >= 1) mxLog("Augmented lagrangian coverges!");
            return;
        }
	if (iter >= maxIter) {
		rf.informOut = INFORM_ITERATION_LIMIT;
		break;
	}
    }
}

<commit_msg>SD: Tidy code further<commit_after>/* Steepest Descent optimizer for unconstrained problems*/

#include "ComputeSD.h"
#include "finiteDifferences.h"

struct fit_functional {
	GradientOptimizerContext &goc;

	fit_functional(GradientOptimizerContext &goc) : goc(goc) {};

	template <typename T1>
	double operator()(Eigen::MatrixBase<T1>& x) const {
		int mode = 0;
		return goc.solFun(x.derived().data(), &mode);
	}
};

void omxSD(GradientOptimizerContext &rf)
{
	int maxIter = rf.maxMajorIterations;
	if (maxIter == -1) maxIter = 50000;

	FitContext *fc = rf.fc;
    int iter = 0;
	double priorSpeed = 1.0, shrinkage = 0.7;
    rf.setupSimpleBounds();
    rf.informOut = INFORM_UNINITIALIZED;

    int mode = 0;
    rf.solFun(fc->est, &mode);
    if (mode == -1) {
	    rf.informOut = INFORM_STARTING_VALUES_INFEASIBLE;
	    return;
    }
    double refFit = fc->fit;

    fc->grad.resize(fc->numParam);

    fit_functional ff(rf);
    Eigen::Map< Eigen::VectorXd > currEst(fc->est, fc->numParam);
    Eigen::VectorXd majorEst = currEst;

    while(++iter < maxIter && !isErrorRaised()) {
	    fc->iterations += 1;
	    gradient_with_ref(rf.gradientAlgo, rf.gradientIterations, rf.gradientStepSize,
			      ff, refFit, majorEst, fc->grad);

	    if (rf.verbose >= 3) mxPrintMat("grad", fc->grad);

        if(fc->grad.norm() == 0)
        {
            rf.informOut = INFORM_CONVERGED_OPTIMUM;
            if(rf.verbose >= 2) mxLog("After %i iterations, gradient achieves zero!", iter);
            break;
        }

        int retries = 300;
        double speed = std::min(priorSpeed, 1.0);
	double bestSpeed = speed;
	bool foundBetter = false;
	Eigen::VectorXd bestEst(majorEst.size());
	Eigen::VectorXd prevEst(majorEst.size());
	Eigen::VectorXd searchDir = fc->grad;
	searchDir /= searchDir.norm();
	prevEst.setConstant(nan("uninit"));
        while (--retries > 0 && !isErrorRaised()){
		Eigen::VectorXd nextEst = majorEst - speed * searchDir;
		nextEst = nextEst.cwiseMax(rf.solLB).cwiseMin(rf.solUB);

		if (nextEst == prevEst) break;
		prevEst = nextEst;

		rf.checkActiveBoxConstraints(nextEst);

		int mode = 0;
		double fit = rf.solFun(nextEst.data(), &mode);
		if (fit < refFit) {
			foundBetter = true;
			refFit = fc->fit;
			bestSpeed = speed;
			bestEst = nextEst;
			break;
		}
		speed *= shrinkage;
        }

	if (false && foundBetter) {
		// In some tests, this did not help so it is not enabled.
		// It might be worth testing more.
		mxLog("trying larger step size");
		retries = 3;
		while (--retries > 0 && !isErrorRaised()){
			speed *= 1.01;
			Eigen::VectorXd nextEst = majorEst - speed * searchDir;
			nextEst = nextEst.cwiseMax(rf.solLB).cwiseMin(rf.solUB);
			rf.checkActiveBoxConstraints(nextEst);
			int mode = 0;
			double fit = rf.solFun(nextEst.data(), &mode);
			if (fit < refFit) {
				foundBetter = true;
				refFit = fc->fit;
				bestSpeed = speed;
				bestEst = nextEst;
			}
		}
	}

        if (!foundBetter) {
            rf.informOut = INFORM_CONVERGED_OPTIMUM;
            if(rf.verbose >= 2) mxLog("After %i iterations, cannot find better estimation along the gradient direction", iter);
            break;
        }

	if (rf.verbose >= 2) mxLog("major fit %f bestSpeed %g", refFit, bestSpeed);
	majorEst = bestEst;
	priorSpeed = bestSpeed * 1.1;
    }
    if ((fc->grad.array().abs() > 0.1).any()) {
	    rf.informOut = INFORM_NOT_AT_OPTIMUM;
    }
    if (iter >= maxIter - 1) {
            rf.informOut = INFORM_ITERATION_LIMIT;
            if(rf.verbose >= 2) mxLog("Maximum iteration achieved!");
    }
    if(rf.verbose >= 1) mxLog("Status code : %i", rf.informOut);
}

/* Steepest Descent optimizer for constrained problems */

template <typename T1, typename T2>
static void SD_AL(GradientOptimizerContext &rf, double rho,
			Eigen::MatrixBase<T1> &lambda, Eigen::MatrixBase<T2> &mu)
{
    rf.fc->copyParamToModel();
    ComputeFit("SD_AL", rf.fitMatrix, FF_COMPUTE_FIT, rf.fc);

    rf.solEqBFun();
    rf.myineqFun();

    for (size_t i = 0; i < unsigned(rf.equality.size()); ++i)
    {
        rf.fc->fit += 0.5 * rho * (rf.equality[i] + lambda[i] / rho) * (rf.equality[i] + lambda[i] / rho);
    }

    for (size_t i = 0; i < unsigned(rf.inequality.size()); ++i)
    {
        rf.fc->fit += 0.5 * rho * std::max(0.0,(rf.inequality[i] + mu[i] / rho)) * std::max(0.0,(rf.inequality[i] + mu[i] / rho));
    }
    return;
}

template <typename T1, typename T2>
static void SD_grad_AL(GradientOptimizerContext &rf, double eps, double rho,
		       Eigen::MatrixBase<T1> &lambda, Eigen::MatrixBase<T2> &mu)
{
    SD_AL(rf, rho, lambda, mu);
    const double refFit = rf.fc->fit;

    Eigen::Map< Eigen::VectorXd > p1(rf.fc->est, rf.fc->numParam);
    Eigen::VectorXd p2 = p1;
    Eigen::VectorXd grad(rf.fc->numParam);

    for (int px = 0; px < int(rf.fc->numParam); px++) {
        p1[px] += eps;
        SD_AL(rf, rho, lambda, mu);
        grad[px] = (rf.fc->fit - refFit) / eps;
        p1 = p2;
    }
    rf.fc->fit = refFit;
    rf.fc->grad = grad;
}

//Armijo's Rule implemented
template <typename T1, typename T2>
static void omxSD_AR(GradientOptimizerContext &rf, int maxIter, double rho,
			Eigen::MatrixBase<T1> &lambda, Eigen::MatrixBase<T2> &mu, double &alpha)
{
	int iter = 0;
	double epsilon = 0.2, eta = 2, eps_grad = 1e-9, grad_tol = 1e-3;
    rf.setupSimpleBounds();
    rf.informOut = INFORM_UNINITIALIZED;
    rf.fc->copyParamToModel();

    SD_grad_AL(rf, eps_grad, rho, lambda, mu);

	while(iter < maxIter && !isErrorRaised())
	{
        alpha = std::min(1.0, alpha);
        iter++;
        SD_grad_AL(rf, eps_grad, rho, lambda, mu);
        Eigen::VectorXd searchDir = rf.fc->grad;

        if (std::isnan(rf.fc->fit))
        {
            rf.informOut = INFORM_STARTING_VALUES_INFEASIBLE;
            break;
        }

        if(rf.fc->grad.norm() < grad_tol)
        {
            rf.informOut = INFORM_CONVERGED_OPTIMUM;
            if(rf.verbose >= 2) mxLog("After %i iterations, gradient achieves zero!", iter);
            break;
        }

        Eigen::Map< Eigen::VectorXd > currEst(rf.fc->est, rf.fc->numParam);
        Eigen::VectorXd prevEst = currEst;

        currEst = prevEst - alpha * searchDir / searchDir.norm();
        currEst = currEst.cwiseMax(rf.solLB).cwiseMin(rf.solUB);
        if(rf.verbose >= 2){
            for(int index = 0; index < int(rf.fc->numParam); index++)
            {
                if(currEst[index] == rf.solLB[index])
                    mxLog("paramter %i hit lower bound %f", index, rf.solLB[index]);
                if(currEst[index] == rf.solUB[index])
                    mxLog("paramter %i hit upper bound %f", index, rf.solUB[index]);
            }
        }

        SD_AL(rf, rho, lambda, mu);
        double phi = rf.fc->fit;

        currEst = prevEst;
        SD_AL(rf, rho, lambda, mu);
        double dashline = rf.fc->fit - epsilon * alpha * searchDir.norm();

        if(phi <= dashline)
        {
            do{
                alpha *= eta;
                currEst = prevEst;
                SD_AL(rf, rho, lambda, mu);
                dashline = rf.fc->fit - epsilon * alpha * searchDir.norm();

                currEst = prevEst - alpha * searchDir / searchDir.norm();
                currEst = currEst.cwiseMax(rf.solLB).cwiseMin(rf.solUB);

		rf.checkActiveBoxConstraints(currEst);

                SD_AL(rf, rho, lambda, mu);
                phi = rf.fc->fit;
            }while(phi <= dashline);
            currEst = prevEst - alpha / eta * searchDir / searchDir.norm();
            currEst = currEst.cwiseMax(rf.solLB).cwiseMin(rf.solUB);
            SD_AL(rf, rho, lambda, mu);
        }
        else
        {
            do{
                alpha /= eta;
                currEst = prevEst;
                SD_AL(rf, rho, lambda, mu);
                dashline = rf.fc->fit - epsilon * alpha * searchDir.norm();

                currEst = prevEst - alpha * searchDir / searchDir.norm();
                currEst = currEst.cwiseMax(rf.solLB).cwiseMin(rf.solUB);

		rf.checkActiveBoxConstraints(currEst);

                SD_AL(rf, rho, lambda, mu);
                phi = rf.fc->fit;
            }while(phi > dashline);
        }

        if (iter == maxIter - 1)
        {
            rf.informOut = INFORM_ITERATION_LIMIT;
            if(rf.verbose >= 2) mxLog("Maximum iteration achieved!");
            break;
        }

    }
    if(rf.verbose >= 1) mxLog("Status code : %i", rf.informOut);
    return;
}

void omxSD_AL(GradientOptimizerContext &rf)
{
	int maxIter = rf.maxMajorIterations;
	if (maxIter == -1) maxIter = 50000;

    double ICM = HUGE_VAL;
    /* magic parameters from Birgin & Martinez */
    const double tau = 0.5, gam = 10;
    const double lam_min = -1e20, lam_max = 1e20, mu_max = 1e20;
    double alpha = 1;

    rf.fc->copyParamToModel();
    ComputeFit("SD_AL", rf.fitMatrix, FF_COMPUTE_FIT, rf.fc);
    rf.solEqBFun();
    rf.myineqFun();

    size_t ineq_size = rf.inequality.size(), eq_size = rf.equality.size();

    // initialize penalty parameter rho and the Lagrange multipliers lambda and mu
    double eq_norm = 0, ineq_norm = 0;

    for(size_t i = 0; i < eq_size; i++)
    {
      eq_norm += rf.equality[i] * rf.equality[i];
    }

    for(size_t i = 0; i < ineq_size; i++)
    {
      ineq_norm += std::max(0.0, rf.inequality[i]) * std::max(0.0, rf.inequality[i]);
    }

    double rho = std::max(1e-6, std::min(10.0, (2 * std::abs(rf.fc->fit) / (eq_norm + ineq_norm))));

    Eigen::VectorXd lambda(eq_size);
    lambda.setZero();
    Eigen::VectorXd mu(ineq_size);
    mu.setZero();
    int iter = 0, minorIter = 1000;
    Eigen::VectorXd V(ineq_size);

    while (1) {
        iter++;
        double ICM_tol = 1e-4;
        double prev_ICM = ICM;
        ICM = 0;

        omxSD_AR(rf, minorIter, rho, lambda, mu, alpha);

        if(rf.informOut == INFORM_STARTING_VALUES_INFEASIBLE) return;

        rf.fc->copyParamToModel();
        rf.solEqBFun();
        rf.myineqFun();

        for(size_t i = 0; i < eq_size; i++){
            lambda[i] = std::min(std::max(lam_min, (lambda[i] + rho * rf.equality[i])), lam_max);
            ICM = std::max(ICM, std::abs(rf.equality[i]));
        }

        for(size_t i = 0; i < ineq_size; i++){
            mu[i] = std::min(std::max(0.0, (mu[i] + rho * rf.inequality[i])),mu_max);
        }

        for(size_t i = 0; i < ineq_size; i++){
            V[i] = std::max(rf.inequality[i], (-mu[i] / rho));
            ICM = std::max(ICM, std::abs(V[i]));
        }

        if(!(iter == 1 || ICM <= tau * prev_ICM))
        {
            rho *= gam;
        }

        if(ICM < ICM_tol)
        {
            if(rf.verbose >= 1) mxLog("Augmented lagrangian coverges!");
            return;
        }
	if (iter >= maxIter) {
		rf.informOut = INFORM_ITERATION_LIMIT;
		break;
	}
    }
}

<|endoftext|>


<commit_before>#include "interpolation.h"

bool CatmullRomWeights(int size, const Float *nodes, Float x,int *offset, Float *weights){
    //先判断x是否在有效的值域内
    //PBRT在这里还解释道，使用这种条件是为了同时判断NaN的情况
    //一旦NaN参与比较操作,肯定返回false,于是整体条件为true,因此函数返回false
    if( !(x>=nodes[0]&&x<=nodes[size-1]) ){
        return false;
    }
    //使用二分法寻找最大的小于x的值的索引
    int idx=FindInterval(size,[&](int i){return nodes[i]<=x;});
    //计算offset
    (*offset)=idx-1;

    //获得x0和x1,然后映射到[0-1]之间
    Float x0=nodes[idx];
    Float x1=nodes[idx+1];

    Float t=(x-x0)/(x1-x0);
    Float t2=t*t;
    Float t3=t2*t;

    //使用中心有限差分时候的公式
    //w0=(x^3-2x^2+x)/(x_{-1}-1)
    //w1=(2x^3-3x^2+1) - w3
    //w2=(-2x^3+3x^2) - w0
    //w3=(x^3-x^2)/(x_2)

    //使用向前向后有限差分时候的公式
    //左:
    //w0=0
    //w1=(2x^3-3x^2+1)-(x^3-2x^2+x)-w3
    //w2=(-2x^3+3x^2) +(x^3-2x^2+x)
    //w3=(x^3-x^2)/(x_2)

    //右:
    //w0=(x^3-2x^2+x)/(x_{-1}-1)
    //w1=(2x^3-3x^2+1)-(x^3-x^2)
    //w2=(-2x^3+3x^2)+(x^3-x^2) - w0
    //w3=0

    //首先计算w1和w2的前面的括号内的内容
    Float w0=0;
    Float w1=2*t3-3*t2+1;
    Float w2=-2*t3+3*t2;
    Float w3=0;
    //计算w0和w3的时候因为涉及到x_{-1}和x_{2},因此可能会越界,所以到分条件处理
    //先处理w0
    if(idx>0){
        //不越界的情况
        //这里没有像pbrt那样做一些优化操作:
        //w0=(t3-2*t2+t)*(x1-x0)/(nodes[idx-1]-x1);
        //w2-=w0;
        //优化:
        w0=(t3-2*t2+t)*(x1-x0)/(x1-nodes[idx-1]);
        w2+=w0;
    }
    else{
        //左越界
        Float v=t3-2*t2+t;
        w1-=v;
        w2+=v;
    }

    //再处理w3
    if((idx+1)<(size-1)){
        //w3=(x^3-x^2)/(x_2)
        w3=(t3-t2)*(x1-x0)/(nodes[idx+2]-x0);
        //w1=(2x^3-3x^2+1) - w3
        w1-=w3;
    }
    else{
        //右越界
         Float v=t3-t2;
         w1-=v;
         w2+=v;
    }

    //真正的赋值的地方
    weights[0]=w0;
    weights[1]=w1;
    weights[2]=w2;
    weights[3]=w3;

    return true;
}

Float IntegrateCatmullRom(int n, const Float *x, const Float *values,Float *cdf){
    Float sum=0;//定积分值
    cdf[0]=0;
    for(int i=0;i<n-1;++i){
        Float x0=x[i];
        Float x1=x[i+1];
        Float w=x1-x0;// dx

        Float f0=values[i];
        Float f1=values[i+1];

        Float d0,d1;//相应端点的一阶导数
        //可以使用中心差分的使用中心差分
        //不然使用右差分
        if(i>0){
            d0=w*(f1-values[i-1])/(x1-x[i-1]);//中心差分
        }else{
            d0=f1-f0;//右差分
        }

        if(i<(n-2)){
            d1=w*(values[i+2]-f0)/(x[i+2]-x0);//中心差分
        }else{
            d1=f1-f0;//右差分
        }

        //累计
        //用的是CatmullRom的解析式
        sum+=w*((f1+f0)*0.5f + (d0-d1)*(1.0f/12.0f));
        cdf[i+1]=sum;
    }
    return sum;
}

Float SampleCatmullRom(int n,const Float *x,const Float *f,const Float *F,Float u,Float* fval,Float* pdf){
    //首先找到u所在的区间
    //PDF=函数值/函数的积分
    //CDF=函数的部分积分/函数的积分

    //这里使用二分法找到u所在的区间
    u=u*F[n-1];
    int i=FindInterval(n,[&](int i){return F[i]<=u;});

    //获得当前区间的相应的值
    Float x0=x[i];
    Float x1=x[i+1];

    Float w=x1-x0;

    Float f0=f[i];
    Float f1=f[i+1];

    Float d0,d1;//相应端点的一阶导数
    //可以使用中心差分的使用中心差分
    //不然使用右差分
    if(i>0){
        d0=w*(f1-f[i-1])/(x1-x[i-1]);//中心差分
    }else{
        d0=f1-f0;//右差分
    }

    if(i<(n-2)){
        d1=w*(f[i+2]-f0)/(x[i+2]-x0);//中心差分
    }else{
        d1=f1-f0;//右差分
    }

    //计算给样条线段的积分的逆函数用的样本
    //非标准化的CDF
    //(这是提醒我自己的，这里为啥要除以w? 请记住dt=(x-x0)/w*dx,然后从dt的积分变换到dx的积分，相信我自己能够回忆起来！！！！)
    u=(u-F[i])/w;

    //开始使用牛顿-二分法来求定义域值
    //首先先要选择一个合适的初始值,这里假设样条线段是线性的 f(t)=(1-t)f(0)+tf(1)
    //然后求积分 F(t)=tf(0)-t^2f(0)+t^2f(1)
    //然后求逆函数  f(0)-srqt(f(0)^2+2(f(1)-f(0))*x)/(f(0)-f(1))
    Float t;
    if(f1!=f0){
        t=(f0-std::sqrt(std::max(f0*f0+2*(f1-f0)*u,(Float)0)))/(f0-f1);
    }else{
        //这种情况为f0=f1,因此f(x)=f0,然后积分，求逆函数巴拉巴拉，就能得到这个了
        t=u/f0;
    }

    int a =0;
    int b =1;
    Float Fhat;
    Float fhat;
    //进入牛顿-二分法
    while(true){
        //首先判断t是否在二分法允许的范围内
        //不在的话，更新t值为当前二分区间的中心点
        if(t<=a||t>=b){
            t=(a+b)*0.5f;
        }
        //计算相应的t的函数值
        //这里是相应的CatmullRom样条的Horner格式
        //这里直接复制于PBRT
        //其实就是换了下函数的排列
        Fhat = t * (f0 + t * (0.5f * d0 + t * ((1.0f/3.0f) * (-2 * d0 - d1) +f1 - f0 + t * (0.25f * (d0 + d1) + 0.5f * (f0 - f1)))));
        fhat = f0 + t * (d0 + t * (-2 * d0 - d1 + 3 * (f1 - f0) + t * (d0 + d1 + 2 * (f0 - f1))));

        //判断是否接近实际的root值
        //牛顿法的话要判断函数值是否接近0
        //二分法的话，比较二分边界是否足够接近
        if( std::abs(Fhat-u)<1e-6f||(b-a)<1e-6f){
            break;
        }
        //到这里的话，说明还需要迭代，提高进度

        if(Fhat<u){
            //说明[a,t]不可能包含解,更新a
            a=t;
        }else {
            //说明[t,b]不可能包含解,更新b
            b=t;
        }
        //运用牛顿法
        t=t-(Fhat-u)/fhat;
    }

    if(fval){
        (*fval)=fhat;
    }

    if(pdf){
        (*pdf)=fhat/F[n-1];
    }

    //从[0-1]映射回原来的空间
    return x0+t*w;
}

Float SampleCatmullRom2D(int n1,int n2,const Float *xv1,const Float *xv2,const Float *f,const Float *cdf,Float alpha,Float u,Float* fval,Float* pdf){
    //首先计算alpha的插值权重
    int offset;
    Float weights[4];
    if(!CatmullRomWeights(n1,xv1,alpha,&offset,weights)){
        return 0;
    }

    //通过第一维度的权重，计算第二维度的值得lambda
    auto interpolate=[&](const Float *f,int idx){
        Float value=0;
        //插值操作
        for(int i=0;i<4;++i){
            if(weights[i]!=0){
                value+=f[n2*(offset+i)+idx]*weights[i];
            }
        }
        return value;
    };

    //首先找到u所在的区间
    //PDF=函数值/函数的积分
    //CDF=函数的部分积分/函数的积分

    //这里使用二分法找到u所在的区间
    Float maximum=interpolate(cdf,n2-1);
    u=u*maximum;
    int i=FindInterval(n2,[&](int i){return interpolate(cdf,i)<=u;});

    //获得当前区间的相应的值
    Float x0=xv2[i];
    Float x1=xv2[i+1];

    Float w=x1-x0;

    Float f0= interpolate(f,i);
    Float f1= interpolate(f,i+1);

    Float d0,d1;//相应端点的一阶导数
    //可以使用中心差分的使用中心差分
    //不然使用右差分
    if(i>0){
        d0=w*(f1-interpolate(f,i-1))/(x1-xv2[i-1]);//中心差分
    }else{
        d0=f1-f0;//右差分
    }

    if(i<(n2-2)){
        d1=w*(interpolate(f,i+2)-f0)/(xv2[i+2]-x0);//中心差分
    }else{
        d1=f1-f0;//右差分
    }

    //计算给样条线段的积分的逆函数用的样本
    //非标准化的CDF
    //(这是提醒我自己的，这里为啥要除以w? 请记住dt=(x-x0)/w*dx,然后从dt的积分变换到dx的积分，相信我自己能够回忆起来！！！！)
    u=(u-interpolate(cdf,i))/w;

    //开始使用牛顿-二分法来求定义域值
    //首先先要选择一个合适的初始值,这里假设样条线段是线性的 f(t)=(1-t)f(0)+tf(1)
    //然后求积分 F(t)=tf(0)-t^2f(0)+t^2f(1)
    //然后求逆函数  f(0)-srqt(f(0)^2+2(f(1)-f(0))*x)/(f(0)-f(1))
    Float t;
    if(f1!=f0){
        t=(f0-std::sqrt(std::max(f0*f0+2*(f1-f0)*u,(Float)0)))/(f0-f1);
    }else{
        //这种情况为f0=f1,因此f(x)=f0,然后积分，求逆函数巴拉巴拉，就能得到这个了
        t=u/f0;
    }

    int a =0;
    int b =1;
    Float Fhat;
    Float fhat;
    //进入牛顿-二分法
    while(true){
        //首先判断t是否在二分法允许的范围内
        //不在的话，更新t值为当前二分区间的中心点
        if(t<=a||t>=b){
            t=(a+b)*0.5f;
        }
        //计算相应的t的函数值
        //这里是相应的CatmullRom样条的Horner格式
        //这里直接复制于PBRT
        //其实就是换了下函数的排列
        Fhat = t * (f0 + t * (0.5f * d0 + t * ((1.0f/3.0f) * (-2 * d0 - d1) +f1 - f0 + t * (0.25f * (d0 + d1) + 0.5f * (f0 - f1)))));
        fhat = f0 + t * (d0 + t * (-2 * d0 - d1 + 3 * (f1 - f0) + t * (d0 + d1 + 2 * (f0 - f1))));

        //判断是否接近实际的root值
        //牛顿法的话要判断函数值是否接近0
        //二分法的话，比较二分边界是否足够接近
        if( std::abs(Fhat-u)<1e-6f||(b-a)<1e-6f){
            break;
        }
        //到这里的话，说明还需要迭代，提高进度

        if(Fhat<u){
            //说明[a,t]不可能包含解,更新a
            a=t;
        }else {
            //说明[t,b]不可能包含解,更新b
            b=t;
        }
        //运用牛顿法
        t=t-(Fhat-u)/fhat;
    }

    if(fval){
        (*fval)=fhat;
    }

    if(pdf){
        (*pdf)=fhat/maximum;
    }

    //从[0-1]映射回原来的空间
    return x0+t*w;
}<commit_msg>修正一个错误<commit_after>#include "interpolation.h"

bool CatmullRomWeights(int size, const Float *nodes, Float x,int *offset, Float *weights){
    //先判断x是否在有效的值域内
    //PBRT在这里还解释道，使用这种条件是为了同时判断NaN的情况
    //一旦NaN参与比较操作,肯定返回false,于是整体条件为true,因此函数返回false
    if( !(x>=nodes[0]&&x<=nodes[size-1]) ){
        return false;
    }
    //使用二分法寻找最大的小于x的值的索引
    int idx=FindInterval(size,[&](int i){return nodes[i]<=x;});
    //计算offset
    (*offset)=idx-1;

    //获得x0和x1,然后映射到[0-1]之间
    Float x0=nodes[idx];
    Float x1=nodes[idx+1];

    Float t=(x-x0)/(x1-x0);
    Float t2=t*t;
    Float t3=t2*t;

    //使用中心有限差分时候的公式
    //w0=(x^3-2x^2+x)/(x_{-1}-1)
    //w1=(2x^3-3x^2+1) - w3
    //w2=(-2x^3+3x^2) - w0
    //w3=(x^3-x^2)/(x_2)

    //使用向前向后有限差分时候的公式
    //左:
    //w0=0
    //w1=(2x^3-3x^2+1)-(x^3-2x^2+x)-w3
    //w2=(-2x^3+3x^2) +(x^3-2x^2+x)
    //w3=(x^3-x^2)/(x_2)

    //右:
    //w0=(x^3-2x^2+x)/(x_{-1}-1)
    //w1=(2x^3-3x^2+1)-(x^3-x^2)
    //w2=(-2x^3+3x^2)+(x^3-x^2) - w0
    //w3=0

    //首先计算w1和w2的前面的括号内的内容
    Float w0=0;
    Float w1=2*t3-3*t2+1;
    Float w2=-2*t3+3*t2;
    Float w3=0;
    //计算w0和w3的时候因为涉及到x_{-1}和x_{2},因此可能会越界,所以到分条件处理
    //先处理w0
    if(idx>0){
        //不越界的情况
        //这里没有像pbrt那样做一些优化操作:
        w0=(t3-2*t2+t)*(x1-x0)/(nodes[idx-1]-x1);
        w2-=w0;
    }
    else{
        //左越界
        Float v=t3-2*t2+t;
        w1-=v;
        w2+=v;
    }

    //再处理w3
    if((idx+1)<(size-1)){
        //w3=(x^3-x^2)/(x_2)
        w3=(t3-t2)*(x1-x0)/(nodes[idx+2]-x0);
        //w1=(2x^3-3x^2+1) - w3
        w1-=w3;
    }
    else{
        //右越界
         Float v=t3-t2;
         w1-=v;
         w2+=v;
    }

    //真正的赋值的地方
    weights[0]=w0;
    weights[1]=w1;
    weights[2]=w2;
    weights[3]=w3;

    return true;
}

Float IntegrateCatmullRom(int n, const Float *x, const Float *values,Float *cdf){
    Float sum=0;//定积分值
    cdf[0]=0;
    for(int i=0;i<n-1;++i){
        Float x0=x[i];
        Float x1=x[i+1];
        Float w=x1-x0;// dx

        Float f0=values[i];
        Float f1=values[i+1];

        Float d0,d1;//相应端点的一阶导数
        //可以使用中心差分的使用中心差分
        //不然使用右差分
        if(i>0){
            d0=w*(f1-values[i-1])/(x1-x[i-1]);//中心差分
        }else{
            d0=f1-f0;//右差分
        }

        if(i<(n-2)){
            d1=w*(values[i+2]-f0)/(x[i+2]-x0);//中心差分
        }else{
            d1=f1-f0;//右差分
        }

        //累计
        //用的是CatmullRom的解析式
        sum+=w*((f1+f0)*0.5f + (d0-d1)*(1.0f/12.0f));
        cdf[i+1]=sum;
    }
    return sum;
}

Float SampleCatmullRom(int n,const Float *x,const Float *f,const Float *F,Float u,Float* fval,Float* pdf){
    //首先找到u所在的区间
    //PDF=函数值/函数的积分
    //CDF=函数的部分积分/函数的积分

    //这里使用二分法找到u所在的区间
    u=u*F[n-1];
    int i=FindInterval(n,[&](int i){return F[i]<=u;});

    //获得当前区间的相应的值
    Float x0=x[i];
    Float x1=x[i+1];

    Float w=x1-x0;

    Float f0=f[i];
    Float f1=f[i+1];

    Float d0,d1;//相应端点的一阶导数
    //可以使用中心差分的使用中心差分
    //不然使用右差分
    if(i>0){
        d0=w*(f1-f[i-1])/(x1-x[i-1]);//中心差分
    }else{
        d0=f1-f0;//右差分
    }

    if(i<(n-2)){
        d1=w*(f[i+2]-f0)/(x[i+2]-x0);//中心差分
    }else{
        d1=f1-f0;//右差分
    }

    //计算给样条线段的积分的逆函数用的样本
    //非标准化的CDF
    //(这是提醒我自己的，这里为啥要除以w? 请记住dt=(x-x0)/w*dx,然后从dt的积分变换到dx的积分，相信我自己能够回忆起来！！！！)
    u=(u-F[i])/w;

    //开始使用牛顿-二分法来求定义域值
    //首先先要选择一个合适的初始值,这里假设样条线段是线性的 f(t)=(1-t)f(0)+tf(1)
    //然后求积分 F(t)=tf(0)-t^2f(0)+t^2f(1)
    //然后求逆函数  f(0)-srqt(f(0)^2+2(f(1)-f(0))*x)/(f(0)-f(1))
    Float t;
    if(f1!=f0){
        t=(f0-std::sqrt(std::max(f0*f0+2*(f1-f0)*u,(Float)0)))/(f0-f1);
    }else{
        //这种情况为f0=f1,因此f(x)=f0,然后积分，求逆函数巴拉巴拉，就能得到这个了
        t=u/f0;
    }

    int a =0;
    int b =1;
    Float Fhat;
    Float fhat;
    //进入牛顿-二分法
    while(true){
        //首先判断t是否在二分法允许的范围内
        //不在的话，更新t值为当前二分区间的中心点
        if(t<=a||t>=b){
            t=(a+b)*0.5f;
        }
        //计算相应的t的函数值
        //这里是相应的CatmullRom样条的Horner格式
        //这里直接复制于PBRT
        //其实就是换了下函数的排列
        Fhat = t * (f0 + t * (0.5f * d0 + t * ((1.0f/3.0f) * (-2 * d0 - d1) +f1 - f0 + t * (0.25f * (d0 + d1) + 0.5f * (f0 - f1)))));
        fhat = f0 + t * (d0 + t * (-2 * d0 - d1 + 3 * (f1 - f0) + t * (d0 + d1 + 2 * (f0 - f1))));

        //判断是否接近实际的root值
        //牛顿法的话要判断函数值是否接近0
        //二分法的话，比较二分边界是否足够接近
        if( std::abs(Fhat-u)<1e-6f||(b-a)<1e-6f){
            break;
        }
        //到这里的话，说明还需要迭代，提高进度

        if(Fhat<u){
            //说明[a,t]不可能包含解,更新a
            a=t;
        }else {
            //说明[t,b]不可能包含解,更新b
            b=t;
        }
        //运用牛顿法
        t=t-(Fhat-u)/fhat;
    }

    if(fval){
        (*fval)=fhat;
    }

    if(pdf){
        (*pdf)=fhat/F[n-1];
    }

    //从[0-1]映射回原来的空间
    return x0+t*w;
}

Float SampleCatmullRom2D(int n1,int n2,const Float *xv1,const Float *xv2,const Float *f,const Float *cdf,Float alpha,Float u,Float* fval,Float* pdf){
    //首先计算alpha的插值权重
    int offset;
    Float weights[4];
    if(!CatmullRomWeights(n1,xv1,alpha,&offset,weights)){
        return 0;
    }

    //通过第一维度的权重，计算第二维度的值得lambda
    auto interpolate=[&](const Float *f,int idx){
        Float value=0;
        //插值操作
        for(int i=0;i<4;++i){
            if(weights[i]!=0){
                value+=f[n2*(offset+i)+idx]*weights[i];
            }
        }
        return value;
    };

    //首先找到u所在的区间
    //PDF=函数值/函数的积分
    //CDF=函数的部分积分/函数的积分

    //这里使用二分法找到u所在的区间
    Float maximum=interpolate(cdf,n2-1);
    u=u*maximum;
    int i=FindInterval(n2,[&](int i){return interpolate(cdf,i)<=u;});

    //获得当前区间的相应的值
    Float x0=xv2[i];
    Float x1=xv2[i+1];

    Float w=x1-x0;

    Float f0= interpolate(f,i);
    Float f1= interpolate(f,i+1);

    Float d0,d1;//相应端点的一阶导数
    //可以使用中心差分的使用中心差分
    //不然使用右差分
    if(i>0){
        d0=w*(f1-interpolate(f,i-1))/(x1-xv2[i-1]);//中心差分
    }else{
        d0=f1-f0;//右差分
    }

    if(i<(n2-2)){
        d1=w*(interpolate(f,i+2)-f0)/(xv2[i+2]-x0);//中心差分
    }else{
        d1=f1-f0;//右差分
    }

    //计算给样条线段的积分的逆函数用的样本
    //非标准化的CDF
    //(这是提醒我自己的，这里为啥要除以w? 请记住dt=(x-x0)/w*dx,然后从dt的积分变换到dx的积分，相信我自己能够回忆起来！！！！)
    u=(u-interpolate(cdf,i))/w;

    //开始使用牛顿-二分法来求定义域值
    //首先先要选择一个合适的初始值,这里假设样条线段是线性的 f(t)=(1-t)f(0)+tf(1)
    //然后求积分 F(t)=tf(0)-t^2f(0)+t^2f(1)
    //然后求逆函数  f(0)-srqt(f(0)^2+2(f(1)-f(0))*x)/(f(0)-f(1))
    Float t;
    if(f1!=f0){
        t=(f0-std::sqrt(std::max(f0*f0+2*(f1-f0)*u,(Float)0)))/(f0-f1);
    }else{
        //这种情况为f0=f1,因此f(x)=f0,然后积分，求逆函数巴拉巴拉，就能得到这个了
        t=u/f0;
    }

    int a =0;
    int b =1;
    Float Fhat;
    Float fhat;
    //进入牛顿-二分法
    while(true){
        //首先判断t是否在二分法允许的范围内
        //不在的话，更新t值为当前二分区间的中心点
        if(t<=a||t>=b){
            t=(a+b)*0.5f;
        }
        //计算相应的t的函数值
        //这里是相应的CatmullRom样条的Horner格式
        //这里直接复制于PBRT
        //其实就是换了下函数的排列
        Fhat = t * (f0 + t * (0.5f * d0 + t * ((1.0f/3.0f) * (-2 * d0 - d1) +f1 - f0 + t * (0.25f * (d0 + d1) + 0.5f * (f0 - f1)))));
        fhat = f0 + t * (d0 + t * (-2 * d0 - d1 + 3 * (f1 - f0) + t * (d0 + d1 + 2 * (f0 - f1))));

        //判断是否接近实际的root值
        //牛顿法的话要判断函数值是否接近0
        //二分法的话，比较二分边界是否足够接近
        if( std::abs(Fhat-u)<1e-6f||(b-a)<1e-6f){
            break;
        }
        //到这里的话，说明还需要迭代，提高进度

        if(Fhat<u){
            //说明[a,t]不可能包含解,更新a
            a=t;
        }else {
            //说明[t,b]不可能包含解,更新b
            b=t;
        }
        //运用牛顿法
        t=t-(Fhat-u)/fhat;
    }

    if(fval){
        (*fval)=fhat;
    }

    if(pdf){
        (*pdf)=fhat/maximum;
    }

    //从[0-1]映射回原来的空间
    return x0+t*w;
}<|endoftext|>


<commit_before>/*
 *
 * Copyright 2017 gRPC authors.
 *
 * 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 <grpc/support/port_platform.h>

#include "src/core/lib/gprpp/fork.h"

#include <string.h>

#include <grpc/support/alloc.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>

#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/memory.h"

/*
 * NOTE: FORKING IS NOT GENERALLY SUPPORTED, THIS IS ONLY INTENDED TO WORK
 *       AROUND VERY SPECIFIC USE CASES.
 */

namespace grpc_core {
namespace internal {
// The exec_ctx_count has 2 modes, blocked and unblocked.
// When unblocked, the count is 2-indexed; exec_ctx_count=2 indicates
// 0 active ExecCtxs, exex_ctx_count=3 indicates 1 active ExecCtxs...

// When blocked, the exec_ctx_count is 0-indexed.  Note that ExecCtx
// creation can only be blocked if there is exactly 1 outstanding ExecCtx,
// meaning that BLOCKED and UNBLOCKED counts partition the integers
#define UNBLOCKED(n) (n + 2)
#define BLOCKED(n) (n)

class ExecCtxState {
 public:
  ExecCtxState() : fork_complete_(true) {
    gpr_mu_init(&mu_);
    gpr_cv_init(&cv_);
    gpr_atm_no_barrier_store(&count_, UNBLOCKED(0));
  }

  void IncExecCtxCount() {
    gpr_atm count = gpr_atm_no_barrier_load(&count_);
    while (true) {
      if (count <= BLOCKED(1)) {
        // This only occurs if we are trying to fork.  Wait until the fork()
        // operation completes before allowing new ExecCtxs.
        gpr_mu_lock(&mu_);
        if (gpr_atm_no_barrier_load(&count_) <= BLOCKED(1)) {
          while (!fork_complete_) {
            gpr_cv_wait(&cv_, &mu_, gpr_inf_future(GPR_CLOCK_REALTIME));
          }
        }
        gpr_mu_unlock(&mu_);
      } else if (gpr_atm_no_barrier_cas(&count_, count, count + 1)) {
        break;
      }
      count = gpr_atm_no_barrier_load(&count_);
    }
  }

  void DecExecCtxCount() { gpr_atm_no_barrier_fetch_add(&count_, -1); }

  bool BlockExecCtx() {
    // Assumes there is an active ExecCtx when this function is called
    if (gpr_atm_no_barrier_cas(&count_, UNBLOCKED(1), BLOCKED(1))) {
      gpr_mu_lock(&mu_);
      fork_complete_ = false;
      gpr_mu_unlock(&mu_);
      return true;
    }
    return false;
  }

  void AllowExecCtx() {
    gpr_mu_lock(&mu_);
    gpr_atm_no_barrier_store(&count_, UNBLOCKED(0));
    fork_complete_ = true;
    gpr_cv_broadcast(&cv_);
    gpr_mu_unlock(&mu_);
  }

  ~ExecCtxState() {
    gpr_mu_destroy(&mu_);
    gpr_cv_destroy(&cv_);
  }

 private:
  bool fork_complete_;
  gpr_mu mu_;
  gpr_cv cv_;
  gpr_atm count_;
};

class ThreadState {
 public:
  ThreadState() : awaiting_threads_(false), threads_done_(false), count_(0) {
    gpr_mu_init(&mu_);
    gpr_cv_init(&cv_);
  }

  void IncThreadCount() {
    gpr_mu_lock(&mu_);
    count_++;
    gpr_mu_unlock(&mu_);
  }

  void DecThreadCount() {
    gpr_mu_lock(&mu_);
    count_--;
    if (awaiting_threads_ && count_ == 0) {
      threads_done_ = true;
      gpr_cv_signal(&cv_);
    }
    gpr_mu_unlock(&mu_);
  }
  void AwaitThreads() {
    gpr_mu_lock(&mu_);
    awaiting_threads_ = true;
    threads_done_ = (count_ == 0);
    while (!threads_done_) {
      gpr_cv_wait(&cv_, &mu_, gpr_inf_future(GPR_CLOCK_REALTIME));
    }
    awaiting_threads_ = true;
    gpr_mu_unlock(&mu_);
  }

  ~ThreadState() {
    gpr_mu_destroy(&mu_);
    gpr_cv_destroy(&cv_);
  }

 private:
  bool awaiting_threads_;
  bool threads_done_;
  gpr_mu mu_;
  gpr_cv cv_;
  int count_;
};

}  // namespace

void Fork::GlobalInit() {
  if (!override_enabled_) {
#ifdef GRPC_ENABLE_FORK_SUPPORT
    support_enabled_ = true;
#else
    support_enabled_ = false;
#endif
    bool env_var_set = false;
    char* env = gpr_getenv("GRPC_ENABLE_FORK_SUPPORT");
    if (env != nullptr) {
      static const char* truthy[] = {"yes",  "Yes",  "YES", "true",
                                     "True", "TRUE", "1"};
      static const char* falsey[] = {"no",    "No",    "NO", "false",
                                     "False", "FALSE", "0"};
      for (size_t i = 0; i < GPR_ARRAY_SIZE(truthy); i++) {
        if (0 == strcmp(env, truthy[i])) {
          support_enabled_ = true;
          env_var_set = true;
          break;
        }
      }
      if (!env_var_set) {
        for (size_t i = 0; i < GPR_ARRAY_SIZE(falsey); i++) {
          if (0 == strcmp(env, falsey[i])) {
            support_enabled_ = false;
            env_var_set = true;
            break;
          }
        }
      }
      gpr_free(env);
    }
  }
  if (support_enabled_) {
    exec_ctx_state_ = grpc_core::New<internal::ExecCtxState>();
    thread_state_ = grpc_core::New<internal::ThreadState>();
  }
}

void Fork::GlobalShutdown() {
  if (support_enabled_) {
    grpc_core::Delete(exec_ctx_state_);
    grpc_core::Delete(thread_state_);
  }
}

bool Fork::Enabled() { return support_enabled_; }

// Testing Only
void Fork::Enable(bool enable) {
  override_enabled_ = true;
  support_enabled_ = enable;
}

void Fork::IncExecCtxCount() {
  if (support_enabled_) {
    exec_ctx_state_->IncExecCtxCount();
  }
}

void Fork::DecExecCtxCount() {
  if (support_enabled_) {
    exec_ctx_state_->DecExecCtxCount();
  }
}

void Fork::SetResetChildPollingEngineFunc(
    Fork::child_postfork_func reset_child_polling_engine) {
  reset_child_polling_engine_ = reset_child_polling_engine;
}
Fork::child_postfork_func Fork::GetResetChildPollingEngineFunc() {
  return reset_child_polling_engine_;
}

bool Fork::BlockExecCtx() {
  if (support_enabled_) {
    return exec_ctx_state_->BlockExecCtx();
  }
  return false;
}

void Fork::AllowExecCtx() {
  if (support_enabled_) {
    exec_ctx_state_->AllowExecCtx();
  }
}

void Fork::IncThreadCount() {
  if (support_enabled_) {
    thread_state_->IncThreadCount();
  }
}

void Fork::DecThreadCount() {
  if (support_enabled_) {
    thread_state_->DecThreadCount();
  }
}
void Fork::AwaitThreads() {
  if (support_enabled_) {
    thread_state_->AwaitThreads();
  }
}

internal::ExecCtxState* Fork::exec_ctx_state_ = nullptr;
internal::ThreadState* Fork::thread_state_ = nullptr;
bool Fork::support_enabled_ = false;
bool Fork::override_enabled_ = false;
Fork::child_postfork_func Fork::reset_child_polling_engine_ = nullptr;
}  // namespace grpc_core
<commit_msg>Remove unnecessary else condition<commit_after>/*
 *
 * Copyright 2017 gRPC authors.
 *
 * 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 <grpc/support/port_platform.h>

#include "src/core/lib/gprpp/fork.h"

#include <string.h>

#include <grpc/support/alloc.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>

#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/memory.h"

/*
 * NOTE: FORKING IS NOT GENERALLY SUPPORTED, THIS IS ONLY INTENDED TO WORK
 *       AROUND VERY SPECIFIC USE CASES.
 */

namespace grpc_core {
namespace internal {
// The exec_ctx_count has 2 modes, blocked and unblocked.
// When unblocked, the count is 2-indexed; exec_ctx_count=2 indicates
// 0 active ExecCtxs, exex_ctx_count=3 indicates 1 active ExecCtxs...

// When blocked, the exec_ctx_count is 0-indexed.  Note that ExecCtx
// creation can only be blocked if there is exactly 1 outstanding ExecCtx,
// meaning that BLOCKED and UNBLOCKED counts partition the integers
#define UNBLOCKED(n) (n + 2)
#define BLOCKED(n) (n)

class ExecCtxState {
 public:
  ExecCtxState() : fork_complete_(true) {
    gpr_mu_init(&mu_);
    gpr_cv_init(&cv_);
    gpr_atm_no_barrier_store(&count_, UNBLOCKED(0));
  }

  void IncExecCtxCount() {
    gpr_atm count = gpr_atm_no_barrier_load(&count_);
    while (true) {
      if (count <= BLOCKED(1)) {
        // This only occurs if we are trying to fork.  Wait until the fork()
        // operation completes before allowing new ExecCtxs.
        gpr_mu_lock(&mu_);
        if (gpr_atm_no_barrier_load(&count_) <= BLOCKED(1)) {
          while (!fork_complete_) {
            gpr_cv_wait(&cv_, &mu_, gpr_inf_future(GPR_CLOCK_REALTIME));
          }
        }
        gpr_mu_unlock(&mu_);
      } else if (gpr_atm_no_barrier_cas(&count_, count, count + 1)) {
        break;
      }
      count = gpr_atm_no_barrier_load(&count_);
    }
  }

  void DecExecCtxCount() { gpr_atm_no_barrier_fetch_add(&count_, -1); }

  bool BlockExecCtx() {
    // Assumes there is an active ExecCtx when this function is called
    if (gpr_atm_no_barrier_cas(&count_, UNBLOCKED(1), BLOCKED(1))) {
      gpr_mu_lock(&mu_);
      fork_complete_ = false;
      gpr_mu_unlock(&mu_);
      return true;
    }
    return false;
  }

  void AllowExecCtx() {
    gpr_mu_lock(&mu_);
    gpr_atm_no_barrier_store(&count_, UNBLOCKED(0));
    fork_complete_ = true;
    gpr_cv_broadcast(&cv_);
    gpr_mu_unlock(&mu_);
  }

  ~ExecCtxState() {
    gpr_mu_destroy(&mu_);
    gpr_cv_destroy(&cv_);
  }

 private:
  bool fork_complete_;
  gpr_mu mu_;
  gpr_cv cv_;
  gpr_atm count_;
};

class ThreadState {
 public:
  ThreadState() : awaiting_threads_(false), threads_done_(false), count_(0) {
    gpr_mu_init(&mu_);
    gpr_cv_init(&cv_);
  }

  void IncThreadCount() {
    gpr_mu_lock(&mu_);
    count_++;
    gpr_mu_unlock(&mu_);
  }

  void DecThreadCount() {
    gpr_mu_lock(&mu_);
    count_--;
    if (awaiting_threads_ && count_ == 0) {
      threads_done_ = true;
      gpr_cv_signal(&cv_);
    }
    gpr_mu_unlock(&mu_);
  }
  void AwaitThreads() {
    gpr_mu_lock(&mu_);
    awaiting_threads_ = true;
    threads_done_ = (count_ == 0);
    while (!threads_done_) {
      gpr_cv_wait(&cv_, &mu_, gpr_inf_future(GPR_CLOCK_REALTIME));
    }
    awaiting_threads_ = true;
    gpr_mu_unlock(&mu_);
  }

  ~ThreadState() {
    gpr_mu_destroy(&mu_);
    gpr_cv_destroy(&cv_);
  }

 private:
  bool awaiting_threads_;
  bool threads_done_;
  gpr_mu mu_;
  gpr_cv cv_;
  int count_;
};

}  // namespace

void Fork::GlobalInit() {
  if (!override_enabled_) {
#ifdef GRPC_ENABLE_FORK_SUPPORT
    support_enabled_ = true;
#endif
    bool env_var_set = false;
    char* env = gpr_getenv("GRPC_ENABLE_FORK_SUPPORT");
    if (env != nullptr) {
      static const char* truthy[] = {"yes",  "Yes",  "YES", "true",
                                     "True", "TRUE", "1"};
      static const char* falsey[] = {"no",    "No",    "NO", "false",
                                     "False", "FALSE", "0"};
      for (size_t i = 0; i < GPR_ARRAY_SIZE(truthy); i++) {
        if (0 == strcmp(env, truthy[i])) {
          support_enabled_ = true;
          env_var_set = true;
          break;
        }
      }
      if (!env_var_set) {
        for (size_t i = 0; i < GPR_ARRAY_SIZE(falsey); i++) {
          if (0 == strcmp(env, falsey[i])) {
            support_enabled_ = false;
            env_var_set = true;
            break;
          }
        }
      }
      gpr_free(env);
    }
  }
  if (support_enabled_) {
    exec_ctx_state_ = grpc_core::New<internal::ExecCtxState>();
    thread_state_ = grpc_core::New<internal::ThreadState>();
  }
}

void Fork::GlobalShutdown() {
  if (support_enabled_) {
    grpc_core::Delete(exec_ctx_state_);
    grpc_core::Delete(thread_state_);
  }
}

bool Fork::Enabled() { return support_enabled_; }

// Testing Only
void Fork::Enable(bool enable) {
  override_enabled_ = true;
  support_enabled_ = enable;
}

void Fork::IncExecCtxCount() {
  if (support_enabled_) {
    exec_ctx_state_->IncExecCtxCount();
  }
}

void Fork::DecExecCtxCount() {
  if (support_enabled_) {
    exec_ctx_state_->DecExecCtxCount();
  }
}

void Fork::SetResetChildPollingEngineFunc(
    Fork::child_postfork_func reset_child_polling_engine) {
  reset_child_polling_engine_ = reset_child_polling_engine;
}
Fork::child_postfork_func Fork::GetResetChildPollingEngineFunc() {
  return reset_child_polling_engine_;
}

bool Fork::BlockExecCtx() {
  if (support_enabled_) {
    return exec_ctx_state_->BlockExecCtx();
  }
  return false;
}

void Fork::AllowExecCtx() {
  if (support_enabled_) {
    exec_ctx_state_->AllowExecCtx();
  }
}

void Fork::IncThreadCount() {
  if (support_enabled_) {
    thread_state_->IncThreadCount();
  }
}

void Fork::DecThreadCount() {
  if (support_enabled_) {
    thread_state_->DecThreadCount();
  }
}
void Fork::AwaitThreads() {
  if (support_enabled_) {
    thread_state_->AwaitThreads();
  }
}

internal::ExecCtxState* Fork::exec_ctx_state_ = nullptr;
internal::ThreadState* Fork::thread_state_ = nullptr;
bool Fork::support_enabled_ = false;
bool Fork::override_enabled_ = false;
Fork::child_postfork_func Fork::reset_child_polling_engine_ = nullptr;
}  // namespace grpc_core
<|endoftext|>


<commit_before>ass Solution {
    public:
        int removeDuplicates(int A[], int n) {
            if(n < 2) return n;
            int i = 0, removed = 0;
            while(i < n - removed){
                int j = i + 1;
                while(A[i] == A[j] && j < n - removed) ++j;
                if(j - i < 2) i = j;
                else{
                    int tmp = j;
                    for(int k = i + 1; j < n - removed; ++j, ++k){
                        A[k] = A[j];
                    }
                    removed += tmp - i - 1;
                    i = i + 1;
                }
            }
            return i;
        }
};
<commit_msg>a better time solution<commit_after>class Solution {
    public:
        int removeDuplicates(int A[], int n) {
            if(n < 2) return n;
            int i = 0, j = 0;
            while(j != n){
                while(A[i] == A[j] && j != n) ++j;
                if(j - i == 1) ++i;
                else{
                    ++i; A[i] = A[j];
                }
            }
            return i;
        }
};
<|endoftext|>


<commit_before>#include <random>

#include "data/corpus_sqlite.h"

namespace marian {
namespace data {

CorpusSQLite::CorpusSQLite(Ptr<Config> options, bool translate /*= false*/)
    : CorpusBase(options, translate), seed_(Config::seed) {
  fillSQLite();
}

CorpusSQLite::CorpusSQLite(std::vector<std::string> paths,
                           std::vector<Ptr<Vocab>> vocabs,
                           Ptr<Config> options)
    : CorpusBase(paths, vocabs, options), seed_(Config::seed) {
  fillSQLite();
}

void CorpusSQLite::fillSQLite() {
  auto tempDir = options_->get<std::string>("tempdir");
  bool fill = false;

  // create a temporary or persistent SQLite database
  if(options_->get<std::string>("sqlite") == "temporary") {
    LOG(info, "[sqlite] Creating temporary database in {}", tempDir);

    db_.reset(
        new SQLite::Database("", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE));
    db_->exec("PRAGMA temp_store_directory = '" + tempDir + "';");

    fill = true;
  } else {
    auto path = options_->get<std::string>("sqlite");

    if(boost::filesystem::exists(path)) {
      LOG(info, "[sqlite] Reusing persistent database {}", path);

      db_.reset(new SQLite::Database(path, SQLite::OPEN_READWRITE));
      db_->exec("PRAGMA temp_store_directory = '" + tempDir + "';");

      if(options_->get<bool>("sqlite-drop")) {
        LOG(info, "[sqlite] Dropping previous data");
        db_->exec("drop table if exists lines");
        fill = true;
      }
    } else {
      LOG(info, "[sqlite] Creating persistent database {}", path);

      db_.reset(new SQLite::Database(
          path, SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE));
      db_->exec("PRAGMA temp_store_directory = '" + tempDir + "';");

      fill = true;
    }
  }

  // populate tables with lines from text files
  if(fill) {
    std::string createStr = "create table lines (_id integer";
    std::string insertStr = "insert into lines values (?";
    for(int i = 0; i < files_.size(); ++i) {
      createStr += ", line" + std::to_string(i) + " text";
      insertStr += ", ?";
    }
    createStr += ");";
    insertStr += ");";

    db_->exec(createStr);

    SQLite::Statement ps(*db_, insertStr);

    int lines = 0;
    int report = 1000000;
    bool cont = true;

    db_->exec("begin;");
    while(cont) {
      ps.bind(1, (int)lines);

      std::string line;
      for(int i = 0; i < files_.size(); ++i) {
        cont = cont && std::getline((std::istream&)*files_[i], line);
        if(cont)
          ps.bind(i + 2, line);
      }

      if(cont) {
        ps.exec();
        ps.reset();
      }
      lines++;

      if(lines % report == 0) {
        LOG(info, "[sqlite] Inserted {} lines", lines);
        db_->exec("commit;");
        db_->exec("begin;");
        report *= 2;
      }
    }
    db_->exec("commit;");
    LOG(info, "[sqlite] Inserted {} lines", lines);
    LOG(info, "[sqlite] Creating primary index");
    db_->exec("create unique index idx_line on lines (_id);");
  }

  createRandomFunction();
}

SentenceTuple CorpusSQLite::next() {
  while(select_->executeStep()) {
    // fill up the sentence tuple with sentences from all input files
    size_t curId = select_->getColumn(0).getInt();
    SentenceTuple tup(curId);

    for(size_t i = 0; i < files_.size(); ++i) {
      auto line = select_->getColumn(i + 1);

      if(i > 0 && i == alignFileIdx_) {
        addAlignmentToSentenceTuple(line, tup);
      } else if(i > 0 && i == weightFileIdx_) {
        addWeightsToSentenceTuple(line, tup);
      } else {
        addWordsToSentenceTuple(line, i, tup);
      }
    }

    if(std::all_of(tup.begin(), tup.end(), [=](const Words& words) {
         return words.size() > 0 && words.size() <= maxLength_;
       }))
      return tup;
  }
  return SentenceTuple(0);
}

void CorpusSQLite::shuffle() {
  LOG(info, "[sqlite] Selecting shuffled data");
  select_.reset(new SQLite::Statement(
      *db_,
      "select * from lines order by random_seed(" + std::to_string(seed_)
          + ");"));
}

void CorpusSQLite::reset() {
  select_.reset(
      new SQLite::Statement(*db_, "select * from lines order by _id;"));
}

void CorpusSQLite::restore(Ptr<TrainingState> ts) {
  for(size_t i = 0; i < ts->epochs - 1; ++i) {
    select_.reset(new SQLite::Statement(
        *db_,
        "select _id from lines order by random_seed(" + std::to_string(seed_)
            + ");"));
    select_->executeStep();
    reset();
  }
}
}
}
<commit_msg>Fix logging the total number of inserted lines<commit_after>#include <random>

#include "data/corpus_sqlite.h"

namespace marian {
namespace data {

CorpusSQLite::CorpusSQLite(Ptr<Config> options, bool translate /*= false*/)
    : CorpusBase(options, translate), seed_(Config::seed) {
  fillSQLite();
}

CorpusSQLite::CorpusSQLite(std::vector<std::string> paths,
                           std::vector<Ptr<Vocab>> vocabs,
                           Ptr<Config> options)
    : CorpusBase(paths, vocabs, options), seed_(Config::seed) {
  fillSQLite();
}

void CorpusSQLite::fillSQLite() {
  auto tempDir = options_->get<std::string>("tempdir");
  bool fill = false;

  // create a temporary or persistent SQLite database
  if(options_->get<std::string>("sqlite") == "temporary") {
    LOG(info, "[sqlite] Creating temporary database in {}", tempDir);

    db_.reset(
        new SQLite::Database("", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE));
    db_->exec("PRAGMA temp_store_directory = '" + tempDir + "';");

    fill = true;
  } else {
    auto path = options_->get<std::string>("sqlite");

    if(boost::filesystem::exists(path)) {
      LOG(info, "[sqlite] Reusing persistent database {}", path);

      db_.reset(new SQLite::Database(path, SQLite::OPEN_READWRITE));
      db_->exec("PRAGMA temp_store_directory = '" + tempDir + "';");

      if(options_->get<bool>("sqlite-drop")) {
        LOG(info, "[sqlite] Dropping previous data");
        db_->exec("drop table if exists lines");
        fill = true;
      }
    } else {
      LOG(info, "[sqlite] Creating persistent database {}", path);

      db_.reset(new SQLite::Database(
          path, SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE));
      db_->exec("PRAGMA temp_store_directory = '" + tempDir + "';");

      fill = true;
    }
  }

  // populate tables with lines from text files
  if(fill) {
    std::string createStr = "create table lines (_id integer";
    std::string insertStr = "insert into lines values (?";
    for(int i = 0; i < files_.size(); ++i) {
      createStr += ", line" + std::to_string(i) + " text";
      insertStr += ", ?";
    }
    createStr += ");";
    insertStr += ");";

    db_->exec(createStr);

    SQLite::Statement ps(*db_, insertStr);

    int lines = 0;
    int report = 1000000;
    bool cont = true;

    db_->exec("begin;");
    while(cont) {
      ps.bind(1, (int)lines);

      std::string line;
      for(int i = 0; i < files_.size(); ++i) {
        cont = cont && std::getline((std::istream&)*files_[i], line);
        if(cont)
          ps.bind(i + 2, line);
      }

      if(cont) {
        ps.exec();
        ps.reset();
      }
      lines++;

      if(lines % report == 0) {
        LOG(info, "[sqlite] Inserted {} lines", lines);
        db_->exec("commit;");
        db_->exec("begin;");
        report *= 2;
      }
    }
    db_->exec("commit;");
    LOG(info, "[sqlite] Inserted {} lines", lines - 1);
    LOG(info, "[sqlite] Creating primary index");
    db_->exec("create unique index idx_line on lines (_id);");
  }

  createRandomFunction();
}

SentenceTuple CorpusSQLite::next() {
  while(select_->executeStep()) {
    // fill up the sentence tuple with sentences from all input files
    size_t curId = select_->getColumn(0).getInt();
    SentenceTuple tup(curId);

    for(size_t i = 0; i < files_.size(); ++i) {
      auto line = select_->getColumn(i + 1);

      if(i > 0 && i == alignFileIdx_) {
        addAlignmentToSentenceTuple(line, tup);
      } else if(i > 0 && i == weightFileIdx_) {
        addWeightsToSentenceTuple(line, tup);
      } else {
        addWordsToSentenceTuple(line, i, tup);
      }
    }

    if(std::all_of(tup.begin(), tup.end(), [=](const Words& words) {
         return words.size() > 0 && words.size() <= maxLength_;
       }))
      return tup;
  }
  return SentenceTuple(0);
}

void CorpusSQLite::shuffle() {
  LOG(info, "[sqlite] Selecting shuffled data");
  select_.reset(new SQLite::Statement(
      *db_,
      "select * from lines order by random_seed(" + std::to_string(seed_)
          + ");"));
}

void CorpusSQLite::reset() {
  select_.reset(
      new SQLite::Statement(*db_, "select * from lines order by _id;"));
}

void CorpusSQLite::restore(Ptr<TrainingState> ts) {
  for(size_t i = 0; i < ts->epochs - 1; ++i) {
    select_.reset(new SQLite::Statement(
        *db_,
        "select _id from lines order by random_seed(" + std::to_string(seed_)
            + ");"));
    select_->executeStep();
    reset();
  }
}
}
}
<|endoftext|>


<commit_before>/** Program Stream (PS) DeMUXer.
 *  Copyright 2008 Takayuki Minegishi
 *
 *  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 <assert.h>
#include <string.h>
#include "mpeg_demux.h"
#include "mpeg2.h"

static inline int skip_packet(pes_demuxer_t *dmx);
static int video_element_packet(pes_demuxer_t *dmx);

static int process_system_packet(pes_demuxer_t *dmx)
{
	int err;
	int code;

	dec_bits *bit = dmx->stream;
	code = get_bits(bit, 8);
	err = 0;
	switch (code) {
	case 0xb9:
		return -1; /* end of iso */
		/* NOT REACHED */
		break;
	case 0xba:
		skip_bytes(bit, 8);
		break;
	case 0xbd:
		err = skip_packet(dmx);
		break;
	case 0xc0:
		err = skip_packet(dmx);
		break;
	case 0xe0:
		err = video_element_packet(dmx);
		break;
	default:
		err = skip_packet(dmx);
		break;
	}
	return err;
}

static inline int skip_packet(pes_demuxer_t *dmx)
{
	int block_size = get_bits(dmx->stream, 2 * 8);
	skip_bytes(dmx->stream, block_size);
	return (0 < block_size) ? 0 : -1;
}

static int video_element_packet(pes_demuxer_t *dmx)
{
	dec_bits *bit = dmx->stream;
	int val = get_bits(bit, 3 * 8);
	const byte_t *packet_tail;

	packet_tail = dec_bits_current(bit) + ((unsigned)val >> 8) - 1;
	dmx->shortage = (int)(packet_tail - dec_bits_tail(bit));
	if ((val & 0xc0) == 0x80) {
		val = get_bits(bit, 2 * 8) & 255;
		if (val) {
			skip_bytes(bit, val);
		}
	} else {
		val &= 255;
		while (val == 255) {
			val = get_bits(bit, 8);
		}
		if (val & 0xc0) {
			if (val & 0x80) {
				return -1;
			}
			val = get_bits(bit, 2 * 8) & 255;
		}
		if (0x30 <= val) {
			if (val & 0xc0) {
				return -1;
			}
			skip_bytes(bit, 9);
		} else if (val & 0x20) {
			skip_bytes(bit, 4);
		} else if (val != 0x0f) {
			return -1;
		}
	}
	dmx->packet_head = dec_bits_current(bit);
	if (0 < dmx->shortage) {
		dmx->packet_len = (int)(dec_bits_tail(bit) - dmx->packet_head);
	} else {
		dmx->packet_len = (int)(packet_tail - dmx->packet_head);
	}
	skip_bytes(bit, dmx->packet_len);
	return 1;
}

int mpeg_demux_init(pes_demuxer_t *dmx, int (*callback_func)(void *), void *arg)
{
	if (dmx == 0) {
		return -1;
	}
	memset((void *)dmx, 0, sizeof(*dmx));
	dec_bits_open(dmx->stream = &dmx->stream_i, 0);
	dec_bits_set_callback(dmx->stream, callback_func, arg);
	return 0;
}

const byte_t *mpeg_demux_get_video(pes_demuxer_t *dmx, int *packet_size_p)
{
	dec_bits *stream;
	int err;

	stream = dmx->stream;
	if (setjmp(stream->jmp) != 0) {
		return 0;
	}
	if (0 < dmx->shortage) {
		const byte_t *current;
		int rest, min;

		show_bits(stream, 8);
		current = dec_bits_current(stream);
		rest = (int)(dec_bits_tail(stream) - current);
		min = (rest < dmx->shortage) ? rest : dmx->shortage;
		skip_bytes(stream, min);
		*packet_size_p = min;
		dmx->shortage -= rest;
		return current;
	} else {
		err = 0;
		do {
			if (err < 0 || m2d_find_mpeg_data(stream) < 0) {
				*packet_size_p = 0;
				return 0;
			}
			err = process_system_packet(dmx);
		} while (err <= 0);
		*packet_size_p = dmx->packet_len;
		return dmx->packet_head;
	}
}

<commit_msg>Fix CRLFs.<commit_after>/** Program Stream (PS) DeMUXer.
 *  Copyright 2008 Takayuki Minegishi
 *
 *  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 <assert.h>
#include <string.h>
#include "mpeg_demux.h"
#include "mpeg2.h"

static inline int skip_packet(pes_demuxer_t *dmx);
static int video_element_packet(pes_demuxer_t *dmx);

static int process_system_packet(pes_demuxer_t *dmx)
{
	int err;
	int code;

	dec_bits *bit = dmx->stream;
	code = get_bits(bit, 8);
	err = 0;
	switch (code) {
	case 0xb9:
		return -1; /* end of iso */
		/* NOT REACHED */
		break;
	case 0xba:
		skip_bytes(bit, 8);
		break;
	case 0xbd:
		err = skip_packet(dmx);
		break;
	case 0xc0:
		err = skip_packet(dmx);
		break;
	case 0xe0:
		err = video_element_packet(dmx);
		break;
	default:
		err = skip_packet(dmx);
		break;
	}
	return err;
}

static inline int skip_packet(pes_demuxer_t *dmx)
{
	int block_size = get_bits(dmx->stream, 2 * 8);
	skip_bytes(dmx->stream, block_size);
	return (0 < block_size) ? 0 : -1;
}

static int video_element_packet(pes_demuxer_t *dmx)
{
	dec_bits *bit = dmx->stream;
	int val = get_bits(bit, 3 * 8);
	const byte_t *packet_tail;

	packet_tail = dec_bits_current(bit) + ((unsigned)val >> 8) - 1;
	dmx->shortage = (int)(packet_tail - dec_bits_tail(bit));
	if ((val & 0xc0) == 0x80) {
		val = get_bits(bit, 2 * 8) & 255;
		if (val) {
			skip_bytes(bit, val);
		}
	} else {
		val &= 255;
		while (val == 255) {
			val = get_bits(bit, 8);
		}
		if (val & 0xc0) {
			if (val & 0x80) {
				return -1;
			}
			val = get_bits(bit, 2 * 8) & 255;
		}
		if (0x30 <= val) {
			if (val & 0xc0) {
				return -1;
			}
			skip_bytes(bit, 9);
		} else if (val & 0x20) {
			skip_bytes(bit, 4);
		} else if (val != 0x0f) {
			return -1;
		}
	}
	dmx->packet_head = dec_bits_current(bit);
	if (0 < dmx->shortage) {
		dmx->packet_len = (int)(dec_bits_tail(bit) - dmx->packet_head);
	} else {
		dmx->packet_len = (int)(packet_tail - dmx->packet_head);
	}
	skip_bytes(bit, dmx->packet_len);
	return 1;
}

int mpeg_demux_init(pes_demuxer_t *dmx, int (*callback_func)(void *), void *arg)
{
	if (dmx == 0) {
		return -1;
	}
	memset((void *)dmx, 0, sizeof(*dmx));
	dec_bits_open(dmx->stream = &dmx->stream_i, 0);
	dec_bits_set_callback(dmx->stream, callback_func, arg);
	return 0;
}

const byte_t *mpeg_demux_get_video(pes_demuxer_t *dmx, int *packet_size_p)
{
	dec_bits *stream;
	int err;

	stream = dmx->stream;
	if (setjmp(stream->jmp) != 0) {
		return 0;
	}
	if (0 < dmx->shortage) {
		const byte_t *current;
		int rest, min;

		show_bits(stream, 8);
		current = dec_bits_current(stream);
		rest = (int)(dec_bits_tail(stream) - current);
		min = (rest < dmx->shortage) ? rest : dmx->shortage;
		skip_bytes(stream, min);
		*packet_size_p = min;
		dmx->shortage -= rest;
		return current;
	} else {
		err = 0;
		do {
			if (err < 0 || m2d_find_mpeg_data(stream) < 0) {
				*packet_size_p = 0;
				return 0;
			}
			err = process_system_packet(dmx);
		} while (err <= 0);
		*packet_size_p = dmx->packet_len;
		return dmx->packet_head;
	}
}

<|endoftext|>


<commit_before>#ifndef HALITE_STATISTICS_HPP
#define HALITE_STATISTICS_HPP

#include <set>
#include <string>
#include <vector>

#include "json.hpp"
#include "Entity.hpp"

struct PlayerStatistics {
    int tag;
    int rank;
    int last_frame_alive;
    int init_response_time;
    double average_frame_response_time;
    double max_frame_response_time;
    int total_ship_count;
    int damage_dealt;
};

struct GameStatistics {
    std::vector<PlayerStatistics> player_statistics;
    std::string output_filename;
    std::set<unsigned short> error_tags;
    std::vector<std::string> log_filenames;
};

auto to_json(nlohmann::json& json, const GameStatistics& stats) -> void;

#endif //HALITE_STATISTICS_HPP
<commit_msg>max_frame_response_time should be an int I guess<commit_after>#ifndef HALITE_STATISTICS_HPP
#define HALITE_STATISTICS_HPP

#include <set>
#include <string>
#include <vector>

#include "json.hpp"
#include "Entity.hpp"

struct PlayerStatistics {
    int tag;
    int rank;
    int last_frame_alive;
    int init_response_time;
    double average_frame_response_time;
    int max_frame_response_time;
    int total_ship_count;
    int damage_dealt;
};

struct GameStatistics {
    std::vector<PlayerStatistics> player_statistics;
    std::string output_filename;
    std::set<unsigned short> error_tags;
    std::vector<std::string> log_filenames;
};

auto to_json(nlohmann::json& json, const GameStatistics& stats) -> void;

#endif //HALITE_STATISTICS_HPP
<|endoftext|>