Beast improvements and vflib compatibility module work

* Add CallQueue vflib compatibility class
* Use run instead of run_one
* Merge BindableServiceQueue into CallQueue
* Take BEAST_VARIADIC_MAX into account
* Fix license headers as suggested by Vinnie
* Remove obsolete comment
* Add ManualServiceQueue
* Add ManualServiceQueue to beast_vflib include
* Move static unit test variables of header only classes to module cpp
* Remove no longer used mutex member
* _VARIADIC_MAX maxes out at 10
* Correctly apply BEAST_VARIADIC_MAX
* Merge BindableServiceQueue into CallQueue
* New GuiServiceQueue and its JUCE dependency
* Fix leftover merge errors
* Fix CallQueue unit test
* Don't use bassert for better CI support
This commit is contained in:
Patrick Dehne
2013-10-24 17:31:18 +02:00
committed by Vinnie Falco
parent bf87614fa6
commit 08aa415c66
31 changed files with 1069 additions and 283 deletions

View File

@@ -107,7 +107,7 @@ extern void beast_reportFatalError (char const* message, char const* fileName, i
This is only compiled in a debug build. This is only compiled in a debug build.
@see Logger::outputDebugString @see Logger::outputDebugString
*/ */
#define DBG(dbgtext) { beast::String tempDbgBuf; tempDbgBuf << dbgtext; beast::Logger::outputDebugString (tempDbgBuf); } #define BDBG(dbgtext) { beast::String tempDbgBuf; tempDbgBuf << dbgtext; beast::Logger::outputDebugString (tempDbgBuf); }
/** This will always cause an assertion failure. /** This will always cause an assertion failure.
It is only compiled in a debug build, (unless BEAST_LOG_ASSERTIONS is enabled for your build). It is only compiled in a debug build, (unless BEAST_LOG_ASSERTIONS is enabled for your build).
@@ -127,7 +127,7 @@ extern void beast_reportFatalError (char const* message, char const* fileName, i
// If debugging is disabled, these dummy debug and assertion macros are used.. // If debugging is disabled, these dummy debug and assertion macros are used..
#define DBG(dbgtext) #define BDBG(dbgtext)
#define bassertfalse { beast_LogCurrentAssertion } #define bassertfalse { beast_LogCurrentAssertion }
# if BEAST_LOG_ASSERTIONS # if BEAST_LOG_ASSERTIONS

View File

@@ -354,6 +354,7 @@ protected:
void wait(); void wait();
virtual void enqueue (Item* item); virtual void enqueue (Item* item);
bool empty();
virtual std::size_t dequeue() = 0; virtual std::size_t dequeue() = 0;
virtual Waiter* new_waiter() = 0; virtual Waiter* new_waiter() = 0;

View File

@@ -179,6 +179,12 @@ void ServiceQueueBase::enqueue (Item* item)
waiter->signal(); waiter->signal();
} }
bool ServiceQueueBase::empty()
{
SharedState::Access state (m_state);
return state->handlers.empty();
}
// A thread can only be blocked on one ServiceQueue so we store the pointer // A thread can only be blocked on one ServiceQueue so we store the pointer
// to which ServiceQueue it is blocked on to determine if the thread belongs // to which ServiceQueue it is blocked on to determine if the thread belongs
// to that queue. // to that queue.

View File

@@ -456,8 +456,8 @@ void BEAST_CALLTYPE Thread::sleep (int millisecs)
void BEAST_API beast_threadEntryPoint (void*); void BEAST_API beast_threadEntryPoint (void*);
extern "C" void* threadEntryProc (void*); extern "C" void* threadEntryProcBeast (void*);
extern "C" void* threadEntryProc (void* userData) extern "C" void* threadEntryProcBeast (void* userData)
{ {
BEAST_AUTORELEASEPOOL BEAST_AUTORELEASEPOOL
{ {
@@ -482,7 +482,7 @@ void Thread::launchThread()
threadHandle = 0; threadHandle = 0;
pthread_t handle = 0; pthread_t handle = 0;
if (pthread_create (&handle, 0, threadEntryProc, this) == 0) if (pthread_create (&handle, 0, threadEntryProcBeast, this) == 0)
{ {
pthread_detach (handle); pthread_detach (handle);
threadHandle = (void*) handle; threadHandle = (void*) handle;

View File

@@ -85,7 +85,7 @@ void LeakCheckedBase::LeakCounterBase::checkForLeaks ()
always use ScopedPointers, OwnedArrays, SharedObjects, always use ScopedPointers, OwnedArrays, SharedObjects,
etc, and avoid the 'delete' operator at all costs! etc, and avoid the 'delete' operator at all costs!
*/ */
DBG ("Leaked objects: " << count << " of " << getClassName ()); BDBG ("Leaked objects: " << count << " of " << getClassName ());
//bassertfalse; //bassertfalse;
} }
@@ -115,7 +115,7 @@ void LeakCheckedBase::reportDanglingPointer (char const*)
SharedObjects, etc, and avoid the 'delete' operator SharedObjects, etc, and avoid the 'delete' operator
at all costs! at all costs!
*/ */
DBG ("Dangling pointer deletion: " << objectName); BDBG ("Dangling pointer deletion: " << objectName);
bassertfalse; bassertfalse;
} }

View File

@@ -9,9 +9,10 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
CD0A5B3F181707F700DA0342 /* mac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD0A5B3E181707F700DA0342 /* mac.cpp */; }; CD0A5B3F181707F700DA0342 /* mac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD0A5B3E181707F700DA0342 /* mac.cpp */; };
CD0A5B421817097800DA0342 /* BeastUnitTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD0A5B401817097800DA0342 /* BeastUnitTests.cpp */; }; CD0A5B421817097800DA0342 /* BeastUnitTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD0A5B401817097800DA0342 /* BeastUnitTests.cpp */; };
CD0A5B4918170DC300DA0342 /* beast.mm in Sources */ = {isa = PBXBuildFile; fileRef = CD0A5B4818170DC300DA0342 /* beast.mm */; }; CD0A5B4918170DC300DA0342 /* beast_modules.mm in Sources */ = {isa = PBXBuildFile; fileRef = CD0A5B4818170DC300DA0342 /* beast_modules.mm */; };
CD0A5B4B18170EBC00DA0342 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD0A5B4A18170EBC00DA0342 /* CoreServices.framework */; }; CD0A5B4B18170EBC00DA0342 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD0A5B4A18170EBC00DA0342 /* CoreServices.framework */; };
CD0A5B4E18170F0D00DA0342 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD0A5B4D18170F0D00DA0342 /* AppKit.framework */; }; CD0A5B4E18170F0D00DA0342 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD0A5B4D18170F0D00DA0342 /* AppKit.framework */; };
CD1CBE68181B2D99002CCC0C /* juce_modules.mm in Sources */ = {isa = PBXBuildFile; fileRef = CD1CBE64181B2689002CCC0C /* juce_modules.mm */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */ /* Begin PBXCopyFilesBuildPhase section */
@@ -31,13 +32,16 @@
CD0A5B3E181707F700DA0342 /* mac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mac.cpp; path = ../../src/mac.cpp; sourceTree = "<group>"; }; CD0A5B3E181707F700DA0342 /* mac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mac.cpp; path = ../../src/mac.cpp; sourceTree = "<group>"; };
CD0A5B401817097800DA0342 /* BeastUnitTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BeastUnitTests.cpp; path = ../../src/BeastUnitTests.cpp; sourceTree = "<group>"; }; CD0A5B401817097800DA0342 /* BeastUnitTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BeastUnitTests.cpp; path = ../../src/BeastUnitTests.cpp; sourceTree = "<group>"; };
CD0A5B411817097800DA0342 /* BeastUnitTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BeastUnitTests.h; path = ../../src/BeastUnitTests.h; sourceTree = "<group>"; }; CD0A5B411817097800DA0342 /* BeastUnitTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BeastUnitTests.h; path = ../../src/BeastUnitTests.h; sourceTree = "<group>"; };
CD0A5B4318170A5100DA0342 /* beast.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = beast.cpp; path = ../../src/beast.cpp; sourceTree = "<group>"; }; CD0A5B4318170A5100DA0342 /* beast_modules.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = beast_modules.cpp; path = ../../src/beast_modules.cpp; sourceTree = "<group>"; };
CD0A5B4418170A5100DA0342 /* beast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = beast.h; path = ../../src/beast.h; sourceTree = "<group>"; }; CD0A5B4418170A5100DA0342 /* beast_modules.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = beast_modules.h; path = ../../src/beast_modules.h; sourceTree = "<group>"; };
CD0A5B4818170DC300DA0342 /* beast.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = beast.mm; path = ../../src/beast.mm; sourceTree = "<group>"; }; CD0A5B4818170DC300DA0342 /* beast_modules.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = beast_modules.mm; path = ../../src/beast_modules.mm; sourceTree = "<group>"; };
CD0A5B4A18170EBC00DA0342 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; }; CD0A5B4A18170EBC00DA0342 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; };
CD0A5B4D18170F0D00DA0342 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; CD0A5B4D18170F0D00DA0342 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
CD0A5B4F181714A000DA0342 /* beast */ = {isa = PBXFileReference; lastKnownFileType = folder; name = beast; path = ../../../../beast; sourceTree = "<group>"; }; CD0A5B4F181714A000DA0342 /* beast */ = {isa = PBXFileReference; lastKnownFileType = folder; name = beast; path = ../../../../beast; sourceTree = "<group>"; };
CD0A5B50181714B800DA0342 /* modules */ = {isa = PBXFileReference; lastKnownFileType = folder; name = modules; path = ../../../../modules; sourceTree = "<group>"; }; CD0A5B50181714B800DA0342 /* modules */ = {isa = PBXFileReference; lastKnownFileType = folder; name = modules; path = ../../../../modules; sourceTree = "<group>"; };
CD1CBE62181B2689002CCC0C /* juce_modules.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = juce_modules.cpp; path = ../../src/juce_modules.cpp; sourceTree = "<group>"; };
CD1CBE63181B2689002CCC0C /* juce_modules.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = juce_modules.h; path = ../../src/juce_modules.h; sourceTree = "<group>"; };
CD1CBE64181B2689002CCC0C /* juce_modules.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = juce_modules.mm; path = ../../src/juce_modules.mm; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@@ -58,11 +62,14 @@
children = ( children = (
CD0A5B50181714B800DA0342 /* modules */, CD0A5B50181714B800DA0342 /* modules */,
CD0A5B4F181714A000DA0342 /* beast */, CD0A5B4F181714A000DA0342 /* beast */,
CD0A5B4818170DC300DA0342 /* beast.mm */, CD0A5B4318170A5100DA0342 /* beast_modules.cpp */,
CD0A5B4318170A5100DA0342 /* beast.cpp */, CD0A5B4418170A5100DA0342 /* beast_modules.h */,
CD0A5B4418170A5100DA0342 /* beast.h */, CD0A5B4818170DC300DA0342 /* beast_modules.mm */,
CD0A5B401817097800DA0342 /* BeastUnitTests.cpp */, CD0A5B401817097800DA0342 /* BeastUnitTests.cpp */,
CD0A5B411817097800DA0342 /* BeastUnitTests.h */, CD0A5B411817097800DA0342 /* BeastUnitTests.h */,
CD1CBE62181B2689002CCC0C /* juce_modules.cpp */,
CD1CBE63181B2689002CCC0C /* juce_modules.h */,
CD1CBE64181B2689002CCC0C /* juce_modules.mm */,
CD0A5B3E181707F700DA0342 /* mac.cpp */, CD0A5B3E181707F700DA0342 /* mac.cpp */,
CD0A5B4C18170EC600DA0342 /* Frameworks */, CD0A5B4C18170EC600DA0342 /* Frameworks */,
CD0A5B331817074500DA0342 /* Products */, CD0A5B331817074500DA0342 /* Products */,
@@ -139,7 +146,8 @@
files = ( files = (
CD0A5B3F181707F700DA0342 /* mac.cpp in Sources */, CD0A5B3F181707F700DA0342 /* mac.cpp in Sources */,
CD0A5B421817097800DA0342 /* BeastUnitTests.cpp in Sources */, CD0A5B421817097800DA0342 /* BeastUnitTests.cpp in Sources */,
CD0A5B4918170DC300DA0342 /* beast.mm in Sources */, CD1CBE68181B2D99002CCC0C /* juce_modules.mm in Sources */,
CD0A5B4918170DC300DA0342 /* beast_modules.mm in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -180,9 +188,10 @@
HEADER_SEARCH_PATHS = ( HEADER_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../../src",
"$(SRCROOT)/../../../../../../../JUCE",
"$(SRCROOT)/../../../../config", "$(SRCROOT)/../../../../config",
"$(SRCROOT)/../../../..", "$(SRCROOT)/../../../..",
"$(SRCROOT)/../../../../beast",
); );
MACOSX_DEPLOYMENT_TARGET = 10.8; MACOSX_DEPLOYMENT_TARGET = 10.8;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
@@ -219,9 +228,10 @@
HEADER_SEARCH_PATHS = ( HEADER_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../../src",
"$(SRCROOT)/../../../../../../../JUCE",
"$(SRCROOT)/../../../../config", "$(SRCROOT)/../../../../config",
"$(SRCROOT)/../../../..", "$(SRCROOT)/../../../..",
"$(SRCROOT)/../../../../beast",
); );
MACOSX_DEPLOYMENT_TARGET = 10.8; MACOSX_DEPLOYMENT_TARGET = 10.8;
SDKROOT = macosx; SDKROOT = macosx;

View File

@@ -0,0 +1,94 @@
/*
IMPORTANT! This file is auto-generated each time you save your
project - if you alter its contents, your changes may be overwritten!
There's a section below where you can add your own custom code safely, and the
Introjucer will preserve the contents of that block, but the best way to change
any of these definitions is by using the Introjucer's project settings.
Any commented-out settings will assume their default values.
*/
#ifndef __JUCE_APPCONFIG_M70QFTRRK__
#define __JUCE_APPCONFIG_M70QFTRRK__
//==============================================================================
// [BEGIN_USER_CODE_SECTION]
// (You can add your own code in this section, and the Introjucer will not overwrite it)
// [END_USER_CODE_SECTION]
//==============================================================================
#define JUCE_MODULE_AVAILABLE_juce_core 1
//#define JUCE_MODULE_AVAILABLE_juce_cryptography 1
//#define JUCE_MODULE_AVAILABLE_juce_data_structures 1
#define JUCE_MODULE_AVAILABLE_juce_events 1
//#define JUCE_MODULE_AVAILABLE_juce_graphics 1
//#define JUCE_MODULE_AVAILABLE_juce_gui_basics 1
//#define JUCE_MODULE_AVAILABLE_juce_gui_extra 1
//==============================================================================
// juce_core flags:
#ifndef JUCE_FORCE_DEBUG
//#define JUCE_FORCE_DEBUG
#endif
#ifndef JUCE_LOG_ASSERTIONS
#define JUCE_LOG_ASSERTIONS 1
#endif
#ifndef JUCE_CHECK_MEMORY_LEAKS
//#define JUCE_CHECK_MEMORY_LEAKS
#endif
#ifndef JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
//#define JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
#endif
#ifndef JUCE_INCLUDE_ZLIB_CODE
//#define JUCE_INCLUDE_ZLIB_CODE
#endif
//==============================================================================
// juce_graphics flags:
#ifndef JUCE_USE_COREIMAGE_LOADER
#define JUCE_USE_COREIMAGE_LOADER 0
#endif
#ifndef JUCE_USE_DIRECTWRITE
//#define JUCE_USE_DIRECTWRITE
#endif
//==============================================================================
// juce_gui_basics flags:
#ifndef JUCE_ENABLE_REPAINT_DEBUGGING
//#define JUCE_ENABLE_REPAINT_DEBUGGING
#endif
#ifndef JUCE_USE_XSHM
//#define JUCE_USE_XSHM
#endif
#ifndef JUCE_USE_XRENDER
//#define JUCE_USE_XRENDER
#endif
#ifndef JUCE_USE_XCURSOR
//#define JUCE_USE_XCURSOR
#endif
//==============================================================================
// juce_gui_extra flags:
#ifndef JUCE_WEB_BROWSER
//#define JUCE_WEB_BROWSER
#endif
#endif // __JUCE_APPCONFIG_M70QFTRRK__

View File

@@ -20,7 +20,7 @@
#ifndef UNITTESTS_BEASTUNITTESTS_H_INCLUDED #ifndef UNITTESTS_BEASTUNITTESTS_H_INCLUDED
#define UNITTESTS_BEASTUNITTESTS_H_INCLUDED #define UNITTESTS_BEASTUNITTESTS_H_INCLUDED
#include "beast.h" #include "beast_modules.h"
int runUnitTests (beast::String const& match, beast::String const& format); int runUnitTests (beast::String const& match, beast::String const& format);

View File

@@ -17,7 +17,7 @@
*/ */
//============================================================================== //==============================================================================
#include "beast.h" #include "beast_modules.h"
#include "modules/beast_core/beast_core.cpp" #include "modules/beast_core/beast_core.cpp"
#include "modules/beast_vflib/beast_vflib.cpp" #include "modules/beast_vflib/beast_vflib.cpp"

View File

@@ -17,8 +17,8 @@
*/ */
//============================================================================== //==============================================================================
#ifndef UNITTESTS_BEAST_H_INCLUDED #ifndef UNITTESTS_BEASTMODULES_H_INCLUDED
#define UNITTESTS_BEAST_H_INCLUDED #define UNITTESTS_BEASTMODULES_H_INCLUDED
#include "BeastConfig.h" #include "BeastConfig.h"

View File

@@ -0,0 +1,20 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include "beast_modules.cpp"

View File

@@ -0,0 +1,21 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include "modules/juce_core/juce_core.cpp"
#include "modules/juce_events/juce_events.cpp"

View File

@@ -0,0 +1,28 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef UNITTESTS_JUCEMODULES_H_INCLUDED
#define UNITTESTS_JUCEMODULES_H_INCLUDED
#include "AppConfig.h"
#include "modules/juce_core/juce_core.h"
#include "modules/juce_events/juce_events.h"
#endif

View File

@@ -17,4 +17,4 @@
*/ */
//============================================================================== //==============================================================================
#include "beast.cpp" #include "juce_modules.cpp"

View File

@@ -17,9 +17,13 @@
*/ */
//============================================================================== //==============================================================================
#include "juce_modules.h"
#include "beast_modules.h"
#include "BeastUnitTests.h" #include "BeastUnitTests.h"
int main(int argc, const char * argv[]) int main(int argc, const char * argv[])
{ {
juce::ScopedJuceInitialiser_GUI juce;
return runUnitTests("", "text"); return runUnitTests("", "text");
} }

View File

@@ -1,3 +1,22 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright Patrick Dehne <patrick@mysonicweb.de> (www.sonicweb-radio.de)
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <stdio.h> #include <stdio.h>
#include <tchar.h> #include <tchar.h>

View File

@@ -199,7 +199,7 @@ void PropertySet::restoreFromXml (const XmlElement& xml)
const ScopedLock sl (lock); const ScopedLock sl (lock);
clear(); clear();
forEachXmlChildElementWithTagName (xml, e, "VALUE") beast_forEachXmlChildElementWithTagName (xml, e, "VALUE")
{ {
if (e->hasAttribute ("name") if (e->hasAttribute ("name")
&& e->hasAttribute ("val")) && e->hasAttribute ("val"))

View File

@@ -47,7 +47,7 @@ FileLogger::~FileLogger() {}
void FileLogger::logMessage (const String& message) void FileLogger::logMessage (const String& message)
{ {
const ScopedLock sl (logLock); const ScopedLock sl (logLock);
DBG (message); BDBG (message);
FileOutputStream out (logFile, 256); FileOutputStream out (logFile, 256);
out << message << newLine; out << message << newLine;
} }

View File

@@ -52,7 +52,7 @@ void logAssertion (const char* const filename, const int lineNum) noexcept
#if BEAST_LOG_ASSERTIONS #if BEAST_LOG_ASSERTIONS
Logger::writeToLog (m); Logger::writeToLog (m);
#else #else
DBG (m); BDBG (m);
#endif #endif
} }
#endif #endif

View File

@@ -93,7 +93,7 @@ struct Expression::Helpers
public: public:
EvaluationError (const String& desc) : description (desc) EvaluationError (const String& desc) : description (desc)
{ {
DBG ("Expression::EvaluationError: " + description); BDBG ("Expression::EvaluationError: " + description);
} }
String description; String description;
@@ -1086,7 +1086,7 @@ SharedPtr<Expression::Term> Expression::Term::negated()
Expression::ParseError::ParseError (const String& message) Expression::ParseError::ParseError (const String& message)
: description (message) : description (message)
{ {
DBG ("Expression::ParseError: " + message); BDBG ("Expression::ParseError: " + message);
} }
//============================================================================== //==============================================================================

View File

@@ -47,10 +47,10 @@
# ifdef _VARIADIC_MAX # ifdef _VARIADIC_MAX
# define BEAST_VARIADIC_MAX _VARIADIC_MAX # define BEAST_VARIADIC_MAX _VARIADIC_MAX
# else # else
# define BEAST_VARIADIC_MAX 9 # define BEAST_VARIADIC_MAX 10
# endif # endif
#else #else
# define BEAST_VARIADIC_MAX 9 # define BEAST_VARIADIC_MAX 10
#endif #endif
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@@ -43,7 +43,7 @@
@see forEachXmlChildElementWithTagName @see forEachXmlChildElementWithTagName
*/ */
#define forEachXmlChildElement(parentXmlElement, childElementVariableName) \ #define beast_forEachXmlChildElement(parentXmlElement, childElementVariableName) \
\ \
for (beast::XmlElement* childElementVariableName = (parentXmlElement).getFirstChildElement(); \ for (beast::XmlElement* childElementVariableName = (parentXmlElement).getFirstChildElement(); \
childElementVariableName != nullptr; \ childElementVariableName != nullptr; \
@@ -72,7 +72,7 @@
@see forEachXmlChildElement @see forEachXmlChildElement
*/ */
#define forEachXmlChildElementWithTagName(parentXmlElement, childElementVariableName, requiredTagName) \ #define beast_forEachXmlChildElementWithTagName(parentXmlElement, childElementVariableName, requiredTagName) \
\ \
for (beast::XmlElement* childElementVariableName = (parentXmlElement).getChildByName (requiredTagName); \ for (beast::XmlElement* childElementVariableName = (parentXmlElement).getChildByName (requiredTagName); \
childElementVariableName != nullptr; \ childElementVariableName != nullptr; \

View File

@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/* /*
This file is part of Beast: https://github.com/vinniefalco/Beast This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com> Copyright Patrick Dehne <patrick@mysonicweb.de> (www.sonicweb-radio.de)
Permission to use, copy, modify, and/or distribute this software for any Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above purpose with or without fee is hereby granted, provided that the above
@@ -20,3 +20,9 @@
#include "beast_vflib.h" #include "beast_vflib.h"
#include "threads/ThreadWithServiceQueue.cpp" #include "threads/ThreadWithServiceQueue.cpp"
/** Unit tests for header only classes
*/
static beast::detail::CallQueueTests callQueueTests;
static beast::detail::ManualServiceQueueTests manualServiceQueueTests;

View File

@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/* /*
This file is part of BeastUtils: https://github.com/pdehne/BeastUtils This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Patrick Dehne <patrick@sonicweb.de> Copyright Patrick Dehne <patrick@mysonicweb.de> (www.sonicweb-radio.de)
Permission to use, copy, modify, and/or distribute this software for any Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above purpose with or without fee is hereby granted, provided that the above
@@ -21,7 +21,9 @@
#define BEAST_VFLIB_H_INCLUDED #define BEAST_VFLIB_H_INCLUDED
#include "functor/BindHelper.h" #include "functor/BindHelper.h"
#include "threads/BindableServiceQueue.h" #include "threads/CallQueue.h"
#include "threads/ThreadWithServiceQueue.h" #include "threads/ThreadWithServiceQueue.h"
#include "threads/ManualServiceQueue.h"
#include "threads/GuiServiceQueue.h"
#endif #endif

View File

@@ -2,6 +2,7 @@
/* /*
This file is part of Beast: https://github.com/vinniefalco/Beast This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com> Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Copyright Patrick Dehne <patrick@mysonicweb.de> (www.sonicweb-radio.de)
Permission to use, copy, modify, and/or distribute this software for any Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above purpose with or without fee is hereby granted, provided that the above
@@ -38,6 +39,7 @@ private:
UnaryFunction m_f; UnaryFunction m_f;
public: public:
#if BEAST_VARIADIC_MAX >= 1
template <typename Arg> template <typename Arg>
explicit BindHelper (Arg& arg) explicit BindHelper (Arg& arg)
: m_f (arg) : m_f (arg)
@@ -51,26 +53,61 @@ public:
template <typename F> template <typename F>
void operator() (F const& f) const void operator() (F const& f) const
{ m_f (f); } { m_f (f); }
#endif
#if BEAST_VARIADIC_MAX >= 2
template <typename F, class P1> template <typename F, class P1>
void operator() (F const& f, P1 const& p1) const void operator() (F const& f, P1 const& p1) const
{ m_f (bind (f, p1)); } { m_f (bind (f, p1)); }
#endif
#if BEAST_VARIADIC_MAX >= 3
template <typename F, class P1, class P2> template <typename F, class P1, class P2>
void operator() (F const& f, P1 const& p1, P2 const& p2) const void operator() (F const& f, P1 const& p1, P2 const& p2) const
{ m_f (bind (f, p1, p2)); } { m_f (bind (f, p1, p2)); }
#endif
#if BEAST_VARIADIC_MAX >= 4
template <typename F, class P1, class P2, class P3> template <typename F, class P1, class P2, class P3>
void operator() (F const& f, P1 const& p1, P2 const& p2, P3 const& p3) const void operator() (F const& f, P1 const& p1, P2 const& p2, P3 const& p3) const
{ m_f (bind (f, p1, p2, p3)); } { m_f (bind (f, p1, p2, p3)); }
#endif
#if BEAST_VARIADIC_MAX >= 5
template <typename F, class P1, class P2, class P3, class P4> template <typename F, class P1, class P2, class P3, class P4>
void operator() (F const& f, P1 const& p1, P2 const& p2, P3 const& p3, P4 const& p4) const void operator() (F const& f, P1 const& p1, P2 const& p2, P3 const& p3, P4 const& p4) const
{ m_f (bind (f, p1, p2, p3, p4)); } { m_f (bind (f, p1, p2, p3, p4)); }
#endif
#if BEAST_VARIADIC_MAX >= 6
template <typename F, class P1, class P2, class P3, class P4, class P5> template <typename F, class P1, class P2, class P3, class P4, class P5>
void operator() (F const& f, P1 const& p1, P2 const& p2, P3 const& p3, P4 const& p4, P5 const& p5) const void operator() (F const& f, P1 const& p1, P2 const& p2, P3 const& p3, P4 const& p4, P5 const& p5) const
{ m_f (bind (f, p1, p2, p3, p4, p5)); } { m_f (bind (f, p1, p2, p3, p4, p5)); }
#endif
#if BEAST_VARIADIC_MAX >= 7
template <typename F, class P1, class P2, class P3, class P4, class P5, class P6>
void operator() (F const& f, P1 const& p1, P2 const& p2, P3 const& p3, P4 const& p4, P5 const& p5, P6 const& p6) const
{ m_f (bind (f, p1, p2, p3, p4, p5, p6)); }
#endif
#if BEAST_VARIADIC_MAX >= 8
template <typename F, class P1, class P2, class P3, class P4, class P5, class P6, class P7>
void operator() (F const& f, P1 const& p1, P2 const& p2, P3 const& p3, P4 const& p4, P5 const& p5, P6 const& p6, P7 const& p7) const
{ m_f (bind (f, p1, p2, p3, p4, p5, p6, p7)); }
#endif
#if BEAST_VARIADIC_MAX >= 9
template <typename F, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>
void operator() (F const& f, P1 const& p1, P2 const& p2, P3 const& p3, P4 const& p4, P5 const& p5, P6 const& p6, P7 const& p7, P8 const& p8) const
{ m_f (bind (f, p1, p2, p3, p4, p5, p6, p7, p8)); }
#endif
#if BEAST_VARIADIC_MAX >= 10
template <typename F, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9>
void operator() (F const& f, P1 const& p1, P2 const& p2, P3 const& p3, P4 const& p4, P5 const& p5, P6 const& p6, P7 const& p7, P8 const& p8, P9 const& p9) const
{ m_f (bind (f, p1, p2, p3, p4, p5, p6, p7, p8, p9)); }
#endif
}; };
} }

View File

@@ -1,71 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_VFLIB_BINDABLESERVICEQUEUETYPE_H_INCLUDED
#define BEAST_VFLIB_BINDABLESERVICEQUEUETYPE_H_INCLUDED
#include "beast/Threads.h"
#include "../functor/BindHelper.h"
namespace beast {
template <class Allocator = std::allocator <char> >
class BindableServiceQueueType
: public ServiceQueueType <Allocator>
{
public:
explicit BindableServiceQueueType (int expectedConcurrency = 1,
Allocator alloc = Allocator())
: ServiceQueueType<Allocator>(expectedConcurrency, alloc)
, queue(*this)
, call(*this)
{
}
struct BindHelperPost
{
BindableServiceQueueType<Allocator>& m_queue;
explicit BindHelperPost (BindableServiceQueueType<Allocator>& queue)
: m_queue (queue)
{ }
template <typename F>
void operator() (F const& f) const
{ m_queue.post ( F (f) ); }
};
struct BindHelperDispatch
{
BindableServiceQueueType<Allocator>& m_queue;
explicit BindHelperDispatch (BindableServiceQueueType<Allocator>& queue)
: m_queue (queue)
{ }
template <typename F>
void operator() (F const& f) const
{ m_queue.dispatch ( F (f) ); }
};
BindHelper <BindHelperPost> const queue;
BindHelper <BindHelperDispatch> const call;
};
typedef BindableServiceQueueType <std::allocator <char> > BindableServiceQueue;
}
#endif

View File

@@ -0,0 +1,382 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Copyright Patrick Dehne <patrick@mysonicweb.de> (www.sonicweb-radio.de)
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_VFLIB_CALLQUEUE_H_INCLUDED
#define BEAST_VFLIB_CALLQUEUE_H_INCLUDED
#include "beast/Threads.h"
#include "../functor/BindHelper.h"
namespace beast {
template <class Allocator = std::allocator <char> >
class CallQueueType
: public ServiceQueueType <Allocator>
{
public:
explicit CallQueueType (const String& name,
int expectedConcurrency = 1,
Allocator alloc = Allocator())
: ServiceQueueType<Allocator>(expectedConcurrency, alloc)
, m_name (name)
, queue(*this)
, call(*this)
{
}
~CallQueueType ()
{
// Someone forget to close the queue.
bassert (m_closed.isSignaled ());
// Can't destroy queue with unprocessed calls.
bassert (ServiceQueueBase::empty ());
}
void enqueue (ServiceQueueBase::Item* item)
{
// If this goes off someone added calls
// after the queue has been closed.
bassert (!m_closed.isSignaled ());
ServiceQueueType <Allocator>::enqueue (item);
}
/** Close the queue.
Functors may not be added after this routine is called. This is used for
diagnostics, to track down spurious calls during application shutdown
or exit. Derived classes may call this if the appropriate time is known.
The queue is synchronized after it is closed.
Can still have pending calls, just can't put new ones in.
*/
virtual void close ()
{
m_closed.signal ();
ServiceQueueType <Allocator>::stop ();
}
struct BindHelperPost
{
CallQueueType<Allocator>& m_queue;
explicit BindHelperPost (CallQueueType<Allocator>& queue)
: m_queue (queue)
{ }
template <typename F>
void operator() (F const& f) const
{ m_queue.post ( F (f) ); }
};
struct BindHelperDispatch
{
CallQueueType<Allocator>& m_queue;
explicit BindHelperDispatch (CallQueueType<Allocator>& queue)
: m_queue (queue)
{ }
template <typename F>
void operator() (F const& f) const
{ m_queue.dispatch ( F (f) ); }
};
BindHelper <BindHelperPost> const queue;
BindHelper <BindHelperDispatch> const call;
private:
String m_name;
AtomicFlag m_closed;
};
typedef CallQueueType <std::allocator <char> > CallQueue;
namespace detail
{
//------------------------------------------------------------------------------
class CallQueueTests
: public UnitTest
{
public:
struct CallTracker
{
CallQueueTests *unitTest;
int c0, c1, c2, c3, c4, c5, c6, c7, c8;
int q0, q1, q2, q3, q4, q5, q6, q7, q8;
CallTracker(CallQueueTests *parent)
: unitTest(parent)
, c0(0), c1(0), c2(0), c3(0), c4(0), c5(0), c6(0), c7(0), c8(0)
, q0(0), q1(0), q2(0), q3(0), q4(0), q5(0), q6(0), q7(0), q8(0)
{
}
void doQ0() { q0++; }
void doQ1(const String& p1)
{
unitTest->expect(p1 == "p1");
q1++;
}
void doQ2(const String& p1, const String& p2)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
q2++;
}
void doQ3(const String& p1, const String& p2, const String& p3)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
unitTest->expect(p3 == "p3");
q3++;
}
void doQ4(const String& p1, const String& p2, const String& p3, const String& p4)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
unitTest->expect(p3 == "p3");
unitTest->expect(p4 == "p4");
q4++;
}
void doQ5(const String& p1, const String& p2, const String& p3, const String& p4, const String& p5)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
unitTest->expect(p3 == "p3");
unitTest->expect(p4 == "p4");
unitTest->expect(p5 == "p5");
q5++;
}
void doQ6(const String& p1, const String& p2, const String& p3, const String& p4, const String& p5, const String& p6)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
unitTest->expect(p3 == "p3");
unitTest->expect(p4 == "p4");
unitTest->expect(p5 == "p5");
unitTest->expect(p6 == "p6");
q6++;
}
void doQ7(const String& p1, const String& p2, const String& p3, const String& p4, const String& p5, const String& p6, const String& p7)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
unitTest->expect(p3 == "p3");
unitTest->expect(p4 == "p4");
unitTest->expect(p5 == "p5");
unitTest->expect(p6 == "p6");
unitTest->expect(p7 == "p7");
q7++;
}
void doQ8(const String& p1, const String& p2, const String& p3, const String& p4, const String& p5, const String& p6, const String& p7, const String& p8)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
unitTest->expect(p3 == "p3");
unitTest->expect(p4 == "p4");
unitTest->expect(p5 == "p5");
unitTest->expect(p6 == "p6");
unitTest->expect(p7 == "p7");
unitTest->expect(p8 == "p8");
q8++;
}
void doC0() { c0++; }
void doC1(const String& p1)
{
unitTest->expect(p1 == "p1");
c1++;
}
void doC2(const String& p1, const String& p2)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
c2++;
}
void doC3(const String& p1, const String& p2, const String& p3)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
unitTest->expect(p3 == "p3");
c3++;
}
void doC4(const String& p1, const String& p2, const String& p3, const String& p4)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
unitTest->expect(p3 == "p3");
unitTest->expect(p4 == "p4");
c4++;
}
void doC5(const String& p1, const String& p2, const String& p3, const String& p4, const String& p5)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
unitTest->expect(p3 == "p3");
unitTest->expect(p4 == "p4");
unitTest->expect(p5 == "p5");
c5++;
}
void doC6(const String& p1, const String& p2, const String& p3, const String& p4, const String& p5, const String& p6)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
unitTest->expect(p3 == "p3");
unitTest->expect(p4 == "p4");
unitTest->expect(p5 == "p5");
unitTest->expect(p6 == "p6");
c6++;
}
void doC7(const String& p1, const String& p2, const String& p3, const String& p4, const String& p5, const String& p6, const String& p7)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
unitTest->expect(p3 == "p3");
unitTest->expect(p4 == "p4");
unitTest->expect(p5 == "p5");
unitTest->expect(p6 == "p6");
unitTest->expect(p7 == "p7");
c7++;
}
void doC8(const String& p1, const String& p2, const String& p3, const String& p4, const String& p5, const String& p6, const String& p7, const String& p8)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
unitTest->expect(p3 == "p3");
unitTest->expect(p4 == "p4");
unitTest->expect(p5 == "p5");
unitTest->expect(p6 == "p6");
unitTest->expect(p7 == "p7");
unitTest->expect(p8 == "p8");
c8++;
}
};
CallTracker m_callTracker;
void testArities ()
{
beginTestCase("Arities");
int calls = 0;
#if BEAST_VARIADIC_MAX >= 2
m_queue.queue(&CallTracker::doQ0, &m_callTracker); calls++;
m_queue.queue(&CallTracker::doC0, &m_callTracker); calls++;
#endif
#if BEAST_VARIADIC_MAX >= 3
m_queue.queue(&CallTracker::doQ1, &m_callTracker, "p1"); calls++;
m_queue.queue(&CallTracker::doC1, &m_callTracker, "p1"); calls++;
#endif
#if BEAST_VARIADIC_MAX >= 4
m_queue.queue(&CallTracker::doQ2, &m_callTracker, "p1", "p2"); calls++;
m_queue.queue(&CallTracker::doC2, &m_callTracker, "p1", "p2"); calls++;
#endif
#if BEAST_VARIADIC_MAX >= 5
m_queue.queue(&CallTracker::doQ3, &m_callTracker, "p1", "p2", "p3"); calls++;
m_queue.queue(&CallTracker::doC3, &m_callTracker, "p1", "p2", "p3"); calls++;
#endif
#if BEAST_VARIADIC_MAX >= 6
m_queue.queue(&CallTracker::doQ4, &m_callTracker, "p1", "p2", "p3", "p4"); calls++;
m_queue.queue(&CallTracker::doC4, &m_callTracker, "p1", "p2", "p3", "p4"); calls++;
#endif
#if BEAST_VARIADIC_MAX >= 7
m_queue.queue(&CallTracker::doQ5, &m_callTracker, "p1", "p2", "p3", "p4", "p5"); calls++;
m_queue.queue(&CallTracker::doC5, &m_callTracker, "p1", "p2", "p3", "p4", "p5"); calls++;
#endif
#if BEAST_VARIADIC_MAX >= 8
m_queue.queue(&CallTracker::doQ6, &m_callTracker, "p1", "p2", "p3", "p4", "p5", "p6"); calls++;
m_queue.queue(&CallTracker::doC6, &m_callTracker, "p1", "p2", "p3", "p4", "p5", "p6"); calls++;
#endif
#if BEAST_VARIADIC_MAX >= 9
m_queue.queue(&CallTracker::doQ7, &m_callTracker, "p1", "p2", "p3", "p4", "p5", "p6", "p7"); calls++;
m_queue.queue(&CallTracker::doC7, &m_callTracker, "p1", "p2", "p3", "p4", "p5", "p6", "p7"); calls++;
#endif
#if BEAST_VARIADIC_MAX >= 10
m_queue.queue(&CallTracker::doQ8, &m_callTracker, "p1", "p2", "p3", "p4", "p5", "p6", "p7", "p8"); calls++;
m_queue.queue(&CallTracker::doC8, &m_callTracker, "p1", "p2", "p3", "p4", "p5", "p6", "p7", "p8"); calls++;
#endif
std::size_t performedCalls = m_queue.poll();
m_queue.close();
expect (performedCalls == calls);
expect (m_callTracker.c0 == 1);
expect (m_callTracker.c1 == 1);
expect (m_callTracker.c2 == 1);
expect (m_callTracker.c3 == 1);
expect (m_callTracker.c4 == 1);
expect (m_callTracker.c5 == 1);
expect (m_callTracker.q0 == 1);
expect (m_callTracker.q1 == 1);
expect (m_callTracker.q2 == 1);
expect (m_callTracker.q3 == 1);
expect (m_callTracker.q4 == 1);
expect (m_callTracker.q5 == 1);
}
void runTest()
{
testArities();
}
CallQueueTests ()
: UnitTest ("CallQueue", "beast")
, m_queue("CallQueue Test Queue")
, m_callTracker(this)
{
}
CallQueue m_queue;
};
}
}
#endif

View File

@@ -0,0 +1,72 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Copyright Patrick Dehne <patrick@mysonicweb.de> (www.sonicweb-radio.de)
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_VFLIB_GUISERVICEQUEUE_H_INCLUDED
#define BEAST_VFLIB_GUISERVICEQUEUE_H_INCLUDED
#include "AppConfig.h"
#include "modules/juce_core/juce_core.h"
#include "modules/juce_events/juce_events.h"
#include "CallQueue.h"
namespace beast {
class GuiServiceQueue
: public CallQueue
, private juce::AsyncUpdater
, private ThreadWithServiceQueue::EntryPoints
{
public:
explicit GuiServiceQueue (const String& name)
: CallQueue(name)
, m_thread(name)
{
bassert (juce::MessageManager::getInstance()->isThisTheMessageThread());
m_thread.start (this);
}
void close ()
{
m_thread.stop (true);
CallQueue::close ();
}
void enqueue (ServiceQueueBase::Item* item)
{
CallQueue::enqueue (item);
m_thread.call (&juce::AsyncUpdater::triggerAsyncUpdate, (AsyncUpdater*)this);
}
void handleAsyncUpdate()
{
poll();
}
private:
ThreadWithServiceQueue m_thread;
};
}
#endif

View File

@@ -0,0 +1,165 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright Patrick Dehne <patrick@mysonicweb.de> (www.sonicweb-radio.de)
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_VFLIB_MANUALSERVICEQUEUE_H_INCLUDED
#define BEAST_VFLIB_MANUALSERVICEQUEUE_H_INCLUDED
#include "CallQueue.h"
namespace beast {
class ManualServiceQueue
: public CallQueue
{
public:
explicit ManualServiceQueue (const String& name)
: CallQueue(name)
{
}
/** Calls all functors in the queue. Returns if there are no
more functors available to run
*/
bool synchronize ()
{
if(poll() > 0)
return true;
return false;
}
};
//------------------------------------------------------------------------------
namespace detail
{
//------------------------------------------------------------------------------
class ManualServiceQueueTests
: public UnitTest
{
public:
struct CallTracker
{
ManualServiceQueueTests *unitTest;
int c0, c1;
int q0, q1;
CallTracker(ManualServiceQueueTests *parent)
: unitTest(parent)
, c0(0), c1(0)
, q0(0), q1(0)
{
}
void doQ0() { q0++; }
void doQ1(const String& p1)
{
unitTest->expect(p1 == "p1");
q1++;
}
void doC0() { c0++; }
void doC1(const String& p1)
{
unitTest->expect(p1 == "p1");
c1++;
}
};
void performEmptyQueue()
{
beginTestCase("Empty queue");
ManualServiceQueue queue("ManualServiceQueueTests");
bool doneSomething = queue.synchronize();
expect(!doneSomething);
queue.close();
}
void performCalls()
{
beginTestCase("Calls");
Random r;
r.setSeedRandomly();
ManualServiceQueue queue("ManualServiceQueueTests");
static int const batches = 1000;
for(std::size_t i=0; i<batches; i++)
{
CallTracker ct(this);
std::size_t batchSize = r.nextLargeNumber(10).toInteger();
if(batchSize > 0)
{
for(std::size_t y=0; y<batchSize; y++)
{
int callType = r.nextLargeNumber(10).toInteger();
if(callType % 2)
{
queue.queue(&CallTracker::doQ0, &ct);
queue.call(&CallTracker::doC0, &ct);
}
else
{
queue.queue(&CallTracker::doQ1, &ct, "p1");
queue.call(&CallTracker::doC1, &ct, "p1");
}
}
bool doneSomething = queue.synchronize();
expect(doneSomething);
expect ((ct.q0 + ct.q1) == batchSize);
expect ((ct.c0 + ct.c1) == batchSize);
doneSomething = queue.synchronize();
expect(!doneSomething);
}
}
queue.close ();
}
void runTest()
{
performEmptyQueue ();
performCalls ();
}
ManualServiceQueueTests () : UnitTest ("ManualServiceQueue", "beast")
{
}
};
}
}
#endif

View File

@@ -2,6 +2,7 @@
/* /*
This file is part of Beast: https://github.com/vinniefalco/Beast This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com> Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Copyright Patrick Dehne <patrick@mysonicweb.de> (www.sonicweb-radio.de)
Permission to use, copy, modify, and/or distribute this software for any Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above purpose with or without fee is hereby granted, provided that the above
@@ -22,11 +23,11 @@
namespace beast { namespace beast {
ThreadWithServiceQueue::ThreadWithServiceQueue (const String& name) ThreadWithServiceQueue::ThreadWithServiceQueue (const String& name)
: Thread (name) : CallQueue(name)
, m_thread(name, this)
, m_entryPoints(nullptr) , m_entryPoints(nullptr)
, m_calledStart(false) , m_calledStart(false)
, m_calledStop(false) , m_calledStop(false)
, m_interrupted(false)
{ {
} }
@@ -37,24 +38,17 @@ ThreadWithServiceQueue::~ThreadWithServiceQueue()
void ThreadWithServiceQueue::start (EntryPoints* const entryPoints) void ThreadWithServiceQueue::start (EntryPoints* const entryPoints)
{ {
{
CriticalSection::ScopedLockType lock (m_mutex);
// start() MUST be called. // start() MUST be called.
bassert (!m_calledStart); bassert (!m_calledStart);
m_calledStart = true; m_calledStart = true;
}
m_entryPoints = entryPoints; m_entryPoints = entryPoints;
startThread(); m_thread.startThread ();
} }
void ThreadWithServiceQueue::stop (bool const wait) void ThreadWithServiceQueue::stop (bool const wait)
{ {
{
CriticalSection::ScopedLockType lock (m_mutex);
// start() MUST be called. // start() MUST be called.
bassert (m_calledStart); bassert (m_calledStart);
@@ -62,66 +56,32 @@ void ThreadWithServiceQueue::stop (bool const wait)
{ {
m_calledStop = true; m_calledStop = true;
{ m_thread.signalThreadShouldExit();
CriticalSection::ScopedUnlockType unlock (m_mutex);
call (&Thread::signalThreadShouldExit, this);
// something could slip in here // something could slip in here
// m_queue.close(); close ();
}
}
} }
if (wait) if (wait)
waitForThreadToExit(); m_thread.waitForThreadToExit ();
} }
void ThreadWithServiceQueue::interrupt () void ThreadWithServiceQueue::runThread ()
{
call (&ThreadWithServiceQueue::doInterrupt, this);
}
bool ThreadWithServiceQueue::interruptionPoint ()
{
return m_interrupted;
}
void ThreadWithServiceQueue::run ()
{ {
m_entryPoints->threadInit (); m_entryPoints->threadInit ();
while (! this->threadShouldExit()) while (! m_thread.threadShouldExit ())
{ run ();
run_one();
bool isInterrupted = m_entryPoints->threadIdle(); // Perform the remaining calls in the queue
isInterrupted |= interruptionPoint(); reset ();
poll ();
if(isInterrupted)
{
// We put this call into the service queue to make
// sure we get through to threadIdle without
// waiting
call (&ThreadWithServiceQueue::doWakeUp, this);
}
}
m_entryPoints->threadExit(); m_entryPoints->threadExit();
} }
void ThreadWithServiceQueue::doInterrupt ()
{
m_interrupted = true;
}
void ThreadWithServiceQueue::doWakeUp ()
{
m_interrupted = false;
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
namespace detail namespace detail
@@ -129,22 +89,27 @@ namespace detail
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
class BindableServiceQueueTests class ThreadWithServiceQueueTests
: public UnitTest : public UnitTest
{ {
public: public:
struct BindableServiceQueueRunner struct ThreadWithServiceQueueRunner
: public ThreadWithServiceQueue::EntryPoints : public ThreadWithServiceQueue::EntryPoints
{ {
ThreadWithServiceQueue m_worker; ThreadWithServiceQueue m_worker;
int cCallCount, c1CallCount, idleInterruptedCount; int cCallCount, c1CallCount;
int qCallCount, q1CallCount;
int initCalled, exitCalled;
BindableServiceQueueRunner() ThreadWithServiceQueueRunner()
: m_worker("BindableServiceQueueRunner") : m_worker("ThreadWithServiceQueueRunner")
, cCallCount(0) , cCallCount(0)
, c1CallCount(0) , c1CallCount(0)
, idleInterruptedCount(0) , qCallCount(0)
, q1CallCount(0)
, initCalled(0)
, exitCalled(0)
{ {
} }
@@ -158,14 +123,9 @@ public:
m_worker.stop(true); m_worker.stop(true);
} }
void interrupt()
{
m_worker.interrupt();
}
void c() void c()
{ {
m_worker.queue(&BindableServiceQueueRunner::cImpl, this); m_worker.call(&ThreadWithServiceQueueRunner::cImpl, this);
} }
void cImpl() void cImpl()
@@ -175,7 +135,7 @@ public:
void c1(int p1) void c1(int p1)
{ {
m_worker.queue(&BindableServiceQueueRunner::c1Impl, this, p1); m_worker.call(&ThreadWithServiceQueueRunner::c1Impl, this, p1);
} }
void c1Impl(int p1) void c1Impl(int p1)
@@ -183,30 +143,58 @@ public:
c1CallCount++; c1CallCount++;
} }
bool threadIdle () void q()
{ {
bool interrupted = m_worker.interruptionPoint (); m_worker.queue(&ThreadWithServiceQueueRunner::qImpl, this);
}
if(interrupted) void qImpl()
idleInterruptedCount++; {
qCallCount++;
}
return interrupted; void q1(int p1)
{
m_worker.queue(&ThreadWithServiceQueueRunner::q1Impl, this, p1);
}
void q1Impl(int p1)
{
q1CallCount++;
}
void threadInit ()
{
initCalled++;
}
void threadExit ()
{
exitCalled++;
} }
}; };
static int const calls = 10000; static int const calls = 1000;
void performCalls() void performCalls()
{ {
Random r; Random r;
r.setSeedRandomly(); r.setSeedRandomly();
BindableServiceQueueRunner runner; ThreadWithServiceQueueRunner runner;
beginTestCase("Calls and interruptions");
runner.start(); runner.start();
for(std::size_t i=0; i<calls; i++)
{
int wait = r.nextLargeNumber(10).toInteger();
if(wait % 2)
runner.q();
else
runner.q1Impl(wait);
}
for(std::size_t i=0; i<calls; i++) for(std::size_t i=0; i<calls; i++)
{ {
int wait = r.nextLargeNumber(10).toInteger(); int wait = r.nextLargeNumber(10).toInteger();
@@ -217,30 +205,31 @@ public:
runner.c1Impl(wait); runner.c1Impl(wait);
} }
for(std::size_t i=0; i<calls; i++)
runner.interrupt();
runner.stop(); runner.stop();
// We can only reason that the idle method must have been interrupted
// at least once
expect ((runner.cCallCount + runner.c1CallCount) == calls); expect ((runner.cCallCount + runner.c1CallCount) == calls);
expect (runner.idleInterruptedCount > 0); expect ((runner.qCallCount + runner.q1CallCount) == calls);
expect (runner.initCalled == 1);
expect (runner.exitCalled == 1);
} }
void runTest() void runTest()
{ {
beginTestCase("Calls");
for(int i=0; i<100; i++)
performCalls (); performCalls ();
} }
BindableServiceQueueTests () : UnitTest ("BindableServiceQueue", "beast") ThreadWithServiceQueueTests () : UnitTest ("ThreadWithServiceQueue", "beast")
{ {
} }
}; };
static BindableServiceQueueTests bindableServiceQueueTests; static CallQueueTests callQueueTests;
static ThreadWithServiceQueueTests bindableServiceQueueTests;
} }
} }

View File

@@ -2,6 +2,7 @@
/* /*
This file is part of Beast: https://github.com/vinniefalco/Beast This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com> Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Copyright Patrick Dehne <patrick@mysonicweb.de> (www.sonicweb-radio.de)
Permission to use, copy, modify, and/or distribute this software for any Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above purpose with or without fee is hereby granted, provided that the above
@@ -20,18 +21,12 @@
#ifndef BEAST_VFLIB_THREADWITHSERVICEQUEUE_H_INCLUDED #ifndef BEAST_VFLIB_THREADWITHSERVICEQUEUE_H_INCLUDED
#define BEAST_VFLIB_THREADWITHSERVICEQUEUE_H_INCLUDED #define BEAST_VFLIB_THREADWITHSERVICEQUEUE_H_INCLUDED
#include "BindableServiceQueue.h" #include "CallQueue.h"
namespace beast { namespace beast {
/** TODO: Queued calls no longer interrupt the idle method at the moment
use an explicit call to interrupt() if you want to also interrupt the
idle method when queuing calls
*/
class ThreadWithServiceQueue class ThreadWithServiceQueue
: public BindableServiceQueue : public CallQueue
, public Thread
{ {
public: public:
/** Entry points for a ThreadWithCallQueue. /** Entry points for a ThreadWithCallQueue.
@@ -44,13 +39,6 @@ namespace beast {
virtual void threadInit () { } virtual void threadInit () { }
virtual void threadExit () { } virtual void threadExit () { }
virtual bool threadIdle ()
{
bool interrupted = false;
return interrupted;
}
}; };
explicit ThreadWithServiceQueue (const String& name); explicit ThreadWithServiceQueue (const String& name);
@@ -61,31 +49,44 @@ namespace beast {
void stop (bool const wait); void stop (bool const wait);
// Should be called periodically by the idle function. /** Calls all functors in the queue. Blocks if there are no
// There are two possible results: functors available to run until more functors become
// available or the queue is stopped
// #1 Returns false. The idle function may continue or return.
// #2 Returns true. The idle function should return as soon as possible.
//
// May only be called on the service queue thead
bool interruptionPoint ();
/* Interrupts the idle function.
*/ */
void interrupt (); bool synchronize ();
/** Helper class to work around ThreadWithServiceQueue and Thread both
having a run member
*/
class Worker
: public Thread
{
public:
Worker(const String& name, ThreadWithServiceQueue *parent)
: Thread(name)
, m_parent(parent)
{
}
void run()
{
m_parent->runThread();
}
private: private:
void run (); ThreadWithServiceQueue *m_parent;
void doInterrupt (); };
void doWakeUp ();
void runThread ();
private: private:
EntryPoints* m_entryPoints; EntryPoints* m_entryPoints;
bool m_calledStart; bool m_calledStart;
bool m_calledStop; bool m_calledStop;
bool m_interrupted; Worker m_thread;
CriticalSection m_mutex;
}; };
} }
#endif #endif