<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: dbgloop.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-16 21:09:10 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"

#ifdef PRODUCT
#error Wer fummelt denn an den makefiles rum?
#endif

#ifndef _STREAM_HXX //autogen
#include <tools/stream.hxx>
#endif
#include "dbgloop.hxx"
#include "errhdl.hxx"

DbgLoopStack DbgLoop::aDbgLoopStack;

/*************************************************************************
 *                      class DbgLoopStack
 *************************************************************************/

DbgLoopStack::DbgLoopStack()
{
    Reset();
}

void DbgLoopStack::Reset()
{
    nPtr = 0;
    pDbg = 0;
    for( USHORT i = 0; i < DBG_MAX_STACK; ++i )
        aCount[i] = 0;
}

/*************************************************************************
 *                       DbgLoopStack::Push()
 *************************************************************************/

void DbgLoopStack::Push( const void *pThis )
{
    // Wir muessen irgendwie mitbekommen, wann die erste Stackposition
    // resettet werden soll, z.B. wenn wir einen Nullpointer uebergeben
    if( !nPtr && ( pDbg != pThis || !pThis ) )
    {
        aCount[1] = 0;
        pDbg = pThis;
    }

    ++nPtr;
    if( DBG_MAX_STACK > nPtr )
    {
        // Wenn eine loop entdeckt wird, wird der counter wieder zurueckgesetzt.
        ASSERT( DBG_MAX_LOOP > aCount[nPtr], "DbgLoopStack::Push: loop detected" );
        if( DBG_MAX_LOOP > aCount[nPtr] )
            ++(aCount[nPtr]);
        else
            aCount[nPtr] = 0;
    }
}

/*************************************************************************
 *                       DbgLoopStack::Pop()
 *************************************************************************/

void DbgLoopStack::Pop()
{
    if( DBG_MAX_STACK > nPtr )
    {
        ASSERT( nPtr, "DbgLoopStack::Pop: can't pop the stack" );

        ASSERT( aCount[nPtr], "DbgLoopStack::Pop: can't dec the count" );
        if( DBG_MAX_STACK > nPtr + 1 )
            aCount[nPtr + 1] = 0;
    }
    --nPtr;
}

/*************************************************************************
 *                       DbgLoopStack::Print()
 *************************************************************************/

void DbgLoopStack::Print( SvStream &rOS ) const
{
    rOS << "POS: " << nPtr << '\n';
    USHORT i;
    for( i = 0; i < DBG_MAX_STACK; ++i )
        rOS << i << " ";
    rOS << '\n';
    for( i = 0; i < DBG_MAX_STACK; ++i )
        rOS << aCount[i] << " ";
    rOS << '\n';
}

#ifdef STAND_ALONE
// compile with: cl /AL /DSTAND_ALONE dbgloop.cxx

/*************************************************************************
 *                          main()
 *************************************************************************/

#include <stdlib.h>

void AssertFail( const char *pErr, const char *pFile, USHORT nLine )
{
    cout << pErr << '\n';
    PrintLoopStack( cout );
    exit(0);
}

class Test
{
public:
        void Run() const;
};

void Test::Run() const
{
    cout << "---" << '\n';
    for( USHORT i = 0; i < 10; ++i )
    {
        cout << "i" << i;
        DBG_LOOP;
        PrintLoopStack( cout );
        for( USHORT j = 0; j < 10; ++j )
        {
            cout << " j" << j;
            DBG_LOOP;
            PrintLoopStack( cout );
        }
        cout << '\n';
    }
    PrintLoopStack( cout );
}

int main()
{
    // unterschiedliche Instanzen waehlen wg. pDbg != pThis
    Test aTest1;
    aTest1.Run();
    Test aTest2;
    aTest2.Run();
    return 0;
}
#endif

<commit_msg>INTEGRATION: CWS changefileheader (1.4.718); FILE MERGED 2008/04/01 15:57:04 thb 1.4.718.2: #i85898# Stripping all external header guards 2008/03/31 16:54:04 rt 1.4.718.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: dbgloop.cxx,v $
 * $Revision: 1.5 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"

#ifdef PRODUCT
#error Wer fummelt denn an den makefiles rum?
#endif
#include <tools/stream.hxx>
#include "dbgloop.hxx"
#include "errhdl.hxx"

DbgLoopStack DbgLoop::aDbgLoopStack;

/*************************************************************************
 *                      class DbgLoopStack
 *************************************************************************/

DbgLoopStack::DbgLoopStack()
{
    Reset();
}

void DbgLoopStack::Reset()
{
    nPtr = 0;
    pDbg = 0;
    for( USHORT i = 0; i < DBG_MAX_STACK; ++i )
        aCount[i] = 0;
}

/*************************************************************************
 *                       DbgLoopStack::Push()
 *************************************************************************/

void DbgLoopStack::Push( const void *pThis )
{
    // Wir muessen irgendwie mitbekommen, wann die erste Stackposition
    // resettet werden soll, z.B. wenn wir einen Nullpointer uebergeben
    if( !nPtr && ( pDbg != pThis || !pThis ) )
    {
        aCount[1] = 0;
        pDbg = pThis;
    }

    ++nPtr;
    if( DBG_MAX_STACK > nPtr )
    {
        // Wenn eine loop entdeckt wird, wird der counter wieder zurueckgesetzt.
        ASSERT( DBG_MAX_LOOP > aCount[nPtr], "DbgLoopStack::Push: loop detected" );
        if( DBG_MAX_LOOP > aCount[nPtr] )
            ++(aCount[nPtr]);
        else
            aCount[nPtr] = 0;
    }
}

/*************************************************************************
 *                       DbgLoopStack::Pop()
 *************************************************************************/

void DbgLoopStack::Pop()
{
    if( DBG_MAX_STACK > nPtr )
    {
        ASSERT( nPtr, "DbgLoopStack::Pop: can't pop the stack" );

        ASSERT( aCount[nPtr], "DbgLoopStack::Pop: can't dec the count" );
        if( DBG_MAX_STACK > nPtr + 1 )
            aCount[nPtr + 1] = 0;
    }
    --nPtr;
}

/*************************************************************************
 *                       DbgLoopStack::Print()
 *************************************************************************/

void DbgLoopStack::Print( SvStream &rOS ) const
{
    rOS << "POS: " << nPtr << '\n';
    USHORT i;
    for( i = 0; i < DBG_MAX_STACK; ++i )
        rOS << i << " ";
    rOS << '\n';
    for( i = 0; i < DBG_MAX_STACK; ++i )
        rOS << aCount[i] << " ";
    rOS << '\n';
}

#ifdef STAND_ALONE
// compile with: cl /AL /DSTAND_ALONE dbgloop.cxx

/*************************************************************************
 *                          main()
 *************************************************************************/

#include <stdlib.h>

void AssertFail( const char *pErr, const char *pFile, USHORT nLine )
{
    cout << pErr << '\n';
    PrintLoopStack( cout );
    exit(0);
}

class Test
{
public:
        void Run() const;
};

void Test::Run() const
{
    cout << "---" << '\n';
    for( USHORT i = 0; i < 10; ++i )
    {
        cout << "i" << i;
        DBG_LOOP;
        PrintLoopStack( cout );
        for( USHORT j = 0; j < 10; ++j )
        {
            cout << " j" << j;
            DBG_LOOP;
            PrintLoopStack( cout );
        }
        cout << '\n';
    }
    PrintLoopStack( cout );
}

int main()
{
    // unterschiedliche Instanzen waehlen wg. pDbg != pThis
    Test aTest1;
    aTest1.Run();
    Test aTest2;
    aTest2.Run();
    return 0;
}
#endif

<|endoftext|>


<commit_before>// Given an input string, reverse the string word by word.
// For example,
// Given s = "the sky is blue",
// return "blue is sky the".
// Update (2015-02-12):
// For C programmers: Try to solve it in-place in O(1) space.
// click to show clarification.
// Clarification:
//     What constitutes a word?
//     A sequence of non-space characters constitutes a word.
//     Could the input string contain leading or trailing spaces?
//     Yes. However, your reversed string should not contain leading or trailing
//     spaces.
//     How about multiple spaces between two words?
//     Reduce them to a single space in the reversed string.

class Solution {
  public:
    void reverseWords(string &s) {
        int i, j;

        // remove spaces at head and tail
        i = 0;
        j = s.size() - 1;
        while (i < s.size() && s[i] == ' ')
            ++i;
        while (j >= 0 && s[j] == ' ')
            --j;
        s = j >= i ? s.substr(i, j - i + 1) : "";

        // remove continuous spaces
        i = 0;
        while (i < s.size() && s[i] != ' ')
            ++i;
        do {
            j = ++i; // second space
            while (j < s.size() && s[j] == ' ')
                ++j;
            while (j < s.size() && s[j] != ' ')
                swap(s[i++], s[j++]);
            // now s[i] == ' ' or i == s.size()
        } while (j < s.size());
        s = s.substr(0, i);

        // reverse sentence
        i = 0;
        j = s.size() - 1;
        while (i < j)
            swap(s[i++], s[j--]);

        // reverse every word
        int k = 0;
        while (k < s.size()) {
            i = k;
            while (i < s.size() && s[i] == ' ')
                ++i;
            j = i;
            while (j < s.size() && s[j] != ' ')
                ++j;
            k = j;
            --j;
            while (i < j)
                swap(s[i++], s[j--]);
        }

        // finish
    }
};<commit_msg>update 151<commit_after>// Given an input string, reverse the string word by word.
// For example,
// Given s = "the sky is blue",
// return "blue is sky the".
// Update (2015-02-12):
// For C programmers: Try to solve it in-place in O(1) space.
// click to show clarification.
// Clarification:
//     What constitutes a word?
//     A sequence of non-space characters constitutes a word.
//     Could the input string contain leading or trailing spaces?
//     Yes. However, your reversed string should not contain leading or trailing
//     spaces.
//     How about multiple spaces between two words?
//     Reduce them to a single space in the reversed string.

class Solution {
  public:
    void reverseWords(string &s) {
        int i, j;

        // remove continuous spaces
        // AND remove spaces at head and tail
        i = -1;
        do {
            j = i + 1; // second space
            while (j < s.size() && s[j] == ' ')
                ++j;
            if (j != s.size())
                ++i;
            while (j < s.size() && s[j] != ' ')
                swap(s[i++], s[j++]);
            // now s[i] == ' ' or i == s.size()
        } while (j < s.size());
        s = i > 0 ? s.substr(0, i) : "";

        // reverse sentence
        i = 0;
        j = s.size() - 1;
        while (i < j)
            swap(s[i++], s[j--]);

        // reverse every word
        int k = 0;
        while (k < s.size()) {
            i = k;
            while (i < s.size() && s[i] == ' ')
                ++i;
            j = i;
            while (j < s.size() && s[j] != ' ')
                ++j;
            k = j;
            --j;
            while (i < j)
                swap(s[i++], s[j--]);
        }

        // finish
    }
};<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: wwstyles.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: kz $ $Date: 2003-12-09 11:41:27 $
 *
 *  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): _______________________________________
 *
 *
 ************************************************************************/

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
/// @HTML
#ifndef WW_WWSTYLES_HXX
#define WW_WWSTYLES_HXX

class String;       //yuck...

namespace ww
{
    enum sti
    {
        stiNormal = 0,                  // 0x0000
        stiLev1 = 1,                    // 0x0001
        stiLev2 = 2,                    // 0x0002
        stiLev3 = 3,                    // 0x0003
        stiLev4 = 4,                    // 0x0004
        stiLev5 = 5,                    // 0x0005
        stiLev6 = 6,                    // 0x0006
        stiLev7 = 7,                    // 0x0007
        stiLev8 = 8,                    // 0x0008
        stiLev9 = 9,                    // 0x0009
        stiLevFirst = stiLev1,
        stiLevLast = stiLev9,
        stiIndex1 = 10,                 // 0x000A
        stiIndex2 = 11,                 // 0x000B
        stiIndex3 = 12,                 // 0x000C
        stiIndex4 = 13,                 // 0x000D
        stiIndex5 = 14,                 // 0x000E
        stiIndex6 = 15,                 // 0x000F
        stiIndex7 = 16,                 // 0x0010
        stiIndex8 = 17,                 // 0x0011
        stiIndex9 = 18,                 // 0x0012
        stiIndexFirst = stiIndex1,
        stiIndexLast = stiIndex9,
        stiToc1 = 19,                   // 0x0013
        stiToc2 = 20,                   // 0x0014
        stiToc3 = 21,                   // 0x0015
        stiToc4 = 22,                   // 0x0016
        stiToc5 = 23,                   // 0x0017
        stiToc6 = 24,                   // 0x0018
        stiToc7 = 25,                   // 0x0019
        stiToc8 = 26,                   // 0x001A
        stiToc9 = 27,                   // 0x001B
        stiTocFirst = stiToc1,
        stiTocLast = stiToc9,
        stiNormIndent = 28,             // 0x001C
        stiFtnText = 29,                // 0x001D
        stiAtnText = 30,                // 0x001E
        stiHeader = 31,                 // 0x001F
        stiFooter = 32,                 // 0x0020
        stiIndexHeading = 33,           // 0x0021
        stiCaption = 34,                // 0x0022
        stiToCaption = 35,              // 0x0023
        stiEnvAddr = 36,                // 0x0024
        stiEnvRet = 37,                 // 0x0025
        stiFtnRef = 38,                 // 0x0026  char style
        stiAtnRef = 39,                 // 0x0027  char style
        stiLnn = 40,                    // 0x0028  char style
        stiPgn = 41,                    // 0x0029  char style
        stiEdnRef = 42,                 // 0x002A  char style
        stiEdnText = 43,                // 0x002B
        stiToa = 44,                    // 0x002C
        stiMacro = 45,                  // 0x002D
        stiToaHeading = 46,             // 0x002E
        stiList = 47,                   // 0x002F
        stiListBullet = 48,             // 0x0030
        stiListNumber = 49,             // 0x0031
        stiList2 = 50,                  // 0x0032
        stiList3 = 51,                  // 0x0033
        stiList4 = 52,                  // 0x0034
        stiList5 = 53,                  // 0x0035
        stiListBullet2 = 54,            // 0x0036
        stiListBullet3 = 55,            // 0x0037
        stiListBullet4 = 56,            // 0x0038
        stiListBullet5 = 57,            // 0x0039
        stiListNumber2 = 58,            // 0x003A
        stiListNumber3 = 59,            // 0x003B
        stiListNumber4 = 60,            // 0x003C
        stiListNumber5 = 61,            // 0x003D
        stiTitle = 62,                  // 0x003E
        stiClosing = 63,                // 0x003F
        stiSignature = 64,              // 0x0040
        stiNormalChar = 65,             // 0x0041  char style
        stiBodyText = 66,               // 0x0042
        /*
         stiBodyTextInd1 was orig stiBodyText2 in documentation, but that
         collides with the other stiBodyText2 and this seems more reasonable.
         cmc@openoffice.org
        */
        stiBodyTextInd1 = 67,           // 0x0043
        stiListCont = 68,               // 0x0044
        stiListCont2 = 69,              // 0x0045
        stiListCont3 = 70,              // 0x0046
        stiListCont4 = 71,              // 0x0047
        stiListCont5 = 72,              // 0x0048
        stiMsgHeader = 73,              // 0x0049
        stiSubtitle = 74,               // 0x004A
        stiSalutation = 75,             // 0x004B
        stiDate = 76,                   // 0X004C
        stiBodyText1I = 77,             // 0x004D
        stiBodyText1I2 = 78,            // 0x004E
        stiNoteHeading = 79,            // 0x004F
        stiBodyText2 = 80,              // 0x0050
        stiBodyText3 = 81,              // 0x0051
        stiBodyTextInd2 = 82,           // 0x0052
        stiBodyTextInd3 = 83,           // 0x0053
        stiBlockQuote = 84,             // 0x0054
        stiHyperlink = 85,              // 0x0055  char style
        stiHyperlinkFollowed = 86,      // 0x0056  char style
        stiStrong = 87,                 // 0x0057  char style
        stiEmphasis = 88,               // 0x0058  char style
        stiNavPane = 89,                // 0x0059  char style
        stiPlainText = 90,              // 0x005A
        stiMax = 91,                    // number of defined sti's
        stiUser = 0x0ffe,               // user styles are distinguished by name
        stiNil = 0x0fff                 // max for 12 bits
    };

    /** Find the WinWord sti index of an english style name.

        When importing a RTF document we would like to treat styles as similiar
        to how word does as possible, to this end word will treat some styles
        with special names as inbuilt styles, and some as user defined styles.

        See OpenOffice.org issue 21881
        (http://www.openoffice.org/issues/show_bug.cgi?id=21881)
        and OpenOffice.org issue 17503
        (http://www.openoffice.org/issues/show_bug.cgi?id=17503)

        @param
        rSting the Style name to test to see what winword sti word would give
        such a name if it has no other information to work with (e.g. importing
        a RTF document)

        @return the sti that word would give it. stiUser if word would treat
        it as a user defined style.

        @author
        Caolán McNamara
        Takashi Ono
    */
    sti GetCanonicalStiFromEnglishName(const String &rString) throw();
};

#endif
/* vi:set tabstop=4 shiftwidth=4 expandtab: */
<commit_msg>INTEGRATION: CWS ooo19126 (1.2.896); FILE MERGED 2005/09/05 13:42:13 rt 1.2.896.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: wwstyles.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 05:52:00 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
/// @HTML
#ifndef WW_WWSTYLES_HXX
#define WW_WWSTYLES_HXX

class String;       //yuck...

namespace ww
{
    enum sti
    {
        stiNormal = 0,                  // 0x0000
        stiLev1 = 1,                    // 0x0001
        stiLev2 = 2,                    // 0x0002
        stiLev3 = 3,                    // 0x0003
        stiLev4 = 4,                    // 0x0004
        stiLev5 = 5,                    // 0x0005
        stiLev6 = 6,                    // 0x0006
        stiLev7 = 7,                    // 0x0007
        stiLev8 = 8,                    // 0x0008
        stiLev9 = 9,                    // 0x0009
        stiLevFirst = stiLev1,
        stiLevLast = stiLev9,
        stiIndex1 = 10,                 // 0x000A
        stiIndex2 = 11,                 // 0x000B
        stiIndex3 = 12,                 // 0x000C
        stiIndex4 = 13,                 // 0x000D
        stiIndex5 = 14,                 // 0x000E
        stiIndex6 = 15,                 // 0x000F
        stiIndex7 = 16,                 // 0x0010
        stiIndex8 = 17,                 // 0x0011
        stiIndex9 = 18,                 // 0x0012
        stiIndexFirst = stiIndex1,
        stiIndexLast = stiIndex9,
        stiToc1 = 19,                   // 0x0013
        stiToc2 = 20,                   // 0x0014
        stiToc3 = 21,                   // 0x0015
        stiToc4 = 22,                   // 0x0016
        stiToc5 = 23,                   // 0x0017
        stiToc6 = 24,                   // 0x0018
        stiToc7 = 25,                   // 0x0019
        stiToc8 = 26,                   // 0x001A
        stiToc9 = 27,                   // 0x001B
        stiTocFirst = stiToc1,
        stiTocLast = stiToc9,
        stiNormIndent = 28,             // 0x001C
        stiFtnText = 29,                // 0x001D
        stiAtnText = 30,                // 0x001E
        stiHeader = 31,                 // 0x001F
        stiFooter = 32,                 // 0x0020
        stiIndexHeading = 33,           // 0x0021
        stiCaption = 34,                // 0x0022
        stiToCaption = 35,              // 0x0023
        stiEnvAddr = 36,                // 0x0024
        stiEnvRet = 37,                 // 0x0025
        stiFtnRef = 38,                 // 0x0026  char style
        stiAtnRef = 39,                 // 0x0027  char style
        stiLnn = 40,                    // 0x0028  char style
        stiPgn = 41,                    // 0x0029  char style
        stiEdnRef = 42,                 // 0x002A  char style
        stiEdnText = 43,                // 0x002B
        stiToa = 44,                    // 0x002C
        stiMacro = 45,                  // 0x002D
        stiToaHeading = 46,             // 0x002E
        stiList = 47,                   // 0x002F
        stiListBullet = 48,             // 0x0030
        stiListNumber = 49,             // 0x0031
        stiList2 = 50,                  // 0x0032
        stiList3 = 51,                  // 0x0033
        stiList4 = 52,                  // 0x0034
        stiList5 = 53,                  // 0x0035
        stiListBullet2 = 54,            // 0x0036
        stiListBullet3 = 55,            // 0x0037
        stiListBullet4 = 56,            // 0x0038
        stiListBullet5 = 57,            // 0x0039
        stiListNumber2 = 58,            // 0x003A
        stiListNumber3 = 59,            // 0x003B
        stiListNumber4 = 60,            // 0x003C
        stiListNumber5 = 61,            // 0x003D
        stiTitle = 62,                  // 0x003E
        stiClosing = 63,                // 0x003F
        stiSignature = 64,              // 0x0040
        stiNormalChar = 65,             // 0x0041  char style
        stiBodyText = 66,               // 0x0042
        /*
         stiBodyTextInd1 was orig stiBodyText2 in documentation, but that
         collides with the other stiBodyText2 and this seems more reasonable.
         cmc@openoffice.org
        */
        stiBodyTextInd1 = 67,           // 0x0043
        stiListCont = 68,               // 0x0044
        stiListCont2 = 69,              // 0x0045
        stiListCont3 = 70,              // 0x0046
        stiListCont4 = 71,              // 0x0047
        stiListCont5 = 72,              // 0x0048
        stiMsgHeader = 73,              // 0x0049
        stiSubtitle = 74,               // 0x004A
        stiSalutation = 75,             // 0x004B
        stiDate = 76,                   // 0X004C
        stiBodyText1I = 77,             // 0x004D
        stiBodyText1I2 = 78,            // 0x004E
        stiNoteHeading = 79,            // 0x004F
        stiBodyText2 = 80,              // 0x0050
        stiBodyText3 = 81,              // 0x0051
        stiBodyTextInd2 = 82,           // 0x0052
        stiBodyTextInd3 = 83,           // 0x0053
        stiBlockQuote = 84,             // 0x0054
        stiHyperlink = 85,              // 0x0055  char style
        stiHyperlinkFollowed = 86,      // 0x0056  char style
        stiStrong = 87,                 // 0x0057  char style
        stiEmphasis = 88,               // 0x0058  char style
        stiNavPane = 89,                // 0x0059  char style
        stiPlainText = 90,              // 0x005A
        stiMax = 91,                    // number of defined sti's
        stiUser = 0x0ffe,               // user styles are distinguished by name
        stiNil = 0x0fff                 // max for 12 bits
    };

    /** Find the WinWord sti index of an english style name.

        When importing a RTF document we would like to treat styles as similiar
        to how word does as possible, to this end word will treat some styles
        with special names as inbuilt styles, and some as user defined styles.

        See OpenOffice.org issue 21881
        (http://www.openoffice.org/issues/show_bug.cgi?id=21881)
        and OpenOffice.org issue 17503
        (http://www.openoffice.org/issues/show_bug.cgi?id=17503)

        @param
        rSting the Style name to test to see what winword sti word would give
        such a name if it has no other information to work with (e.g. importing
        a RTF document)

        @return the sti that word would give it. stiUser if word would treat
        it as a user defined style.

        @author
        Caolán McNamara
        Takashi Ono
    */
    sti GetCanonicalStiFromEnglishName(const String &rString) throw();
};

#endif
/* vi:set tabstop=4 shiftwidth=4 expandtab: */
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: swdialmgr.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2004-08-23 08:49:27 $
 *
 *  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): _______________________________________
 *
 *
 ************************************************************************/

#ifdef SW_DLLIMPLEMENTATION
#undef SW_DLLIMPLEMENTATION
#endif

// include ---------------------------------------------------------------

#include "dialmgr.hxx"

#ifndef _STRING_HXX
#include "tools/string.hxx"
#endif
#ifndef _SFXAPP_HXX
#include <sfx2/app.hxx>
#endif

//copy from core\bastyp\swtypes.cxx
String aEmptyStr;               // Konstante Strings

ResMgr* pSwResMgr=0;

ResMgr* SwDialogsResMgr::GetResMgr()
{
    if ( !pSwResMgr )
    {
        pSwResMgr = SfxApplication::CreateResManager( "sw" );
    }

    return pSwResMgr;
}
<commit_msg>INTEGRATION: CWS ooo19126 (1.3.596); FILE MERGED 2005/09/05 13:43:58 rt 1.3.596.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: swdialmgr.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 07:15:03 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifdef SW_DLLIMPLEMENTATION
#undef SW_DLLIMPLEMENTATION
#endif

// include ---------------------------------------------------------------

#include "dialmgr.hxx"

#ifndef _STRING_HXX
#include "tools/string.hxx"
#endif
#ifndef _SFXAPP_HXX
#include <sfx2/app.hxx>
#endif

//copy from core\bastyp\swtypes.cxx
String aEmptyStr;               // Konstante Strings

ResMgr* pSwResMgr=0;

ResMgr* SwDialogsResMgr::GetResMgr()
{
    if ( !pSwResMgr )
    {
        pSwResMgr = SfxApplication::CreateResManager( "sw" );
    }

    return pSwResMgr;
}
<|endoftext|>


<commit_before>#ifndef NNGCPP_MESSAGING_HPP
#define NNGCPP_MESSAGING_HPP

#include "messaging/binary_message.h"
#include "messaging/message_pipe.h"
#include "messaging/messaging_utils.h"

#endif // NNGCPP_MESSAGING_HPP
<commit_msg>updated messaging include file<commit_after>#ifndef NNGCPP_MESSAGING_HPP
#define NNGCPP_MESSAGING_HPP

#include "core/enums.h"
#include "messaging/binary_message.h"
#include "messaging/message_pipe.h"
#include "messaging/messaging_utils.h"

#endif // NNGCPP_MESSAGING_HPP
<|endoftext|>


<commit_before>//
// Copyright 2017 Garrett D'Amore <garrett@damore.org>
// Copyright 2017 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt).  A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//

#include <catch.hpp>
#include <nngcpp.h>

#include "../tests/messaging/messaging_gymnastics.h"

#include <string>
#include <memory>
#include <thread>

void allocate(nng::messaging::binary_message* const bmp
    , nng::messaging::message_base::size_type sz = 0) {

    REQUIRE(bmp != nullptr);
    REQUIRE(bmp->has_message() == false);
    REQUIRE(bmp->get_msgp() == nullptr);

    REQUIRE_NOTHROW(bmp->allocate(sz));
    REQUIRE(bmp->has_message() == true);

    REQUIRE(bmp->get_msgp() != nullptr);
    const auto* msgp = bmp->get_msgp();

    REQUIRE(bmp->header() != nullptr);
    REQUIRE(bmp->header()->has_message());
    REQUIRE(bmp->header()->get_msgp() == msgp);

    REQUIRE(bmp->body() != nullptr);
    REQUIRE(bmp->body()->has_message());
    REQUIRE(bmp->body()->get_msgp() == msgp);
}

namespace constants {

    const std::string nng_addr = "inproc://nng";

    const std::string test_addr = "inproc://test";

    const std::string hello = "hello";
    const std::string again = "again";

    const nng::messaging::message_base::buffer_vector_type hello_buf = { 'h','e','l','l','o' };
    const nng::messaging::message_base::buffer_vector_type again_buf = { 'a','g','a','i','n' };
}

#define NNG_TESTS_INIT() int errnum

#define NNG_TESTS_APPEND_STR(m, s) \
    REQUIRE(::nng_msg_append(m, s, std::strlen(s)) == 0); \
    REQUIRE(::nng_msg_len(m) == std::strlen(s)); \
    REQUIRE(std::memcmp(::nng_msg_body(m), s, std::strlen(s)) == 0)

#define NNG_TESTS_CHECK_STR(m, s) \
    REQUIRE(m != nullptr); \
    REQUIRE(::nng_msg_len(m) == std::strlen(s)); \
    REQUIRE(std::memcmp(::nng_msg_body(m), s, std::strlen(s)) == 0)

//// todo:
//TEST_CASE("Do some math tests", "[math][foo][bar]") {
//
//    SECTION("This is a test") {
//
//        REQUIRE(2 + 2 != 4);
//    }
//
//    SECTION("This is a test 2") {
//
//        REQUIRE(3 + 3 != 6);
//    }
//}

struct c_style_fixture {

    ::nng_socket push;
    ::nng_socket pull;

    c_style_fixture() : push(0), pull(0) {
        REQUIRE(::nng_push_open(&push) == 0);
        REQUIRE(::nng_pull_open(&pull) == 0);
    }

    virtual ~c_style_fixture() {
        ::nng_close(push);
        ::nng_close(pull);
        ::nng_fini();
    }
};

TEST_CASE("C style NNG reconnect works", "[reconnect][nng]") {

    using namespace std;
    using namespace std::chrono;
    using namespace constants;

    SECTION("We can create a pipeline") {

        NNG_TESTS_INIT();

        c_style_fixture $;

        REQUIRE(::nng_setopt_usec($.pull, NNG_OPT_RECONNMINT, 10000) == 0);
        REQUIRE(::nng_setopt_usec($.pull, NNG_OPT_RECONNMAXT, 10000) == 0);

        // Strictly adapted from the NNG C-style unit tests, but for std::thread specifics.
        SECTION("Dialing before listening works") {

            INFO("Dialing push on address: '" + nng_addr + "'");

            // With Reconnect Times configured, Should re-dial until Listener comes online.
            REQUIRE(::nng_dial($.push, nng_addr.c_str(), nullptr, NNG_FLAG_NONBLOCK) == 0);

            this_thread::sleep_for(100ms);

            INFO("Pull listening on address: '" + nng_addr + "'");

            REQUIRE(::nng_listen($.pull, nng_addr.c_str(), nullptr, 0) == 0);

            // TODO: TBD: for comparison, so far the original C-style approach is working
            SECTION("We can send a frame") {

                struct ::nng_msg *msgp = nullptr;

                this_thread::sleep_for(100ms);

                REQUIRE(::nng_msg_alloc(&msgp, 0) == 0);
                REQUIRE(msgp != nullptr);

                NNG_TESTS_APPEND_STR(msgp, hello.c_str());

                //::nng_tests_append_str(msgp, hello.c_str());
                REQUIRE(::nng_sendmsg($.push, msgp, 0) == 0);

                ::nng_msg_free(msgp);
                msgp = nullptr;

                ::nng_msg_alloc(&msgp, 0);
                REQUIRE(msgp != nullptr);

                // Which Receiving a Message should allocate when we did not provide one.
                errnum = ::nng_recvmsg($.pull, &msgp, 0);
                REQUIRE(errnum == 0);
                REQUIRE(msgp != nullptr);

                NNG_TESTS_CHECK_STR(msgp, hello.c_str());

                ::nng_msg_free(msgp);
            }

            // TODO: TBD: continue appending sections of the original test.
        }

        //SECTION("Reconnection works") {

        //    ::nng_listener l;

        //    REQUIRE(::nng_dial($.push, nng_addr.c_str(), nullptr, NNG_FLAG_NONBLOCK) == 0);
        //    REQUIRE(::nng_listen($.pull, nng_addr.c_str(), &l, 0) == 0);

        //    this_thread::sleep_for(100ms);

        //    REQUIRE(::nng_listener_close(l) == 0);
        //    REQUIRE(::nng_listen($.pull, nng_addr.c_str(), nullptr, 0) == 0);

        //    SECTION("They still exchange frames") {

        //        ::nng_msg* msgp;
        //        ::nng_pipe p1;

        //        this_thread::sleep_for(100ms);

        //        REQUIRE(::nng_msg_alloc(&msgp, 0) == 0);

        //        NNG_TESTS_APPEND_STR(msgp, hello.c_str());
        //        REQUIRE(::nng_sendmsg($.push, msgp, 0) == 0);

        //        ::nng_msg_free(msgp);
        //        msgp = nullptr;

        //        REQUIRE(::nng_recvmsg($.pull, &msgp, 0) == 0);
        //        REQUIRE(msgp != nullptr);

        //        NNG_TESTS_CHECK_STR(msgp, hello.c_str());

        //        p1 = ::nng_msg_get_pipe(msgp);

        //        ::nng_msg_free(msgp);

        //        SECTION("Even after pipe close") {

        //            ::nng_pipe p2;

        //            ::nng_pipe_close(p1);

        //            this_thread::sleep_for(100ms);

        //            REQUIRE(::nng_msg_alloc(&msgp, 0) == 0);
        //            NNG_TESTS_APPEND_STR(msgp, again.c_str());
        //        }
        //    }
        //}

        //Convey("Reconnection works", {

        //Convey("They still exchange frames",{

        //Convey("Even after pipe close",{

        //APPENDSTR(msg, "again");
        //So(nng_sendmsg(push, msg, 0) == 0);
        //msg = NULL;
        //So(nng_recvmsg(pull, &msg, 0) == 0);
        //So(msg != NULL);
        //CHECKSTR(msg, "again");
        //p2 = nng_msg_get_pipe(msg);
        //nng_msg_free(msg);
        //So(p2 != p1);
        //});
        //});
        //});
    }
}

TEST_CASE("Wrapper style reconnect works", "[reconnect][cxx]") {

    using namespace std;
    using namespace std::chrono;
    using namespace nng;
    using namespace nng::protocol;
    using namespace nng::messaging;
    using namespace constants;
    using namespace Catch::Matchers;
    using _opt_ = option_names;

    // Which "at-exit" destructor handles cleaning up the NNG resources: i.e. ::nng_fini.
    session _session_;

    SECTION("We can create a pipeline") {

        std::shared_ptr<latest_push_socket> push;
        std::shared_ptr<latest_pull_socket> pull;

        REQUIRE_NOTHROW(push = _session_.create_push_socket());
        REQUIRE_NOTHROW(pull = _session_.create_pull_socket());

        const duration<uint64_t, milli> reconnect_time = 10ms;

        // TODO: TBD: count() might be the way to go here, but I cannot say for sure.
        // http://en.cppreference.com/w/cpp/chrono/duration
        REQUIRE_NOTHROW(pull->set_option_usec(_opt_::min_reconnect_time_usec, reconnect_time.count()));
        REQUIRE_NOTHROW(pull->set_option_usec(_opt_::max_reconnect_time_usec, reconnect_time.count()));

        SECTION("Dialing before listening works") {

            REQUIRE_NOTHROW(push->dial(test_addr, to_int(flag_nonblock)));
            this_thread::sleep_for(100ms);

            REQUIRE_NOTHROW(pull->listen(test_addr));

            /* 'Frame' in this case is loosely speaking. We do not care about exposing the NNG msg structure,
            per se. Rather, we should simply be able to "frame" buffers or strings, accordingly. */
            SECTION("We can send a frame") {

                this_thread::sleep_for(100ms);

                binary_message bm;

                allocate(&bm);

                // And with a little C++ operator overloading help:
                REQUIRE_NOTHROW(bm << hello);

                REQUIRE_THAT(bm.body()->get(), Equals(hello_buf));

                push->send(&bm);

                FAIL();
                REQUIRE_NOTHROW(push->send(&bm));
                REQUIRE_NOTHROW(pull->try_receive(&bm));

                std::string _pulled_actual;

                // Ditto C++ operator overloading.
                _pulled_actual << bm;

                REQUIRE_THAT(_pulled_actual, Equals(hello));
            }
        }

        SECTION("Reconnection works") {

            FAIL();

            REQUIRE_NOTHROW(push->dial(test_addr, to_int(flag_nonblock)));

            {
                shared_ptr<listener> lp;

                REQUIRE_NOTHROW(lp = _session_.create_listener_ep());
                REQUIRE(lp != nullptr);

                REQUIRE_NOTHROW(pull->listen(test_addr, lp.get()));
                this_thread::sleep_for(100ms);

                REQUIRE_NOTHROW(_session_.remove_listener_ep(lp.get()));
                REQUIRE_NOTHROW(lp.reset());
            }

            REQUIRE_NOTHROW(pull->listen(test_addr));

            // TODO: TBD: This was heavily nng_pipe based from reconnect.c
            // TODO: TBD: we may provide comprehension of nng_pipe from a nngcpp POV, but I'm not sure the complexity of nng_msg how that is different from a simple send/receive?
            SECTION("They still exchange frames") {

                FAIL();

                std::unique_ptr<binary_message> bmp;

                this_thread::sleep_for(100ms);

                REQUIRE_NOTHROW(bmp = std::make_unique<binary_message>());
                REQUIRE(bmp != nullptr);

                allocate(bmp.get());

                *bmp << hello;

                REQUIRE_NOTHROW(push->send(bmp.get()));

                /* The C-based tests simple "reset" the pointer to NULL. Clearly a memory leak in the making.
                Instead, we will make the effort to be friendly to our memory consumption. */
                REQUIRE_NOTHROW(bmp = std::make_unique<binary_message>());
                REQUIRE(bmp != nullptr);

                REQUIRE_NOTHROW(pull->try_receive(bmp.get()));

                REQUIRE(bmp->has_message() == true);
                REQUIRE(bmp->header()->has_message() == true);
                REQUIRE(bmp->body()->has_message() == true);

                // Type conversion magic from the Message to a std::string.
                std::string _gotten_actual = *bmp;

                REQUIRE_THAT(_gotten_actual, Equals(hello));

                std::unique_ptr<message_pipe> mpp1;

                REQUIRE_NOTHROW(mpp1 = std::make_unique<message_pipe>(bmp.get()));
                REQUIRE(mpp1 != nullptr);

                // Now both we and the original C-based unit test agree, reset the memory.
                REQUIRE_NOTHROW(bmp.reset());
                REQUIRE(bmp == nullptr);

                SECTION("Even after pipe close") {

                    FAIL();

                    std::unique_ptr<message_pipe> mpp2;

                    REQUIRE_NOTHROW(mpp1->close());

                    this_thread::sleep_for(100ms);

                    allocate(bmp.get());

                    *bmp << again;

                    REQUIRE_NOTHROW(push->send(bmp.get()));

                    // Ditto C-based NULL-ifying the pointers without freeing them.
                    REQUIRE_NOTHROW(bmp = std::make_unique<binary_message>());
                    REQUIRE(bmp != nullptr);

                    REQUIRE_NOTHROW(pull->try_receive(bmp.get()));

                    REQUIRE(bmp->has_message() == true);
                    REQUIRE(bmp->header()->has_message() == true);
                    REQUIRE(bmp->body()->has_message() == true);

                    // Type conversion magic from the Message to a std::string.
                    _gotten_actual = *bmp;

                    REQUIRE_THAT(_gotten_actual, Equals(again));

                    auto mp2 = message_pipe(bmp.get());

                    // TODO: TBD: so, we can define the != operator alone, but there is no std::not_equal_to implemented. is there a patch? or migration path from 2015 -> 2017?
                    REQUIRE((*mpp1.get()) != mp2);
                }
            }
        }
    }
}
<commit_msg>updated unit test to reflect correct message passing semantics effort is ready with straight Catch translation of C unit tests CXX adaptation is still a work in progress which this unit test not only works with messaging but also explores message pipes<commit_after>//
// Copyright 2017 Garrett D'Amore <garrett@damore.org>
// Copyright 2017 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt).  A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//

#include <catch.hpp>
#include <nngcpp.h>

#include "../tests/messaging/messaging_gymnastics.h"

#include <string>
#include <memory>
#include <thread>

void allocate(nng::messaging::binary_message* const bmp
    , nng::messaging::message_base::size_type sz = 0) {

    REQUIRE(bmp != nullptr);
    REQUIRE(bmp->has_message() == false);
    REQUIRE(bmp->get_msgp() == nullptr);

    REQUIRE_NOTHROW(bmp->allocate(sz));
    REQUIRE(bmp->has_message() == true);

    REQUIRE(bmp->get_msgp() != nullptr);
    const auto* msgp = bmp->get_msgp();

    REQUIRE(bmp->header() != nullptr);
    REQUIRE(bmp->header()->has_message());
    REQUIRE(bmp->header()->get_msgp() == msgp);

    REQUIRE(bmp->body() != nullptr);
    REQUIRE(bmp->body()->has_message());
    REQUIRE(bmp->body()->get_msgp() == msgp);
}

namespace constants {

    const std::string nng_addr = "inproc://nng";
    const std::string test_addr = "inproc://test";

    const std::string hello = "hello";
    const std::string again = "again";

    const nng::messaging::message_base::buffer_vector_type hello_buf = { 'h','e','l','l','o' };
    const nng::messaging::message_base::buffer_vector_type again_buf = { 'a','g','a','i','n' };
}

/* This is interesting in the event we actually need/want to separate the code under
test with a returning error number. */
#define NNG_TESTS_INIT() int errnum

#define NNG_TESTS_REQUIRE_ERR_EQ(code, expected) errnum = code; \
    REQUIRE(errnum == expected)

/* While I despise macro code expansion, this is "better" for us because in the event
of a legit failure, we see the actual line IN-SITU where the test case ACTUALLY IS. */
#define NNG_TESTS_APPEND_STR(m, s) \
    REQUIRE(::nng_msg_append(m, s, std::strlen(s)) == 0); \
    REQUIRE(::nng_msg_len(m) == std::strlen(s)); \
    REQUIRE(std::memcmp(::nng_msg_body(m), s, std::strlen(s)) == 0)

#define NNG_TESTS_CHECK_STR(m, s) \
    REQUIRE(m != nullptr); \
    REQUIRE(::nng_msg_len(m) == std::strlen(s)); \
    REQUIRE(std::memcmp(::nng_msg_body(m), s, std::strlen(s)) == 0)

//// todo:
//TEST_CASE("Do some math tests", "[math][foo][bar]") {
//
//    SECTION("This is a test") {
//
//        REQUIRE(2 + 2 != 4);
//    }
//
//    SECTION("This is a test 2") {
//
//        REQUIRE(3 + 3 != 6);
//    }
//}

struct c_style_fixture {

    ::nng_socket push;
    ::nng_socket pull;

    c_style_fixture() : push(0), pull(0) {

        REQUIRE(::nng_push_open(&push) == 0);
        REQUIRE(::nng_pull_open(&pull) == 0);

        REQUIRE(push > 0);
        REQUIRE(pull > 0);
    }

    virtual ~c_style_fixture() {
        ::nng_close(push);
        ::nng_close(pull);
        ::nng_fini();
    }
};

#define NNG_TESTS_VERIFY_TEST_CASE_DATA() \
    REQUIRE(std::memcmp(constants::hello.c_str(), "hello", std::strlen("hello")) == 0); \
    REQUIRE(std::memcmp(constants::again.c_str(), "again", std::strlen("again")) == 0); \
    REQUIRE(std::memcmp(constants::nng_addr.c_str(), "inproc://nng", std::strlen("inproc://nng")) == 0); \
    REQUIRE(std::memcmp(constants::test_addr.c_str(), "inproc://test", std::strlen("inproc://test")) == 0)

TEST_CASE("Catch translation of NNG C reconnect unit tests", "[nng][c][reconnect]") {

    using namespace std;
    using namespace std::chrono;
    using namespace constants;

    SECTION("Verify that we have the required data") {
        NNG_TESTS_VERIFY_TEST_CASE_DATA();
    }

    SECTION("We can create a pipeline") {

        /* When the scope rolls back, we want to destroy the fixture, which
        effectively closes the sockets, and finishes the NNG session. */
        c_style_fixture $;

        auto& pull = $.pull;
        auto& push = $.push;

        REQUIRE(::nng_setopt_usec(pull, NNG_OPT_RECONNMINT, 10000) == 0);
        REQUIRE(::nng_setopt_usec(pull, NNG_OPT_RECONNMAXT, 10000) == 0);

        SECTION("Dialing before listening works") {

            // With Reconnect Times configured, Should re-dial until Listener comes online.
            REQUIRE(::nng_dial(push, test_addr.c_str(), nullptr, NNG_FLAG_NONBLOCK) == 0);
            this_thread::sleep_for(100ms);
            REQUIRE(::nng_listen(pull, test_addr.c_str(), nullptr, 0) == 0);

            SECTION("We can send a frame") {

                ::nng_msg* msgp = nullptr;

                this_thread::sleep_for(100ms);

                REQUIRE(::nng_msg_alloc(&msgp, 0) == 0);
                REQUIRE(msgp != nullptr);
                NNG_TESTS_APPEND_STR(msgp, hello.c_str());
                REQUIRE(::nng_sendmsg(push, msgp, 0) == 0);

                /* Nullifying the pointer is NOT a mistake. It is part of the zero-copy message ownership
                semantics. Once the message is "sent", the framework effectively assumes ownership. */
                msgp = nullptr;

                // Which Receiving a Message should allocate when we did not provide one.
                REQUIRE(::nng_recvmsg(pull, &msgp, 0) == 0);
                NNG_TESTS_CHECK_STR(msgp, hello.c_str());

                ::nng_msg_free(msgp);
            }
        }

        SECTION("Reconnection works") {

            ::nng_listener l;

            REQUIRE(::nng_dial(push, test_addr.c_str(), nullptr, NNG_FLAG_NONBLOCK) == 0);
            REQUIRE(::nng_listen(pull, test_addr.c_str(), &l, 0) == 0);
            this_thread::sleep_for(100ms);
            REQUIRE(::nng_listener_close(l) == 0);
            REQUIRE(::nng_listen(pull, test_addr.c_str(), nullptr, 0) == 0);

            SECTION("They still exchange frames") {
                ::nng_msg *msgp;
                ::nng_pipe p1;

                this_thread::sleep_for(100ms);
                REQUIRE(::nng_msg_alloc(&msgp, 0) == 0);
                NNG_TESTS_APPEND_STR(msgp, hello.c_str());
                REQUIRE(::nng_sendmsg(push, msgp, 0) == 0);
                // Ditto message passing ownership semantics.
                msgp = nullptr;
                REQUIRE(::nng_recvmsg(pull, &msgp, 0) == 0);
                REQUIRE(msgp != nullptr);
                NNG_TESTS_CHECK_STR(msgp, hello.c_str());
                REQUIRE((p1 = ::nng_msg_get_pipe(msgp)) > 0);
                ::nng_msg_free(msgp);

                SECTION("Even after pipe close") {
                    ::nng_pipe p2;

                    REQUIRE(::nng_pipe_close(p1) == 0);
                    this_thread::sleep_for(100ms);
                    REQUIRE(::nng_msg_alloc(&msgp, 0) == 0);
                    NNG_TESTS_APPEND_STR(msgp, again.c_str());
                    REQUIRE(::nng_sendmsg(push, msgp, 0) == 0);
                    msgp = nullptr;
                    REQUIRE(::nng_recvmsg(pull, &msgp, 0) == 0);
                    REQUIRE(msgp != nullptr);
                    NNG_TESTS_CHECK_STR(msgp, again.c_str());
                    REQUIRE((p2 = nng_msg_get_pipe(msgp)) > 0);
                    ::nng_msg_free(msgp);
                    REQUIRE(p2 != p1);
                }
            }
        }
    }
}

TEST_CASE("NNG C++ wrapper reconnect works", "[reconnect][cxx][wrapper]") {

    using namespace std;
    using namespace std::chrono;
    using namespace nng;
    using namespace nng::protocol;
    using namespace nng::messaging;
    using namespace constants;
    using namespace Catch::Matchers;
    using _opt_ = option_names;

    // Which "at-exit" destructor handles cleaning up the NNG resources: i.e. ::nng_fini.
    session _session_;

    SECTION("We can create a pipeline") {

        std::shared_ptr<latest_push_socket> push;
        std::shared_ptr<latest_pull_socket> pull;

        REQUIRE_NOTHROW(push = _session_.create_push_socket());
        REQUIRE_NOTHROW(pull = _session_.create_pull_socket());

        const duration<uint64_t, milli> reconnect_time = 10ms;

        // TODO: TBD: count() might be the way to go here, but I cannot say for sure.
        // http://en.cppreference.com/w/cpp/chrono/duration
        REQUIRE_NOTHROW(pull->set_option_usec(_opt_::min_reconnect_time_usec, reconnect_time.count()));
        REQUIRE_NOTHROW(pull->set_option_usec(_opt_::max_reconnect_time_usec, reconnect_time.count()));

        SECTION("Dialing before listening works") {

            REQUIRE_NOTHROW(push->dial(test_addr, to_int(flag_nonblock)));
            this_thread::sleep_for(100ms);

            REQUIRE_NOTHROW(pull->listen(test_addr));

            /* 'Frame' in this case is loosely speaking. We do not care about exposing the NNG msg structure,
            per se. Rather, we should simply be able to "frame" buffers or strings, accordingly. */
            SECTION("We can send a frame") {

                this_thread::sleep_for(100ms);

                binary_message bm;

                allocate(&bm);

                // And with a little C++ operator overloading help:
                REQUIRE_NOTHROW(bm << hello);

                REQUIRE_THAT(bm.body()->get(), Equals(hello_buf));

                push->send(&bm);

                FAIL();
                REQUIRE_NOTHROW(push->send(&bm));
                REQUIRE_NOTHROW(pull->try_receive(&bm));

                std::string _pulled_actual;

                // Ditto C++ operator overloading.
                _pulled_actual << bm;

                REQUIRE_THAT(_pulled_actual, Equals(hello));
            }
        }

        SECTION("Reconnection works") {

            FAIL();

            REQUIRE_NOTHROW(push->dial(test_addr, to_int(flag_nonblock)));

            {
                shared_ptr<listener> lp;

                REQUIRE_NOTHROW(lp = _session_.create_listener_ep());
                REQUIRE(lp != nullptr);

                REQUIRE_NOTHROW(pull->listen(test_addr, lp.get()));
                this_thread::sleep_for(100ms);

                REQUIRE_NOTHROW(_session_.remove_listener_ep(lp.get()));
                REQUIRE_NOTHROW(lp.reset());
            }

            REQUIRE_NOTHROW(pull->listen(test_addr));

            // TODO: TBD: This was heavily nng_pipe based from reconnect.c
            // TODO: TBD: we may provide comprehension of nng_pipe from a nngcpp POV, but I'm not sure the complexity of nng_msg how that is different from a simple send/receive?
            SECTION("They still exchange frames") {

                FAIL();

                std::unique_ptr<binary_message> bmp;

                this_thread::sleep_for(100ms);

                REQUIRE_NOTHROW(bmp = std::make_unique<binary_message>());
                REQUIRE(bmp != nullptr);

                allocate(bmp.get());

                *bmp << hello;

                REQUIRE_NOTHROW(push->send(bmp.get()));

                /* The C-based tests simple "reset" the pointer to NULL. Clearly a memory leak in the making.
                Instead, we will make the effort to be friendly to our memory consumption. */
                REQUIRE_NOTHROW(bmp = std::make_unique<binary_message>());
                REQUIRE(bmp != nullptr);

                REQUIRE_NOTHROW(pull->try_receive(bmp.get()));

                REQUIRE(bmp->has_message() == true);
                REQUIRE(bmp->header()->has_message() == true);
                REQUIRE(bmp->body()->has_message() == true);

                // Type conversion magic from the Message to a std::string.
                std::string _gotten_actual = *bmp;

                REQUIRE_THAT(_gotten_actual, Equals(hello));

                std::unique_ptr<message_pipe> mpp1;

                REQUIRE_NOTHROW(mpp1 = std::make_unique<message_pipe>(bmp.get()));
                REQUIRE(mpp1 != nullptr);

                // Now both we and the original C-based unit test agree, reset the memory.
                REQUIRE_NOTHROW(bmp.reset());
                REQUIRE(bmp == nullptr);

                SECTION("Even after pipe close") {

                    FAIL();

                    std::unique_ptr<message_pipe> mpp2;

                    REQUIRE_NOTHROW(mpp1->close());

                    this_thread::sleep_for(100ms);

                    allocate(bmp.get());

                    *bmp << again;

                    REQUIRE_NOTHROW(push->send(bmp.get()));

                    // Ditto C-based NULL-ifying the pointers without freeing them.
                    REQUIRE_NOTHROW(bmp = std::make_unique<binary_message>());
                    REQUIRE(bmp != nullptr);

                    REQUIRE_NOTHROW(pull->try_receive(bmp.get()));

                    REQUIRE(bmp->has_message() == true);
                    REQUIRE(bmp->header()->has_message() == true);
                    REQUIRE(bmp->body()->has_message() == true);

                    // Type conversion magic from the Message to a std::string.
                    _gotten_actual = *bmp;

                    REQUIRE_THAT(_gotten_actual, Equals(again));

                    auto mp2 = message_pipe(bmp.get());

                    // TODO: TBD: so, we can define the != operator alone, but there is no std::not_equal_to implemented. is there a patch? or migration path from 2015 -> 2017?
                    REQUIRE((*mpp1.get()) != mp2);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#ifndef _TASKING_SCHEDULER_HPP_
#define _TASKING_SCHEDULER_HPP_

#include "Scheduler.hpp"
#include <Timestamp.hpp>
#include <glog/logging.h>

DECLARE_int64( periodic_poll_ticks );

class TaskManager;
struct task_worker_args;

class TaskingScheduler : public Scheduler {
    private:
        ThreadQueue readyQ;
        ThreadQueue periodicQ;
        ThreadQueue unassignedQ;

        Thread * master;
        Thread * current_thread;
        threadid_t nextId;

        uint64_t num_idle;
        TaskManager * task_manager;
        uint64_t num_workers;

        Thread * getWorker ();

        task_worker_args * work_args;

        // STUB: replace with real periodic threads
        SoftXMT_Timestamp previous_periodic_ts;
        int periodctr;
        Thread * periodicDequeue() {
            // tick the timestap counter
            SoftXMT_tick();
            SoftXMT_Timestamp current_ts = SoftXMT_get_timestamp();

            if( current_ts - previous_periodic_ts > FLAGS_periodic_poll_ticks ) {
                previous_periodic_ts =  current_ts;
                return periodicQ.dequeue();
            } else {
                return NULL;
            }
        }
        //////

        bool queuesFinished();

        Thread * nextCoroutine ( bool isBlocking=true ) {
            do {
                Thread * result;

                // check for periodic tasks
                result = periodicDequeue();
                if (result != NULL) {
                 //   DVLOG(5) << current_thread->id << " scheduler: pick periodic";
                    return result;
                }

                // check ready tasks
                result = readyQ.dequeue();
                if (result != NULL) {
                //    DVLOG(5) << current_thread->id << " scheduler: pick ready";
                    return result;
                }

                // check for new workers
                result = getWorker();
                if (result != NULL) {
                  //  DVLOG(5) << current_thread->id << " scheduler: pick task worker";
                    return result;
                }

                // no coroutines can run, so handle
                /*DVLOG(5) << current_thread->id << " scheduler: no coroutines can run"
                    << "[isBlocking=" << isBlocking
                    << " periodQ=" << (periodicQ.empty() ? "empty" : "full")
                    << " unassignedQ=" << (unassignedQ.empty() ? "empty" : "full") << "]";*/
                usleep(1);
            } while ( isBlocking || !queuesFinished() );
            // exit if all threads exited, including idle workers
            // TODO just as use mightBeWork as shortcut, also kill all idle unassigned workers on cbarrier_exit

            return NULL;
        }

    public:
       TaskingScheduler ( Thread * master, TaskManager * taskman );

       Thread * get_current_thread() {
           return current_thread;
       }

       void assignTid( Thread * thr ) {
           thr->id = nextId++;
       }

      void createWorkers( uint64_t num );
      Thread* maybeSpawnCoroutines( );
      void onWorkerStart( );

       void unassigned( Thread * thr ) {
           unassignedQ.enqueue( thr );
       }

       void ready( Thread * thr ) {
            readyQ.enqueue( thr );
       }

       void periodic( Thread * thr ) {
           periodicQ.enqueue( thr );
       }

       /// run threads until all exit
       void run ( );

       bool thread_yield( );
       bool thread_yield_periodic( );
       void thread_suspend( );
       void thread_wake( Thread * next );
       void thread_yield_wake( Thread * next );
       void thread_suspend_wake( Thread * next );
       bool thread_idle( uint64_t total_idle );
       bool thread_idle( );
       void thread_join( Thread* wait_on );

       // Start running threads from <scheduler> until one dies.  Return that Thread
       // (which can't be restarted--it's trash.)  If <result> non-NULL,
       // store the Thread's exit value there.
       // If no threads to run, returns NULL.
       Thread * thread_wait( void **result );

       void thread_on_exit( );
};

struct task_worker_args {
    TaskManager *const tasks;
    TaskingScheduler *const scheduler;

    task_worker_args( TaskManager * task_manager, TaskingScheduler * sched )
        : tasks( task_manager )
        , scheduler( sched ) { }
};

/// Yield the CPU to the next Thread on your scheduler.  Doesn't ever touch
/// the master Thread.
inline bool TaskingScheduler::thread_yield( ) {
    CHECK( current_thread != master ) << "can't yield on a system Thread";

    ready( current_thread );

    Thread * yieldedThr = current_thread;

    Thread * next = nextCoroutine( );
    bool gotRescheduled = (next == yieldedThr);

    current_thread = next;
    //DVLOG(5) << "Thread " << yieldedThr->id << " yielding to " << next->id << (gotRescheduled ? " (same thread)." : " (diff thread).");
    thread_context_switch( yieldedThr, next, NULL);

    return gotRescheduled; // 0=another ran; 1=me got rescheduled immediately
}

/// For periodic threads: yield the CPU to the next Thread on your scheduler.  Doesn't ever touch
/// the master Thread.
inline bool TaskingScheduler::thread_yield_periodic( ) {
    CHECK( current_thread != master ) << "can't yield on a system Thread";

    periodic( current_thread );

    Thread * yieldedThr = current_thread;

    Thread * next = nextCoroutine( );
    bool gotRescheduled = (next == yieldedThr);

    current_thread = next;
    //DVLOG(5) << "Thread " << yieldedThr->id << " yielding to " << next->id << (gotRescheduled ? " (same thread)." : " (diff thread).");
    thread_context_switch( yieldedThr, next, NULL);

    return gotRescheduled; // 0=another ran; 1=me got rescheduled immediately
}

/// Suspend the current Thread. Thread is not placed on any queue.
inline void TaskingScheduler::thread_suspend( ) {
    CHECK( current_thread != master ) << "can't yield on a system Thread";
    CHECK( thread_is_running(current_thread) ) << "may only suspend a running coroutine";

    Thread * yieldedThr = current_thread;
    yieldedThr->co->running = 0;
    Thread * next = nextCoroutine( );

    current_thread = next;
    thread_context_switch( yieldedThr, next, NULL);
}

/// Wake a suspended Thread by putting it on the run queue.
/// For now, waking a running Thread is a fatal error.
/// For now, waking a queued Thread is also a fatal error.
/// For now, can only wake a Thread on your scheduler
inline void TaskingScheduler::thread_wake( Thread * next ) {
  CHECK( next->sched == this ) << "can only wake a Thread on your scheduler";
  CHECK( next->next == NULL ) << "woken Thread should not be on any queue";
  CHECK( !thread_is_running( next ) ) << "woken Thread should not be running";

  DVLOG(5) << "Thread " << current_thread->id << " wakes thread " << next->id;

  ready( next );
}

/// Yield the current Thread and wake a suspended thread.
/// For now, waking a running Thread is a fatal error.
/// For now, waking a queued Thread is also a fatal error.
inline void TaskingScheduler::thread_yield_wake( Thread * next ) {
    CHECK( current_thread != master ) << "can't yield on a system Thread";
    CHECK( next->sched == this ) << "can only wake a Thread on your scheduler";
    CHECK( next->next == NULL ) << "woken Thread should not be on any queue";
    CHECK( !thread_is_running( next ) ) << "woken Thread should not be running";

    Thread * yieldedThr = current_thread;
    ready( yieldedThr );

    current_thread = next;
    thread_context_switch( yieldedThr, next, NULL);
}

/// Suspend current Thread and wake a suspended thread.
/// For now, waking a running Thread is a fatal error.
/// For now, waking a queued Thread is also a fatal error.
inline void TaskingScheduler::thread_suspend_wake( Thread *next ) {
    CHECK( current_thread != master ) << "can't yield on a system Thread";
    CHECK( next->next == NULL ) << "woken Thread should not be on any queue";
    CHECK( !thread_is_running( next ) ) << "woken Thread should not be running";

    Thread * yieldedThr = current_thread;

    current_thread = next;
    thread_context_switch( yieldedThr, next, NULL);
}

/// Make the current Thread idle.
/// Like suspend except the Thread is not blocking on a
/// particular resource, just waiting to be woken.
inline bool TaskingScheduler::thread_idle( uint64_t total_idle ) {
    CHECK( num_idle+1 <= total_idle ) << "number of idle threads should not be more than total"
                                      << " (" << num_idle+1 << " / " << total_idle << ")";
    if (num_idle+1 == total_idle) {
        DVLOG(5) << "going idle and is last";
        return false;
    } else {
        DVLOG(5) << "going idle and is " << num_idle+1 << " of " << total_idle;
        num_idle++;

        unassigned( current_thread );

        thread_suspend( );

        // woke so decrement idle counter
        num_idle--;

        return true;
    }
}

inline bool TaskingScheduler::thread_idle( ) {
    return thread_idle( num_workers );
}

inline void TaskingScheduler::thread_on_exit( ) {
  Thread * exitedThr = current_thread;
  current_thread = master;

  thread_context_switch( exitedThr, master, (void *)exitedThr);
}

#endif

<commit_msg>make periodicQ's window start *after* deaggregate is done<commit_after>#ifndef _TASKING_SCHEDULER_HPP_
#define _TASKING_SCHEDULER_HPP_

#include "Scheduler.hpp"
#include <Timestamp.hpp>
#include <glog/logging.h>

DECLARE_int64( periodic_poll_ticks );

class TaskManager;
struct task_worker_args;

class TaskingScheduler : public Scheduler {
    private:
        ThreadQueue readyQ;
        ThreadQueue periodicQ;
        ThreadQueue unassignedQ;

        Thread * master;
        Thread * current_thread;
        threadid_t nextId;

        uint64_t num_idle;
        TaskManager * task_manager;
        uint64_t num_workers;

        Thread * getWorker ();

        task_worker_args * work_args;

        // STUB: replace with real periodic threads
        SoftXMT_Timestamp previous_periodic_ts;
        int periodctr;
        Thread * periodicDequeue() {
            // tick the timestap counter
            SoftXMT_tick();
            SoftXMT_Timestamp current_ts = SoftXMT_get_timestamp();

            if( current_ts - previous_periodic_ts > FLAGS_periodic_poll_ticks ) {
                previous_periodic_ts =  current_ts;
                return periodicQ.dequeue();
            } else {
                return NULL;
            }
        }
        //////

        bool queuesFinished();

        Thread * nextCoroutine ( bool isBlocking=true ) {
            do {
                Thread * result;

                // check for periodic tasks
                result = periodicDequeue();
                if (result != NULL) {
                 //   DVLOG(5) << current_thread->id << " scheduler: pick periodic";
                    return result;
                }

                // check ready tasks
                result = readyQ.dequeue();
                if (result != NULL) {
                //    DVLOG(5) << current_thread->id << " scheduler: pick ready";
                    return result;
                }

                // check for new workers
                result = getWorker();
                if (result != NULL) {
                  //  DVLOG(5) << current_thread->id << " scheduler: pick task worker";
                    return result;
                }

                // no coroutines can run, so handle
                /*DVLOG(5) << current_thread->id << " scheduler: no coroutines can run"
                    << "[isBlocking=" << isBlocking
                    << " periodQ=" << (periodicQ.empty() ? "empty" : "full")
                    << " unassignedQ=" << (unassignedQ.empty() ? "empty" : "full") << "]";*/
                usleep(1);
            } while ( isBlocking || !queuesFinished() );
            // exit if all threads exited, including idle workers
            // TODO just as use mightBeWork as shortcut, also kill all idle unassigned workers on cbarrier_exit

            return NULL;
        }

    public:
       TaskingScheduler ( Thread * master, TaskManager * taskman );

       Thread * get_current_thread() {
           return current_thread;
       }

       void assignTid( Thread * thr ) {
           thr->id = nextId++;
       }

      void createWorkers( uint64_t num );
      Thread* maybeSpawnCoroutines( );
      void onWorkerStart( );

       void unassigned( Thread * thr ) {
           unassignedQ.enqueue( thr );
       }

       void ready( Thread * thr ) {
            readyQ.enqueue( thr );
       }

       void periodic( Thread * thr ) {
           periodicQ.enqueue( thr );
           SoftXMT_tick();
           previous_periodic_ts = SoftXMT_get_timestamp();
       }

       /// run threads until all exit
       void run ( );

       bool thread_yield( );
       bool thread_yield_periodic( );
       void thread_suspend( );
       void thread_wake( Thread * next );
       void thread_yield_wake( Thread * next );
       void thread_suspend_wake( Thread * next );
       bool thread_idle( uint64_t total_idle );
       bool thread_idle( );
       void thread_join( Thread* wait_on );

       // Start running threads from <scheduler> until one dies.  Return that Thread
       // (which can't be restarted--it's trash.)  If <result> non-NULL,
       // store the Thread's exit value there.
       // If no threads to run, returns NULL.
       Thread * thread_wait( void **result );

       void thread_on_exit( );
};

struct task_worker_args {
    TaskManager *const tasks;
    TaskingScheduler *const scheduler;

    task_worker_args( TaskManager * task_manager, TaskingScheduler * sched )
        : tasks( task_manager )
        , scheduler( sched ) { }
};

/// Yield the CPU to the next Thread on your scheduler.  Doesn't ever touch
/// the master Thread.
inline bool TaskingScheduler::thread_yield( ) {
    CHECK( current_thread != master ) << "can't yield on a system Thread";

    ready( current_thread );

    Thread * yieldedThr = current_thread;

    Thread * next = nextCoroutine( );
    bool gotRescheduled = (next == yieldedThr);

    current_thread = next;
    //DVLOG(5) << "Thread " << yieldedThr->id << " yielding to " << next->id << (gotRescheduled ? " (same thread)." : " (diff thread).");
    thread_context_switch( yieldedThr, next, NULL);

    return gotRescheduled; // 0=another ran; 1=me got rescheduled immediately
}

/// For periodic threads: yield the CPU to the next Thread on your scheduler.  Doesn't ever touch
/// the master Thread.
inline bool TaskingScheduler::thread_yield_periodic( ) {
    CHECK( current_thread != master ) << "can't yield on a system Thread";

    periodic( current_thread );

    Thread * yieldedThr = current_thread;

    Thread * next = nextCoroutine( );
    bool gotRescheduled = (next == yieldedThr);

    current_thread = next;
    //DVLOG(5) << "Thread " << yieldedThr->id << " yielding to " << next->id << (gotRescheduled ? " (same thread)." : " (diff thread).");
    thread_context_switch( yieldedThr, next, NULL);

    return gotRescheduled; // 0=another ran; 1=me got rescheduled immediately
}

/// Suspend the current Thread. Thread is not placed on any queue.
inline void TaskingScheduler::thread_suspend( ) {
    CHECK( current_thread != master ) << "can't yield on a system Thread";
    CHECK( thread_is_running(current_thread) ) << "may only suspend a running coroutine";

    Thread * yieldedThr = current_thread;
    yieldedThr->co->running = 0;
    Thread * next = nextCoroutine( );

    current_thread = next;
    thread_context_switch( yieldedThr, next, NULL);
}

/// Wake a suspended Thread by putting it on the run queue.
/// For now, waking a running Thread is a fatal error.
/// For now, waking a queued Thread is also a fatal error.
/// For now, can only wake a Thread on your scheduler
inline void TaskingScheduler::thread_wake( Thread * next ) {
  CHECK( next->sched == this ) << "can only wake a Thread on your scheduler";
  CHECK( next->next == NULL ) << "woken Thread should not be on any queue";
  CHECK( !thread_is_running( next ) ) << "woken Thread should not be running";

  DVLOG(5) << "Thread " << current_thread->id << " wakes thread " << next->id;

  ready( next );
}

/// Yield the current Thread and wake a suspended thread.
/// For now, waking a running Thread is a fatal error.
/// For now, waking a queued Thread is also a fatal error.
inline void TaskingScheduler::thread_yield_wake( Thread * next ) {
    CHECK( current_thread != master ) << "can't yield on a system Thread";
    CHECK( next->sched == this ) << "can only wake a Thread on your scheduler";
    CHECK( next->next == NULL ) << "woken Thread should not be on any queue";
    CHECK( !thread_is_running( next ) ) << "woken Thread should not be running";

    Thread * yieldedThr = current_thread;
    ready( yieldedThr );

    current_thread = next;
    thread_context_switch( yieldedThr, next, NULL);
}

/// Suspend current Thread and wake a suspended thread.
/// For now, waking a running Thread is a fatal error.
/// For now, waking a queued Thread is also a fatal error.
inline void TaskingScheduler::thread_suspend_wake( Thread *next ) {
    CHECK( current_thread != master ) << "can't yield on a system Thread";
    CHECK( next->next == NULL ) << "woken Thread should not be on any queue";
    CHECK( !thread_is_running( next ) ) << "woken Thread should not be running";

    Thread * yieldedThr = current_thread;

    current_thread = next;
    thread_context_switch( yieldedThr, next, NULL);
}

/// Make the current Thread idle.
/// Like suspend except the Thread is not blocking on a
/// particular resource, just waiting to be woken.
inline bool TaskingScheduler::thread_idle( uint64_t total_idle ) {
    CHECK( num_idle+1 <= total_idle ) << "number of idle threads should not be more than total"
                                      << " (" << num_idle+1 << " / " << total_idle << ")";
    if (num_idle+1 == total_idle) {
        DVLOG(5) << "going idle and is last";
        return false;
    } else {
        DVLOG(5) << "going idle and is " << num_idle+1 << " of " << total_idle;
        num_idle++;

        unassigned( current_thread );

        thread_suspend( );

        // woke so decrement idle counter
        num_idle--;

        return true;
    }
}

inline bool TaskingScheduler::thread_idle( ) {
    return thread_idle( num_workers );
}

inline void TaskingScheduler::thread_on_exit( ) {
  Thread * exitedThr = current_thread;
  current_thread = master;

  thread_context_switch( exitedThr, master, (void *)exitedThr);
}

#endif

<|endoftext|>


<commit_before>#include "CppUTest/CommandLineTestRunner.h"
#include "Sigmoid.h"

microbe::Sigmoid *sigmoid;

TEST_GROUP(Sigmoid)
{
	void setup()
	{
		sigmoid = new microbe::Sigmoid();
	}

	void teardown()
	{
		delete sigmoid;
	}
};

TEST(Sigmoid, Limits)
{
	DOUBLES_EQUAL(1.0, sigmoid->getUpperLimit(), 0.00001);
	DOUBLES_EQUAL(0.0, sigmoid->getLowerLimit(), 0.00001);
};

TEST(Sigmoid, Function)
{
	DOUBLES_EQUAL(0.50000, sigmoid->function(0.00000), 0.00001);
	DOUBLES_EQUAL(0.62245, sigmoid->function(0.50000), 0.00001);
	DOUBLES_EQUAL(0.73105, sigmoid->function(1.00000), 0.00001);
};

TEST(Sigmoid, Derivative)
{
	DOUBLES_EQUAL(0.25000, sigmoid->derivative(0.50000), 0.00001);
	DOUBLES_EQUAL(0.23500, sigmoid->derivative(0.62245), 0.00001);
	DOUBLES_EQUAL(0.19661, sigmoid->derivative(0.73105), 0.00001);
};

int main(int argc, char **argv)
{
   return CommandLineTestRunner::RunAllTests(argc, argv);
}
<commit_msg>Add missing license header to Sigmoid test<commit_after>/**
 * Copyright 2014 Krzysztof Magosa
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "CppUTest/CommandLineTestRunner.h"
#include "Sigmoid.h"

microbe::Sigmoid *sigmoid;

TEST_GROUP(Sigmoid)
{
	void setup()
	{
		sigmoid = new microbe::Sigmoid();
	}

	void teardown()
	{
		delete sigmoid;
	}
};

TEST(Sigmoid, Limits)
{
	DOUBLES_EQUAL(1.0, sigmoid->getUpperLimit(), 0.00001);
	DOUBLES_EQUAL(0.0, sigmoid->getLowerLimit(), 0.00001);
};

TEST(Sigmoid, Function)
{
	DOUBLES_EQUAL(0.50000, sigmoid->function(0.00000), 0.00001);
	DOUBLES_EQUAL(0.62245, sigmoid->function(0.50000), 0.00001);
	DOUBLES_EQUAL(0.73105, sigmoid->function(1.00000), 0.00001);
};

TEST(Sigmoid, Derivative)
{
	DOUBLES_EQUAL(0.25000, sigmoid->derivative(0.50000), 0.00001);
	DOUBLES_EQUAL(0.23500, sigmoid->derivative(0.62245), 0.00001);
	DOUBLES_EQUAL(0.19661, sigmoid->derivative(0.73105), 0.00001);
};

int main(int argc, char **argv)
{
   return CommandLineTestRunner::RunAllTests(argc, argv);
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Sören Krecker
 *
 * This file is part of Kleiderkammer.
 *
 * Kleiderkammer is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation version 3 of the License.
 *
 * Kleiderkammer 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Kleiderkammer.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Diese Datei ist Teil von Kleiderkammer.
 *
 * Kleiderkammer ist Freie Software: Sie können es unter den Bedingungen
 * der GNU Affero General Public License, wie von der Free Software Foundation,
 * Version 3 der Lizenz, weiterverbreiten und/oder modifizieren.
 *
 * Kleiderkammer wird in der Hoffnung, dass es nützlich sein wird, aber
 * OHNE JEDE GEWÄHRLEISTUNG, bereitgestellt; sogar ohne die implizite
 * Gewährleistung der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN
 * ZWECK.Siehe die GNU Affero General Public License für weitere Details.
 *
 * Sie sollten eine Kopie der GNU Affero General Public License zusammen mit
 * diesem Programm erhalten haben. Wenn nicht, siehe
 * <http://www.gnu.org/licenses/>.
*/

#include "kleidungstableview.h"

KleidungsTableview::KleidungsTableview(DatenQuelle *Daten, int Modus, QObject *parent) :
    QAbstractTableModel(parent)
{
    this->Daten=Daten;
    this->Modus=Modus;
    FilterTyp=0;
    FilterGroesse=-1;
    FilterPerson=0;
    Kleidung=Daten->getKleiderinKammer(0,0);
    DatumTitle=QString::fromUtf8("Letzte Änderung");
}

int KleidungsTableview::columnCount(const QModelIndex &) const
{
    return 7;
}

QVariant KleidungsTableview::data(const QModelIndex &index, int role) const
{
    if (role == Qt::DisplayRole)
    {
        if (index.row()<Kleidung->Anzahl)
            switch(index.column())
            {
            case 0:
                return QVariant(Kleidung->Nummer[index.row()]);break;
            case 1:
                return QVariant(Kleidung->Typ[index.row()]);break;
            case 2:
            {
                if (Kleidung->Groesseunbekannt[index.row()])
                    return QVariant("Unbekannt");
                else
                    return QVariant(Kleidung->Groesse[index.row()]);
                break;
            }
            case 3:
            {
                return QVariant(Kleidung->DatumLeihen[index.row()].toString("dd.MM.yy"));
            }
            case 4:
            {
                int alter=QDate::currentDate().year() - Kleidung->Anschaffung[index.row()].date().year();
                return QVariant(alter);break;
            }
            case 5:
                return QVariant(Kleidung->AnzahlAusleihen[index.row()]);break;
            case 6:
                return QVariant(Kleidung->Bemerkung[index.row()]);break;
            }
    }
    if (role == Qt::EditRole)
        if (index.row()<Kleidung->Anzahl)
        {
            if (index.column()==5)
            {
                return QVariant(Kleidung->Bemerkung[index.row()]);
            }
        }
    return QVariant();
}

Qt::ItemFlags KleidungsTableview::flags(const QModelIndex &index) const
{
    if (index.column()==5)
        return Qt::ItemIsEditable|Qt::ItemIsSelectable | Qt::ItemIsEnabled;
    if (index.column()==2)
        if (Kleidung->Groesseunbekannt[index.row()])
        return Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable;
    return Qt::ItemIsEnabled|Qt::ItemIsSelectable;
}

int KleidungsTableview::getKleidungsId(int row)
{
    if (row<Kleidung->Anzahl)
        return Kleidung->ID[row];
    return -1;
}

QVariant KleidungsTableview::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (role==Qt::DisplayRole)
    {
        if(orientation==Qt::Horizontal)
        {
            switch(section)
            {
                case 0:
                    return QString("Nummer");
                case 1:
                    return QString("Typ");
                case 2:
                    return QString::fromUtf8("Größe");
                case 3:
                    return DatumTitle;
                case 4:
                    return QString("Alter");
                case 5:
                    return QString("Ausleihen");
                case 6:
                   return QString("Bemerkung");

            }
        }
    }
    return QAbstractTableModel::headerData(section,orientation,role);
}

int KleidungsTableview::rowCount(const QModelIndex &) const
{
    return Kleidung->Anzahl;
}

bool KleidungsTableview::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if(role==Qt::EditRole)
    {
        int row=index.row();
        switch (index.column())
        {
            case 6:
            {
                int ID=Kleidung->ID[row];
                QString Text=value.toString();
                Daten->setKleidungsKommentar(ID,Text);
                Kleidung->Bemerkung[index.row()]=Text;
                dataChanged(index,index);
            }break;
            case 2:
            {if (Kleidung->Groesseunbekannt[row])
            {
                QString Eingabe=value.toString();
                int TID=Daten->getKleidungsTypID(Kleidung->Typ[row]);
                int GID=Daten->getGroessenID(Eingabe,TID);
                if (GID==-1)
                    return false;
                Daten->setKleidungsGroesse(Kleidung->ID[row],GID);
                Kleidung->Groesse[index.row()]=Eingabe;
                Kleidung->Groesseunbekannt[index.row()]=false;
                dataChanged(index,index);
            }
            }break;
        }
    }
    return true ;
}

void KleidungsTableview::setDateTitel(QString Titel)
{
    if (!Titel.isEmpty())
        DatumTitle=Titel;
}

void KleidungsTableview::setFilterGroesse(int Groesse)
{
    if (Groesse>0)
        FilterGroesse=Groesse;
    else
        FilterGroesse=-1;
    update();
}

void KleidungsTableview::setFilterNummer(QString Nummer)
{
    FilterNummer=Nummer;
    update();
}

void KleidungsTableview::setFilterPerson(int Person)
{
    if (Person>=0)
        FilterPerson=Person;
    update();
}

void KleidungsTableview::setFilterTyp(int Typ)
{
    if (Typ>=0)
        FilterTyp=Typ;
    update();
}

void KleidungsTableview::update()
{
    int anz_Alt=0;
    if (Kleidung!=NULL)
    {
        anz_Alt=Kleidung->Anzahl-1;
        beginRemoveRows(QModelIndex(),0,anz_Alt);
        delete Kleidung;
        endRemoveRows();
    }
    if (Modus==0)
        Kleidung=Daten->getKleiderinKammer(FilterTyp,FilterGroesse,FilterNummer);
    if (Modus==1)
        Kleidung=Daten->getKleidervonPerson(FilterPerson,FilterTyp);
    beginInsertRows(QModelIndex(),0,Kleidung->Anzahl-1);
    endInsertRows();
}
<commit_msg>Bemerkungen Ändern wieder Möglich<commit_after>/*
 * Copyright (C) 2015 Sören Krecker
 *
 * This file is part of Kleiderkammer.
 *
 * Kleiderkammer is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation version 3 of the License.
 *
 * Kleiderkammer 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Kleiderkammer.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Diese Datei ist Teil von Kleiderkammer.
 *
 * Kleiderkammer ist Freie Software: Sie können es unter den Bedingungen
 * der GNU Affero General Public License, wie von der Free Software Foundation,
 * Version 3 der Lizenz, weiterverbreiten und/oder modifizieren.
 *
 * Kleiderkammer wird in der Hoffnung, dass es nützlich sein wird, aber
 * OHNE JEDE GEWÄHRLEISTUNG, bereitgestellt; sogar ohne die implizite
 * Gewährleistung der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN
 * ZWECK.Siehe die GNU Affero General Public License für weitere Details.
 *
 * Sie sollten eine Kopie der GNU Affero General Public License zusammen mit
 * diesem Programm erhalten haben. Wenn nicht, siehe
 * <http://www.gnu.org/licenses/>.
*/

#include "kleidungstableview.h"

KleidungsTableview::KleidungsTableview(DatenQuelle *Daten, int Modus, QObject *parent) :
    QAbstractTableModel(parent)
{
    this->Daten=Daten;
    this->Modus=Modus;
    FilterTyp=0;
    FilterGroesse=-1;
    FilterPerson=0;
    Kleidung=Daten->getKleiderinKammer(0,0);
    DatumTitle=QString::fromUtf8("Letzte Änderung");
}

int KleidungsTableview::columnCount(const QModelIndex &) const
{
    return 7;
}

QVariant KleidungsTableview::data(const QModelIndex &index, int role) const
{
    if (role == Qt::DisplayRole)
    {
        if (index.row()<Kleidung->Anzahl)
            switch(index.column())
            {
            case 0:
                return QVariant(Kleidung->Nummer[index.row()]);break;
            case 1:
                return QVariant(Kleidung->Typ[index.row()]);break;
            case 2:
            {
                if (Kleidung->Groesseunbekannt[index.row()])
                    return QVariant("Unbekannt");
                else
                    return QVariant(Kleidung->Groesse[index.row()]);
                break;
            }
            case 3:
            {
                return QVariant(Kleidung->DatumLeihen[index.row()].toString("dd.MM.yy"));
            }
            case 4:
            {
                int alter=QDate::currentDate().year() - Kleidung->Anschaffung[index.row()].date().year();
                return QVariant(alter);break;
            }
            case 5:
                return QVariant(Kleidung->AnzahlAusleihen[index.row()]);break;
            case 6:
                return QVariant(Kleidung->Bemerkung[index.row()]);break;
            }
    }
    if (role == Qt::EditRole)
        if (index.row()<Kleidung->Anzahl)
        {
            if (index.column()==5)
            {
                return QVariant(Kleidung->Bemerkung[index.row()]);
            }
        }
    return QVariant();
}

Qt::ItemFlags KleidungsTableview::flags(const QModelIndex &index) const
{
    if (index.column()==6)
        return Qt::ItemIsEditable|Qt::ItemIsSelectable | Qt::ItemIsEnabled;
    if (index.column()==2)
        if (Kleidung->Groesseunbekannt[index.row()])
        return Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable;
    return Qt::ItemIsEnabled|Qt::ItemIsSelectable;
}

int KleidungsTableview::getKleidungsId(int row)
{
    if (row<Kleidung->Anzahl)
        return Kleidung->ID[row];
    return -1;
}

QVariant KleidungsTableview::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (role==Qt::DisplayRole)
    {
        if(orientation==Qt::Horizontal)
        {
            switch(section)
            {
                case 0:
                    return QString("Nummer");
                case 1:
                    return QString("Typ");
                case 2:
                    return QString::fromUtf8("Größe");
                case 3:
                    return DatumTitle;
                case 4:
                    return QString("Alter");
                case 5:
                    return QString("Ausleihen");
                case 6:
                   return QString("Bemerkung");

            }
        }
    }
    return QAbstractTableModel::headerData(section,orientation,role);
}

int KleidungsTableview::rowCount(const QModelIndex &) const
{
    return Kleidung->Anzahl;
}

bool KleidungsTableview::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if(role==Qt::EditRole)
    {
        int row=index.row();
        switch (index.column())
        {
            case 6:
            {
                int ID=Kleidung->ID[row];
                QString Text=value.toString();
                Daten->setKleidungsKommentar(ID,Text);
                Kleidung->Bemerkung[index.row()]=Text;
                dataChanged(index,index);
            }break;
            case 2:
            {if (Kleidung->Groesseunbekannt[row])
            {
                QString Eingabe=value.toString();
                int TID=Daten->getKleidungsTypID(Kleidung->Typ[row]);
                int GID=Daten->getGroessenID(Eingabe,TID);
                if (GID==-1)
                    return false;
                Daten->setKleidungsGroesse(Kleidung->ID[row],GID);
                Kleidung->Groesse[index.row()]=Eingabe;
                Kleidung->Groesseunbekannt[index.row()]=false;
                dataChanged(index,index);
            }
            }break;
        }
    }
    return true ;
}

void KleidungsTableview::setDateTitel(QString Titel)
{
    if (!Titel.isEmpty())
        DatumTitle=Titel;
}

void KleidungsTableview::setFilterGroesse(int Groesse)
{
    if (Groesse>0)
        FilterGroesse=Groesse;
    else
        FilterGroesse=-1;
    update();
}

void KleidungsTableview::setFilterNummer(QString Nummer)
{
    FilterNummer=Nummer;
    update();
}

void KleidungsTableview::setFilterPerson(int Person)
{
    if (Person>=0)
        FilterPerson=Person;
    update();
}

void KleidungsTableview::setFilterTyp(int Typ)
{
    if (Typ>=0)
        FilterTyp=Typ;
    update();
}

void KleidungsTableview::update()
{
    int anz_Alt=0;
    if (Kleidung!=NULL)
    {
        anz_Alt=Kleidung->Anzahl-1;
        beginRemoveRows(QModelIndex(),0,anz_Alt);
        delete Kleidung;
        endRemoveRows();
    }
    if (Modus==0)
        Kleidung=Daten->getKleiderinKammer(FilterTyp,FilterGroesse,FilterNummer);
    if (Modus==1)
        Kleidung=Daten->getKleidervonPerson(FilterPerson,FilterTyp);
    beginInsertRows(QModelIndex(),0,Kleidung->Anzahl-1);
    endInsertRows();
}
<|endoftext|>