<commit_before>////// Copyright 2020 by Sean Luke
////// Licensed under the Apache 2.0 License

#include "All.h"

#ifdef INCLUDE_GAUGE

/// GAUGE HELPER FUNCTIONS
/// Most of the Gauge app is inlined in the state machine below.
/// These three helper functions reduce the memory footprint.
/// However we can't move these to a file like Gauge.cpp because
/// the linker wastes memory in doing so.  So they're staying here.

/// Adds a number to the buffer.  The number may be buffered with spaces
/// at its beginning: these are not removed.  This is used to write the FIRST
/// number in a scrolling message for CC, RPN, or NRPN.
void addGaugeNumberNoTrim(uint16_t val)
    {
    char b[6];
    numberToString(b, val);
    addToBuffer(b);
    }

/// Adds a number to the buffer, removing initial spaces.  This is used to write
/// subsequent numbers in a scrolling message for CC, RPN, or NRPN.
void addGaugeNumber(uint16_t val)
    {
    char b[6];
    char* a;
    numberToString(b, val);
    a = b;
    while(a[0] == ' ') a++;  // trim out initial spaces
    addToBuffer(a);
    }

/// Writes a note pitch and velocity (or pressure value) to the screen.
void writeGaugeNote()
    {
    writeNotePitch(led2, (uint8_t) itemNumber);                           // Note
    writeShortNumber(led, (uint8_t) itemValue, false);            // Velocity or Pressure
    }

void stateGauge()
    {
    if (entry)
        {
        backupOptions = options;
        clearScreen();
        clearBuffer();
        memset(local.gauge.fastMidi, 0, 3);
        setParseRawCC(options.gaugeMidiInProvideRawCC);
        entry = false;
        }
    else
        {
        uint8_t dontShowValue = 0;

        // at present I'm saying (newItem) rather than (newItem == NEW_ITEM)
        // so even the WAIT_FOR_A_SEC stuff gets sent through.  Note sure
        // if testing for (newItem=1) will result in display starvation
        // when every time the display comes up we have a new incomplete
        // CC, NRPN, or RPN.

        if (getBufferLength() > 0 && updateDisplay)  // we've got a scrollbuffer loaded.  Won't happen on first update.
            {
            clearScreen();
            scrollBuffer(led, led2);
            }

        if (isUpdated(SELECT_BUTTON, RELEASED))
            {
            setParseRawCC(options.gaugeMidiInProvideRawCC = !options.gaugeMidiInProvideRawCC);
            saveOptions();
            }
        if (newItem)
            {
            if ((itemType >= MIDI_NOTE_ON))   // It's not fast midi
                {
                const char* str = NULL;

                clearScreen();
                if (itemType < MIDI_CC_7_BIT) // it's not a CC, RPN, or NRPN, and it's not displayable FAST MIDI
                    {
                    clearBuffer(); // so we stop scrolling
                    }

                switch(itemType)
                    {
                    case MIDI_NOTE_ON:
                        {
                        // Note we can't arrange this and NOTE OFF as a FALL THRU
                        // because writeGaugeNote() overwrites the points that we set
                        // immediately afterwards, so it can't be after them!
                        writeGaugeNote();
                        for(uint8_t i = 0; i < 5; i++)
                            setPoint(led, i, 1);
                        }
                    break;
                    case MIDI_NOTE_OFF:
                        {
                        writeGaugeNote();
                        }
                    break;
                    case MIDI_AFTERTOUCH:
                        {
                        write3x5Glyph(led2, GLYPH_3x5_A, 0);
                        write3x5Glyph(led2, GLYPH_3x5_T, 4);
                        writeShortNumber(led, (uint8_t) itemValue, false);
                        }
                    break;
                    case MIDI_AFTERTOUCH_POLY:
                        {
                        writeGaugeNote();
                        for(uint8_t i = 0; i < 5; i+=2)
                            setPoint(led, i, 1);
                        }
                    break;
                    case MIDI_PROGRAM_CHANGE:
                        {
                        write3x5Glyph(led2, GLYPH_3x5_P, 0);
                        write3x5Glyph(led2, GLYPH_3x5_C, 4);
                        writeShortNumber(led, (uint8_t) itemNumber, false);
                        }
                    break;
                    case MIDI_CC_7_BIT:
                        {
                        if (options.gaugeMidiInProvideRawCC)
                            {
                            clearBuffer(); // so we stop scrolling
                            writeShortNumber(led2, (uint8_t) itemNumber, true);
                            writeShortNumber(led, (uint8_t) itemValue, false);
                            break;
                            }
                        else if (itemNumber >= 120)             // Channel Mode
                            {
                            dontShowValue = true;
                            switch(itemNumber)
                                {
                                case 120:
                                    {
                                    str = PSTR("ALL SOUND OFF");
                                    break;
                                    }
                                case 121:
                                    {
                                    str = PSTR("RESET ALL CONTROLLERS");
                                    break;
                                    }
                                case 122:
                                    {
                                    if (itemValue)
                                        str = PSTR("LOCAL ON");
                                    else
                                        str = PSTR("LOCAL OFF");
                                    break;
                                    }
                                case 123:
                                    {
                                    str = PSTR("ALL NOTES OFF");
                                    break;
                                    }
                                case 124:
                                    {
                                    str = PSTR("OMNI OFF");
                                    break;
                                    }
                                case 125:
                                    {
                                    str = PSTR("OMNI ON");
                                    break;
                                    }
                                case 126:
                                    {
                                    dontShowValue = false;  // we want to see the value (it's the channel)
                                    str = PSTR("MONO ON");
                                    break;
                                    }
                                case 127:
                                    {
                                    str = PSTR("POLY ON");
                                    break;
                                    }
                                }
                            break;
                            }
                        // else we fall thru
                        }
                    // FALL THRU
                    case MIDI_CC_14_BIT:
                        {
                        str = PSTR("CC");
                        }
                    break;
                    case MIDI_NRPN_14_BIT:
                        // FALL THRU
                    case MIDI_NRPN_INCREMENT:
                        // FALL THRU
                    case MIDI_NRPN_DECREMENT:
                        {
                        str = PSTR("NRPN");
                        }
                    break;
                    case MIDI_RPN_14_BIT:
                        // FALL THRU
                    case MIDI_RPN_INCREMENT:
                        // FALL THRU
                    case MIDI_RPN_DECREMENT:
                        {
                        str = PSTR("RPN");
                        if (itemValue == RPN_NULL)  // note FALL THRU
                            {
                            newItem = NO_NEW_ITEM;
                            str = NULL;
                            }
                        }
                    break;
                    case MIDI_PITCH_BEND:
                        {
                        writeNumber(led, led2, ((int16_t) itemValue) - 8192);           // pitch bend is actually signed
                        }
                    break;
                    case MIDI_SYSTEM_EXCLUSIVE:
                    case MIDI_SONG_POSITION:
                    case MIDI_SONG_SELECT:
                    case MIDI_TUNE_REQUEST:
                    case MIDI_START:
                    case MIDI_CONTINUE:
                    case MIDI_STOP:
                    case MIDI_SYSTEM_RESET:
                        {
                        write3x5Glyphs(itemType - MIDI_SYSTEM_EXCLUSIVE + GLYPH_SYSTEM_RESET);
                        }
                    break;
                    }

                if (str != NULL)
                    {
                    char b[5];

                    clearBuffer();

                    // If we're incrementing/decrementing, add UP or DOWN
                    if ((itemType >= MIDI_NRPN_INCREMENT))
                        {
                        addToBuffer("   ");
                        if (itemType >= MIDI_NRPN_DECREMENT)
                            {
                            strcpy_P(b, PSTR("-"));
                            }
                        else
                            {
                            strcpy_P(b, PSTR("+"));
                            }
                        addToBuffer(b);
                        }

                    // else if we're 7-bit CC, just add the value
                    else if (itemType == MIDI_CC_7_BIT)
                        {
                        if (!dontShowValue)
                            addGaugeNumberNoTrim(itemValue);
                        }

                    // else add the MSB
                    else
                        {
                        addGaugeNumberNoTrim(itemValue >> 7);
                        }

                    // Next load the name
                    if (!dontShowValue)
                        addToBuffer(" ");
                    strcpy_P(b, str);
                    addToBuffer(b);

                    if (itemType != MIDI_CC_7_BIT || itemNumber < 120)  // we don't want channel mode drawing here
                        {
                        // Next the number
                        addToBuffer(" ");
                        addGaugeNumber(itemNumber);

                        if (itemType != MIDI_CC_7_BIT)          // either we indicate how much we increment/decrement, or show the full 14-bit number
                            {
                            addToBuffer(" (");
                            addGaugeNumber(itemValue);
                            addToBuffer(")");
                            }
                        }
                    }
                }
            else if (newItem != NO_NEW_ITEM)                   // Fast MIDI is all that's left.  RPN_NULL will trigger NO_NEW_ITEM
                {
                local.gauge.fastMidi[itemType] = !local.gauge.fastMidi[itemType];
                }

            if (newItem == WAIT_FOR_A_SEC)
                newItem = NEW_ITEM;
            else
                newItem = NO_NEW_ITEM;
            }
        }

    if (updateDisplay)
        {
        // blink the fast MIDI stuff
        for(uint8_t i = 0; i < 3; i++)
            {
            // slightly inefficient but it gets us under the byte limit
            clearPoint(led, i + 5, 1);
            if (local.gauge.fastMidi[i])
                setPoint(led, i + 5, 1);
            }
        drawMIDIChannel(itemChannel);

        if (options.gaugeMidiInProvideRawCC)
            setPoint(led, 5, 1);
        else
            clearPoint(led, 5, 1);

        // At any rate...
        // Clear the bypass/beat so it can draw itself again,
        // because we don't update ourselves every single time
        for(uint8_t i = 0; i < 8; i++)
            clearPoint(led, i, 0);
        }

    if (isUpdated(BACK_BUTTON, RELEASED))
        {
        setParseRawCC(false);
        goUpStateWithBackup(STATE_ROOT);
        }
    }

#endif INCLUDE_GAUGE
<commit_msg>formatting<commit_after>////// Copyright 2020 by Sean Luke
////// Licensed under the Apache 2.0 License

#include "All.h"

#ifdef INCLUDE_GAUGE

/// GAUGE HELPER FUNCTIONS
/// Most of the Gauge app is inlined in the state machine below.
/// These three helper functions reduce the memory footprint.
/// However we can't move these to a file like Gauge.cpp because
/// the linker wastes memory in doing so.  So they're staying here.

/// Adds a number to the buffer.  The number may be buffered with spaces
/// at its beginning: these are not removed.  This is used to write the FIRST
/// number in a scrolling message for CC, RPN, or NRPN.
void addGaugeNumberNoTrim(uint16_t val)
    {
    char b[6];
    numberToString(b, val);
    addToBuffer(b);
    }

/// Adds a number to the buffer, removing initial spaces.  This is used to write
/// subsequent numbers in a scrolling message for CC, RPN, or NRPN.
void addGaugeNumber(uint16_t val)
    {
    char b[6];
    char* a;
    numberToString(b, val);
    a = b;
    while(a[0] == ' ') a++;  // trim out initial spaces
    addToBuffer(a);
    }

/// Writes a note pitch and velocity (or pressure value) to the screen.
void writeGaugeNote()
    {
    writeNotePitch(led2, (uint8_t) itemNumber);                   // Note
    writeShortNumber(led, (uint8_t) itemValue, false);            // Velocity or Pressure
    }

void stateGauge()
    {
    if (entry)
        {
        backupOptions = options;
        clearScreen();
        clearBuffer();
        memset(local.gauge.fastMidi, 0, 3);
        setParseRawCC(options.gaugeMidiInProvideRawCC);
        entry = false;
        }
    else
        {
        uint8_t dontShowValue = 0;

        // at present I'm saying (newItem) rather than (newItem == NEW_ITEM)
        // so even the WAIT_FOR_A_SEC stuff gets sent through.  Note sure
        // if testing for (newItem=1) will result in display starvation
        // when every time the display comes up we have a new incomplete
        // CC, NRPN, or RPN.

        if (getBufferLength() > 0 && updateDisplay)  // we've got a scrollbuffer loaded.  Won't happen on first update.
            {
            clearScreen();
            scrollBuffer(led, led2);
            }

        if (isUpdated(SELECT_BUTTON, RELEASED))
            {
            setParseRawCC(options.gaugeMidiInProvideRawCC = !options.gaugeMidiInProvideRawCC);
            saveOptions();
            }
        if (newItem)
            {
            if ((itemType >= MIDI_NOTE_ON))   // It's not fast midi
                {
                const char* str = NULL;

                clearScreen();
                if (itemType < MIDI_CC_7_BIT) // it's not a CC, RPN, or NRPN, and it's not displayable FAST MIDI
                    {
                    clearBuffer(); // so we stop scrolling
                    }

                switch(itemType)
                    {
                    case MIDI_NOTE_ON:
                        {
                        // Note we can't arrange this and NOTE OFF as a FALL THRU
                        // because writeGaugeNote() overwrites the points that we set
                        // immediately afterwards, so it can't be after them!
                        writeGaugeNote();
                        for(uint8_t i = 0; i < 5; i++)
                            setPoint(led, i, 1);
                        }
                    break;
                    case MIDI_NOTE_OFF:
                        {
                        writeGaugeNote();
                        }
                    break;
                    case MIDI_AFTERTOUCH:
                        {
                        write3x5Glyph(led2, GLYPH_3x5_A, 0);
                        write3x5Glyph(led2, GLYPH_3x5_T, 4);
                        writeShortNumber(led, (uint8_t) itemValue, false);
                        }
                    break;
                    case MIDI_AFTERTOUCH_POLY:
                        {
                        writeGaugeNote();
                        for(uint8_t i = 0; i < 5; i+=2)
                            setPoint(led, i, 1);
                        }
                    break;
                    case MIDI_PROGRAM_CHANGE:
                        {
                        write3x5Glyph(led2, GLYPH_3x5_P, 0);
                        write3x5Glyph(led2, GLYPH_3x5_C, 4);
                        writeShortNumber(led, (uint8_t) itemNumber, false);
                        }
                    break;
                    case MIDI_CC_7_BIT:
                        {
                        if (options.gaugeMidiInProvideRawCC)
                            {
                            clearBuffer(); // so we stop scrolling
                            writeShortNumber(led2, (uint8_t) itemNumber, true);
                            writeShortNumber(led, (uint8_t) itemValue, false);
                            break;
                            }
                        else if (itemNumber >= 120)             // Channel Mode
                            {
                            dontShowValue = true;
                            switch(itemNumber)
                                {
                                case 120:
                                    {
                                    str = PSTR("ALL SOUND OFF");
                                    break;
                                    }
                                case 121:
                                    {
                                    str = PSTR("RESET ALL CONTROLLERS");
                                    break;
                                    }
                                case 122:
                                    {
                                    if (itemValue)
                                        str = PSTR("LOCAL ON");
                                    else
                                        str = PSTR("LOCAL OFF");
                                    break;
                                    }
                                case 123:
                                    {
                                    str = PSTR("ALL NOTES OFF");
                                    break;
                                    }
                                case 124:
                                    {
                                    str = PSTR("OMNI OFF");
                                    break;
                                    }
                                case 125:
                                    {
                                    str = PSTR("OMNI ON");
                                    break;
                                    }
                                case 126:
                                    {
                                    dontShowValue = false;  // we want to see the value (it's the channel)
                                    str = PSTR("MONO ON");
                                    break;
                                    }
                                case 127:
                                    {
                                    str = PSTR("POLY ON");
                                    break;
                                    }
                                }
                            break;
                            }
                        // else we fall thru
                        }
                    // FALL THRU
                    case MIDI_CC_14_BIT:
                        {
                        str = PSTR("CC");
                        }
                    break;
                    case MIDI_NRPN_14_BIT:
                        // FALL THRU
                    case MIDI_NRPN_INCREMENT:
                        // FALL THRU
                    case MIDI_NRPN_DECREMENT:
                        {
                        str = PSTR("NRPN");
                        }
                    break;
                    case MIDI_RPN_14_BIT:
                        // FALL THRU
                    case MIDI_RPN_INCREMENT:
                        // FALL THRU
                    case MIDI_RPN_DECREMENT:
                        {
                        str = PSTR("RPN");
                        if (itemValue == RPN_NULL)  // note FALL THRU
                            {
                            newItem = NO_NEW_ITEM;
                            str = NULL;
                            }
                        }
                    break;
                    case MIDI_PITCH_BEND:
                        {
                        writeNumber(led, led2, ((int16_t) itemValue) - 8192);           // pitch bend is actually signed
                        }
                    break;
                    case MIDI_SYSTEM_EXCLUSIVE:
                    case MIDI_SONG_POSITION:
                    case MIDI_SONG_SELECT:
                    case MIDI_TUNE_REQUEST:
                    case MIDI_START:
                    case MIDI_CONTINUE:
                    case MIDI_STOP:
                    case MIDI_SYSTEM_RESET:
                        {
                        write3x5Glyphs(itemType - MIDI_SYSTEM_EXCLUSIVE + GLYPH_SYSTEM_RESET);
                        }
                    break;
                    }

                if (str != NULL)
                    {
                    char b[5];

                    clearBuffer();

                    // If we're incrementing/decrementing, add UP or DOWN
                    if ((itemType >= MIDI_NRPN_INCREMENT))
                        {
                        addToBuffer("   ");
                        if (itemType >= MIDI_NRPN_DECREMENT)
                            {
                            strcpy_P(b, PSTR("-"));
                            }
                        else
                            {
                            strcpy_P(b, PSTR("+"));
                            }
                        addToBuffer(b);
                        }

                    // else if we're 7-bit CC, just add the value
                    else if (itemType == MIDI_CC_7_BIT)
                        {
                        if (!dontShowValue)
                            addGaugeNumberNoTrim(itemValue);
                        }

                    // else add the MSB
                    else
                        {
                        addGaugeNumberNoTrim(itemValue >> 7);
                        }

                    // Next load the name
                    if (!dontShowValue)
                        addToBuffer(" ");
                    strcpy_P(b, str);
                    addToBuffer(b);

                    if (itemType != MIDI_CC_7_BIT || itemNumber < 120)  // we don't want channel mode drawing here
                        {
                        // Next the number
                        addToBuffer(" ");
                        addGaugeNumber(itemNumber);

                        if (itemType != MIDI_CC_7_BIT)          // either we indicate how much we increment/decrement, or show the full 14-bit number
                            {
                            addToBuffer(" (");
                            addGaugeNumber(itemValue);
                            addToBuffer(")");
                            }
                        }
                    }
                }
            else if (newItem != NO_NEW_ITEM)                   // Fast MIDI is all that's left.  RPN_NULL will trigger NO_NEW_ITEM
                {
                local.gauge.fastMidi[itemType] = !local.gauge.fastMidi[itemType];
                }

            if (newItem == WAIT_FOR_A_SEC)
                newItem = NEW_ITEM;
            else
                newItem = NO_NEW_ITEM;
            }
        }

    if (updateDisplay)
        {
        // blink the fast MIDI stuff
        for(uint8_t i = 0; i < 3; i++)
            {
            // slightly inefficient but it gets us under the byte limit
            clearPoint(led, i + 5, 1);
            if (local.gauge.fastMidi[i])
                setPoint(led, i + 5, 1);
            }
        drawMIDIChannel(itemChannel);

        if (options.gaugeMidiInProvideRawCC)
            setPoint(led, 5, 1);
        else
            clearPoint(led, 5, 1);

        // At any rate...
        // Clear the bypass/beat so it can draw itself again,
        // because we don't update ourselves every single time
        for(uint8_t i = 0; i < 8; i++)
            clearPoint(led, i, 0);
        }

    if (isUpdated(BACK_BUTTON, RELEASED))
        {
        setParseRawCC(false);
        goUpStateWithBackup(STATE_ROOT);
        }
    }

#endif INCLUDE_GAUGE
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: opcodes.hxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: rt $ $Date: 2005-01-28 16:07:35 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _OPCODES_HXX
#define _OPCODES_HXX

#include "sbintern.hxx"

#ifdef MTW
#undef _NUMBER
#endif

// Ein Opcode ist entweder 1, 3 oder 5 Bytes lang, je nach numerischen
// Wert des Opcodes (s.u.).

enum SbiOpcode {
    // Alle Opcodes ohne Operanden
    _NOP = 0,

    SbOP0_START = _NOP,

    // Operatoren
    // die folgenden Operatoren sind genauso angeordnet
    // wie der enum SbxVarOp
    _EXP, _MUL, _DIV, _MOD, _PLUS, _MINUS, _NEG,
    _EQ,  _NE,  _LT,  _GT, _LE, _GE,
    _IDIV, _AND, _OR, _XOR, _EQV, _IMP, _NOT,
    _CAT,
    // Ende enum SbxVarOp
    _LIKE, _IS,
    // Laden/speichern
    _ARGC,              // neuen Argv einrichten
    _ARGV,              // TOS ==> aktueller Argv
    _INPUT,             // Input ==> TOS
    _LINPUT,            // Line Input ==> TOS
    _GET,               // TOS anfassen
    _SET,               // Speichern Objekt TOS ==> TOS-1
    _PUT,               // TOS ==> TOS-1
    _PUTC,              // TOS ==> TOS-1, dann ReadOnly
    _DIM,               // DIM
    _REDIM,             // REDIM
    _REDIMP,            // REDIM PRESERVE
    _ERASE,             // TOS loeschen
    // Verzweigen
    _STOP,              // Programmende
    _INITFOR,           // FOR-Variable initialisieren
    _NEXT,              // FOR-Variable inkrementieren
    _CASE,              // Anfang CASE
    _ENDCASE,           // Ende CASE
    _STDERROR,          // Standard-Fehlerbehandlung
    _NOERROR,           // keine Fehlerbehandlung
    _LEAVE,             // UP verlassen
    // E/A
    _CHANNEL,           // TOS = Kanalnummer
    _BPRINT,            // print TOS
    _PRINTF,            // print TOS in field
    _BWRITE,            // write TOS
    _RENAME,            // Rename Tos+1 to Tos
    _PROMPT,            // TOS = Prompt for Input
    _RESTART,           // Restartpunkt definieren
    _CHAN0,             // I/O-Kanal 0
    // Sonstiges
    _EMPTY,             // Leeren Ausdruck auf Stack
    _ERROR,             // TOS = Fehlercode
    _LSET,              // Speichern Objekt TOS ==> TOS-1
    _RSET,              // Speichern Objekt TOS ==> TOS-1
    _REDIMP_ERASE,      // Copies array to be later used by REDIM PRESERVE before erasing it
    _INITFOREACH,
    SbOP0_END,

    // Alle Opcodes mit einem Operanden

    _NUMBER = 0x40,     // Laden einer numerischen Konstanten (+ID)

    SbOP1_START = _NUMBER,

    _SCONST,            // Laden einer Stringkonstanten (+ID)
    _CONST,             // Immediate Load (+Wert)
    _ARGN,              // Speichern eines named Args in Argv (+StringID)
    _PAD,               // String auf feste Laenge bringen (+Laenge)
    // Verzweigungen
    _JUMP,              // Sprung (+Target)
    _JUMPT,             // TOS auswerten, bedingter Sprung (+Target)
    _JUMPF,             // TOS auswerten, bedingter Sprung (+Target)
    _ONJUMP,            // TOS auswerten, Sprung in JUMP-Tabelle (+MaxVal)
    _GOSUB,             // UP-Aufruf (+Target)
    _RETURN,            // UP-Return (+0 oder Target)
    _TESTFOR,           // FOR-Variable testen, inkrementieren (+Endlabel)
    _CASETO,            // Tos+1 <= Case <= Tos, 2xremove (+Target)
    _ERRHDL,            // Fehler-Handler (+Offset)
    _RESUME,            // Resume nach Fehlern (+0 or 1 or Label)
    // E/A
    _CLOSE,             // (+Kanal/0)
    _PRCHAR,            // (+char)
    // Verwaltung
    _CLASS,             // Klassennamen testen (+StringId)
    _LIB,               // Libnamen fuer Declare-Procs setzen (+StringId)
    _BASED,             // TOS wird um BASE erhoeht, BASE davor gepusht (+base)
    // Typanpassung im Argv
    _ARGTYP,            // Letzten Parameter in Argv konvertieren (+Typ)

    SbOP1_END,

    // Alle Opcodes mit zwei Operanden

    _RTL = 0x80,        // Laden aus RTL (+StringID+Typ)

    SbOP2_START = _RTL,

    _FIND,              // Laden (+StringID+Typ)
    _ELEM,              // Laden Element (+StringID+Typ)
    _PARAM,             // Parameter (+Offset+Typ)
    // Verzweigen
    _CALL,              // DECLARE-Methode rufen (+StringID+Typ)
    _CALLC,             // Cdecl-DECLARE-Methode rufen (+StringID+Typ)
    _CASEIS,            // Case-Test (+Test-Opcode+True-Target)
    // Verwaltung
    _STMNT,             // Beginn eines Statements (+Line+Col)
    // E/A
    _OPEN,              // (+SvStreamFlags+Flags)
    // Objekte
    _LOCAL,             // Lokale Variable definieren (+StringID+Typ)
    _PUBLIC,            // Modulglobale Variable (+StringID+Typ)
    _GLOBAL,            // Globale Variable definieren, public-Anweisung (+StringID+Typ)
    _CREATE,            // Objekt kreieren (+StringId+StringID)
    _STATIC,            // Statische Variabl (+StringID+Typ) JSM
    _TCREATE,           // User Defined Objekt kreieren
    _DCREATE,           // Objekt-Array kreieren (+StringId+StringID)
    _GLOBAL_P,          // Globale Variable definieren, die beim Neustart von Basic
                        // nicht ueberschrieben wird, P=PERSIST (+StringID+Typ)
    _FIND_G,            // Sucht globale Variable mit Spezialbehandlung wegen _GLOBAL_P
    _DCREATE_REDIMP,    // Objekt-Array redimensionieren (+StringId+StringID)
    _FIND_CM,           // Search inside a class module (CM) to enable global search in time
    SbOP2_END

};

#endif
<commit_msg>INTEGRATION: CWS ab14fixes (1.5.22); FILE MERGED 2005/03/16 15:24:31 ab 1.5.22.3: RESYNC: (1.5-1.6); FILE MERGED 2005/03/04 11:59:02 ab 1.5.22.2: #120061# New opcode _TESTCLASS 2005/02/21 16:27:51 ab 1.5.22.1: #115829# Opcode _CLASS -> opcode _SETCLASS due to new semantics<commit_after>/*************************************************************************
 *
 *  $RCSfile: opcodes.hxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: rt $ $Date: 2005-03-29 11:50:40 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _OPCODES_HXX
#define _OPCODES_HXX

#include "sbintern.hxx"

#ifdef MTW
#undef _NUMBER
#endif

// Ein Opcode ist entweder 1, 3 oder 5 Bytes lang, je nach numerischen
// Wert des Opcodes (s.u.).

enum SbiOpcode {
    // Alle Opcodes ohne Operanden
    _NOP = 0,

    SbOP0_START = _NOP,

    // Operatoren
    // die folgenden Operatoren sind genauso angeordnet
    // wie der enum SbxVarOp
    _EXP, _MUL, _DIV, _MOD, _PLUS, _MINUS, _NEG,
    _EQ,  _NE,  _LT,  _GT, _LE, _GE,
    _IDIV, _AND, _OR, _XOR, _EQV, _IMP, _NOT,
    _CAT,
    // Ende enum SbxVarOp
    _LIKE, _IS,
    // Laden/speichern
    _ARGC,              // neuen Argv einrichten
    _ARGV,              // TOS ==> aktueller Argv
    _INPUT,             // Input ==> TOS
    _LINPUT,            // Line Input ==> TOS
    _GET,               // TOS anfassen
    _SET,               // Speichern Objekt TOS ==> TOS-1
    _PUT,               // TOS ==> TOS-1
    _PUTC,              // TOS ==> TOS-1, dann ReadOnly
    _DIM,               // DIM
    _REDIM,             // REDIM
    _REDIMP,            // REDIM PRESERVE
    _ERASE,             // TOS loeschen
    // Verzweigen
    _STOP,              // Programmende
    _INITFOR,           // FOR-Variable initialisieren
    _NEXT,              // FOR-Variable inkrementieren
    _CASE,              // Anfang CASE
    _ENDCASE,           // Ende CASE
    _STDERROR,          // Standard-Fehlerbehandlung
    _NOERROR,           // keine Fehlerbehandlung
    _LEAVE,             // UP verlassen
    // E/A
    _CHANNEL,           // TOS = Kanalnummer
    _BPRINT,            // print TOS
    _PRINTF,            // print TOS in field
    _BWRITE,            // write TOS
    _RENAME,            // Rename Tos+1 to Tos
    _PROMPT,            // TOS = Prompt for Input
    _RESTART,           // Restartpunkt definieren
    _CHAN0,             // I/O-Kanal 0
    // Sonstiges
    _EMPTY,             // Leeren Ausdruck auf Stack
    _ERROR,             // TOS = Fehlercode
    _LSET,              // Speichern Objekt TOS ==> TOS-1
    _RSET,              // Speichern Objekt TOS ==> TOS-1
    _REDIMP_ERASE,      // Copies array to be later used by REDIM PRESERVE before erasing it
    _INITFOREACH,
    SbOP0_END,

    // Alle Opcodes mit einem Operanden

    _NUMBER = 0x40,     // Laden einer numerischen Konstanten (+ID)

    SbOP1_START = _NUMBER,

    _SCONST,            // Laden einer Stringkonstanten (+ID)
    _CONST,             // Immediate Load (+Wert)
    _ARGN,              // Speichern eines named Args in Argv (+StringID)
    _PAD,               // String auf feste Laenge bringen (+Laenge)
    // Verzweigungen
    _JUMP,              // Sprung (+Target)
    _JUMPT,             // TOS auswerten, bedingter Sprung (+Target)
    _JUMPF,             // TOS auswerten, bedingter Sprung (+Target)
    _ONJUMP,            // TOS auswerten, Sprung in JUMP-Tabelle (+MaxVal)
    _GOSUB,             // UP-Aufruf (+Target)
    _RETURN,            // UP-Return (+0 oder Target)
    _TESTFOR,           // FOR-Variable testen, inkrementieren (+Endlabel)
    _CASETO,            // Tos+1 <= Case <= Tos, 2xremove (+Target)
    _ERRHDL,            // Fehler-Handler (+Offset)
    _RESUME,            // Resume nach Fehlern (+0 or 1 or Label)
    // E/A
    _CLOSE,             // (+Kanal/0)
    _PRCHAR,            // (+char)
    // Verwaltung
    _SETCLASS,          // Set + Klassennamen testen (+StringId)
    _TESTCLASS,         // Check TOS class (+StringId)
    _LIB,               // Libnamen fuer Declare-Procs setzen (+StringId)
    _BASED,             // TOS wird um BASE erhoeht, BASE davor gepusht (+base)
    // Typanpassung im Argv
    _ARGTYP,            // Letzten Parameter in Argv konvertieren (+Typ)

    SbOP1_END,

    // Alle Opcodes mit zwei Operanden

    _RTL = 0x80,        // Laden aus RTL (+StringID+Typ)

    SbOP2_START = _RTL,

    _FIND,              // Laden (+StringID+Typ)
    _ELEM,              // Laden Element (+StringID+Typ)
    _PARAM,             // Parameter (+Offset+Typ)
    // Verzweigen
    _CALL,              // DECLARE-Methode rufen (+StringID+Typ)
    _CALLC,             // Cdecl-DECLARE-Methode rufen (+StringID+Typ)
    _CASEIS,            // Case-Test (+Test-Opcode+True-Target)
    // Verwaltung
    _STMNT,             // Beginn eines Statements (+Line+Col)
    // E/A
    _OPEN,              // (+SvStreamFlags+Flags)
    // Objekte
    _LOCAL,             // Lokale Variable definieren (+StringID+Typ)
    _PUBLIC,            // Modulglobale Variable (+StringID+Typ)
    _GLOBAL,            // Globale Variable definieren, public-Anweisung (+StringID+Typ)
    _CREATE,            // Objekt kreieren (+StringId+StringID)
    _STATIC,            // Statische Variabl (+StringID+Typ) JSM
    _TCREATE,           // User Defined Objekt kreieren
    _DCREATE,           // Objekt-Array kreieren (+StringId+StringID)
    _GLOBAL_P,          // Globale Variable definieren, die beim Neustart von Basic
                        // nicht ueberschrieben wird, P=PERSIST (+StringID+Typ)
    _FIND_G,            // Sucht globale Variable mit Spezialbehandlung wegen _GLOBAL_P
    _DCREATE_REDIMP,    // Objekt-Array redimensionieren (+StringId+StringID)
    _FIND_CM,           // Search inside a class module (CM) to enable global search in time
    SbOP2_END

};

#endif
<|endoftext|>


<commit_before>/* $Id$ */
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-11 Bradley M. Bell

CppAD is distributed under multiple licenses. This distribution is under
the terms of the
                    Common Public License Version 1.0.

A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */

/*
$begin multi_newton.cpp$$
$spell
	CppAD
	parallelize
$$
$index OpenMP, example program$$
$index example, OpenMP program$$
$index program, OpenMP example$$

$section Multi-Threaded Newton's Method Main Program$$

$head Syntax$$
$syntax%multi_newton %n_thread% %repeat% %n_zero% %n_grid% %n_sum% %use_ad%$$

$head Purpose$$
Runs a timing test of the $cref/multi_newton/$$ routine.
This routine uses Newton's method to determine if there is a zero of a
function on each of a set of sub-intervals.
CppAD is used to calculate the derivatives required by Newton's method.
OpenMP is used to parallelize the calculation on the different sub-intervals.

$head n_thread$$
If the argument $italic n_thread$$ is equal to $code automatic$$,
dynamic thread adjustment is used.
Otherwise, $italic n_thread$$ must be a positive number
specifying the number of OpenMP threads to use.

$head repeat$$
If the argument $italic repeat$$ is equal to $code automatic$$,
the number of times to repeat the calculation of the number of zeros
in total interval is automatically determined.
In this case, the rate of execution of the total solution is reported.
$pre

$$
If the argument $italic repeat$$ is not equal to $italic automatic$$,
it must be a positive integer.
In this case $italic repeat$$ determination of the number of times
the calculation of the zeros in the total interval is repeated.
The rate of execution is not reported (it is assumed that the
program execution time is being calculated some other way).

$head n_zero$$
The argument $italic n_zero$$ is the actual number of zeros
that there should be in the test function, $latex \sin(x)$$.
It must be an integer greater than one.
The total interval searched  for zeros is
$latex [ 0 , (n\_zero - 1) \pi ]$$.

$head n_grid$$
The argument $italic n_grid$$
specifies the number of sub-intervals to divide the total interval into.
It must an integer greater than zero
(should probably be greater than two times $italic n_zero$$).

$head n_sum$$
The actual function that is used is
$latex \[
	f(x) = \frac{1}{n\_sum} \sum_{i=1}^{n\_sum} \sin (x)
\] $$
where $italic n_sum$$ is a positive integer.
The larger the value of $italic n_sum$$,
the more computation is required to calculate the function.

$head use_ad$$
If $icode use_ad$$ is $code true$$,
then derivatives will be computed using algorithmic differentiation.
If $icode use_ad$$ is $code false$$,
derivatives will be computed using a hand coded routine.

$head Subroutines$$
$children%
	openmp/multi_newton.hpp
%$$
$table
$rref multi_newton$$
$rref multi_newton.hpp$$
$tend

$head Example Source$$
$code
$verbatim%openmp/multi_newton.cpp%0%// BEGIN PROGRAM%// END PROGRAM%1%$$
$$

$end
*/
// BEGIN PROGRAM

# include <cppad/cppad.hpp>
# include <cmath>
# include <cstring>
# include "multi_newton.hpp"

# ifdef _OPENMP
# include <omp.h>
# endif

namespace { // empty namespace
	size_t n_sum;  // larger values make f(x) take longer to calculate
	size_t n_zero; // number of zeros of f(x) in the total interval
	bool   use_ad; // compute derivatives using AD
}

// A slow version of the sine function
template <class Float>
Float f_eval(Float x)
{	Float sum = 0.;
	size_t i;
	for(i = 0; i < n_sum; i++)
		sum += sin(x);

	return sum / Float(n_sum);
}
// Direct calculation of derivative
double df_direct(double x)
{	double sum = 0.;
	size_t i;
	for(i = 0; i < n_sum; i++)
		sum += cos(x);

	return sum / double(n_sum);
}
// AD calculation of detivative
void fun_ad(double x, double& f, double& df)
{	using CppAD::vector;
	using CppAD::AD;
	vector< AD<double> > X(1), Y(1);
	X[0] = x;
	CppAD::Independent(X);
	Y[0] = f_eval(X[0]);
	CppAD::ADFun<double> F(X, Y);
	vector<double> dx(1), dy(1);
	dx[0] = 1.;
	dy    = F.Forward(1, dx);
	f     = Value( Y[0] );
	df    = dy[0];
	return;
}

void fun(double x, double& f, double& df)
{	if( use_ad )
		fun_ad(x, f, df);
	else
	{	f  = f_eval(x);
		df = df_direct(x);
	}
	return;
}

void test_once(CppAD::vector<double> &xout, size_t n_grid)
{	assert( n_zero > 1 );
	double pi      = 4. * std::atan(1.);
	double xlow    = 0.;
	double xup     = (n_zero - 1) * pi;
	double epsilon = 1e-6;
	size_t max_itr = 20;

	multi_newton(
		xout    ,
		fun     ,
		n_grid  ,
		xlow    ,
		xup     ,
		epsilon ,
		max_itr
	);
	return;
}

void test_repeat(size_t size, size_t repeat)
{	size_t i;
	CppAD::vector<double> xout;
	for(i = 0; i < repeat; i++)
		test_once(xout, size);
	return;
}

int main(int argc, char *argv[])
{
	using std::cout;
	using std::endl;
	using CppAD::vector;

	const char *usage =
		"multi_newton n_thread repeat n_zero n_grid n_sum use_ad";
	if( argc != 7 )
	{	std::cerr << usage << endl;
		exit(1);
	}
	argv++;

	// n_thread command line argument
	int n_thread;
	if( std::strcmp(*argv, "automatic") == 0 )
		n_thread = 0;
	else
	{	n_thread = std::atoi(*argv);
		if( n_thread == 0 )
		{	cout << "multi_newton: n_thread is equal to zero" << endl;
			cout << "perhaps you want n_thread equal to automatic" << endl;
			exit(1);
		}
	}
	argv++;

	// repeat command line argument
	size_t repeat;
	if( std::strcmp(*argv, "automatic") == 0 )
		repeat = 0;
	else
	{	assert( std::atoi(*argv) > 0 );
		repeat = std::atoi(*argv);
		if( repeat == 0 )
		{	cout << "multi_newton: repeat is equal to zero" << endl;
			cout << "perhaps you want repeat equal to automatic" << endl;
			exit(1);
		}
	}
	argv++;

	// n_zero command line argument
	assert( std::atoi(*argv) > 1 );
	n_zero = std::atoi(*argv++);

	// n_grid command line argument
	assert( std::atoi(*argv) > 0 );
	size_t n_grid = std::atoi(*argv++);

	// n_sum command line argument
	assert( std::atoi(*argv) > 0 );
	n_sum = std::atoi(*argv++);

	// use_ad
	if( std::strcmp(*argv, "true") == 0 )
		use_ad = true;
	else if( std::strcmp(*argv, "false") == 0 )
		use_ad = false;
	else
		std::cerr << "multi_newton: use_ad is not true or false" << endl;
	argv++;

	// minimum time for test (repeat until this much time)
	double time_min = 1.;

# ifdef _OPENMP
	if( n_thread > 0 )
	{	omp_set_dynamic(0);            // off dynamic thread adjust
		omp_set_num_threads(n_thread); // set the number of threads
	}
	// now determine the maximum number of threads
	n_thread = omp_get_max_threads();
	assert( n_thread > 0 );

	// No tapes are currently active,
	// so we can inform CppAD of the maximum number of threads
	CppAD::AD<double>::omp_max_thread(size_t(n_thread));

	// inform the user of the maximum number of threads
	cout << "OpenMP="     << _OPENMP;
# else
	cout << "OPENMP=\"\"";
	n_thread = 1;
# endif
	cout << ", n_thread=" << n_thread;
	cout << ", n_zero="   << n_zero;
	cout << ", n_grid="   << n_grid;
	cout << ", n_sum="    << n_sum;
	cout << ", use_ad="   << use_ad;
	cout << endl;
	// initialize flag
	bool ok = true;

	// sub-block so xout gets deallocated before call to CPPAD_TRACK_COUNT
	{	// Correctness check
		vector<double> xout;
		test_once(xout, n_grid);
		double epsilon = 1e-6;
		double pi      = 4. * std::atan(1.);
		ok            &= (xout.size() == n_zero);
		size_t i       = 0;
		while( ok & (i < n_zero) )
		{	ok &= std::fabs( xout[i] - pi * i) <= 2 * epsilon;
			++i;
		}
	}
	if( repeat > 0 )
	{	// run the calculation the requested number of time
		test_repeat(n_grid, repeat);
	}
	else
	{	// actually time the calculation

		// size of the one test case
		vector<size_t> size_vec(1);
		size_vec[0] = n_grid;

		// run the test case
		vector<size_t> rate_vec =
		CppAD::speed_test(test_repeat, size_vec, time_min);

		// report results
		cout << "repeats per sec  = " << rate_vec[0] << endl;
	}
	// check all the threads for a CppAD memory leak
	if( CppAD::memory_leak() )
	{	ok = false;
		cout << "Error: memory leak detected" << endl;
	}
	if( ok )
		cout << "Correctness Test = OK" << endl;
	else	cout << "Correctness Test = Error" << endl;

	return static_cast<int>( ! ok );
}

// END PROGRAM
<commit_msg>multi_newton.cpp: 1. change to modern omhelp comands (using modern_omhelp.sh). 2. Add restriction n_sum > 0. 3. Put all local functions in empty namespace (and indent them). 4. Use local routine arg2size_t to convert command line arguments to size_t. 5. Change n_thread to be size_t (like other local variables). 6. Check no omp_alloc memeory in use or avaiable at start. 7. Print omp_alloc memory at end. 8. Move correctness test to be after speed test.<commit_after>/* $Id$ */
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-11 Bradley M. Bell

CppAD is distributed under multiple licenses. This distribution is under
the terms of the
                    Common Public License Version 1.0.

A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */

/*
$begin multi_newton.cpp$$
$spell
	CppAD
	parallelize
$$
$index OpenMP, example program$$
$index example, OpenMP program$$
$index program, OpenMP example$$

$section Multi-Threaded Newton's Method Main Program$$

$head Syntax$$
$codei%multi_newton %n_thread% %repeat% %n_zero% %n_grid% %n_sum% %use_ad%$$

$head Purpose$$
Runs a timing test of the $cref/multi_newton/$$ routine.
This routine uses Newton's method to determine if there is a zero of a
function on each of a set of sub-intervals.
CppAD is used to calculate the derivatives required by Newton's method.
OpenMP is used to parallelize the calculation on the different sub-intervals.

$head n_thread$$
If the argument $icode n_thread$$ is equal to $code automatic$$,
dynamic thread adjustment is used.
Otherwise, $icode n_thread$$ must be a positive number
specifying the number of OpenMP threads to use.

$head repeat$$
If the argument $icode repeat$$ is equal to $code automatic$$,
the number of times to repeat the calculation of the number of zeros
in total interval is automatically determined.
In this case, the rate of execution of the total solution is reported.
$pre

$$
If the argument $icode repeat$$ is not equal to $italic automatic$$,
it must be a positive integer.
In this case $icode repeat$$ determination of the number of times
the calculation of the zeros in the total interval is repeated.
The rate of execution is not reported (it is assumed that the
program execution time is being calculated some other way).

$head n_zero$$
The argument $icode n_zero$$ is the actual number of zeros
that there should be in the test function, $latex \sin(x)$$.
It must be an integer greater than one.
The total interval searched  for zeros is
$latex [ 0 , (n\_zero - 1) \pi ]$$.

$head n_grid$$
The argument $icode n_grid$$
specifies the number of sub-intervals to divide the total interval into.
It must an integer greater than zero
(should probably be greater than two times $icode n_zero$$).

$head n_sum$$
The actual function that is used is
$latex \[
	f(x) = \frac{1}{n\_sum} \sum_{i=1}^{n\_sum} \sin (x)
\] $$
where $icode n_sum$$ is a positive integer.
The larger the value of $icode n_sum$$,
the more computation is required to calculate the function.
This must be an integer greater than zero.

$head use_ad$$
If $icode use_ad$$ is $code true$$,
then derivatives will be computed using algorithmic differentiation.
If $icode use_ad$$ is $code false$$,
derivatives will be computed using a hand coded routine.

$head Subroutines$$
$children%
	openmp/multi_newton.hpp
%$$
$table
$rref multi_newton$$
$rref multi_newton.hpp$$
$tend

$head Example Source$$
$code
$verbatim%openmp/multi_newton.cpp%0%// BEGIN PROGRAM%// END PROGRAM%1%$$
$$

$end
*/
// BEGIN PROGRAM

# include <cppad/cppad.hpp>
# include <cmath>
# include <cstring>
# include "multi_newton.hpp"

# ifdef _OPENMP
# include <omp.h>
# endif

namespace { // empty namespace

	// set by main program and used by functions in this file
	size_t n_sum;  // larger values make f(x) take longer to calculate
	size_t n_zero; // number of zeros of f(x) in the total interval
	bool   use_ad; // compute derivatives using AD

	// A slow version of the sine function
	template <class Float>
	Float f_eval(Float x)
	{	Float sum = 0.;
		size_t i;
		for(i = 0; i < n_sum; i++)
			sum += sin(x);

		return sum / Float(n_sum);
	}

	// Direct calculation of derivative
	double df_direct(double x)
	{	double sum = 0.;
		size_t i;
		for(i = 0; i < n_sum; i++)
			sum += cos(x);

		return sum / double(n_sum);
	}

	// AD calculation of detivative
	void fun_ad(double x, double& f, double& df)
	{	using CppAD::vector;
		using CppAD::AD;
		vector< AD<double> > X(1), Y(1);
		X[0] = x;
		CppAD::Independent(X);
		Y[0] = f_eval(X[0]);
		CppAD::ADFun<double> F(X, Y);
		vector<double> dx(1), dy(1);
		dx[0] = 1.;
		dy    = F.Forward(1, dx);
		f     = Value( Y[0] );
		df    = dy[0];
		return;
	}

	// evaulate the function and its derivative
	void fun(double x, double& f, double& df)
	{	if( use_ad )
			fun_ad(x, f, df);
		else
		{	f  = f_eval(x);
			df = df_direct(x);
		}
		return;
	}

	// run the multi-newton test once
	void test_once(CppAD::vector<double> &xout, size_t n_grid)
	{	assert( n_zero > 1 );
		double pi      = 4. * std::atan(1.);
		double xlow    = 0.;
		double xup     = (n_zero - 1) * pi;
		double epsilon = 1e-6;
		size_t max_itr = 20;

		multi_newton(
			xout    ,
			fun     ,
			n_grid  ,
			xlow    ,
			xup     ,
			epsilon ,
			max_itr
		);
		return;
	}

	// repeat the multi-newton test a specified number of times
	void test_repeat(size_t size, size_t repeat)
	{	size_t i;
		CppAD::vector<double> xout;
		for(i = 0; i < repeat; i++)
			test_once(xout, size);
		return;
	}

	size_t arg2size_t(
		const char* arg       ,
		bool automatic_ok     ,
		int limit             ,
		const char* error_msg )
	{	if( std::strcmp(arg, "automatic") == 0 )
		{	if( automatic_ok )
				return 0;
			std::cout << error_msg << std::endl;
			exit(1);
		}
		int i = std::atoi(arg);
		if( i >= limit )
			return size_t(i);
		std::cout << error_msg << std::endl;
		exit(1);
	}

}

int main(int argc, char *argv[])
{
	using std::cout;
	using std::endl;
	using CppAD::vector;

	const char *usage =
	"usage: multi_newton n_thread repeat n_zero n_grid n_sum use_ad";
	if( argc != 7 )
	{	std::cerr << usage << endl;
		exit(1);
	}
	argv++;

	// n_thread command line argument
	size_t n_thread = arg2size_t( *argv++, true, 1,
		"multi_newton: n_thread is less than or equal zero\n"
		"perhaps you want n_thread equal automatic"
	);

	// repeat command line argument
	size_t repeat = arg2size_t( *argv++, true, 1,
		"multi_newton: repeat is less than or equal zero\n"
		"perhaps you want repeat equal to automatic"
	);

	// n_zero command line argument
	n_zero = arg2size_t( *argv++, false, 2,
		"multi_newton: n_zero is less than or equal one\n"
		"or it is equal to automatic"
	);

	// n_grid command line argument
	size_t n_grid = arg2size_t( *argv++, false, 1,
		"multi_newton: n_grid is less than or equal zero\n"
		"or it is equal to automatic"
	);

	// n_sum command line argument
	n_sum = arg2size_t( *argv++, false, 1,
		"multi_netwon: n_sum is less than or equal zero\n"
		"or it si equal to automatic"
	);

	// use_ad
	if( std::strcmp(*argv, "true") == 0 )
		use_ad = true;
	else if( std::strcmp(*argv, "false") == 0 )
		use_ad = false;
	else
		std::cerr << "multi_newton: use_ad is not true or false" << endl;
	argv++;

# ifdef _OPENMP
	if( n_thread > 0 )
	{	omp_set_dynamic(0);                 // off dynamic thread adjust
		omp_set_num_threads(int(n_thread)); // set the number of threads
	}
	// now determine the maximum number of threads
	n_thread = size_t( omp_get_max_threads() );
	assert( n_thread > 0 );

	// No tapes are currently active,
	// so we can inform CppAD of the maximum number of threads
	CppAD::AD<double>::omp_max_thread(n_thread);

	// inform the user of the maximum number of threads
	cout << "OpenMP="     << _OPENMP;
# else
	cout << "OPENMP=\"\"";
	n_thread = 1;
# endif
	cout << ", n_thread=" << n_thread;
	cout << ", n_zero="   << n_zero;
	cout << ", n_grid="   << n_grid;
	cout << ", n_sum="    << n_sum;
	cout << ", use_ad="   << use_ad;
	cout << endl;

	// check that no memory is in use or avialable at start
	bool ok = true;
	size_t thread;
	for(thread = 0; thread < n_thread; thread++)
	{	ok &= CppAD::omp_alloc::inuse(thread) == 0;
		ok &= CppAD::omp_alloc::available(thread) == 0;
	}

	if( repeat > 0 )
	{	// run the calculation the requested number of times
		test_repeat(n_grid, repeat);
	}
	else
	{	// determine number of times to the calculation runs per second

		// size of the one test case
		vector<size_t> size_vec(1);
		size_vec[0] = n_grid;

		// minimum time for test (repeat until this much time)
		double time_min = 1.;

		// run the test case
		vector<size_t> rate_vec =
		CppAD::speed_test(test_repeat, size_vec, time_min);

		// report results
		cout << "repeats per sec  = " << rate_vec[0] << endl;
	}
	// print amount of memory each thread used
	cout << "omp_alloc::available = [ ";
	for(thread = 0; thread < n_thread; thread++)
	{	cout << CppAD::omp_alloc::available(thread);
		if( thread + 1 < n_thread )
			cout << ", ";
	}
	cout << " ]" << endl;

	// sub-block so xout is not in use when memory_leak is called.
	{	// Correctness test
		vector<double> xout;
		test_once(xout, n_grid);
		double epsilon = 1e-6;
		double pi      = 4. * std::atan(1.);
		ok            &= (xout.size() == n_zero);
		size_t i       = 0;
		while( ok & (i < n_zero) )
		{	ok &= std::fabs( xout[i] - pi * i) <= 2 * epsilon;
			++i;
		}
	}

	// check all the threads for a CppAD memory leak
	if( CppAD::memory_leak() )
	{	ok = false;
		cout << "Error: memory leak detected" << endl;
	}
	if( ok )
		cout << "Correctness Test = OK" << endl;
	else	cout << "Correctness Test = Error" << endl;

	return static_cast<int>( ! ok );
}

// END PROGRAM
<|endoftext|>


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

#include "chrome_frame/bho.h"

#include <shlguid.h>

#include "base/file_path.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/registry.h"
#include "base/scoped_bstr_win.h"
#include "base/scoped_variant_win.h"
#include "base/string_util.h"
#include "chrome_tab.h" // NOLINT
#include "chrome_frame/extra_system_apis.h"
#include "chrome_frame/http_negotiate.h"
#include "chrome_frame/protocol_sink_wrap.h"
#include "chrome_frame/urlmon_moniker.h"
#include "chrome_frame/utils.h"
#include "chrome_frame/vtable_patch_manager.h"

static const int kIBrowserServiceOnHttpEquivIndex = 30;

PatchHelper g_patch_helper;

BEGIN_VTABLE_PATCHES(IBrowserService)
  VTABLE_PATCH_ENTRY(kIBrowserServiceOnHttpEquivIndex, Bho::OnHttpEquiv)
END_VTABLE_PATCHES()

_ATL_FUNC_INFO Bho::kBeforeNavigate2Info = {
  CC_STDCALL, VT_EMPTY, 7, {
    VT_DISPATCH,
    VT_VARIANT | VT_BYREF,
    VT_VARIANT | VT_BYREF,
    VT_VARIANT | VT_BYREF,
    VT_VARIANT | VT_BYREF,
    VT_VARIANT | VT_BYREF,
    VT_BOOL | VT_BYREF
  }
};

_ATL_FUNC_INFO Bho::kNavigateComplete2Info = {
  CC_STDCALL, VT_EMPTY, 2, {
    VT_DISPATCH,
    VT_VARIANT | VT_BYREF
  }
};

Bho::Bho() {
}

HRESULT Bho::FinalConstruct() {
  return S_OK;
}

void Bho::FinalRelease() {
}

STDMETHODIMP Bho::SetSite(IUnknown* site) {
  HRESULT hr = S_OK;
  if (site) {
    ScopedComPtr<IWebBrowser2> web_browser2;
    web_browser2.QueryFrom(site);
    if (web_browser2) {
      hr = DispEventAdvise(web_browser2, &DIID_DWebBrowserEvents2);
      DCHECK(SUCCEEDED(hr)) << "DispEventAdvise failed. Error: " << hr;
    }

    if (g_patch_helper.state() == PatchHelper::PATCH_IBROWSER) {
      ScopedComPtr<IBrowserService> browser_service;
      hr = DoQueryService(SID_SShellBrowser, site, browser_service.Receive());
      DCHECK(browser_service) << "DoQueryService - SID_SShellBrowser failed."
          << " Site: " << site << " Error: " << hr;
      if (browser_service) {
        g_patch_helper.PatchBrowserService(browser_service);
        DCHECK(SUCCEEDED(hr)) << "vtable_patch::PatchInterfaceMethods failed."
            << " Site: " << site << " Error: " << hr;
      }
    }
    // Save away our BHO instance in TLS which enables it to be referenced by
    // our active document/activex instances to query referrer and other
    // information for a URL.
    AddRef();
    RegisterThreadInstance();
  } else {
    UnregisterThreadInstance();
    Release();
  }

  return IObjectWithSiteImpl<Bho>::SetSite(site);
}

STDMETHODIMP Bho::BeforeNavigate2(IDispatch* dispatch, VARIANT* url,
    VARIANT* flags, VARIANT* target_frame_name, VARIANT* post_data,
    VARIANT* headers, VARIANT_BOOL* cancel) {
  if (!url || url->vt != VT_BSTR || url->bstrVal == NULL) {
    DLOG(WARNING) << "Invalid URL passed in";
    return S_OK;
  }

  ScopedComPtr<IWebBrowser2> web_browser2;
  if (dispatch)
    web_browser2.QueryFrom(dispatch);

  if (!web_browser2) {
    NOTREACHED() << "Can't find WebBrowser2 with given dispatch";
    return S_OK;
  }

  DLOG(INFO) << "BeforeNavigate2: " << url->bstrVal;
  ScopedComPtr<IBrowserService> browser_service;
  DoQueryService(SID_SShellBrowser, web_browser2, browser_service.Receive());
  if (!browser_service || !CheckForCFNavigation(browser_service, false)) {
    referrer_.clear();
  }

  VARIANT_BOOL is_top_level = VARIANT_FALSE;
  web_browser2->get_TopLevelContainer(&is_top_level);
  if (is_top_level) {
    set_url(url->bstrVal);
    ProcessOptInUrls(web_browser2, url->bstrVal);
  }

  return S_OK;
}

STDMETHODIMP_(void) Bho::NavigateComplete2(IDispatch* dispatch, VARIANT* url) {
  DLOG(INFO) << __FUNCTION__;
}

namespace {

// See comments in Bho::OnHttpEquiv for details.
void ClearDocumentContents(IUnknown* browser) {
  ScopedComPtr<IWebBrowser2> web_browser2;
  if (SUCCEEDED(DoQueryService(SID_SWebBrowserApp, browser,
                               web_browser2.Receive()))) {
    ScopedComPtr<IDispatch> doc_disp;
    web_browser2->get_Document(doc_disp.Receive());
    ScopedComPtr<IHTMLDocument2> doc;
    if (doc_disp && SUCCEEDED(doc.QueryFrom(doc_disp))) {
      SAFEARRAY* sa = ::SafeArrayCreateVector(VT_UI1, 0, 0);
      doc->write(sa);
      ::SafeArrayDestroy(sa);
    }
  }
}

// Returns true if the currently loaded document in the browser has
// any embedded items such as a frame or an iframe.
bool DocumentHasEmbeddedItems(IUnknown* browser) {
  bool has_embedded_items = false;

  ScopedComPtr<IWebBrowser2> web_browser2;
  ScopedComPtr<IDispatch> document;
  if (SUCCEEDED(DoQueryService(SID_SWebBrowserApp, browser,
                               web_browser2.Receive())) &&
      SUCCEEDED(web_browser2->get_Document(document.Receive()))) {
    ScopedComPtr<IOleContainer> container;
    if (SUCCEEDED(container.QueryFrom(document))) {
      ScopedComPtr<IEnumUnknown> enumerator;
      container->EnumObjects(OLECONTF_EMBEDDINGS, enumerator.Receive());
      if (enumerator) {
        ScopedComPtr<IUnknown> unk;
        DWORD fetched = 0;
        while (!has_embedded_items &&
               SUCCEEDED(enumerator->Next(1, unk.Receive(), &fetched))
               && fetched) {
          // If a top level document has embedded iframes then the theory is
          // that first the top level document finishes loading and then the
          // iframes load. We should only treat an embedded element as an
          // iframe if it supports the IWebBrowser interface.
          ScopedComPtr<IWebBrowser2> embedded_web_browser2;
          if (SUCCEEDED(embedded_web_browser2.QueryFrom(unk))) {
            // If we initiate a top level navigation then at times MSHTML
            // creates a temporary IWebBrowser2 interface which basically shows
            // up as a temporary iframe in the parent document. It is not clear
            // as to how we can detect this. I tried the usual stuff like
            // getting to the parent IHTMLWindow2 interface. They all end up
            // pointing to dummy tear off interfaces owned by MSHTML.
            // As a temporary workaround, we found that the location url in
            // this case is about:blank. We now check for the same and don't
            // treat it as an iframe. This should be fine in most cases as we
            // hit this code only when the actual page has a meta tag. However
            // this would break for cases like the initial src url for an
            // iframe pointing to about:blank and the page then writing to it
            // via document.write.
            // TODO(ananta)
            // Revisit this and come up with a better approach.
            ScopedBstr location_url;
            embedded_web_browser2->get_LocationURL(location_url.Receive());

            std::wstring location_url_string;
            location_url_string.assign(location_url, location_url.Length());

            if (!LowerCaseEqualsASCII(location_url_string, "about:blank")) {
              has_embedded_items = true;
            }
          }

          fetched = 0;
          unk.Release();
        }
      }
    }
  }

  return has_embedded_items;
}

}  // end namespace

HRESULT Bho::OnHttpEquiv(IBrowserService_OnHttpEquiv_Fn original_httpequiv,
    IBrowserService* browser, IShellView* shell_view, BOOL done,
    VARIANT* in_arg, VARIANT* out_arg) {
  DLOG(INFO) << __FUNCTION__ << " done:" << done;

  // OnHttpEquiv with 'done' set to TRUE is called for all pages.
  // 0 or more calls with done set to FALSE are made.
  // When done is FALSE, the current moniker may not represent the page
  // being navigated to so we always have to wait for done to be TRUE
  // before re-initiating the navigation.

  if (!done && in_arg && VT_BSTR == V_VT(in_arg)) {
    if (StrStrI(V_BSTR(in_arg), kChromeContentPrefix)) {
      // OnHttpEquiv is invoked for meta tags within sub frames as well.
      // We want to switch renderers only for the top level frame.
      // The theory here is that if there are any existing embedded items
      // (frames or iframes) in the current document, then the http-equiv
      // notification is coming from those and not the top level document.
      // The embedded items should only be created once the top level
      // doc has been created.
      if (!DocumentHasEmbeddedItems(browser)) {
        NavigationManager* mgr = NavigationManager::GetThreadInstance();
        DCHECK(mgr);
        DLOG(INFO) << "Found tag in page. Marking browser." <<
            StringPrintf(" tid=0x%08X", ::GetCurrentThreadId());
        if (mgr) {
          // TODO(tommi): See if we can't figure out a cleaner way to avoid
          // this.  For some documents we can hit a problem here.  When we
          // attempt to navigate the document again in CF, mshtml can "complete"
          // the current navigation (if all data is available) and fire off
          // script events such as onload and even render the page.
          // This will happen inside NavigateBrowserToMoniker below.
          // To work around this, we clear the contents of the document before
          // opening it up in CF.
          ClearDocumentContents(browser);
          mgr->NavigateToCurrentUrlInCF(browser);
        }
      }
    }
  } else if (done) {
    DLOG(INFO) << "Releasing cached data.";
    NavigationManager* mgr = NavigationManager::GetThreadInstance();
    if (mgr)
      mgr->ReleaseRequestData();
  }

  return original_httpequiv(browser, shell_view, done, in_arg, out_arg);
}

// static
void Bho::ProcessOptInUrls(IWebBrowser2* browser, BSTR url) {
  if (!browser || !url) {
    NOTREACHED();
    return;
  }

#ifndef NDEBUG
  // This check must already have been made.
  VARIANT_BOOL is_top_level = VARIANT_FALSE;
  browser->get_TopLevelContainer(&is_top_level);
  DCHECK(is_top_level);
#endif

  std::wstring current_url(url, SysStringLen(url));
  if (IsValidUrlScheme(current_url, false)) {
    bool cf_protocol = StartsWith(current_url, kChromeProtocolPrefix, false);
    if (!cf_protocol && IsOptInUrl(current_url.c_str())) {
      DLOG(INFO) << "Opt-in URL. Switching to cf.";
      ScopedComPtr<IBrowserService> browser_service;
      DoQueryService(SID_SShellBrowser, browser, browser_service.Receive());
      DCHECK(browser_service) << "DoQueryService - SID_SShellBrowser failed.";
      MarkBrowserOnThreadForCFNavigation(browser_service);
    }
  }
}

namespace {
// Utility function that prevents the current module from ever being unloaded.
void PinModule() {
  FilePath module_path;
  if (PathService::Get(base::FILE_MODULE, &module_path)) {
    HMODULE unused;
    if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN,
                           module_path.value().c_str(), &unused)) {
      NOTREACHED() << "Failed to pin module " << module_path.value().c_str()
                   << " , last error: " << GetLastError();
    }
  } else {
    NOTREACHED() << "Could not get module path.";
  }
}
}  // namespace

bool PatchHelper::InitializeAndPatchProtocolsIfNeeded() {
  bool ret = false;

  _pAtlModule->m_csStaticDataInitAndTypeInfo.Lock();

  if (state_ == UNKNOWN) {
    // If we're going to start patching things, we'd better make sure that we
    // stick around for ever more:
    PinModule();

    HttpNegotiatePatch::Initialize();

    ProtocolPatchMethod patch_method =
        static_cast<ProtocolPatchMethod>(
            GetConfigInt(PATCH_METHOD_IBROWSER, kPatchProtocols));

    if (patch_method == PATCH_METHOD_INET_PROTOCOL) {
      ProtocolSinkWrap::PatchProtocolHandlers();
      state_ = PATCH_PROTOCOL;
    } else {
      DCHECK(patch_method == PATCH_METHOD_IBROWSER ||
             patch_method == PATCH_METHOD_IBROWSER_AND_MONIKER);
      state_ = PATCH_IBROWSER;
      if (patch_method == PATCH_METHOD_IBROWSER_AND_MONIKER) {
        MonikerPatch::Initialize();
      }
    }
    ret = true;
  }

  _pAtlModule->m_csStaticDataInitAndTypeInfo.Unlock();

  return ret;
}

void PatchHelper::PatchBrowserService(IBrowserService* browser_service) {
  DCHECK(state_ == PATCH_IBROWSER);
  if (!IS_PATCHED(IBrowserService)) {
    vtable_patch::PatchInterfaceMethods(browser_service,
                                        IBrowserService_PatchInfo);
  }
}

void PatchHelper::UnpatchIfNeeded() {
  if (state_ == PATCH_PROTOCOL) {
    ProtocolSinkWrap::UnpatchProtocolHandlers();
  } else if (state_ == PATCH_IBROWSER) {
    vtable_patch::UnpatchInterfaceMethods(IBrowserService_PatchInfo);
    MonikerPatch::Uninitialize();
  }

  HttpNegotiatePatch::Uninitialize();

  state_ = UNKNOWN;
}

<commit_msg>Enable the moniker patch by default.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome_frame/bho.h"

#include <shlguid.h>

#include "base/file_path.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/registry.h"
#include "base/scoped_bstr_win.h"
#include "base/scoped_variant_win.h"
#include "base/string_util.h"
#include "chrome_tab.h" // NOLINT
#include "chrome_frame/extra_system_apis.h"
#include "chrome_frame/http_negotiate.h"
#include "chrome_frame/protocol_sink_wrap.h"
#include "chrome_frame/urlmon_moniker.h"
#include "chrome_frame/utils.h"
#include "chrome_frame/vtable_patch_manager.h"

static const int kIBrowserServiceOnHttpEquivIndex = 30;

PatchHelper g_patch_helper;

BEGIN_VTABLE_PATCHES(IBrowserService)
  VTABLE_PATCH_ENTRY(kIBrowserServiceOnHttpEquivIndex, Bho::OnHttpEquiv)
END_VTABLE_PATCHES()

_ATL_FUNC_INFO Bho::kBeforeNavigate2Info = {
  CC_STDCALL, VT_EMPTY, 7, {
    VT_DISPATCH,
    VT_VARIANT | VT_BYREF,
    VT_VARIANT | VT_BYREF,
    VT_VARIANT | VT_BYREF,
    VT_VARIANT | VT_BYREF,
    VT_VARIANT | VT_BYREF,
    VT_BOOL | VT_BYREF
  }
};

_ATL_FUNC_INFO Bho::kNavigateComplete2Info = {
  CC_STDCALL, VT_EMPTY, 2, {
    VT_DISPATCH,
    VT_VARIANT | VT_BYREF
  }
};

Bho::Bho() {
}

HRESULT Bho::FinalConstruct() {
  return S_OK;
}

void Bho::FinalRelease() {
}

STDMETHODIMP Bho::SetSite(IUnknown* site) {
  HRESULT hr = S_OK;
  if (site) {
    ScopedComPtr<IWebBrowser2> web_browser2;
    web_browser2.QueryFrom(site);
    if (web_browser2) {
      hr = DispEventAdvise(web_browser2, &DIID_DWebBrowserEvents2);
      DCHECK(SUCCEEDED(hr)) << "DispEventAdvise failed. Error: " << hr;
    }

    if (g_patch_helper.state() == PatchHelper::PATCH_IBROWSER) {
      ScopedComPtr<IBrowserService> browser_service;
      hr = DoQueryService(SID_SShellBrowser, site, browser_service.Receive());
      DCHECK(browser_service) << "DoQueryService - SID_SShellBrowser failed."
          << " Site: " << site << " Error: " << hr;
      if (browser_service) {
        g_patch_helper.PatchBrowserService(browser_service);
        DCHECK(SUCCEEDED(hr)) << "vtable_patch::PatchInterfaceMethods failed."
            << " Site: " << site << " Error: " << hr;
      }
    }
    // Save away our BHO instance in TLS which enables it to be referenced by
    // our active document/activex instances to query referrer and other
    // information for a URL.
    AddRef();
    RegisterThreadInstance();
  } else {
    UnregisterThreadInstance();
    Release();
  }

  return IObjectWithSiteImpl<Bho>::SetSite(site);
}

STDMETHODIMP Bho::BeforeNavigate2(IDispatch* dispatch, VARIANT* url,
    VARIANT* flags, VARIANT* target_frame_name, VARIANT* post_data,
    VARIANT* headers, VARIANT_BOOL* cancel) {
  if (!url || url->vt != VT_BSTR || url->bstrVal == NULL) {
    DLOG(WARNING) << "Invalid URL passed in";
    return S_OK;
  }

  ScopedComPtr<IWebBrowser2> web_browser2;
  if (dispatch)
    web_browser2.QueryFrom(dispatch);

  if (!web_browser2) {
    NOTREACHED() << "Can't find WebBrowser2 with given dispatch";
    return S_OK;
  }

  DLOG(INFO) << "BeforeNavigate2: " << url->bstrVal;
  ScopedComPtr<IBrowserService> browser_service;
  DoQueryService(SID_SShellBrowser, web_browser2, browser_service.Receive());
  if (!browser_service || !CheckForCFNavigation(browser_service, false)) {
    referrer_.clear();
  }

  VARIANT_BOOL is_top_level = VARIANT_FALSE;
  web_browser2->get_TopLevelContainer(&is_top_level);
  if (is_top_level) {
    set_url(url->bstrVal);
    ProcessOptInUrls(web_browser2, url->bstrVal);
  }

  return S_OK;
}

STDMETHODIMP_(void) Bho::NavigateComplete2(IDispatch* dispatch, VARIANT* url) {
  DLOG(INFO) << __FUNCTION__;
}

namespace {

// See comments in Bho::OnHttpEquiv for details.
void ClearDocumentContents(IUnknown* browser) {
  ScopedComPtr<IWebBrowser2> web_browser2;
  if (SUCCEEDED(DoQueryService(SID_SWebBrowserApp, browser,
                               web_browser2.Receive()))) {
    ScopedComPtr<IDispatch> doc_disp;
    web_browser2->get_Document(doc_disp.Receive());
    ScopedComPtr<IHTMLDocument2> doc;
    if (doc_disp && SUCCEEDED(doc.QueryFrom(doc_disp))) {
      SAFEARRAY* sa = ::SafeArrayCreateVector(VT_UI1, 0, 0);
      doc->write(sa);
      ::SafeArrayDestroy(sa);
    }
  }
}

// Returns true if the currently loaded document in the browser has
// any embedded items such as a frame or an iframe.
bool DocumentHasEmbeddedItems(IUnknown* browser) {
  bool has_embedded_items = false;

  ScopedComPtr<IWebBrowser2> web_browser2;
  ScopedComPtr<IDispatch> document;
  if (SUCCEEDED(DoQueryService(SID_SWebBrowserApp, browser,
                               web_browser2.Receive())) &&
      SUCCEEDED(web_browser2->get_Document(document.Receive()))) {
    ScopedComPtr<IOleContainer> container;
    if (SUCCEEDED(container.QueryFrom(document))) {
      ScopedComPtr<IEnumUnknown> enumerator;
      container->EnumObjects(OLECONTF_EMBEDDINGS, enumerator.Receive());
      if (enumerator) {
        ScopedComPtr<IUnknown> unk;
        DWORD fetched = 0;
        while (!has_embedded_items &&
               SUCCEEDED(enumerator->Next(1, unk.Receive(), &fetched))
               && fetched) {
          // If a top level document has embedded iframes then the theory is
          // that first the top level document finishes loading and then the
          // iframes load. We should only treat an embedded element as an
          // iframe if it supports the IWebBrowser interface.
          ScopedComPtr<IWebBrowser2> embedded_web_browser2;
          if (SUCCEEDED(embedded_web_browser2.QueryFrom(unk))) {
            // If we initiate a top level navigation then at times MSHTML
            // creates a temporary IWebBrowser2 interface which basically shows
            // up as a temporary iframe in the parent document. It is not clear
            // as to how we can detect this. I tried the usual stuff like
            // getting to the parent IHTMLWindow2 interface. They all end up
            // pointing to dummy tear off interfaces owned by MSHTML.
            // As a temporary workaround, we found that the location url in
            // this case is about:blank. We now check for the same and don't
            // treat it as an iframe. This should be fine in most cases as we
            // hit this code only when the actual page has a meta tag. However
            // this would break for cases like the initial src url for an
            // iframe pointing to about:blank and the page then writing to it
            // via document.write.
            // TODO(ananta)
            // Revisit this and come up with a better approach.
            ScopedBstr location_url;
            embedded_web_browser2->get_LocationURL(location_url.Receive());

            std::wstring location_url_string;
            location_url_string.assign(location_url, location_url.Length());

            if (!LowerCaseEqualsASCII(location_url_string, "about:blank")) {
              has_embedded_items = true;
            }
          }

          fetched = 0;
          unk.Release();
        }
      }
    }
  }

  return has_embedded_items;
}

}  // end namespace

HRESULT Bho::OnHttpEquiv(IBrowserService_OnHttpEquiv_Fn original_httpequiv,
    IBrowserService* browser, IShellView* shell_view, BOOL done,
    VARIANT* in_arg, VARIANT* out_arg) {
  DLOG(INFO) << __FUNCTION__ << " done:" << done;

  // OnHttpEquiv with 'done' set to TRUE is called for all pages.
  // 0 or more calls with done set to FALSE are made.
  // When done is FALSE, the current moniker may not represent the page
  // being navigated to so we always have to wait for done to be TRUE
  // before re-initiating the navigation.

  if (!done && in_arg && VT_BSTR == V_VT(in_arg)) {
    if (StrStrI(V_BSTR(in_arg), kChromeContentPrefix)) {
      // OnHttpEquiv is invoked for meta tags within sub frames as well.
      // We want to switch renderers only for the top level frame.
      // The theory here is that if there are any existing embedded items
      // (frames or iframes) in the current document, then the http-equiv
      // notification is coming from those and not the top level document.
      // The embedded items should only be created once the top level
      // doc has been created.
      if (!DocumentHasEmbeddedItems(browser)) {
        NavigationManager* mgr = NavigationManager::GetThreadInstance();
        DCHECK(mgr);
        DLOG(INFO) << "Found tag in page. Marking browser." <<
            StringPrintf(" tid=0x%08X", ::GetCurrentThreadId());
        if (mgr) {
          // TODO(tommi): See if we can't figure out a cleaner way to avoid
          // this.  For some documents we can hit a problem here.  When we
          // attempt to navigate the document again in CF, mshtml can "complete"
          // the current navigation (if all data is available) and fire off
          // script events such as onload and even render the page.
          // This will happen inside NavigateBrowserToMoniker below.
          // To work around this, we clear the contents of the document before
          // opening it up in CF.
          ClearDocumentContents(browser);
          mgr->NavigateToCurrentUrlInCF(browser);
        }
      }
    }
  } else if (done) {
    DLOG(INFO) << "Releasing cached data.";
    NavigationManager* mgr = NavigationManager::GetThreadInstance();
    if (mgr)
      mgr->ReleaseRequestData();
  }

  return original_httpequiv(browser, shell_view, done, in_arg, out_arg);
}

// static
void Bho::ProcessOptInUrls(IWebBrowser2* browser, BSTR url) {
  if (!browser || !url) {
    NOTREACHED();
    return;
  }

#ifndef NDEBUG
  // This check must already have been made.
  VARIANT_BOOL is_top_level = VARIANT_FALSE;
  browser->get_TopLevelContainer(&is_top_level);
  DCHECK(is_top_level);
#endif

  std::wstring current_url(url, SysStringLen(url));
  if (IsValidUrlScheme(current_url, false)) {
    bool cf_protocol = StartsWith(current_url, kChromeProtocolPrefix, false);
    if (!cf_protocol && IsOptInUrl(current_url.c_str())) {
      DLOG(INFO) << "Opt-in URL. Switching to cf.";
      ScopedComPtr<IBrowserService> browser_service;
      DoQueryService(SID_SShellBrowser, browser, browser_service.Receive());
      DCHECK(browser_service) << "DoQueryService - SID_SShellBrowser failed.";
      MarkBrowserOnThreadForCFNavigation(browser_service);
    }
  }
}

namespace {
// Utility function that prevents the current module from ever being unloaded.
void PinModule() {
  FilePath module_path;
  if (PathService::Get(base::FILE_MODULE, &module_path)) {
    HMODULE unused;
    if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN,
                           module_path.value().c_str(), &unused)) {
      NOTREACHED() << "Failed to pin module " << module_path.value().c_str()
                   << " , last error: " << GetLastError();
    }
  } else {
    NOTREACHED() << "Could not get module path.";
  }
}
}  // namespace

bool PatchHelper::InitializeAndPatchProtocolsIfNeeded() {
  bool ret = false;

  _pAtlModule->m_csStaticDataInitAndTypeInfo.Lock();

  if (state_ == UNKNOWN) {
    // If we're going to start patching things, we'd better make sure that we
    // stick around for ever more:
    PinModule();

    HttpNegotiatePatch::Initialize();

    ProtocolPatchMethod patch_method =
        static_cast<ProtocolPatchMethod>(
            GetConfigInt(PATCH_METHOD_IBROWSER_AND_MONIKER, kPatchProtocols));

    if (patch_method == PATCH_METHOD_INET_PROTOCOL) {
      ProtocolSinkWrap::PatchProtocolHandlers();
      state_ = PATCH_PROTOCOL;
    } else {
      DCHECK(patch_method == PATCH_METHOD_IBROWSER ||
             patch_method == PATCH_METHOD_IBROWSER_AND_MONIKER);
      state_ = PATCH_IBROWSER;
      if (patch_method == PATCH_METHOD_IBROWSER_AND_MONIKER) {
        MonikerPatch::Initialize();
      }
    }
    ret = true;
  }

  _pAtlModule->m_csStaticDataInitAndTypeInfo.Unlock();

  return ret;
}

void PatchHelper::PatchBrowserService(IBrowserService* browser_service) {
  DCHECK(state_ == PATCH_IBROWSER);
  if (!IS_PATCHED(IBrowserService)) {
    vtable_patch::PatchInterfaceMethods(browser_service,
                                        IBrowserService_PatchInfo);
  }
}

void PatchHelper::UnpatchIfNeeded() {
  if (state_ == PATCH_PROTOCOL) {
    ProtocolSinkWrap::UnpatchProtocolHandlers();
  } else if (state_ == PATCH_IBROWSER) {
    vtable_patch::UnpatchInterfaceMethods(IBrowserService_PatchInfo);
    MonikerPatch::Uninitialize();
  }

  HttpNegotiatePatch::Uninitialize();

  state_ = UNKNOWN;
}

<|endoftext|>


<commit_before><commit_msg>commit as CREATE/DESTROY<commit_after><|endoftext|>


<commit_before>#include "GateTask.hpp"
#include "Robosub/ModuleEnableMsg.h"
#include "Robosub/Point.h"
#include "std_msgs/String.h"
#include <stdio.h>
#include <math.h>
#include <float.h>

GateTask::GateTask()
 : m_nodeHandle(),
   m_gateSubscriber(),
   m_taskStateSubscriber(),
   m_centerPointPublisher(),
   m_taskCompletePublisher(),
   m_highLevelMotorPublisher(),
   m_isEnabled(false),
   m_identifiedCenter(false),
   m_haveBothLegs(false),
   m_center(),
   m_zeroth(),
   m_lastId(-1)
{
  m_gateSubscriber = m_nodeHandle.subscribe("img_rec/gate", 10, &GateTask::gateCallback, this);
  m_taskStateSubscriber = m_nodeHandle.subscribe("Module_Enable", 10, &GateTask::moduleEnableCallback, this);
  m_centerPointPublisher = m_nodeHandle.advertise<Robosub::Point>("Center_On_Point", 10);
  m_taskCompletePublisher = m_nodeHandle.advertise<std_msgs::String>("Task_Completion", 10);
  m_highLevelMotorPublisher = m_nodeHandle.advertise<Robosub::HighLevelControl>("High_Level_Motion", 10);
}

GateTask::~GateTask()
{

}

void GateTask::run()
{
  while (ros::ok())
  {
    ros::spin();
  }
}

void GateTask::moduleEnableCallback(const Robosub::ModuleEnableMsg& msg)
{
  if (msg.Module == "GateTask")
  {
    if (msg.State == true)
    {
      printf("GateTask: enabled\n");
      m_isEnabled = true;
      m_identifiedCenter = m_haveBothLegs = false;
    }
    else
    {
      printf("GateTask: Disabled\n");
      m_isEnabled = false;
    }
  }
}

void GateTask::gateCallback(const SubImageRecognition::ImgRecObject& msg)
{
  if (m_isEnabled)
  {
    if (m_identifiedCenter && m_lastId == msg.id)
    {
      //then we see a section of the gate. Identify its position in the screen and move it out of screen (turn)
      float dir = 2.0f;
      dir *= msg.center_x > 0.0f ? 1.0f : -1.0f;
      printf("Turning2 by %f\n", dir);
      publishMotor("Turn", "Offset", dir);
    }
    else
    {
      if (msg.id == 0)
      {
        m_zeroth = msg;
      }

      if (m_lastId == msg.id)
      {
        //dont have two, turn away
        float dir = 2.0f;
        dir *= msg.center_x > 0.0f ? 1.0f : -1.0f;
        printf("Turning3 by %f\n", dir);
        publishMotor("Turn", "Offset", dir);
      }
      else if (msg.id != 0)
      {
        //have both, calculate center
        m_center.center_x = (m_zeroth.center_x + msg.center_x)/2;
        m_center.center_y = m_zeroth.center_y + msg.center_y;
        m_identifiedCenter = true;

        if (m_center.center_x < -10.0f || m_center.center_x > 10.0f)
        {
          printf("Turning by %f\n", m_center.center_x);
          publishMotor("Turn", "Offset", m_center.center_x);
          //possibly turn off forward
        }
        else
        {
          float straight = etDistance(msg.width, 3.0f)*1.75;
          printf("Forward by %f\n", straight);
          publishMotor("Forward", "Offset", straight);
        }
      }
    }
    m_lastId = msg.id;
  }
}

/**
 * @brief Calcualte the distance the center of the object is off from the center of the camera in inches
 *
 * @param centerDir The current center direction
 * @param width The width of the object
 *
 * @return The distance in inches
 */
float GateTask::calculateDistanceFromCenter(float centerDir, float width)
{
  float pxlPerInch = getPixelsPerInch(width, 3.0f);
  return centerDir * pxlPerInch;
}

/**
 * @brief Get the number of pixels per inch
 *
 * @param curWidthPixels The current width of a known object in pixels
 * @param expectedWidthInches The expected with of an object in inches
 *
 * @return The number of pixels per inch if everything goes well, or float_max if inputs were unacceptable
 */
float GateTask::getPixelsPerInch(float curWidthPixels, float expectedWidthInches)
{
  float dist = getDistance(curWidthPixels, expectedWidthInches);
  return curWidthPixels/dist;
}

/**
 * @brief Calculate the distance to the object
 *
 * @param curObjSize The objects current size
 * @param actualObjSize The objects expected size
 *
 * @return The distance
 */
float GateTask::getDistance(float curObjSize, float actualObjSize)
{
  return (actualObjSize/(2.0f*tan(((curObjSize * (M_PI/3.0))/960.0f))));
}

/**
 * @brief plubish to the high level motor controller topic
 *
 * @param direction The direction: Forward, Straf, Turn
 * @param motion The motion type: Manual, Offset
 * @param value The value
 */
void GateTask::publishMotor(std::string direction, std::string motion, float value)
{
  Robosub::HighLevelControl msg;
  msg.Direction = direction;
  msg.MotionType = motion;
  msg.Value = value;

  m_highLevelMotorPublisher.publish(msg);
}
<commit_msg>fixed GateTask not compiling<commit_after>#include "GateTask.hpp"
#include "Robosub/ModuleEnableMsg.h"
#include "Robosub/Point.h"
#include "std_msgs/String.h"
#include <stdio.h>
#include <math.h>
#include <float.h>

GateTask::GateTask()
 : m_nodeHandle(),
   m_gateSubscriber(),
   m_taskStateSubscriber(),
   m_centerPointPublisher(),
   m_taskCompletePublisher(),
   m_highLevelMotorPublisher(),
   m_isEnabled(false),
   m_identifiedCenter(false),
   m_haveBothLegs(false),
   m_center(),
   m_zeroth(),
   m_lastId(-1)
{
  m_gateSubscriber = m_nodeHandle.subscribe("img_rec/gate", 10, &GateTask::gateCallback, this);
  m_taskStateSubscriber = m_nodeHandle.subscribe("Module_Enable", 10, &GateTask::moduleEnableCallback, this);
  m_centerPointPublisher = m_nodeHandle.advertise<Robosub::Point>("Center_On_Point", 10);
  m_taskCompletePublisher = m_nodeHandle.advertise<std_msgs::String>("Task_Completion", 10);
  m_highLevelMotorPublisher = m_nodeHandle.advertise<Robosub::HighLevelControl>("High_Level_Motion", 10);
}

GateTask::~GateTask()
{

}

void GateTask::run()
{
  while (ros::ok())
  {
    ros::spin();
  }
}

void GateTask::moduleEnableCallback(const Robosub::ModuleEnableMsg& msg)
{
  if (msg.Module == "GateTask")
  {
    if (msg.State == true)
    {
      printf("GateTask: enabled\n");
      m_isEnabled = true;
      m_identifiedCenter = m_haveBothLegs = false;
    }
    else
    {
      printf("GateTask: Disabled\n");
      m_isEnabled = false;
    }
  }
}

void GateTask::gateCallback(const SubImageRecognition::ImgRecObject& msg)
{
  if (m_isEnabled)
  {
    if (m_identifiedCenter && m_lastId == msg.id)
    {
      //then we see a section of the gate. Identify its position in the screen and move it out of screen (turn)
      float dir = 2.0f;
      dir *= msg.center_x > 0.0f ? 1.0f : -1.0f;
      printf("Turning2 by %f\n", dir);
      publishMotor("Turn", "Offset", dir);
    }
    else
    {
      if (msg.id == 0)
      {
        m_zeroth = msg;
      }

      if (m_lastId == msg.id)
      {
        //dont have two, turn away
        float dir = 2.0f;
        dir *= msg.center_x > 0.0f ? 1.0f : -1.0f;
        printf("Turning3 by %f\n", dir);
        publishMotor("Turn", "Offset", dir);
      }
      else if (msg.id != 0)
      {
        //have both, calculate center
        m_center.center_x = (m_zeroth.center_x + msg.center_x)/2;
        m_center.center_y = m_zeroth.center_y + msg.center_y;
        m_identifiedCenter = true;

        if (m_center.center_x < -10 || m_center.center_x > 10)
        {
          printf("Turning by %d\n", m_center.center_x);
          publishMotor("Turn", "Offset", m_center.center_x);
          //possibly turn off forward
        }
        else
        {
          float straight = getDistance(msg.width, 3.0f)*1.75;
          printf("Forward by %f\n", straight);
          publishMotor("Forward", "Offset", straight);
        }
      }
    }
    m_lastId = msg.id;
  }
}

/**
 * @brief Calculate the distance the center of the object is off from the center of the camera in inches
 *
 * @param centerDir The current center direction
 * @param width The width of the object
 *
 * @return The distance in inches
 */
float GateTask::calculateDistanceFromCenter(float centerDir, float width)
{
  float pxlPerInch = getPixelsPerInch(width, 3.0f);
  return centerDir * pxlPerInch;
}

/**
 * @brief Get the number of pixels per inch
 *
 * @param curWidthPixels The current width of a known object in pixels
 * @param expectedWidthInches The expected with of an object in inches
 *
 * @return The number of pixels per inch if everything goes well, or float_max if inputs were unacceptable
 */
float GateTask::getPixelsPerInch(float curWidthPixels, float expectedWidthInches)
{
  float dist = getDistance(curWidthPixels, expectedWidthInches);
  return curWidthPixels/dist;
}

/**
 * @brief Calculate the distance to the object
 *
 * @param curObjSize The objects current size
 * @param actualObjSize The objects expected size
 *
 * @return The distance
 */
float GateTask::getDistance(float curObjSize, float actualObjSize)
{
  return (actualObjSize/(2.0f*tan(((curObjSize * (M_PI/3.0))/960.0f))));
}

/**
 * @brief plubish to the high level motor controller topic
 *
 * @param direction The direction: Forward, Straf, Turn
 * @param motion The motion type: Manual, Offset
 * @param value The value
 */
void GateTask::publishMotor(std::string direction, std::string motion, float value)
{
  Robosub::HighLevelControl msg;
  msg.Direction = direction;
  msg.MotionType = motion;
  msg.Value = value;

  m_highLevelMotorPublisher.publish(msg);
}
<|endoftext|>