<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: sbxform.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: vg $ $Date: 2008-01-28 13:58:55 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _SBXFORM_HXX
#define _SBXFORM_HXX

//====================================================================
// Klasse zur Implementation des Basic-Befehls: Format$( d,formatStr )
//====================================================================
/*
  Die Grammatik des Format-Strings (ein Versuch):
  -----------------------------------------------

  format_string     := {\special_char} general_format | scientific_format {\special_char} {;format_string}
  general_format    := {#[,]}{0[,]}[.{0}{#}]
  scientific_format := {0}[.{0}{#}](e | E)(+ | -){#}{0}

  percent_char      := '%'
  special_char      := \char | + | - | ( | ) | $ | space_char
  char              := all_ascii_chars
  space_char        := ' '

  {}    mehrfach wiederholt, auch null-mal
  []    genau einmal oder null-mal
  ()    Klammer, z.B. (e | E) heisst e oder E, genau einmal

  Weitere vordefinierte Formate f"ur den Format-String im Format$()-Befehl:
    "General Number"
    "Currency"
    "Fixed"
    "Standard"
    "Percent"
    "Scientific"
    "Yes/No"
    "True/False"
    "On/Off"

 Bemerkung: fehlerhafte Format-Strings werden wie bei Visual-Basic ignoriert,
            die Ausgabe ist dann ggf. 'undefiniert'.
            Ascii-Buchstaben werden direkt ausgegeben.

 Einschr"ankungen in Visual-Basic:
    - der Exponent (wiss. Schreibweise) kann maximal 3 Stellen haben !

 Einschr"ankungen der neuen Implementation:
    - das '+' Zeichen als Platzhalter bei der Mantisse ist nicht erlaubt

 TODO:
    - Datums-Formatierung
        Platzhalter sind: 'h', 'm', 's', 'y'
        vordefinierte String-Konstanten/Befehle:
            "AMPM", "Long Date", "Long Time"
*/

/*
    es gibt zwei M"oglichkeiten eine Zahl auf einzelne
    Ziffern zu untersuchen:

        a) verwende sprintf()
        b) verwende log10() und pow() um Ziffer
           'selbst' zu pr"aparieren (hab Probleme mit Rundungsfehlern!)
*/
#define _with_sprintf   // verwende M"oglichkeit a)

#ifndef _STRING_HXX
#include <tools/string.hxx>
#endif

class SbxBasicFormater {
  public:
    // der Konstruktor, nimmt die Zeichen f"ur den Dezimal-Punkt,
    // das Tausender-Trenn-Zeichen sowie die notwendigen Resource
    // Strings als Parameter.
    SbxBasicFormater( sal_Unicode _cDecPoint, sal_Unicode _cThousandSep,
                      String _sOnStrg,
                      String _sOffStrg,
                      String _sYesStrg,
                      String _sNoStrg,
                      String _sTrueStrg,
                      String _sFalseStrg,
                      String _sCurrencyStrg,
                      String _sCurrencyFormatStrg );

    /* der Basic-Befehl: Format$( number,format-string )

       Parameter:
        dNumber     : die Zahl, die formatiert ausgegeben werden soll
        sFormatStrg : der Format-String, z.B. ###0.0###

       Return-Wert:
        String mit der gew"unschten, formatierten Ausgabe
    */
    String  BasicFormat( double dNumber, String sFormatStrg );
    String  BasicFormatNull( String sFormatStrg );

    static  BOOL isBasicFormat( String sFormatStrg );

  private:
    //*** einige Hilfsmethoden ***
    //void  ShowError( char *sErrMsg );
    inline void ShiftString( String& sStrg, USHORT nStartPos );
    inline void StrAppendChar( String& sStrg, sal_Unicode ch );
    void    AppendDigit( String& sStrg, short nDigit );
    void    LeftShiftDecimalPoint( String& sStrg );
    void    StrRoundDigit( String& sStrg, short nPos, BOOL& bOverflow );
    void    StrRoundDigit( String& sStrg, short nPos );
    void    ParseBack( String& sStrg, const String& sFormatStrg,
                short nFormatPos );
#ifdef _with_sprintf
    // Methoden "uber String-Konvertierung mit sprintf():
    void    InitScan( double _dNum );
    void    InitExp( double _dNewExp );
    short   GetDigitAtPosScan( short nPos, BOOL& bFoundFirstDigit );
    short   GetDigitAtPosExpScan( double dNewExponent, short nPos,
                BOOL& bFoundFirstDigit );
    short   GetDigitAtPosExpScan( short nPos, BOOL& bFoundFirstDigit );
#else
    // Methoden "uber direktes 'ausrechen' mit log10() und pow():
    short   GetDigitAtPos( double dNumber, short nPos, double& dNextNumber,
                BOOL& bFoundFirstDigit );
    short   RoundDigit( double dNumber );
#endif
    String  GetPosFormatString( const String& sFormatStrg, BOOL & bFound );
    String  GetNegFormatString( const String& sFormatStrg, BOOL & bFound );
    String  Get0FormatString( const String& sFormatStrg, BOOL & bFound );
    String  GetNullFormatString( const String& sFormatStrg, BOOL & bFound );
    short   AnalyseFormatString( const String& sFormatStrg,
                short& nNoOfDigitsLeft, short& nNoOfDigitsRight,
                short& nNoOfOptionalDigitsLeft,
                short& nNoOfExponentDigits,
                short& nNoOfOptionalExponentDigits,
                BOOL& bPercent, BOOL& bCurrency, BOOL& bScientific,
                BOOL& bGenerateThousandSeparator,
                short& nMultipleThousandSeparators );
    void    ScanFormatString( double dNumber, const String& sFormatStrg,
                String& sReturnStrg, BOOL bCreateSign );

    //*** Daten ***
    sal_Unicode cDecPoint;      // das Zeichen f"ur den Dezimal-Punkt
    sal_Unicode cThousandSep;   // das Zeichen f"ur das Tausender-Trennzeichen
    // Texte zur Ausgabe:
    String  sOnStrg;
    String  sOffStrg;
    String  sYesStrg;
    String  sNoStrg;
    String  sTrueStrg;
    String  sFalseStrg;
    String  sCurrencyStrg;
    String  sCurrencyFormatStrg;

    //*** tempor"are Daten f"ur die Scan-Schleife ***
    //-----------------------------------------------
    // Zeichenkette, in dem die Zahl als Scientific-Format abgelegt wird
    String  sSciNumStrg;
    // Zeichenkette, in der der Exponent der Zahl abgelegt wird
    String  sNumExpStrg;
    double  dNum;           // die zu scannede Zahl
    short   nNumExp;        // der Exponent der zu scannenden Zahl
    short   nExpExp;        // die Anzahl der Stellen im Exponenten
};

#endif

<commit_msg>INTEGRATION: CWS changefileheader (1.3.24); FILE MERGED 2008/04/01 15:01:45 thb 1.3.24.2: #i85898# Stripping all external header guards 2008/03/28 16:06:57 rt 1.3.24.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: sbxform.hxx,v $
 * $Revision: 1.4 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _SBXFORM_HXX
#define _SBXFORM_HXX

//====================================================================
// Klasse zur Implementation des Basic-Befehls: Format$( d,formatStr )
//====================================================================
/*
  Die Grammatik des Format-Strings (ein Versuch):
  -----------------------------------------------

  format_string     := {\special_char} general_format | scientific_format {\special_char} {;format_string}
  general_format    := {#[,]}{0[,]}[.{0}{#}]
  scientific_format := {0}[.{0}{#}](e | E)(+ | -){#}{0}

  percent_char      := '%'
  special_char      := \char | + | - | ( | ) | $ | space_char
  char              := all_ascii_chars
  space_char        := ' '

  {}    mehrfach wiederholt, auch null-mal
  []    genau einmal oder null-mal
  ()    Klammer, z.B. (e | E) heisst e oder E, genau einmal

  Weitere vordefinierte Formate f"ur den Format-String im Format$()-Befehl:
    "General Number"
    "Currency"
    "Fixed"
    "Standard"
    "Percent"
    "Scientific"
    "Yes/No"
    "True/False"
    "On/Off"

 Bemerkung: fehlerhafte Format-Strings werden wie bei Visual-Basic ignoriert,
            die Ausgabe ist dann ggf. 'undefiniert'.
            Ascii-Buchstaben werden direkt ausgegeben.

 Einschr"ankungen in Visual-Basic:
    - der Exponent (wiss. Schreibweise) kann maximal 3 Stellen haben !

 Einschr"ankungen der neuen Implementation:
    - das '+' Zeichen als Platzhalter bei der Mantisse ist nicht erlaubt

 TODO:
    - Datums-Formatierung
        Platzhalter sind: 'h', 'm', 's', 'y'
        vordefinierte String-Konstanten/Befehle:
            "AMPM", "Long Date", "Long Time"
*/

/*
    es gibt zwei M"oglichkeiten eine Zahl auf einzelne
    Ziffern zu untersuchen:

        a) verwende sprintf()
        b) verwende log10() und pow() um Ziffer
           'selbst' zu pr"aparieren (hab Probleme mit Rundungsfehlern!)
*/
#define _with_sprintf   // verwende M"oglichkeit a)

#include <tools/string.hxx>

class SbxBasicFormater {
  public:
    // der Konstruktor, nimmt die Zeichen f"ur den Dezimal-Punkt,
    // das Tausender-Trenn-Zeichen sowie die notwendigen Resource
    // Strings als Parameter.
    SbxBasicFormater( sal_Unicode _cDecPoint, sal_Unicode _cThousandSep,
                      String _sOnStrg,
                      String _sOffStrg,
                      String _sYesStrg,
                      String _sNoStrg,
                      String _sTrueStrg,
                      String _sFalseStrg,
                      String _sCurrencyStrg,
                      String _sCurrencyFormatStrg );

    /* der Basic-Befehl: Format$( number,format-string )

       Parameter:
        dNumber     : die Zahl, die formatiert ausgegeben werden soll
        sFormatStrg : der Format-String, z.B. ###0.0###

       Return-Wert:
        String mit der gew"unschten, formatierten Ausgabe
    */
    String  BasicFormat( double dNumber, String sFormatStrg );
    String  BasicFormatNull( String sFormatStrg );

    static  BOOL isBasicFormat( String sFormatStrg );

  private:
    //*** einige Hilfsmethoden ***
    //void  ShowError( char *sErrMsg );
    inline void ShiftString( String& sStrg, USHORT nStartPos );
    inline void StrAppendChar( String& sStrg, sal_Unicode ch );
    void    AppendDigit( String& sStrg, short nDigit );
    void    LeftShiftDecimalPoint( String& sStrg );
    void    StrRoundDigit( String& sStrg, short nPos, BOOL& bOverflow );
    void    StrRoundDigit( String& sStrg, short nPos );
    void    ParseBack( String& sStrg, const String& sFormatStrg,
                short nFormatPos );
#ifdef _with_sprintf
    // Methoden "uber String-Konvertierung mit sprintf():
    void    InitScan( double _dNum );
    void    InitExp( double _dNewExp );
    short   GetDigitAtPosScan( short nPos, BOOL& bFoundFirstDigit );
    short   GetDigitAtPosExpScan( double dNewExponent, short nPos,
                BOOL& bFoundFirstDigit );
    short   GetDigitAtPosExpScan( short nPos, BOOL& bFoundFirstDigit );
#else
    // Methoden "uber direktes 'ausrechen' mit log10() und pow():
    short   GetDigitAtPos( double dNumber, short nPos, double& dNextNumber,
                BOOL& bFoundFirstDigit );
    short   RoundDigit( double dNumber );
#endif
    String  GetPosFormatString( const String& sFormatStrg, BOOL & bFound );
    String  GetNegFormatString( const String& sFormatStrg, BOOL & bFound );
    String  Get0FormatString( const String& sFormatStrg, BOOL & bFound );
    String  GetNullFormatString( const String& sFormatStrg, BOOL & bFound );
    short   AnalyseFormatString( const String& sFormatStrg,
                short& nNoOfDigitsLeft, short& nNoOfDigitsRight,
                short& nNoOfOptionalDigitsLeft,
                short& nNoOfExponentDigits,
                short& nNoOfOptionalExponentDigits,
                BOOL& bPercent, BOOL& bCurrency, BOOL& bScientific,
                BOOL& bGenerateThousandSeparator,
                short& nMultipleThousandSeparators );
    void    ScanFormatString( double dNumber, const String& sFormatStrg,
                String& sReturnStrg, BOOL bCreateSign );

    //*** Daten ***
    sal_Unicode cDecPoint;      // das Zeichen f"ur den Dezimal-Punkt
    sal_Unicode cThousandSep;   // das Zeichen f"ur das Tausender-Trennzeichen
    // Texte zur Ausgabe:
    String  sOnStrg;
    String  sOffStrg;
    String  sYesStrg;
    String  sNoStrg;
    String  sTrueStrg;
    String  sFalseStrg;
    String  sCurrencyStrg;
    String  sCurrencyFormatStrg;

    //*** tempor"are Daten f"ur die Scan-Schleife ***
    //-----------------------------------------------
    // Zeichenkette, in dem die Zahl als Scientific-Format abgelegt wird
    String  sSciNumStrg;
    // Zeichenkette, in der der Exponent der Zahl abgelegt wird
    String  sNumExpStrg;
    double  dNum;           // die zu scannede Zahl
    short   nNumExp;        // der Exponent der zu scannenden Zahl
    short   nExpExp;        // die Anzahl der Stellen im Exponenten
};

#endif

<|endoftext|>


<commit_before>// infoware - C++ System information Library
//
// Written in 2016-2019 by nabijaczleweli <nabijaczleweli@gmail.com> and ThePhD <phdofthehouse@gmail.com>
//
// To the extent possible under law, the author(s) have dedicated all copyright and related
// and neighboring rights to this software to the public domain worldwide. This software is
// distributed without any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>

#ifndef INFOWARE_USE_D3D
#ifdef INFOWARE_USE_OPENCL

#include "infoware/gpu.hpp"
#include <cstdlib>
#include <cstring>
#ifdef __APPLE__
#include <OpenCL/opencl.h>
#else
#include <CL/cl.h>
#endif

static iware::gpu::vendor_t parse_vendor(const char* name) {
	if(!strcmp(name, "Intel(R) Corporation"))
		return iware::gpu::vendor_t::intel;
	else if(!strcmp(name, "Advanced Micro Devices, Inc."))
		return iware::gpu::vendor_t::amd;
	else if(!strcmp(name, "NVIDIA Corporation"))
		return iware::gpu::vendor_t::nvidia;
	else
		return iware::gpu::vendor_t::unknown;
}

std::vector<iware::gpu::device_properties_t> iware::gpu::device_properties() {
	cl_platform_id platforms[64];
	cl_uint platforms_used;
	clGetPlatformIDs(sizeof platforms / sizeof(*platforms), platforms, &platforms_used);

	std::vector<iware::gpu::device_properties_t> ret;
	for(auto i = 0u; i < platforms_used; ++i) {
		cl_device_id devices[64];
		cl_uint devices_used;
		clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_GPU, sizeof devices / sizeof(*devices), devices, &devices_used);

		for(auto j = 0u; j < devices_used; ++j) {
			char name[256];
			char vendorname[256];
			cl_ulong cache;
			cl_ulong memory;

			clGetDeviceInfo(devices[j], CL_DEVICE_GLOBAL_MEM_CACHE_SIZE, sizeof(cache), &cache, nullptr);
			clGetDeviceInfo(devices[j], CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(memory), &memory, nullptr);
			clGetDeviceInfo(devices[j], CL_DEVICE_VENDOR, sizeof vendorname, &vendorname, nullptr);
			clGetDeviceInfo(devices[j], CL_DEVICE_NAME, sizeof name, &name, nullptr);

			ret.push_back(iware::gpu::device_properties_t{parse_vendor(vendorname), name, memory, cache});
		}
	}

	return ret;
}

#endif
#endif
<commit_msg>But do gnome OpenCL while we're at it<commit_after>// infoware - C++ System information Library
//
// Written in 2016-2019 by nabijaczleweli <nabijaczleweli@gmail.com> and ThePhD <phdofthehouse@gmail.com>
//
// To the extent possible under law, the author(s) have dedicated all copyright and related
// and neighboring rights to this software to the public domain worldwide. This software is
// distributed without any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>

#ifndef INFOWARE_USE_D3D
#ifdef INFOWARE_USE_OPENCL

#include "infoware/gpu.hpp"
#include <cstdlib>
#include <cstring>
#ifdef __APPLE__
#include <OpenCL/opencl.h>
#else
#include <CL/cl.h>
#endif

static iware::gpu::vendor_t parse_vendor(const char* name) {
	if(!std::strcmp(name, "Intel(R) Corporation"))
		return iware::gpu::vendor_t::intel;
	else if(!std::strcmp(name, "Advanced Micro Devices, Inc."))
		return iware::gpu::vendor_t::amd;
	else if(!std::strcmp(name, "NVIDIA Corporation"))
		return iware::gpu::vendor_t::nvidia;
	else
		return iware::gpu::vendor_t::unknown;
}

std::vector<iware::gpu::device_properties_t> iware::gpu::device_properties() {
	cl_platform_id platforms[64];
	cl_uint platforms_used;
	clGetPlatformIDs(sizeof(platforms) / sizeof(*platforms), platforms, &platforms_used);

	std::vector<iware::gpu::device_properties_t> ret;
	for(auto i = 0u; i < platforms_used; ++i) {
		cl_device_id devices[64];
		cl_uint devices_used;
		clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_GPU, sizeof(devices) / sizeof(*devices), devices, &devices_used);

		for(auto j = 0u; j < devices_used; ++j) {
			char name[256];
			char vendorname[256];
			cl_ulong cache;
			cl_ulong memory;

			clGetDeviceInfo(devices[j], CL_DEVICE_GLOBAL_MEM_CACHE_SIZE, sizeof(cache), &cache, nullptr);
			clGetDeviceInfo(devices[j], CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(memory), &memory, nullptr);
			clGetDeviceInfo(devices[j], CL_DEVICE_VENDOR, sizeof(vendorname) / sizeof(*vendorname), &vendorname, nullptr);
			clGetDeviceInfo(devices[j], CL_DEVICE_NAME, sizeof(name) / sizeof(*name), &name, nullptr);

			ret.push_back({parse_vendor(vendorname), name, memory, cache});
		}
	}

	return ret;
}

#endif
#endif
<|endoftext|>


<commit_before>/*
 * fMBT, free Model Based Testing tool
 * Copyright (c) 2011, Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU Lesser General Public License,
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */
#ifndef __log_null_h__
#define __log_null_h__

#include "log.hh"

class Log_null: public Log {
public:
  virtual ~Log_null() {}
  virtual void write(const char* msg) {}
  virtual void print(const char* format,...) {}
  virtual void write(int action,const char *name,
		     const char *msg) {}
};

#endif
<commit_msg>log.error<commit_after>/*
 * fMBT, free Model Based Testing tool
 * Copyright (c) 2011, Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU Lesser General Public License,
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */
#ifndef __log_null_h__
#define __log_null_h__

#include "log.hh"

class Log_null: public Log {
public:
  virtual ~Log_null() {}
  virtual void write(const char* msg) {}
  virtual void error(const char**format,...) {}
  virtual void print(const char* format,va_list ap) {}
  virtual void print(const char* format,...) {}
  virtual void write(int action,const char *name,
		     const char *msg) {}
};

#endif
<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

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

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

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

*/

#include "libtorrent/pch.hpp"

#include "libtorrent/lsd.hpp"
#include "libtorrent/io.hpp"
#include "libtorrent/http_tracker_connection.hpp"
#include "libtorrent/buffer.hpp"
#include "libtorrent/http_parser.hpp"
#include "libtorrent/escape_string.hpp"
#include "libtorrent/socket_io.hpp" // for print_address

#include <boost/bind.hpp>
#include <boost/ref.hpp>
#if BOOST_VERSION < 103500
#include <asio/ip/host_name.hpp>
#include <asio/ip/multicast.hpp>
#else
#include <boost/asio/ip/host_name.hpp>
#include <boost/asio/ip/multicast.hpp>
#endif
#include <cstdlib>
#include <boost/config.hpp>

using boost::bind;
using namespace libtorrent;

namespace libtorrent
{
	// defined in broadcast_socket.cpp
	address guess_local_address(io_service&);
}

static error_code ec;

lsd::lsd(io_service& ios, address const& listen_interface
	, peer_callback_t const& cb)
	: m_callback(cb)
	, m_retry_count(1)
	, m_socket(ios, udp::endpoint(address_v4::from_string("239.192.152.143", ec), 6771)
		, bind(&lsd::on_announce, self(), _1, _2, _3))
	, m_broadcast_timer(ios)
	, m_disabled(false)
{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log.open("lsd.log", std::ios::in | std::ios::out | std::ios::trunc);
#endif
}

lsd::~lsd() {}

void lsd::announce(sha1_hash const& ih, int listen_port)
{
	if (m_disabled) return;

	char ih_hex[41];
	to_hex((char const*)&ih[0], 20, ih_hex);
	char msg[200];
	int msg_len = snprintf(msg, 200,
		"BT-SEARCH * HTTP/1.1\r\n"
		"Host: 239.192.152.143:6771\r\n"
		"Port: %d\r\n"
		"Infohash: %s\r\n"
		"\r\n\r\n", listen_port, ih_hex);

	m_retry_count = 1;
	error_code ec;
	m_socket.send(msg, msg_len, ec);
	if (ec)
	{
		m_disabled = true;
		return;
	}

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	snprintf(msg, 200, "%s ==> announce: ih: %s port: %u"
		, time_now_string(), ih_hex, listen_port);
	m_log << msg << std::endl;
#endif

	m_broadcast_timer.expires_from_now(milliseconds(250 * m_retry_count), ec);
	m_broadcast_timer.async_wait(bind(&lsd::resend_announce, self(), _1, msg));
}

void lsd::resend_announce(error_code const& e, std::string msg)
{
	if (e) return;

	error_code ec;
	m_socket.send(msg.c_str(), int(msg.size()), ec);

	++m_retry_count;
	if (m_retry_count >= 5)
		return;

	m_broadcast_timer.expires_from_now(milliseconds(250 * m_retry_count), ec);
	m_broadcast_timer.async_wait(bind(&lsd::resend_announce, self(), _1, msg));
}

void lsd::on_announce(udp::endpoint const& from, char* buffer
	, std::size_t bytes_transferred)
{
	using namespace libtorrent::detail;

	http_parser p;

	bool error = false;
	p.incoming(buffer::const_interval(buffer, buffer + bytes_transferred)
		, error);

	if (!p.header_finished() || error)
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " <== announce: incomplete HTTP message" << std::endl;
#endif
		return;
	}

	if (p.method() != "bt-search")
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " <== announce: invalid HTTP method: " << p.method() << std::endl;
#endif
		return;
	}

	std::string const& port_str = p.header("port");
	if (port_str.empty())
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " <== announce: invalid BT-SEARCH, missing port" << std::endl;
#endif
		return;
	}

	std::string const& ih_str = p.header("infohash");
	if (ih_str.empty())
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " <== announce: invalid BT-SEARCH, missing infohash" << std::endl;
#endif
		return;
	}

	sha1_hash ih(0);
	from_hex(ih_str.c_str(), 40, (char*)&ih[0]);
	int port = std::atoi(port_str.c_str());

	if (!ih.is_all_zeros() && port != 0)
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		char msg[200];
		snprintf(msg, 200, "%s *** incoming local announce %s:%d ih: %s\n"
			, time_now_string(), print_address(from.address()).c_str()
			, port, ih_str.c_str());
#endif
		// we got an announce, pass it on through the callback
#ifndef BOOST_NO_EXCEPTIONS
		try {
#endif
			m_callback(tcp::endpoint(from.address(), port), ih);
#ifndef BOOST_NO_EXCEPTIONS
		}
		catch (std::exception&) {}
#endif
	}
}

void lsd::close()
{
	m_socket.close();
	error_code ec;
	m_broadcast_timer.cancel(ec);
	m_disabled = true;
	m_callback.clear();
}

<commit_msg>local service discovery fix<commit_after>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

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

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

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

*/

#include "libtorrent/pch.hpp"

#include "libtorrent/lsd.hpp"
#include "libtorrent/io.hpp"
#include "libtorrent/http_tracker_connection.hpp"
#include "libtorrent/buffer.hpp"
#include "libtorrent/http_parser.hpp"
#include "libtorrent/escape_string.hpp"
#include "libtorrent/socket_io.hpp" // for print_address

#include <boost/bind.hpp>
#include <boost/ref.hpp>
#if BOOST_VERSION < 103500
#include <asio/ip/host_name.hpp>
#include <asio/ip/multicast.hpp>
#else
#include <boost/asio/ip/host_name.hpp>
#include <boost/asio/ip/multicast.hpp>
#endif
#include <cstdlib>
#include <boost/config.hpp>

using boost::bind;
using namespace libtorrent;

namespace libtorrent
{
	// defined in broadcast_socket.cpp
	address guess_local_address(io_service&);
}

static error_code ec;

lsd::lsd(io_service& ios, address const& listen_interface
	, peer_callback_t const& cb)
	: m_callback(cb)
	, m_retry_count(1)
	, m_socket(ios, udp::endpoint(address_v4::from_string("239.192.152.143", ec), 6771)
		, bind(&lsd::on_announce, self(), _1, _2, _3))
	, m_broadcast_timer(ios)
	, m_disabled(false)
{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log.open("lsd.log", std::ios::in | std::ios::out | std::ios::trunc);
#endif
}

lsd::~lsd() {}

void lsd::announce(sha1_hash const& ih, int listen_port)
{
	if (m_disabled) return;

	char ih_hex[41];
	to_hex((char const*)&ih[0], 20, ih_hex);
	char msg[200];
	int msg_len = snprintf(msg, 200,
		"BT-SEARCH * HTTP/1.1\r\n"
		"Host: 239.192.152.143:6771\r\n"
		"Port: %d\r\n"
		"Infohash: %s\r\n"
		"\r\n\r\n", listen_port, ih_hex);

	m_retry_count = 1;
	error_code ec;
	m_socket.send(msg, msg_len, ec);
	if (ec)
	{
		m_disabled = true;
		return;
	}

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	snprintf(msg, 200, "%s ==> announce: ih: %s port: %u"
		, time_now_string(), ih_hex, listen_port);
	m_log << msg << std::endl;
#endif

	m_broadcast_timer.expires_from_now(milliseconds(250 * m_retry_count), ec);
	m_broadcast_timer.async_wait(bind(&lsd::resend_announce, self(), _1, std::string(msg)));
}

void lsd::resend_announce(error_code const& e, std::string msg)
{
	if (e) return;

	error_code ec;
	m_socket.send(msg.c_str(), int(msg.size()), ec);

	++m_retry_count;
	if (m_retry_count >= 5)
		return;

	m_broadcast_timer.expires_from_now(milliseconds(250 * m_retry_count), ec);
	m_broadcast_timer.async_wait(bind(&lsd::resend_announce, self(), _1, msg));
}

void lsd::on_announce(udp::endpoint const& from, char* buffer
	, std::size_t bytes_transferred)
{
	using namespace libtorrent::detail;

	http_parser p;

	bool error = false;
	p.incoming(buffer::const_interval(buffer, buffer + bytes_transferred)
		, error);

	if (!p.header_finished() || error)
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " <== announce: incomplete HTTP message" << std::endl;
#endif
		return;
	}

	if (p.method() != "bt-search")
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " <== announce: invalid HTTP method: " << p.method() << std::endl;
#endif
		return;
	}

	std::string const& port_str = p.header("port");
	if (port_str.empty())
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " <== announce: invalid BT-SEARCH, missing port" << std::endl;
#endif
		return;
	}

	std::string const& ih_str = p.header("infohash");
	if (ih_str.empty())
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " <== announce: invalid BT-SEARCH, missing infohash" << std::endl;
#endif
		return;
	}

	sha1_hash ih(0);
	from_hex(ih_str.c_str(), 40, (char*)&ih[0]);
	int port = std::atoi(port_str.c_str());

	if (!ih.is_all_zeros() && port != 0)
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		char msg[200];
		snprintf(msg, 200, "%s *** incoming local announce %s:%d ih: %s\n"
			, time_now_string(), print_address(from.address()).c_str()
			, port, ih_str.c_str());
#endif
		// we got an announce, pass it on through the callback
#ifndef BOOST_NO_EXCEPTIONS
		try {
#endif
			m_callback(tcp::endpoint(from.address(), port), ih);
#ifndef BOOST_NO_EXCEPTIONS
		}
		catch (std::exception&) {}
#endif
	}
}

void lsd::close()
{
	m_socket.close();
	error_code ec;
	m_broadcast_timer.cancel(ec);
	m_disabled = true;
	m_callback.clear();
}

<|endoftext|>


<commit_before>#include <qt/test/util.h>
#include <qt/test/wallettests.h>

#include <cashaddrenc.h>
#include <chain.h>
#include <chainparams.h>
#include <interfaces/node.h>
#include <key_io.h>
#include <qt/bitcoinamountfield.h>
#include <qt/optionsmodel.h>
#include <qt/overviewpage.h>
#include <qt/platformstyle.h>
#include <qt/qvalidatedlineedit.h>
#include <qt/receivecoinsdialog.h>
#include <qt/receiverequestdialog.h>
#include <qt/recentrequeststablemodel.h>
#include <qt/sendcoinsdialog.h>
#include <qt/sendcoinsentry.h>
#include <qt/transactiontablemodel.h>
#include <qt/walletmodel.h>
#include <validation.h>
#include <wallet/wallet.h>

#include <test/test_bitcoin.h>

#include <QAbstractButton>
#include <QApplication>
#include <QDialogButtonBox>
#include <QListView>
#include <QPushButton>
#include <QTextEdit>
#include <QTimer>
#include <QVBoxLayout>

namespace {
//! Press "Yes" or "Cancel" buttons in modal send confirmation dialog.
void ConfirmSend(QString *text = nullptr, bool cancel = false) {
    QTimer::singleShot(0, Qt::PreciseTimer, [text, cancel]() {
        for (QWidget *widget : QApplication::topLevelWidgets()) {
            if (widget->inherits("SendConfirmationDialog")) {
                SendConfirmationDialog *dialog =
                    qobject_cast<SendConfirmationDialog *>(widget);
                if (text) {
                    *text = dialog->text();
                }
                QAbstractButton *button = dialog->button(
                    cancel ? QMessageBox::Cancel : QMessageBox::Yes);
                button->setEnabled(true);
                button->click();
            }
        }
    });
}

//! Send coins to address and return txid.
uint256 SendCoins(CWallet &wallet, SendCoinsDialog &sendCoinsDialog,
                  const CTxDestination &address, Amount amount) {
    QVBoxLayout *entries = sendCoinsDialog.findChild<QVBoxLayout *>("entries");
    SendCoinsEntry *entry =
        qobject_cast<SendCoinsEntry *>(entries->itemAt(0)->widget());
    entry->findChild<QValidatedLineEdit *>("payTo")->setText(
        QString::fromStdString(EncodeCashAddr(address, Params())));
    entry->findChild<BitcoinAmountField *>("payAmount")->setValue(amount);
    uint256 txid;
    boost::signals2::scoped_connection c =
        wallet.NotifyTransactionChanged.connect(
            [&txid](CWallet *, const uint256 &hash, ChangeType status) {
                if (status == CT_NEW) {
                    txid = hash;
                }
            });
    ConfirmSend();
    QMetaObject::invokeMethod(&sendCoinsDialog, "on_sendButton_clicked");
    return txid;
}

//! Find index of txid in transaction list.
QModelIndex FindTx(const QAbstractItemModel &model, const uint256 &txid) {
    QString hash = QString::fromStdString(txid.ToString());
    int rows = model.rowCount({});
    for (int row = 0; row < rows; ++row) {
        QModelIndex index = model.index(row, 0, {});
        if (model.data(index, TransactionTableModel::TxHashRole) == hash) {
            return index;
        }
    }
    return {};
}

//! Simple qt wallet tests.
//
// Test widgets can be debugged interactively calling show() on them and
// manually running the event loop, e.g.:
//
//     sendCoinsDialog.show();
//     QEventLoop().exec();
//
// This also requires overriding the default minimal Qt platform:
//
//     src/qt/test/test_bitcoin-qt -platform xcb      # Linux
//     src/qt/test/test_bitcoin-qt -platform windows  # Windows
//     src/qt/test/test_bitcoin-qt -platform cocoa    # macOS
void TestGUI() {
    // Set up wallet and chain with 105 blocks (5 mature blocks for spending).
    TestChain100Setup test;
    for (int i = 0; i < 5; ++i) {
        test.CreateAndProcessBlock(
            {}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey()));
    }
    CWallet wallet(Params(), "mock", WalletDatabase::CreateMock());
    bool firstRun;
    wallet.LoadWallet(firstRun);
    {
        LOCK(wallet.cs_wallet);
        wallet.SetAddressBook(
            GetDestinationForKey(test.coinbaseKey.GetPubKey(),
                                 wallet.m_default_address_type),
            "", "receive");
        wallet.AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey());
    }
    {
        LOCK(cs_main);
        WalletRescanReserver reserver(&wallet);
        reserver.reserve();
        wallet.ScanForWalletTransactions(chainActive.Genesis(), nullptr,
                                         reserver, true);
    }
    wallet.SetBroadcastTransactions(true);

    // Create widgets for sending coins and listing transactions.
    std::unique_ptr<const PlatformStyle> platformStyle(
        PlatformStyle::instantiate("other"));
    auto node = interfaces::MakeNode();
    OptionsModel optionsModel(*node);
    AddWallet(&wallet);
    WalletModel walletModel(std::move(node->getWallets().back()), *node,
                            platformStyle.get(), &optionsModel);
    RemoveWallet(&wallet);

    // Send two transactions, and verify they are added to transaction list.
    SendCoinsDialog sendCoinsDialog(platformStyle.get(), &walletModel);
    TransactionTableModel *transactionTableModel =
        walletModel.getTransactionTableModel();
    QCOMPARE(transactionTableModel->rowCount({}), 105);
    uint256 txid1 =
        SendCoins(wallet, sendCoinsDialog, CTxDestination(CKeyID()), 5 * COIN);
    uint256 txid2 =
        SendCoins(wallet, sendCoinsDialog, CTxDestination(CKeyID()), 10 * COIN);
    QCOMPARE(transactionTableModel->rowCount({}), 107);
    QVERIFY(FindTx(*transactionTableModel, txid1).isValid());
    QVERIFY(FindTx(*transactionTableModel, txid2).isValid());

    // Check current balance on OverviewPage
    OverviewPage overviewPage(platformStyle.get());
    overviewPage.setWalletModel(&walletModel);
    QLabel *balanceLabel = overviewPage.findChild<QLabel *>("labelBalance");
    QString balanceText = balanceLabel->text();
    int unit = walletModel.getOptionsModel()->getDisplayUnit();
    Amount balance = walletModel.wallet().getBalance();
    QString balanceComparison = BitcoinUnits::formatWithUnit(
        unit, balance, false, BitcoinUnits::separatorAlways);
    QCOMPARE(balanceText, balanceComparison);

    // Check Request Payment button
    ReceiveCoinsDialog receiveCoinsDialog(platformStyle.get());
    receiveCoinsDialog.setModel(&walletModel);
    RecentRequestsTableModel *requestTableModel =
        walletModel.getRecentRequestsTableModel();

    // Label input
    QLineEdit *labelInput =
        receiveCoinsDialog.findChild<QLineEdit *>("reqLabel");
    labelInput->setText("TEST_LABEL_1");

    // Amount input
    BitcoinAmountField *amountInput =
        receiveCoinsDialog.findChild<BitcoinAmountField *>("reqAmount");
    amountInput->setValue(1 * SATOSHI);

    // Message input
    QLineEdit *messageInput =
        receiveCoinsDialog.findChild<QLineEdit *>("reqMessage");
    messageInput->setText("TEST_MESSAGE_1");
    int initialRowCount = requestTableModel->rowCount({});
    QPushButton *requestPaymentButton =
        receiveCoinsDialog.findChild<QPushButton *>("receiveButton");
    requestPaymentButton->click();
    for (QWidget *widget : QApplication::topLevelWidgets()) {
        if (widget->inherits("ReceiveRequestDialog")) {
            ReceiveRequestDialog *receiveRequestDialog =
                qobject_cast<ReceiveRequestDialog *>(widget);
            QTextEdit *rlist =
                receiveRequestDialog->QObject::findChild<QTextEdit *>("outUri");
            QString paymentText = rlist->toPlainText();
            QStringList paymentTextList = paymentText.split('\n');
            QCOMPARE(paymentTextList.at(0), QString("Payment information"));
            QVERIFY(paymentTextList.at(1).indexOf(QString("URI: bchreg:")) !=
                    -1);
            QVERIFY(paymentTextList.at(2).indexOf(QString("Address:")) != -1);
            QCOMPARE(paymentTextList.at(3),
                     QString("Amount: 0.00000001 ") +
                         QString::fromStdString(CURRENCY_UNIT));
            QCOMPARE(paymentTextList.at(4), QString("Label: TEST_LABEL_1"));
            QCOMPARE(paymentTextList.at(5), QString("Message: TEST_MESSAGE_1"));
        }
    }

    // Clear button
    QPushButton *clearButton =
        receiveCoinsDialog.findChild<QPushButton *>("clearButton");
    clearButton->click();
    QCOMPARE(labelInput->text(), QString(""));
    QCOMPARE(amountInput->value(), Amount::zero());
    QCOMPARE(messageInput->text(), QString(""));

    // Check addition to history
    int currentRowCount = requestTableModel->rowCount({});
    QCOMPARE(currentRowCount, initialRowCount + 1);

    // Check Remove button
    QTableView *table =
        receiveCoinsDialog.findChild<QTableView *>("recentRequestsView");
    table->selectRow(currentRowCount - 1);
    QPushButton *removeRequestButton =
        receiveCoinsDialog.findChild<QPushButton *>("removeRequestButton");
    removeRequestButton->click();
    QCOMPARE(requestTableModel->rowCount({}), currentRowCount - 1);
}

} // namespace

void WalletTests::walletTests() {
#ifdef Q_OS_MAC
    if (QApplication::platformName() == "minimal") {
        // Disable for mac on "minimal" platform to avoid crashes inside the Qt
        // framework when it tries to look up unimplemented cocoa functions,
        // and fails to handle returned nulls
        // (https://bugreports.qt.io/browse/QTBUG-49686).
        QWARN("Skipping WalletTests on mac build with 'minimal' platform set "
              "due to Qt bugs. To run AppTests, invoke with 'test_bitcoin-qt "
              "-platform cocoa' on mac, or else use a linux or windows build.");
        return;
    }
#endif
    TestGUI();
}
<commit_msg>Use TxId where apropriate in wallettests.cpp<commit_after>#include <qt/test/util.h>
#include <qt/test/wallettests.h>

#include <cashaddrenc.h>
#include <chain.h>
#include <chainparams.h>
#include <interfaces/node.h>
#include <key_io.h>
#include <qt/bitcoinamountfield.h>
#include <qt/optionsmodel.h>
#include <qt/overviewpage.h>
#include <qt/platformstyle.h>
#include <qt/qvalidatedlineedit.h>
#include <qt/receivecoinsdialog.h>
#include <qt/receiverequestdialog.h>
#include <qt/recentrequeststablemodel.h>
#include <qt/sendcoinsdialog.h>
#include <qt/sendcoinsentry.h>
#include <qt/transactiontablemodel.h>
#include <qt/walletmodel.h>
#include <validation.h>
#include <wallet/wallet.h>

#include <test/test_bitcoin.h>

#include <QAbstractButton>
#include <QApplication>
#include <QDialogButtonBox>
#include <QListView>
#include <QPushButton>
#include <QTextEdit>
#include <QTimer>
#include <QVBoxLayout>

namespace {
//! Press "Yes" or "Cancel" buttons in modal send confirmation dialog.
void ConfirmSend(QString *text = nullptr, bool cancel = false) {
    QTimer::singleShot(0, Qt::PreciseTimer, [text, cancel]() {
        for (QWidget *widget : QApplication::topLevelWidgets()) {
            if (widget->inherits("SendConfirmationDialog")) {
                SendConfirmationDialog *dialog =
                    qobject_cast<SendConfirmationDialog *>(widget);
                if (text) {
                    *text = dialog->text();
                }
                QAbstractButton *button = dialog->button(
                    cancel ? QMessageBox::Cancel : QMessageBox::Yes);
                button->setEnabled(true);
                button->click();
            }
        }
    });
}

//! Send coins to address and return txid.
TxId SendCoins(CWallet &wallet, SendCoinsDialog &sendCoinsDialog,
               const CTxDestination &address, Amount amount) {
    QVBoxLayout *entries = sendCoinsDialog.findChild<QVBoxLayout *>("entries");
    SendCoinsEntry *entry =
        qobject_cast<SendCoinsEntry *>(entries->itemAt(0)->widget());
    entry->findChild<QValidatedLineEdit *>("payTo")->setText(
        QString::fromStdString(EncodeCashAddr(address, Params())));
    entry->findChild<BitcoinAmountField *>("payAmount")->setValue(amount);
    TxId txid;
    boost::signals2::scoped_connection c =
        wallet.NotifyTransactionChanged.connect(
            [&txid](CWallet *, const TxId &hash, ChangeType status) {
                if (status == CT_NEW) {
                    txid = hash;
                }
            });
    ConfirmSend();
    QMetaObject::invokeMethod(&sendCoinsDialog, "on_sendButton_clicked");
    return txid;
}

//! Find index of txid in transaction list.
QModelIndex FindTx(const QAbstractItemModel &model, const uint256 &txid) {
    QString hash = QString::fromStdString(txid.ToString());
    int rows = model.rowCount({});
    for (int row = 0; row < rows; ++row) {
        QModelIndex index = model.index(row, 0, {});
        if (model.data(index, TransactionTableModel::TxHashRole) == hash) {
            return index;
        }
    }
    return {};
}

//! Simple qt wallet tests.
//
// Test widgets can be debugged interactively calling show() on them and
// manually running the event loop, e.g.:
//
//     sendCoinsDialog.show();
//     QEventLoop().exec();
//
// This also requires overriding the default minimal Qt platform:
//
//     src/qt/test/test_bitcoin-qt -platform xcb      # Linux
//     src/qt/test/test_bitcoin-qt -platform windows  # Windows
//     src/qt/test/test_bitcoin-qt -platform cocoa    # macOS
void TestGUI() {
    // Set up wallet and chain with 105 blocks (5 mature blocks for spending).
    TestChain100Setup test;
    for (int i = 0; i < 5; ++i) {
        test.CreateAndProcessBlock(
            {}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey()));
    }
    CWallet wallet(Params(), "mock", WalletDatabase::CreateMock());
    bool firstRun;
    wallet.LoadWallet(firstRun);
    {
        LOCK(wallet.cs_wallet);
        wallet.SetAddressBook(
            GetDestinationForKey(test.coinbaseKey.GetPubKey(),
                                 wallet.m_default_address_type),
            "", "receive");
        wallet.AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey());
    }
    {
        LOCK(cs_main);
        WalletRescanReserver reserver(&wallet);
        reserver.reserve();
        wallet.ScanForWalletTransactions(chainActive.Genesis(), nullptr,
                                         reserver, true);
    }
    wallet.SetBroadcastTransactions(true);

    // Create widgets for sending coins and listing transactions.
    std::unique_ptr<const PlatformStyle> platformStyle(
        PlatformStyle::instantiate("other"));
    auto node = interfaces::MakeNode();
    OptionsModel optionsModel(*node);
    AddWallet(&wallet);
    WalletModel walletModel(std::move(node->getWallets().back()), *node,
                            platformStyle.get(), &optionsModel);
    RemoveWallet(&wallet);

    // Send two transactions, and verify they are added to transaction list.
    SendCoinsDialog sendCoinsDialog(platformStyle.get(), &walletModel);
    TransactionTableModel *transactionTableModel =
        walletModel.getTransactionTableModel();
    QCOMPARE(transactionTableModel->rowCount({}), 105);
    TxId txid1 =
        SendCoins(wallet, sendCoinsDialog, CTxDestination(CKeyID()), 5 * COIN);
    TxId txid2 =
        SendCoins(wallet, sendCoinsDialog, CTxDestination(CKeyID()), 10 * COIN);
    QCOMPARE(transactionTableModel->rowCount({}), 107);
    QVERIFY(FindTx(*transactionTableModel, txid1).isValid());
    QVERIFY(FindTx(*transactionTableModel, txid2).isValid());

    // Check current balance on OverviewPage
    OverviewPage overviewPage(platformStyle.get());
    overviewPage.setWalletModel(&walletModel);
    QLabel *balanceLabel = overviewPage.findChild<QLabel *>("labelBalance");
    QString balanceText = balanceLabel->text();
    int unit = walletModel.getOptionsModel()->getDisplayUnit();
    Amount balance = walletModel.wallet().getBalance();
    QString balanceComparison = BitcoinUnits::formatWithUnit(
        unit, balance, false, BitcoinUnits::separatorAlways);
    QCOMPARE(balanceText, balanceComparison);

    // Check Request Payment button
    ReceiveCoinsDialog receiveCoinsDialog(platformStyle.get());
    receiveCoinsDialog.setModel(&walletModel);
    RecentRequestsTableModel *requestTableModel =
        walletModel.getRecentRequestsTableModel();

    // Label input
    QLineEdit *labelInput =
        receiveCoinsDialog.findChild<QLineEdit *>("reqLabel");
    labelInput->setText("TEST_LABEL_1");

    // Amount input
    BitcoinAmountField *amountInput =
        receiveCoinsDialog.findChild<BitcoinAmountField *>("reqAmount");
    amountInput->setValue(1 * SATOSHI);

    // Message input
    QLineEdit *messageInput =
        receiveCoinsDialog.findChild<QLineEdit *>("reqMessage");
    messageInput->setText("TEST_MESSAGE_1");
    int initialRowCount = requestTableModel->rowCount({});
    QPushButton *requestPaymentButton =
        receiveCoinsDialog.findChild<QPushButton *>("receiveButton");
    requestPaymentButton->click();
    for (QWidget *widget : QApplication::topLevelWidgets()) {
        if (widget->inherits("ReceiveRequestDialog")) {
            ReceiveRequestDialog *receiveRequestDialog =
                qobject_cast<ReceiveRequestDialog *>(widget);
            QTextEdit *rlist =
                receiveRequestDialog->QObject::findChild<QTextEdit *>("outUri");
            QString paymentText = rlist->toPlainText();
            QStringList paymentTextList = paymentText.split('\n');
            QCOMPARE(paymentTextList.at(0), QString("Payment information"));
            QVERIFY(paymentTextList.at(1).indexOf(QString("URI: bchreg:")) !=
                    -1);
            QVERIFY(paymentTextList.at(2).indexOf(QString("Address:")) != -1);
            QCOMPARE(paymentTextList.at(3),
                     QString("Amount: 0.00000001 ") +
                         QString::fromStdString(CURRENCY_UNIT));
            QCOMPARE(paymentTextList.at(4), QString("Label: TEST_LABEL_1"));
            QCOMPARE(paymentTextList.at(5), QString("Message: TEST_MESSAGE_1"));
        }
    }

    // Clear button
    QPushButton *clearButton =
        receiveCoinsDialog.findChild<QPushButton *>("clearButton");
    clearButton->click();
    QCOMPARE(labelInput->text(), QString(""));
    QCOMPARE(amountInput->value(), Amount::zero());
    QCOMPARE(messageInput->text(), QString(""));

    // Check addition to history
    int currentRowCount = requestTableModel->rowCount({});
    QCOMPARE(currentRowCount, initialRowCount + 1);

    // Check Remove button
    QTableView *table =
        receiveCoinsDialog.findChild<QTableView *>("recentRequestsView");
    table->selectRow(currentRowCount - 1);
    QPushButton *removeRequestButton =
        receiveCoinsDialog.findChild<QPushButton *>("removeRequestButton");
    removeRequestButton->click();
    QCOMPARE(requestTableModel->rowCount({}), currentRowCount - 1);
}

} // namespace

void WalletTests::walletTests() {
#ifdef Q_OS_MAC
    if (QApplication::platformName() == "minimal") {
        // Disable for mac on "minimal" platform to avoid crashes inside the Qt
        // framework when it tries to look up unimplemented cocoa functions,
        // and fails to handle returned nulls
        // (https://bugreports.qt.io/browse/QTBUG-49686).
        QWARN("Skipping WalletTests on mac build with 'minimal' platform set "
              "due to Qt bugs. To run AppTests, invoke with 'test_bitcoin-qt "
              "-platform cocoa' on mac, or else use a linux or windows build.");
        return;
    }
#endif
    TestGUI();
}
<|endoftext|>


<commit_before>#include "bussignalitem.h"

#include <QString>

QVariant tin::Bus_signal_item::data(int column) const
{
  switch (column) {
    case 0: return bus_signal_.signal_def ? QString::fromStdString(bus_signal_.signal_def->name)
        : QVariant{};
  }

  return QVariant{};
}
<commit_msg>Add signal raw value<commit_after>#include "bussignalitem.h"

#include <cstdint>
#include <QString>

QVariant tin::Bus_signal_item::data(int column) const
{
  switch (column) {
    case 0: return QString::fromStdString(bus_signal_->signal_def->name);
    case 3:
      if (std::holds_alternative<std::uint64_t>(bus_signal_->raw))
        return std::get<std::uint64_t>(bus_signal_->raw);
      return std::get<std::int64_t>(bus_signal_->raw);
  }

  return QVariant{};
}
<|endoftext|>


<commit_before>/*
 * This file is part of the UnTech Editor Suite.
 * Copyright (c) 2016 - 2020, Marcus Rowe <undisbeliever@gmail.com>.
 * Distributed under The MIT License: https://opensource.org/licenses/MIT
 */

#include "string.h"
#include <fstream>
#include <string>

using namespace UnTech;

bool String::checkUtf8WellFormed(const std::string& str)
{
    const unsigned char* c = (const unsigned char*)str.c_str();
    size_t length = 0;

    if (str.empty()) {
        return true;
    }

    while (*c) {
        // Code based off The Unicode 7.0 Standard
        // Table 3-7. *Well-Formed UTF-8 Byte Sequences*

        if (c[0] <= 0x7F) {
            c++;
            length++;
        }
        else if ((c[0] >= 0xC2 && c[0] <= 0xDF)
                 && (c[1] >= 0x80 && c[1] <= 0xBF)) {
            c += 2;
            length += 2;
        }
        else if (c[0] == 0xE0
                 && (c[1] >= 0xA0 && c[1] <= 0xBF)
                 && (c[2] >= 0x80 && c[2] <= 0xBF)) {
            c += 3;
            length += 3;
        }
        else if ((c[0] == 0xE1 && c[0] <= 0xEC)
                 && (c[1] >= 0x80 && c[1] <= 0xBF)
                 && (c[2] >= 0x80 && c[2] <= 0xBF)) {
            c += 3;
            length += 3;
        }
        else if (c[0] == 0xED
                 && (c[1] >= 0x80 && c[1] <= 0x9F)
                 && (c[2] >= 0x80 && c[2] <= 0xBF)) {
            c += 3;
            length += 3;
        }
        else if ((c[0] >= 0xEE && c[0] <= 0xEF)
                 && (c[1] >= 0x80 && c[1] <= 0xBF)
                 && (c[2] >= 0x80 && c[2] <= 0xBF)) {
            c += 3;
            length += 3;
        }
        else if (c[0] == 0xF0
                 && (c[1] >= 0x90 && c[1] <= 0xBF)
                 && (c[2] >= 0x80 && c[2] <= 0xBF)
                 && (c[3] >= 0x80 && c[3] <= 0xBF)) {
            c += 4;
            length += 4;
        }
        else if ((c[0] >= 0xF1 && c[0] <= 0xF3)
                 && (c[1] >= 0x80 && c[1] <= 0xBF)
                 && (c[2] >= 0x80 && c[2] <= 0xBF)
                 && (c[3] >= 0x80 && c[3] <= 0xBF)) {
            c += 4;
            length += 4;
        }
        else if (c[0] == 0xF4
                 && (c[1] >= 0x80 && c[1] <= 0x8F)
                 && (c[2] >= 0x80 && c[2] <= 0xBF)
                 && (c[3] >= 0x80 && c[3] <= 0xBF)) {
            c += 4;
            length += 4;
        }
        else {
            return false;
        }
    }

    return length == str.size();
}
<commit_msg>Fix String::checkUtf8WellFormed<commit_after>/*
 * This file is part of the UnTech Editor Suite.
 * Copyright (c) 2016 - 2020, Marcus Rowe <undisbeliever@gmail.com>.
 * Distributed under The MIT License: https://opensource.org/licenses/MIT
 */

#include "string.h"
#include <fstream>
#include <string>

using namespace UnTech;

bool String::checkUtf8WellFormed(const std::string& str)
{
    const unsigned char* c = (const unsigned char*)str.c_str();
    size_t length = 0;

    if (str.empty()) {
        return true;
    }

    while (*c) {
        // Code based off The Unicode 7.0 Standard
        // Table 3-7. *Well-Formed UTF-8 Byte Sequences*

        if (c[0] <= 0x7F) {
            c++;
            length++;
        }
        else if ((c[0] >= 0xC2 && c[0] <= 0xDF)
                 && (c[1] >= 0x80 && c[1] <= 0xBF)) {
            c += 2;
            length += 2;
        }
        else if (c[0] == 0xE0
                 && (c[1] >= 0xA0 && c[1] <= 0xBF)
                 && (c[2] >= 0x80 && c[2] <= 0xBF)) {
            c += 3;
            length += 3;
        }
        else if ((c[0] >= 0xE1 && c[0] <= 0xEC)
                 && (c[1] >= 0x80 && c[1] <= 0xBF)
                 && (c[2] >= 0x80 && c[2] <= 0xBF)) {
            c += 3;
            length += 3;
        }
        else if (c[0] == 0xED
                 && (c[1] >= 0x80 && c[1] <= 0x9F)
                 && (c[2] >= 0x80 && c[2] <= 0xBF)) {
            c += 3;
            length += 3;
        }
        else if ((c[0] >= 0xEE && c[0] <= 0xEF)
                 && (c[1] >= 0x80 && c[1] <= 0xBF)
                 && (c[2] >= 0x80 && c[2] <= 0xBF)) {
            c += 3;
            length += 3;
        }
        else if (c[0] == 0xF0
                 && (c[1] >= 0x90 && c[1] <= 0xBF)
                 && (c[2] >= 0x80 && c[2] <= 0xBF)
                 && (c[3] >= 0x80 && c[3] <= 0xBF)) {
            c += 4;
            length += 4;
        }
        else if ((c[0] >= 0xF1 && c[0] <= 0xF3)
                 && (c[1] >= 0x80 && c[1] <= 0xBF)
                 && (c[2] >= 0x80 && c[2] <= 0xBF)
                 && (c[3] >= 0x80 && c[3] <= 0xBF)) {
            c += 4;
            length += 4;
        }
        else if (c[0] == 0xF4
                 && (c[1] >= 0x80 && c[1] <= 0x8F)
                 && (c[2] >= 0x80 && c[2] <= 0xBF)
                 && (c[3] >= 0x80 && c[3] <= 0xBF)) {
            c += 4;
            length += 4;
        }
        else {
            return false;
        }
    }

    return length == str.size();
}
<|endoftext|>


<commit_before>//===------------------------- chrono.cpp ---------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#define _LIBCPP_BUILDING_CHRONO
#include "chrono"
#include "cerrno"        // errno
#include "system_error"  // __throw_system_error
#include <time.h>        // clock_gettime, CLOCK_MONOTONIC and CLOCK_REALTIME

#if !defined(CLOCK_REALTIME)
#include <sys/time.h>        // for gettimeofday and timeval
#endif

#if !defined(_LIBCPP_HAS_NO_MONOTONIC_CLOCK) && !defined(CLOCK_MONOTONIC)
#if __APPLE__
#include <mach/mach_time.h>  // mach_absolute_time, mach_timebase_info_data_t
#else
#error "Monotonic clock not implemented"
#endif
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

namespace chrono
{

// system_clock

const bool system_clock::is_steady;
// Make is_steady non-discardable in C++17
// See PR28395 (https://llvm.org/bugs/show_bug.cgi?id=28395)
static const bool& __is_steady_force_use1 __attribute__((used)) = system_clock::is_steady;

system_clock::time_point
system_clock::now() _NOEXCEPT
{
#ifdef CLOCK_REALTIME
    struct timespec tp;
    if (0 != clock_gettime(CLOCK_REALTIME, &tp))
        __throw_system_error(errno, "clock_gettime(CLOCK_REALTIME) failed");
    return time_point(seconds(tp.tv_sec) + microseconds(tp.tv_nsec / 1000));
#else  // !CLOCK_REALTIME
    timeval tv;
    gettimeofday(&tv, 0);
    return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec));
#endif  // CLOCK_REALTIME
}

time_t
system_clock::to_time_t(const time_point& t) _NOEXCEPT
{
    return time_t(duration_cast<seconds>(t.time_since_epoch()).count());
}

system_clock::time_point
system_clock::from_time_t(time_t t) _NOEXCEPT
{
    return system_clock::time_point(seconds(t));
}

#ifndef _LIBCPP_HAS_NO_MONOTONIC_CLOCK
// steady_clock
//
// Warning:  If this is not truly steady, then it is non-conforming.  It is
//  better for it to not exist and have the rest of libc++ use system_clock
//  instead.

const bool steady_clock::is_steady;
// Make is_steady non-discardable in C++17
// See PR28395 (https://llvm.org/bugs/show_bug.cgi?id=28395)
static const bool& __is_steady_force_use2 __attribute__((used)) = steady_clock::is_steady;

#ifdef CLOCK_MONOTONIC

steady_clock::time_point
steady_clock::now() _NOEXCEPT
{
    struct timespec tp;
    if (0 != clock_gettime(CLOCK_MONOTONIC, &tp))
        __throw_system_error(errno, "clock_gettime(CLOCK_MONOTONIC) failed");
    return time_point(seconds(tp.tv_sec) + nanoseconds(tp.tv_nsec));
}

#elif defined(__APPLE__)

//   mach_absolute_time() * MachInfo.numer / MachInfo.denom is the number of
//   nanoseconds since the computer booted up.  MachInfo.numer and MachInfo.denom
//   are run time constants supplied by the OS.  This clock has no relationship
//   to the Gregorian calendar.  It's main use is as a high resolution timer.

// MachInfo.numer / MachInfo.denom is often 1 on the latest equipment.  Specialize
//   for that case as an optimization.

#pragma GCC visibility push(hidden)

static
steady_clock::rep
steady_simplified()
{
    return static_cast<steady_clock::rep>(mach_absolute_time());
}

static
double
compute_steady_factor()
{
    mach_timebase_info_data_t MachInfo;
    mach_timebase_info(&MachInfo);
    return static_cast<double>(MachInfo.numer) / MachInfo.denom;
}

static
steady_clock::rep
steady_full()
{
    static const double factor = compute_steady_factor();
    return static_cast<steady_clock::rep>(mach_absolute_time() * factor);
}

typedef steady_clock::rep (*FP)();

static
FP
init_steady_clock()
{
    mach_timebase_info_data_t MachInfo;
    mach_timebase_info(&MachInfo);
    if (MachInfo.numer == MachInfo.denom)
        return &steady_simplified;
    return &steady_full;
}

#pragma GCC visibility pop

steady_clock::time_point
steady_clock::now() _NOEXCEPT
{
    static FP fp = init_steady_clock();
    return time_point(duration(fp()));
}

#else
#error "Monotonic clock not implemented"
#endif

#endif // !_LIBCPP_HAS_NO_MONOTONIC_CLOCK

}

_LIBCPP_END_NAMESPACE_STD
<commit_msg>Remove accidental change committed in r274403.<commit_after>//===------------------------- chrono.cpp ---------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "chrono"
#include "cerrno"        // errno
#include "system_error"  // __throw_system_error
#include <time.h>        // clock_gettime, CLOCK_MONOTONIC and CLOCK_REALTIME

#if !defined(CLOCK_REALTIME)
#include <sys/time.h>        // for gettimeofday and timeval
#endif

#if !defined(_LIBCPP_HAS_NO_MONOTONIC_CLOCK) && !defined(CLOCK_MONOTONIC)
#if __APPLE__
#include <mach/mach_time.h>  // mach_absolute_time, mach_timebase_info_data_t
#else
#error "Monotonic clock not implemented"
#endif
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

namespace chrono
{

// system_clock

const bool system_clock::is_steady;
// Make is_steady non-discardable in C++17
// See PR28395 (https://llvm.org/bugs/show_bug.cgi?id=28395)
static const bool& __is_steady_force_use1 __attribute__((used)) = system_clock::is_steady;

system_clock::time_point
system_clock::now() _NOEXCEPT
{
#ifdef CLOCK_REALTIME
    struct timespec tp;
    if (0 != clock_gettime(CLOCK_REALTIME, &tp))
        __throw_system_error(errno, "clock_gettime(CLOCK_REALTIME) failed");
    return time_point(seconds(tp.tv_sec) + microseconds(tp.tv_nsec / 1000));
#else  // !CLOCK_REALTIME
    timeval tv;
    gettimeofday(&tv, 0);
    return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec));
#endif  // CLOCK_REALTIME
}

time_t
system_clock::to_time_t(const time_point& t) _NOEXCEPT
{
    return time_t(duration_cast<seconds>(t.time_since_epoch()).count());
}

system_clock::time_point
system_clock::from_time_t(time_t t) _NOEXCEPT
{
    return system_clock::time_point(seconds(t));
}

#ifndef _LIBCPP_HAS_NO_MONOTONIC_CLOCK
// steady_clock
//
// Warning:  If this is not truly steady, then it is non-conforming.  It is
//  better for it to not exist and have the rest of libc++ use system_clock
//  instead.

const bool steady_clock::is_steady;
// Make is_steady non-discardable in C++17
// See PR28395 (https://llvm.org/bugs/show_bug.cgi?id=28395)
static const bool& __is_steady_force_use2 __attribute__((used)) = steady_clock::is_steady;

#ifdef CLOCK_MONOTONIC

steady_clock::time_point
steady_clock::now() _NOEXCEPT
{
    struct timespec tp;
    if (0 != clock_gettime(CLOCK_MONOTONIC, &tp))
        __throw_system_error(errno, "clock_gettime(CLOCK_MONOTONIC) failed");
    return time_point(seconds(tp.tv_sec) + nanoseconds(tp.tv_nsec));
}

#elif defined(__APPLE__)

//   mach_absolute_time() * MachInfo.numer / MachInfo.denom is the number of
//   nanoseconds since the computer booted up.  MachInfo.numer and MachInfo.denom
//   are run time constants supplied by the OS.  This clock has no relationship
//   to the Gregorian calendar.  It's main use is as a high resolution timer.

// MachInfo.numer / MachInfo.denom is often 1 on the latest equipment.  Specialize
//   for that case as an optimization.

#pragma GCC visibility push(hidden)

static
steady_clock::rep
steady_simplified()
{
    return static_cast<steady_clock::rep>(mach_absolute_time());
}

static
double
compute_steady_factor()
{
    mach_timebase_info_data_t MachInfo;
    mach_timebase_info(&MachInfo);
    return static_cast<double>(MachInfo.numer) / MachInfo.denom;
}

static
steady_clock::rep
steady_full()
{
    static const double factor = compute_steady_factor();
    return static_cast<steady_clock::rep>(mach_absolute_time() * factor);
}

typedef steady_clock::rep (*FP)();

static
FP
init_steady_clock()
{
    mach_timebase_info_data_t MachInfo;
    mach_timebase_info(&MachInfo);
    if (MachInfo.numer == MachInfo.denom)
        return &steady_simplified;
    return &steady_full;
}

#pragma GCC visibility pop

steady_clock::time_point
steady_clock::now() _NOEXCEPT
{
    static FP fp = init_steady_clock();
    return time_point(duration(fp()));
}

#else
#error "Monotonic clock not implemented"
#endif

#endif // !_LIBCPP_HAS_NO_MONOTONIC_CLOCK

}

_LIBCPP_END_NAMESPACE_STD
<|endoftext|>


<commit_before>#include "rdb_protocol/profile.hpp"

#include <inttypes.h>

#include <limits>

#include "errors.hpp"
#include <boost/variant/static_visitor.hpp>

#include "containers/archive/stl_types.hpp"
#include "logger.hpp"
#include "rdb_protocol/math_utils.hpp"
#include "rdb_protocol/datum.hpp"
#include "rdb_protocol/env.hpp"

namespace profile {

start_t::start_t() { }

start_t::start_t(const std::string &description)
    : description_(description), when_(get_ticks()) { }

RDB_IMPL_SERIALIZABLE_2_SINCE_v1_13(start_t, description_, when_);

split_t::split_t() { }

split_t::split_t(size_t n_parallel_jobs)
    : n_parallel_jobs_(n_parallel_jobs) { }

RDB_IMPL_SERIALIZABLE_1_SINCE_v1_13(split_t, n_parallel_jobs_);

sample_t::sample_t() { }

sample_t::sample_t(const std::string &description,
        ticks_t mean_duration, size_t n_samples)
    : description_(description), mean_duration_(mean_duration),
      n_samples_(n_samples)
{ }

RDB_IMPL_SERIALIZABLE_3_SINCE_v1_13(sample_t, description_, mean_duration_, n_samples_);

stop_t::stop_t()
    : when_(get_ticks()) { }

RDB_IMPL_SERIALIZABLE_1_SINCE_v1_13(stop_t, when_);

counted_t<const ql::datum_t> construct_start(
        ticks_t duration, std::string description,
        counted_t<const ql::datum_t> sub_tasks) {
    std::map<std::string, counted_t<const ql::datum_t> > res;
    res["duration(ms)"] = make_counted<const ql::datum_t>(safe_to_double(duration) / MILLION);
    res["description"] = make_counted<const ql::datum_t>(std::move(description));
    res["sub_tasks"] = sub_tasks;
    return make_counted<const ql::datum_t>(std::move(res));
}

counted_t<const ql::datum_t> construct_split(
        counted_t<const ql::datum_t> par_tasks) {
    std::map<std::string, counted_t<const ql::datum_t> > res;
    res["parallel_tasks"] = par_tasks;
    return make_counted<const ql::datum_t>(std::move(res));
}

counted_t<const ql::datum_t> construct_sample(
        const sample_t *sample) {
    std::map<std::string, counted_t<const ql::datum_t> > res;
    double mean_duration = safe_to_double(sample->mean_duration_) / MILLION;
    double n_samples = safe_to_double(sample->n_samples_);
    res["mean_duration(ms)"] = make_counted<const ql::datum_t>(mean_duration);
    res["n_samples"] = make_counted<const ql::datum_t>(n_samples);
    res["description"] = make_counted<const ql::datum_t>(std::string(sample->description_));
    return make_counted<const ql::datum_t>(std::move(res));
}

counted_t<const ql::datum_t> construct_datum(
        event_log_t::const_iterator *begin,
        event_log_t::const_iterator end,
        const ql::configured_limits_t &limits);

class construct_datum_visitor_t : public boost::static_visitor<void> {
public:
    construct_datum_visitor_t(
        event_log_t::const_iterator *begin, event_log_t::const_iterator end,
        const ql::configured_limits_t &limits,
        std::vector<counted_t<const ql::datum_t> > *res)
        : begin_(begin), end_(end), limits_(limits), res_(res) { }

    void operator()(const start_t &start) const {
        (*begin_)++;
        counted_t<const ql::datum_t> sub_tasks = construct_datum(begin_, end_, limits_);
        auto stop = boost::get<stop_t>(&**begin_);
        guarantee(stop);
        res_->push_back(construct_start(
            stop->when_ - start.when_, start.description_, sub_tasks));
        (*begin_)++;
    }
    void operator()(const split_t &split) const {
        (*begin_)++;
        std::vector<counted_t<const ql::datum_t> > parallel_tasks;
        for (size_t i = 0; i < split.n_parallel_jobs_; ++i) {
            parallel_tasks.push_back(construct_datum(begin_, end_, limits_));
            guarantee(boost::get<stop_t>(&**begin_));
            (*begin_)++;
        }
        res_->push_back(construct_split(
            make_counted<const ql::datum_t>(std::move(parallel_tasks), limits_)));
    }
    void operator()(const sample_t &sample) const {
        (*begin_)++;
        res_->push_back(construct_sample(&sample));
    }
    void operator()(const stop_t &) const {
        //Nothing to do here
    }

private:
    event_log_t::const_iterator *begin_;
    event_log_t::const_iterator end_;
    const ql::configured_limits_t &limits_;
    std::vector<counted_t<const ql::datum_t> > *res_;
};

counted_t<const ql::datum_t> construct_datum(
        event_log_t::const_iterator *begin,
        event_log_t::const_iterator end,
        const ql::configured_limits_t &limits) {
    std::vector<counted_t<const ql::datum_t> > res;

    construct_datum_visitor_t visitor(begin, end, limits, &res);
    while (*begin != end && !boost::get<stop_t>(&**begin)) {
        boost::apply_visitor(visitor, **begin);
    }

    return make_counted<const ql::datum_t>(std::move(res), limits);
}

class print_event_log_visitor_t : public boost::static_visitor<void> {
public:
    void operator()(const start_t &start) const {
        logINF("Start: %s.\n", start.description_.c_str());
    }
    void operator()(const split_t &split) const {
        logINF("Split: %zu.\n", split.n_parallel_jobs_);
    }
    void operator()(const sample_t &) const {
        logINF("Sample.");
    }
    void operator()(const stop_t &) const {
        logINF("Stop.\n");
    }
};

void print_event_log(const event_log_t &event_log) {
    print_event_log_visitor_t visitor;
    for (auto it = event_log.begin(); it != event_log.end(); ++it) {
        boost::apply_visitor(visitor, *it);
    }
}

starter_t::starter_t(const std::string &description, trace_t *parent) {
    init(description, parent);
}

starter_t::starter_t(const std::string &description, const scoped_ptr_t<trace_t> &parent) {
    init(description, parent.get_or_null());
}

starter_t::~starter_t() {
    if (parent_) {
        parent_->stop();
    }
}

void starter_t::init(const std::string &description, trace_t *parent) {
    parent_ = parent;
    if (parent_) {
        parent_->start(description);
    }
}

splitter_t::splitter_t(trace_t *parent) {
    init(parent);
}

splitter_t::splitter_t(const scoped_ptr_t<trace_t> &parent) {
    init(parent.get_or_null());
}

void splitter_t::give_splits(
    size_t n_parallel_jobs, const event_log_t &event_log) {
    n_parallel_jobs_ = n_parallel_jobs;
    event_log_ = event_log;
}

splitter_t::~splitter_t() {
    if (parent_) {
        parent_->stop_split(n_parallel_jobs_, event_log_);
    }
}

void splitter_t::init(trace_t *parent) {
    parent_ = parent;
    n_parallel_jobs_ = 0;

    if (parent_) {
        parent_->start_split();
    }
}

sampler_t::sampler_t(const std::string &description, trace_t *parent) {
    init(description, parent);
}

sampler_t::sampler_t(const std::string &description, const scoped_ptr_t<trace_t> &parent) {
    init(description, parent.get_or_null());
}

void sampler_t::init(const std::string &description, trace_t *parent) {
    parent_ = parent;
    description_ = description;
    total_time_ = 0;
    n_samples_ = 0;
    if (parent_) {
        parent_->start_sample(&event_log_);
    }
}

ticks_t duration(const event_log_t &event_log) {
    guarantee(!event_log.empty());
    if (auto start = boost::get<start_t>(&event_log.at(0))) {
        auto stop = boost::get<stop_t>(&event_log.back());
        guarantee(stop);
        return stop->when_ - start->when_;
    } else {
        //This is a code path that is currently never hit and that will go a
        //way when we implement more meaningful sampling functions.
        return 0;
    }
}

void sampler_t::new_sample() {
    if (!event_log_.empty()) {
        n_samples_++;
        total_time_ += duration(event_log_);
    }

    event_log_.clear();
}

sampler_t::~sampler_t() {
    new_sample();
    if (parent_) {
        if (n_samples_ > 0) {
            parent_->stop_sample(description_, total_time_ / n_samples_, n_samples_, &event_log_);
        } else {
            parent_->stop_sample(&event_log_);
        }
    }
}

disabler_t::disabler_t(trace_t *parent) {
    init(parent);
}

disabler_t::disabler_t(const scoped_ptr_t<trace_t> &parent) {
    init(parent.get_or_null());
}

disabler_t::~disabler_t() {
    if (parent_) {
        parent_->enable();
    }
}

void disabler_t::init(trace_t *parent) {
    parent_ = parent;
    if (parent_) {
        parent_->disable();
    }
}

trace_t::trace_t()
    : redirected_event_log_(NULL), disabled_ref_count_(0) { }

counted_t<const ql::datum_t> trace_t::as_datum() const {
    guarantee(!redirected_event_log_);
    event_log_t::const_iterator begin = event_log_.begin();
    ql::configured_limits_t limits;
    return construct_datum(&begin, event_log_.end(), limits);
}

event_log_t trace_t::extract_event_log() RVALUE_THIS {
    // These guarantees imply that this trace_t gets left in a default-constructed
    // state (which is valid, thereby acceptable for an RVALUE_THIS function).
    guarantee(redirected_event_log_ == NULL);
    guarantee(disabled_ref_count_ == 0);
    return std::move(event_log_);
}

void trace_t::start(const std::string &description) {
    if (disabled()) { return; }
    //debugf("Start %s %p.\n", description.c_str(), this);
    event_log_target()->push_back(start_t(description));
}

void trace_t::stop() {
    if (disabled()) { return; }
    //debugf("Stop %p.\n", this);
    event_log_target()->push_back(stop_t());
}

void trace_t::start_split() {
    if (disabled()) { return; }
    //debugf("Start split %p.\n", this);
    event_log_target()->push_back(split_t());
}

void trace_t::stop_split(size_t n_parallel_jobs_, const event_log_t &par_event_log) {
    if (disabled()) { return; }
    //debugf("Stop split %zu, %p.\n", n_parallel_jobs_, this);
    auto split = boost::get<split_t>(&event_log_target()->back());
    guarantee(split);
    split->n_parallel_jobs_ = n_parallel_jobs_;
    event_log_target()->insert(event_log_target()->end(), par_event_log.begin(), par_event_log.end());
}

void trace_t::start_sample(event_log_t *event_log) {
    if (disabled()) { return; }
    //debugf("Start sample %p.\n", this);
    /* This is a tad hacky. We currently don't  allow samples within samples.
     * And if someone tries to do it the inner sample winds up just being a
     * no-op. We should see if in practice this is something we actually want
     * to support. */
    if (!redirected_event_log_) {
        redirected_event_log_ = event_log;
    }
}

void trace_t::stop_sample(const std::string &description,
        ticks_t mean_duration, size_t n_samples, event_log_t *event_log) {
    if (disabled()) { return; }
    //debugf("Stop sample %s, %p.\n", description.c_str(), this);
    /* Don't reset the redirected_event_log_ if the sampler_t wasn't
     * actually being redirected to. The predicate fails when the
     * innter samplers in nested sampler_ts are destructed. */
    if (event_log == redirected_event_log_) {
        redirected_event_log_ = NULL;
    }
    event_log_target()->push_back(sample_t(description, mean_duration, n_samples));
}

void trace_t::stop_sample(event_log_t *event_log) {
    if (disabled()) { return; }
    //debugf("Stop sample %p.\n", this);
    /* Don't reset the redirected_event_log_ if the sampler_t wasn't
     * actually being redirected to. The predicate fails when the
     * innter samplers in nested sampler_ts are destructed. */
    if (event_log == redirected_event_log_) {
        redirected_event_log_ = NULL;
    }
}

void trace_t::disable() {
    disabled_ref_count_++;
}
void trace_t::enable() {
    disabled_ref_count_--;
}

bool trace_t::disabled() {
    return disabled_ref_count_ > 0;
}

event_log_t *trace_t::event_log_target() {
    if (redirected_event_log_) {
        return redirected_event_log_;
    } else {
        return &event_log_;
    }
}

} //namespace profile
<commit_msg>Add explanatory comment.<commit_after>#include "rdb_protocol/profile.hpp"

#include <inttypes.h>

#include <limits>

#include "errors.hpp"
#include <boost/variant/static_visitor.hpp>

#include "containers/archive/stl_types.hpp"
#include "logger.hpp"
#include "rdb_protocol/math_utils.hpp"
#include "rdb_protocol/datum.hpp"
#include "rdb_protocol/env.hpp"

namespace profile {

start_t::start_t() { }

start_t::start_t(const std::string &description)
    : description_(description), when_(get_ticks()) { }

RDB_IMPL_SERIALIZABLE_2_SINCE_v1_13(start_t, description_, when_);

split_t::split_t() { }

split_t::split_t(size_t n_parallel_jobs)
    : n_parallel_jobs_(n_parallel_jobs) { }

RDB_IMPL_SERIALIZABLE_1_SINCE_v1_13(split_t, n_parallel_jobs_);

sample_t::sample_t() { }

sample_t::sample_t(const std::string &description,
        ticks_t mean_duration, size_t n_samples)
    : description_(description), mean_duration_(mean_duration),
      n_samples_(n_samples)
{ }

RDB_IMPL_SERIALIZABLE_3_SINCE_v1_13(sample_t, description_, mean_duration_, n_samples_);

stop_t::stop_t()
    : when_(get_ticks()) { }

RDB_IMPL_SERIALIZABLE_1_SINCE_v1_13(stop_t, when_);

counted_t<const ql::datum_t> construct_start(
        ticks_t duration, std::string description,
        counted_t<const ql::datum_t> sub_tasks) {
    std::map<std::string, counted_t<const ql::datum_t> > res;
    res["duration(ms)"] = make_counted<const ql::datum_t>(safe_to_double(duration) / MILLION);
    res["description"] = make_counted<const ql::datum_t>(std::move(description));
    res["sub_tasks"] = sub_tasks;
    return make_counted<const ql::datum_t>(std::move(res));
}

counted_t<const ql::datum_t> construct_split(
        counted_t<const ql::datum_t> par_tasks) {
    std::map<std::string, counted_t<const ql::datum_t> > res;
    res["parallel_tasks"] = par_tasks;
    return make_counted<const ql::datum_t>(std::move(res));
}

counted_t<const ql::datum_t> construct_sample(
        const sample_t *sample) {
    std::map<std::string, counted_t<const ql::datum_t> > res;
    double mean_duration = safe_to_double(sample->mean_duration_) / MILLION;
    double n_samples = safe_to_double(sample->n_samples_);
    res["mean_duration(ms)"] = make_counted<const ql::datum_t>(mean_duration);
    res["n_samples"] = make_counted<const ql::datum_t>(n_samples);
    res["description"] = make_counted<const ql::datum_t>(std::string(sample->description_));
    return make_counted<const ql::datum_t>(std::move(res));
}

counted_t<const ql::datum_t> construct_datum(
        event_log_t::const_iterator *begin,
        event_log_t::const_iterator end,
        const ql::configured_limits_t &limits);

class construct_datum_visitor_t : public boost::static_visitor<void> {
public:
    construct_datum_visitor_t(
        event_log_t::const_iterator *begin, event_log_t::const_iterator end,
        const ql::configured_limits_t &limits,
        std::vector<counted_t<const ql::datum_t> > *res)
        : begin_(begin), end_(end), limits_(limits), res_(res) { }

    void operator()(const start_t &start) const {
        (*begin_)++;
        counted_t<const ql::datum_t> sub_tasks = construct_datum(begin_, end_, limits_);
        auto stop = boost::get<stop_t>(&**begin_);
        guarantee(stop);
        res_->push_back(construct_start(
            stop->when_ - start.when_, start.description_, sub_tasks));
        (*begin_)++;
    }
    void operator()(const split_t &split) const {
        (*begin_)++;
        std::vector<counted_t<const ql::datum_t> > parallel_tasks;
        for (size_t i = 0; i < split.n_parallel_jobs_; ++i) {
            parallel_tasks.push_back(construct_datum(begin_, end_, limits_));
            guarantee(boost::get<stop_t>(&**begin_));
            (*begin_)++;
        }
        res_->push_back(construct_split(
            make_counted<const ql::datum_t>(std::move(parallel_tasks), limits_)));
    }
    void operator()(const sample_t &sample) const {
        (*begin_)++;
        res_->push_back(construct_sample(&sample));
    }
    void operator()(const stop_t &) const {
        //Nothing to do here
    }

private:
    event_log_t::const_iterator *begin_;
    event_log_t::const_iterator end_;
    const ql::configured_limits_t &limits_;
    std::vector<counted_t<const ql::datum_t> > *res_;
};

counted_t<const ql::datum_t> construct_datum(
        event_log_t::const_iterator *begin,
        event_log_t::const_iterator end,
        const ql::configured_limits_t &limits) {
    std::vector<counted_t<const ql::datum_t> > res;

    construct_datum_visitor_t visitor(begin, end, limits, &res);
    while (*begin != end && !boost::get<stop_t>(&**begin)) {
        boost::apply_visitor(visitor, **begin);
    }

    return make_counted<const ql::datum_t>(std::move(res), limits);
}

class print_event_log_visitor_t : public boost::static_visitor<void> {
public:
    void operator()(const start_t &start) const {
        logINF("Start: %s.\n", start.description_.c_str());
    }
    void operator()(const split_t &split) const {
        logINF("Split: %zu.\n", split.n_parallel_jobs_);
    }
    void operator()(const sample_t &) const {
        logINF("Sample.");
    }
    void operator()(const stop_t &) const {
        logINF("Stop.\n");
    }
};

void print_event_log(const event_log_t &event_log) {
    print_event_log_visitor_t visitor;
    for (auto it = event_log.begin(); it != event_log.end(); ++it) {
        boost::apply_visitor(visitor, *it);
    }
}

starter_t::starter_t(const std::string &description, trace_t *parent) {
    init(description, parent);
}

starter_t::starter_t(const std::string &description, const scoped_ptr_t<trace_t> &parent) {
    init(description, parent.get_or_null());
}

starter_t::~starter_t() {
    if (parent_) {
        parent_->stop();
    }
}

void starter_t::init(const std::string &description, trace_t *parent) {
    parent_ = parent;
    if (parent_) {
        parent_->start(description);
    }
}

splitter_t::splitter_t(trace_t *parent) {
    init(parent);
}

splitter_t::splitter_t(const scoped_ptr_t<trace_t> &parent) {
    init(parent.get_or_null());
}

void splitter_t::give_splits(
    size_t n_parallel_jobs, const event_log_t &event_log) {
    n_parallel_jobs_ = n_parallel_jobs;
    event_log_ = event_log;
}

splitter_t::~splitter_t() {
    if (parent_) {
        parent_->stop_split(n_parallel_jobs_, event_log_);
    }
}

void splitter_t::init(trace_t *parent) {
    parent_ = parent;
    n_parallel_jobs_ = 0;

    if (parent_) {
        parent_->start_split();
    }
}

sampler_t::sampler_t(const std::string &description, trace_t *parent) {
    init(description, parent);
}

sampler_t::sampler_t(const std::string &description, const scoped_ptr_t<trace_t> &parent) {
    init(description, parent.get_or_null());
}

void sampler_t::init(const std::string &description, trace_t *parent) {
    parent_ = parent;
    description_ = description;
    total_time_ = 0;
    n_samples_ = 0;
    if (parent_) {
        parent_->start_sample(&event_log_);
    }
}

ticks_t duration(const event_log_t &event_log) {
    guarantee(!event_log.empty());
    if (auto start = boost::get<start_t>(&event_log.at(0))) {
        auto stop = boost::get<stop_t>(&event_log.back());
        guarantee(stop);
        return stop->when_ - start->when_;
    } else {
        //This is a code path that is currently never hit and that will go a
        //way when we implement more meaningful sampling functions.
        return 0;
    }
}

void sampler_t::new_sample() {
    if (!event_log_.empty()) {
        n_samples_++;
        total_time_ += duration(event_log_);
    }

    event_log_.clear();
}

sampler_t::~sampler_t() {
    new_sample();
    if (parent_) {
        if (n_samples_ > 0) {
            parent_->stop_sample(description_, total_time_ / n_samples_, n_samples_, &event_log_);
        } else {
            parent_->stop_sample(&event_log_);
        }
    }
}

disabler_t::disabler_t(trace_t *parent) {
    init(parent);
}

disabler_t::disabler_t(const scoped_ptr_t<trace_t> &parent) {
    init(parent.get_or_null());
}

disabler_t::~disabler_t() {
    if (parent_) {
        parent_->enable();
    }
}

void disabler_t::init(trace_t *parent) {
    parent_ = parent;
    if (parent_) {
        parent_->disable();
    }
}

trace_t::trace_t()
    : redirected_event_log_(NULL), disabled_ref_count_(0) { }

counted_t<const ql::datum_t> trace_t::as_datum() const {
    guarantee(!redirected_event_log_);
    event_log_t::const_iterator begin = event_log_.begin();
    // Again, use defaults, as there's no predicting where this could
    // come in response to user requests.
    return construct_datum(&begin, event_log_.end(),
                           ql::configured_limits_t());
}

event_log_t trace_t::extract_event_log() RVALUE_THIS {
    // These guarantees imply that this trace_t gets left in a default-constructed
    // state (which is valid, thereby acceptable for an RVALUE_THIS function).
    guarantee(redirected_event_log_ == NULL);
    guarantee(disabled_ref_count_ == 0);
    return std::move(event_log_);
}

void trace_t::start(const std::string &description) {
    if (disabled()) { return; }
    //debugf("Start %s %p.\n", description.c_str(), this);
    event_log_target()->push_back(start_t(description));
}

void trace_t::stop() {
    if (disabled()) { return; }
    //debugf("Stop %p.\n", this);
    event_log_target()->push_back(stop_t());
}

void trace_t::start_split() {
    if (disabled()) { return; }
    //debugf("Start split %p.\n", this);
    event_log_target()->push_back(split_t());
}

void trace_t::stop_split(size_t n_parallel_jobs_, const event_log_t &par_event_log) {
    if (disabled()) { return; }
    //debugf("Stop split %zu, %p.\n", n_parallel_jobs_, this);
    auto split = boost::get<split_t>(&event_log_target()->back());
    guarantee(split);
    split->n_parallel_jobs_ = n_parallel_jobs_;
    event_log_target()->insert(event_log_target()->end(), par_event_log.begin(), par_event_log.end());
}

void trace_t::start_sample(event_log_t *event_log) {
    if (disabled()) { return; }
    //debugf("Start sample %p.\n", this);
    /* This is a tad hacky. We currently don't  allow samples within samples.
     * And if someone tries to do it the inner sample winds up just being a
     * no-op. We should see if in practice this is something we actually want
     * to support. */
    if (!redirected_event_log_) {
        redirected_event_log_ = event_log;
    }
}

void trace_t::stop_sample(const std::string &description,
        ticks_t mean_duration, size_t n_samples, event_log_t *event_log) {
    if (disabled()) { return; }
    //debugf("Stop sample %s, %p.\n", description.c_str(), this);
    /* Don't reset the redirected_event_log_ if the sampler_t wasn't
     * actually being redirected to. The predicate fails when the
     * innter samplers in nested sampler_ts are destructed. */
    if (event_log == redirected_event_log_) {
        redirected_event_log_ = NULL;
    }
    event_log_target()->push_back(sample_t(description, mean_duration, n_samples));
}

void trace_t::stop_sample(event_log_t *event_log) {
    if (disabled()) { return; }
    //debugf("Stop sample %p.\n", this);
    /* Don't reset the redirected_event_log_ if the sampler_t wasn't
     * actually being redirected to. The predicate fails when the
     * innter samplers in nested sampler_ts are destructed. */
    if (event_log == redirected_event_log_) {
        redirected_event_log_ = NULL;
    }
}

void trace_t::disable() {
    disabled_ref_count_++;
}
void trace_t::enable() {
    disabled_ref_count_--;
}

bool trace_t::disabled() {
    return disabled_ref_count_ > 0;
}

event_log_t *trace_t::event_log_target() {
    if (redirected_event_log_) {
        return redirected_event_log_;
    } else {
        return &event_log_;
    }
}

} //namespace profile
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <assert.h>
#include <jni.h>

#include "webrtc/modules/audio_device/android/audio_device_template.h"
#include "webrtc/modules/audio_device/android/audio_record_jni.h"
#include "webrtc/modules/audio_device/android/audio_track_jni.h"
#include "webrtc/modules/audio_device/android/opensles_input.h"
#include "webrtc/modules/audio_device/android/opensles_output.h"
#include "webrtc/modules/audio_device/android/test/fake_audio_device_buffer.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"

// Java globals
static JavaVM* g_vm = NULL;
static jclass g_osr = NULL;

namespace webrtc {

template <class InputType, class OutputType>
class OpenSlRunnerTemplate {
 public:
  OpenSlRunnerTemplate()
      : output_(0),
        input_(0, &output_) {
    output_.AttachAudioBuffer(&audio_buffer_);
    if (output_.Init() != 0) {
      assert(false);
    }
    if (output_.InitPlayout() != 0) {
      assert(false);
    }
    input_.AttachAudioBuffer(&audio_buffer_);
    if (input_.Init() != 0) {
      assert(false);
    }
    if (input_.InitRecording() != 0) {
      assert(false);
    }
  }

  ~OpenSlRunnerTemplate() {}

  void StartPlayRecord() {
    output_.StartPlayout();
    input_.StartRecording();
  }

  void StopPlayRecord() {
    // There are large enough buffers to compensate for recording and playing
    // jitter such that the timing of stopping playing or recording should not
    // result in over or underrun.
    input_.StopRecording();
    output_.StopPlayout();
    audio_buffer_.ClearBuffer();
  }

  void RegisterApplicationContext(
      JNIEnv* env,
      jobject obj,
      jobject context) {
    OutputType::SetAndroidAudioDeviceObjects(env, obj, context);
    InputType::SetAndroidAudioDeviceObjects(env, obj, context);
  }

 private:
  OutputType output_;
  InputType input_;
  FakeAudioDeviceBuffer audio_buffer_;
};

class OpenSlRunner
    : public OpenSlRunnerTemplate<OpenSlesInput, OpenSlesOutput> {
 public:
  // Global class implementing native code.
  static OpenSlRunner* g_runner;

  OpenSlRunner() {}
  virtual ~OpenSlRunner() {}

  static JNIEXPORT void JNICALL RegisterApplicationContext(
      JNIEnv* env,
      jobject obj,
      jobject context) {
    assert(!g_runner);  // Should only be called once.
    g_runner = new OpenSlRunner();
  }

  static JNIEXPORT void JNICALL Start(JNIEnv * env, jobject) {
    g_runner->StartPlayRecord();
  }

  static JNIEXPORT void JNICALL Stop(JNIEnv * env, jobject) {
    g_runner->StopPlayRecord();
  }
};

OpenSlRunner* OpenSlRunner::g_runner = NULL;

}  // namespace webrtc

jint JNI_OnLoad(JavaVM* vm, void* reserved) {
  // Only called once.
  assert(!g_vm);
  JNIEnv* env;
  if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
    return -1;
  }

  jclass local_osr = env->FindClass("org/webrtc/app/OpenSlRunner");
  assert(local_osr != NULL);
  g_osr = static_cast<jclass>(env->NewGlobalRef(local_osr));
  JNINativeMethod nativeFunctions[] = {
    {"RegisterApplicationContext", "(Landroid/content/Context;)V",
     reinterpret_cast<void*>(
         &webrtc::OpenSlRunner::RegisterApplicationContext)},
    {"Start", "()V", reinterpret_cast<void*>(&webrtc::OpenSlRunner::Start)},
    {"Stop",  "()V", reinterpret_cast<void*>(&webrtc::OpenSlRunner::Stop)}
  };
  int ret_val = env->RegisterNatives(g_osr, nativeFunctions, 3);
  if (ret_val != 0) {
    assert(false);
  }
  g_vm = vm;
  return JNI_VERSION_1_6;
}
<commit_msg>Android, OpenSlDemo: fixes issue where app would crash as soon as the application is started.<commit_after>/*
 *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <assert.h>
#include <jni.h>

#include "webrtc/modules/audio_device/android/audio_device_template.h"
#include "webrtc/modules/audio_device/android/audio_record_jni.h"
#include "webrtc/modules/audio_device/android/audio_track_jni.h"
#include "webrtc/modules/audio_device/android/opensles_input.h"
#include "webrtc/modules/audio_device/android/opensles_output.h"
#include "webrtc/modules/audio_device/android/test/fake_audio_device_buffer.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"

// Java globals
static JavaVM* g_vm = NULL;
static jclass g_osr = NULL;

namespace webrtc {

template <class InputType, class OutputType>
class OpenSlRunnerTemplate {
 public:
  OpenSlRunnerTemplate()
      : output_(0),
        input_(0, &output_) {
    output_.AttachAudioBuffer(&audio_buffer_);
    if (output_.Init() != 0) {
      assert(false);
    }
    if (output_.InitPlayout() != 0) {
      assert(false);
    }
    input_.AttachAudioBuffer(&audio_buffer_);
    if (input_.Init() != 0) {
      assert(false);
    }
    if (input_.InitRecording() != 0) {
      assert(false);
    }
  }

  ~OpenSlRunnerTemplate() {}

  void StartPlayRecord() {
    output_.StartPlayout();
    input_.StartRecording();
  }

  void StopPlayRecord() {
    // There are large enough buffers to compensate for recording and playing
    // jitter such that the timing of stopping playing or recording should not
    // result in over or underrun.
    input_.StopRecording();
    output_.StopPlayout();
    audio_buffer_.ClearBuffer();
  }

 private:
  OutputType output_;
  InputType input_;
  FakeAudioDeviceBuffer audio_buffer_;
};

class OpenSlRunner
    : public OpenSlRunnerTemplate<OpenSlesInput, OpenSlesOutput> {
 public:
  // Global class implementing native code.
  static OpenSlRunner* g_runner;

  OpenSlRunner() {}
  virtual ~OpenSlRunner() {}

  static JNIEXPORT void JNICALL RegisterApplicationContext(
      JNIEnv* env,
      jobject obj,
      jobject context) {
    assert(!g_runner);  // Should only be called once.
    // Register the application context in the superclass to avoid having to
    // qualify the template instantiation again.
    OpenSlesInput::SetAndroidAudioDeviceObjects(g_vm, env, context);
    OpenSlesOutput::SetAndroidAudioDeviceObjects(g_vm, env, context);
    g_runner = new OpenSlRunner();
  }

  static JNIEXPORT void JNICALL Start(JNIEnv * env, jobject) {
    g_runner->StartPlayRecord();
  }

  static JNIEXPORT void JNICALL Stop(JNIEnv * env, jobject) {
    g_runner->StopPlayRecord();
  }
};

OpenSlRunner* OpenSlRunner::g_runner = NULL;

}  // namespace webrtc

jint JNI_OnLoad(JavaVM* vm, void* reserved) {
  // Only called once.
  assert(!g_vm);
  JNIEnv* env;
  if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
    return -1;
  }

  jclass local_osr = env->FindClass("org/webrtc/app/OpenSlRunner");
  assert(local_osr != NULL);
  g_osr = static_cast<jclass>(env->NewGlobalRef(local_osr));
  JNINativeMethod nativeFunctions[] = {
    {"RegisterApplicationContext", "(Landroid/content/Context;)V",
     reinterpret_cast<void*>(
         &webrtc::OpenSlRunner::RegisterApplicationContext)},
    {"Start", "()V", reinterpret_cast<void*>(&webrtc::OpenSlRunner::Start)},
    {"Stop",  "()V", reinterpret_cast<void*>(&webrtc::OpenSlRunner::Stop)}
  };
  int ret_val = env->RegisterNatives(g_osr, nativeFunctions, 3);
  if (ret_val != 0) {
    assert(false);
  }
  g_vm = vm;
  return JNI_VERSION_1_6;
}
<|endoftext|>