Skip to content

Instantly share code, notes, and snippets.

@GavinRay97
Created April 11, 2021 22:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save GavinRay97/b8bdb882a391e63cb7e2f73b247d4a6e to your computer and use it in GitHub Desktop.
Save GavinRay97/b8bdb882a391e63cb7e2f73b247d4a6e to your computer and use it in GitHub Desktop.
JUCE amalgamated audio plugin headers
This file has been truncated, but you can view the full file.
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
/*******************************************************************************
The block below describes the properties of this module, and is read by
the Projucer to automatically generate project code that uses it.
For details about the syntax and how to create or use a module, see the
JUCE Module Format.md file.
BEGIN_JUCE_MODULE_DECLARATION
ID: juce_audio_plugin_client
vendor: juce
version: 6.0.8
name: JUCE audio plugin wrapper classes
description: Classes for building VST, VST3, AudioUnit, AAX and RTAS plugins.
website: http://www.juce.com/juce
license: GPL/Commercial
dependencies: juce_audio_processors
END_JUCE_MODULE_DECLARATION
*******************************************************************************/
/*** Start of inlined file: juce_gui_basics.h ***/
/*******************************************************************************
The block below describes the properties of this module, and is read by
the Projucer to automatically generate project code that uses it.
For details about the syntax and how to create or use a module, see the
JUCE Module Format.md file.
BEGIN_JUCE_MODULE_DECLARATION
ID: juce_gui_basics
vendor: juce
version: 6.0.8
name: JUCE GUI core classes
description: Basic user-interface components and related classes.
website: http://www.juce.com/juce
license: GPL/Commercial
dependencies: juce_graphics juce_data_structures
OSXFrameworks: Cocoa Carbon QuartzCore
iOSFrameworks: UIKit CoreServices
END_JUCE_MODULE_DECLARATION
*******************************************************************************/
#define JUCE_GUI_BASICS_H_INCLUDED
/*** Start of inlined file: juce_graphics.h ***/
/*******************************************************************************
The block below describes the properties of this module, and is read by
the Projucer to automatically generate project code that uses it.
For details about the syntax and how to create or use a module, see the
JUCE Module Format.md file.
BEGIN_JUCE_MODULE_DECLARATION
ID: juce_graphics
vendor: juce
version: 6.0.8
name: JUCE graphics classes
description: Classes for 2D vector graphics, image loading/saving, font handling, etc.
website: http://www.juce.com/juce
license: GPL/Commercial
dependencies: juce_events
OSXFrameworks: Cocoa QuartzCore
iOSFrameworks: CoreGraphics CoreImage CoreText QuartzCore
linuxPackages: freetype2
END_JUCE_MODULE_DECLARATION
*******************************************************************************/
#define JUCE_GRAPHICS_H_INCLUDED
/*** Start of inlined file: juce_core.h ***/
/*******************************************************************************
The block below describes the properties of this module, and is read by
the Projucer to automatically generate project code that uses it.
For details about the syntax and how to create or use a module, see the
JUCE Module Format.md file.
BEGIN_JUCE_MODULE_DECLARATION
ID: juce_core
vendor: juce
version: 6.0.8
name: JUCE core classes
description: The essential set of basic JUCE classes, as required by all the other JUCE modules. Includes text, container, memory, threading and i/o functionality.
website: http://www.juce.com/juce
license: ISC
dependencies:
OSXFrameworks: Cocoa Foundation IOKit
iOSFrameworks: Foundation
linuxLibs: rt dl pthread
mingwLibs: uuid wsock32 wininet version ole32 ws2_32 oleaut32 imm32 comdlg32 shlwapi rpcrt4 winmm
END_JUCE_MODULE_DECLARATION
*******************************************************************************/
#define JUCE_CORE_H_INCLUDED
#ifdef _MSC_VER
#pragma warning (push)
// Disable warnings for long class names, padding, and undefined preprocessor definitions.
#pragma warning (disable: 4251 4786 4668 4820)
#ifdef __INTEL_COMPILER
#pragma warning (disable: 1125)
#endif
#endif
/*** Start of inlined file: juce_TargetPlatform.h ***/
/* This file figures out which platform is being built, and defines some macros
that the rest of the code can use for OS-specific compilation.
Macros that will be set here are:
- One of JUCE_WINDOWS, JUCE_MAC JUCE_LINUX, JUCE_IOS, JUCE_ANDROID, etc.
- Either JUCE_32BIT or JUCE_64BIT, depending on the architecture.
- Either JUCE_LITTLE_ENDIAN or JUCE_BIG_ENDIAN.
- Either JUCE_INTEL or JUCE_ARM
- Either JUCE_GCC or JUCE_CLANG or JUCE_MSVC
*/
#ifdef JUCE_APP_CONFIG_HEADER
#include JUCE_APP_CONFIG_HEADER
#elif ! defined (JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED)
/*
Most projects will contain a global header file containing various settings that
should be applied to all the code in your project. If you use the projucer, it'll
set up a global header file for you automatically, but if you're doing things manually,
you may want to set the JUCE_APP_CONFIG_HEADER macro with the name of a file to include,
or just include one before all the module cpp files, in which you set
JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1 to silence this error.
(Or if you don't need a global header, then you can just define JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED
globally to avoid this error).
Note for people who hit this error when trying to compile a JUCE project created by
a pre-v4.2 version of the Introjucer/Projucer, it's very easy to fix: just re-save
your project with the latest version of the Projucer, and it'll magically fix this!
*/
#error "No global header file was included!"
#endif
#if defined (_WIN32) || defined (_WIN64)
#define JUCE_WINDOWS 1
#elif defined (JUCE_ANDROID)
#undef JUCE_ANDROID
#define JUCE_ANDROID 1
#elif defined (__FreeBSD__) || (__OpenBSD__)
#define JUCE_BSD 1
#elif defined (LINUX) || defined (__linux__)
#define JUCE_LINUX 1
#elif defined (__APPLE_CPP__) || defined (__APPLE_CC__)
#define CF_EXCLUDE_CSTD_HEADERS 1
#include <TargetConditionals.h> // (needed to find out what platform we're using)
#include <AvailabilityMacros.h>
/*** Start of inlined file: juce_mac_ClangBugWorkaround.h ***/
#if JUCE_PROJUCER_LIVE_BUILD && (defined (__APPLE_CPP__) || defined(__APPLE_CC__))
// This hack is a workaround for a bug (?) in Apple's 10.11 SDK headers
// which cause some configurations of Clang to throw out a spurious error..
#include <CoreFoundation/CFAvailability.h>
#undef CF_OPTIONS
#define CF_OPTIONS(_type, _name) _type _name; enum
// This is a workaround for the Xcode 9 version of NSUUID.h causing some errors
// in the live-build engine.
#define _Nullable
#define _Nonnull
// A workaround for compiling the 10.15 headers with an older compiler version
#undef API_UNAVAILABLE_BEGIN
#define API_UNAVAILABLE_BEGIN(...)
#undef API_UNAVAILABLE_END
#define API_UNAVAILABLE_END
#endif
/*** End of inlined file: juce_mac_ClangBugWorkaround.h ***/
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
#define JUCE_IPHONE 1
#define JUCE_IOS 1
#else
#define JUCE_MAC 1
#endif
#elif defined (__wasm__)
#define JUCE_WASM 1
#else
#error "Unknown platform!"
#endif
#if JUCE_WINDOWS
#ifdef _MSC_VER
#ifdef _WIN64
#define JUCE_64BIT 1
#else
#define JUCE_32BIT 1
#endif
#endif
#ifdef _DEBUG
#define JUCE_DEBUG 1
#endif
#ifdef __MINGW32__
#define JUCE_MINGW 1
#ifdef __MINGW64__
#define JUCE_64BIT 1
#else
#define JUCE_32BIT 1
#endif
#endif
/** If defined, this indicates that the processor is little-endian. */
#define JUCE_LITTLE_ENDIAN 1
#define JUCE_INTEL 1
#endif
#if JUCE_MAC || JUCE_IOS
#if defined (DEBUG) || defined (_DEBUG) || ! (defined (NDEBUG) || defined (_NDEBUG))
#define JUCE_DEBUG 1
#endif
#if ! (defined (DEBUG) || defined (_DEBUG) || defined (NDEBUG) || defined (_NDEBUG))
#warning "Neither NDEBUG or DEBUG has been defined - you should set one of these to make it clear whether this is a release build,"
#endif
#ifdef __LITTLE_ENDIAN__
#define JUCE_LITTLE_ENDIAN 1
#else
#define JUCE_BIG_ENDIAN 1
#endif
#ifdef __LP64__
#define JUCE_64BIT 1
#else
#define JUCE_32BIT 1
#endif
#if defined (__ppc__) || defined (__ppc64__)
#error "PowerPC is no longer supported by JUCE!"
#elif defined (__arm__) || defined (__arm64__)
#define JUCE_ARM 1
#else
#define JUCE_INTEL 1
#endif
#if JUCE_MAC
#if ! defined (MAC_OS_X_VERSION_10_11)
#error "The 10.11 SDK (Xcode 7.3.1+) is required to build JUCE apps. You can create apps that run on macOS 10.7+ by changing the deployment target."
#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
#error "Building for OSX 10.6 is no longer supported!"
#endif
#endif
#endif
#if JUCE_LINUX || JUCE_ANDROID || JUCE_BSD
#ifdef _DEBUG
#define JUCE_DEBUG 1
#endif
// Allow override for big-endian Linux platforms
#if defined (__LITTLE_ENDIAN__) || ! defined (JUCE_BIG_ENDIAN)
#define JUCE_LITTLE_ENDIAN 1
#undef JUCE_BIG_ENDIAN
#else
#undef JUCE_LITTLE_ENDIAN
#define JUCE_BIG_ENDIAN 1
#endif
#if defined (__LP64__) || defined (_LP64) || defined (__arm64__)
#define JUCE_64BIT 1
#else
#define JUCE_32BIT 1
#endif
#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__)
#define JUCE_ARM 1
#elif __MMX__ || __SSE__ || __amd64__
#define JUCE_INTEL 1
#endif
#endif
// Compiler type macros.
#if defined (__clang__)
#define JUCE_CLANG 1
#elif defined (__GNUC__)
#define JUCE_GCC 1
#elif defined (_MSC_VER)
#define JUCE_MSVC 1
#else
#error unknown compiler
#endif
/*** End of inlined file: juce_TargetPlatform.h ***/
/** Config: JUCE_FORCE_DEBUG
Normally, JUCE_DEBUG is set to 1 or 0 based on compiler and project settings,
but if you define this value, you can override this to force it to be true or false.
*/
#ifndef JUCE_FORCE_DEBUG
//#define JUCE_FORCE_DEBUG 0
#endif
/** Config: JUCE_LOG_ASSERTIONS
If this flag is enabled, the jassert and jassertfalse macros will always use Logger::writeToLog()
to write a message when an assertion happens.
Enabling it will also leave this turned on in release builds. When it's disabled,
however, the jassert and jassertfalse macros will not be compiled in a
release build.
@see jassert, jassertfalse, Logger
*/
#ifndef JUCE_LOG_ASSERTIONS
#if JUCE_ANDROID
#define JUCE_LOG_ASSERTIONS 1
#else
#define JUCE_LOG_ASSERTIONS 0
#endif
#endif
/** Config: JUCE_CHECK_MEMORY_LEAKS
Enables a memory-leak check for certain objects when the app terminates. See the LeakedObjectDetector
class and the JUCE_LEAK_DETECTOR macro for more details about enabling leak checking for specific classes.
*/
#if JUCE_DEBUG && ! defined (JUCE_CHECK_MEMORY_LEAKS)
#define JUCE_CHECK_MEMORY_LEAKS 1
#endif
/** Config: JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
In a Windows build, this can be used to stop the required system libs being
automatically added to the link stage.
*/
#ifndef JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
#define JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES 0
#endif
/** Config: JUCE_INCLUDE_ZLIB_CODE
This can be used to disable Juce's embedded 3rd-party zlib code.
You might need to tweak this if you're linking to an external zlib library in your app,
but for normal apps, this option should be left alone.
If you disable this, you might also want to set a value for JUCE_ZLIB_INCLUDE_PATH, to
specify the path where your zlib headers live.
*/
#ifndef JUCE_INCLUDE_ZLIB_CODE
#define JUCE_INCLUDE_ZLIB_CODE 1
#endif
#ifndef JUCE_ZLIB_INCLUDE_PATH
#define JUCE_ZLIB_INCLUDE_PATH <zlib.h>
#endif
/** Config: JUCE_USE_CURL
Enables http/https support via libcurl (Linux only). Enabling this will add an additional
run-time dynamic dependency to libcurl.
If you disable this then https/ssl support will not be available on Linux.
*/
#ifndef JUCE_USE_CURL
#define JUCE_USE_CURL 1
#endif
/** Config: JUCE_LOAD_CURL_SYMBOLS_LAZILY
If enabled, JUCE will load libcurl lazily when required (for example, when WebInputStream
is used). Enabling this flag may also help with library dependency errors as linking
libcurl at compile-time may instruct the linker to hard depend on a specific version
of libcurl. It's also useful if you want to limit the amount of JUCE dependencies and
you are not using WebInputStream or the URL classes.
*/
#ifndef JUCE_LOAD_CURL_SYMBOLS_LAZILY
#define JUCE_LOAD_CURL_SYMBOLS_LAZILY 0
#endif
/** Config: JUCE_CATCH_UNHANDLED_EXCEPTIONS
If enabled, this will add some exception-catching code to forward unhandled exceptions
to your JUCEApplicationBase::unhandledException() callback.
*/
#ifndef JUCE_CATCH_UNHANDLED_EXCEPTIONS
#define JUCE_CATCH_UNHANDLED_EXCEPTIONS 0
#endif
/** Config: JUCE_ALLOW_STATIC_NULL_VARIABLES
If disabled, this will turn off dangerous static globals like String::empty, var::null, etc
which can cause nasty order-of-initialisation problems if they are referenced during static
constructor code.
*/
#ifndef JUCE_ALLOW_STATIC_NULL_VARIABLES
#define JUCE_ALLOW_STATIC_NULL_VARIABLES 0
#endif
/** Config: JUCE_STRICT_REFCOUNTEDPOINTER
If enabled, this will make the ReferenceCountedObjectPtr class stricter about allowing
itself to be cast directly to a raw pointer. By default this is disabled, for compatibility
with old code, but if possible, you should always enable it to improve code safety!
*/
#ifndef JUCE_STRICT_REFCOUNTEDPOINTER
#define JUCE_STRICT_REFCOUNTEDPOINTER 0
#endif
/** Config: JUCE_ENABLE_ALLOCATION_HOOKS
If enabled, this will add global allocation functions with built-in assertions, which may
help when debugging allocations in unit tests.
*/
#ifndef JUCE_ENABLE_ALLOCATION_HOOKS
#define JUCE_ENABLE_ALLOCATION_HOOKS 0
#endif
#ifndef JUCE_STRING_UTF_TYPE
#define JUCE_STRING_UTF_TYPE 8
#endif
#if JUCE_CORE_INCLUDE_NATIVE_HEADERS
/*** Start of inlined file: juce_BasicNativeHeaders.h ***/
#undef T
#if JUCE_MAC || JUCE_IOS
#if JUCE_IOS
#if JUCE_MODULE_AVAILABLE_juce_opengl && defined (__IPHONE_12_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_12_0
#define GLES_SILENCE_DEPRECATION 1
#endif
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
#import <MobileCoreServices/MobileCoreServices.h>
#include <sys/fcntl.h>
#else
#if JUCE_MODULE_AVAILABLE_juce_opengl && defined (MAC_OS_X_VERSION_10_14) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14
#define GL_SILENCE_DEPRECATION 1
#endif
#import <Cocoa/Cocoa.h>
#if (! defined MAC_OS_X_VERSION_10_12) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12
#define NSEventModifierFlagCommand NSCommandKeyMask
#define NSEventModifierFlagControl NSControlKeyMask
#define NSEventModifierFlagHelp NSHelpKeyMask
#define NSEventModifierFlagNumericPad NSNumericPadKeyMask
#define NSEventModifierFlagOption NSAlternateKeyMask
#define NSEventModifierFlagShift NSShiftKeyMask
#define NSCompositingOperationSourceOver NSCompositeSourceOver
#define NSEventMaskApplicationDefined NSApplicationDefinedMask
#define NSEventTypeApplicationDefined NSApplicationDefined
#define NSEventTypeCursorUpdate NSCursorUpdate
#define NSEventTypeMouseMoved NSMouseMoved
#define NSEventTypeLeftMouseDown NSLeftMouseDown
#define NSEventTypeRightMouseDown NSRightMouseDown
#define NSEventTypeOtherMouseDown NSOtherMouseDown
#define NSEventTypeLeftMouseUp NSLeftMouseUp
#define NSEventTypeRightMouseUp NSRightMouseUp
#define NSEventTypeOtherMouseUp NSOtherMouseUp
#define NSEventTypeLeftMouseDragged NSLeftMouseDragged
#define NSEventTypeRightMouseDragged NSRightMouseDragged
#define NSEventTypeOtherMouseDragged NSOtherMouseDragged
#define NSEventTypeScrollWheel NSScrollWheel
#define NSEventTypeKeyDown NSKeyDown
#define NSEventTypeKeyUp NSKeyUp
#define NSEventTypeFlagsChanged NSFlagsChanged
#define NSEventMaskAny NSAnyEventMask
#define NSWindowStyleMaskBorderless NSBorderlessWindowMask
#define NSWindowStyleMaskClosable NSClosableWindowMask
#define NSWindowStyleMaskFullScreen NSFullScreenWindowMask
#define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask
#define NSWindowStyleMaskResizable NSResizableWindowMask
#define NSWindowStyleMaskTitled NSTitledWindowMask
#define NSAlertStyleCritical NSCriticalAlertStyle
#define NSControlSizeRegular NSRegularControlSize
#define NSEventTypeMouseEntered NSMouseEntered
#define NSEventTypeMouseExited NSMouseExited
#define NSAlertStyleInformational NSInformationalAlertStyle
#define NSEventTypeTabletPoint NSTabletPoint
#define NSEventTypeTabletProximity NSTabletProximity
#define NSEventTypeFlagsChanged NSFlagsChanged
#define NSEventTypeAppKitDefined NSAppKitDefined
#define NSEventTypeSystemDefined NSSystemDefined
#define NSEventTypeApplicationDefined NSApplicationDefined
#define NSEventTypePeriodic NSPeriodic
#define NSEventTypeSmartMagnify NSEventTypeSmartMagnify
#endif
#import <CoreAudio/HostTime.h>
#include <sys/dir.h>
#endif
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/utsname.h>
#include <sys/mman.h>
#include <fnmatch.h>
#include <utime.h>
#include <dlfcn.h>
#include <ifaddrs.h>
#include <net/if_dl.h>
#include <mach/mach_time.h>
#include <mach-o/dyld.h>
#include <objc/runtime.h>
#include <objc/objc.h>
#include <objc/message.h>
#include <poll.h>
#elif JUCE_WINDOWS
#if JUCE_MSVC
#ifndef _CPPRTTI
#error "You're compiling without RTTI enabled! This is needed for a lot of JUCE classes, please update your compiler settings!"
#endif
#ifndef _CPPUNWIND
#error "You're compiling without exceptions enabled! This is needed for a lot of JUCE classes, please update your compiler settings!"
#endif
#pragma warning (push, 0) // disable all warnings whilst including system headers
#endif
#define NOMINMAX
#define _WINSOCK_DEPRECATED_NO_WARNINGS 1
#define STRICT 1
#define WIN32_LEAN_AND_MEAN 1
#if JUCE_MINGW
#define _WIN32_WINNT 0x0600
#else
#define _WIN32_WINNT 0x0602
#endif
#define _UNICODE 1
#define UNICODE 1
#ifndef _WIN32_IE
#define _WIN32_IE 0x0501
#endif
#include <windows.h>
#include <shellapi.h>
#include <tchar.h>
#include <stddef.h>
#include <ctime>
#include <wininet.h>
#include <nb30.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <mapi.h>
#include <float.h>
#include <process.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <mmsystem.h>
#include <winioctl.h>
#if JUCE_MINGW
#include <basetyps.h>
#include <sys/time.h>
#ifndef alloca
#define alloca __builtin_alloca
#endif
#else
#include <crtdbg.h>
#include <comutil.h>
#endif
#ifndef S_FALSE
#define S_FALSE (1) // (apparently some obscure win32 dev environments don't define this)
#endif
#undef PACKED
#if JUCE_MSVC
#pragma warning (pop)
#pragma warning (4: 4511 4512 4100)
#endif
#if ! JUCE_MINGW && ! JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
#pragma comment (lib, "kernel32.lib")
#pragma comment (lib, "user32.lib")
#pragma comment (lib, "wininet.lib")
#pragma comment (lib, "advapi32.lib")
#pragma comment (lib, "ws2_32.lib")
#pragma comment (lib, "version.lib")
#pragma comment (lib, "shlwapi.lib")
#pragma comment (lib, "winmm.lib")
#ifdef _NATIVE_WCHAR_T_DEFINED
#ifdef _DEBUG
#pragma comment (lib, "comsuppwd.lib")
#else
#pragma comment (lib, "comsuppw.lib")
#endif
#else
#ifdef _DEBUG
#pragma comment (lib, "comsuppd.lib")
#else
#pragma comment (lib, "comsupp.lib")
#endif
#endif
#endif
/* Used with DynamicLibrary to simplify importing functions from a win32 DLL.
dll: the DynamicLibrary object
functionName: function to import
localFunctionName: name you want to use to actually call it (must be different)
returnType: the return type
params: list of params (bracketed)
*/
#define JUCE_LOAD_WINAPI_FUNCTION(dll, functionName, localFunctionName, returnType, params) \
typedef returnType (WINAPI *type##localFunctionName) params; \
type##localFunctionName localFunctionName = (type##localFunctionName) dll.getFunction (#functionName);
#elif JUCE_LINUX
#include <arpa/inet.h>
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
#include <net/if.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pthread.h>
#include <pwd.h>
#include <sched.h>
#include <signal.h>
#include <stddef.h>
#include <sys/dir.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <sys/ptrace.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/sysinfo.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/vfs.h>
#include <sys/wait.h>
#include <utime.h>
#include <poll.h>
#elif JUCE_BSD
#include <arpa/inet.h>
#include <dirent.h>
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
#include <ifaddrs.h>
#include <langinfo.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pthread.h>
#include <pwd.h>
#include <sched.h>
#include <signal.h>
#include <stddef.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/ptrace.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <utime.h>
#include <poll.h>
#elif JUCE_ANDROID
#include <jni.h>
#include <pthread.h>
#include <sched.h>
#include <sys/time.h>
#include <utime.h>
#include <errno.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <sys/ptrace.h>
#include <sys/sysinfo.h>
#include <sys/mman.h>
#include <pwd.h>
#include <dirent.h>
#include <fnmatch.h>
#include <sys/wait.h>
#include <android/api-level.h>
#include <poll.h>
// If you are getting include errors here, then you to re-build the Projucer
// and re-save your .jucer file.
#include <cpu-features.h>
#endif
// Need to clear various moronic redefinitions made by system headers..
#undef max
#undef min
#undef direct
#undef check
/*** End of inlined file: juce_BasicNativeHeaders.h ***/
#endif
#if JUCE_WINDOWS
#undef small
#endif
/*** Start of inlined file: juce_StandardHeader.h ***/
/** Current JUCE version number.
See also SystemStats::getJUCEVersion() for a string version.
*/
#define JUCE_MAJOR_VERSION 6
#define JUCE_MINOR_VERSION 0
#define JUCE_BUILDNUMBER 8
/** Current JUCE version number.
Bits 16 to 32 = major version.
Bits 8 to 16 = minor version.
Bits 0 to 8 = point release.
See also SystemStats::getJUCEVersion() for a string version.
*/
#define JUCE_VERSION ((JUCE_MAJOR_VERSION << 16) + (JUCE_MINOR_VERSION << 8) + JUCE_BUILDNUMBER)
#include <algorithm>
#include <array>
#include <atomic>
#include <cmath>
#include <condition_variable>
#include <cstddef>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <memory>
#include <mutex>
#include <numeric>
#include <queue>
#include <sstream>
#include <unordered_set>
#include <vector>
/*** Start of inlined file: juce_CompilerSupport.h ***/
/*
This file provides flags for compiler features that aren't supported on all platforms.
*/
// GCC
#if JUCE_GCC
#if (__GNUC__ * 100 + __GNUC_MINOR__) < 407
#error "JUCE requires GCC 4.7 or later"
#endif
#if ! (__cplusplus >= 201103L || defined (__GXX_EXPERIMENTAL_CXX0X__))
#error "JUCE requires that GCC has C++11 compatibility enabled"
#endif
#ifndef JUCE_EXCEPTIONS_DISABLED
#if ! __EXCEPTIONS
#define JUCE_EXCEPTIONS_DISABLED 1
#endif
#endif
#define JUCE_CXX14_IS_AVAILABLE ((__cplusplus >= 201402L) || ((__GNUC__ * 100 + __GNUC_MINOR__) >= 409 && (__cplusplus >= 201300L)))
#define JUCE_CXX17_IS_AVAILABLE (__cplusplus >= 201703L)
#endif
// Clang
#if JUCE_CLANG
#if (__clang_major__ < 3) || (__clang_major__ == 3 && __clang_minor__ < 3)
#error "JUCE requires Clang 3.3 or later"
#endif
#ifndef JUCE_COMPILER_SUPPORTS_ARC
#define JUCE_COMPILER_SUPPORTS_ARC 1
#endif
#ifndef JUCE_EXCEPTIONS_DISABLED
#if ! __has_feature (cxx_exceptions)
#define JUCE_EXCEPTIONS_DISABLED 1
#endif
#endif
#define JUCE_CXX14_IS_AVAILABLE (__cplusplus >= 201402L)
#define JUCE_CXX17_IS_AVAILABLE (__cplusplus >= 201703L)
#endif
// MSVC
#if JUCE_MSVC
#if _MSC_VER < 1900 // VS2015
#error "JUCE requires Visual Studio 2015 or later"
#endif
#ifndef JUCE_EXCEPTIONS_DISABLED
#if ! _CPPUNWIND
#define JUCE_EXCEPTIONS_DISABLED 1
#endif
#endif
#endif
// C++ library
#if (defined (__GLIBCXX__) && __GLIBCXX__ < 20130322) || (defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION < 3700))
#error "JUCE requires a C++ library containing std::atomic"
#endif
#if (! JUCE_MSVC) && (! JUCE_CXX14_IS_AVAILABLE)
namespace std
{
template <typename T, typename... Args>
unique_ptr<T> make_unique(Args&&... args)
{
return unique_ptr<T>(new T(std::forward<Args>(args)...));
}
}
#endif
#if ! DOXYGEN
// These are old flags that are now supported on all compatible build targets
#define JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL 1
#define JUCE_COMPILER_SUPPORTS_VARIADIC_TEMPLATES 1
#define JUCE_COMPILER_SUPPORTS_INITIALIZER_LISTS 1
#define JUCE_COMPILER_SUPPORTS_NOEXCEPT 1
#define JUCE_DELETED_FUNCTION = delete
#define JUCE_CONSTEXPR constexpr
#endif
/*** End of inlined file: juce_CompilerSupport.h ***/
/*** Start of inlined file: juce_CompilerWarnings.h ***/
/** Return the Nth argument. By passing a variadic pack followed by N other
parameters, we can select one of those N parameter based on the length of
the parameter pack.
*/
#define JUCE_NTH_ARG_(_00, _01, _02, _03, _04, _05, _06, _07, _08, _09, \
_10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \
_20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \
_30, _31, _32, _33, _34, _35, _36, _37, _38, _39, N, ...)\
N
#define JUCE_EACH_00_(FN)
#define JUCE_EACH_01_(FN, X) FN(X)
#define JUCE_EACH_02_(FN, X, ...) FN(X) JUCE_EACH_01_(FN, __VA_ARGS__)
#define JUCE_EACH_03_(FN, X, ...) FN(X) JUCE_EACH_02_(FN, __VA_ARGS__)
#define JUCE_EACH_04_(FN, X, ...) FN(X) JUCE_EACH_03_(FN, __VA_ARGS__)
#define JUCE_EACH_05_(FN, X, ...) FN(X) JUCE_EACH_04_(FN, __VA_ARGS__)
#define JUCE_EACH_06_(FN, X, ...) FN(X) JUCE_EACH_05_(FN, __VA_ARGS__)
#define JUCE_EACH_07_(FN, X, ...) FN(X) JUCE_EACH_06_(FN, __VA_ARGS__)
#define JUCE_EACH_08_(FN, X, ...) FN(X) JUCE_EACH_07_(FN, __VA_ARGS__)
#define JUCE_EACH_09_(FN, X, ...) FN(X) JUCE_EACH_08_(FN, __VA_ARGS__)
#define JUCE_EACH_10_(FN, X, ...) FN(X) JUCE_EACH_09_(FN, __VA_ARGS__)
#define JUCE_EACH_11_(FN, X, ...) FN(X) JUCE_EACH_10_(FN, __VA_ARGS__)
#define JUCE_EACH_12_(FN, X, ...) FN(X) JUCE_EACH_11_(FN, __VA_ARGS__)
#define JUCE_EACH_13_(FN, X, ...) FN(X) JUCE_EACH_12_(FN, __VA_ARGS__)
#define JUCE_EACH_14_(FN, X, ...) FN(X) JUCE_EACH_13_(FN, __VA_ARGS__)
#define JUCE_EACH_15_(FN, X, ...) FN(X) JUCE_EACH_14_(FN, __VA_ARGS__)
#define JUCE_EACH_16_(FN, X, ...) FN(X) JUCE_EACH_15_(FN, __VA_ARGS__)
#define JUCE_EACH_17_(FN, X, ...) FN(X) JUCE_EACH_16_(FN, __VA_ARGS__)
#define JUCE_EACH_18_(FN, X, ...) FN(X) JUCE_EACH_17_(FN, __VA_ARGS__)
#define JUCE_EACH_19_(FN, X, ...) FN(X) JUCE_EACH_18_(FN, __VA_ARGS__)
#define JUCE_EACH_20_(FN, X, ...) FN(X) JUCE_EACH_19_(FN, __VA_ARGS__)
#define JUCE_EACH_21_(FN, X, ...) FN(X) JUCE_EACH_20_(FN, __VA_ARGS__)
#define JUCE_EACH_22_(FN, X, ...) FN(X) JUCE_EACH_21_(FN, __VA_ARGS__)
#define JUCE_EACH_23_(FN, X, ...) FN(X) JUCE_EACH_22_(FN, __VA_ARGS__)
#define JUCE_EACH_24_(FN, X, ...) FN(X) JUCE_EACH_23_(FN, __VA_ARGS__)
#define JUCE_EACH_25_(FN, X, ...) FN(X) JUCE_EACH_24_(FN, __VA_ARGS__)
#define JUCE_EACH_26_(FN, X, ...) FN(X) JUCE_EACH_25_(FN, __VA_ARGS__)
#define JUCE_EACH_27_(FN, X, ...) FN(X) JUCE_EACH_26_(FN, __VA_ARGS__)
#define JUCE_EACH_28_(FN, X, ...) FN(X) JUCE_EACH_27_(FN, __VA_ARGS__)
#define JUCE_EACH_29_(FN, X, ...) FN(X) JUCE_EACH_28_(FN, __VA_ARGS__)
#define JUCE_EACH_30_(FN, X, ...) FN(X) JUCE_EACH_29_(FN, __VA_ARGS__)
#define JUCE_EACH_31_(FN, X, ...) FN(X) JUCE_EACH_30_(FN, __VA_ARGS__)
#define JUCE_EACH_32_(FN, X, ...) FN(X) JUCE_EACH_31_(FN, __VA_ARGS__)
#define JUCE_EACH_33_(FN, X, ...) FN(X) JUCE_EACH_32_(FN, __VA_ARGS__)
#define JUCE_EACH_34_(FN, X, ...) FN(X) JUCE_EACH_33_(FN, __VA_ARGS__)
#define JUCE_EACH_35_(FN, X, ...) FN(X) JUCE_EACH_34_(FN, __VA_ARGS__)
#define JUCE_EACH_36_(FN, X, ...) FN(X) JUCE_EACH_35_(FN, __VA_ARGS__)
#define JUCE_EACH_37_(FN, X, ...) FN(X) JUCE_EACH_36_(FN, __VA_ARGS__)
#define JUCE_EACH_38_(FN, X, ...) FN(X) JUCE_EACH_37_(FN, __VA_ARGS__)
#define JUCE_EACH_39_(FN, X, ...) FN(X) JUCE_EACH_38_(FN, __VA_ARGS__)
/** Apply the macro FN to each of the other arguments. */
#define JUCE_EACH(FN, ...) \
JUCE_NTH_ARG_(, __VA_ARGS__, \
JUCE_EACH_39_, \
JUCE_EACH_38_, \
JUCE_EACH_37_, \
JUCE_EACH_36_, \
JUCE_EACH_35_, \
JUCE_EACH_34_, \
JUCE_EACH_33_, \
JUCE_EACH_32_, \
JUCE_EACH_31_, \
JUCE_EACH_30_, \
JUCE_EACH_29_, \
JUCE_EACH_28_, \
JUCE_EACH_27_, \
JUCE_EACH_26_, \
JUCE_EACH_25_, \
JUCE_EACH_24_, \
JUCE_EACH_23_, \
JUCE_EACH_22_, \
JUCE_EACH_21_, \
JUCE_EACH_20_, \
JUCE_EACH_19_, \
JUCE_EACH_18_, \
JUCE_EACH_17_, \
JUCE_EACH_16_, \
JUCE_EACH_15_, \
JUCE_EACH_14_, \
JUCE_EACH_13_, \
JUCE_EACH_12_, \
JUCE_EACH_11_, \
JUCE_EACH_10_, \
JUCE_EACH_09_, \
JUCE_EACH_08_, \
JUCE_EACH_07_, \
JUCE_EACH_06_, \
JUCE_EACH_05_, \
JUCE_EACH_04_, \
JUCE_EACH_03_, \
JUCE_EACH_02_, \
JUCE_EACH_01_, \
JUCE_EACH_00_) \
(FN, __VA_ARGS__)
/** Concatenate two tokens to form a new token. */
#define JUCE_CONCAT_(a, b) a##b
#define JUCE_CONCAT(a, b) JUCE_CONCAT_(a, b)
/** Quote the argument, turning it into a string. */
#define JUCE_TO_STRING(x) #x
#if JUCE_CLANG || JUCE_GCC
#define JUCE_IGNORE_GCC_IMPL_(compiler, warning)
#define JUCE_IGNORE_GCC_IMPL_0(compiler, warning)
#define JUCE_IGNORE_GCC_IMPL_1(compiler, warning) \
_Pragma(JUCE_TO_STRING(compiler diagnostic ignored warning))
/** If 'warning' is recognised by this compiler, ignore it. */
#if defined (__has_warning)
#define JUCE_IGNORE_GCC_LIKE(compiler, warning) \
JUCE_CONCAT(JUCE_IGNORE_GCC_IMPL_, __has_warning(warning))(compiler, warning)
#else
#define JUCE_IGNORE_GCC_LIKE(compiler, warning) \
JUCE_IGNORE_GCC_IMPL_1(compiler, warning)
#endif
/** Ignore GCC/clang-specific warnings. */
#define JUCE_IGNORE_GCC(warning) JUCE_IGNORE_GCC_LIKE(GCC, warning)
#define JUCE_IGNORE_clang(warning) JUCE_IGNORE_GCC_LIKE(clang, warning)
#define JUCE_IGNORE_WARNINGS_GCC_LIKE(compiler, ...) \
_Pragma(JUCE_TO_STRING(compiler diagnostic push)) \
JUCE_EACH(JUCE_CONCAT(JUCE_IGNORE_, compiler), __VA_ARGS__)
/** Push a new warning scope, and then ignore each warning for either clang
or gcc. If the compiler doesn't support __has_warning, we add -Wpragmas
as the first disabled warning because otherwise we might get complaints
about unknown warning options.
*/
#if defined (__has_warning)
#define JUCE_PUSH_WARNINGS_GCC_LIKE(compiler, ...) \
JUCE_IGNORE_WARNINGS_GCC_LIKE(compiler, __VA_ARGS__)
#else
#define JUCE_PUSH_WARNINGS_GCC_LIKE(compiler, ...) \
JUCE_IGNORE_WARNINGS_GCC_LIKE(compiler, "-Wpragmas", __VA_ARGS__)
#endif
/** Pop the current warning scope. */
#define JUCE_POP_WARNINGS_GCC_LIKE(compiler) \
_Pragma(JUCE_TO_STRING(compiler diagnostic pop))
/** Push/pop warnings on compilers with gcc-like warning flags.
These macros expand to nothing on other compilers (like MSVC).
*/
#if JUCE_CLANG
#define JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE(...) JUCE_PUSH_WARNINGS_GCC_LIKE(clang, __VA_ARGS__)
#define JUCE_END_IGNORE_WARNINGS_GCC_LIKE JUCE_POP_WARNINGS_GCC_LIKE(clang)
#else
#define JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE(...) JUCE_PUSH_WARNINGS_GCC_LIKE(GCC, __VA_ARGS__)
#define JUCE_END_IGNORE_WARNINGS_GCC_LIKE JUCE_POP_WARNINGS_GCC_LIKE(GCC)
#endif
#else
#define JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE(...)
#define JUCE_END_IGNORE_WARNINGS_GCC_LIKE
#endif
/** Push/pop warnings on MSVC. These macros expand to nothing on other
compilers (like clang and gcc).
*/
#if JUCE_MSVC
#define JUCE_IGNORE_MSVC(warnings) __pragma(warning(disable:warnings))
#define JUCE_BEGIN_IGNORE_WARNINGS_LEVEL_MSVC(level, warnings) \
__pragma(warning(push, level)) JUCE_IGNORE_MSVC(warnings)
#define JUCE_BEGIN_IGNORE_WARNINGS_MSVC(warnings) \
__pragma(warning(push)) JUCE_IGNORE_MSVC(warnings)
#define JUCE_END_IGNORE_WARNINGS_MSVC __pragma(warning(pop))
#else
#define JUCE_IGNORE_MSVC(warnings)
#define JUCE_BEGIN_IGNORE_WARNINGS_LEVEL_MSVC(level, warnings)
#define JUCE_BEGIN_IGNORE_WARNINGS_MSVC(warnings)
#define JUCE_END_IGNORE_WARNINGS_MSVC
#endif
/*** End of inlined file: juce_CompilerWarnings.h ***/
/*** Start of inlined file: juce_PlatformDefs.h ***/
namespace juce
{
/* This file defines miscellaneous macros for debugging, assertions, etc.
*/
#ifdef JUCE_FORCE_DEBUG
#undef JUCE_DEBUG
#if JUCE_FORCE_DEBUG
#define JUCE_DEBUG 1
#endif
#endif
/** This macro defines the C calling convention used as the standard for JUCE calls. */
#if JUCE_WINDOWS
#define JUCE_CALLTYPE __stdcall
#define JUCE_CDECL __cdecl
#else
#define JUCE_CALLTYPE
#define JUCE_CDECL
#endif
// Debugging and assertion macros
#ifndef JUCE_LOG_CURRENT_ASSERTION
#if JUCE_LOG_ASSERTIONS || JUCE_DEBUG
#define JUCE_LOG_CURRENT_ASSERTION juce::logAssertion (__FILE__, __LINE__);
#else
#define JUCE_LOG_CURRENT_ASSERTION
#endif
#endif
#if JUCE_IOS || (JUCE_MAC && JUCE_ARM) || JUCE_LINUX || JUCE_BSD
/** This will try to break into the debugger if the app is currently being debugged.
If called by an app that's not being debugged, the behaviour isn't defined - it may
crash or not, depending on the platform.
@see jassert()
*/
#define JUCE_BREAK_IN_DEBUGGER { ::kill (0, SIGTRAP); }
#elif JUCE_MSVC
#ifndef __INTEL_COMPILER
#pragma intrinsic (__debugbreak)
#endif
#define JUCE_BREAK_IN_DEBUGGER { __debugbreak(); }
#elif JUCE_INTEL && (JUCE_GCC || JUCE_MAC)
#if JUCE_NO_INLINE_ASM
#define JUCE_BREAK_IN_DEBUGGER { }
#else
#define JUCE_BREAK_IN_DEBUGGER { asm ("int $3"); }
#endif
#elif JUCE_ANDROID
#define JUCE_BREAK_IN_DEBUGGER { __builtin_trap(); }
#else
#define JUCE_BREAK_IN_DEBUGGER { __asm int 3 }
#endif
#if JUCE_CLANG && defined (__has_feature) && ! defined (JUCE_ANALYZER_NORETURN)
#if __has_feature (attribute_analyzer_noreturn)
inline void __attribute__((analyzer_noreturn)) juce_assert_noreturn() {}
#define JUCE_ANALYZER_NORETURN juce::juce_assert_noreturn();
#endif
#endif
#ifndef JUCE_ANALYZER_NORETURN
#define JUCE_ANALYZER_NORETURN
#endif
/** Used to silence Wimplicit-fallthrough on Clang and GCC where available
as there are a few places in the codebase where we need to do this
deliberately and want to ignore the warning.
*/
#if JUCE_CLANG
#if __has_cpp_attribute(clang::fallthrough)
#define JUCE_FALLTHROUGH [[clang::fallthrough]];
#else
#define JUCE_FALLTHROUGH
#endif
#elif JUCE_GCC
#if __GNUC__ >= 7
#define JUCE_FALLTHROUGH [[gnu::fallthrough]];
#else
#define JUCE_FALLTHROUGH
#endif
#else
#define JUCE_FALLTHROUGH
#endif
#if JUCE_MSVC && ! DOXYGEN
#define JUCE_BLOCK_WITH_FORCED_SEMICOLON(x) \
__pragma(warning(push)) \
__pragma(warning(disable:4127)) \
do { x } while (false) \
__pragma(warning(pop))
#else
/** This is the good old C++ trick for creating a macro that forces the user to put
a semicolon after it when they use it.
*/
#define JUCE_BLOCK_WITH_FORCED_SEMICOLON(x) do { x } while (false)
#endif
#if (JUCE_DEBUG && ! JUCE_DISABLE_ASSERTIONS) || DOXYGEN
/** Writes a string to the standard error stream.
Note that as well as a single string, you can use this to write multiple items
as a stream, e.g.
@code
DBG ("foo = " << foo << "bar = " << bar);
@endcode
The macro is only enabled in a debug build, so be careful not to use it with expressions
that have important side-effects!
@see Logger::outputDebugString
*/
#define DBG(textToWrite) JUCE_BLOCK_WITH_FORCED_SEMICOLON (juce::String tempDbgBuf; tempDbgBuf << textToWrite; juce::Logger::outputDebugString (tempDbgBuf);)
/** This will always cause an assertion failure.
It is only compiled in a debug build, (unless JUCE_LOG_ASSERTIONS is enabled for your build).
@see jassert
*/
#define jassertfalse JUCE_BLOCK_WITH_FORCED_SEMICOLON (JUCE_LOG_CURRENT_ASSERTION; if (juce::juce_isRunningUnderDebugger()) JUCE_BREAK_IN_DEBUGGER; JUCE_ANALYZER_NORETURN)
/** Platform-independent assertion macro.
This macro gets turned into a no-op when you're building with debugging turned off, so be
careful that the expression you pass to it doesn't perform any actions that are vital for the
correct behaviour of your program!
@see jassertfalse
*/
#define jassert(expression) JUCE_BLOCK_WITH_FORCED_SEMICOLON (if (! (expression)) jassertfalse;)
#else
// If debugging is disabled, these dummy debug and assertion macros are used..
#define DBG(textToWrite)
#define jassertfalse JUCE_BLOCK_WITH_FORCED_SEMICOLON (JUCE_LOG_CURRENT_ASSERTION)
#if JUCE_LOG_ASSERTIONS
#define jassert(expression) JUCE_BLOCK_WITH_FORCED_SEMICOLON (if (! (expression)) jassertfalse;)
#else
#define jassert(expression) JUCE_BLOCK_WITH_FORCED_SEMICOLON ( ; )
#endif
#endif
#if ! DOXYGEN
#define JUCE_JOIN_MACRO_HELPER(a, b) a ## b
#define JUCE_STRINGIFY_MACRO_HELPER(a) #a
#endif
/** A good old-fashioned C macro concatenation helper.
This combines two items (which may themselves be macros) into a single string,
avoiding the pitfalls of the ## macro operator.
*/
#define JUCE_JOIN_MACRO(item1, item2) JUCE_JOIN_MACRO_HELPER (item1, item2)
/** A handy C macro for stringifying any symbol, rather than just a macro parameter. */
#define JUCE_STRINGIFY(item) JUCE_STRINGIFY_MACRO_HELPER (item)
/** This is a shorthand macro for deleting a class's copy constructor and
copy assignment operator.
For example, instead of
@code
class MyClass
{
etc..
private:
MyClass (const MyClass&);
MyClass& operator= (const MyClass&);
};@endcode
..you can just write:
@code
class MyClass
{
etc..
private:
JUCE_DECLARE_NON_COPYABLE (MyClass)
};@endcode
*/
#define JUCE_DECLARE_NON_COPYABLE(className) \
className (const className&) = delete;\
className& operator= (const className&) = delete;
/** This is a shorthand macro for deleting a class's move constructor and
move assignment operator.
*/
#define JUCE_DECLARE_NON_MOVEABLE(className) \
className (className&&) = delete;\
className& operator= (className&&) = delete;
/** This is a shorthand way of writing both a JUCE_DECLARE_NON_COPYABLE and
JUCE_LEAK_DETECTOR macro for a class.
*/
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className) \
JUCE_DECLARE_NON_COPYABLE(className) \
JUCE_LEAK_DETECTOR(className)
/** This macro can be added to class definitions to disable the use of new/delete to
allocate the object on the heap, forcing it to only be used as a stack or member variable.
*/
#define JUCE_PREVENT_HEAP_ALLOCATION \
private: \
static void* operator new (size_t) = delete; \
static void operator delete (void*) = delete;
#if JUCE_MSVC && ! defined (DOXYGEN)
#define JUCE_WARNING_HELPER(file, line, mess) message(file "(" JUCE_STRINGIFY (line) ") : Warning: " #mess)
#define JUCE_COMPILER_WARNING(message) __pragma(JUCE_WARNING_HELPER (__FILE__, __LINE__, message))
#else
#ifndef DOXYGEN
#define JUCE_WARNING_HELPER(mess) message(#mess)
#endif
/** This macro allows you to emit a custom compiler warning message.
Very handy for marking bits of code as "to-do" items, or for shaming
code written by your co-workers in a way that's hard to ignore.
GCC and Clang provide the \#warning directive, but MSVC doesn't, so this macro
is a cross-compiler way to get the same functionality as \#warning.
*/
#define JUCE_COMPILER_WARNING(message) _Pragma(JUCE_STRINGIFY (JUCE_WARNING_HELPER (message)))
#endif
#if JUCE_DEBUG || DOXYGEN
/** A platform-independent way of forcing an inline function.
Use the syntax: @code
forcedinline void myfunction (int x)
@endcode
*/
#define forcedinline inline
#else
#if JUCE_MSVC
#define forcedinline __forceinline
#else
#define forcedinline inline __attribute__((always_inline))
#endif
#endif
#if JUCE_MSVC || DOXYGEN
/** This can be placed before a stack or member variable declaration to tell the compiler
to align it to the specified number of bytes. */
#define JUCE_ALIGN(bytes) __declspec (align (bytes))
#else
#define JUCE_ALIGN(bytes) __attribute__ ((aligned (bytes)))
#endif
// Cross-compiler deprecation macros..
#ifdef DOXYGEN
/** This macro can be used to wrap a function which has been deprecated. */
#define JUCE_DEPRECATED(functionDef)
#define JUCE_DEPRECATED_WITH_BODY(functionDef, body)
#elif JUCE_MSVC && ! JUCE_NO_DEPRECATION_WARNINGS
#define JUCE_DEPRECATED_ATTRIBUTE __declspec(deprecated)
#define JUCE_DEPRECATED(functionDef) JUCE_DEPRECATED_ATTRIBUTE functionDef
#define JUCE_DEPRECATED_WITH_BODY(functionDef, body) JUCE_DEPRECATED_ATTRIBUTE functionDef body
#elif (JUCE_GCC || JUCE_CLANG) && ! JUCE_NO_DEPRECATION_WARNINGS
#define JUCE_DEPRECATED_ATTRIBUTE __attribute__ ((deprecated))
#define JUCE_DEPRECATED(functionDef) functionDef JUCE_DEPRECATED_ATTRIBUTE
#define JUCE_DEPRECATED_WITH_BODY(functionDef, body) functionDef JUCE_DEPRECATED_ATTRIBUTE body
#else
#define JUCE_DEPRECATED_ATTRIBUTE
#define JUCE_DEPRECATED(functionDef) functionDef
#define JUCE_DEPRECATED_WITH_BODY(functionDef, body) functionDef body
#endif
#if JUCE_ALLOW_STATIC_NULL_VARIABLES
#if ! (defined (DOXYGEN) || defined (JUCE_GCC) || (JUCE_MSVC && _MSC_VER <= 1900))
#define JUCE_DEPRECATED_STATIC(valueDef) JUCE_DEPRECATED_ATTRIBUTE valueDef
#if JUCE_MSVC
#define JUCE_DECLARE_DEPRECATED_STATIC(valueDef) \
__pragma(warning(push)) \
__pragma(warning(disable:4996)) \
valueDef \
__pragma(warning(pop))
#else
#define JUCE_DECLARE_DEPRECATED_STATIC(valueDef) valueDef
#endif
#else
#define JUCE_DEPRECATED_STATIC(valueDef) valueDef
#define JUCE_DECLARE_DEPRECATED_STATIC(valueDef) valueDef
#endif
#else
#define JUCE_DEPRECATED_STATIC(valueDef)
#define JUCE_DECLARE_DEPRECATED_STATIC(valueDef)
#endif
#if JUCE_ANDROID && ! DOXYGEN
#define JUCE_MODAL_LOOPS_PERMITTED 0
#elif ! defined (JUCE_MODAL_LOOPS_PERMITTED)
/** Some operating environments don't provide a modal loop mechanism, so this flag can be
used to disable any functions that try to run a modal loop. */
#define JUCE_MODAL_LOOPS_PERMITTED 1
#endif
#if JUCE_GCC || JUCE_CLANG
#define JUCE_PACKED __attribute__((packed))
#elif ! DOXYGEN
#define JUCE_PACKED
#endif
#if JUCE_GCC || DOXYGEN
/** This can be appended to a function declaration to tell gcc to disable associative
math optimisations which break some floating point algorithms. */
#define JUCE_NO_ASSOCIATIVE_MATH_OPTIMISATIONS __attribute__((__optimize__("no-associative-math")))
#else
#define JUCE_NO_ASSOCIATIVE_MATH_OPTIMISATIONS
#endif
} // namespace juce
/*** End of inlined file: juce_PlatformDefs.h ***/
// Now we'll include some common OS headers..
JUCE_BEGIN_IGNORE_WARNINGS_MSVC(4514 4245 4100)
#if JUCE_MSVC
#include <intrin.h>
#endif
#if JUCE_MAC || JUCE_IOS
#include <libkern/OSAtomic.h>
#include <xlocale.h>
#include <signal.h>
#endif
#if JUCE_LINUX || JUCE_BSD
#include <cstring>
#include <signal.h>
#if __INTEL_COMPILER
#if __ia64__
#include <ia64intrin.h>
#else
#include <ia32intrin.h>
#endif
#endif
#endif
#if JUCE_MSVC && JUCE_DEBUG
#include <crtdbg.h>
#endif
JUCE_END_IGNORE_WARNINGS_MSVC
#if JUCE_MINGW
#include <cstring>
#include <sys/types.h>
#endif
#if JUCE_ANDROID
#include <cstring>
#include <byteswap.h>
#endif
// undef symbols that are sometimes set by misguided 3rd-party headers..
#undef TYPE_BOOL
#undef max
#undef min
#undef major
#undef minor
#undef KeyPress
// DLL building settings on Windows
#if JUCE_MSVC
#ifdef JUCE_DLL_BUILD
#define JUCE_API __declspec (dllexport)
#pragma warning (disable: 4251)
#elif defined (JUCE_DLL)
#define JUCE_API __declspec (dllimport)
#pragma warning (disable: 4251)
#endif
#ifdef __INTEL_COMPILER
#pragma warning (disable: 1125) // (virtual override warning)
#endif
#elif defined (JUCE_DLL) || defined (JUCE_DLL_BUILD)
#define JUCE_API __attribute__ ((visibility("default")))
#endif
#ifndef JUCE_API
#define JUCE_API /**< This macro is added to all JUCE public class declarations. */
#endif
#if JUCE_MSVC && JUCE_DLL_BUILD
#define JUCE_PUBLIC_IN_DLL_BUILD(declaration) public: declaration; private:
#else
#define JUCE_PUBLIC_IN_DLL_BUILD(declaration) declaration;
#endif
/** This macro is added to all JUCE public function declarations. */
#define JUCE_PUBLIC_FUNCTION JUCE_API JUCE_CALLTYPE
#if (! defined (JUCE_CATCH_DEPRECATED_CODE_MISUSE)) && JUCE_DEBUG && ! DOXYGEN
/** This turns on some non-essential bits of code that should prevent old code from compiling
in cases where method signatures have changed, etc.
*/
#define JUCE_CATCH_DEPRECATED_CODE_MISUSE 1
#endif
#ifndef DOXYGEN
#define JUCE_NAMESPACE juce // This old macro is deprecated: you should just use the juce namespace directly.
#endif
/*** End of inlined file: juce_StandardHeader.h ***/
namespace juce
{
class StringRef;
class MemoryBlock;
class File;
class InputStream;
class OutputStream;
class DynamicObject;
class FileInputStream;
class FileOutputStream;
class XmlElement;
extern JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger() noexcept;
extern JUCE_API void JUCE_CALLTYPE logAssertion(const char* file, int line) noexcept;
}
/*** Start of inlined file: juce_Memory.h ***/
namespace juce
{
/** Fills a block of memory with zeros. */
inline void zeromem(void* memory, size_t numBytes) noexcept { memset(memory, 0, numBytes); }
/** Overwrites a structure or object with zeros. */
template <typename Type>
inline void zerostruct(Type& structure) noexcept { memset((void*)&structure, 0, sizeof(structure)); }
/** Delete an object pointer, and sets the pointer to null.
Remember that it's not good c++ practice to use delete directly - always try to use a std::unique_ptr
or other automatic lifetime-management system rather than resorting to deleting raw pointers!
*/
template <typename Type>
inline void deleteAndZero(Type& pointer) { delete pointer; pointer = nullptr; }
/** A handy function to round up a pointer to the nearest multiple of a given number of bytes.
alignmentBytes must be a power of two. */
template <typename Type, typename IntegerType>
inline Type* snapPointerToAlignment(Type* basePointer, IntegerType alignmentBytes) noexcept
{
return (Type*)((((size_t)basePointer) + (alignmentBytes - 1)) & ~(alignmentBytes - 1));
}
/** A handy function which returns the difference between any two pointers, in bytes.
The address of the second pointer is subtracted from the first, and the difference in bytes is returned.
*/
template <typename Type1, typename Type2>
inline int getAddressDifference(Type1* pointer1, Type2* pointer2) noexcept { return (int)(((const char*)pointer1) - (const char*)pointer2); }
/** If a pointer is non-null, this returns a new copy of the object that it points to, or safely returns
nullptr if the pointer is null.
*/
template <class Type>
inline Type* createCopyIfNotNull(const Type* objectToCopy) { return objectToCopy != nullptr ? new Type(*objectToCopy) : nullptr; }
/** A handy function to read un-aligned memory without a performance penalty or bus-error. */
template <typename Type>
inline Type readUnaligned(const void* srcPtr) noexcept
{
Type value;
memcpy(&value, srcPtr, sizeof(Type));
return value;
}
/** A handy function to write un-aligned memory without a performance penalty or bus-error. */
template <typename Type>
inline void writeUnaligned(void* dstPtr, Type value) noexcept
{
memcpy(dstPtr, &value, sizeof(Type));
}
/** Casts a pointer to another type via `void*`, which suppresses the cast-align
warning which sometimes arises when casting pointers to types with different
alignment.
You should only use this when you know for a fact that the input pointer points
to a region that has suitable alignment for `Type`, e.g. regions returned from
malloc/calloc that should be suitable for any non-over-aligned type.
*/
template <typename Type, typename std::enable_if<std::is_pointer<Type>::value, int>::type = 0>
inline Type unalignedPointerCast(void* ptr) noexcept
{
return reinterpret_cast<Type> (ptr);
}
/** Casts a pointer to another type via `void*`, which suppresses the cast-align
warning which sometimes arises when casting pointers to types with different
alignment.
You should only use this when you know for a fact that the input pointer points
to a region that has suitable alignment for `Type`, e.g. regions returned from
malloc/calloc that should be suitable for any non-over-aligned type.
*/
template <typename Type, typename std::enable_if<std::is_pointer<Type>::value, int>::type = 0>
inline Type unalignedPointerCast(const void* ptr) noexcept
{
return reinterpret_cast<Type> (ptr);
}
/** A handy function which adds a number of bytes to any type of pointer and returns the result.
This can be useful to avoid casting pointers to a char* and back when you want to move them by
a specific number of bytes,
*/
template <typename Type, typename IntegerType>
inline Type* addBytesToPointer(Type* basePointer, IntegerType bytes) noexcept
{
return unalignedPointerCast<Type*>(reinterpret_cast<char*> (basePointer) + bytes);
}
/** A handy function which adds a number of bytes to any type of pointer and returns the result.
This can be useful to avoid casting pointers to a char* and back when you want to move them by
a specific number of bytes,
*/
template <typename Type, typename IntegerType>
inline const Type* addBytesToPointer(const Type* basePointer, IntegerType bytes) noexcept
{
return unalignedPointerCast<const Type*>(reinterpret_cast<const char*> (basePointer) + bytes);
}
#if JUCE_MAC || JUCE_IOS || DOXYGEN
/** A handy C++ wrapper that creates and deletes an NSAutoreleasePool object using RAII.
You should use the JUCE_AUTORELEASEPOOL macro to create a local auto-release pool on the stack.
@tags{Core}
*/
class JUCE_API ScopedAutoReleasePool
{
public:
ScopedAutoReleasePool();
~ScopedAutoReleasePool();
private:
void* pool;
JUCE_DECLARE_NON_COPYABLE(ScopedAutoReleasePool)
};
/** A macro that can be used to easily declare a local ScopedAutoReleasePool
object for RAII-based obj-C autoreleasing.
Because this may use the \@autoreleasepool syntax, you must follow the macro with
a set of braces to mark the scope of the pool.
*/
#if (JUCE_COMPILER_SUPPORTS_ARC && defined (__OBJC__)) || DOXYGEN
#define JUCE_AUTORELEASEPOOL @autoreleasepool
#else
#define JUCE_AUTORELEASEPOOL const juce::ScopedAutoReleasePool JUCE_JOIN_MACRO (autoReleasePool_, __LINE__);
#endif
#else
#define JUCE_AUTORELEASEPOOL
#endif
/* In a Windows DLL build, we'll expose some malloc/free functions that live inside the DLL, and use these for
allocating all the objects - that way all juce objects in the DLL and in the host will live in the same heap,
avoiding problems when an object is created in one module and passed across to another where it is deleted.
By piggy-backing on the JUCE_LEAK_DETECTOR macro, these allocators can be injected into most juce classes.
*/
#if JUCE_MSVC && (defined (JUCE_DLL) || defined (JUCE_DLL_BUILD)) && ! (JUCE_DISABLE_DLL_ALLOCATORS || DOXYGEN)
extern JUCE_API void* juceDLL_malloc(size_t);
extern JUCE_API void juceDLL_free(void*);
#define JUCE_LEAK_DETECTOR(OwnerClass) public:\
static void* operator new (size_t sz) { return juce::juceDLL_malloc (sz); } \
static void* operator new (size_t, void* p) { return p; } \
static void operator delete (void* p) { juce::juceDLL_free (p); } \
static void operator delete (void*, void*) {}
#endif
/** (Deprecated) This was a Windows-specific way of checking for object leaks - now please
use the JUCE_LEAK_DETECTOR instead.
*/
#ifndef juce_UseDebuggingNewOperator
#define juce_UseDebuggingNewOperator
#endif
/** Converts an owning raw pointer into a unique_ptr, deriving the
type of the unique_ptr automatically.
This should only be used with pointers to single objects.
Do NOT pass a pointer to an array to this function, as the
destructor of the unique_ptr will incorrectly call `delete`
instead of `delete[]` on the pointer.
*/
template <typename T>
std::unique_ptr<T> rawToUniquePtr(T* ptr)
{
return std::unique_ptr<T>(ptr);
}
} // namespace juce
/*** End of inlined file: juce_Memory.h ***/
/*** Start of inlined file: juce_MathsFunctions.h ***/
namespace juce
{
/*
This file sets up some handy mathematical typdefs and functions.
*/
// Definitions for the int8, int16, int32, int64 and pointer_sized_int types.
/** A platform-independent 8-bit signed integer type. */
using int8 = signed char;
/** A platform-independent 8-bit unsigned integer type. */
using uint8 = unsigned char;
/** A platform-independent 16-bit signed integer type. */
using int16 = signed short;
/** A platform-independent 16-bit unsigned integer type. */
using uint16 = unsigned short;
/** A platform-independent 32-bit signed integer type. */
using int32 = signed int;
/** A platform-independent 32-bit unsigned integer type. */
using uint32 = unsigned int;
#if JUCE_MSVC
/** A platform-independent 64-bit integer type. */
using int64 = __int64;
/** A platform-independent 64-bit unsigned integer type. */
using uint64 = unsigned __int64;
#else
/** A platform-independent 64-bit integer type. */
using int64 = long long;
/** A platform-independent 64-bit unsigned integer type. */
using uint64 = unsigned long long;
#endif
#ifndef DOXYGEN
/** A macro for creating 64-bit literals.
Historically, this was needed to support portability with MSVC6, and is kept here
so that old code will still compile, but nowadays every compiler will support the
LL and ULL suffixes, so you should use those in preference to this macro.
*/
#define literal64bit(longLiteral) (longLiteral##LL)
#endif
#if JUCE_64BIT
/** A signed integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
using pointer_sized_int = int64;
/** An unsigned integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
using pointer_sized_uint = uint64;
#elif JUCE_MSVC
/** A signed integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
using pointer_sized_int = _W64 int;
/** An unsigned integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
using pointer_sized_uint = _W64 unsigned int;
#else
/** A signed integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
using pointer_sized_int = int;
/** An unsigned integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
using pointer_sized_uint = unsigned int;
#endif
#if JUCE_WINDOWS && ! JUCE_MINGW
using ssize_t = pointer_sized_int;
#endif
// Some indispensable min/max functions
/** Returns the larger of two values. */
template <typename Type>
constexpr Type jmax(Type a, Type b) { return a < b ? b : a; }
/** Returns the larger of three values. */
template <typename Type>
constexpr Type jmax(Type a, Type b, Type c) { return a < b ? (b < c ? c : b) : (a < c ? c : a); }
/** Returns the larger of four values. */
template <typename Type>
constexpr Type jmax(Type a, Type b, Type c, Type d) { return jmax(a, jmax(b, c, d)); }
/** Returns the smaller of two values. */
template <typename Type>
constexpr Type jmin(Type a, Type b) { return b < a ? b : a; }
/** Returns the smaller of three values. */
template <typename Type>
constexpr Type jmin(Type a, Type b, Type c) { return b < a ? (c < b ? c : b) : (c < a ? c : a); }
/** Returns the smaller of four values. */
template <typename Type>
constexpr Type jmin(Type a, Type b, Type c, Type d) { return jmin(a, jmin(b, c, d)); }
/** Remaps a normalised value (between 0 and 1) to a target range.
This effectively returns (targetRangeMin + value0To1 * (targetRangeMax - targetRangeMin)).
*/
template <typename Type>
constexpr Type jmap(Type value0To1, Type targetRangeMin, Type targetRangeMax)
{
return targetRangeMin + value0To1 * (targetRangeMax - targetRangeMin);
}
/** Remaps a value from a source range to a target range. */
template <typename Type>
Type jmap(Type sourceValue, Type sourceRangeMin, Type sourceRangeMax, Type targetRangeMin, Type targetRangeMax)
{
jassert(sourceRangeMax != sourceRangeMin); // mapping from a range of zero will produce NaN!
return targetRangeMin + ((targetRangeMax - targetRangeMin) * (sourceValue - sourceRangeMin)) / (sourceRangeMax - sourceRangeMin);
}
/** Remaps a normalised value (between 0 and 1) to a logarithmic target range.
The entire target range must be greater than zero.
@see mapFromLog10
@code
mapToLog10 (0.5, 0.4, 40.0) == 4.0
@endcode
*/
template <typename Type>
Type mapToLog10(Type value0To1, Type logRangeMin, Type logRangeMax)
{
jassert(logRangeMin > 0);
jassert(logRangeMax > 0);
auto logMin = std::log10(logRangeMin);
auto logMax = std::log10(logRangeMax);
return std::pow((Type)10.0, value0To1 * (logMax - logMin) + logMin);
}
/** Remaps a logarithmic value in a target range to a normalised value (between 0 and 1).
The entire target range must be greater than zero.
@see mapToLog10
@code
mapFromLog10 (4.0, 0.4, 40.0) == 0.5
@endcode
*/
template <typename Type>
Type mapFromLog10(Type valueInLogRange, Type logRangeMin, Type logRangeMax)
{
jassert(logRangeMin > 0);
jassert(logRangeMax > 0);
auto logMin = std::log10(logRangeMin);
auto logMax = std::log10(logRangeMax);
return (std::log10(valueInLogRange) - logMin) / (logMax - logMin);
}
/** Scans an array of values, returning the minimum value that it contains. */
template <typename Type>
Type findMinimum(const Type* data, int numValues)
{
if (numValues <= 0)
return Type(0);
auto result = *data++;
while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
{
auto v = *data++;
if (v < result)
result = v;
}
return result;
}
/** Scans an array of values, returning the maximum value that it contains. */
template <typename Type>
Type findMaximum(const Type* values, int numValues)
{
if (numValues <= 0)
return Type(0);
auto result = *values++;
while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
{
auto v = *values++;
if (result < v)
result = v;
}
return result;
}
/** Scans an array of values, returning the minimum and maximum values that it contains. */
template <typename Type>
void findMinAndMax(const Type* values, int numValues, Type& lowest, Type& highest)
{
if (numValues <= 0)
{
lowest = Type(0);
highest = Type(0);
}
else
{
auto mn = *values++;
auto mx = mn;
while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
{
auto v = *values++;
if (mx < v) mx = v;
if (v < mn) mn = v;
}
lowest = mn;
highest = mx;
}
}
/** Constrains a value to keep it within a given range.
This will check that the specified value lies between the lower and upper bounds
specified, and if not, will return the nearest value that would be in-range. Effectively,
it's like calling jmax (lowerLimit, jmin (upperLimit, value)).
Note that it expects that lowerLimit <= upperLimit. If this isn't true,
the results will be unpredictable.
@param lowerLimit the minimum value to return
@param upperLimit the maximum value to return
@param valueToConstrain the value to try to return
@returns the closest value to valueToConstrain which lies between lowerLimit
and upperLimit (inclusive)
@see jmin, jmax, jmap
*/
template <typename Type>
Type jlimit(Type lowerLimit,
Type upperLimit,
Type valueToConstrain) noexcept
{
jassert(lowerLimit <= upperLimit); // if these are in the wrong order, results are unpredictable..
return valueToConstrain < lowerLimit ? lowerLimit
: (upperLimit < valueToConstrain ? upperLimit
: valueToConstrain);
}
/** Returns true if a value is at least zero, and also below a specified upper limit.
This is basically a quicker way to write:
@code valueToTest >= 0 && valueToTest < upperLimit
@endcode
*/
template <typename Type1, typename Type2>
bool isPositiveAndBelow(Type1 valueToTest, Type2 upperLimit) noexcept
{
jassert(Type1() <= static_cast<Type1> (upperLimit)); // makes no sense to call this if the upper limit is itself below zero..
return Type1() <= valueToTest && valueToTest < static_cast<Type1> (upperLimit);
}
template <typename Type>
bool isPositiveAndBelow(int valueToTest, Type upperLimit) noexcept
{
jassert(upperLimit >= 0); // makes no sense to call this if the upper limit is itself below zero..
return static_cast<unsigned int> (valueToTest) < static_cast<unsigned int> (upperLimit);
}
/** Returns true if a value is at least zero, and also less than or equal to a specified upper limit.
This is basically a quicker way to write:
@code valueToTest >= 0 && valueToTest <= upperLimit
@endcode
*/
template <typename Type1, typename Type2>
bool isPositiveAndNotGreaterThan(Type1 valueToTest, Type2 upperLimit) noexcept
{
jassert(Type1() <= static_cast<Type1> (upperLimit)); // makes no sense to call this if the upper limit is itself below zero..
return Type1() <= valueToTest && valueToTest <= static_cast<Type1> (upperLimit);
}
template <typename Type>
bool isPositiveAndNotGreaterThan(int valueToTest, Type upperLimit) noexcept
{
jassert(upperLimit >= 0); // makes no sense to call this if the upper limit is itself below zero..
return static_cast<unsigned int> (valueToTest) <= static_cast<unsigned int> (upperLimit);
}
/** Computes the absolute difference between two values and returns true if it is less than or equal
to a given tolerance, otherwise it returns false.
*/
template <typename Type>
bool isWithin(Type a, Type b, Type tolerance) noexcept
{
return std::abs(a - b) <= tolerance;
}
/** Returns true if the two numbers are approximately equal. This is useful for floating-point
and double comparisons.
*/
template <typename Type>
bool approximatelyEqual(Type a, Type b) noexcept
{
return std::abs(a - b) <= (std::numeric_limits<Type>::epsilon() * std::max(a, b))
|| std::abs(a - b) < std::numeric_limits<Type>::min();
}
/** Handy function for avoiding unused variables warning. */
template <typename... Types>
void ignoreUnused(Types&&...) noexcept {}
/** Handy function for getting the number of elements in a simple const C array.
E.g.
@code
static int myArray[] = { 1, 2, 3 };
int numElements = numElementsInArray (myArray) // returns 3
@endcode
*/
template <typename Type, size_t N>
constexpr int numElementsInArray(Type(&)[N]) noexcept { return N; }
// Some useful maths functions that aren't always present with all compilers and build settings.
/** Using juce_hypot is easier than dealing with the different types of hypot function
that are provided by the various platforms and compilers. */
template <typename Type>
Type juce_hypot(Type a, Type b) noexcept
{
#if JUCE_MSVC
return static_cast<Type> (_hypot(a, b));
#else
return static_cast<Type> (hypot(a, b));
#endif
}
#ifndef DOXYGEN
template <>
inline float juce_hypot(float a, float b) noexcept
{
#if JUCE_MSVC
return _hypotf(a, b);
#else
return hypotf(a, b);
#endif
}
#endif
/** Commonly used mathematical constants
@tags{Core}
*/
template <typename FloatType>
struct MathConstants
{
/** A predefined value for Pi */
static constexpr FloatType pi = static_cast<FloatType> (3.141592653589793238L);
/** A predefined value for 2 * Pi */
static constexpr FloatType twoPi = static_cast<FloatType> (2 * 3.141592653589793238L);
/** A predefined value for Pi / 2 */
static constexpr FloatType halfPi = static_cast<FloatType> (3.141592653589793238L / 2);
/** A predefined value for Euler's number */
static constexpr FloatType euler = static_cast<FloatType> (2.71828182845904523536L);
/** A predefined value for sqrt(2) */
static constexpr FloatType sqrt2 = static_cast<FloatType> (1.4142135623730950488L);
};
#ifndef DOXYGEN
/** A double-precision constant for pi.
@deprecated This is deprecated in favour of MathConstants<double>::pi.
The reason is that "double_Pi" was a confusing name, and many people misused it,
wrongly thinking it meant 2 * pi !
*/
const constexpr double double_Pi = MathConstants<double>::pi;
/** A single-precision constant for pi.
@deprecated This is deprecated in favour of MathConstants<float>::pi.
The reason is that "double_Pi" was a confusing name, and many people misused it,
wrongly thinking it meant 2 * pi !
*/
const constexpr float float_Pi = MathConstants<float>::pi;
#endif
/** Converts an angle in degrees to radians. */
template <typename FloatType>
constexpr FloatType degreesToRadians(FloatType degrees) noexcept { return degrees * (MathConstants<FloatType>::pi / FloatType(180)); }
/** Converts an angle in radians to degrees. */
template <typename FloatType>
constexpr FloatType radiansToDegrees(FloatType radians) noexcept { return radians * (FloatType(180) / MathConstants<FloatType>::pi); }
/** The isfinite() method seems to vary between platforms, so this is a
platform-independent function for it.
*/
template <typename NumericType>
bool juce_isfinite(NumericType) noexcept
{
return true; // Integer types are always finite
}
template <>
inline bool juce_isfinite(float value) noexcept
{
#if JUCE_WINDOWS && ! JUCE_MINGW
return _finite(value) != 0;
#else
return std::isfinite(value);
#endif
}
template <>
inline bool juce_isfinite(double value) noexcept
{
#if JUCE_WINDOWS && ! JUCE_MINGW
return _finite(value) != 0;
#else
return std::isfinite(value);
#endif
}
#if JUCE_MSVC
#ifndef __INTEL_COMPILER
#pragma float_control (precise, on, push)
#endif
#endif
/** Fast floating-point-to-integer conversion.
This is faster than using the normal c++ cast to convert a float to an int, and
it will round the value to the nearest integer, rather than rounding it down
like the normal cast does.
Note that this routine gets its speed at the expense of some accuracy, and when
rounding values whose floating point component is exactly 0.5, odd numbers and
even numbers will be rounded up or down differently.
*/
template <typename FloatType>
int roundToInt(const FloatType value) noexcept
{
#ifdef __INTEL_COMPILER
#pragma float_control (precise, on, push)
#endif
union { int asInt[2]; double asDouble; } n;
n.asDouble = ((double)value) + 6755399441055744.0;
#if JUCE_BIG_ENDIAN
return n.asInt[1];
#else
return n.asInt[0];
#endif
}
inline int roundToInt(int value) noexcept
{
return value;
}
#if JUCE_MSVC
#ifndef __INTEL_COMPILER
#pragma float_control (pop)
#endif
#endif
/** Fast floating-point-to-integer conversion.
This is a slightly slower and slightly more accurate version of roundToInt(). It works
fine for values above zero, but negative numbers are rounded the wrong way.
*/
inline int roundToIntAccurate(double value) noexcept
{
#ifdef __INTEL_COMPILER
#pragma float_control (pop)
#endif
return roundToInt(value + 1.5e-8);
}
/** Truncates a positive floating-point number to an unsigned int.
This is generally faster than static_cast<unsigned int> (std::floor (x))
but it only works for positive numbers small enough to be represented as an
unsigned int.
*/
template <typename FloatType>
unsigned int truncatePositiveToUnsignedInt(FloatType value) noexcept
{
jassert(value >= static_cast<FloatType> (0));
jassert(static_cast<FloatType> (value)
<= static_cast<FloatType> (std::numeric_limits<unsigned int>::max()));
return static_cast<unsigned int> (value);
}
/** Returns true if the specified integer is a power-of-two. */
template <typename IntegerType>
constexpr bool isPowerOfTwo(IntegerType value)
{
return (value & (value - 1)) == 0;
}
/** Returns the smallest power-of-two which is equal to or greater than the given integer. */
inline int nextPowerOfTwo(int n) noexcept
{
--n;
n |= (n >> 1);
n |= (n >> 2);
n |= (n >> 4);
n |= (n >> 8);
n |= (n >> 16);
return n + 1;
}
/** Returns the index of the highest set bit in a (non-zero) number.
So for n=3 this would return 1, for n=7 it returns 2, etc.
An input value of 0 is illegal!
*/
int findHighestSetBit(uint32 n) noexcept;
/** Returns the number of bits in a 32-bit integer. */
inline int countNumberOfBits(uint32 n) noexcept
{
n -= ((n >> 1) & 0x55555555);
n = (((n >> 2) & 0x33333333) + (n & 0x33333333));
n = (((n >> 4) + n) & 0x0f0f0f0f);
n += (n >> 8);
n += (n >> 16);
return (int)(n & 0x3f);
}
/** Returns the number of bits in a 64-bit integer. */
inline int countNumberOfBits(uint64 n) noexcept
{
return countNumberOfBits((uint32)n) + countNumberOfBits((uint32)(n >> 32));
}
/** Performs a modulo operation, but can cope with the dividend being negative.
The divisor must be greater than zero.
*/
template <typename IntegerType>
IntegerType negativeAwareModulo(IntegerType dividend, const IntegerType divisor) noexcept
{
jassert(divisor > 0);
dividend %= divisor;
return (dividend < 0) ? (dividend + divisor) : dividend;
}
/** Returns the square of its argument. */
template <typename NumericType>
inline constexpr NumericType square(NumericType n) noexcept
{
return n * n;
}
/** Writes a number of bits into a memory buffer at a given bit index.
The buffer is treated as a sequence of 8-bit bytes, and the value is encoded in little-endian order,
so for example if startBit = 10, and numBits = 11 then the lower 6 bits of the value would be written
into bits 2-8 of targetBuffer[1], and the upper 5 bits of value into bits 0-5 of targetBuffer[2].
@see readLittleEndianBitsInBuffer
*/
void writeLittleEndianBitsInBuffer(void* targetBuffer, uint32 startBit, uint32 numBits, uint32 value) noexcept;
/** Reads a number of bits from a buffer at a given bit index.
The buffer is treated as a sequence of 8-bit bytes, and the value is encoded in little-endian order,
so for example if startBit = 10, and numBits = 11 then the lower 6 bits of the result would be read
from bits 2-8 of sourceBuffer[1], and the upper 5 bits of the result from bits 0-5 of sourceBuffer[2].
@see writeLittleEndianBitsInBuffer
*/
uint32 readLittleEndianBitsInBuffer(const void* sourceBuffer, uint32 startBit, uint32 numBits) noexcept;
#if JUCE_INTEL || defined (DOXYGEN)
/** This macro can be applied to a float variable to check whether it contains a denormalised
value, and to normalise it if necessary.
On CPUs that aren't vulnerable to denormalisation problems, this will have no effect.
*/
#define JUCE_UNDENORMALISE(x) { (x) += 0.1f; (x) -= 0.1f; }
#else
#define JUCE_UNDENORMALISE(x)
#endif
/** This namespace contains a few template classes for helping work out class type variations.
*/
namespace TypeHelpers
{
/** The ParameterType struct is used to find the best type to use when passing some kind
of object as a parameter.
Of course, this is only likely to be useful in certain esoteric template situations.
E.g. "myFunction (typename TypeHelpers::ParameterType<int>::type, typename TypeHelpers::ParameterType<MyObject>::type)"
would evaluate to "myfunction (int, const MyObject&)", keeping any primitive types as
pass-by-value, but passing objects as a const reference, to avoid copying.
@tags{Core}
*/
template <typename Type> struct ParameterType { using type = const Type&; };
#if ! DOXYGEN
template <typename Type> struct ParameterType <Type&> { using type = Type&; };
template <typename Type> struct ParameterType <Type*> { using type = Type*; };
template <> struct ParameterType <char> { using type = char; };
template <> struct ParameterType <unsigned char> { using type = unsigned char; };
template <> struct ParameterType <short> { using type = short; };
template <> struct ParameterType <unsigned short> { using type = unsigned short; };
template <> struct ParameterType <int> { using type = int; };
template <> struct ParameterType <unsigned int> { using type = unsigned int; };
template <> struct ParameterType <long> { using type = long; };
template <> struct ParameterType <unsigned long> { using type = unsigned long; };
template <> struct ParameterType <int64> { using type = int64; };
template <> struct ParameterType <uint64> { using type = uint64; };
template <> struct ParameterType <bool> { using type = bool; };
template <> struct ParameterType <float> { using type = float; };
template <> struct ParameterType <double> { using type = double; };
#endif
/** These templates are designed to take a type, and if it's a double, they return a double
type; for anything else, they return a float type.
@tags{Core}
*/
template <typename Type> struct SmallestFloatType { using type = float; };
#if ! DOXYGEN
template <> struct SmallestFloatType <double> { using type = double; };
#endif
/** These templates are designed to take an integer type, and return an unsigned int
version with the same size.
@tags{Core}
*/
template <int bytes> struct UnsignedTypeWithSize {};
#if ! DOXYGEN
template <> struct UnsignedTypeWithSize<1> { using type = uint8; };
template <> struct UnsignedTypeWithSize<2> { using type = uint16; };
template <> struct UnsignedTypeWithSize<4> { using type = uint32; };
template <> struct UnsignedTypeWithSize<8> { using type = uint64; };
#endif
}
#if ! DOXYGEN
// These old functions are deprecated: Just use roundToInt instead.
JUCE_DEPRECATED_ATTRIBUTE inline int roundDoubleToInt(double value) noexcept { return roundToInt(value); }
JUCE_DEPRECATED_ATTRIBUTE inline int roundFloatToInt(float value) noexcept { return roundToInt(value); }
// This old function isn't needed - just use std::abs() instead
JUCE_DEPRECATED_ATTRIBUTE inline int64 abs64(int64 n) noexcept { return std::abs(n); }
#endif
} // namespace juce
/*** End of inlined file: juce_MathsFunctions.h ***/
/*** Start of inlined file: juce_ByteOrder.h ***/
#if ! DOXYGEN && (JUCE_MAC || JUCE_IOS)
#include <libkern/OSByteOrder.h>
#endif
namespace juce
{
/** Contains static methods for converting the byte order between different
endiannesses.
@tags{Core}
*/
class JUCE_API ByteOrder
{
public:
/** Swaps the upper and lower bytes of a 16-bit integer. */
constexpr static uint16 swap(uint16 value) noexcept;
/** Swaps the upper and lower bytes of a 16-bit integer. */
constexpr static int16 swap(int16 value) noexcept;
/** Reverses the order of the 4 bytes in a 32-bit integer. */
static uint32 swap(uint32 value) noexcept;
/** Reverses the order of the 4 bytes in a 32-bit integer. */
static int32 swap(int32 value) noexcept;
/** Reverses the order of the 8 bytes in a 64-bit integer. */
static uint64 swap(uint64 value) noexcept;
/** Reverses the order of the 8 bytes in a 64-bit integer. */
static int64 swap(int64 value) noexcept;
/** Returns a garbled float which has the reverse byte-order of the original. */
static float swap(float value) noexcept;
/** Returns a garbled double which has the reverse byte-order of the original. */
static double swap(double value) noexcept;
/** Swaps the byte order of a signed or unsigned integer if the CPU is big-endian */
template <typename Type>
static Type swapIfBigEndian(Type value) noexcept
{
#if JUCE_LITTLE_ENDIAN
return value;
#else
return swap(value);
#endif
}
/** Swaps the byte order of a signed or unsigned integer if the CPU is little-endian */
template <typename Type>
static Type swapIfLittleEndian(Type value) noexcept
{
#if JUCE_LITTLE_ENDIAN
return swap(value);
#else
return value;
#endif
}
/** Turns 4 bytes into a little-endian integer. */
constexpr static uint32 littleEndianInt(const void* bytes) noexcept;
/** Turns 8 bytes into a little-endian integer. */
constexpr static uint64 littleEndianInt64(const void* bytes) noexcept;
/** Turns 2 bytes into a little-endian integer. */
constexpr static uint16 littleEndianShort(const void* bytes) noexcept;
/** Converts 3 little-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */
constexpr static int littleEndian24Bit(const void* bytes) noexcept;
/** Copies a 24-bit number to 3 little-endian bytes. */
static void littleEndian24BitToChars(int32 value, void* destBytes) noexcept;
/** Turns 4 bytes into a big-endian integer. */
constexpr static uint32 bigEndianInt(const void* bytes) noexcept;
/** Turns 8 bytes into a big-endian integer. */
constexpr static uint64 bigEndianInt64(const void* bytes) noexcept;
/** Turns 2 bytes into a big-endian integer. */
constexpr static uint16 bigEndianShort(const void* bytes) noexcept;
/** Converts 3 big-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */
constexpr static int bigEndian24Bit(const void* bytes) noexcept;
/** Copies a 24-bit number to 3 big-endian bytes. */
static void bigEndian24BitToChars(int32 value, void* destBytes) noexcept;
/** Constructs a 16-bit integer from its constituent bytes, in order of significance. */
constexpr static uint16 makeInt(uint8 leastSig, uint8 mostSig) noexcept;
/** Constructs a 32-bit integer from its constituent bytes, in order of significance. */
constexpr static uint32 makeInt(uint8 leastSig, uint8 byte1, uint8 byte2, uint8 mostSig) noexcept;
/** Constructs a 64-bit integer from its constituent bytes, in order of significance. */
constexpr static uint64 makeInt(uint8 leastSig, uint8 byte1, uint8 byte2, uint8 byte3,
uint8 byte4, uint8 byte5, uint8 byte6, uint8 mostSig) noexcept;
/** Returns true if the current CPU is big-endian. */
constexpr static bool isBigEndian() noexcept
{
#if JUCE_LITTLE_ENDIAN
return false;
#else
return true;
#endif
}
private:
ByteOrder() = delete;
};
constexpr inline uint16 ByteOrder::swap(uint16 v) noexcept { return static_cast<uint16> ((v << 8) | (v >> 8)); }
constexpr inline int16 ByteOrder::swap(int16 v) noexcept { return static_cast<int16> (swap(static_cast<uint16> (v))); }
inline int32 ByteOrder::swap(int32 v) noexcept { return static_cast<int32> (swap(static_cast<uint32> (v))); }
inline int64 ByteOrder::swap(int64 v) noexcept { return static_cast<int64> (swap(static_cast<uint64> (v))); }
inline float ByteOrder::swap(float v) noexcept { union { uint32 asUInt; float asFloat; } n; n.asFloat = v; n.asUInt = swap(n.asUInt); return n.asFloat; }
inline double ByteOrder::swap(double v) noexcept { union { uint64 asUInt; double asFloat; } n; n.asFloat = v; n.asUInt = swap(n.asUInt); return n.asFloat; }
#if JUCE_MSVC && ! defined (__INTEL_COMPILER)
#pragma intrinsic (_byteswap_ulong)
#endif
inline uint32 ByteOrder::swap(uint32 n) noexcept
{
#if JUCE_MAC || JUCE_IOS
return OSSwapInt32(n);
#elif (JUCE_GCC || JUCE_CLANG) && JUCE_INTEL && ! JUCE_NO_INLINE_ASM
asm("bswap %%eax" : "=a"(n) : "a"(n));
return n;
#elif JUCE_MSVC
return _byteswap_ulong(n);
#elif JUCE_ANDROID
return bswap_32(n);
#else
return (n << 24) | (n >> 24) | ((n & 0xff00) << 8) | ((n & 0xff0000) >> 8);
#endif
}
inline uint64 ByteOrder::swap(uint64 value) noexcept
{
#if JUCE_MAC || JUCE_IOS
return OSSwapInt64(value);
#elif JUCE_MSVC
return _byteswap_uint64(value);
#else
return (((uint64)swap((uint32)value)) << 32) | swap((uint32)(value >> 32));
#endif
}
constexpr inline uint16 ByteOrder::makeInt(uint8 b0, uint8 b1) noexcept
{
return static_cast<uint16> (static_cast<uint16> (b0) | (static_cast<uint16> (b1) << 8));
}
constexpr inline uint32 ByteOrder::makeInt(uint8 b0, uint8 b1, uint8 b2, uint8 b3) noexcept
{
return static_cast<uint32> (b0) | (static_cast<uint32> (b1) << 8)
| (static_cast<uint32> (b2) << 16) | (static_cast<uint32> (b3) << 24);
}
constexpr inline uint64 ByteOrder::makeInt(uint8 b0, uint8 b1, uint8 b2, uint8 b3, uint8 b4, uint8 b5, uint8 b6, uint8 b7) noexcept
{
return static_cast<uint64> (b0) | (static_cast<uint64> (b1) << 8) | (static_cast<uint64> (b2) << 16) | (static_cast<uint64> (b3) << 24)
| (static_cast<uint64> (b4) << 32) | (static_cast<uint64> (b5) << 40) | (static_cast<uint64> (b6) << 48) | (static_cast<uint64> (b7) << 56);
}
constexpr inline uint16 ByteOrder::littleEndianShort(const void* bytes) noexcept { return makeInt(static_cast<const uint8*> (bytes)[0], static_cast<const uint8*> (bytes)[1]); }
constexpr inline uint32 ByteOrder::littleEndianInt(const void* bytes) noexcept {
return makeInt(static_cast<const uint8*> (bytes)[0], static_cast<const uint8*> (bytes)[1],
static_cast<const uint8*> (bytes)[2], static_cast<const uint8*> (bytes)[3]);
}
constexpr inline uint64 ByteOrder::littleEndianInt64(const void* bytes) noexcept {
return makeInt(static_cast<const uint8*> (bytes)[0], static_cast<const uint8*> (bytes)[1],
static_cast<const uint8*> (bytes)[2], static_cast<const uint8*> (bytes)[3],
static_cast<const uint8*> (bytes)[4], static_cast<const uint8*> (bytes)[5],
static_cast<const uint8*> (bytes)[6], static_cast<const uint8*> (bytes)[7]);
}
constexpr inline uint16 ByteOrder::bigEndianShort(const void* bytes) noexcept { return makeInt(static_cast<const uint8*> (bytes)[1], static_cast<const uint8*> (bytes)[0]); }
constexpr inline uint32 ByteOrder::bigEndianInt(const void* bytes) noexcept {
return makeInt(static_cast<const uint8*> (bytes)[3], static_cast<const uint8*> (bytes)[2],
static_cast<const uint8*> (bytes)[1], static_cast<const uint8*> (bytes)[0]);
}
constexpr inline uint64 ByteOrder::bigEndianInt64(const void* bytes) noexcept {
return makeInt(static_cast<const uint8*> (bytes)[7], static_cast<const uint8*> (bytes)[6],
static_cast<const uint8*> (bytes)[5], static_cast<const uint8*> (bytes)[4],
static_cast<const uint8*> (bytes)[3], static_cast<const uint8*> (bytes)[2],
static_cast<const uint8*> (bytes)[1], static_cast<const uint8*> (bytes)[0]);
}
constexpr inline int32 ByteOrder::littleEndian24Bit(const void* bytes) noexcept { return (int32)((((uint32) static_cast<const int8*> (bytes)[2]) << 16) | (((uint32) static_cast<const uint8*> (bytes)[1]) << 8) | ((uint32) static_cast<const uint8*> (bytes)[0])); }
constexpr inline int32 ByteOrder::bigEndian24Bit(const void* bytes) noexcept { return (int32)((((uint32) static_cast<const int8*> (bytes)[0]) << 16) | (((uint32) static_cast<const uint8*> (bytes)[1]) << 8) | ((uint32) static_cast<const uint8*> (bytes)[2])); }
inline void ByteOrder::littleEndian24BitToChars(int32 value, void* destBytes) noexcept { static_cast<uint8*> (destBytes)[0] = (uint8)value; static_cast<uint8*> (destBytes)[1] = (uint8)(value >> 8); static_cast<uint8*> (destBytes)[2] = (uint8)(value >> 16); }
inline void ByteOrder::bigEndian24BitToChars(int32 value, void* destBytes) noexcept { static_cast<uint8*> (destBytes)[0] = (uint8)(value >> 16); static_cast<uint8*> (destBytes)[1] = (uint8)(value >> 8); static_cast<uint8*> (destBytes)[2] = (uint8)value; }
} // namespace juce
/*** End of inlined file: juce_ByteOrder.h ***/
/*** Start of inlined file: juce_Atomic.h ***/
namespace juce
{
#ifndef DOXYGEN
namespace AtomicHelpers
{
template <typename T> struct DiffTypeHelper { using Type = T; };
template <typename T> struct DiffTypeHelper<T*> { using Type = std::ptrdiff_t; };
}
#endif
/**
A simple wrapper around std::atomic.
@tags{Core}
*/
template <typename Type>
struct Atomic final
{
using DiffType = typename AtomicHelpers::DiffTypeHelper<Type>::Type;
/** Creates a new value, initialised to zero. */
Atomic() noexcept : value(Type()) {}
/** Creates a new value, with a given initial value. */
Atomic(Type initialValue) noexcept : value(initialValue) {}
/** Copies another value (atomically). */
Atomic(const Atomic& other) noexcept : value(other.get()) {}
/** Destructor. */
~Atomic() noexcept
{
#if __cpp_lib_atomic_is_always_lock_free
static_assert (std::atomic<Type>::is_always_lock_free,
"This class can only be used for lock-free types");
#endif
}
/** Atomically reads and returns the current value. */
Type get() const noexcept { return value.load(); }
/** Atomically sets the current value. */
void set(Type newValue) noexcept { value = newValue; }
/** Atomically sets the current value, returning the value that was replaced. */
Type exchange(Type newValue) noexcept { return value.exchange(newValue); }
/** Atomically compares this value with a target value, and if it is equal, sets
this to be equal to a new value.
This operation is the atomic equivalent of doing this:
@code
bool compareAndSetBool (Type newValue, Type valueToCompare)
{
if (get() == valueToCompare)
{
set (newValue);
return true;
}
return false;
}
@endcode
Internally, this method calls std::atomic::compare_exchange_strong with
memory_order_seq_cst (the strictest std::memory_order).
@returns true if the comparison was true and the value was replaced; false if
the comparison failed and the value was left unchanged.
@see compareAndSetValue
*/
bool compareAndSetBool(Type newValue, Type valueToCompare) noexcept
{
return value.compare_exchange_strong(valueToCompare, newValue);
}
/** Copies another value into this one (atomically). */
Atomic<Type>& operator= (const Atomic& other) noexcept
{
value = other.value.load();
return *this;
}
/** Copies another value into this one (atomically). */
Atomic<Type>& operator= (Type newValue) noexcept
{
value = newValue;
return *this;
}
/** Atomically adds a number to this value, returning the new value. */
Type operator+= (DiffType amountToAdd) noexcept { return value += amountToAdd; }
/** Atomically subtracts a number from this value, returning the new value. */
Type operator-= (DiffType amountToSubtract) noexcept { return value -= amountToSubtract; }
/** Atomically increments this value, returning the new value. */
Type operator++() noexcept { return ++value; }
/** Atomically decrements this value, returning the new value. */
Type operator--() noexcept { return --value; }
/** Implements a memory read/write barrier.
Internally this calls std::atomic_thread_fence with
memory_order_seq_cst (the strictest std::memory_order).
*/
void memoryBarrier() noexcept { atomic_thread_fence(std::memory_order_seq_cst); }
/** The std::atomic object that this class operates on. */
std::atomic<Type> value;
#ifndef DOXYGEN
/* This method has been deprecated as there is no equivalent method in
std::atomic. Use compareAndSetBool instead.
*/
JUCE_DEPRECATED(Type compareAndSetValue(Type, Type) noexcept);
#endif
};
} // namespace juce
/*** End of inlined file: juce_Atomic.h ***/
/*** Start of inlined file: juce_CharacterFunctions.h ***/
namespace juce
{
#if JUCE_WINDOWS && ! DOXYGEN
#define JUCE_NATIVE_WCHAR_IS_UTF8 0
#define JUCE_NATIVE_WCHAR_IS_UTF16 1
#define JUCE_NATIVE_WCHAR_IS_UTF32 0
#else
/** This macro will be set to 1 if the compiler's native wchar_t is an 8-bit type. */
#define JUCE_NATIVE_WCHAR_IS_UTF8 0
/** This macro will be set to 1 if the compiler's native wchar_t is a 16-bit type. */
#define JUCE_NATIVE_WCHAR_IS_UTF16 0
/** This macro will be set to 1 if the compiler's native wchar_t is a 32-bit type. */
#define JUCE_NATIVE_WCHAR_IS_UTF32 1
#endif
#if JUCE_NATIVE_WCHAR_IS_UTF32 || DOXYGEN
/** A platform-independent 32-bit unicode character type. */
using juce_wchar = wchar_t;
#else
using juce_wchar = uint32;
#endif
#ifndef DOXYGEN
/** This macro is deprecated, but preserved for compatibility with old code. */
#define JUCE_T(stringLiteral) (L##stringLiteral)
#endif
#if JUCE_DEFINE_T_MACRO
/** The 'T' macro is an alternative for using the "L" prefix in front of a string literal.
This macro is deprecated, but available for compatibility with old code if you set
JUCE_DEFINE_T_MACRO = 1. The fastest, most portable and best way to write your string
literals is as standard char strings, using escaped utf-8 character sequences for extended
characters, rather than trying to store them as wide-char strings.
*/
#define T(stringLiteral) JUCE_T(stringLiteral)
#endif
#if ! DOXYGEN
// GNU libstdc++ does not have std::make_unsigned
namespace internal
{
template <typename Type> struct make_unsigned { using type = Type; };
template <> struct make_unsigned<signed char> { using type = unsigned char; };
template <> struct make_unsigned<char> { using type = unsigned char; };
template <> struct make_unsigned<short> { using type = unsigned short; };
template <> struct make_unsigned<int> { using type = unsigned int; };
template <> struct make_unsigned<long> { using type = unsigned long; };
template <> struct make_unsigned<long long> { using type = unsigned long long; };
}
#endif
/**
A collection of functions for manipulating characters and character strings.
Most of these methods are designed for internal use by the String and CharPointer
classes, but some of them may be useful to call directly.
@see String, CharPointer_UTF8, CharPointer_UTF16, CharPointer_UTF32
@tags{Core}
*/
class JUCE_API CharacterFunctions
{
public:
/** Converts a character to upper-case. */
static juce_wchar toUpperCase(juce_wchar character) noexcept;
/** Converts a character to lower-case. */
static juce_wchar toLowerCase(juce_wchar character) noexcept;
/** Checks whether a unicode character is upper-case. */
static bool isUpperCase(juce_wchar character) noexcept;
/** Checks whether a unicode character is lower-case. */
static bool isLowerCase(juce_wchar character) noexcept;
/** Checks whether a character is whitespace. */
static bool isWhitespace(char character) noexcept;
/** Checks whether a character is whitespace. */
static bool isWhitespace(juce_wchar character) noexcept;
/** Checks whether a character is a digit. */
static bool isDigit(char character) noexcept;
/** Checks whether a character is a digit. */
static bool isDigit(juce_wchar character) noexcept;
/** Checks whether a character is alphabetic. */
static bool isLetter(char character) noexcept;
/** Checks whether a character is alphabetic. */
static bool isLetter(juce_wchar character) noexcept;
/** Checks whether a character is alphabetic or numeric. */
static bool isLetterOrDigit(char character) noexcept;
/** Checks whether a character is alphabetic or numeric. */
static bool isLetterOrDigit(juce_wchar character) noexcept;
/** Checks whether a character is a printable character, i.e. alphabetic, numeric,
a punctuation character or a space.
*/
static bool isPrintable(char character) noexcept;
/** Checks whether a character is a printable character, i.e. alphabetic, numeric,
a punctuation character or a space.
*/
static bool isPrintable(juce_wchar character) noexcept;
/** Returns 0 to 16 for '0' to 'F", or -1 for characters that aren't a legal hex digit. */
static int getHexDigitValue(juce_wchar digit) noexcept;
/** Converts a byte of Windows 1252 codepage to unicode. */
static juce_wchar getUnicodeCharFromWindows1252Codepage(uint8 windows1252Char) noexcept;
/** Parses a character string to read a floating-point number.
Note that this will advance the pointer that is passed in, leaving it at
the end of the number.
*/
template <typename CharPointerType>
static double readDoubleValue(CharPointerType& text) noexcept
{
constexpr auto inf = std::numeric_limits<double>::infinity();
bool isNegative = false;
#if ! JUCE_MINGW
constexpr const int maxSignificantDigits = 17 + 1; // An additional digit for rounding
constexpr const int bufferSize = maxSignificantDigits + 7 + 1; // -.E-XXX and a trailing null-terminator
char buffer[(size_t)bufferSize] = {};
char* writePtr = &(buffer[0]);
#endif
const auto endOfWhitspace = text.findEndOfWhitespace();
text = endOfWhitspace;
auto c = *text;
switch (c)
{
case '-':
isNegative = true;
#if ! JUCE_MINGW
* writePtr++ = '-';
#endif
JUCE_FALLTHROUGH
case '+':
c = *++text;
break;
default:
break;
}
switch (c)
{
case 'n':
case 'N':
{
if ((text[1] == 'a' || text[1] == 'A') && (text[2] == 'n' || text[2] == 'N'))
{
text += 3;
return std::numeric_limits<double>::quiet_NaN();
}
text = endOfWhitspace;
return 0.0;
}
case 'i':
case 'I':
{
if ((text[1] == 'n' || text[1] == 'N') && (text[2] == 'f' || text[2] == 'F'))
{
text += 3;
return isNegative ? -inf : inf;
}
text = endOfWhitspace;
return 0.0;
}
default:
break;
}
#if JUCE_MINGW
// MinGW does not have access to the locale functions required for strtold, so we parse the doubles
// ourselves. There are some edge cases where the least significant digit will be wrong!
double result[3] = { 0 }, accumulator[2] = { 0 };
int exponentAdjustment[2] = { 0 }, exponentAccumulator[2] = { -1, -1 };
int exponent = 0, decPointIndex = 0, digit = 0;
int lastDigit = 0, numSignificantDigits = 0;
bool digitsFound = false;
constexpr const int maxSignificantDigits = 17 + 1;
for (;;)
{
if (text.isDigit())
{
lastDigit = digit;
digit = (int)text.getAndAdvance() - '0';
digitsFound = true;
if (decPointIndex != 0)
exponentAdjustment[1]++;
if (numSignificantDigits == 0 && digit == 0)
continue;
if (++numSignificantDigits > maxSignificantDigits)
{
if (digit > 5)
++accumulator[decPointIndex];
else if (digit == 5 && (lastDigit & 1) != 0)
++accumulator[decPointIndex];
if (decPointIndex > 0)
exponentAdjustment[1]--;
else
exponentAdjustment[0]++;
while (text.isDigit())
{
++text;
if (decPointIndex == 0)
exponentAdjustment[0]++;
}
}
else
{
const auto maxAccumulatorValue = (double)((std::numeric_limits<unsigned int>::max() - 9) / 10);
if (accumulator[decPointIndex] > maxAccumulatorValue)
{
result[decPointIndex] = mulexp10(result[decPointIndex], exponentAccumulator[decPointIndex])
+ accumulator[decPointIndex];
accumulator[decPointIndex] = 0;
exponentAccumulator[decPointIndex] = 0;
}
accumulator[decPointIndex] = accumulator[decPointIndex] * 10 + digit;
exponentAccumulator[decPointIndex]++;
}
}
else if (decPointIndex == 0 && *text == '.')
{
++text;
decPointIndex = 1;
if (numSignificantDigits > maxSignificantDigits)
{
while (text.isDigit())
++text;
break;
}
}
else
{
break;
}
}
result[0] = mulexp10(result[0], exponentAccumulator[0]) + accumulator[0];
if (decPointIndex != 0)
result[1] = mulexp10(result[1], exponentAccumulator[1]) + accumulator[1];
c = *text;
if ((c == 'e' || c == 'E') && digitsFound)
{
auto negativeExponent = false;
switch (*++text)
{
case '-': negativeExponent = true; JUCE_FALLTHROUGH
case '+': ++text;
}
while (text.isDigit())
exponent = (exponent * 10) + ((int)text.getAndAdvance() - '0');
if (negativeExponent)
exponent = -exponent;
}
auto r = mulexp10(result[0], exponent + exponentAdjustment[0]);
if (decPointIndex != 0)
r += mulexp10(result[1], exponent - exponentAdjustment[1]);
return isNegative ? -r : r;
#else // ! JUCE_MINGW
int numSigFigs = 0, extraExponent = 0;
bool decimalPointFound = false, leadingZeros = false;
for (;;)
{
if (text.isDigit())
{
auto digit = (int)text.getAndAdvance() - '0';
if (decimalPointFound)
{
if (numSigFigs >= maxSignificantDigits)
continue;
}
else
{
if (numSigFigs >= maxSignificantDigits)
{
++extraExponent;
continue;
}
if (numSigFigs == 0 && digit == 0)
{
leadingZeros = true;
continue;
}
}
*writePtr++ = (char)('0' + (char)digit);
numSigFigs++;
}
else if ((!decimalPointFound) && *text == '.')
{
++text;
*writePtr++ = '.';
decimalPointFound = true;
}
else
{
break;
}
}
if ((!leadingZeros) && (numSigFigs == 0))
{
text = endOfWhitspace;
return 0.0;
}
auto writeExponentDigits = [](int exponent, char* destination)
{
auto exponentDivisor = 100;
while (exponentDivisor > 1)
{
auto digit = exponent / exponentDivisor;
*destination++ = (char)('0' + (char)digit);
exponent -= digit * exponentDivisor;
exponentDivisor /= 10;
}
*destination++ = (char)('0' + (char)exponent);
};
c = *text;
if (c == 'e' || c == 'E')
{
const auto startOfExponent = text;
*writePtr++ = 'e';
bool parsedExponentIsPositive = true;
switch (*++text)
{
case '-':
parsedExponentIsPositive = false;
JUCE_FALLTHROUGH
case '+':
++text;
break;
default:
break;
}
int exponent = 0;
const auto startOfExponentDigits = text;
while (text.isDigit())
{
auto digit = (int)text.getAndAdvance() - '0';
if (digit != 0 || exponent != 0)
exponent = (exponent * 10) + digit;
}
if (text == startOfExponentDigits)
text = startOfExponent;
exponent = extraExponent + (parsedExponentIsPositive ? exponent : -exponent);
if (exponent < 0)
{
if (exponent < std::numeric_limits<double>::min_exponent10 - 1)
return isNegative ? -0.0 : 0.0;
*writePtr++ = '-';
exponent = -exponent;
}
else if (exponent > std::numeric_limits<double>::max_exponent10 + 1)
{
return isNegative ? -inf : inf;
}
writeExponentDigits(exponent, writePtr);
}
else if (extraExponent > 0)
{
*writePtr++ = 'e';
writeExponentDigits(extraExponent, writePtr);
}
#if JUCE_WINDOWS
static _locale_t locale = _create_locale(LC_ALL, "C");
return _strtod_l(&buffer[0], nullptr, locale);
#else
static locale_t locale = newlocale(LC_ALL_MASK, "C", nullptr);
#if JUCE_ANDROID
return (double)strtold_l(&buffer[0], nullptr, locale);
#else
return strtod_l(&buffer[0], nullptr, locale);
#endif
#endif
#endif // JUCE_MINGW
}
/** Parses a character string, to read a floating-point value. */
template <typename CharPointerType>
static double getDoubleValue(CharPointerType text) noexcept
{
return readDoubleValue(text);
}
/** Parses a character string, to read an integer value. */
template <typename IntType, typename CharPointerType>
static IntType getIntValue(const CharPointerType text) noexcept
{
using UIntType = typename internal::make_unsigned<IntType>::type;
UIntType v = 0;
auto s = text.findEndOfWhitespace();
const bool isNeg = *s == '-';
if (isNeg)
++s;
for (;;)
{
auto c = s.getAndAdvance();
if (c >= '0' && c <= '9')
v = v * 10 + (UIntType)(c - '0');
else
break;
}
return isNeg ? -(IntType)v : (IntType)v;
}
/** Parses a character string, to read a hexadecimal value. */
template <typename ResultType>
struct HexParser
{
template <typename CharPointerType>
static ResultType parse(CharPointerType t) noexcept
{
ResultType result = 0;
while (!t.isEmpty())
{
auto hexValue = CharacterFunctions::getHexDigitValue(t.getAndAdvance());
if (hexValue >= 0)
result = (result << 4) | hexValue;
}
return result;
}
};
/** Counts the number of characters in a given string, stopping if the count exceeds
a specified limit. */
template <typename CharPointerType>
static size_t lengthUpTo(CharPointerType text, const size_t maxCharsToCount) noexcept
{
size_t len = 0;
while (len < maxCharsToCount && text.getAndAdvance() != 0)
++len;
return len;
}
/** Counts the number of characters in a given string, stopping if the count exceeds
a specified end-pointer. */
template <typename CharPointerType>
static size_t lengthUpTo(CharPointerType start, const CharPointerType end) noexcept
{
size_t len = 0;
while (start < end && start.getAndAdvance() != 0)
++len;
return len;
}
/** Copies null-terminated characters from one string to another. */
template <typename DestCharPointerType, typename SrcCharPointerType>
static void copyAll(DestCharPointerType& dest, SrcCharPointerType src) noexcept
{
while (auto c = src.getAndAdvance())
dest.write(c);
dest.writeNull();
}
/** Copies characters from one string to another, up to a null terminator
or a given byte size limit. */
template <typename DestCharPointerType, typename SrcCharPointerType>
static size_t copyWithDestByteLimit(DestCharPointerType& dest, SrcCharPointerType src, size_t maxBytesToWrite) noexcept
{
auto startAddress = dest.getAddress();
auto maxBytes = (ssize_t)maxBytesToWrite;
maxBytes -= (ssize_t)sizeof(typename DestCharPointerType::CharType); // (allow for a terminating null)
for (;;)
{
auto c = src.getAndAdvance();
auto bytesNeeded = (ssize_t)DestCharPointerType::getBytesRequiredFor(c);
maxBytes -= bytesNeeded;
if (c == 0 || maxBytes < 0)
break;
dest.write(c);
}
dest.writeNull();
return (size_t)getAddressDifference(dest.getAddress(), startAddress)
+ sizeof(typename DestCharPointerType::CharType);
}
/** Copies characters from one string to another, up to a null terminator
or a given maximum number of characters. */
template <typename DestCharPointerType, typename SrcCharPointerType>
static void copyWithCharLimit(DestCharPointerType& dest, SrcCharPointerType src, int maxChars) noexcept
{
while (--maxChars > 0)
{
auto c = src.getAndAdvance();
if (c == 0)
break;
dest.write(c);
}
dest.writeNull();
}
/** Compares two characters. */
static int compare(juce_wchar char1, juce_wchar char2) noexcept
{
if (auto diff = static_cast<int> (char1) - static_cast<int> (char2))
return diff < 0 ? -1 : 1;
return 0;
}
/** Compares two null-terminated character strings. */
template <typename CharPointerType1, typename CharPointerType2>
static int compare(CharPointerType1 s1, CharPointerType2 s2) noexcept
{
for (;;)
{
auto c1 = s1.getAndAdvance();
if (auto diff = compare(c1, s2.getAndAdvance()))
return diff;
if (c1 == 0)
break;
}
return 0;
}
/** Compares two null-terminated character strings, up to a given number of characters. */
template <typename CharPointerType1, typename CharPointerType2>
static int compareUpTo(CharPointerType1 s1, CharPointerType2 s2, int maxChars) noexcept
{
while (--maxChars >= 0)
{
auto c1 = s1.getAndAdvance();
if (auto diff = compare(c1, s2.getAndAdvance()))
return diff;
if (c1 == 0)
break;
}
return 0;
}
/** Compares two characters, using a case-independant match. */
static int compareIgnoreCase(juce_wchar char1, juce_wchar char2) noexcept
{
return char1 != char2 ? compare(toUpperCase(char1), toUpperCase(char2)) : 0;
}
/** Compares two null-terminated character strings, using a case-independant match. */
template <typename CharPointerType1, typename CharPointerType2>
static int compareIgnoreCase(CharPointerType1 s1, CharPointerType2 s2) noexcept
{
for (;;)
{
auto c1 = s1.getAndAdvance();
if (auto diff = compareIgnoreCase(c1, s2.getAndAdvance()))
return diff;
if (c1 == 0)
break;
}
return 0;
}
/** Compares two null-terminated character strings, using a case-independent match. */
template <typename CharPointerType1, typename CharPointerType2>
static int compareIgnoreCaseUpTo(CharPointerType1 s1, CharPointerType2 s2, int maxChars) noexcept
{
while (--maxChars >= 0)
{
auto c1 = s1.getAndAdvance();
if (auto diff = compareIgnoreCase(c1, s2.getAndAdvance()))
return diff;
if (c1 == 0)
break;
}
return 0;
}
/** Finds the character index of a given substring in another string.
Returns -1 if the substring is not found.
*/
template <typename CharPointerType1, typename CharPointerType2>
static int indexOf(CharPointerType1 textToSearch, const CharPointerType2 substringToLookFor) noexcept
{
int index = 0;
auto substringLength = (int)substringToLookFor.length();
for (;;)
{
if (textToSearch.compareUpTo(substringToLookFor, substringLength) == 0)
return index;
if (textToSearch.getAndAdvance() == 0)
return -1;
++index;
}
}
/** Returns a pointer to the first occurrence of a substring in a string.
If the substring is not found, this will return a pointer to the string's
null terminator.
*/
template <typename CharPointerType1, typename CharPointerType2>
static CharPointerType1 find(CharPointerType1 textToSearch, const CharPointerType2 substringToLookFor) noexcept
{
auto substringLength = (int)substringToLookFor.length();
while (textToSearch.compareUpTo(substringToLookFor, substringLength) != 0
&& !textToSearch.isEmpty())
++textToSearch;
return textToSearch;
}
/** Returns a pointer to the first occurrence of a substring in a string.
If the substring is not found, this will return a pointer to the string's
null terminator.
*/
template <typename CharPointerType>
static CharPointerType find(CharPointerType textToSearch, const juce_wchar charToLookFor) noexcept
{
for (;; ++textToSearch)
{
auto c = *textToSearch;
if (c == charToLookFor || c == 0)
break;
}
return textToSearch;
}
/** Finds the character index of a given substring in another string, using
a case-independent match.
Returns -1 if the substring is not found.
*/
template <typename CharPointerType1, typename CharPointerType2>
static int indexOfIgnoreCase(CharPointerType1 haystack, const CharPointerType2 needle) noexcept
{
int index = 0;
auto needleLength = (int)needle.length();
for (;;)
{
if (haystack.compareIgnoreCaseUpTo(needle, needleLength) == 0)
return index;
if (haystack.getAndAdvance() == 0)
return -1;
++index;
}
}
/** Finds the character index of a given character in another string.
Returns -1 if the character is not found.
*/
template <typename Type>
static int indexOfChar(Type text, const juce_wchar charToFind) noexcept
{
int i = 0;
while (!text.isEmpty())
{
if (text.getAndAdvance() == charToFind)
return i;
++i;
}
return -1;
}
/** Finds the character index of a given character in another string, using
a case-independent match.
Returns -1 if the character is not found.
*/
template <typename Type>
static int indexOfCharIgnoreCase(Type text, juce_wchar charToFind) noexcept
{
charToFind = CharacterFunctions::toLowerCase(charToFind);
int i = 0;
while (!text.isEmpty())
{
if (text.toLowerCase() == charToFind)
return i;
++text;
++i;
}
return -1;
}
/** Increments a pointer until it points to the first non-whitespace character
in a string.
If the string contains only whitespace, the pointer will point to the
string's null terminator.
*/
template <typename Type>
static void incrementToEndOfWhitespace(Type& text) noexcept
{
while (text.isWhitespace())
++text;
}
/** Returns a pointer to the first non-whitespace character in a string.
If the string contains only whitespace, this will return a pointer
to its null terminator.
*/
template <typename Type>
static Type findEndOfWhitespace(Type text) noexcept
{
incrementToEndOfWhitespace(text);
return text;
}
/** Returns a pointer to the first character in the string which is found in
the breakCharacters string.
*/
template <typename Type, typename BreakType>
static Type findEndOfToken(Type text, BreakType breakCharacters, Type quoteCharacters)
{
juce_wchar currentQuoteChar = 0;
while (!text.isEmpty())
{
auto c = text.getAndAdvance();
if (currentQuoteChar == 0 && breakCharacters.indexOf(c) >= 0)
{
--text;
break;
}
if (quoteCharacters.indexOf(c) >= 0)
{
if (currentQuoteChar == 0)
currentQuoteChar = c;
else if (currentQuoteChar == c)
currentQuoteChar = 0;
}
}
return text;
}
private:
static double mulexp10(double value, int exponent) noexcept;
};
} // namespace juce
/*** End of inlined file: juce_CharacterFunctions.h ***/
JUCE_BEGIN_IGNORE_WARNINGS_MSVC(4514 4996)
/*** Start of inlined file: juce_CharPointer_UTF8.h ***/
namespace juce
{
/**
Wraps a pointer to a null-terminated UTF-8 character string, and provides
various methods to operate on the data.
@see CharPointer_UTF16, CharPointer_UTF32
@tags{Core}
*/
class CharPointer_UTF8 final
{
public:
using CharType = char;
explicit CharPointer_UTF8(const CharType* rawPointer) noexcept
: data(const_cast<CharType*> (rawPointer))
{
}
CharPointer_UTF8(const CharPointer_UTF8& other) = default;
CharPointer_UTF8 operator= (CharPointer_UTF8 other) noexcept
{
data = other.data;
return *this;
}
CharPointer_UTF8 operator= (const CharType* text) noexcept
{
data = const_cast<CharType*> (text);
return *this;
}
/** This is a pointer comparison, it doesn't compare the actual text. */
bool operator== (CharPointer_UTF8 other) const noexcept { return data == other.data; }
bool operator!= (CharPointer_UTF8 other) const noexcept { return data != other.data; }
bool operator<= (CharPointer_UTF8 other) const noexcept { return data <= other.data; }
bool operator< (CharPointer_UTF8 other) const noexcept { return data < other.data; }
bool operator>= (CharPointer_UTF8 other) const noexcept { return data >= other.data; }
bool operator> (CharPointer_UTF8 other) const noexcept { return data > other.data; }
/** Returns the address that this pointer is pointing to. */
CharType* getAddress() const noexcept { return data; }
/** Returns the address that this pointer is pointing to. */
operator const CharType* () const noexcept { return data; }
/** Returns true if this pointer is pointing to a null character. */
bool isEmpty() const noexcept { return *data == 0; }
/** Returns true if this pointer is not pointing to a null character. */
bool isNotEmpty() const noexcept { return *data != 0; }
/** Returns the unicode character that this pointer is pointing to. */
juce_wchar operator*() const noexcept
{
auto byte = (signed char)*data;
if (byte >= 0)
return (juce_wchar)(uint8)byte;
uint32 n = (uint32)(uint8)byte;
uint32 mask = 0x7f;
uint32 bit = 0x40;
int numExtraValues = 0;
while ((n & bit) != 0 && bit > 0x8)
{
mask >>= 1;
++numExtraValues;
bit >>= 1;
}
n &= mask;
for (int i = 1; i <= numExtraValues; ++i)
{
auto nextByte = (uint32)(uint8)data[i];
if ((nextByte & 0xc0) != 0x80)
break;
n <<= 6;
n |= (nextByte & 0x3f);
}
return (juce_wchar)n;
}
/** Moves this pointer along to the next character in the string. */
CharPointer_UTF8& operator++() noexcept
{
jassert(*data != 0); // trying to advance past the end of the string?
auto n = (signed char)*data++;
if (n < 0)
{
uint8 bit = 0x40;
while ((static_cast<uint8> (n) & bit) != 0 && bit > 0x8)
{
++data;
bit = static_cast<uint8> (bit >> 1);
}
}
return *this;
}
/** Moves this pointer back to the previous character in the string. */
CharPointer_UTF8 operator--() noexcept
{
int count = 0;
while ((*--data & 0xc0) == 0x80 && ++count < 4)
{
}
return *this;
}
/** Returns the character that this pointer is currently pointing to, and then
advances the pointer to point to the next character. */
juce_wchar getAndAdvance() noexcept
{
auto byte = (signed char)*data++;
if (byte >= 0)
return (juce_wchar)(uint8)byte;
uint32 n = (uint32)(uint8)byte;
uint32 mask = 0x7f;
uint32 bit = 0x40;
int numExtraValues = 0;
while ((n & bit) != 0 && bit > 0x8)
{
mask >>= 1;
++numExtraValues;
bit >>= 1;
}
n &= mask;
while (--numExtraValues >= 0)
{
auto nextByte = (uint32)(uint8)*data;
if ((nextByte & 0xc0) != 0x80)
break;
++data;
n <<= 6;
n |= (nextByte & 0x3f);
}
return (juce_wchar)n;
}
/** Moves this pointer along to the next character in the string. */
CharPointer_UTF8 operator++ (int) noexcept
{
CharPointer_UTF8 temp(*this);
++* this;
return temp;
}
/** Moves this pointer forwards by the specified number of characters. */
void operator+= (int numToSkip) noexcept
{
if (numToSkip < 0)
{
while (++numToSkip <= 0)
--* this;
}
else
{
while (--numToSkip >= 0)
++* this;
}
}
/** Moves this pointer backwards by the specified number of characters. */
void operator-= (int numToSkip) noexcept
{
operator+= (-numToSkip);
}
/** Returns the character at a given character index from the start of the string. */
juce_wchar operator[] (int characterIndex) const noexcept
{
auto p(*this);
p += characterIndex;
return *p;
}
/** Returns a pointer which is moved forwards from this one by the specified number of characters. */
CharPointer_UTF8 operator+ (int numToSkip) const noexcept
{
auto p(*this);
p += numToSkip;
return p;
}
/** Returns a pointer which is moved backwards from this one by the specified number of characters. */
CharPointer_UTF8 operator- (int numToSkip) const noexcept
{
auto p(*this);
p += -numToSkip;
return p;
}
/** Returns the number of characters in this string. */
size_t length() const noexcept
{
auto* d = data;
size_t count = 0;
for (;;)
{
auto n = (uint32)(uint8)*d++;
if ((n & 0x80) != 0)
{
while ((*d & 0xc0) == 0x80)
++d;
}
else if (n == 0)
break;
++count;
}
return count;
}
/** Returns the number of characters in this string, or the given value, whichever is lower. */
size_t lengthUpTo(const size_t maxCharsToCount) const noexcept
{
return CharacterFunctions::lengthUpTo(*this, maxCharsToCount);
}
/** Returns the number of characters in this string, or up to the given end pointer, whichever is lower. */
size_t lengthUpTo(const CharPointer_UTF8 end) const noexcept
{
return CharacterFunctions::lengthUpTo(*this, end);
}
/** Returns the number of bytes that are used to represent this string.
This includes the terminating null character.
*/
size_t sizeInBytes() const noexcept
{
jassert(data != nullptr);
return strlen(data) + 1;
}
/** Returns the number of bytes that would be needed to represent the given
unicode character in this encoding format.
*/
static size_t getBytesRequiredFor(const juce_wchar charToWrite) noexcept
{
size_t num = 1;
auto c = (uint32)charToWrite;
if (c >= 0x80)
{
++num;
if (c >= 0x800)
{
++num;
if (c >= 0x10000)
++num;
}
}
return num;
}
/** Returns the number of bytes that would be needed to represent the given
string in this encoding format.
The value returned does NOT include the terminating null character.
*/
template <class CharPointer>
static size_t getBytesRequiredFor(CharPointer text) noexcept
{
size_t count = 0;
while (auto n = text.getAndAdvance())
count += getBytesRequiredFor(n);
return count;
}
/** Returns a pointer to the null character that terminates this string. */
CharPointer_UTF8 findTerminatingNull() const noexcept
{
return CharPointer_UTF8(data + strlen(data));
}
/** Writes a unicode character to this string, and advances this pointer to point to the next position. */
void write(const juce_wchar charToWrite) noexcept
{
auto c = (uint32)charToWrite;
if (c >= 0x80)
{
int numExtraBytes = 1;
if (c >= 0x800)
{
++numExtraBytes;
if (c >= 0x10000)
++numExtraBytes;
}
*data++ = (CharType)((uint32)(0xff << (7 - numExtraBytes)) | (c >> (numExtraBytes * 6)));
while (--numExtraBytes >= 0)
*data++ = (CharType)(0x80 | (0x3f & (c >> (numExtraBytes * 6))));
}
else
{
*data++ = (CharType)c;
}
}
/** Writes a null character to this string (leaving the pointer's position unchanged). */
void writeNull() const noexcept
{
*data = 0;
}
/** Copies a source string to this pointer, advancing this pointer as it goes. */
template <typename CharPointer>
void writeAll(const CharPointer src) noexcept
{
CharacterFunctions::copyAll(*this, src);
}
/** Copies a source string to this pointer, advancing this pointer as it goes. */
void writeAll(const CharPointer_UTF8 src) noexcept
{
auto* s = src.data;
while ((*data = *s) != 0)
{
++data;
++s;
}
}
/** Copies a source string to this pointer, advancing this pointer as it goes.
The maxDestBytes parameter specifies the maximum number of bytes that can be written
to the destination buffer before stopping.
*/
template <typename CharPointer>
size_t writeWithDestByteLimit(const CharPointer src, const size_t maxDestBytes) noexcept
{
return CharacterFunctions::copyWithDestByteLimit(*this, src, maxDestBytes);
}
/** Copies a source string to this pointer, advancing this pointer as it goes.
The maxChars parameter specifies the maximum number of characters that can be
written to the destination buffer before stopping (including the terminating null).
*/
template <typename CharPointer>
void writeWithCharLimit(const CharPointer src, const int maxChars) noexcept
{
CharacterFunctions::copyWithCharLimit(*this, src, maxChars);
}
/** Compares this string with another one. */
template <typename CharPointer>
int compare(const CharPointer other) const noexcept
{
return CharacterFunctions::compare(*this, other);
}
/** Compares this string with another one, up to a specified number of characters. */
template <typename CharPointer>
int compareUpTo(const CharPointer other, const int maxChars) const noexcept
{
return CharacterFunctions::compareUpTo(*this, other, maxChars);
}
/** Compares this string with another one. */
template <typename CharPointer>
int compareIgnoreCase(const CharPointer other) const noexcept
{
return CharacterFunctions::compareIgnoreCase(*this, other);
}
/** Compares this string with another one. */
int compareIgnoreCase(const CharPointer_UTF8 other) const noexcept
{
return CharacterFunctions::compareIgnoreCase(*this, other);
}
/** Compares this string with another one, up to a specified number of characters. */
template <typename CharPointer>
int compareIgnoreCaseUpTo(const CharPointer other, const int maxChars) const noexcept
{
return CharacterFunctions::compareIgnoreCaseUpTo(*this, other, maxChars);
}
/** Returns the character index of a substring, or -1 if it isn't found. */
template <typename CharPointer>
int indexOf(const CharPointer stringToFind) const noexcept
{
return CharacterFunctions::indexOf(*this, stringToFind);
}
/** Returns the character index of a unicode character, or -1 if it isn't found. */
int indexOf(const juce_wchar charToFind) const noexcept
{
return CharacterFunctions::indexOfChar(*this, charToFind);
}
/** Returns the character index of a unicode character, or -1 if it isn't found. */
int indexOf(const juce_wchar charToFind, const bool ignoreCase) const noexcept
{
return ignoreCase ? CharacterFunctions::indexOfCharIgnoreCase(*this, charToFind)
: CharacterFunctions::indexOfChar(*this, charToFind);
}
/** Returns true if the first character of this string is whitespace. */
bool isWhitespace() const noexcept { const CharType c = *data; return c == ' ' || (c <= 13 && c >= 9); }
/** Returns true if the first character of this string is a digit. */
bool isDigit() const noexcept { const CharType c = *data; return c >= '0' && c <= '9'; }
/** Returns true if the first character of this string is a letter. */
bool isLetter() const noexcept { return CharacterFunctions::isLetter(operator*()) != 0; }
/** Returns true if the first character of this string is a letter or digit. */
bool isLetterOrDigit() const noexcept { return CharacterFunctions::isLetterOrDigit(operator*()) != 0; }
/** Returns true if the first character of this string is upper-case. */
bool isUpperCase() const noexcept { return CharacterFunctions::isUpperCase(operator*()) != 0; }
/** Returns true if the first character of this string is lower-case. */
bool isLowerCase() const noexcept { return CharacterFunctions::isLowerCase(operator*()) != 0; }
/** Returns an upper-case version of the first character of this string. */
juce_wchar toUpperCase() const noexcept { return CharacterFunctions::toUpperCase(operator*()); }
/** Returns a lower-case version of the first character of this string. */
juce_wchar toLowerCase() const noexcept { return CharacterFunctions::toLowerCase(operator*()); }
/** Parses this string as a 32-bit integer. */
int getIntValue32() const noexcept { return atoi(data); }
/** Parses this string as a 64-bit integer. */
int64 getIntValue64() const noexcept
{
#if JUCE_WINDOWS && ! JUCE_MINGW
return _atoi64(data);
#else
return atoll(data);
#endif
}
/** Parses this string as a floating point double. */
double getDoubleValue() const noexcept { return CharacterFunctions::getDoubleValue(*this); }
/** Returns the first non-whitespace character in the string. */
CharPointer_UTF8 findEndOfWhitespace() const noexcept { return CharacterFunctions::findEndOfWhitespace(*this); }
/** Move this pointer to the first non-whitespace character in the string. */
void incrementToEndOfWhitespace() noexcept { CharacterFunctions::incrementToEndOfWhitespace(*this); }
/** Returns true if the given unicode character can be represented in this encoding. */
static bool canRepresent(juce_wchar character) noexcept
{
return ((uint32)character) < (uint32)0x10ffff;
}
/** Returns true if this data contains a valid string in this encoding. */
static bool isValidString(const CharType* dataToTest, int maxBytesToRead)
{
while (--maxBytesToRead >= 0 && *dataToTest != 0)
{
auto byte = (signed char)*dataToTest++;
if (byte < 0)
{
int bit = 0x40;
int numExtraValues = 0;
while ((byte & bit) != 0)
{
if (bit < 8)
return false;
++numExtraValues;
bit >>= 1;
if (bit == 8 && (numExtraValues > maxBytesToRead
|| *CharPointer_UTF8(dataToTest - 1) > 0x10ffff))
return false;
}
if (numExtraValues == 0)
return false;
maxBytesToRead -= numExtraValues;
if (maxBytesToRead < 0)
return false;
while (--numExtraValues >= 0)
if ((*dataToTest++ & 0xc0) != 0x80)
return false;
}
}
return true;
}
/** Atomically swaps this pointer for a new value, returning the previous value. */
CharPointer_UTF8 atomicSwap(const CharPointer_UTF8 newValue)
{
return CharPointer_UTF8(reinterpret_cast<Atomic<CharType*>&> (data).exchange(newValue.data));
}
/** These values are the byte-order mark (BOM) values for a UTF-8 stream. */
enum
{
byteOrderMark1 = 0xef,
byteOrderMark2 = 0xbb,
byteOrderMark3 = 0xbf
};
/** Returns true if the first three bytes in this pointer are the UTF8 byte-order mark (BOM).
The pointer must not be null, and must point to at least 3 valid bytes.
*/
static bool isByteOrderMark(const void* possibleByteOrder) noexcept
{
jassert(possibleByteOrder != nullptr);
auto c = static_cast<const uint8*> (possibleByteOrder);
return c[0] == (uint8)byteOrderMark1
&& c[1] == (uint8)byteOrderMark2
&& c[2] == (uint8)byteOrderMark3;
}
private:
CharType* data;
};
} // namespace juce
/*** End of inlined file: juce_CharPointer_UTF8.h ***/
/*** Start of inlined file: juce_CharPointer_UTF16.h ***/
namespace juce
{
/**
Wraps a pointer to a null-terminated UTF-16 character string, and provides
various methods to operate on the data.
@see CharPointer_UTF8, CharPointer_UTF32
@tags{Core}
*/
class CharPointer_UTF16 final
{
public:
#if JUCE_NATIVE_WCHAR_IS_UTF16
using CharType = wchar_t;
#else
using CharType = int16;
#endif
inline explicit CharPointer_UTF16(const CharType* rawPointer) noexcept
: data(const_cast<CharType*> (rawPointer))
{
}
inline CharPointer_UTF16(const CharPointer_UTF16& other) = default;
inline CharPointer_UTF16 operator= (CharPointer_UTF16 other) noexcept
{
data = other.data;
return *this;
}
inline CharPointer_UTF16 operator= (const CharType* text) noexcept
{
data = const_cast<CharType*> (text);
return *this;
}
/** This is a pointer comparison, it doesn't compare the actual text. */
inline bool operator== (CharPointer_UTF16 other) const noexcept { return data == other.data; }
inline bool operator!= (CharPointer_UTF16 other) const noexcept { return data != other.data; }
inline bool operator<= (CharPointer_UTF16 other) const noexcept { return data <= other.data; }
inline bool operator< (CharPointer_UTF16 other) const noexcept { return data < other.data; }
inline bool operator>= (CharPointer_UTF16 other) const noexcept { return data >= other.data; }
inline bool operator> (CharPointer_UTF16 other) const noexcept { return data > other.data; }
/** Returns the address that this pointer is pointing to. */
inline CharType* getAddress() const noexcept { return data; }
/** Returns the address that this pointer is pointing to. */
inline operator const CharType* () const noexcept { return data; }
/** Returns true if this pointer is pointing to a null character. */
inline bool isEmpty() const noexcept { return *data == 0; }
/** Returns true if this pointer is not pointing to a null character. */
inline bool isNotEmpty() const noexcept { return *data != 0; }
/** Returns the unicode character that this pointer is pointing to. */
juce_wchar operator*() const noexcept
{
auto n = (uint32)(uint16)*data;
if (n >= 0xd800 && n <= 0xdfff && ((uint32)(uint16)data[1]) >= 0xdc00)
n = 0x10000 + (((n - 0xd800) << 10) | (((uint32)(uint16)data[1]) - 0xdc00));
return (juce_wchar)n;
}
/** Moves this pointer along to the next character in the string. */
CharPointer_UTF16 operator++() noexcept
{
auto n = (uint32)(uint16)*data++;
if (n >= 0xd800 && n <= 0xdfff && ((uint32)(uint16)*data) >= 0xdc00)
++data;
return *this;
}
/** Moves this pointer back to the previous character in the string. */
CharPointer_UTF16 operator--() noexcept
{
auto n = (uint32)(uint16)(*--data);
if (n >= 0xdc00 && n <= 0xdfff)
--data;
return *this;
}
/** Returns the character that this pointer is currently pointing to, and then
advances the pointer to point to the next character. */
juce_wchar getAndAdvance() noexcept
{
auto n = (uint32)(uint16)*data++;
if (n >= 0xd800 && n <= 0xdfff && ((uint32)(uint16)*data) >= 0xdc00)
n = 0x10000 + ((((n - 0xd800) << 10) | (((uint32)(uint16)*data++) - 0xdc00)));
return (juce_wchar)n;
}
/** Moves this pointer along to the next character in the string. */
CharPointer_UTF16 operator++ (int) noexcept
{
auto temp(*this);
++* this;
return temp;
}
/** Moves this pointer forwards by the specified number of characters. */
void operator+= (int numToSkip) noexcept
{
if (numToSkip < 0)
{
while (++numToSkip <= 0)
--* this;
}
else
{
while (--numToSkip >= 0)
++* this;
}
}
/** Moves this pointer backwards by the specified number of characters. */
void operator-= (int numToSkip) noexcept
{
operator+= (-numToSkip);
}
/** Returns the character at a given character index from the start of the string. */
juce_wchar operator[] (int characterIndex) const noexcept
{
auto p(*this);
p += characterIndex;
return *p;
}
/** Returns a pointer which is moved forwards from this one by the specified number of characters. */
CharPointer_UTF16 operator+ (int numToSkip) const noexcept
{
auto p(*this);
p += numToSkip;
return p;
}
/** Returns a pointer which is moved backwards from this one by the specified number of characters. */
CharPointer_UTF16 operator- (int numToSkip) const noexcept
{
auto p(*this);
p += -numToSkip;
return p;
}
/** Writes a unicode character to this string, and advances this pointer to point to the next position. */
void write(juce_wchar charToWrite) noexcept
{
if (charToWrite >= 0x10000)
{
charToWrite -= 0x10000;
*data++ = (CharType)(0xd800 + (charToWrite >> 10));
*data++ = (CharType)(0xdc00 + (charToWrite & 0x3ff));
}
else
{
*data++ = (CharType)charToWrite;
}
}
/** Writes a null character to this string (leaving the pointer's position unchanged). */
inline void writeNull() const noexcept
{
*data = 0;
}
/** Returns the number of characters in this string. */
size_t length() const noexcept
{
auto* d = data;
size_t count = 0;
for (;;)
{
auto n = (uint32)(uint16)*d++;
if (n >= 0xd800 && n <= 0xdfff)
{
if (*d++ == 0)
break;
}
else if (n == 0)
break;
++count;
}
return count;
}
/** Returns the number of characters in this string, or the given value, whichever is lower. */
size_t lengthUpTo(size_t maxCharsToCount) const noexcept
{
return CharacterFunctions::lengthUpTo(*this, maxCharsToCount);
}
/** Returns the number of characters in this string, or up to the given end pointer, whichever is lower. */
size_t lengthUpTo(CharPointer_UTF16 end) const noexcept
{
return CharacterFunctions::lengthUpTo(*this, end);
}
/** Returns the number of bytes that are used to represent this string.
This includes the terminating null character.
*/
size_t sizeInBytes() const noexcept
{
return sizeof(CharType) * (findNullIndex(data) + 1);
}
/** Returns the number of bytes that would be needed to represent the given
unicode character in this encoding format.
*/
static size_t getBytesRequiredFor(juce_wchar charToWrite) noexcept
{
return (charToWrite >= 0x10000) ? (sizeof(CharType) * 2) : sizeof(CharType);
}
/** Returns the number of bytes that would be needed to represent the given
string in this encoding format.
The value returned does NOT include the terminating null character.
*/
template <class CharPointer>
static size_t getBytesRequiredFor(CharPointer text) noexcept
{
size_t count = 0;
juce_wchar n;
while ((n = text.getAndAdvance()) != 0)
count += getBytesRequiredFor(n);
return count;
}
/** Returns a pointer to the null character that terminates this string. */
CharPointer_UTF16 findTerminatingNull() const noexcept
{
auto* t = data;
while (*t != 0)
++t;
return CharPointer_UTF16(t);
}
/** Copies a source string to this pointer, advancing this pointer as it goes. */
template <typename CharPointer>
void writeAll(CharPointer src) noexcept
{
CharacterFunctions::copyAll(*this, src);
}
/** Copies a source string to this pointer, advancing this pointer as it goes. */
void writeAll(CharPointer_UTF16 src) noexcept
{
auto* s = src.data;
while ((*data = *s) != 0)
{
++data;
++s;
}
}
/** Copies a source string to this pointer, advancing this pointer as it goes.
The maxDestBytes parameter specifies the maximum number of bytes that can be written
to the destination buffer before stopping.
*/
template <typename CharPointer>
size_t writeWithDestByteLimit(CharPointer src, size_t maxDestBytes) noexcept
{
return CharacterFunctions::copyWithDestByteLimit(*this, src, maxDestBytes);
}
/** Copies a source string to this pointer, advancing this pointer as it goes.
The maxChars parameter specifies the maximum number of characters that can be
written to the destination buffer before stopping (including the terminating null).
*/
template <typename CharPointer>
void writeWithCharLimit(CharPointer src, int maxChars) noexcept
{
CharacterFunctions::copyWithCharLimit(*this, src, maxChars);
}
/** Compares this string with another one. */
template <typename CharPointer>
int compare(CharPointer other) const noexcept
{
return CharacterFunctions::compare(*this, other);
}
/** Compares this string with another one, up to a specified number of characters. */
template <typename CharPointer>
int compareUpTo(CharPointer other, int maxChars) const noexcept
{
return CharacterFunctions::compareUpTo(*this, other, maxChars);
}
/** Compares this string with another one. */
template <typename CharPointer>
int compareIgnoreCase(CharPointer other) const noexcept
{
return CharacterFunctions::compareIgnoreCase(*this, other);
}
/** Compares this string with another one, up to a specified number of characters. */
template <typename CharPointer>
int compareIgnoreCaseUpTo(CharPointer other, int maxChars) const noexcept
{
return CharacterFunctions::compareIgnoreCaseUpTo(*this, other, maxChars);
}
#if JUCE_MSVC && ! DOXYGEN
int compareIgnoreCase(CharPointer_UTF16 other) const noexcept
{
return _wcsicmp(data, other.data);
}
int compareIgnoreCaseUpTo(CharPointer_UTF16 other, int maxChars) const noexcept
{
return _wcsnicmp(data, other.data, (size_t)maxChars);
}
int indexOf(CharPointer_UTF16 stringToFind) const noexcept
{
const CharType* const t = wcsstr(data, stringToFind.getAddress());
return t == nullptr ? -1 : (int)(t - data);
}
#endif
/** Returns the character index of a substring, or -1 if it isn't found. */
template <typename CharPointer>
int indexOf(CharPointer stringToFind) const noexcept
{
return CharacterFunctions::indexOf(*this, stringToFind);
}
/** Returns the character index of a unicode character, or -1 if it isn't found. */
int indexOf(juce_wchar charToFind) const noexcept
{
return CharacterFunctions::indexOfChar(*this, charToFind);
}
/** Returns the character index of a unicode character, or -1 if it isn't found. */
int indexOf(juce_wchar charToFind, bool ignoreCase) const noexcept
{
return ignoreCase ? CharacterFunctions::indexOfCharIgnoreCase(*this, charToFind)
: CharacterFunctions::indexOfChar(*this, charToFind);
}
/** Returns true if the first character of this string is whitespace. */
bool isWhitespace() const noexcept { return CharacterFunctions::isWhitespace(operator*()) != 0; }
/** Returns true if the first character of this string is a digit. */
bool isDigit() const noexcept { return CharacterFunctions::isDigit(operator*()) != 0; }
/** Returns true if the first character of this string is a letter. */
bool isLetter() const noexcept { return CharacterFunctions::isLetter(operator*()) != 0; }
/** Returns true if the first character of this string is a letter or digit. */
bool isLetterOrDigit() const noexcept { return CharacterFunctions::isLetterOrDigit(operator*()) != 0; }
/** Returns true if the first character of this string is upper-case. */
bool isUpperCase() const noexcept { return CharacterFunctions::isUpperCase(operator*()) != 0; }
/** Returns true if the first character of this string is lower-case. */
bool isLowerCase() const noexcept { return CharacterFunctions::isLowerCase(operator*()) != 0; }
/** Returns an upper-case version of the first character of this string. */
juce_wchar toUpperCase() const noexcept { return CharacterFunctions::toUpperCase(operator*()); }
/** Returns a lower-case version of the first character of this string. */
juce_wchar toLowerCase() const noexcept { return CharacterFunctions::toLowerCase(operator*()); }
/** Parses this string as a 32-bit integer. */
int getIntValue32() const noexcept
{
#if JUCE_MSVC
return _wtoi(data);
#else
return CharacterFunctions::getIntValue<int, CharPointer_UTF16>(*this);
#endif
}
/** Parses this string as a 64-bit integer. */
int64 getIntValue64() const noexcept
{
#if JUCE_MSVC
return _wtoi64(data);
#else
return CharacterFunctions::getIntValue<int64, CharPointer_UTF16>(*this);
#endif
}
/** Parses this string as a floating point double. */
double getDoubleValue() const noexcept { return CharacterFunctions::getDoubleValue(*this); }
/** Returns the first non-whitespace character in the string. */
CharPointer_UTF16 findEndOfWhitespace() const noexcept { return CharacterFunctions::findEndOfWhitespace(*this); }
/** Move this pointer to the first non-whitespace character in the string. */
void incrementToEndOfWhitespace() noexcept { CharacterFunctions::incrementToEndOfWhitespace(*this); }
/** Returns true if the given unicode character can be represented in this encoding. */
static bool canRepresent(juce_wchar character) noexcept
{
auto n = (uint32)character;
return n < 0x10ffff && (n < 0xd800 || n > 0xdfff);
}
/** Returns true if this data contains a valid string in this encoding. */
static bool isValidString(const CharType* dataToTest, int maxBytesToRead)
{
maxBytesToRead /= (int)sizeof(CharType);
while (--maxBytesToRead >= 0 && *dataToTest != 0)
{
auto n = (uint32)(uint16)*dataToTest++;
if (n >= 0xd800)
{
if (n > 0x10ffff)
return false;
if (n <= 0xdfff)
{
if (n > 0xdc00)
return false;
auto nextChar = (uint32)(uint16)*dataToTest++;
if (nextChar < 0xdc00 || nextChar > 0xdfff)
return false;
}
}
}
return true;
}
/** Atomically swaps this pointer for a new value, returning the previous value. */
CharPointer_UTF16 atomicSwap(CharPointer_UTF16 newValue)
{
return CharPointer_UTF16(reinterpret_cast<Atomic<CharType*>&> (data).exchange(newValue.data));
}
/** These values are the byte-order-mark (BOM) values for a UTF-16 stream. */
enum
{
byteOrderMarkBE1 = 0xfe,
byteOrderMarkBE2 = 0xff,
byteOrderMarkLE1 = 0xff,
byteOrderMarkLE2 = 0xfe
};
/** Returns true if the first pair of bytes in this pointer are the UTF16 byte-order mark (big endian).
The pointer must not be null, and must contain at least two valid bytes.
*/
static bool isByteOrderMarkBigEndian(const void* possibleByteOrder) noexcept
{
jassert(possibleByteOrder != nullptr);
auto c = static_cast<const uint8*> (possibleByteOrder);
return c[0] == (uint8)byteOrderMarkBE1
&& c[1] == (uint8)byteOrderMarkBE2;
}
/** Returns true if the first pair of bytes in this pointer are the UTF16 byte-order mark (little endian).
The pointer must not be null, and must contain at least two valid bytes.
*/
static bool isByteOrderMarkLittleEndian(const void* possibleByteOrder) noexcept
{
jassert(possibleByteOrder != nullptr);
auto c = static_cast<const uint8*> (possibleByteOrder);
return c[0] == (uint8)byteOrderMarkLE1
&& c[1] == (uint8)byteOrderMarkLE2;
}
private:
CharType* data;
static unsigned int findNullIndex(const CharType* t) noexcept
{
unsigned int n = 0;
while (t[n] != 0)
++n;
return n;
}
};
} // namespace juce
/*** End of inlined file: juce_CharPointer_UTF16.h ***/
/*** Start of inlined file: juce_CharPointer_UTF32.h ***/
namespace juce
{
/**
Wraps a pointer to a null-terminated UTF-32 character string, and provides
various methods to operate on the data.
@see CharPointer_UTF8, CharPointer_UTF16
@tags{Core}
*/
class CharPointer_UTF32 final
{
public:
using CharType = juce_wchar;
inline explicit CharPointer_UTF32(const CharType* rawPointer) noexcept
: data(const_cast<CharType*> (rawPointer))
{
}
inline CharPointer_UTF32(const CharPointer_UTF32& other) = default;
inline CharPointer_UTF32 operator= (CharPointer_UTF32 other) noexcept
{
data = other.data;
return *this;
}
inline CharPointer_UTF32 operator= (const CharType* text) noexcept
{
data = const_cast<CharType*> (text);
return *this;
}
/** This is a pointer comparison, it doesn't compare the actual text. */
inline bool operator== (CharPointer_UTF32 other) const noexcept { return data == other.data; }
inline bool operator!= (CharPointer_UTF32 other) const noexcept { return data != other.data; }
inline bool operator<= (CharPointer_UTF32 other) const noexcept { return data <= other.data; }
inline bool operator< (CharPointer_UTF32 other) const noexcept { return data < other.data; }
inline bool operator>= (CharPointer_UTF32 other) const noexcept { return data >= other.data; }
inline bool operator> (CharPointer_UTF32 other) const noexcept { return data > other.data; }
/** Returns the address that this pointer is pointing to. */
inline CharType* getAddress() const noexcept { return data; }
/** Returns the address that this pointer is pointing to. */
inline operator const CharType* () const noexcept { return data; }
/** Returns true if this pointer is pointing to a null character. */
inline bool isEmpty() const noexcept { return *data == 0; }
/** Returns true if this pointer is not pointing to a null character. */
inline bool isNotEmpty() const noexcept { return *data != 0; }
/** Returns the unicode character that this pointer is pointing to. */
inline juce_wchar operator*() const noexcept { return *data; }
/** Moves this pointer along to the next character in the string. */
inline CharPointer_UTF32 operator++() noexcept
{
++data;
return *this;
}
/** Moves this pointer to the previous character in the string. */
inline CharPointer_UTF32 operator--() noexcept
{
--data;
return *this;
}
/** Returns the character that this pointer is currently pointing to, and then
advances the pointer to point to the next character. */
inline juce_wchar getAndAdvance() noexcept { return *data++; }
/** Moves this pointer along to the next character in the string. */
CharPointer_UTF32 operator++ (int) noexcept
{
auto temp(*this);
++data;
return temp;
}
/** Moves this pointer forwards by the specified number of characters. */
inline void operator+= (int numToSkip) noexcept
{
data += numToSkip;
}
inline void operator-= (int numToSkip) noexcept
{
data -= numToSkip;
}
/** Returns the character at a given character index from the start of the string. */
inline juce_wchar& operator[] (int characterIndex) const noexcept
{
return data[characterIndex];
}
/** Returns a pointer which is moved forwards from this one by the specified number of characters. */
CharPointer_UTF32 operator+ (int numToSkip) const noexcept
{
return CharPointer_UTF32(data + numToSkip);
}
/** Returns a pointer which is moved backwards from this one by the specified number of characters. */
CharPointer_UTF32 operator- (int numToSkip) const noexcept
{
return CharPointer_UTF32(data - numToSkip);
}
/** Writes a unicode character to this string, and advances this pointer to point to the next position. */
inline void write(juce_wchar charToWrite) noexcept
{
*data++ = charToWrite;
}
inline void replaceChar(juce_wchar newChar) noexcept
{
*data = newChar;
}
/** Writes a null character to this string (leaving the pointer's position unchanged). */
inline void writeNull() const noexcept
{
*data = 0;
}
/** Returns the number of characters in this string. */
size_t length() const noexcept
{
#if JUCE_NATIVE_WCHAR_IS_UTF32 && ! JUCE_ANDROID
return wcslen(data);
#else
size_t n = 0;
while (data[n] != 0)
++n;
return n;
#endif
}
/** Returns the number of characters in this string, or the given value, whichever is lower. */
size_t lengthUpTo(size_t maxCharsToCount) const noexcept
{
return CharacterFunctions::lengthUpTo(*this, maxCharsToCount);
}
/** Returns the number of characters in this string, or up to the given end pointer, whichever is lower. */
size_t lengthUpTo(CharPointer_UTF32 end) const noexcept
{
return CharacterFunctions::lengthUpTo(*this, end);
}
/** Returns the number of bytes that are used to represent this string.
This includes the terminating null character.
*/
size_t sizeInBytes() const noexcept
{
return sizeof(CharType) * (length() + 1);
}
/** Returns the number of bytes that would be needed to represent the given
unicode character in this encoding format.
*/
static size_t getBytesRequiredFor(juce_wchar) noexcept
{
return sizeof(CharType);
}
/** Returns the number of bytes that would be needed to represent the given
string in this encoding format.
The value returned does NOT include the terminating null character.
*/
template <class CharPointer>
static size_t getBytesRequiredFor(CharPointer text) noexcept
{
return sizeof(CharType) * text.length();
}
/** Returns a pointer to the null character that terminates this string. */
CharPointer_UTF32 findTerminatingNull() const noexcept
{
return CharPointer_UTF32(data + length());
}
/** Copies a source string to this pointer, advancing this pointer as it goes. */
template <typename CharPointer>
void writeAll(CharPointer src) noexcept
{
CharacterFunctions::copyAll(*this, src);
}
/** Copies a source string to this pointer, advancing this pointer as it goes. */
void writeAll(CharPointer_UTF32 src) noexcept
{
auto* s = src.data;
while ((*data = *s) != 0)
{
++data;
++s;
}
}
/** Copies a source string to this pointer, advancing this pointer as it goes.
The maxDestBytes parameter specifies the maximum number of bytes that can be written
to the destination buffer before stopping.
*/
template <typename CharPointer>
size_t writeWithDestByteLimit(CharPointer src, size_t maxDestBytes) noexcept
{
return CharacterFunctions::copyWithDestByteLimit(*this, src, maxDestBytes);
}
/** Copies a source string to this pointer, advancing this pointer as it goes.
The maxChars parameter specifies the maximum number of characters that can be
written to the destination buffer before stopping (including the terminating null).
*/
template <typename CharPointer>
void writeWithCharLimit(CharPointer src, int maxChars) noexcept
{
CharacterFunctions::copyWithCharLimit(*this, src, maxChars);
}
/** Compares this string with another one. */
template <typename CharPointer>
int compare(CharPointer other) const noexcept
{
return CharacterFunctions::compare(*this, other);
}
#if JUCE_NATIVE_WCHAR_IS_UTF32 && ! JUCE_ANDROID
/** Compares this string with another one. */
int compare(CharPointer_UTF32 other) const noexcept
{
return wcscmp(data, other.data);
}
#endif
/** Compares this string with another one, up to a specified number of characters. */
template <typename CharPointer>
int compareUpTo(CharPointer other, int maxChars) const noexcept
{
return CharacterFunctions::compareUpTo(*this, other, maxChars);
}
/** Compares this string with another one. */
template <typename CharPointer>
int compareIgnoreCase(CharPointer other) const
{
return CharacterFunctions::compareIgnoreCase(*this, other);
}
/** Compares this string with another one, up to a specified number of characters. */
template <typename CharPointer>
int compareIgnoreCaseUpTo(CharPointer other, int maxChars) const noexcept
{
return CharacterFunctions::compareIgnoreCaseUpTo(*this, other, maxChars);
}
/** Returns the character index of a substring, or -1 if it isn't found. */
template <typename CharPointer>
int indexOf(CharPointer stringToFind) const noexcept
{
return CharacterFunctions::indexOf(*this, stringToFind);
}
/** Returns the character index of a unicode character, or -1 if it isn't found. */
int indexOf(juce_wchar charToFind) const noexcept
{
int i = 0;
while (data[i] != 0)
{
if (data[i] == charToFind)
return i;
++i;
}
return -1;
}
/** Returns the character index of a unicode character, or -1 if it isn't found. */
int indexOf(juce_wchar charToFind, bool ignoreCase) const noexcept
{
return ignoreCase ? CharacterFunctions::indexOfCharIgnoreCase(*this, charToFind)
: CharacterFunctions::indexOfChar(*this, charToFind);
}
/** Returns true if the first character of this string is whitespace. */
bool isWhitespace() const { return CharacterFunctions::isWhitespace(*data) != 0; }
/** Returns true if the first character of this string is a digit. */
bool isDigit() const { return CharacterFunctions::isDigit(*data) != 0; }
/** Returns true if the first character of this string is a letter. */
bool isLetter() const { return CharacterFunctions::isLetter(*data) != 0; }
/** Returns true if the first character of this string is a letter or digit. */
bool isLetterOrDigit() const { return CharacterFunctions::isLetterOrDigit(*data) != 0; }
/** Returns true if the first character of this string is upper-case. */
bool isUpperCase() const { return CharacterFunctions::isUpperCase(*data) != 0; }
/** Returns true if the first character of this string is lower-case. */
bool isLowerCase() const { return CharacterFunctions::isLowerCase(*data) != 0; }
/** Returns an upper-case version of the first character of this string. */
juce_wchar toUpperCase() const noexcept { return CharacterFunctions::toUpperCase(*data); }
/** Returns a lower-case version of the first character of this string. */
juce_wchar toLowerCase() const noexcept { return CharacterFunctions::toLowerCase(*data); }
/** Parses this string as a 32-bit integer. */
int getIntValue32() const noexcept { return CharacterFunctions::getIntValue <int, CharPointer_UTF32>(*this); }
/** Parses this string as a 64-bit integer. */
int64 getIntValue64() const noexcept { return CharacterFunctions::getIntValue <int64, CharPointer_UTF32>(*this); }
/** Parses this string as a floating point double. */
double getDoubleValue() const noexcept { return CharacterFunctions::getDoubleValue(*this); }
/** Returns the first non-whitespace character in the string. */
CharPointer_UTF32 findEndOfWhitespace() const noexcept { return CharacterFunctions::findEndOfWhitespace(*this); }
/** Move this pointer to the first non-whitespace character in the string. */
void incrementToEndOfWhitespace() noexcept { CharacterFunctions::incrementToEndOfWhitespace(*this); }
/** Returns true if the given unicode character can be represented in this encoding. */
static bool canRepresent(juce_wchar character) noexcept
{
return ((uint32)character) < (uint32)0x10ffff;
}
/** Returns true if this data contains a valid string in this encoding. */
static bool isValidString(const CharType* dataToTest, int maxBytesToRead)
{
maxBytesToRead /= (int)sizeof(CharType);
while (--maxBytesToRead >= 0 && *dataToTest != 0)
if (!canRepresent(*dataToTest++))
return false;
return true;
}
/** Atomically swaps this pointer for a new value, returning the previous value. */
CharPointer_UTF32 atomicSwap(CharPointer_UTF32 newValue)
{
return CharPointer_UTF32(reinterpret_cast<Atomic<CharType*>&> (data).exchange(newValue.data));
}
private:
CharType* data;
};
} // namespace juce
/*** End of inlined file: juce_CharPointer_UTF32.h ***/
/*** Start of inlined file: juce_CharPointer_ASCII.h ***/
namespace juce
{
/**
Wraps a pointer to a null-terminated ASCII character string, and provides
various methods to operate on the data.
A valid ASCII string is assumed to not contain any characters above 127.
@see CharPointer_UTF8, CharPointer_UTF16, CharPointer_UTF32
@tags{Core}
*/
class CharPointer_ASCII final
{
public:
using CharType = char;
inline explicit CharPointer_ASCII(const CharType* rawPointer) noexcept
: data(const_cast<CharType*> (rawPointer))
{
}
inline CharPointer_ASCII(const CharPointer_ASCII& other) = default;
inline CharPointer_ASCII operator= (const CharPointer_ASCII other) noexcept
{
data = other.data;
return *this;
}
inline CharPointer_ASCII operator= (const CharType* text) noexcept
{
data = const_cast<CharType*> (text);
return *this;
}
/** This is a pointer comparison, it doesn't compare the actual text. */
inline bool operator== (CharPointer_ASCII other) const noexcept { return data == other.data; }
inline bool operator!= (CharPointer_ASCII other) const noexcept { return data != other.data; }
inline bool operator<= (CharPointer_ASCII other) const noexcept { return data <= other.data; }
inline bool operator< (CharPointer_ASCII other) const noexcept { return data < other.data; }
inline bool operator>= (CharPointer_ASCII other) const noexcept { return data >= other.data; }
inline bool operator> (CharPointer_ASCII other) const noexcept { return data > other.data; }
/** Returns the address that this pointer is pointing to. */
inline CharType* getAddress() const noexcept { return data; }
/** Returns the address that this pointer is pointing to. */
inline operator const CharType* () const noexcept { return data; }
/** Returns true if this pointer is pointing to a null character. */
inline bool isEmpty() const noexcept { return *data == 0; }
/** Returns true if this pointer is not pointing to a null character. */
inline bool isNotEmpty() const noexcept { return *data != 0; }
/** Returns the unicode character that this pointer is pointing to. */
inline juce_wchar operator*() const noexcept { return (juce_wchar)(uint8)*data; }
/** Moves this pointer along to the next character in the string. */
inline CharPointer_ASCII operator++() noexcept
{
++data;
return *this;
}
/** Moves this pointer to the previous character in the string. */
inline CharPointer_ASCII operator--() noexcept
{
--data;
return *this;
}
/** Returns the character that this pointer is currently pointing to, and then
advances the pointer to point to the next character. */
inline juce_wchar getAndAdvance() noexcept { return (juce_wchar)(uint8)*data++; }
/** Moves this pointer along to the next character in the string. */
CharPointer_ASCII operator++ (int) noexcept
{
auto temp(*this);
++data;
return temp;
}
/** Moves this pointer forwards by the specified number of characters. */
inline void operator+= (const int numToSkip) noexcept
{
data += numToSkip;
}
inline void operator-= (const int numToSkip) noexcept
{
data -= numToSkip;
}
/** Returns the character at a given character index from the start of the string. */
inline juce_wchar operator[] (const int characterIndex) const noexcept
{
return (juce_wchar)(uint8)data[characterIndex];
}
/** Returns a pointer which is moved forwards from this one by the specified number of characters. */
CharPointer_ASCII operator+ (const int numToSkip) const noexcept
{
return CharPointer_ASCII(data + numToSkip);
}
/** Returns a pointer which is moved backwards from this one by the specified number of characters. */
CharPointer_ASCII operator- (const int numToSkip) const noexcept
{
return CharPointer_ASCII(data - numToSkip);
}
/** Writes a unicode character to this string, and advances this pointer to point to the next position. */
inline void write(const juce_wchar charToWrite) noexcept
{
*data++ = (char)charToWrite;
}
inline void replaceChar(const juce_wchar newChar) noexcept
{
*data = (char)newChar;
}
/** Writes a null character to this string (leaving the pointer's position unchanged). */
inline void writeNull() const noexcept
{
*data = 0;
}
/** Returns the number of characters in this string. */
size_t length() const noexcept
{
return (size_t)strlen(data);
}
/** Returns the number of characters in this string, or the given value, whichever is lower. */
size_t lengthUpTo(const size_t maxCharsToCount) const noexcept
{
return CharacterFunctions::lengthUpTo(*this, maxCharsToCount);
}
/** Returns the number of characters in this string, or up to the given end pointer, whichever is lower. */
size_t lengthUpTo(const CharPointer_ASCII end) const noexcept
{
return CharacterFunctions::lengthUpTo(*this, end);
}
/** Returns the number of bytes that are used to represent this string.
This includes the terminating null character.
*/
size_t sizeInBytes() const noexcept
{
return length() + 1;
}
/** Returns the number of bytes that would be needed to represent the given
unicode character in this encoding format.
*/
static size_t getBytesRequiredFor(const juce_wchar) noexcept
{
return 1;
}
/** Returns the number of bytes that would be needed to represent the given
string in this encoding format.
The value returned does NOT include the terminating null character.
*/
template <class CharPointer>
static size_t getBytesRequiredFor(const CharPointer text) noexcept
{
return text.length();
}
/** Returns a pointer to the null character that terminates this string. */
CharPointer_ASCII findTerminatingNull() const noexcept
{
return CharPointer_ASCII(data + length());
}
/** Copies a source string to this pointer, advancing this pointer as it goes. */
template <typename CharPointer>
void writeAll(const CharPointer src) noexcept
{
CharacterFunctions::copyAll(*this, src);
}
/** Copies a source string to this pointer, advancing this pointer as it goes.
The maxDestBytes parameter specifies the maximum number of bytes that can be written
to the destination buffer before stopping.
*/
template <typename CharPointer>
size_t writeWithDestByteLimit(const CharPointer src, const size_t maxDestBytes) noexcept
{
return CharacterFunctions::copyWithDestByteLimit(*this, src, maxDestBytes);
}
/** Copies a source string to this pointer, advancing this pointer as it goes.
The maxChars parameter specifies the maximum number of characters that can be
written to the destination buffer before stopping (including the terminating null).
*/
template <typename CharPointer>
void writeWithCharLimit(const CharPointer src, const int maxChars) noexcept
{
CharacterFunctions::copyWithCharLimit(*this, src, maxChars);
}
/** Compares this string with another one. */
template <typename CharPointer>
int compare(const CharPointer other) const noexcept
{
return CharacterFunctions::compare(*this, other);
}
/** Compares this string with another one. */
int compare(const CharPointer_ASCII other) const noexcept
{
return strcmp(data, other.data);
}
/** Compares this string with another one, up to a specified number of characters. */
template <typename CharPointer>
int compareUpTo(const CharPointer other, const int maxChars) const noexcept
{
return CharacterFunctions::compareUpTo(*this, other, maxChars);
}
/** Compares this string with another one, up to a specified number of characters. */
int compareUpTo(const CharPointer_ASCII other, const int maxChars) const noexcept
{
return strncmp(data, other.data, (size_t)maxChars);
}
/** Compares this string with another one. */
template <typename CharPointer>
int compareIgnoreCase(const CharPointer other) const
{
return CharacterFunctions::compareIgnoreCase(*this, other);
}
int compareIgnoreCase(const CharPointer_ASCII other) const
{
#if JUCE_MINGW || (JUCE_WINDOWS && JUCE_CLANG)
return CharacterFunctions::compareIgnoreCase(*this, other);
#elif JUCE_WINDOWS
return stricmp(data, other.data);
#else
return strcasecmp(data, other.data);
#endif
}
/** Compares this string with another one, up to a specified number of characters. */
template <typename CharPointer>
int compareIgnoreCaseUpTo(const CharPointer other, const int maxChars) const noexcept
{
return CharacterFunctions::compareIgnoreCaseUpTo(*this, other, maxChars);
}
/** Returns the character index of a substring, or -1 if it isn't found. */
template <typename CharPointer>
int indexOf(const CharPointer stringToFind) const noexcept
{
return CharacterFunctions::indexOf(*this, stringToFind);
}
/** Returns the character index of a unicode character, or -1 if it isn't found. */
int indexOf(const juce_wchar charToFind) const noexcept
{
int i = 0;
while (data[i] != 0)
{
if (data[i] == (char)charToFind)
return i;
++i;
}
return -1;
}
/** Returns the character index of a unicode character, or -1 if it isn't found. */
int indexOf(const juce_wchar charToFind, const bool ignoreCase) const noexcept
{
return ignoreCase ? CharacterFunctions::indexOfCharIgnoreCase(*this, charToFind)
: CharacterFunctions::indexOfChar(*this, charToFind);
}
/** Returns true if the first character of this string is whitespace. */
bool isWhitespace() const { return CharacterFunctions::isWhitespace(*data) != 0; }
/** Returns true if the first character of this string is a digit. */
bool isDigit() const { return CharacterFunctions::isDigit(*data) != 0; }
/** Returns true if the first character of this string is a letter. */
bool isLetter() const { return CharacterFunctions::isLetter(*data) != 0; }
/** Returns true if the first character of this string is a letter or digit. */
bool isLetterOrDigit() const { return CharacterFunctions::isLetterOrDigit(*data) != 0; }
/** Returns true if the first character of this string is upper-case. */
bool isUpperCase() const { return CharacterFunctions::isUpperCase((juce_wchar)(uint8)*data) != 0; }
/** Returns true if the first character of this string is lower-case. */
bool isLowerCase() const { return CharacterFunctions::isLowerCase((juce_wchar)(uint8)*data) != 0; }
/** Returns an upper-case version of the first character of this string. */
juce_wchar toUpperCase() const noexcept { return CharacterFunctions::toUpperCase((juce_wchar)(uint8)*data); }
/** Returns a lower-case version of the first character of this string. */
juce_wchar toLowerCase() const noexcept { return CharacterFunctions::toLowerCase((juce_wchar)(uint8)*data); }
/** Parses this string as a 32-bit integer. */
int getIntValue32() const noexcept { return atoi(data); }
/** Parses this string as a 64-bit integer. */
int64 getIntValue64() const noexcept
{
#if JUCE_LINUX || JUCE_BSD || JUCE_ANDROID || JUCE_MINGW
return atoll(data);
#elif JUCE_WINDOWS
return _atoi64(data);
#else
return CharacterFunctions::getIntValue <int64, CharPointer_ASCII>(*this);
#endif
}
/** Parses this string as a floating point double. */
double getDoubleValue() const noexcept { return CharacterFunctions::getDoubleValue(*this); }
/** Returns the first non-whitespace character in the string. */
CharPointer_ASCII findEndOfWhitespace() const noexcept { return CharacterFunctions::findEndOfWhitespace(*this); }
/** Move this pointer to the first non-whitespace character in the string. */
void incrementToEndOfWhitespace() noexcept { CharacterFunctions::incrementToEndOfWhitespace(*this); }
/** Returns true if the given unicode character can be represented in this encoding. */
static bool canRepresent(juce_wchar character) noexcept
{
return ((unsigned int)character) < (unsigned int)128;
}
/** Returns true if this data contains a valid string in this encoding. */
static bool isValidString(const CharType* dataToTest, int maxBytesToRead)
{
while (--maxBytesToRead >= 0)
{
if (((signed char)*dataToTest) <= 0)
return *dataToTest == 0;
++dataToTest;
}
return true;
}
private:
CharType* data;
};
} // namespace juce
/*** End of inlined file: juce_CharPointer_ASCII.h ***/
JUCE_END_IGNORE_WARNINGS_MSVC
/*** Start of inlined file: juce_String.h ***/
#if ! DOXYGEN && (JUCE_MAC || JUCE_IOS)
// Annoyingly we can only forward-declare a typedef by forward-declaring the
// aliased type
#if __has_attribute(objc_bridge)
#define JUCE_CF_BRIDGED_TYPE(T) __attribute__((objc_bridge(T)))
#else
#define JUCE_CF_BRIDGED_TYPE(T)
#endif
typedef const struct JUCE_CF_BRIDGED_TYPE(NSString) __CFString* CFStringRef;
#undef JUCE_CF_BRIDGED_TYPE
#endif
namespace juce
{
/**
The JUCE String class!
Using a reference-counted internal representation, these strings are fast
and efficient, and there are methods to do just about any operation you'll ever
dream of.
@see StringArray, StringPairArray
@tags{Core}
*/
class JUCE_API String final
{
public:
/** Creates an empty string.
@see empty
*/
String() noexcept;
/** Creates a copy of another string. */
String(const String&) noexcept;
/** Move constructor */
String(String&&) noexcept;
/** Creates a string from a zero-terminated ascii text string.
The string passed-in must not contain any characters with a value above 127, because
these can't be converted to unicode without knowing the original encoding that was
used to create the string. If you attempt to pass-in values above 127, you'll get an
assertion.
To create strings with extended characters from UTF-8, you should explicitly call
String (CharPointer_UTF8 ("my utf8 string..")). It's *highly* recommended that you
use UTF-8 with escape characters in your source code to represent extended characters,
because there's no other way to represent unicode strings in a way that isn't dependent
on the compiler, source code editor and platform.
*/
String(const char* text);
/** Creates a string from a string of 8-bit ascii characters.
The string passed-in must not contain any characters with a value above 127, because
these can't be converted to unicode without knowing the original encoding that was
used to create the string. If you attempt to pass-in values above 127, you'll get an
assertion.
To create strings with extended characters from UTF-8, you should explicitly call
String (CharPointer_UTF8 ("my utf8 string..")). It's *highly* recommended that you
use UTF-8 with escape characters in your source code to represent extended characters,
because there's no other way to represent unicode strings in a way that isn't dependent
on the compiler, source code editor and platform.
This will use up to the first maxChars characters of the string (or less if the string
is actually shorter).
*/
String(const char* text, size_t maxChars);
/** Creates a string from a wchar_t character string.
Depending on the platform, this may be treated as either UTF-32 or UTF-16.
*/
String(const wchar_t* text);
/** Creates a string from a wchar_t character string.
Depending on the platform, this may be treated as either UTF-32 or UTF-16.
*/
String(const wchar_t* text, size_t maxChars);
/** Creates a string from a UTF-8 character string */
String(CharPointer_UTF8 text);
/** Creates a string from a UTF-8 character string */
String(CharPointer_UTF8 text, size_t maxChars);
/** Creates a string from a UTF-8 character string */
String(CharPointer_UTF8 start, CharPointer_UTF8 end);
/** Creates a string from a UTF-16 character string */
String(CharPointer_UTF16 text);
/** Creates a string from a UTF-16 character string */
String(CharPointer_UTF16 text, size_t maxChars);
/** Creates a string from a UTF-16 character string */
String(CharPointer_UTF16 start, CharPointer_UTF16 end);
/** Creates a string from a UTF-32 character string */
String(CharPointer_UTF32 text);
/** Creates a string from a UTF-32 character string */
String(CharPointer_UTF32 text, size_t maxChars);
/** Creates a string from a UTF-32 character string */
String(CharPointer_UTF32 start, CharPointer_UTF32 end);
/** Creates a string from an ASCII character string */
String(CharPointer_ASCII text);
/** Creates a string from a UTF-8 encoded std::string. */
String(const std::string&);
/** Creates a string from a StringRef */
String(StringRef);
/** Creates a string from a single character. */
static String charToString(juce_wchar character);
/** Destructor. */
~String() noexcept;
/** This is the character encoding type used internally to store the string.
By setting the value of JUCE_STRING_UTF_TYPE to 8, 16, or 32, you can change the
internal storage format of the String class. UTF-8 uses the least space (if your strings
contain few extended characters), but call operator[] involves iterating the string to find
the required index. UTF-32 provides instant random access to its characters, but uses 4 bytes
per character to store them. UTF-16 uses more space than UTF-8 and is also slow to index,
but is the native wchar_t format used in Windows.
It doesn't matter too much which format you pick, because the toUTF8(), toUTF16() and
toUTF32() methods let you access the string's content in any of the other formats.
*/
#if (JUCE_STRING_UTF_TYPE == 32)
using CharPointerType = CharPointer_UTF32;
#elif (JUCE_STRING_UTF_TYPE == 16)
using CharPointerType = CharPointer_UTF16;
#elif (DOXYGEN || JUCE_STRING_UTF_TYPE == 8)
using CharPointerType = CharPointer_UTF8;
#else
#error "You must set the value of JUCE_STRING_UTF_TYPE to be either 8, 16, or 32!"
#endif
/** Generates a probably-unique 32-bit hashcode from this string. */
int hashCode() const noexcept;
/** Generates a probably-unique 64-bit hashcode from this string. */
int64 hashCode64() const noexcept;
/** Generates a probably-unique hashcode from this string. */
size_t hash() const noexcept;
/** Returns the number of characters in the string. */
int length() const noexcept;
// Assignment and concatenation operators..
/** Replaces this string's contents with another string. */
String& operator= (const String& other) noexcept;
/** Moves the contents of another string to the receiver */
String& operator= (String&& other) noexcept;
/** Appends another string at the end of this one. */
String& operator+= (const String& stringToAppend);
/** Appends another string at the end of this one. */
String& operator+= (const char* textToAppend);
/** Appends another string at the end of this one. */
String& operator+= (const wchar_t* textToAppend);
/** Appends another string at the end of this one. */
String& operator+= (StringRef textToAppend);
/** Appends a decimal number at the end of this string. */
String& operator+= (int numberToAppend);
/** Appends a decimal number at the end of this string. */
String& operator+= (long numberToAppend);
/** Appends a decimal number at the end of this string. */
String& operator+= (int64 numberToAppend);
/** Appends a decimal number at the end of this string. */
String& operator+= (uint64 numberToAppend);
/** Appends a character at the end of this string. */
String& operator+= (char characterToAppend);
/** Appends a character at the end of this string. */
String& operator+= (wchar_t characterToAppend);
#if ! JUCE_NATIVE_WCHAR_IS_UTF32
/** Appends a character at the end of this string. */
String& operator+= (juce_wchar characterToAppend);
#endif
/** Appends a string to the end of this one.
@param textToAppend the string to add
@param maxCharsToTake the maximum number of characters to take from the string passed in
*/
void append(const String& textToAppend, size_t maxCharsToTake);
/** Appends a string to the end of this one.
@param startOfTextToAppend the start of the string to add. This must not be a nullptr
@param endOfTextToAppend the end of the string to add. This must not be a nullptr
*/
void appendCharPointer(CharPointerType startOfTextToAppend,
CharPointerType endOfTextToAppend);
/** Appends a string to the end of this one.
@param startOfTextToAppend the start of the string to add. This must not be a nullptr
@param endOfTextToAppend the end of the string to add. This must not be a nullptr
*/
template <class CharPointer>
void appendCharPointer(CharPointer startOfTextToAppend,
CharPointer endOfTextToAppend)
{
jassert(startOfTextToAppend.getAddress() != nullptr && endOfTextToAppend.getAddress() != nullptr);
size_t extraBytesNeeded = 0, numChars = 1;
for (auto t = startOfTextToAppend; t != endOfTextToAppend && !t.isEmpty(); ++numChars)
extraBytesNeeded += CharPointerType::getBytesRequiredFor(t.getAndAdvance());
if (extraBytesNeeded > 0)
{
auto byteOffsetOfNull = getByteOffsetOfEnd();
preallocateBytes(byteOffsetOfNull + extraBytesNeeded);
CharPointerType(addBytesToPointer(text.getAddress(), (int)byteOffsetOfNull))
.writeWithCharLimit(startOfTextToAppend, (int)numChars);
}
}
/** Appends a string to the end of this one. */
void appendCharPointer(CharPointerType textToAppend);
/** Appends a string to the end of this one.
@param textToAppend the string to add
@param maxCharsToTake the maximum number of characters to take from the string passed in
*/
template <class CharPointer>
void appendCharPointer(CharPointer textToAppend, size_t maxCharsToTake)
{
if (textToAppend.getAddress() != nullptr)
{
size_t extraBytesNeeded = 0, numChars = 1;
for (auto t = textToAppend; numChars <= maxCharsToTake && !t.isEmpty(); ++numChars)
extraBytesNeeded += CharPointerType::getBytesRequiredFor(t.getAndAdvance());
if (extraBytesNeeded > 0)
{
auto byteOffsetOfNull = getByteOffsetOfEnd();
preallocateBytes(byteOffsetOfNull + extraBytesNeeded);
CharPointerType(addBytesToPointer(text.getAddress(), (int)byteOffsetOfNull))
.writeWithCharLimit(textToAppend, (int)numChars);
}
}
}
/** Appends a string to the end of this one. */
template <class CharPointer>
void appendCharPointer(CharPointer textToAppend)
{
appendCharPointer(textToAppend, std::numeric_limits<size_t>::max());
}
// Comparison methods..
/** Returns true if the string contains no characters.
Note that there's also an isNotEmpty() method to help write readable code.
@see containsNonWhitespaceChars()
*/
bool isEmpty() const noexcept { return text.isEmpty(); }
/** Returns true if the string contains at least one character.
Note that there's also an isEmpty() method to help write readable code.
@see containsNonWhitespaceChars()
*/
bool isNotEmpty() const noexcept { return !text.isEmpty(); }
/** Resets this string to be empty. */
void clear() noexcept;
/** Case-insensitive comparison with another string. */
bool equalsIgnoreCase(const String& other) const noexcept;
/** Case-insensitive comparison with another string. */
bool equalsIgnoreCase(StringRef other) const noexcept;
/** Case-insensitive comparison with another string. */
bool equalsIgnoreCase(const wchar_t* other) const noexcept;
/** Case-insensitive comparison with another string. */
bool equalsIgnoreCase(const char* other) const noexcept;
/** Case-sensitive comparison with another string.
@returns 0 if the two strings are identical; negative if this string comes before
the other one alphabetically, or positive if it comes after it.
*/
int compare(const String& other) const noexcept;
/** Case-sensitive comparison with another string.
@returns 0 if the two strings are identical; negative if this string comes before
the other one alphabetically, or positive if it comes after it.
*/
int compare(const char* other) const noexcept;
/** Case-sensitive comparison with another string.
@returns 0 if the two strings are identical; negative if this string comes before
the other one alphabetically, or positive if it comes after it.
*/
int compare(const wchar_t* other) const noexcept;
/** Case-insensitive comparison with another string.
@returns 0 if the two strings are identical; negative if this string comes before
the other one alphabetically, or positive if it comes after it.
*/
int compareIgnoreCase(const String& other) const noexcept;
/** Compares two strings, taking into account textual characteristics like numbers and spaces.
This comparison is case-insensitive and can detect words and embedded numbers in the
strings, making it good for sorting human-readable lists of things like filenames.
@returns 0 if the two strings are identical; negative if this string comes before
the other one alphabetically, or positive if it comes after it.
*/
int compareNatural(StringRef other, bool isCaseSensitive = false) const noexcept;
/** Tests whether the string begins with another string.
If the parameter is an empty string, this will always return true.
Uses a case-sensitive comparison.
*/
bool startsWith(StringRef text) const noexcept;
/** Tests whether the string begins with a particular character.
If the character is 0, this will always return false.
Uses a case-sensitive comparison.
*/
bool startsWithChar(juce_wchar character) const noexcept;
/** Tests whether the string begins with another string.
If the parameter is an empty string, this will always return true.
Uses a case-insensitive comparison.
*/
bool startsWithIgnoreCase(StringRef text) const noexcept;
/** Tests whether the string ends with another string.
If the parameter is an empty string, this will always return true.
Uses a case-sensitive comparison.
*/
bool endsWith(StringRef text) const noexcept;
/** Tests whether the string ends with a particular character.
If the character is 0, this will always return false.
Uses a case-sensitive comparison.
*/
bool endsWithChar(juce_wchar character) const noexcept;
/** Tests whether the string ends with another string.
If the parameter is an empty string, this will always return true.
Uses a case-insensitive comparison.
*/
bool endsWithIgnoreCase(StringRef text) const noexcept;
/** Tests whether the string contains another substring.
If the parameter is an empty string, this will always return true.
Uses a case-sensitive comparison.
*/
bool contains(StringRef text) const noexcept;
/** Tests whether the string contains a particular character.
Uses a case-sensitive comparison.
*/
bool containsChar(juce_wchar character) const noexcept;
/** Tests whether the string contains another substring.
Uses a case-insensitive comparison.
*/
bool containsIgnoreCase(StringRef text) const noexcept;
/** Tests whether the string contains another substring as a distinct word.
@returns true if the string contains this word, surrounded by
non-alphanumeric characters
@see indexOfWholeWord, containsWholeWordIgnoreCase
*/
bool containsWholeWord(StringRef wordToLookFor) const noexcept;
/** Tests whether the string contains another substring as a distinct word.
@returns true if the string contains this word, surrounded by
non-alphanumeric characters
@see indexOfWholeWordIgnoreCase, containsWholeWord
*/
bool containsWholeWordIgnoreCase(StringRef wordToLookFor) const noexcept;
/** Finds an instance of another substring if it exists as a distinct word.
@returns if the string contains this word, surrounded by non-alphanumeric characters,
then this will return the index of the start of the substring. If it isn't
found, then it will return -1
@see indexOfWholeWordIgnoreCase, containsWholeWord
*/
int indexOfWholeWord(StringRef wordToLookFor) const noexcept;
/** Finds an instance of another substring if it exists as a distinct word.
@returns if the string contains this word, surrounded by non-alphanumeric characters,
then this will return the index of the start of the substring. If it isn't
found, then it will return -1
@see indexOfWholeWord, containsWholeWordIgnoreCase
*/
int indexOfWholeWordIgnoreCase(StringRef wordToLookFor) const noexcept;
/** Looks for any of a set of characters in the string.
Uses a case-sensitive comparison.
@returns true if the string contains any of the characters from
the string that is passed in.
*/
bool containsAnyOf(StringRef charactersItMightContain) const noexcept;
/** Looks for a set of characters in the string.
Uses a case-sensitive comparison.
@returns Returns false if any of the characters in this string do not occur in
the parameter string. If this string is empty, the return value will
always be true.
*/
bool containsOnly(StringRef charactersItMightContain) const noexcept;
/** Returns true if this string contains any non-whitespace characters.
This will return false if the string contains only whitespace characters, or
if it's empty.
It is equivalent to calling "myString.trim().isNotEmpty()".
*/
bool containsNonWhitespaceChars() const noexcept;
/** Returns true if the string matches this simple wildcard expression.
So for example String ("abcdef").matchesWildcard ("*DEF", true) would return true.
This isn't a full-blown regex though! The only wildcard characters supported
are "*" and "?". It's mainly intended for filename pattern matching.
*/
bool matchesWildcard(StringRef wildcard, bool ignoreCase) const noexcept;
// Substring location methods..
/** Searches for a character inside this string.
Uses a case-sensitive comparison.
@returns the index of the first occurrence of the character in this
string, or -1 if it's not found.
*/
int indexOfChar(juce_wchar characterToLookFor) const noexcept;
/** Searches for a character inside this string.
Uses a case-sensitive comparison.
@param startIndex the index from which the search should proceed
@param characterToLookFor the character to look for
@returns the index of the first occurrence of the character in this
string, or -1 if it's not found.
*/
int indexOfChar(int startIndex, juce_wchar characterToLookFor) const noexcept;
/** Returns the index of the first character that matches one of the characters
passed-in to this method.
This scans the string, beginning from the startIndex supplied, and if it finds
a character that appears in the string charactersToLookFor, it returns its index.
If none of these characters are found, it returns -1.
If ignoreCase is true, the comparison will be case-insensitive.
@see indexOfChar, lastIndexOfAnyOf
*/
int indexOfAnyOf(StringRef charactersToLookFor,
int startIndex = 0,
bool ignoreCase = false) const noexcept;
/** Searches for a substring within this string.
Uses a case-sensitive comparison.
@returns the index of the first occurrence of this substring, or -1 if it's not found.
If textToLookFor is an empty string, this will always return 0.
*/
int indexOf(StringRef textToLookFor) const noexcept;
/** Searches for a substring within this string.
Uses a case-sensitive comparison.
@param startIndex the index from which the search should proceed
@param textToLookFor the string to search for
@returns the index of the first occurrence of this substring, or -1 if it's not found.
If textToLookFor is an empty string, this will always return -1.
*/
int indexOf(int startIndex, StringRef textToLookFor) const noexcept;
/** Searches for a substring within this string.
Uses a case-insensitive comparison.
@returns the index of the first occurrence of this substring, or -1 if it's not found.
If textToLookFor is an empty string, this will always return 0.
*/
int indexOfIgnoreCase(StringRef textToLookFor) const noexcept;
/** Searches for a substring within this string.
Uses a case-insensitive comparison.
@param startIndex the index from which the search should proceed
@param textToLookFor the string to search for
@returns the index of the first occurrence of this substring, or -1 if it's not found.
If textToLookFor is an empty string, this will always return -1.
*/
int indexOfIgnoreCase(int startIndex, StringRef textToLookFor) const noexcept;
/** Searches for a character inside this string (working backwards from the end of the string).
Uses a case-sensitive comparison.
@returns the index of the last occurrence of the character in this string, or -1 if it's not found.
*/
int lastIndexOfChar(juce_wchar character) const noexcept;
/** Searches for a substring inside this string (working backwards from the end of the string).
Uses a case-sensitive comparison.
@returns the index of the start of the last occurrence of the substring within this string,
or -1 if it's not found. If textToLookFor is an empty string, this will always return -1.
*/
int lastIndexOf(StringRef textToLookFor) const noexcept;
/** Searches for a substring inside this string (working backwards from the end of the string).
Uses a case-insensitive comparison.
@returns the index of the start of the last occurrence of the substring within this string, or -1
if it's not found. If textToLookFor is an empty string, this will always return -1.
*/
int lastIndexOfIgnoreCase(StringRef textToLookFor) const noexcept;
/** Returns the index of the last character in this string that matches one of the
characters passed-in to this method.
This scans the string backwards, starting from its end, and if it finds
a character that appears in the string charactersToLookFor, it returns its index.
If none of these characters are found, it returns -1.
If ignoreCase is true, the comparison will be case-insensitive.
@see lastIndexOf, indexOfAnyOf
*/
int lastIndexOfAnyOf(StringRef charactersToLookFor,
bool ignoreCase = false) const noexcept;
// Substring extraction and manipulation methods..
/** Returns the character at this index in the string.
In a release build, no checks are made to see if the index is within a valid range, so be
careful! In a debug build, the index is checked and an assertion fires if it's out-of-range.
Also beware that depending on the encoding format that the string is using internally, this
method may execute in either O(1) or O(n) time, so be careful when using it in your algorithms.
If you're scanning through a string to inspect its characters, you should never use this operator
for random access, it's far more efficient to call getCharPointer() to return a pointer, and
then to use that to iterate the string.
@see getCharPointer
*/
juce_wchar operator[] (int index) const noexcept;
/** Returns the final character of the string.
If the string is empty this will return 0.
*/
juce_wchar getLastCharacter() const noexcept;
/** Returns a subsection of the string.
If the range specified is beyond the limits of the string, as much as
possible is returned.
@param startIndex the index of the start of the substring needed
@param endIndex all characters from startIndex up to (but not including)
this index are returned
@see fromFirstOccurrenceOf, dropLastCharacters, getLastCharacters, upToFirstOccurrenceOf
*/
String substring(int startIndex, int endIndex) const;
/** Returns a section of the string, starting from a given position.
@param startIndex the first character to include. If this is beyond the end
of the string, an empty string is returned. If it is zero or
less, the whole string is returned.
@returns the substring from startIndex up to the end of the string
@see dropLastCharacters, getLastCharacters, fromFirstOccurrenceOf, upToFirstOccurrenceOf, fromLastOccurrenceOf
*/
String substring(int startIndex) const;
/** Returns a version of this string with a number of characters removed
from the end.
@param numberToDrop the number of characters to drop from the end of the
string. If this is greater than the length of the string,
an empty string will be returned. If zero or less, the
original string will be returned.
@see substring, fromFirstOccurrenceOf, upToFirstOccurrenceOf, fromLastOccurrenceOf, getLastCharacter
*/
String dropLastCharacters(int numberToDrop) const;
/** Returns a number of characters from the end of the string.
This returns the last numCharacters characters from the end of the string. If the
string is shorter than numCharacters, the whole string is returned.
@see substring, dropLastCharacters, getLastCharacter
*/
String getLastCharacters(int numCharacters) const;
/** Returns a section of the string starting from a given substring.
This will search for the first occurrence of the given substring, and
return the section of the string starting from the point where this is
found (optionally not including the substring itself).
e.g. for the string "123456", fromFirstOccurrenceOf ("34", true) would return "3456", and
fromFirstOccurrenceOf ("34", false) would return "56".
If the substring isn't found, the method will return an empty string.
If ignoreCase is true, the comparison will be case-insensitive.
@see upToFirstOccurrenceOf, fromLastOccurrenceOf
*/
String fromFirstOccurrenceOf(StringRef substringToStartFrom,
bool includeSubStringInResult,
bool ignoreCase) const;
/** Returns a section of the string starting from the last occurrence of a given substring.
Similar to fromFirstOccurrenceOf(), but using the last occurrence of the substring, and
unlike fromFirstOccurrenceOf(), if the substring isn't found, this method will
return the whole of the original string.
@see fromFirstOccurrenceOf, upToLastOccurrenceOf
*/
String fromLastOccurrenceOf(StringRef substringToFind,
bool includeSubStringInResult,
bool ignoreCase) const;
/** Returns the start of this string, up to the first occurrence of a substring.
This will search for the first occurrence of a given substring, and then
return a copy of the string, up to the position of this substring,
optionally including or excluding the substring itself in the result.
e.g. for the string "123456", upTo ("34", false) would return "12", and
upTo ("34", true) would return "1234".
If the substring isn't found, this will return the whole of the original string.
@see upToLastOccurrenceOf, fromFirstOccurrenceOf
*/
String upToFirstOccurrenceOf(StringRef substringToEndWith,
bool includeSubStringInResult,
bool ignoreCase) const;
/** Returns the start of this string, up to the last occurrence of a substring.
Similar to upToFirstOccurrenceOf(), but this finds the last occurrence rather than the first.
If the substring isn't found, this will return the whole of the original string.
@see upToFirstOccurrenceOf, fromFirstOccurrenceOf
*/
String upToLastOccurrenceOf(StringRef substringToFind,
bool includeSubStringInResult,
bool ignoreCase) const;
/** Returns a copy of this string with any whitespace characters removed from the start and end. */
String trim() const;
/** Returns a copy of this string with any whitespace characters removed from the start. */
String trimStart() const;
/** Returns a copy of this string with any whitespace characters removed from the end. */
String trimEnd() const;
/** Returns a copy of this string, having removed a specified set of characters from its start.
Characters are removed from the start of the string until it finds one that is not in the
specified set, and then it stops.
@param charactersToTrim the set of characters to remove.
@see trim, trimStart, trimCharactersAtEnd
*/
String trimCharactersAtStart(StringRef charactersToTrim) const;
/** Returns a copy of this string, having removed a specified set of characters from its end.
Characters are removed from the end of the string until it finds one that is not in the
specified set, and then it stops.
@param charactersToTrim the set of characters to remove.
@see trim, trimEnd, trimCharactersAtStart
*/
String trimCharactersAtEnd(StringRef charactersToTrim) const;
/** Returns an upper-case version of this string. */
String toUpperCase() const;
/** Returns an lower-case version of this string. */
String toLowerCase() const;
/** Replaces a sub-section of the string with another string.
This will return a copy of this string, with a set of characters
from startIndex to startIndex + numCharsToReplace removed, and with
a new string inserted in their place.
Note that this is a const method, and won't alter the string itself.
@param startIndex the first character to remove. If this is beyond the bounds of the string,
it will be constrained to a valid range.
@param numCharactersToReplace the number of characters to remove. If zero or less, no
characters will be taken out.
@param stringToInsert the new string to insert at startIndex after the characters have been
removed.
*/
String replaceSection(int startIndex,
int numCharactersToReplace,
StringRef stringToInsert) const;
/** Replaces all occurrences of a substring with another string.
Returns a copy of this string, with any occurrences of stringToReplace
swapped for stringToInsertInstead.
Note that this is a const method, and won't alter the string itself.
*/
String replace(StringRef stringToReplace,
StringRef stringToInsertInstead,
bool ignoreCase = false) const;
/** Replaces the first occurrence of a substring with another string.
Returns a copy of this string, with the first occurrence of stringToReplace
swapped for stringToInsertInstead.
Note that this is a const method, and won't alter the string itself.
*/
String replaceFirstOccurrenceOf(StringRef stringToReplace,
StringRef stringToInsertInstead,
bool ignoreCase = false) const;
/** Returns a string with all occurrences of a character replaced with a different one. */
String replaceCharacter(juce_wchar characterToReplace,
juce_wchar characterToInsertInstead) const;
/** Replaces a set of characters with another set.
Returns a string in which each character from charactersToReplace has been replaced
by the character at the equivalent position in newCharacters (so the two strings
passed in must be the same length).
e.g. replaceCharacters ("abc", "def") replaces 'a' with 'd', 'b' with 'e', etc.
Note that this is a const method, and won't affect the string itself.
*/
String replaceCharacters(StringRef charactersToReplace,
StringRef charactersToInsertInstead) const;
/** Returns a version of this string that only retains a fixed set of characters.
This will return a copy of this string, omitting any characters which are not
found in the string passed-in.
e.g. for "1122334455", retainCharacters ("432") would return "223344"
Note that this is a const method, and won't alter the string itself.
*/
String retainCharacters(StringRef charactersToRetain) const;
/** Returns a version of this string with a set of characters removed.
This will return a copy of this string, omitting any characters which are
found in the string passed-in.
e.g. for "1122334455", removeCharacters ("432") would return "1155"
Note that this is a const method, and won't alter the string itself.
*/
String removeCharacters(StringRef charactersToRemove) const;
/** Returns a section from the start of the string that only contains a certain set of characters.
This returns the leftmost section of the string, up to (and not including) the
first character that doesn't appear in the string passed in.
*/
String initialSectionContainingOnly(StringRef permittedCharacters) const;
/** Returns a section from the start of the string that only contains a certain set of characters.
This returns the leftmost section of the string, up to (and not including) the
first character that occurs in the string passed in. (If none of the specified
characters are found in the string, the return value will just be the original string).
*/
String initialSectionNotContaining(StringRef charactersToStopAt) const;
/** Checks whether the string might be in quotation marks.
@returns true if the string begins with a quote character (either a double or single quote).
It is also true if there is whitespace before the quote, but it doesn't check the end of the string.
@see unquoted, quoted
*/
bool isQuotedString() const;
/** Removes quotation marks from around the string, (if there are any).
Returns a copy of this string with any quotes removed from its ends. Quotes that aren't
at the ends of the string are not affected. If there aren't any quotes, the original string
is returned.
Note that this is a const method, and won't alter the string itself.
@see isQuotedString, quoted
*/
String unquoted() const;
/** Adds quotation marks around a string.
This will return a copy of the string with a quote at the start and end, (but won't
add the quote if there's already one there, so it's safe to call this on strings that
may already have quotes around them).
Note that this is a const method, and won't alter the string itself.
@param quoteCharacter the character to add at the start and end
@see isQuotedString, unquoted
*/
String quoted(juce_wchar quoteCharacter = '"') const;
/** Creates a string which is a version of a string repeated and joined together.
@param stringToRepeat the string to repeat
@param numberOfTimesToRepeat how many times to repeat it
*/
static String repeatedString(StringRef stringToRepeat,
int numberOfTimesToRepeat);
/** Returns a copy of this string with the specified character repeatedly added to its
beginning until the total length is at least the minimum length specified.
*/
String paddedLeft(juce_wchar padCharacter, int minimumLength) const;
/** Returns a copy of this string with the specified character repeatedly added to its
end until the total length is at least the minimum length specified.
*/
String paddedRight(juce_wchar padCharacter, int minimumLength) const;
/** Creates a string from data in an unknown format.
This looks at some binary data and tries to guess whether it's Unicode
or 8-bit characters, then returns a string that represents it correctly.
Should be able to handle Unicode endianness correctly, by looking at
the first two bytes.
*/
static String createStringFromData(const void* data, int size);
/** Creates a String from a printf-style parameter list.
I don't like this method. I don't use it myself, and I recommend avoiding it and
using the operator<< methods or pretty much anything else instead. It's only provided
here because of the popular unrest that was stirred-up when I tried to remove it...
If you're really determined to use it, at least make sure that you never, ever,
pass any String objects to it as parameters. And bear in mind that internally, depending
on the platform, it may be using wchar_t or char character types, so that even string
literals can't be safely used as parameters if you're writing portable code.
*/
template <typename... Args>
static String formatted(const String& formatStr, Args... args) { return formattedRaw(formatStr.toRawUTF8(), args...); }
/** Returns an iterator pointing at the beginning of the string. */
CharPointerType begin() const { return getCharPointer(); }
/** Returns an iterator pointing at the terminating null of the string.
Note that this has to find the terminating null before returning it, so prefer to
call this once before looping and then reuse the result, rather than calling 'end()'
each time through the loop.
@code
String str = ...;
// BEST
for (auto c : str)
DBG (c);
// GOOD
for (auto ptr = str.begin(), end = str.end(); ptr != end; ++ptr)
DBG (*ptr);
std::for_each (str.begin(), str.end(), [] (juce_wchar c) { DBG (c); });
// BAD
for (auto ptr = str.begin(); ptr != str.end(); ++ptr)
DBG (*ptr);
@endcode
*/
CharPointerType end() const { return begin().findTerminatingNull(); }
// Numeric conversions..
/** Creates a string containing this signed 32-bit integer as a decimal number.
@see getIntValue, getFloatValue, getDoubleValue, toHexString
*/
explicit String(int decimalInteger);
/** Creates a string containing this unsigned 32-bit integer as a decimal number.
@see getIntValue, getFloatValue, getDoubleValue, toHexString
*/
explicit String(unsigned int decimalInteger);
/** Creates a string containing this signed 16-bit integer as a decimal number.
@see getIntValue, getFloatValue, getDoubleValue, toHexString
*/
explicit String(short decimalInteger);
/** Creates a string containing this unsigned 16-bit integer as a decimal number.
@see getIntValue, getFloatValue, getDoubleValue, toHexString
*/
explicit String(unsigned short decimalInteger);
/** Creates a string containing this signed 64-bit integer as a decimal number.
@see getLargeIntValue, getFloatValue, getDoubleValue, toHexString
*/
explicit String(int64 largeIntegerValue);
/** Creates a string containing this unsigned 64-bit integer as a decimal number.
@see getLargeIntValue, getFloatValue, getDoubleValue, toHexString
*/
explicit String(uint64 largeIntegerValue);
/** Creates a string containing this signed long integer as a decimal number.
@see getIntValue, getFloatValue, getDoubleValue, toHexString
*/
explicit String(long decimalInteger);
/** Creates a string containing this unsigned long integer as a decimal number.
@see getIntValue, getFloatValue, getDoubleValue, toHexString
*/
explicit String(unsigned long decimalInteger);
/** Creates a string representing this floating-point number.
@param floatValue the value to convert to a string
@see getDoubleValue, getIntValue
*/
explicit String(float floatValue);
/** Creates a string representing this floating-point number.
@param doubleValue the value to convert to a string
@see getFloatValue, getIntValue
*/
explicit String(double doubleValue);
/** Creates a string representing this floating-point number.
@param floatValue the value to convert to a string
@param numberOfDecimalPlaces if this is > 0 the number will be formatted using that many
decimal places, adding trailing zeros as required. If 0 or
less the number will be formatted using the C++ standard
library default format, which uses scientific notation for
large and small numbers.
@param useScientificNotation if the number should be formatted using scientific notation
@see getDoubleValue, getIntValue
*/
String(float floatValue, int numberOfDecimalPlaces, bool useScientificNotation = false);
/** Creates a string representing this floating-point number.
@param doubleValue the value to convert to a string
@param numberOfDecimalPlaces if this is > 0, it will format the number using that many
decimal places, adding trailing zeros as required, and
will not use exponent notation. If 0 or less, it will use
exponent notation if necessary.
@param useScientificNotation if the number should be formatted using scientific notation
@see getFloatValue, getIntValue
*/
String(double doubleValue, int numberOfDecimalPlaces, bool useScientificNotation = false);
#ifndef DOXYGEN
// Automatically creating a String from a bool opens up lots of nasty type conversion edge cases.
// If you want a String representation of a bool you can cast the bool to an int first.
explicit String(bool) = delete;
#endif
/** Reads the value of the string as a decimal number (up to 32 bits in size).
@returns the value of the string as a 32 bit signed base-10 integer.
@see getTrailingIntValue, getHexValue32, getHexValue64
*/
int getIntValue() const noexcept;
/** Reads the value of the string as a decimal number (up to 64 bits in size).
@returns the value of the string as a 64 bit signed base-10 integer.
*/
int64 getLargeIntValue() const noexcept;
/** Parses a decimal number from the end of the string.
This will look for a value at the end of the string.
e.g. for "321 xyz654" it will return 654; for "2 3 4" it'll return 4.
If the string ends with a hyphen followed by numeric characters, the
return value will be negative.
@see getIntValue
*/
int getTrailingIntValue() const noexcept;
/** Parses this string as a floating point number.
@returns the value of the string as a 32-bit floating point value.
@see getDoubleValue
*/
float getFloatValue() const noexcept;
/** Parses this string as a floating point number.
@returns the value of the string as a 64-bit floating point value.
@see getFloatValue
*/
double getDoubleValue() const noexcept;
/** Parses the string as a hexadecimal number.
Non-hexadecimal characters in the string are ignored.
If the string contains too many characters, then the lowest significant
digits are returned, e.g. "ffff12345678" would produce 0x12345678.
@returns a 32-bit number which is the value of the string in hex.
*/
int getHexValue32() const noexcept;
/** Parses the string as a hexadecimal number.
Non-hexadecimal characters in the string are ignored.
If the string contains too many characters, then the lowest significant
digits are returned, e.g. "ffff1234567812345678" would produce 0x1234567812345678.
@returns a 64-bit number which is the value of the string in hex.
*/
int64 getHexValue64() const noexcept;
/** Returns a string representing this numeric value in hexadecimal. */
template <typename IntegerType>
static String toHexString(IntegerType number) { return createHex(number); }
/** Returns a string containing a hex dump of a block of binary data.
@param data the binary data to use as input
@param size how many bytes of data to use
@param groupSize how many bytes are grouped together before inserting a
space into the output. e.g. group size 0 has no spaces,
group size 1 looks like: "be a1 c2 ff", group size 2 looks
like "bea1 c2ff".
*/
static String toHexString(const void* data, int size, int groupSize = 1);
/** Returns a string containing a decimal with a set number of significant figures.
@param number the input number
@param numberOfSignificantFigures the number of significant figures to use
*/
template <typename DecimalType>
static String toDecimalStringWithSignificantFigures(DecimalType number, int numberOfSignificantFigures)
{
jassert(numberOfSignificantFigures > 0);
if (number == 0)
{
if (numberOfSignificantFigures > 1)
{
String result("0.0");
for (int i = 2; i < numberOfSignificantFigures; ++i)
result += "0";
return result;
}
return "0";
}
auto numDigitsBeforePoint = (int)std::ceil(std::log10(number < 0 ? -number : number));
#if JUCE_PROJUCER_LIVE_BUILD
auto doubleNumber = (double)number;
constexpr int bufferSize = 311;
char buffer[bufferSize];
auto* ptr = &(buffer[0]);
auto* const safeEnd = ptr + (bufferSize - 1);
auto numSigFigsParsed = 0;
auto writeToBuffer = [safeEnd](char* destination, char data)
{
*destination++ = data;
if (destination == safeEnd)
{
*destination = '\0';
return true;
}
return false;
};
auto truncateOrRound = [numberOfSignificantFigures](double fractional, int sigFigsParsed)
{
return (sigFigsParsed == numberOfSignificantFigures - 1) ? (int)std::round(fractional)
: (int)fractional;
};
if (doubleNumber < 0)
{
doubleNumber *= -1;
*ptr++ = '-';
}
if (numDigitsBeforePoint > 0)
{
doubleNumber /= std::pow(10.0, numDigitsBeforePoint);
while (numDigitsBeforePoint-- > 0)
{
if (numSigFigsParsed == numberOfSignificantFigures)
{
if (writeToBuffer(ptr++, '0'))
return buffer;
continue;
}
doubleNumber *= 10;
auto digit = truncateOrRound(doubleNumber, numSigFigsParsed);
if (writeToBuffer(ptr++, (char)('0' + digit)))
return buffer;
++numSigFigsParsed;
doubleNumber -= digit;
}
if (numSigFigsParsed == numberOfSignificantFigures)
{
*ptr++ = '\0';
return buffer;
}
}
else
{
*ptr++ = '0';
}
if (writeToBuffer(ptr++, '.'))
return buffer;
while (numSigFigsParsed < numberOfSignificantFigures)
{
doubleNumber *= 10;
auto digit = truncateOrRound(doubleNumber, numSigFigsParsed);
if (writeToBuffer(ptr++, (char)('0' + digit)))
return buffer;
if (numSigFigsParsed != 0 || digit != 0)
++numSigFigsParsed;
doubleNumber -= digit;
}
*ptr++ = '\0';
return buffer;
#else
auto shift = numberOfSignificantFigures - numDigitsBeforePoint;
auto factor = std::pow(10.0, shift);
auto rounded = std::round(number * factor) / factor;
std::stringstream ss;
ss << std::fixed << std::setprecision(std::max(shift, 0)) << rounded;
return ss.str();
#endif
}
/** Returns the character pointer currently being used to store this string.
Because it returns a reference to the string's internal data, the pointer
that is returned must not be stored anywhere, as it can be deleted whenever the
string changes.
*/
CharPointerType getCharPointer() const noexcept { return text; }
/** Returns a pointer to a UTF-8 version of this string.
Because it returns a reference to the string's internal data, the pointer
that is returned must not be stored anywhere, as it can be deleted whenever the
string changes.
To find out how many bytes you need to store this string as UTF-8, you can call
CharPointer_UTF8::getBytesRequiredFor (myString.getCharPointer())
@see toRawUTF8, getCharPointer, toUTF16, toUTF32
*/
CharPointer_UTF8 toUTF8() const;
/** Returns a pointer to a UTF-8 version of this string.
Because it returns a reference to the string's internal data, the pointer
that is returned must not be stored anywhere, as it can be deleted whenever the
string changes.
To find out how many bytes you need to store this string as UTF-8, you can call
CharPointer_UTF8::getBytesRequiredFor (myString.getCharPointer())
@see getCharPointer, toUTF8, toUTF16, toUTF32
*/
const char* toRawUTF8() const;
/** Returns a pointer to a UTF-16 version of this string.
Because it returns a reference to the string's internal data, the pointer
that is returned must not be stored anywhere, as it can be deleted whenever the
string changes.
To find out how many bytes you need to store this string as UTF-16, you can call
CharPointer_UTF16::getBytesRequiredFor (myString.getCharPointer())
@see getCharPointer, toUTF8, toUTF32
*/
CharPointer_UTF16 toUTF16() const;
/** Returns a pointer to a UTF-32 version of this string.
Because it returns a reference to the string's internal data, the pointer
that is returned must not be stored anywhere, as it can be deleted whenever the
string changes.
@see getCharPointer, toUTF8, toUTF16
*/
CharPointer_UTF32 toUTF32() const;
/** Returns a pointer to a wchar_t version of this string.
Because it returns a reference to the string's internal data, the pointer
that is returned must not be stored anywhere, as it can be deleted whenever the
string changes.
Bear in mind that the wchar_t type is different on different platforms, so on
Windows, this will be equivalent to calling toUTF16(), on unix it'll be the same
as calling toUTF32(), etc.
@see getCharPointer, toUTF8, toUTF16, toUTF32
*/
const wchar_t* toWideCharPointer() const;
/** */
std::string toStdString() const;
/** Creates a String from a UTF-8 encoded buffer.
If the size is < 0, it'll keep reading until it hits a zero.
*/
static String fromUTF8(const char* utf8buffer, int bufferSizeBytes = -1);
/** Returns the number of bytes required to represent this string as UTF8.
The number returned does NOT include the trailing zero.
@see toUTF8, copyToUTF8
*/
size_t getNumBytesAsUTF8() const noexcept;
/** Copies the string to a buffer as UTF-8 characters.
Returns the number of bytes copied to the buffer, including the terminating null
character.
To find out how many bytes you need to store this string as UTF-8, you can call
CharPointer_UTF8::getBytesRequiredFor (myString.getCharPointer())
@param destBuffer the place to copy it to; if this is a null pointer, the method just
returns the number of bytes required (including the terminating null character).
@param maxBufferSizeBytes the size of the destination buffer, in bytes. If the string won't fit, it'll
put in as many as it can while still allowing for a terminating null char at the
end, and will return the number of bytes that were actually used.
@see CharPointer_UTF8::writeWithDestByteLimit
*/
size_t copyToUTF8(CharPointer_UTF8::CharType* destBuffer, size_t maxBufferSizeBytes) const noexcept;
/** Copies the string to a buffer as UTF-16 characters.
Returns the number of bytes copied to the buffer, including the terminating null
character.
To find out how many bytes you need to store this string as UTF-16, you can call
CharPointer_UTF16::getBytesRequiredFor (myString.getCharPointer())
@param destBuffer the place to copy it to; if this is a null pointer, the method just
returns the number of bytes required (including the terminating null character).
@param maxBufferSizeBytes the size of the destination buffer, in bytes. If the string won't fit, it'll
put in as many as it can while still allowing for a terminating null char at the
end, and will return the number of bytes that were actually used.
@see CharPointer_UTF16::writeWithDestByteLimit
*/
size_t copyToUTF16(CharPointer_UTF16::CharType* destBuffer, size_t maxBufferSizeBytes) const noexcept;
/** Copies the string to a buffer as UTF-32 characters.
Returns the number of bytes copied to the buffer, including the terminating null
character.
To find out how many bytes you need to store this string as UTF-32, you can call
CharPointer_UTF32::getBytesRequiredFor (myString.getCharPointer())
@param destBuffer the place to copy it to; if this is a null pointer, the method just
returns the number of bytes required (including the terminating null character).
@param maxBufferSizeBytes the size of the destination buffer, in bytes. If the string won't fit, it'll
put in as many as it can while still allowing for a terminating null char at the
end, and will return the number of bytes that were actually used.
@see CharPointer_UTF32::writeWithDestByteLimit
*/
size_t copyToUTF32(CharPointer_UTF32::CharType* destBuffer, size_t maxBufferSizeBytes) const noexcept;
/** Increases the string's internally allocated storage.
Although the string's contents won't be affected by this call, it will
increase the amount of memory allocated internally for the string to grow into.
If you're about to make a large number of calls to methods such
as += or <<, it's more efficient to preallocate enough extra space
beforehand, so that these methods won't have to keep resizing the string
to append the extra characters.
@param numBytesNeeded the number of bytes to allocate storage for. If this
value is less than the currently allocated size, it will
have no effect.
*/
void preallocateBytes(size_t numBytesNeeded);
/** Swaps the contents of this string with another one.
This is a very fast operation, as no allocation or copying needs to be done.
*/
void swapWith(String& other) noexcept;
#if JUCE_MAC || JUCE_IOS || DOXYGEN
/** OSX ONLY - Creates a String from an OSX CFString. */
static String fromCFString(CFStringRef cfString);
/** OSX ONLY - Converts this string to a CFString.
Remember that you must use CFRelease() to free the returned string when you're
finished with it.
*/
CFStringRef toCFString() const;
/** OSX ONLY - Returns a copy of this string in which any decomposed unicode characters have
been converted to their precomposed equivalents. */
String convertToPrecomposedUnicode() const;
#endif
/** Returns the number of String objects which are currently sharing the same internal
data as this one.
*/
int getReferenceCount() const noexcept;
/* This was a static empty string object, but is now deprecated as it's too easy to accidentally
use it indirectly during a static constructor, leading to hard-to-find order-of-initialisation
problems.
@deprecated If you need an empty String object, just use String() or {}.
The only time you might miss having String::empty available might be if you need to return an
empty string from a function by reference, but if you need to do that, it's easy enough to use
a function-local static String object and return that, avoiding any order-of-initialisation issues.
*/
JUCE_DEPRECATED_STATIC(static const String empty;)
private:
CharPointerType text;
struct PreallocationBytes
{
explicit PreallocationBytes(size_t) noexcept;
size_t numBytes;
};
explicit String(const PreallocationBytes&); // This constructor preallocates a certain amount of memory
size_t getByteOffsetOfEnd() const noexcept;
JUCE_DEPRECATED(String(const String&, size_t));
// This private cast operator should prevent strings being accidentally cast
// to bools (this is possible because the compiler can add an implicit cast
// via a const char*)
operator bool() const noexcept { return false; }
static String formattedRaw(const char*, ...);
static String createHex(uint8);
static String createHex(uint16);
static String createHex(uint32);
static String createHex(uint64);
template <typename Type>
static String createHex(Type n) { return createHex(static_cast<typename TypeHelpers::UnsignedTypeWithSize<(int)sizeof(n)>::type> (n)); }
};
/** Concatenates two strings. */
JUCE_API String JUCE_CALLTYPE operator+ (const char* string1, const String& string2);
/** Concatenates two strings. */
JUCE_API String JUCE_CALLTYPE operator+ (const wchar_t* string1, const String& string2);
/** Concatenates two strings. */
JUCE_API String JUCE_CALLTYPE operator+ (char string1, const String& string2);
/** Concatenates two strings. */
JUCE_API String JUCE_CALLTYPE operator+ (wchar_t string1, const String& string2);
#if ! JUCE_NATIVE_WCHAR_IS_UTF32
/** Concatenates two strings. */
JUCE_API String JUCE_CALLTYPE operator+ (juce_wchar string1, const String& string2);
#endif
/** Concatenates two strings. */
JUCE_API String JUCE_CALLTYPE operator+ (String string1, const String& string2);
/** Concatenates two strings. */
JUCE_API String JUCE_CALLTYPE operator+ (String string1, const char* string2);
/** Concatenates two strings. */
JUCE_API String JUCE_CALLTYPE operator+ (String string1, const wchar_t* string2);
/** Concatenates two strings. */
JUCE_API String JUCE_CALLTYPE operator+ (String string1, const std::string& string2);
/** Concatenates two strings. */
JUCE_API String JUCE_CALLTYPE operator+ (String string1, char characterToAppend);
/** Concatenates two strings. */
JUCE_API String JUCE_CALLTYPE operator+ (String string1, wchar_t characterToAppend);
#if ! JUCE_NATIVE_WCHAR_IS_UTF32
/** Concatenates two strings. */
JUCE_API String JUCE_CALLTYPE operator+ (String string1, juce_wchar characterToAppend);
#endif
/** Appends a character at the end of a string. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, char characterToAppend);
/** Appends a character at the end of a string. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, wchar_t characterToAppend);
#if ! JUCE_NATIVE_WCHAR_IS_UTF32
/** Appends a character at the end of a string. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, juce_wchar characterToAppend);
#endif
/** Appends a string to the end of the first one. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, const char* string2);
/** Appends a string to the end of the first one. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, const wchar_t* string2);
/** Appends a string to the end of the first one. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, const String& string2);
/** Appends a string to the end of the first one. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, StringRef string2);
/** Appends a string to the end of the first one. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, const std::string& string2);
/** Appends a decimal number to the end of a string. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, uint8 number);
/** Appends a decimal number to the end of a string. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, short number);
/** Appends a decimal number to the end of a string. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, int number);
/** Appends a decimal number to the end of a string. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, long number);
/** Appends a decimal number to the end of a string. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, unsigned long number);
/** Appends a decimal number to the end of a string. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, int64 number);
/** Appends a decimal number to the end of a string. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, uint64 number);
/** Appends a decimal number to the end of a string. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, float number);
/** Appends a decimal number to the end of a string. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, double number);
#ifndef DOXYGEN
// Automatically creating a String from a bool opens up lots of nasty type conversion edge cases.
// If you want a String representation of a bool you can cast the bool to an int first.
String& JUCE_CALLTYPE operator<< (String&, bool) = delete;
#endif
/** Case-sensitive comparison of two strings. */
JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const String& string2) noexcept;
/** Case-sensitive comparison of two strings. */
JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const char* string2) noexcept;
/** Case-sensitive comparison of two strings. */
JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const wchar_t* string2) noexcept;
/** Case-sensitive comparison of two strings. */
JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, CharPointer_UTF8 string2) noexcept;
/** Case-sensitive comparison of two strings. */
JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, CharPointer_UTF16 string2) noexcept;
/** Case-sensitive comparison of two strings. */
JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, CharPointer_UTF32 string2) noexcept;
/** Case-sensitive comparison of two strings. */
JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const String& string2) noexcept;
/** Case-sensitive comparison of two strings. */
JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const char* string2) noexcept;
/** Case-sensitive comparison of two strings. */
JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const wchar_t* string2) noexcept;
/** Case-sensitive comparison of two strings. */
JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, CharPointer_UTF8 string2) noexcept;
/** Case-sensitive comparison of two strings. */
JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, CharPointer_UTF16 string2) noexcept;
/** Case-sensitive comparison of two strings. */
JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, CharPointer_UTF32 string2) noexcept;
/** This operator allows you to write a juce String directly to std output streams.
This is handy for writing strings to std::cout, std::cerr, etc.
*/
template <class traits>
std::basic_ostream <char, traits>& JUCE_CALLTYPE operator<< (std::basic_ostream <char, traits>& stream, const String& stringToWrite)
{
return stream << stringToWrite.toRawUTF8();
}
/** This operator allows you to write a juce String directly to std output streams.
This is handy for writing strings to std::wcout, std::wcerr, etc.
*/
template <class traits>
std::basic_ostream <wchar_t, traits>& JUCE_CALLTYPE operator<< (std::basic_ostream <wchar_t, traits>& stream, const String& stringToWrite)
{
return stream << stringToWrite.toWideCharPointer();
}
/** Writes a string to an OutputStream as UTF8. */
JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const String& stringToWrite);
/** Writes a string to an OutputStream as UTF8. */
JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, StringRef stringToWrite);
} // namespace juce
#if ! DOXYGEN
namespace std
{
template <> struct hash<juce::String>
{
size_t operator() (const juce::String& s) const noexcept { return s.hash(); }
};
}
#endif
/*** End of inlined file: juce_String.h ***/
/*** Start of inlined file: juce_StringRef.h ***/
namespace juce
{
/**
A simple class for holding temporary references to a string literal or String.
Unlike a real String object, the StringRef does not allocate any memory or
take ownership of the strings you give to it - it simply holds a reference to
a string that has been allocated elsewhere.
The main purpose of the class is to be used instead of a const String& as the type
of function arguments where the caller may pass either a string literal or a String
object. This means that when the called uses a string literal, there's no need
for an temporary String object to be allocated, and this cuts down overheads
substantially.
Because the class is simply a wrapper around a pointer, you should always pass
it by value, not by reference.
@code
void myStringFunction1 (const String&);
void myStringFunction2 (StringRef);
myStringFunction1 ("abc"); // Implicitly allocates a temporary String object.
myStringFunction2 ("abc"); // Much faster, as no local allocations are needed.
@endcode
For examples of it in use, see the XmlElement or StringArray classes.
Bear in mind that there are still many cases where it's better to use an argument
which is a const String&. For example if the function stores the string or needs
to internally create a String from the argument, then it's better for the original
argument to already be a String.
@see String
@tags{Core}
*/
class JUCE_API StringRef final
{
public:
/** Creates a StringRef from a raw string literal.
The StringRef object does NOT take ownership or copy this data, so you must
ensure that the data does not change during the lifetime of the StringRef.
Note that this pointer cannot be null!
*/
StringRef(const char* stringLiteral) noexcept;
/** Creates a StringRef from a raw char pointer.
The StringRef object does NOT take ownership or copy this data, so you must
ensure that the data does not change during the lifetime of the StringRef.
*/
StringRef(String::CharPointerType stringLiteral) noexcept;
/** Creates a StringRef from a String.
The StringRef object does NOT take ownership or copy the data from the String,
so you must ensure that the String is not modified or deleted during the lifetime
of the StringRef.
*/
StringRef(const String& string) noexcept;
/** Creates a StringRef from a String.
The StringRef object does NOT take ownership or copy the data from the std::string,
so you must ensure that the source string object is not modified or deleted during
the lifetime of the StringRef.
*/
StringRef(const std::string& string);
/** Creates a StringRef pointer to an empty string. */
StringRef() noexcept;
/** Returns a raw pointer to the underlying string data. */
operator const String::CharPointerType::CharType* () const noexcept { return text.getAddress(); }
/** Returns a pointer to the underlying string data as a char pointer object. */
operator String::CharPointerType() const noexcept { return text; }
/** Returns true if the string is empty. */
bool isEmpty() const noexcept { return text.isEmpty(); }
/** Returns true if the string is not empty. */
bool isNotEmpty() const noexcept { return !text.isEmpty(); }
/** Returns the number of characters in the string. */
int length() const noexcept { return (int)text.length(); }
/** Retrieves a character by index. */
juce_wchar operator[] (int index) const noexcept { return text[index]; }
/** Compares this StringRef with a String. */
bool operator== (const String& s) const noexcept { return text.compare(s.getCharPointer()) == 0; }
/** Compares this StringRef with a String. */
bool operator!= (const String& s) const noexcept { return text.compare(s.getCharPointer()) != 0; }
/** Compares this StringRef with a String. */
bool operator< (const String& s) const noexcept { return text.compare(s.getCharPointer()) < 0; }
/** Compares this StringRef with a String. */
bool operator<= (const String& s) const noexcept { return text.compare(s.getCharPointer()) <= 0; }
/** Compares this StringRef with a String. */
bool operator> (const String& s) const noexcept { return text.compare(s.getCharPointer()) > 0; }
/** Compares this StringRef with a String. */
bool operator>= (const String& s) const noexcept { return text.compare(s.getCharPointer()) >= 0; }
/** Case-sensitive comparison of two StringRefs. */
bool operator== (StringRef s) const noexcept { return text.compare(s.text) == 0; }
/** Case-sensitive comparison of two StringRefs. */
bool operator!= (StringRef s) const noexcept { return text.compare(s.text) != 0; }
/** The text that is referenced. */
String::CharPointerType text;
#if JUCE_STRING_UTF_TYPE != 8 && ! defined (DOXYGEN)
// Sorry, non-UTF8 people, you're unable to take advantage of StringRef, because
// you've chosen a character encoding that doesn't match C++ string literals.
String stringCopy;
#endif
};
/** Case-sensitive comparison of two strings. */
JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, StringRef string2) noexcept;
/** Case-sensitive comparison of two strings. */
JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, StringRef string2) noexcept;
/** Case-sensitive comparison of two strings. */
JUCE_API bool JUCE_CALLTYPE operator< (const String& string1, StringRef string2) noexcept;
/** Case-sensitive comparison of two strings. */
JUCE_API bool JUCE_CALLTYPE operator<= (const String& string1, StringRef string2) noexcept;
/** Case-sensitive comparison of two strings. */
JUCE_API bool JUCE_CALLTYPE operator> (const String& string1, StringRef string2) noexcept;
/** Case-sensitive comparison of two strings. */
JUCE_API bool JUCE_CALLTYPE operator>= (const String& string1, StringRef string2) noexcept;
inline String operator+ (String s1, StringRef s2) { return s1 += String(s2.text); }
inline String operator+ (StringRef s1, const String& s2) { return String(s1.text) + s2; }
inline String operator+ (const char* s1, StringRef s2) { return String(s1) + String(s2.text); }
inline String operator+ (StringRef s1, const char* s2) { return String(s1.text) + String(s2); }
} // namespace juce
/*** End of inlined file: juce_StringRef.h ***/
/*** Start of inlined file: juce_Logger.h ***/
namespace juce
{
/**
Acts as an application-wide logging class.
A subclass of Logger can be created and passed into the Logger::setCurrentLogger
method and this will then be used by all calls to writeToLog.
The logger class also contains methods for writing messages to the debugger's
output stream.
@see FileLogger
@tags{Core}
*/
class JUCE_API Logger
{
public:
/** Destructor. */
virtual ~Logger();
/** Sets the current logging class to use.
Note that the object passed in will not be owned or deleted by the logger, so
the caller must make sure that it is not deleted while still being used.
A null pointer can be passed-in to reset the system to the default logger.
*/
static void JUCE_CALLTYPE setCurrentLogger(Logger* newLogger) noexcept;
/** Returns the current logger, or nullptr if no custom logger has been set. */
static Logger* JUCE_CALLTYPE getCurrentLogger() noexcept;
/** Writes a string to the current logger.
This will pass the string to the logger's logMessage() method if a logger
has been set.
@see logMessage
*/
static void JUCE_CALLTYPE writeToLog(const String& message);
/** Writes a message to the standard error stream.
This can be called directly, or by using the DBG() macro in
juce_PlatformDefs.h (which will avoid calling the method in non-debug builds).
*/
static void JUCE_CALLTYPE outputDebugString(const String& text);
protected:
Logger();
/** This is overloaded by subclasses to implement custom logging behaviour.
@see setCurrentLogger
*/
virtual void logMessage(const String& message) = 0;
private:
static Logger* currentLogger;
};
} // namespace juce
/*** End of inlined file: juce_Logger.h ***/
/*** Start of inlined file: juce_LeakedObjectDetector.h ***/
namespace juce
{
/**
Embedding an instance of this class inside another class can be used as a low-overhead
way of detecting leaked instances.
This class keeps an internal static count of the number of instances that are
active, so that when the app is shutdown and the static destructors are called,
it can check whether there are any left-over instances that may have been leaked.
To use it, use the JUCE_LEAK_DETECTOR macro as a simple way to put one in your
class declaration. Have a look through the juce codebase for examples, it's used
in most of the classes.
@tags{Core}
*/
template <class OwnerClass>
class LeakedObjectDetector
{
public:
LeakedObjectDetector() noexcept { ++(getCounter().numObjects); }
LeakedObjectDetector(const LeakedObjectDetector&) noexcept { ++(getCounter().numObjects); }
LeakedObjectDetector& operator= (const LeakedObjectDetector&) noexcept = default;
~LeakedObjectDetector()
{
if (--(getCounter().numObjects) < 0)
{
DBG("*** Dangling pointer deletion! Class: " << getLeakedObjectClassName());
/** If you hit this, then you've managed to delete more instances of this class than you've
created.. That indicates that you're deleting some dangling pointers.
Note that although this assertion will have been triggered during a destructor, it might
not be this particular deletion that's at fault - the incorrect one may have happened
at an earlier point in the program, and simply not been detected until now.
Most errors like this are caused by using old-fashioned, non-RAII techniques for
your object management. Tut, tut. Always, always use std::unique_ptrs, OwnedArrays,
ReferenceCountedObjects, etc, and avoid the 'delete' operator at all costs!
*/
jassertfalse;
}
}
private:
class LeakCounter
{
public:
LeakCounter() = default;
~LeakCounter()
{
if (numObjects.value > 0)
{
DBG("*** Leaked objects detected: " << numObjects.value << " instance(s) of class " << getLeakedObjectClassName());
/** If you hit this, then you've leaked one or more objects of the type specified by
the 'OwnerClass' template parameter - the name should have been printed by the line above.
If you're leaking, it's probably because you're using old-fashioned, non-RAII techniques for
your object management. Tut, tut. Always, always use std::unique_ptrs, OwnedArrays,
ReferenceCountedObjects, etc, and avoid the 'delete' operator at all costs!
*/
jassertfalse;
}
}
Atomic<int> numObjects;
};
static const char* getLeakedObjectClassName()
{
return OwnerClass::getLeakedObjectClassName();
}
static LeakCounter& getCounter() noexcept
{
static LeakCounter counter;
return counter;
}
};
#if DOXYGEN || ! defined (JUCE_LEAK_DETECTOR)
#if (DOXYGEN || JUCE_CHECK_MEMORY_LEAKS)
/** This macro lets you embed a leak-detecting object inside a class.
To use it, simply declare a JUCE_LEAK_DETECTOR(YourClassName) inside a private section
of the class declaration. E.g.
@code
class MyClass
{
public:
MyClass();
void blahBlah();
private:
JUCE_LEAK_DETECTOR (MyClass)
};
@endcode
@see JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR, LeakedObjectDetector
*/
#define JUCE_LEAK_DETECTOR(OwnerClass) \
friend class juce::LeakedObjectDetector<OwnerClass>; \
static const char* getLeakedObjectClassName() noexcept { return #OwnerClass; } \
juce::LeakedObjectDetector<OwnerClass> JUCE_JOIN_MACRO (leakDetector, __LINE__);
#else
#define JUCE_LEAK_DETECTOR(OwnerClass)
#endif
#endif
} // namespace juce
/*** End of inlined file: juce_LeakedObjectDetector.h ***/
/*** Start of inlined file: juce_ContainerDeletePolicy.h ***/
namespace juce
{
/**
Used by container classes as an indirect way to delete an object of a
particular type.
The generic implementation of this class simply calls 'delete', but you can
create a specialised version of it for a particular class if you need to
delete that type of object in a more appropriate way.
@see OwnedArray
@tags{Core}
*/
template <typename ObjectType>
struct ContainerDeletePolicy
{
static void destroy(ObjectType* object)
{
// If the line below triggers a compiler error, it means that you are using
// an incomplete type for ObjectType (for example, a type that is declared
// but not defined). This is a problem because then the following delete is
// undefined behaviour. The purpose of the sizeof is to capture this situation.
// If this was caused by a OwnedArray of a forward-declared type, move the
// implementation of all methods trying to use the OwnedArray (e.g. the destructor
// of the class owning it) into cpp files where they can see to the definition
// of ObjectType. This should fix the error.
ignoreUnused(sizeof(ObjectType));
delete object;
}
};
} // namespace juce
/*** End of inlined file: juce_ContainerDeletePolicy.h ***/
/*** Start of inlined file: juce_HeapBlock.h ***/
namespace juce
{
#if ! (defined (DOXYGEN) || JUCE_EXCEPTIONS_DISABLED)
namespace HeapBlockHelper
{
template <bool shouldThrow>
struct ThrowOnFail { static void checkPointer(void*) {} };
template <>
struct ThrowOnFail<true> { static void checkPointer(void* data) { if (data == nullptr) throw std::bad_alloc(); } };
}
#endif
/**
Very simple container class to hold a pointer to some data on the heap.
When you need to allocate some heap storage for something, always try to use
this class instead of allocating the memory directly using malloc/free.
A HeapBlock<char> object can be treated in pretty much exactly the same way
as an char*, but as long as you allocate it on the stack or as a class member,
it's almost impossible for it to leak memory.
It also makes your code much more concise and readable than doing the same thing
using direct allocations,
E.g. instead of this:
@code
int* temp = (int*) malloc (1024 * sizeof (int));
memcpy (temp, xyz, 1024 * sizeof (int));
free (temp);
temp = (int*) calloc (2048 * sizeof (int));
temp[0] = 1234;
memcpy (foobar, temp, 2048 * sizeof (int));
free (temp);
@endcode
..you could just write this:
@code
HeapBlock<int> temp (1024);
memcpy (temp, xyz, 1024 * sizeof (int));
temp.calloc (2048);
temp[0] = 1234;
memcpy (foobar, temp, 2048 * sizeof (int));
@endcode
The class is extremely lightweight, containing only a pointer to the
data, and exposes malloc/realloc/calloc/free methods that do the same jobs
as their less object-oriented counterparts. Despite adding safety, you probably
won't sacrifice any performance by using this in place of normal pointers.
The throwOnFailure template parameter can be set to true if you'd like the class
to throw a std::bad_alloc exception when an allocation fails. If this is false,
then a failed allocation will just leave the heapblock with a null pointer (assuming
that the system's malloc() function doesn't throw).
@see Array, OwnedArray, MemoryBlock
@tags{Core}
*/
template <class ElementType, bool throwOnFailure = false>
class HeapBlock
{
private:
template <class OtherElementType>
using AllowConversion = typename std::enable_if<std::is_base_of<typename std::remove_pointer<ElementType>::type,
typename std::remove_pointer<OtherElementType>::type>::value>::type;
public:
/** Creates a HeapBlock which is initially just a null pointer.
After creation, you can resize the array using the malloc(), calloc(),
or realloc() methods.
*/
HeapBlock() = default;
/** Creates a HeapBlock containing a number of elements.
The contents of the block are undefined, as it will have been created by a
malloc call.
If you want an array of zero values, you can use the calloc() method or the
other constructor that takes an InitialisationState parameter.
*/
template <typename SizeType>
explicit HeapBlock(SizeType numElements)
: data(static_cast<ElementType*> (std::malloc(static_cast<size_t> (numElements) * sizeof(ElementType))))
{
throwOnAllocationFailure();
}
/** Creates a HeapBlock containing a number of elements.
The initialiseToZero parameter determines whether the new memory should be cleared,
or left uninitialised.
*/
template <typename SizeType>
HeapBlock(SizeType numElements, bool initialiseToZero)
: data(static_cast<ElementType*> (initialiseToZero
? std::calloc(static_cast<size_t> (numElements), sizeof(ElementType))
: std::malloc(static_cast<size_t> (numElements) * sizeof(ElementType))))
{
throwOnAllocationFailure();
}
/** Destructor.
This will free the data, if any has been allocated.
*/
~HeapBlock()
{
std::free(data);
}
/** Move constructor */
HeapBlock(HeapBlock&& other) noexcept
: data(other.data)
{
other.data = nullptr;
}
/** Move assignment operator */
HeapBlock& operator= (HeapBlock&& other) noexcept
{
std::swap(data, other.data);
return *this;
}
/** Converting move constructor.
Only enabled if this is a HeapBlock<Base*> and the other object is a HeapBlock<Derived*>,
where std::is_base_of<Base, Derived>::value == true.
*/
template <class OtherElementType, bool otherThrowOnFailure, typename = AllowConversion<OtherElementType>>
HeapBlock(HeapBlock<OtherElementType, otherThrowOnFailure>&& other) noexcept
: data(reinterpret_cast<ElementType*> (other.data))
{
other.data = nullptr;
}
/** Converting move assignment operator.
Only enabled if this is a HeapBlock<Base*> and the other object is a HeapBlock<Derived*>,
where std::is_base_of<Base, Derived>::value == true.
*/
template <class OtherElementType, bool otherThrowOnFailure, typename = AllowConversion<OtherElementType>>
HeapBlock& operator= (HeapBlock<OtherElementType, otherThrowOnFailure>&& other) noexcept
{
free();
data = reinterpret_cast<ElementType*> (other.data);
other.data = nullptr;
return *this;
}
/** Returns a raw pointer to the allocated data.
This may be a null pointer if the data hasn't yet been allocated, or if it has been
freed by calling the free() method.
*/
inline operator ElementType* () const noexcept { return data; }
/** Returns a raw pointer to the allocated data.
This may be a null pointer if the data hasn't yet been allocated, or if it has been
freed by calling the free() method.
*/
inline ElementType* get() const noexcept { return data; }
/** Returns a raw pointer to the allocated data.
This may be a null pointer if the data hasn't yet been allocated, or if it has been
freed by calling the free() method.
*/
inline ElementType* getData() const noexcept { return data; }
/** Returns a void pointer to the allocated data.
This may be a null pointer if the data hasn't yet been allocated, or if it has been
freed by calling the free() method.
*/
inline operator void* () const noexcept { return static_cast<void*> (data); }
/** Returns a void pointer to the allocated data.
This may be a null pointer if the data hasn't yet been allocated, or if it has been
freed by calling the free() method.
*/
inline operator const void* () const noexcept { return static_cast<const void*> (data); }
/** Lets you use indirect calls to the first element in the array.
Obviously this will cause problems if the array hasn't been initialised, because it'll
be referencing a null pointer.
*/
inline ElementType* operator->() const noexcept { return data; }
/** Returns a reference to one of the data elements.
Obviously there's no bounds-checking here, as this object is just a dumb pointer and
has no idea of the size it currently has allocated.
*/
template <typename IndexType>
ElementType& operator[] (IndexType index) const noexcept { return data[index]; }
/** Returns a pointer to a data element at an offset from the start of the array.
This is the same as doing pointer arithmetic on the raw pointer itself.
*/
template <typename IndexType>
ElementType* operator+ (IndexType index) const noexcept { return data + index; }
/** Compares the pointer with another pointer.
This can be handy for checking whether this is a null pointer.
*/
inline bool operator== (const ElementType* otherPointer) const noexcept { return otherPointer == data; }
/** Compares the pointer with another pointer.
This can be handy for checking whether this is a null pointer.
*/
inline bool operator!= (const ElementType* otherPointer) const noexcept { return otherPointer != data; }
/** Allocates a specified amount of memory.
This uses the normal malloc to allocate an amount of memory for this object.
Any previously allocated memory will be freed by this method.
The number of bytes allocated will be (newNumElements * elementSize). Normally
you wouldn't need to specify the second parameter, but it can be handy if you need
to allocate a size in bytes rather than in terms of the number of elements.
The data that is allocated will be freed when this object is deleted, or when you
call free() or any of the allocation methods.
*/
template <typename SizeType>
void malloc(SizeType newNumElements, size_t elementSize = sizeof(ElementType))
{
std::free(data);
data = static_cast<ElementType*> (std::malloc(static_cast<size_t> (newNumElements) * elementSize));
throwOnAllocationFailure();
}
/** Allocates a specified amount of memory and clears it.
This does the same job as the malloc() method, but clears the memory that it allocates.
*/
template <typename SizeType>
void calloc(SizeType newNumElements, const size_t elementSize = sizeof(ElementType))
{
std::free(data);
data = static_cast<ElementType*> (std::calloc(static_cast<size_t> (newNumElements), elementSize));
throwOnAllocationFailure();
}
/** Allocates a specified amount of memory and optionally clears it.
This does the same job as either malloc() or calloc(), depending on the
initialiseToZero parameter.
*/
template <typename SizeType>
void allocate(SizeType newNumElements, bool initialiseToZero)
{
std::free(data);
data = static_cast<ElementType*> (initialiseToZero
? std::calloc(static_cast<size_t> (newNumElements), sizeof(ElementType))
: std::malloc(static_cast<size_t> (newNumElements) * sizeof(ElementType)));
throwOnAllocationFailure();
}
/** Re-allocates a specified amount of memory.
The semantics of this method are the same as malloc() and calloc(), but it
uses realloc() to keep as much of the existing data as possible.
*/
template <typename SizeType>
void realloc(SizeType newNumElements, size_t elementSize = sizeof(ElementType))
{
data = static_cast<ElementType*> (data == nullptr ? std::malloc(static_cast<size_t> (newNumElements) * elementSize)
: std::realloc(data, static_cast<size_t> (newNumElements) * elementSize));
throwOnAllocationFailure();
}
/** Frees any currently-allocated data.
This will free the data and reset this object to be a null pointer.
*/
void free() noexcept
{
std::free(data);
data = nullptr;
}
/** Swaps this object's data with the data of another HeapBlock.
The two objects simply exchange their data pointers.
*/
template <bool otherBlockThrows>
void swapWith(HeapBlock<ElementType, otherBlockThrows>& other) noexcept
{
std::swap(data, other.data);
}
/** This fills the block with zeros, up to the number of elements specified.
Since the block has no way of knowing its own size, you must make sure that the number of
elements you specify doesn't exceed the allocated size.
*/
template <typename SizeType>
void clear(SizeType numElements) noexcept
{
zeromem(data, sizeof(ElementType) * static_cast<size_t> (numElements));
}
/** This typedef can be used to get the type of the heapblock's elements. */
using Type = ElementType;
private:
ElementType* data = nullptr;
void throwOnAllocationFailure() const
{
#if JUCE_EXCEPTIONS_DISABLED
jassert(data != nullptr); // without exceptions, you'll need to find a better way to handle this failure case.
#else
HeapBlockHelper::ThrowOnFail<throwOnFailure>::checkPointer(data);
#endif
}
template <class OtherElementType, bool otherThrowOnFailure>
friend class HeapBlock;
#if ! (defined (JUCE_DLL) || defined (JUCE_DLL_BUILD))
JUCE_DECLARE_NON_COPYABLE(HeapBlock)
JUCE_PREVENT_HEAP_ALLOCATION // Creating a 'new HeapBlock' would be missing the point!
#endif
};
} // namespace juce
/*** End of inlined file: juce_HeapBlock.h ***/
/*** Start of inlined file: juce_MemoryBlock.h ***/
namespace juce
{
/**
A class to hold a resizable block of raw data.
@tags{Core}
*/
class JUCE_API MemoryBlock
{
public:
/** Create an uninitialised block with 0 size. */
MemoryBlock() noexcept;
/** Creates a memory block with a given initial size.
@param initialSize the size of block to create
@param initialiseToZero whether to clear the memory or just leave it uninitialised
*/
MemoryBlock(const size_t initialSize,
bool initialiseToZero = false);
/** Creates a copy of another memory block. */
MemoryBlock(const MemoryBlock&);
/** Creates a memory block using a copy of a block of data.
@param dataToInitialiseFrom some data to copy into this block
@param sizeInBytes how much space to use
*/
MemoryBlock(const void* dataToInitialiseFrom, size_t sizeInBytes);
/** Destructor. */
~MemoryBlock() noexcept;
/** Copies another memory block onto this one.
This block will be resized and copied to exactly match the other one.
*/
MemoryBlock& operator= (const MemoryBlock&);
/** Move constructor */
MemoryBlock(MemoryBlock&&) noexcept;
/** Move assignment operator */
MemoryBlock& operator= (MemoryBlock&&) noexcept;
/** Compares two memory blocks.
@returns true only if the two blocks are the same size and have identical contents.
*/
bool operator== (const MemoryBlock& other) const noexcept;
/** Compares two memory blocks.
@returns true if the two blocks are different sizes or have different contents.
*/
bool operator!= (const MemoryBlock& other) const noexcept;
/** Returns true if the data in this MemoryBlock matches the raw bytes passed-in. */
bool matches(const void* data, size_t dataSize) const noexcept;
/** Returns a void pointer to the data.
Note that the pointer returned will probably become invalid when the
block is resized.
*/
void* getData() noexcept { return data; }
/** Returns a void pointer to the data.
Note that the pointer returned will probably become invalid when the
block is resized.
*/
const void* getData() const noexcept { return data; }
/** Returns a byte from the memory block.
This returns a reference, so you can also use it to set a byte.
*/
template <typename Type>
char& operator[] (const Type offset) noexcept { return data[offset]; }
/** Returns a byte from the memory block. */
template <typename Type>
const char& operator[] (const Type offset) const noexcept { return data[offset]; }
/** Returns an iterator for the data. */
char* begin() noexcept { return data; }
/** Returns an iterator for the data. */
const char* begin() const noexcept { return data; }
/** Returns an end-iterator for the data. */
char* end() noexcept { return begin() + getSize(); }
/** Returns an end-iterator for the data. */
const char* end() const noexcept { return begin() + getSize(); }
/** Returns the block's current allocated size, in bytes. */
size_t getSize() const noexcept { return size; }
/** Resizes the memory block.
Any data that is present in both the old and new sizes will be retained.
When enlarging the block, the new space that is allocated at the end can either be
cleared, or left uninitialised.
@param newSize the new desired size for the block
@param initialiseNewSpaceToZero if the block gets enlarged, this determines
whether to clear the new section or just leave it
uninitialised
@see ensureSize
*/
void setSize(const size_t newSize,
bool initialiseNewSpaceToZero = false);
/** Increases the block's size only if it's smaller than a given size.
@param minimumSize if the block is already bigger than this size, no action
will be taken; otherwise it will be increased to this size
@param initialiseNewSpaceToZero if the block gets enlarged, this determines
whether to clear the new section or just leave it
uninitialised
@see setSize
*/
void ensureSize(const size_t minimumSize,
bool initialiseNewSpaceToZero = false);
/** Frees all the blocks data, setting its size to 0. */
void reset();
/** Fills the entire memory block with a repeated byte value.
This is handy for clearing a block of memory to zero.
*/
void fillWith(uint8 valueToUse) noexcept;
/** Adds another block of data to the end of this one.
The data pointer must not be null. This block's size will be increased accordingly.
*/
void append(const void* data, size_t numBytes);
/** Resizes this block to the given size and fills its contents from the supplied buffer.
The data pointer must not be null.
*/
void replaceWith(const void* data, size_t numBytes);
/** Inserts some data into the block.
The dataToInsert pointer must not be null. This block's size will be increased accordingly.
If the insert position lies outside the valid range of the block, it will be clipped to
within the range before being used.
*/
void insert(const void* dataToInsert, size_t numBytesToInsert, size_t insertPosition);
/** Chops out a section of the block.
This will remove a section of the memory block and close the gap around it,
shifting any subsequent data downwards and reducing the size of the block.
If the range specified goes beyond the size of the block, it will be clipped.
*/
void removeSection(size_t startByte, size_t numBytesToRemove);
/** Copies data into this MemoryBlock from a memory address.
@param srcData the memory location of the data to copy into this block
@param destinationOffset the offset in this block at which the data being copied should begin
@param numBytes how much to copy in (if this goes beyond the size of the memory block,
it will be clipped so not to do anything nasty)
*/
void copyFrom(const void* srcData,
int destinationOffset,
size_t numBytes) noexcept;
/** Copies data from this MemoryBlock to a memory address.
@param destData the memory location to write to
@param sourceOffset the offset within this block from which the copied data will be read
@param numBytes how much to copy (if this extends beyond the limits of the memory block,
zeros will be used for that portion of the data)
*/
void copyTo(void* destData,
int sourceOffset,
size_t numBytes) const noexcept;
/** Exchanges the contents of this and another memory block.
No actual copying is required for this, so it's very fast.
*/
void swapWith(MemoryBlock& other) noexcept;
/** Attempts to parse the contents of the block as a zero-terminated UTF8 string. */
String toString() const;
/** Parses a string of hexadecimal numbers and writes this data into the memory block.
The block will be resized to the number of valid bytes read from the string.
Non-hex characters in the string will be ignored.
@see String::toHexString()
*/
void loadFromHexString(StringRef sourceHexString);
/** Sets a number of bits in the memory block, treating it as a long binary sequence. */
void setBitRange(size_t bitRangeStart,
size_t numBits,
int binaryNumberToApply) noexcept;
/** Reads a number of bits from the memory block, treating it as one long binary sequence */
int getBitRange(size_t bitRangeStart,
size_t numBitsToRead) const noexcept;
/** Returns a string of characters in a JUCE-specific text encoding that represents the
binary contents of this block.
This uses a JUCE-specific (i.e. not standard!) 64-bit encoding system to convert binary
data into a string of ASCII characters for purposes like storage in XML.
Note that this proprietary format is mainly kept here for backwards-compatibility, and
you may prefer to use the Base64::toBase64() method if you want to use the standard
base-64 encoding.
@see fromBase64Encoding, Base64::toBase64, Base64::convertToBase64
*/
String toBase64Encoding() const;
/** Takes a string created by MemoryBlock::toBase64Encoding() and extracts the original data.
The string passed in must have been created by to64BitEncoding(), and this
block will be resized to recreate the original data block.
Note that these methods use a JUCE-specific (i.e. not standard!) 64-bit encoding system.
You may prefer to use the Base64::convertFromBase64() method if you want to use the
standard base-64 encoding.
@see toBase64Encoding, Base64::convertFromBase64
*/
bool fromBase64Encoding(StringRef encodedString);
private:
using HeapBlockType = HeapBlock<char, true>;
HeapBlockType data;
size_t size = 0;
JUCE_LEAK_DETECTOR(MemoryBlock)
};
} // namespace juce
/*** End of inlined file: juce_MemoryBlock.h ***/
/*** Start of inlined file: juce_ReferenceCountedObject.h ***/
namespace juce
{
/**
A base class which provides methods for reference-counting.
To add reference-counting to a class, derive it from this class, and
use the ReferenceCountedObjectPtr class to point to it.
e.g. @code
class MyClass : public ReferenceCountedObject
{
void foo();
// This is a neat way of declaring a typedef for a pointer class,
// rather than typing out the full templated name each time..
using Ptr = ReferenceCountedObjectPtr<MyClass>;
};
MyClass::Ptr p = new MyClass();
MyClass::Ptr p2 = p;
p = nullptr;
p2->foo();
@endcode
Once a new ReferenceCountedObject has been assigned to a pointer, be
careful not to delete the object manually.
This class uses an Atomic<int> value to hold the reference count, so
the reference count can be updated on multiple threads. Note that
whilst it's thread-safe to create and delete a ReferenceCountedObjectPtr
to a ReferenceCountedObject shared between threads, it's not thread-safe
to modify or swap the ReferenceCountedObject.
For a faster but non-thread-safe version, use SingleThreadedReferenceCountedObject
instead.
@see ReferenceCountedObjectPtr, ReferenceCountedArray, SingleThreadedReferenceCountedObject
@tags{Core}
*/
class JUCE_API ReferenceCountedObject
{
public:
/** Increments the object's reference count.
This is done automatically by the smart pointer, but is public just
in case it's needed for nefarious purposes.
*/
void incReferenceCount() noexcept
{
++refCount;
}
/** Decreases the object's reference count.
If the count gets to zero, the object will be deleted.
*/
void decReferenceCount() noexcept
{
jassert(getReferenceCount() > 0);
if (--refCount == 0)
delete this;
}
/** Decreases the object's reference count.
If the count gets to zero, the object will not be deleted, but this method
will return true, allowing the caller to take care of deletion.
*/
bool decReferenceCountWithoutDeleting() noexcept
{
jassert(getReferenceCount() > 0);
return --refCount == 0;
}
/** Returns the object's current reference count. */
int getReferenceCount() const noexcept { return refCount.get(); }
protected:
/** Creates the reference-counted object (with an initial ref count of zero). */
ReferenceCountedObject() = default;
/** Copying from another object does not affect this one's reference-count. */
ReferenceCountedObject(const ReferenceCountedObject&) noexcept {}
/** Copying from another object does not affect this one's reference-count. */
ReferenceCountedObject(ReferenceCountedObject&&) noexcept {}
/** Copying from another object does not affect this one's reference-count. */
ReferenceCountedObject& operator= (const ReferenceCountedObject&) noexcept { return *this; }
/** Copying from another object does not affect this one's reference-count. */
ReferenceCountedObject& operator= (ReferenceCountedObject&&) noexcept { return *this; }
/** Destructor. */
virtual ~ReferenceCountedObject()
{
// it's dangerous to delete an object that's still referenced by something else!
jassert(getReferenceCount() == 0);
}
/** Resets the reference count to zero without deleting the object.
You should probably never need to use this!
*/
void resetReferenceCount() noexcept
{
refCount = 0;
}
private:
Atomic<int> refCount{ 0 };
friend struct ContainerDeletePolicy<ReferenceCountedObject>;
};
/**
Adds reference-counting to an object.
This is effectively a version of the ReferenceCountedObject class, but which
uses a non-atomic counter, and so is not thread-safe (but which will be more
efficient).
For more details on how to use it, see the ReferenceCountedObject class notes.
@see ReferenceCountedObject, ReferenceCountedObjectPtr, ReferenceCountedArray
@tags{Core}
*/
class JUCE_API SingleThreadedReferenceCountedObject
{
public:
/** Increments the object's reference count.
This is done automatically by the smart pointer, but is public just
in case it's needed for nefarious purposes.
*/
void incReferenceCount() noexcept
{
++refCount;
}
/** Decreases the object's reference count.
If the count gets to zero, the object will be deleted.
*/
void decReferenceCount() noexcept
{
jassert(getReferenceCount() > 0);
if (--refCount == 0)
delete this;
}
/** Decreases the object's reference count.
If the count gets to zero, the object will not be deleted, but this method
will return true, allowing the caller to take care of deletion.
*/
bool decReferenceCountWithoutDeleting() noexcept
{
jassert(getReferenceCount() > 0);
return --refCount == 0;
}
/** Returns the object's current reference count. */
int getReferenceCount() const noexcept { return refCount; }
protected:
/** Creates the reference-counted object (with an initial ref count of zero). */
SingleThreadedReferenceCountedObject() = default;
/** Copying from another object does not affect this one's reference-count. */
SingleThreadedReferenceCountedObject(const SingleThreadedReferenceCountedObject&) {}
/** Copying from another object does not affect this one's reference-count. */
SingleThreadedReferenceCountedObject(SingleThreadedReferenceCountedObject&&) {}
/** Copying from another object does not affect this one's reference-count. */
SingleThreadedReferenceCountedObject& operator= (const SingleThreadedReferenceCountedObject&) { return *this; }
/** Copying from another object does not affect this one's reference-count. */
SingleThreadedReferenceCountedObject& operator= (SingleThreadedReferenceCountedObject&&) { return *this; }
/** Destructor. */
virtual ~SingleThreadedReferenceCountedObject()
{
// it's dangerous to delete an object that's still referenced by something else!
jassert(getReferenceCount() == 0);
}
private:
int refCount = 0;
friend struct ContainerDeletePolicy<ReferenceCountedObject>;
};
/**
A smart-pointer class which points to a reference-counted object.
The template parameter specifies the class of the object you want to point to - the easiest
way to make a class reference-countable is to simply make it inherit from ReferenceCountedObject
or SingleThreadedReferenceCountedObject, but if you need to, you can roll your own reference-countable
class by implementing a set of methods called incReferenceCount(), decReferenceCount(), and
decReferenceCountWithoutDeleting(). See ReferenceCountedObject for examples of how these methods
should behave.
When using this class, you'll probably want to create a typedef to abbreviate the full
templated name - e.g.
@code
struct MyClass : public ReferenceCountedObject
{
using Ptr = ReferenceCountedObjectPtr<MyClass>;
...
}
@endcode
@see ReferenceCountedObject, ReferenceCountedObjectArray
@tags{Core}
*/
template <class ObjectType>
class ReferenceCountedObjectPtr
{
public:
/** The class being referenced by this pointer. */
using ReferencedType = ObjectType;
/** Creates a pointer to a null object. */
ReferenceCountedObjectPtr() = default;
/** Creates a pointer to a null object. */
ReferenceCountedObjectPtr(decltype (nullptr)) noexcept {}
/** Creates a pointer to an object.
This will increment the object's reference-count.
*/
ReferenceCountedObjectPtr(ReferencedType* refCountedObject) noexcept
: referencedObject(refCountedObject)
{
incIfNotNull(refCountedObject);
}
/** Creates a pointer to an object.
This will increment the object's reference-count.
*/
ReferenceCountedObjectPtr(ReferencedType& refCountedObject) noexcept
: referencedObject(&refCountedObject)
{
refCountedObject.incReferenceCount();
}
/** Copies another pointer.
This will increment the object's reference-count.
*/
ReferenceCountedObjectPtr(const ReferenceCountedObjectPtr& other) noexcept
: referencedObject(other.referencedObject)
{
incIfNotNull(referencedObject);
}
/** Takes-over the object from another pointer. */
ReferenceCountedObjectPtr(ReferenceCountedObjectPtr&& other) noexcept
: referencedObject(other.referencedObject)
{
other.referencedObject = nullptr;
}
/** Copies another pointer.
This will increment the object's reference-count (if it is non-null).
*/
template <typename Convertible>
ReferenceCountedObjectPtr(const ReferenceCountedObjectPtr<Convertible>& other) noexcept
: referencedObject(other.get())
{
incIfNotNull(referencedObject);
}
/** Changes this pointer to point at a different object.
The reference count of the old object is decremented, and it might be
deleted if it hits zero. The new object's count is incremented.
*/
ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr& other)
{
return operator= (other.referencedObject);
}
/** Changes this pointer to point at a different object.
The reference count of the old object is decremented, and it might be
deleted if it hits zero. The new object's count is incremented.
*/
template <typename Convertible>
ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr<Convertible>& other)
{
return operator= (other.get());
}
/** Changes this pointer to point at a different object.
The reference count of the old object is decremented, and it might be
deleted if it hits zero. The new object's count is incremented.
*/
ReferenceCountedObjectPtr& operator= (ReferencedType* newObject)
{
if (newObject != nullptr)
return operator= (*newObject);
reset();
return *this;
}
/** Changes this pointer to point at a different object.
The reference count of the old object is decremented, and it might be
deleted if it hits zero. The new object's count is incremented.
*/
ReferenceCountedObjectPtr& operator= (ReferencedType& newObject)
{
if (referencedObject != &newObject)
{
newObject.incReferenceCount();
auto* oldObject = referencedObject;
referencedObject = &newObject;
decIfNotNull(oldObject);
}
return *this;
}
/** Resets this pointer to a null pointer. */
ReferenceCountedObjectPtr& operator= (decltype (nullptr))
{
reset();
return *this;
}
/** Takes-over the object from another pointer. */
ReferenceCountedObjectPtr& operator= (ReferenceCountedObjectPtr&& other) noexcept
{
std::swap(referencedObject, other.referencedObject);
return *this;
}
/** Destructor.
This will decrement the object's reference-count, which will cause the
object to be deleted when the ref-count hits zero.
*/
~ReferenceCountedObjectPtr()
{
decIfNotNull(referencedObject);
}
/** Returns the object that this pointer references.
The pointer returned may be null, of course.
*/
ReferencedType* get() const noexcept { return referencedObject; }
/** Resets this object to a null pointer. */
void reset() noexcept
{
auto oldObject = referencedObject; // need to null the pointer before deleting the object
referencedObject = nullptr; // in case this ptr is itself deleted as a side-effect
decIfNotNull(oldObject); // of the destructor
}
// the -> operator is called on the referenced object
ReferencedType* operator->() const noexcept
{
jassert(referencedObject != nullptr); // null pointer method call!
return referencedObject;
}
/** Dereferences the object that this pointer references.
The pointer returned may be null, of course.
*/
ReferencedType& operator*() const noexcept { jassert(referencedObject != nullptr); return *referencedObject; }
/** Checks whether this pointer is null */
bool operator== (decltype (nullptr)) const noexcept { return referencedObject == nullptr; }
/** Checks whether this pointer is null */
bool operator!= (decltype (nullptr)) const noexcept { return referencedObject != nullptr; }
/** Compares two ReferenceCountedObjectPtrs. */
bool operator== (const ObjectType* other) const noexcept { return referencedObject == other; }
/** Compares two ReferenceCountedObjectPtrs. */
bool operator== (const ReferenceCountedObjectPtr& other) const noexcept { return referencedObject == other.get(); }
/** Compares two ReferenceCountedObjectPtrs. */
bool operator!= (const ObjectType* other) const noexcept { return referencedObject != other; }
/** Compares two ReferenceCountedObjectPtrs. */
bool operator!= (const ReferenceCountedObjectPtr& other) const noexcept { return referencedObject != other.get(); }
#if JUCE_STRICT_REFCOUNTEDPOINTER
/** Checks whether this pointer is null */
explicit operator bool() const noexcept { return referencedObject != nullptr; }
#else
/** Returns the object that this pointer references.
The pointer returned may be null, of course.
Note that this methods allows the compiler to be very lenient with what it allows you to do
with the pointer, it's safer to disable this by setting JUCE_STRICT_REFCOUNTEDPOINTER=1, which
increased type safety and can prevent some common slip-ups.
*/
operator ReferencedType* () const noexcept { return referencedObject; }
#endif
// This old method is deprecated in favour of the shorter and more standard get() method.
JUCE_DEPRECATED_WITH_BODY(ReferencedType* getObject() const, { return get(); })
private:
ReferencedType* referencedObject = nullptr;
static void incIfNotNull(ReferencedType* o) noexcept
{
if (o != nullptr)
o->incReferenceCount();
}
static void decIfNotNull(ReferencedType* o) noexcept
{
if (o != nullptr && o->decReferenceCountWithoutDeleting())
ContainerDeletePolicy<ReferencedType>::destroy(o);
}
};
/** Compares two ReferenceCountedObjectPtrs. */
template <typename Type>
bool operator== (const Type* object1, const ReferenceCountedObjectPtr<Type>& object2) noexcept
{
return object1 == object2.get();
}
/** Compares two ReferenceCountedObjectPtrs. */
template <typename Type>
bool operator!= (const Type* object1, const ReferenceCountedObjectPtr<Type>& object2) noexcept
{
return object1 != object2.get();
}
} // namespace juce
/*** End of inlined file: juce_ReferenceCountedObject.h ***/
/*** Start of inlined file: juce_ScopedPointer.h ***/
#ifndef DOXYGEN
namespace juce
{
/**
This class is deprecated. You should use std::unique_ptr instead.
*/
template <class ObjectType>
class ScopedPointer
{
public:
// ScopedPointer is deprecated! You should use std::unique_ptr instead.
JUCE_DEPRECATED_ATTRIBUTE inline ScopedPointer() = default;
// ScopedPointer is deprecated! You should use std::unique_ptr instead.
JUCE_DEPRECATED_ATTRIBUTE inline ScopedPointer(decltype (nullptr)) noexcept {}
// ScopedPointer is deprecated! You should use std::unique_ptr instead.
JUCE_DEPRECATED_ATTRIBUTE inline ScopedPointer(ObjectType* objectToTakePossessionOf) noexcept
: object(objectToTakePossessionOf)
{
}
// ScopedPointer is deprecated! You should use std::unique_ptr instead.
ScopedPointer(ScopedPointer& objectToTransferFrom) noexcept
: object(objectToTransferFrom.release())
{
}
// ScopedPointer is deprecated! You should use std::unique_ptr instead.
JUCE_DEPRECATED_ATTRIBUTE inline ~ScopedPointer() { reset(); }
ScopedPointer& operator= (ScopedPointer& objectToTransferFrom)
{
if (this != objectToTransferFrom.getAddress())
{
// Two ScopedPointers should never be able to refer to the same object - if
// this happens, you must have done something dodgy!
jassert(object == nullptr || object != objectToTransferFrom.object);
reset(objectToTransferFrom.release());
}
return *this;
}
ScopedPointer& operator= (ObjectType* newObjectToTakePossessionOf)
{
reset(newObjectToTakePossessionOf);
return *this;
}
ScopedPointer(ScopedPointer&& other) noexcept : object(other.object)
{
other.object = nullptr;
}
ScopedPointer& operator= (ScopedPointer&& other) noexcept
{
reset(other.release());
return *this;
}
inline operator ObjectType* () const noexcept { return object; }
inline ObjectType* get() const noexcept { return object; }
inline ObjectType& operator*() const noexcept { return *object; }
inline ObjectType* operator->() const noexcept { return object; }
void reset()
{
auto* oldObject = object;
object = {};
ContainerDeletePolicy<ObjectType>::destroy(oldObject);
}
void reset(ObjectType* newObject)
{
if (object != newObject)
{
auto* oldObject = object;
object = newObject;
ContainerDeletePolicy<ObjectType>::destroy(oldObject);
}
else
{
// You're trying to reset this ScopedPointer to itself! This will work here as ScopedPointer does an equality check
// but be aware that std::unique_ptr won't do this and you could end up with some nasty, subtle bugs!
jassert(newObject == nullptr);
}
}
void reset(ScopedPointer& newObject)
{
reset(newObject.release());
}
ObjectType* release() noexcept { auto* o = object; object = {}; return o; }
void swapWith(ScopedPointer<ObjectType>& other) noexcept
{
// Two ScopedPointers should never be able to refer to the same object - if
// this happens, you must have done something dodgy!
jassert(object != other.object || this == other.getAddress() || object == nullptr);
std::swap(object, other.object);
}
inline ObjectType* createCopy() const { return createCopyIfNotNull(object); }
private:
ObjectType* object = nullptr;
const ScopedPointer* getAddress() const noexcept { return this; } // Used internally to avoid the & operator
#if ! JUCE_MSVC // (MSVC can't deal with multiple copy constructors)
ScopedPointer(const ScopedPointer&) = delete;
ScopedPointer& operator= (const ScopedPointer&) = delete;
#endif
};
template <typename ObjectType1, typename ObjectType2>
bool operator== (ObjectType1* pointer1, const ScopedPointer<ObjectType2>& pointer2) noexcept
{
return pointer1 == pointer2.get();
}
template <typename ObjectType1, typename ObjectType2>
bool operator!= (ObjectType1* pointer1, const ScopedPointer<ObjectType2>& pointer2) noexcept
{
return pointer1 != pointer2.get();
}
template <typename ObjectType1, typename ObjectType2>
bool operator== (const ScopedPointer<ObjectType1>& pointer1, ObjectType2* pointer2) noexcept
{
return pointer1.get() == pointer2;
}
template <typename ObjectType1, typename ObjectType2>
bool operator!= (const ScopedPointer<ObjectType1>& pointer1, ObjectType2* pointer2) noexcept
{
return pointer1.get() != pointer2;
}
template <typename ObjectType1, typename ObjectType2>
bool operator== (const ScopedPointer<ObjectType1>& pointer1, const ScopedPointer<ObjectType2>& pointer2) noexcept
{
return pointer1.get() == pointer2.get();
}
template <typename ObjectType1, typename ObjectType2>
bool operator!= (const ScopedPointer<ObjectType1>& pointer1, const ScopedPointer<ObjectType2>& pointer2) noexcept
{
return pointer1.get() != pointer2.get();
}
template <class ObjectType>
bool operator== (decltype (nullptr), const ScopedPointer<ObjectType>& pointer) noexcept
{
return pointer.get() == nullptr;
}
template <class ObjectType>
bool operator!= (decltype (nullptr), const ScopedPointer<ObjectType>& pointer) noexcept
{
return pointer.get() != nullptr;
}
template <class ObjectType>
bool operator== (const ScopedPointer<ObjectType>& pointer, decltype (nullptr)) noexcept
{
return pointer.get() == nullptr;
}
template <class ObjectType>
bool operator!= (const ScopedPointer<ObjectType>& pointer, decltype (nullptr)) noexcept
{
return pointer.get() != nullptr;
}
// NB: This is just here to prevent any silly attempts to call deleteAndZero() on a ScopedPointer.
template <typename Type>
void deleteAndZero(ScopedPointer<Type>&) {
static_assert (sizeof(Type) == 12345,
"Attempt to call deleteAndZero() on a ScopedPointer");
}
} // namespace juce
#endif
/*** End of inlined file: juce_ScopedPointer.h ***/
/*** Start of inlined file: juce_OptionalScopedPointer.h ***/
namespace juce
{
/**
Holds a pointer to an object which can optionally be deleted when this pointer
goes out of scope.
This acts in many ways like a std::unique_ptr, but allows you to specify whether or
not the object is deleted.
@tags{Core}
*/
template <class ObjectType>
class OptionalScopedPointer
{
public:
/** Creates an empty OptionalScopedPointer. */
OptionalScopedPointer() = default;
/** Creates an OptionalScopedPointer to point to a given object, and specifying whether
the OptionalScopedPointer will delete it.
If takeOwnership is true, then the OptionalScopedPointer will act like a std::unique_ptr,
deleting the object when it is itself deleted. If this parameter is false, then the
OptionalScopedPointer just holds a normal pointer to the object, and won't delete it.
*/
OptionalScopedPointer(ObjectType* objectToHold, bool takeOwnership)
: object(objectToHold),
shouldDelete(takeOwnership)
{
}
/** Takes ownership of the object that another OptionalScopedPointer holds.
Like a normal std::unique_ptr, the objectToTransferFrom object will become null,
as ownership of the managed object is transferred to this object.
The flag to indicate whether or not to delete the managed object is also
copied from the source object.
*/
OptionalScopedPointer(OptionalScopedPointer&& other) noexcept
: object(std::move(other.object)),
shouldDelete(std::move(other.shouldDelete))
{
}
/** Takes ownership of the object owned by `ptr`. */
explicit OptionalScopedPointer(std::unique_ptr<ObjectType>&& ptr) noexcept
: OptionalScopedPointer(ptr.release(), true)
{
}
/** Points to the same object as `ref`, but does not take ownership. */
explicit OptionalScopedPointer(ObjectType& ref) noexcept
: OptionalScopedPointer(std::addressof(ref), false)
{
}
/** Takes ownership of the object that another OptionalScopedPointer holds.
Like a normal std::unique_ptr, the objectToTransferFrom object will become null,
as ownership of the managed object is transferred to this object.
The ownership flag that says whether or not to delete the managed object is also
copied from the source object.
*/
OptionalScopedPointer& operator= (OptionalScopedPointer&& other) noexcept
{
swapWith(other);
other.reset();
return *this;
}
/** The destructor may or may not delete the object that is being held, depending on the
takeOwnership flag that was specified when the object was first passed into an
OptionalScopedPointer constructor.
*/
~OptionalScopedPointer() noexcept
{
reset();
}
/** Returns the object that this pointer is managing. */
operator ObjectType* () const noexcept { return object.get(); }
/** Returns the object that this pointer is managing. */
ObjectType* get() const noexcept { return object.get(); }
/** Returns the object that this pointer is managing. */
ObjectType& operator*() const noexcept { return *object; }
/** Lets you access methods and properties of the object that this pointer is holding. */
ObjectType* operator->() const noexcept { return object.get(); }
/** Removes the current object from this OptionalScopedPointer without deleting it.
This will return the current object, and set this OptionalScopedPointer to a null pointer.
*/
ObjectType* release() noexcept { return object.release(); }
/** Resets this pointer to null, possibly deleting the object that it holds, if it has
ownership of it.
*/
void reset() noexcept
{
if (!shouldDelete)
object.release();
else
object.reset();
}
/** Does the same thing as reset(). */
void clear() { reset(); }
/** Makes this OptionalScopedPointer point at a new object, specifying whether the
OptionalScopedPointer will take ownership of the object.
If takeOwnership is true, then the OptionalScopedPointer will act like a std::unique_ptr,
deleting the object when it is itself deleted. If this parameter is false, then the
OptionalScopedPointer just holds a normal pointer to the object, and won't delete it.
*/
void set(ObjectType* newObject, bool takeOwnership)
{
if (object.get() != newObject)
{
reset();
object.reset(newObject);
}
shouldDelete = takeOwnership;
}
/** Makes this OptionalScopedPointer point at a new object, and take ownership of that object. */
void setOwned(ObjectType* newObject)
{
set(newObject, true);
}
/** Makes this OptionalScopedPointer point at a new object, but will not take ownership of that object. */
void setNonOwned(ObjectType* newObject)
{
set(newObject, false);
}
/** Returns true if the target object will be deleted when this pointer
object is deleted.
*/
bool willDeleteObject() const noexcept { return shouldDelete; }
/** Swaps this object with another OptionalScopedPointer.
The two objects simply exchange their states.
*/
void swapWith(OptionalScopedPointer<ObjectType>& other) noexcept
{
std::swap(other.object, object);
std::swap(other.shouldDelete, shouldDelete);
}
private:
std::unique_ptr<ObjectType> object;
bool shouldDelete = false;
};
} // namespace juce
/*** End of inlined file: juce_OptionalScopedPointer.h ***/
/*** Start of inlined file: juce_Singleton.h ***/
namespace juce
{
/**
Used by the JUCE_DECLARE_SINGLETON macros to manage a static pointer
to a singleton instance.
You generally won't use this directly, but see the macros JUCE_DECLARE_SINGLETON,
JUCE_DECLARE_SINGLETON_SINGLETHREADED, JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL,
and JUCE_IMPLEMENT_SINGLETON for how it is intended to be used.
@tags{Core}
*/
template <typename Type, typename MutexType, bool onlyCreateOncePerRun>
struct SingletonHolder : private MutexType // (inherited so we can use the empty-base-class optimisation)
{
SingletonHolder() = default;
~SingletonHolder()
{
/* The static singleton holder is being deleted before the object that it holds
has been deleted. This could mean that you've forgotten to call clearSingletonInstance()
in the class's destructor, or have failed to delete it before your app shuts down.
If you're having trouble cleaning up your singletons, perhaps consider using the
SharedResourcePointer class instead.
*/
jassert(instance == nullptr);
}
/** Returns the current instance, or creates a new instance if there isn't one. */
Type* get()
{
if (instance == nullptr)
{
typename MutexType::ScopedLockType sl(*this);
if (instance == nullptr)
{
auto once = onlyCreateOncePerRun; // (local copy avoids VS compiler warning about this being constant)
if (once)
{
static bool createdOnceAlready = false;
if (createdOnceAlready)
{
// This means that the doNotRecreateAfterDeletion flag was set
// and you tried to create the singleton more than once.
jassertfalse;
return nullptr;
}
createdOnceAlready = true;
}
static bool alreadyInside = false;
if (alreadyInside)
{
// This means that your object's constructor has done something which has
// ended up causing a recursive loop of singleton creation..
jassertfalse;
}
else
{
alreadyInside = true;
getWithoutChecking();
alreadyInside = false;
}
}
}
return instance;
}
/** Returns the current instance, or creates a new instance if there isn't one, but doesn't do
any locking, or checking for recursion or error conditions.
*/
Type* getWithoutChecking()
{
if (instance == nullptr)
{
auto newObject = new Type(); // (create into a local so that instance is still null during construction)
instance = newObject;
}
return instance;
}
/** Deletes and resets the current instance, if there is one. */
void deleteInstance()
{
typename MutexType::ScopedLockType sl(*this);
auto old = instance;
instance = nullptr;
delete old;
}
/** Called by the class's destructor to clear the pointer if it is currently set to the given object. */
void clear(Type* expectedObject) noexcept
{
if (instance == expectedObject)
instance = nullptr;
}
Type* instance = nullptr;
};
/**
Macro to generate the appropriate methods and boilerplate for a singleton class.
To use this, add the line JUCE_DECLARE_SINGLETON(MyClass, doNotRecreateAfterDeletion)
to the class's definition.
Then put a macro JUCE_IMPLEMENT_SINGLETON(MyClass) along with the class's
implementation code.
It's also a very good idea to also add the call clearSingletonInstance() in your class's
destructor, in case it is deleted by other means than deleteInstance()
Clients can then call the static method MyClass::getInstance() to get a pointer
to the singleton, or MyClass::getInstanceWithoutCreating() which will return nullptr if
no instance currently exists.
e.g. @code
struct MySingleton
{
MySingleton() {}
~MySingleton()
{
// this ensures that no dangling pointers are left when the
// singleton is deleted.
clearSingletonInstance();
}
JUCE_DECLARE_SINGLETON (MySingleton, false)
};
// ..and this goes in a suitable .cpp file:
JUCE_IMPLEMENT_SINGLETON (MySingleton)
// example of usage:
auto* m = MySingleton::getInstance(); // creates the singleton if there isn't already one.
...
MySingleton::deleteInstance(); // safely deletes the singleton (if it's been created).
@endcode
If doNotRecreateAfterDeletion = true, it won't allow the object to be created more
than once during the process's lifetime - i.e. after you've created and deleted the
object, getInstance() will refuse to create another one. This can be useful to stop
objects being accidentally re-created during your app's shutdown code.
If you know that your object will only be created and deleted by a single thread, you
can use the slightly more efficient JUCE_DECLARE_SINGLETON_SINGLETHREADED macro instead
of this one.
@see JUCE_IMPLEMENT_SINGLETON, JUCE_DECLARE_SINGLETON_SINGLETHREADED
*/
#define JUCE_DECLARE_SINGLETON(Classname, doNotRecreateAfterDeletion) \
\
static juce::SingletonHolder<Classname, juce::CriticalSection, doNotRecreateAfterDeletion> singletonHolder; \
friend decltype (singletonHolder); \
\
static Classname* JUCE_CALLTYPE getInstance() { return singletonHolder.get(); } \
static Classname* JUCE_CALLTYPE getInstanceWithoutCreating() noexcept { return singletonHolder.instance; } \
static void JUCE_CALLTYPE deleteInstance() noexcept { singletonHolder.deleteInstance(); } \
void clearSingletonInstance() noexcept { singletonHolder.clear (this); }
/** This is a counterpart to the JUCE_DECLARE_SINGLETON macros.
After adding the JUCE_DECLARE_SINGLETON to the class definition, this macro has
to be used in the cpp file.
*/
#define JUCE_IMPLEMENT_SINGLETON(Classname) \
\
decltype (Classname::singletonHolder) Classname::singletonHolder;
/**
Macro to declare member variables and methods for a singleton class.
This is exactly the same as JUCE_DECLARE_SINGLETON, but doesn't use a critical
section to make access to it thread-safe. If you know that your object will
only ever be created or deleted by a single thread, then this is a
more efficient version to use.
If doNotRecreateAfterDeletion = true, it won't allow the object to be created more
than once during the process's lifetime - i.e. after you've created and deleted the
object, getInstance() will refuse to create another one. This can be useful to stop
objects being accidentally re-created during your app's shutdown code.
See the documentation for JUCE_DECLARE_SINGLETON for more information about
how to use it. Just like JUCE_DECLARE_SINGLETON you need to also have a
corresponding JUCE_IMPLEMENT_SINGLETON statement somewhere in your code.
@see JUCE_IMPLEMENT_SINGLETON, JUCE_DECLARE_SINGLETON, JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL
*/
#define JUCE_DECLARE_SINGLETON_SINGLETHREADED(Classname, doNotRecreateAfterDeletion) \
\
static juce::SingletonHolder<Classname, juce::DummyCriticalSection, doNotRecreateAfterDeletion> singletonHolder; \
friend decltype (singletonHolder); \
\
static Classname* JUCE_CALLTYPE getInstance() { return singletonHolder.get(); } \
static Classname* JUCE_CALLTYPE getInstanceWithoutCreating() noexcept { return singletonHolder.instance; } \
static void JUCE_CALLTYPE deleteInstance() noexcept { singletonHolder.deleteInstance(); } \
void clearSingletonInstance() noexcept { singletonHolder.clear (this); }
/**
Macro to declare member variables and methods for a singleton class.
This is like JUCE_DECLARE_SINGLETON_SINGLETHREADED, but doesn't do any checking
for recursion or repeated instantiation. It's intended for use as a lightweight
version of a singleton, where you're using it in very straightforward
circumstances and don't need the extra checking.
See the documentation for JUCE_DECLARE_SINGLETON for more information about
how to use it. Just like JUCE_DECLARE_SINGLETON you need to also have a
corresponding JUCE_IMPLEMENT_SINGLETON statement somewhere in your code.
@see JUCE_IMPLEMENT_SINGLETON, JUCE_DECLARE_SINGLETON
*/
#define JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL(Classname) \
\
static juce::SingletonHolder<Classname, juce::DummyCriticalSection, false> singletonHolder; \
friend decltype (singletonHolder); \
\
static Classname* JUCE_CALLTYPE getInstance() { return singletonHolder.getWithoutChecking(); } \
static Classname* JUCE_CALLTYPE getInstanceWithoutCreating() noexcept { return singletonHolder.instance; } \
static void JUCE_CALLTYPE deleteInstance() noexcept { singletonHolder.deleteInstance(); } \
void clearSingletonInstance() noexcept { singletonHolder.clear (this); }
#ifndef DOXYGEN
// These are ancient macros, and have now been updated with new names to match the JUCE style guide,
// so please update your code to use the newer versions!
#define juce_DeclareSingleton(Classname, doNotRecreate) JUCE_DECLARE_SINGLETON(Classname, doNotRecreate)
#define juce_DeclareSingleton_SingleThreaded(Classname, doNotRecreate) JUCE_DECLARE_SINGLETON_SINGLETHREADED(Classname, doNotRecreate)
#define juce_DeclareSingleton_SingleThreaded_Minimal(Classname) JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL(Classname)
#define juce_ImplementSingleton(Classname) JUCE_IMPLEMENT_SINGLETON(Classname)
#define juce_ImplementSingleton_SingleThreaded(Classname) JUCE_IMPLEMENT_SINGLETON(Classname)
#endif
} // namespace juce
/*** End of inlined file: juce_Singleton.h ***/
/*** Start of inlined file: juce_WeakReference.h ***/
namespace juce
{
/**
This class acts as a pointer which will automatically become null if the object
to which it points is deleted.
To accomplish this, the source object needs to cooperate by performing a couple of simple tasks.
It must embed a WeakReference::Master object, which stores a shared pointer object, and must clear
this master pointer in its destructor.
Note that WeakReference is not designed to be thread-safe, so if you're accessing it from
different threads, you'll need to do your own locking around all uses of the pointer and
the object it refers to.
E.g.
@code
class MyObject
{
public:
MyObject() {}
~MyObject()
{
// This will zero all the references - you need to call this in your destructor.
masterReference.clear();
}
private:
// You need to embed a variable of this type, with the name "masterReference" inside your object. If the
// variable is not public, you should make your class a friend of WeakReference<MyObject> so that the
// WeakReference class can access it.
WeakReference<MyObject>::Master masterReference;
friend class WeakReference<MyObject>;
};
OR: just use the handy JUCE_DECLARE_WEAK_REFERENCEABLE macro to do all this for you.
// Here's an example of using a pointer..
auto* n = new MyObject();
WeakReference<MyObject> myObjectRef = n;
auto pointer1 = myObjectRef.get(); // returns a valid pointer to 'n'
delete n;
auto pointer2 = myObjectRef.get(); // now returns nullptr
@endcode
@see WeakReference::Master
@tags{Core}
*/
template <class ObjectType, class ReferenceCountingType = ReferenceCountedObject>
class WeakReference
{
public:
/** Creates a null WeakReference. */
inline WeakReference() = default;
/** Creates a WeakReference that points at the given object. */
WeakReference(ObjectType* object) : holder(getRef(object)) {}
/** Creates a copy of another WeakReference. */
WeakReference(const WeakReference& other) noexcept : holder(other.holder) {}
/** Move constructor */
WeakReference(WeakReference&& other) noexcept : holder(std::move(other.holder)) {}
/** Copies another pointer to this one. */
WeakReference& operator= (const WeakReference& other) { holder = other.holder; return *this; }
/** Copies another pointer to this one. */
WeakReference& operator= (ObjectType* newObject) { holder = getRef(newObject); return *this; }
/** Move assignment operator */
WeakReference& operator= (WeakReference&& other) noexcept { holder = std::move(other.holder); return *this; }
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
ObjectType* get() const noexcept { return holder != nullptr ? holder->get() : nullptr; }
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
operator ObjectType* () const noexcept { return get(); }
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
ObjectType* operator->() const noexcept { return get(); }
/** This returns true if this reference has been pointing at an object, but that object has
since been deleted.
If this reference was only ever pointing at a null pointer, this will return false. Using
operator=() to make this refer to a different object will reset this flag to match the status
of the reference from which you're copying.
*/
bool wasObjectDeleted() const noexcept { return holder != nullptr && holder->get() == nullptr; }
bool operator== (ObjectType* object) const noexcept { return get() == object; }
bool operator!= (ObjectType* object) const noexcept { return get() != object; }
/** This class is used internally by the WeakReference class - don't use it directly
in your code!
@see WeakReference
*/
class SharedPointer : public ReferenceCountingType
{
public:
explicit SharedPointer(ObjectType* obj) noexcept : owner(obj) {}
inline ObjectType* get() const noexcept { return owner; }
void clearPointer() noexcept { owner = nullptr; }
private:
ObjectType* owner;
JUCE_DECLARE_NON_COPYABLE(SharedPointer)
};
using SharedRef = ReferenceCountedObjectPtr<SharedPointer>;
/**
This class is embedded inside an object to which you want to attach WeakReference pointers.
See the WeakReference class notes for an example of how to use this class.
@see WeakReference
*/
class Master
{
public:
Master() = default;
~Master() noexcept
{
// You must remember to call clear() in your source object's destructor! See the notes
// for the WeakReference class for an example of how to do this.
jassert(sharedPointer == nullptr || sharedPointer->get() == nullptr);
}
/** The first call to this method will create an internal object that is shared by all weak
references to the object.
*/
SharedRef getSharedPointer(ObjectType* object)
{
if (sharedPointer == nullptr)
{
sharedPointer = *new SharedPointer(object);
}
else
{
// You're trying to create a weak reference to an object that has already been deleted!!
jassert(sharedPointer->get() != nullptr);
}
return sharedPointer;
}
/** The object that owns this master pointer should call this before it gets destroyed,
to zero all the references to this object that may be out there. See the WeakReference
class notes for an example of how to do this.
*/
void clear() noexcept
{
if (sharedPointer != nullptr)
sharedPointer->clearPointer();
}
/** Returns the number of WeakReferences that are out there pointing to this object. */
int getNumActiveWeakReferences() const noexcept
{
return sharedPointer == nullptr ? 0 : (sharedPointer->getReferenceCount() - 1);
}
private:
SharedRef sharedPointer;
JUCE_DECLARE_NON_COPYABLE(Master)
};
private:
SharedRef holder;
static SharedRef getRef(ObjectType* o)
{
if (o != nullptr)
return o->masterReference.getSharedPointer(o);
return {};
}
};
/**
Macro to easily allow a class to be made weak-referenceable.
This can be inserted in a class definition to add the requisite weak-ref boilerplate to that class.
e.g.
@code
class MyObject
{
public:
MyObject();
~MyObject();
private:
JUCE_DECLARE_WEAK_REFERENCEABLE (MyObject)
};
@endcode
@see WeakReference, WeakReference::Master
*/
#define JUCE_DECLARE_WEAK_REFERENCEABLE(Class) \
struct WeakRefMaster : public juce::WeakReference<Class>::Master { ~WeakRefMaster() { this->clear(); } }; \
WeakRefMaster masterReference; \
friend class juce::WeakReference<Class>; \
} // namespace juce
/*** End of inlined file: juce_WeakReference.h ***/
/*** Start of inlined file: juce_ScopedLock.h ***/
namespace juce
{
/**
Automatically locks and unlocks a mutex object.
Use one of these as a local variable to provide RAII-based locking of a mutex.
The templated class could be a CriticalSection, SpinLock, or anything else that
provides enter() and exit() methods.
e.g. @code
CriticalSection myCriticalSection;
for (;;)
{
const GenericScopedLock<CriticalSection> myScopedLock (myCriticalSection);
// myCriticalSection is now locked
...do some stuff...
// myCriticalSection gets unlocked here.
}
@endcode
@see GenericScopedUnlock, CriticalSection, SpinLock, ScopedLock, ScopedUnlock
@tags{Core}
*/
template <class LockType>
class GenericScopedLock
{
public:
/** Creates a GenericScopedLock.
As soon as it is created, this will acquire the lock, and when the GenericScopedLock
object is deleted, the lock will be released.
Make sure this object is created and deleted by the same thread,
otherwise there are no guarantees what will happen! Best just to use it
as a local stack object, rather than creating one with the new() operator.
*/
inline explicit GenericScopedLock(const LockType& lock) noexcept : lock_(lock) { lock.enter(); }
/** Destructor.
The lock will be released when the destructor is called.
Make sure this object is created and deleted by the same thread, otherwise there are
no guarantees what will happen!
*/
inline ~GenericScopedLock() noexcept { lock_.exit(); }
private:
const LockType& lock_;
JUCE_DECLARE_NON_COPYABLE(GenericScopedLock)
};
/**
Automatically unlocks and re-locks a mutex object.
This is the reverse of a GenericScopedLock object - instead of locking the mutex
for the lifetime of this object, it unlocks it.
Make sure you don't try to unlock mutexes that aren't actually locked!
e.g. @code
CriticalSection myCriticalSection;
for (;;)
{
const GenericScopedLock<CriticalSection> myScopedLock (myCriticalSection);
// myCriticalSection is now locked
... do some stuff with it locked ..
while (xyz)
{
... do some stuff with it locked ..
const GenericScopedUnlock<CriticalSection> unlocker (myCriticalSection);
// myCriticalSection is now unlocked for the remainder of this block,
// and re-locked at the end.
...do some stuff with it unlocked ...
}
// myCriticalSection gets unlocked here.
}
@endcode
@see GenericScopedLock, CriticalSection, ScopedLock, ScopedUnlock
@tags{Core}
*/
template <class LockType>
class GenericScopedUnlock
{
public:
/** Creates a GenericScopedUnlock.
As soon as it is created, this will unlock the CriticalSection, and
when the ScopedLock object is deleted, the CriticalSection will
be re-locked.
Make sure this object is created and deleted by the same thread,
otherwise there are no guarantees what will happen! Best just to use it
as a local stack object, rather than creating one with the new() operator.
*/
inline explicit GenericScopedUnlock(const LockType& lock) noexcept : lock_(lock) { lock.exit(); }
/** Destructor.
The CriticalSection will be unlocked when the destructor is called.
Make sure this object is created and deleted by the same thread,
otherwise there are no guarantees what will happen!
*/
inline ~GenericScopedUnlock() noexcept { lock_.enter(); }
private:
const LockType& lock_;
JUCE_DECLARE_NON_COPYABLE(GenericScopedUnlock)
};
/**
Automatically locks and unlocks a mutex object.
Use one of these as a local variable to provide RAII-based locking of a mutex.
The templated class could be a CriticalSection, SpinLock, or anything else that
provides enter() and exit() methods.
e.g. @code
CriticalSection myCriticalSection;
for (;;)
{
const GenericScopedTryLock<CriticalSection> myScopedTryLock (myCriticalSection);
// Unlike using a ScopedLock, this may fail to actually get the lock, so you
// should test this with the isLocked() method before doing your thread-unsafe
// action..
if (myScopedTryLock.isLocked())
{
...do some stuff...
}
else
{
..our attempt at locking failed because another thread had already locked it..
}
// myCriticalSection gets unlocked here (if it was locked)
}
@endcode
@see CriticalSection::tryEnter, GenericScopedLock, GenericScopedUnlock
@tags{Core}
*/
template <class LockType>
class GenericScopedTryLock
{
public:
/** Creates a GenericScopedTryLock.
If acquireLockOnInitialisation is true then as soon as this ScopedTryLock
is created, it will attempt to acquire the lock with tryEnter.
You can retry acquiring the lock by calling retryLock.
When GenericScopedTryLock is deleted, the lock will be released (if the lock
was successfully acquired).
Make sure this object is created and deleted by the same thread,
otherwise there are no guarantees what will happen! Best just to use it
as a local stack object, rather than creating one with the new() operator.
@see retryLock, isLocked
*/
inline explicit GenericScopedTryLock(const LockType& lock, bool acquireLockOnInitialisation = true) noexcept
: lock_(lock), lockWasSuccessful(acquireLockOnInitialisation&& lock.tryEnter()) {}
/** Destructor.
The mutex will be unlocked (if it had been successfully locked) when the
destructor is called.
Make sure this object is created and deleted by the same thread,
otherwise there are no guarantees what will happen!
*/
inline ~GenericScopedTryLock() noexcept { if (lockWasSuccessful) lock_.exit(); }
/** Returns true if the mutex was successfully locked. */
bool isLocked() const noexcept { return lockWasSuccessful; }
/** Retry gaining the lock by calling tryEnter on the underlying lock. */
bool retryLock() const noexcept { lockWasSuccessful = lock_.tryEnter(); return lockWasSuccessful; }
private:
const LockType& lock_;
mutable bool lockWasSuccessful;
JUCE_DECLARE_NON_COPYABLE(GenericScopedTryLock)
};
} // namespace juce
/*** End of inlined file: juce_ScopedLock.h ***/
/*** Start of inlined file: juce_CriticalSection.h ***/
namespace juce
{
/**
A re-entrant mutex.
A CriticalSection acts as a re-entrant mutex object. The best way to lock and unlock
one of these is by using RAII in the form of a local ScopedLock object - have a look
through the codebase for many examples of how to do this.
In almost all cases you'll want to declare your CriticalSection as a member variable.
Occasionally you may want to declare one as a static variable, but in that case the usual
C++ static object order-of-construction warnings should be heeded.
@see ScopedLock, ScopedTryLock, ScopedUnlock, SpinLock, ReadWriteLock, Thread, InterProcessLock
@tags{Core}
*/
class JUCE_API CriticalSection
{
public:
/** Creates a CriticalSection object. */
CriticalSection() noexcept;
/** Destructor.
If the critical section is deleted whilst locked, any subsequent behaviour
is unpredictable.
*/
~CriticalSection() noexcept;
/** Acquires the lock.
If the lock is already held by the caller thread, the method returns immediately.
If the lock is currently held by another thread, this will wait until it becomes free.
It's strongly recommended that you never call this method directly - instead use the
ScopedLock class to manage the locking using an RAII pattern instead.
@see exit, tryEnter, ScopedLock
*/
void enter() const noexcept;
/** Attempts to lock this critical section without blocking.
This method behaves identically to CriticalSection::enter, except that the caller thread
does not wait if the lock is currently held by another thread but returns false immediately.
@returns false if the lock is currently held by another thread, true otherwise.
@see enter
*/
bool tryEnter() const noexcept;
/** Releases the lock.
If the caller thread hasn't got the lock, this can have unpredictable results.
If the enter() method has been called multiple times by the thread, each
call must be matched by a call to exit() before other threads will be allowed
to take over the lock.
@see enter, ScopedLock
*/
void exit() const noexcept;
/** Provides the type of scoped lock to use with a CriticalSection. */
using ScopedLockType = GenericScopedLock<CriticalSection>;
/** Provides the type of scoped unlocker to use with a CriticalSection. */
using ScopedUnlockType = GenericScopedUnlock<CriticalSection>;
/** Provides the type of scoped try-locker to use with a CriticalSection. */
using ScopedTryLockType = GenericScopedTryLock<CriticalSection>;
private:
#if JUCE_WINDOWS
// To avoid including windows.h in the public JUCE headers, we'll just allocate
// a block of memory here that's big enough to be used internally as a windows
// CRITICAL_SECTION structure.
#if JUCE_64BIT
uint8 lock[44];
#else
uint8 lock[24];
#endif
#else
mutable pthread_mutex_t lock;
#endif
JUCE_DECLARE_NON_COPYABLE(CriticalSection)
};
/**
A class that can be used in place of a real CriticalSection object, but which
doesn't perform any locking.
This is currently used by some templated classes, and most compilers should
manage to optimise it out of existence.
@see CriticalSection, Array, OwnedArray, ReferenceCountedArray
@tags{Core}
*/
class JUCE_API DummyCriticalSection
{
public:
inline DummyCriticalSection() = default;
inline ~DummyCriticalSection() = default;
inline void enter() const noexcept {}
inline bool tryEnter() const noexcept { return true; }
inline void exit() const noexcept {}
/** A dummy scoped-lock type to use with a dummy critical section. */
struct ScopedLockType
{
ScopedLockType(const DummyCriticalSection&) noexcept {}
};
/** A dummy scoped-unlocker type to use with a dummy critical section. */
using ScopedUnlockType = ScopedLockType;
private:
JUCE_DECLARE_NON_COPYABLE(DummyCriticalSection)
};
/**
Automatically locks and unlocks a CriticalSection object.
You can use a ScopedLock as a local variable to provide RAII-based locking of a CriticalSection.
e.g. @code
struct MyObject
{
CriticalSection objectLock;
// assuming that this example function will be called by multiple threads
void foo()
{
const ScopedLock myScopedLock (objectLock);
// objectLock is now locked..
...do some thread-safe work here...
// ..and objectLock gets unlocked here, as myScopedLock goes out of
// scope at the end of the block
}
};
@endcode
@see CriticalSection, ScopedUnlock
*/
using ScopedLock = CriticalSection::ScopedLockType;
/**
Automatically unlocks and re-locks a CriticalSection object.
This is the reverse of a ScopedLock object - instead of locking the critical
section for the lifetime of this object, it unlocks it.
Make sure you don't try to unlock critical sections that aren't actually locked!
e.g. @code
struct MyObject
{
CriticalSection objectLock;
void foo()
{
{
const ScopedLock myScopedLock (objectLock);
// objectLock is now locked..
{
ScopedUnlock myUnlocker (objectLock);
// ..and now unlocked..
}
// ..and now locked again..
}
// ..and finally unlocked.
}
};
@endcode
@see CriticalSection, ScopedLock
*/
using ScopedUnlock = CriticalSection::ScopedUnlockType;
/**
Automatically tries to lock and unlock a CriticalSection object.
Use one of these as a local variable to control access to a CriticalSection.
e.g. @code
struct MyObject
{
CriticalSection objectLock;
void foo()
{
const ScopedTryLock myScopedTryLock (objectLock);
// Unlike using a ScopedLock, this may fail to actually get the lock, so you
// must call the isLocked() method before making any assumptions..
if (myScopedTryLock.isLocked())
{
...safely do some work...
}
else
{
// If we get here, then our attempt at locking failed because another thread had already locked it..
}
}
};
@endcode
@see CriticalSection::tryEnter, ScopedLock, ScopedUnlock, ScopedReadLock
*/
using ScopedTryLock = CriticalSection::ScopedTryLockType;
} // namespace juce
/*** End of inlined file: juce_CriticalSection.h ***/
/*** Start of inlined file: juce_Range.h ***/
namespace juce
{
/** A general-purpose range object, that simply represents any linear range with
a start and end point.
Note that when checking whether values fall within the range, the start value is
considered to be inclusive, and the end of the range exclusive.
The templated parameter is expected to be a primitive integer or floating point
type, though class types could also be used if they behave in a number-like way.
@tags{Core}
*/
template <typename ValueType>
class Range
{
public:
/** Constructs an empty range. */
constexpr Range() = default;
/** Constructs a range with given start and end values. */
constexpr Range(const ValueType startValue, const ValueType endValue) noexcept
: start(startValue), end(jmax(startValue, endValue))
{
}
/** Constructs a copy of another range. */
constexpr Range(const Range&) = default;
/** Copies another range object. */
Range& operator= (const Range&) = default;
/** Returns the range that lies between two positions (in either order). */
constexpr static Range between(const ValueType position1, const ValueType position2) noexcept
{
return position1 < position2 ? Range(position1, position2)
: Range(position2, position1);
}
/** Returns a range with a given start and length. */
static Range withStartAndLength(const ValueType startValue, const ValueType length) noexcept
{
jassert(length >= ValueType());
return Range(startValue, startValue + length);
}
/** Returns a range with the specified start position and a length of zero. */
constexpr static Range emptyRange(const ValueType start) noexcept
{
return Range(start, start);
}
/** Returns the start of the range. */
constexpr inline ValueType getStart() const noexcept { return start; }
/** Returns the length of the range. */
constexpr inline ValueType getLength() const noexcept { return end - start; }
/** Returns the end of the range. */
constexpr inline ValueType getEnd() const noexcept { return end; }
/** Returns true if the range has a length of zero. */
constexpr inline bool isEmpty() const noexcept { return start == end; }
/** Changes the start position of the range, leaving the end position unchanged.
If the new start position is higher than the current end of the range, the end point
will be pushed along to equal it, leaving an empty range at the new position.
*/
void setStart(const ValueType newStart) noexcept
{
start = newStart;
if (end < newStart)
end = newStart;
}
/** Returns a range with the same end as this one, but a different start.
If the new start position is higher than the current end of the range, the end point
will be pushed along to equal it, returning an empty range at the new position.
*/
constexpr Range withStart(const ValueType newStart) const noexcept
{
return Range(newStart, jmax(newStart, end));
}
/** Returns a range with the same length as this one, but moved to have the given start position. */
constexpr Range movedToStartAt(const ValueType newStart) const noexcept
{
return Range(newStart, end + (newStart - start));
}
/** Changes the end position of the range, leaving the start unchanged.
If the new end position is below the current start of the range, the start point
will be pushed back to equal the new end point.
*/
void setEnd(const ValueType newEnd) noexcept
{
end = newEnd;
if (newEnd < start)
start = newEnd;
}
/** Returns a range with the same start position as this one, but a different end.
If the new end position is below the current start of the range, the start point
will be pushed back to equal the new end point.
*/
constexpr Range withEnd(const ValueType newEnd) const noexcept
{
return Range(jmin(start, newEnd), newEnd);
}
/** Returns a range with the same length as this one, but moved to have the given end position. */
constexpr Range movedToEndAt(const ValueType newEnd) const noexcept
{
return Range(start + (newEnd - end), newEnd);
}
/** Changes the length of the range.
Lengths less than zero are treated as zero.
*/
void setLength(const ValueType newLength) noexcept
{
end = start + jmax(ValueType(), newLength);
}
/** Returns a range with the same start as this one, but a different length.
Lengths less than zero are treated as zero.
*/
constexpr Range withLength(const ValueType newLength) const noexcept
{
return Range(start, start + newLength);
}
/** Returns a range which has its start moved down and its end moved up by the
given amount.
@returns The returned range will be (start - amount, end + amount)
*/
constexpr Range expanded(ValueType amount) const noexcept
{
return Range(start - amount, end + amount);
}
/** Adds an amount to the start and end of the range. */
inline Range operator+= (const ValueType amountToAdd) noexcept
{
start += amountToAdd;
end += amountToAdd;
return *this;
}
/** Subtracts an amount from the start and end of the range. */
inline Range operator-= (const ValueType amountToSubtract) noexcept
{
start -= amountToSubtract;
end -= amountToSubtract;
return *this;
}
/** Returns a range that is equal to this one with an amount added to its
start and end.
*/
constexpr Range operator+ (const ValueType amountToAdd) const noexcept
{
return Range(start + amountToAdd, end + amountToAdd);
}
/** Returns a range that is equal to this one with the specified amount
subtracted from its start and end. */
constexpr Range operator- (const ValueType amountToSubtract) const noexcept
{
return Range(start - amountToSubtract, end - amountToSubtract);
}
constexpr bool operator== (Range other) const noexcept { return start == other.start && end == other.end; }
constexpr bool operator!= (Range other) const noexcept { return start != other.start || end != other.end; }
/** Returns true if the given position lies inside this range.
When making this comparison, the start value is considered to be inclusive,
and the end of the range exclusive.
*/
constexpr bool contains(const ValueType position) const noexcept
{
return start <= position && position < end;
}
/** Returns the nearest value to the one supplied, which lies within the range. */
ValueType clipValue(const ValueType value) const noexcept
{
return jlimit(start, end, value);
}
/** Returns true if the given range lies entirely inside this range. */
constexpr bool contains(Range other) const noexcept
{
return start <= other.start && end >= other.end;
}
/** Returns true if the given range intersects this one. */
constexpr bool intersects(Range other) const noexcept
{
return other.start < end&& start < other.end;
}
/** Returns the range that is the intersection of the two ranges, or an empty range
with an undefined start position if they don't overlap. */
constexpr Range getIntersectionWith(Range other) const noexcept
{
return Range(jmax(start, other.start),
jmin(end, other.end));
}
/** Returns the smallest range that contains both this one and the other one. */
constexpr Range getUnionWith(Range other) const noexcept
{
return Range(jmin(start, other.start),
jmax(end, other.end));
}
/** Returns the smallest range that contains both this one and the given value. */
constexpr Range getUnionWith(const ValueType valueToInclude) const noexcept
{
return Range(jmin(valueToInclude, start),
jmax(valueToInclude, end));
}
/** Returns a given range, after moving it forwards or backwards to fit it
within this range.
If the supplied range has a greater length than this one, the return value
will be this range.
Otherwise, if the supplied range is smaller than this one, the return value
will be the new range, shifted forwards or backwards so that it doesn't extend
beyond this one, but keeping its original length.
*/
Range constrainRange(Range rangeToConstrain) const noexcept
{
const ValueType otherLen = rangeToConstrain.getLength();
return getLength() <= otherLen
? *this
: rangeToConstrain.movedToStartAt(jlimit(start, end - otherLen, rangeToConstrain.getStart()));
}
/** Scans an array of values for its min and max, and returns these as a Range. */
static Range findMinAndMax(const ValueType* values, int numValues) noexcept
{
if (numValues <= 0)
return Range();
const ValueType first(*values++);
Range r(first, first);
while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
{
const ValueType v(*values++);
if (r.end < v) r.end = v;
if (v < r.start) r.start = v;
}
return r;
}
private:
ValueType start{}, end{};
};
} // namespace juce
/*** End of inlined file: juce_Range.h ***/
/*** Start of inlined file: juce_NormalisableRange.h ***/
namespace juce
{
/**
Represents a mapping between an arbitrary range of values and a
normalised 0->1 range.
The properties of the mapping also include an optional snapping interval
and skew-factor.
@see Range
@tags{Core}
*/
template <typename ValueType>
class NormalisableRange
{
public:
/** Creates a continuous range that performs a dummy mapping. */
NormalisableRange() = default;
NormalisableRange(const NormalisableRange&) = default;
NormalisableRange& operator= (const NormalisableRange&) = default;
NormalisableRange(NormalisableRange&&) = default;
NormalisableRange& operator= (NormalisableRange&&) = default;
/** Creates a NormalisableRange with a given range, interval and skew factor. */
NormalisableRange(ValueType rangeStart,
ValueType rangeEnd,
ValueType intervalValue,
ValueType skewFactor,
bool useSymmetricSkew = false) noexcept
: start(rangeStart), end(rangeEnd), interval(intervalValue),
skew(skewFactor), symmetricSkew(useSymmetricSkew)
{
checkInvariants();
}
/** Creates a NormalisableRange with a given range, continuous interval, but a dummy skew-factor. */
NormalisableRange(ValueType rangeStart,
ValueType rangeEnd) noexcept
: start(rangeStart), end(rangeEnd)
{
checkInvariants();
}
/** Creates a NormalisableRange with a given range and interval, but a dummy skew-factor. */
NormalisableRange(ValueType rangeStart,
ValueType rangeEnd,
ValueType intervalValue) noexcept
: start(rangeStart), end(rangeEnd), interval(intervalValue)
{
checkInvariants();
}
/** Creates a NormalisableRange with a given range, continuous interval, but a dummy skew-factor. */
NormalisableRange(Range<ValueType> range) noexcept
: NormalisableRange(range.getStart(), range.getEnd())
{
}
/** Creates a NormalisableRange with a given range and interval, but a dummy skew-factor. */
NormalisableRange(Range<ValueType> range, ValueType intervalValue) noexcept
: NormalisableRange(range.getStart(), range.getEnd(), intervalValue)
{
}
/** A function object which can remap a value in some way based on the start and end of a range. */
using ValueRemapFunction = std::function<ValueType(ValueType rangeStart,
ValueType rangeEnd,
ValueType valueToRemap)>;
/** Creates a NormalisableRange with a given range and an injective mapping function.
@param rangeStart The minimum value in the range.
@param rangeEnd The maximum value in the range.
@param convertFrom0To1Func A function which uses the current start and end of this NormalisableRange
and produces a mapped value from a normalised value.
@param convertTo0To1Func A function which uses the current start and end of this NormalisableRange
and produces a normalised value from a mapped value.
@param snapToLegalValueFunc A function which uses the current start and end of this NormalisableRange
to take a mapped value and snap it to the nearest legal value.
*/
NormalisableRange(ValueType rangeStart,
ValueType rangeEnd,
ValueRemapFunction convertFrom0To1Func,
ValueRemapFunction convertTo0To1Func,
ValueRemapFunction snapToLegalValueFunc = {}) noexcept
: start(rangeStart),
end(rangeEnd),
convertFrom0To1Function(std::move(convertFrom0To1Func)),
convertTo0To1Function(std::move(convertTo0To1Func)),
snapToLegalValueFunction(std::move(snapToLegalValueFunc))
{
checkInvariants();
}
/** Uses the properties of this mapping to convert a non-normalised value to
its 0->1 representation.
*/
ValueType convertTo0to1(ValueType v) const noexcept
{
if (convertTo0To1Function != nullptr)
return clampTo0To1(convertTo0To1Function(start, end, v));
auto proportion = clampTo0To1((v - start) / (end - start));
if (skew == static_cast<ValueType> (1))
return proportion;
if (!symmetricSkew)
return std::pow(proportion, skew);
auto distanceFromMiddle = static_cast<ValueType> (2) * proportion - static_cast<ValueType> (1);
return (static_cast<ValueType> (1) + std::pow(std::abs(distanceFromMiddle), skew)
* (distanceFromMiddle < ValueType() ? static_cast<ValueType> (-1)
: static_cast<ValueType> (1)))
/ static_cast<ValueType> (2);
}
/** Uses the properties of this mapping to convert a normalised 0->1 value to
its full-range representation.
*/
ValueType convertFrom0to1(ValueType proportion) const noexcept
{
proportion = clampTo0To1(proportion);
if (convertFrom0To1Function != nullptr)
return convertFrom0To1Function(start, end, proportion);
if (!symmetricSkew)
{
if (skew != static_cast<ValueType> (1) && proportion > ValueType())
proportion = std::exp(std::log(proportion) / skew);
return start + (end - start) * proportion;
}
auto distanceFromMiddle = static_cast<ValueType> (2) * proportion - static_cast<ValueType> (1);
if (skew != static_cast<ValueType> (1) && distanceFromMiddle != static_cast<ValueType> (0))
distanceFromMiddle = std::exp(std::log(std::abs(distanceFromMiddle)) / skew)
* (distanceFromMiddle < ValueType() ? static_cast<ValueType> (-1)
: static_cast<ValueType> (1));
return start + (end - start) / static_cast<ValueType> (2) * (static_cast<ValueType> (1) + distanceFromMiddle);
}
/** Takes a non-normalised value and snaps it based on either the interval property of
this NormalisableRange or the lambda function supplied to the constructor.
*/
ValueType snapToLegalValue(ValueType v) const noexcept
{
if (snapToLegalValueFunction != nullptr)
return snapToLegalValueFunction(start, end, v);
if (interval > ValueType())
v = start + interval * std::floor((v - start) / interval + static_cast<ValueType> (0.5));
return (v <= start || end <= start) ? start : (v >= end ? end : v);
}
/** Returns the extent of the normalisable range. */
Range<ValueType> getRange() const noexcept { return { start, end }; }
/** Given a value which is between the start and end points, this sets the skew
such that convertFrom0to1 (0.5) will return this value.
If you have used lambda functions for convertFrom0to1Func and convertFrom0to1Func in the
constructor of this class then the skew value is ignored.
@param centrePointValue this must be greater than the start of the range and less than the end.
*/
void setSkewForCentre(ValueType centrePointValue) noexcept
{
jassert(centrePointValue > start);
jassert(centrePointValue < end);
symmetricSkew = false;
skew = std::log(static_cast<ValueType> (0.5)) / std::log((centrePointValue - start) / (end - start));
checkInvariants();
}
/** The minimum value of the non-normalised range. */
ValueType start = 0;
/** The maximum value of the non-normalised range. */
ValueType end = 1;
/** The snapping interval that should be used (for a non-normalised value). Use 0 for a
continuous range.
If you have used a lambda function for snapToLegalValueFunction in the constructor of
this class then the interval is ignored.
*/
ValueType interval = 0;
/** An optional skew factor that alters the way values are distribute across the range.
The skew factor lets you skew the mapping logarithmically so that larger or smaller
values are given a larger proportion of the available space.
A factor of 1.0 has no skewing effect at all. If the factor is < 1.0, the lower end
of the range will fill more of the slider's length; if the factor is > 1.0, the upper
end of the range will be expanded.
If you have used lambda functions for convertFrom0to1Func and convertFrom0to1Func in the
constructor of this class then the skew value is ignored.
*/
ValueType skew = 1;
/** If true, the skew factor applies from the middle of the slider to each of its ends. */
bool symmetricSkew = false;
private:
void checkInvariants() const
{
jassert(end > start);
jassert(interval >= ValueType());
jassert(skew > ValueType());
}
static ValueType clampTo0To1(ValueType value)
{
auto clampedValue = jlimit(static_cast<ValueType> (0), static_cast<ValueType> (1), value);
// If you hit this assertion then either your normalisation function is not working
// correctly or your input is out of the expected bounds.
jassert(clampedValue == value);
return clampedValue;
}
ValueRemapFunction convertFrom0To1Function, convertTo0To1Function, snapToLegalValueFunction;
};
} // namespace juce
/*** End of inlined file: juce_NormalisableRange.h ***/
/*** Start of inlined file: juce_StatisticsAccumulator.h ***/
namespace juce
{
/**
A class that measures various statistics about a series of floating point
values that it is given.
@tags{Core}
*/
template <typename FloatType>
class StatisticsAccumulator
{
public:
/** Constructs a new StatisticsAccumulator. */
StatisticsAccumulator() = default;
/** Add a new value to the accumulator.
This will update all running statistics accordingly.
*/
void addValue(FloatType v) noexcept
{
jassert(juce_isfinite(v));
sum += v;
sumSquares += v * v;
++count;
if (v > maximum) maximum = v;
if (v < minimum) minimum = v;
}
/** Reset the accumulator.
This will reset all currently saved statistcs.
*/
void reset() noexcept { *this = StatisticsAccumulator<FloatType>(); }
/** Returns the average (arithmetic mean) of all previously added values.
If no values have been added yet, this will return zero.
*/
FloatType getAverage() const noexcept
{
return count > 0 ? sum / (FloatType)count
: FloatType();
}
/** Returns the variance of all previously added values.
If no values have been added yet, this will return zero.
*/
FloatType getVariance() const noexcept
{
return count > 0 ? (sumSquares - sum * sum / (FloatType)count) / (FloatType)count
: FloatType();
}
/** Returns the standard deviation of all previously added values.
If no values have been added yet, this will return zero.
*/
FloatType getStandardDeviation() const noexcept
{
return std::sqrt(getVariance());
}
/** Returns the smallest of all previously added values.
If no values have been added yet, this will return positive infinity.
*/
FloatType getMinValue() const noexcept
{
return minimum;
}
/** Returns the largest of all previously added values.
If no values have been added yet, this will return negative infinity.
*/
FloatType getMaxValue() const noexcept
{
return maximum;
}
/** Returns how many values have been added to this accumulator. */
size_t getCount() const noexcept
{
return count;
}
private:
struct KahanSum
{
KahanSum() = default;
operator FloatType() const noexcept { return sum; }
void JUCE_NO_ASSOCIATIVE_MATH_OPTIMISATIONS operator+= (FloatType value) noexcept
{
FloatType correctedValue = value - error;
FloatType newSum = sum + correctedValue;
error = (newSum - sum) - correctedValue;
sum = newSum;
}
FloatType sum{}, error{};
};
size_t count{ 0 };
KahanSum sum, sumSquares;
FloatType minimum{ std::numeric_limits<FloatType>::infinity() },
maximum{ -std::numeric_limits<FloatType>::infinity() };
};
} // namespace juce
/*** End of inlined file: juce_StatisticsAccumulator.h ***/
/*** Start of inlined file: juce_ElementComparator.h ***/
namespace juce
{
#ifndef DOXYGEN
/** This is an internal helper class which converts a juce ElementComparator style
class (using a "compareElements" method) into a class that's compatible with
std::sort (i.e. using an operator() to compare the elements)
@tags{Core}
*/
template <typename ElementComparator>
struct SortFunctionConverter
{
SortFunctionConverter(ElementComparator& e) : comparator(e) {}
template <typename Type>
bool operator() (Type a, Type b) { return comparator.compareElements(a, b) < 0; }
private:
ElementComparator& comparator;
SortFunctionConverter& operator= (const SortFunctionConverter&) = delete;
};
#endif
/**
Sorts a range of elements in an array.
The comparator object that is passed-in must define a public method with the following
signature:
@code
int compareElements (ElementType first, ElementType second);
@endcode
..and this method must return:
- a value of < 0 if the first comes before the second
- a value of 0 if the two objects are equivalent
- a value of > 0 if the second comes before the first
To improve performance, the compareElements() method can be declared as static or const.
@param comparator an object which defines a compareElements() method
@param array the array to sort
@param firstElement the index of the first element of the range to be sorted
@param lastElement the index of the last element in the range that needs
sorting (this is inclusive)
@param retainOrderOfEquivalentItems if true, the order of items that the
comparator deems the same will be maintained - this will be
a slower algorithm than if they are allowed to be moved around.
@see sortArrayRetainingOrder
*/
template <class ElementType, class ElementComparator>
static void sortArray(ElementComparator& comparator,
ElementType* const array,
int firstElement,
int lastElement,
const bool retainOrderOfEquivalentItems)
{
jassert(firstElement >= 0);
if (lastElement > firstElement)
{
SortFunctionConverter<ElementComparator> converter(comparator);
if (retainOrderOfEquivalentItems)
std::stable_sort(array + firstElement, array + lastElement + 1, converter);
else
std::sort(array + firstElement, array + lastElement + 1, converter);
}
}
/**
Searches a sorted array of elements, looking for the index at which a specified value
should be inserted for it to be in the correct order.
The comparator object that is passed-in must define a public method with the following
signature:
@code
int compareElements (ElementType first, ElementType second);
@endcode
..and this method must return:
- a value of < 0 if the first comes before the second
- a value of 0 if the two objects are equivalent
- a value of > 0 if the second comes before the first
To improve performance, the compareElements() method can be declared as static or const.
@param comparator an object which defines a compareElements() method
@param array the array to search
@param newElement the value that is going to be inserted
@param firstElement the index of the first element to search
@param lastElement the index of the last element in the range (this is non-inclusive)
*/
template <class ElementType, class ElementComparator>
static int findInsertIndexInSortedArray(ElementComparator& comparator,
ElementType* const array,
const ElementType newElement,
int firstElement,
int lastElement)
{
jassert(firstElement <= lastElement);
ignoreUnused(comparator); // if you pass in an object with a static compareElements() method, this
// avoids getting warning messages about the parameter being unused
while (firstElement < lastElement)
{
if (comparator.compareElements(newElement, array[firstElement]) == 0)
{
++firstElement;
break;
}
else
{
const int halfway = (firstElement + lastElement) >> 1;
if (halfway == firstElement)
{
if (comparator.compareElements(newElement, array[halfway]) >= 0)
++firstElement;
break;
}
else if (comparator.compareElements(newElement, array[halfway]) >= 0)
{
firstElement = halfway;
}
else
{
lastElement = halfway;
}
}
}
return firstElement;
}
/**
A simple ElementComparator class that can be used to sort an array of
objects that support the '<' operator.
This will work for primitive types and objects that implement operator<().
Example: @code
Array<int> myArray;
DefaultElementComparator<int> sorter;
myArray.sort (sorter);
@endcode
@see ElementComparator
@tags{Core}
*/
template <class ElementType>
class DefaultElementComparator
{
private:
using ParameterType = typename TypeHelpers::ParameterType<ElementType>::type;
public:
static int compareElements(ParameterType first, ParameterType second)
{
return (first < second) ? -1 : ((second < first) ? 1 : 0);
}
};
} // namespace juce
/*** End of inlined file: juce_ElementComparator.h ***/
/*** Start of inlined file: juce_ArrayAllocationBase.h ***/
namespace juce
{
/**
Implements some basic array storage allocation functions.
This class isn't really for public use - it used to be part of the
container classes but has since been superseded by ArrayBase. Eventually
it will be removed from the API.
@tags{Core}
*/
template <class ElementType, class TypeOfCriticalSectionToUse>
class ArrayAllocationBase : public TypeOfCriticalSectionToUse
{
public:
/** Creates an empty array. */
ArrayAllocationBase() = default;
/** Destructor. */
~ArrayAllocationBase() = default;
ArrayAllocationBase(ArrayAllocationBase&& other) noexcept
: elements(std::move(other.elements)),
numAllocated(other.numAllocated)
{
}
ArrayAllocationBase& operator= (ArrayAllocationBase&& other) noexcept
{
elements = std::move(other.elements);
numAllocated = other.numAllocated;
return *this;
}
/** Changes the amount of storage allocated.
This will retain any data currently held in the array, and either add or
remove extra space at the end.
@param numElements the number of elements that are needed
*/
void setAllocatedSize(int numElements)
{
if (numAllocated != numElements)
{
if (numElements > 0)
elements.realloc((size_t)numElements);
else
elements.free();
numAllocated = numElements;
}
}
/** Increases the amount of storage allocated if it is less than a given amount.
This will retain any data currently held in the array, but will add
extra space at the end to make sure there it's at least as big as the size
passed in. If it's already bigger, no action is taken.
@param minNumElements the minimum number of elements that are needed
*/
void ensureAllocatedSize(int minNumElements)
{
if (minNumElements > numAllocated)
setAllocatedSize((minNumElements + minNumElements / 2 + 8) & ~7);
jassert(numAllocated <= 0 || elements != nullptr);
}
/** Minimises the amount of storage allocated so that it's no more than
the given number of elements.
*/
void shrinkToNoMoreThan(int maxNumElements)
{
if (maxNumElements < numAllocated)
setAllocatedSize(maxNumElements);
}
/** Swap the contents of two objects. */
void swapWith(ArrayAllocationBase& other) noexcept
{
elements.swapWith(other.elements);
std::swap(numAllocated, other.numAllocated);
}
HeapBlock<ElementType> elements;
int numAllocated = 0;
private:
JUCE_DECLARE_NON_COPYABLE(ArrayAllocationBase)
};
} // namespace juce
/*** End of inlined file: juce_ArrayAllocationBase.h ***/
/*** Start of inlined file: juce_ArrayBase.h ***/
namespace juce
{
/**
A basic object container.
This class isn't really for public use - it's used by the other
array classes, but might come in handy for some purposes.
It inherits from a critical section class to allow the arrays to use
the "empty base class optimisation" pattern to reduce their footprint.
@see Array, OwnedArray, ReferenceCountedArray
@tags{Core}
*/
template <class ElementType, class TypeOfCriticalSectionToUse>
class ArrayBase : public TypeOfCriticalSectionToUse
{
private:
using ParameterType = typename TypeHelpers::ParameterType<ElementType>::type;
template <class OtherElementType, class OtherCriticalSection>
using AllowConversion = typename std::enable_if<!std::is_same<std::tuple<ElementType, TypeOfCriticalSectionToUse>,
std::tuple<OtherElementType, OtherCriticalSection>>::value>::type;
public:
ArrayBase() = default;
~ArrayBase()
{
clear();
}
ArrayBase(ArrayBase&& other) noexcept
: elements(std::move(other.elements)),
numAllocated(other.numAllocated),
numUsed(other.numUsed)
{
other.numAllocated = 0;
other.numUsed = 0;
}
ArrayBase& operator= (ArrayBase&& other) noexcept
{
if (this != &other)
{
auto tmp(std::move(other));
swapWith(tmp);
}
return *this;
}
/** Converting move constructor.
Only enabled when the other array has a different type to this one.
If you see a compile error here, it's probably because you're attempting a conversion that
HeapBlock won't allow.
*/
template <class OtherElementType,
class OtherCriticalSection,
typename = AllowConversion<OtherElementType, OtherCriticalSection>>
ArrayBase(ArrayBase<OtherElementType, OtherCriticalSection>&& other) noexcept
: elements(std::move(other.elements)),
numAllocated(other.numAllocated),
numUsed(other.numUsed)
{
other.numAllocated = 0;
other.numUsed = 0;
}
/** Converting move assignment operator.
Only enabled when the other array has a different type to this one.
If you see a compile error here, it's probably because you're attempting a conversion that
HeapBlock won't allow.
*/
template <class OtherElementType,
class OtherCriticalSection,
typename = AllowConversion<OtherElementType, OtherCriticalSection>>
ArrayBase & operator= (ArrayBase<OtherElementType, OtherCriticalSection>&& other) noexcept
{
// No need to worry about assignment to *this, because 'other' must be of a different type.
elements = std::move(other.elements);
numAllocated = other.numAllocated;
numUsed = other.numUsed;
other.numAllocated = 0;
other.numUsed = 0;
return *this;
}
template <class OtherArrayType>
bool operator== (const OtherArrayType& other) const noexcept
{
if (size() != (int)other.size())
return false;
auto* e = begin();
for (auto& o : other)
if (!(*e++ == o))
return false;
return true;
}
template <class OtherArrayType>
bool operator!= (const OtherArrayType& other) const noexcept
{
return !operator== (other);
}
inline ElementType& operator[] (const int index) noexcept
{
jassert(elements != nullptr);
jassert(isPositiveAndBelow(index, numUsed));
return elements[index];
}
inline const ElementType& operator[] (const int index) const noexcept
{
jassert(elements != nullptr);
jassert(isPositiveAndBelow(index, numUsed));
return elements[index];
}
inline ElementType getValueWithDefault(const int index) const noexcept
{
return isPositiveAndBelow(index, numUsed) ? elements[index] : ElementType();
}
inline ElementType getFirst() const noexcept
{
return numUsed > 0 ? elements[0] : ElementType();
}
inline ElementType getLast() const noexcept
{
return numUsed > 0 ? elements[numUsed - 1] : ElementType();
}
inline ElementType* begin() noexcept
{
return elements;
}
inline const ElementType* begin() const noexcept
{
return elements;
}
inline ElementType* end() noexcept
{
return elements + numUsed;
}
inline const ElementType* end() const noexcept
{
return elements + numUsed;
}
inline ElementType* data() noexcept
{
return elements;
}
inline const ElementType* data() const noexcept
{
return elements;
}
inline int size() const noexcept
{
return numUsed;
}
inline int capacity() const noexcept
{
return numAllocated;
}
void setAllocatedSize(int numElements)
{
jassert(numElements >= numUsed);
if (numAllocated != numElements)
{
if (numElements > 0)
setAllocatedSizeInternal(numElements);
else
elements.free();
}
numAllocated = numElements;
}
void ensureAllocatedSize(int minNumElements)
{
if (minNumElements > numAllocated)
setAllocatedSize((minNumElements + minNumElements / 2 + 8) & ~7);
jassert(numAllocated <= 0 || elements != nullptr);
}
void shrinkToNoMoreThan(int maxNumElements)
{
if (maxNumElements < numAllocated)
setAllocatedSize(maxNumElements);
}
void clear()
{
for (int i = 0; i < numUsed; ++i)
elements[i].~ElementType();
numUsed = 0;
}
void swapWith(ArrayBase& other) noexcept
{
elements.swapWith(other.elements);
std::swap(numAllocated, other.numAllocated);
std::swap(numUsed, other.numUsed);
}
void add(const ElementType& newElement)
{
addImpl(newElement);
}
void add(ElementType&& newElement)
{
addImpl(std::move(newElement));
}
template <typename... OtherElements>
void add(const ElementType& firstNewElement, OtherElements&&... otherElements)
{
addImpl(firstNewElement, std::forward<OtherElements>(otherElements)...);
}
template <typename... OtherElements>
void add(ElementType&& firstNewElement, OtherElements&&... otherElements)
{
addImpl(std::move(firstNewElement), std::forward<OtherElements>(otherElements)...);
}
template <typename Type>
void addArray(const Type* elementsToAdd, int numElementsToAdd)
{
ensureAllocatedSize(numUsed + numElementsToAdd);
addArrayInternal(elementsToAdd, numElementsToAdd);
numUsed += numElementsToAdd;
}
template <typename TypeToCreateFrom>
void addArray(const std::initializer_list<TypeToCreateFrom>& items)
{
ensureAllocatedSize(numUsed + (int)items.size());
for (auto& item : items)
new (elements + numUsed++) ElementType(item);
}
template <class OtherArrayType>
void addArray(const OtherArrayType& arrayToAddFrom)
{
jassert((const void*)this != (const void*)&arrayToAddFrom); // can't add from our own elements!
ensureAllocatedSize(numUsed + (int)arrayToAddFrom.size());
for (auto& e : arrayToAddFrom)
addAssumingCapacityIsReady(e);
}
template <class OtherArrayType>
typename std::enable_if<!std::is_pointer<OtherArrayType>::value, int>::type
addArray(const OtherArrayType& arrayToAddFrom,
int startIndex, int numElementsToAdd = -1)
{
jassert((const void*)this != (const void*)&arrayToAddFrom); // can't add from our own elements!
if (startIndex < 0)
{
jassertfalse;
startIndex = 0;
}
if (numElementsToAdd < 0 || startIndex + numElementsToAdd >(int) arrayToAddFrom.size())
numElementsToAdd = (int)arrayToAddFrom.size() - startIndex;
addArray(arrayToAddFrom.data() + startIndex, numElementsToAdd);
return numElementsToAdd;
}
void insert(int indexToInsertAt, ParameterType newElement, int numberOfTimesToInsertIt)
{
checkSourceIsNotAMember(newElement);
auto* space = createInsertSpace(indexToInsertAt, numberOfTimesToInsertIt);
for (int i = 0; i < numberOfTimesToInsertIt; ++i)
new (space++) ElementType(newElement);
numUsed += numberOfTimesToInsertIt;
}
void insertArray(int indexToInsertAt, const ElementType* newElements, int numberOfElements)
{
auto* space = createInsertSpace(indexToInsertAt, numberOfElements);
for (int i = 0; i < numberOfElements; ++i)
new (space++) ElementType(*(newElements++));
numUsed += numberOfElements;
}
void removeElements(int indexToRemoveAt, int numElementsToRemove)
{
jassert(indexToRemoveAt >= 0);
jassert(numElementsToRemove >= 0);
jassert(indexToRemoveAt + numElementsToRemove <= numUsed);
if (numElementsToRemove > 0)
{
removeElementsInternal(indexToRemoveAt, numElementsToRemove);
numUsed -= numElementsToRemove;
}
}
void swap(int index1, int index2)
{
if (isPositiveAndBelow(index1, numUsed)
&& isPositiveAndBelow(index2, numUsed))
{
std::swap(elements[index1],
elements[index2]);
}
}
void move(int currentIndex, int newIndex) noexcept
{
if (isPositiveAndBelow(currentIndex, numUsed))
{
if (!isPositiveAndBelow(newIndex, numUsed))
newIndex = numUsed - 1;
moveInternal(currentIndex, newIndex);
}
}
private:
template <typename T>
#if defined(__GNUC__) && __GNUC__ < 5 && ! defined(__clang__)
using IsTriviallyCopyable = std::is_scalar<T>;
#else
using IsTriviallyCopyable = std::is_trivially_copyable<T>;
#endif
template <typename T>
using TriviallyCopyableVoid = typename std::enable_if<IsTriviallyCopyable<T>::value, void>::type;
template <typename T>
using NonTriviallyCopyableVoid = typename std::enable_if<!IsTriviallyCopyable<T>::value, void>::type;
template <typename T = ElementType>
TriviallyCopyableVoid<T> addArrayInternal(const ElementType* otherElements, int numElements)
{
memcpy(elements + numUsed, otherElements, (size_t)numElements * sizeof(ElementType));
}
template <typename Type, typename T = ElementType>
TriviallyCopyableVoid<T> addArrayInternal(const Type* otherElements, int numElements)
{
auto* start = elements + numUsed;
while (--numElements >= 0)
new (start++) ElementType(*(otherElements++));
}
template <typename Type, typename T = ElementType>
NonTriviallyCopyableVoid<T> addArrayInternal(const Type* otherElements, int numElements)
{
auto* start = elements + numUsed;
while (--numElements >= 0)
new (start++) ElementType(*(otherElements++));
}
template <typename T = ElementType>
TriviallyCopyableVoid<T> setAllocatedSizeInternal(int numElements)
{
elements.realloc((size_t)numElements);
}
template <typename T = ElementType>
NonTriviallyCopyableVoid<T> setAllocatedSizeInternal(int numElements)
{
HeapBlock<ElementType> newElements(numElements);
for (int i = 0; i < numUsed; ++i)
{
new (newElements + i) ElementType(std::move(elements[i]));
elements[i].~ElementType();
}
elements = std::move(newElements);
}
ElementType* createInsertSpace(int indexToInsertAt, int numElements)
{
ensureAllocatedSize(numUsed + numElements);
if (!isPositiveAndBelow(indexToInsertAt, numUsed))
return elements + numUsed;
createInsertSpaceInternal(indexToInsertAt, numElements);
return elements + indexToInsertAt;
}
template <typename T = ElementType>
TriviallyCopyableVoid<T> createInsertSpaceInternal(int indexToInsertAt, int numElements)
{
auto* start = elements + indexToInsertAt;
auto numElementsToShift = numUsed - indexToInsertAt;
memmove(start + numElements, start, (size_t)numElementsToShift * sizeof(ElementType));
}
template <typename T = ElementType>
NonTriviallyCopyableVoid<T> createInsertSpaceInternal(int indexToInsertAt, int numElements)
{
auto* end = elements + numUsed;
auto* newEnd = end + numElements;
auto numElementsToShift = numUsed - indexToInsertAt;
for (int i = 0; i < numElementsToShift; ++i)
{
new (--newEnd) ElementType(std::move(*(--end)));
end->~ElementType();
}
}
template <typename T = ElementType>
TriviallyCopyableVoid<T> removeElementsInternal(int indexToRemoveAt, int numElementsToRemove)
{
auto* start = elements + indexToRemoveAt;
auto numElementsToShift = numUsed - (indexToRemoveAt + numElementsToRemove);
memmove(start, start + numElementsToRemove, (size_t)numElementsToShift * sizeof(ElementType));
}
template <typename T = ElementType>
NonTriviallyCopyableVoid<T> removeElementsInternal(int indexToRemoveAt, int numElementsToRemove)
{
auto numElementsToShift = numUsed - (indexToRemoveAt + numElementsToRemove);
auto* destination = elements + indexToRemoveAt;
auto* source = destination + numElementsToRemove;
for (int i = 0; i < numElementsToShift; ++i)
moveAssignElement(destination++, std::move(*(source++)));
for (int i = 0; i < numElementsToRemove; ++i)
(destination++)->~ElementType();
}
template <typename T = ElementType>
TriviallyCopyableVoid<T> moveInternal(int currentIndex, int newIndex) noexcept
{
char tempCopy[sizeof(ElementType)];
memcpy(tempCopy, elements + currentIndex, sizeof(ElementType));
if (newIndex > currentIndex)
{
memmove(elements + currentIndex,
elements + currentIndex + 1,
(size_t)(newIndex - currentIndex) * sizeof(ElementType));
}
else
{
memmove(elements + newIndex + 1,
elements + newIndex,
(size_t)(currentIndex - newIndex) * sizeof(ElementType));
}
memcpy(elements + newIndex, tempCopy, sizeof(ElementType));
}
template <typename T = ElementType>
NonTriviallyCopyableVoid<T> moveInternal(int currentIndex, int newIndex) noexcept
{
auto* e = elements + currentIndex;
ElementType tempCopy(std::move(*e));
auto delta = newIndex - currentIndex;
if (delta > 0)
{
for (int i = 0; i < delta; ++i)
{
moveAssignElement(e, std::move(*(e + 1)));
++e;
}
}
else
{
for (int i = 0; i < -delta; ++i)
{
moveAssignElement(e, std::move(*(e - 1)));
--e;
}
}
moveAssignElement(e, std::move(tempCopy));
}
template <typename... Elements>
void addImpl(Elements&&... toAdd)
{
ignoreUnused(std::initializer_list<int> { (((void)checkSourceIsNotAMember(toAdd)), 0)... });
ensureAllocatedSize(numUsed + (int)sizeof... (toAdd));
addAssumingCapacityIsReady(std::forward<Elements>(toAdd)...);
}
template <typename... Elements>
void addAssumingCapacityIsReady(Elements&&... toAdd)
{
ignoreUnused(std::initializer_list<int> { ((void)(new (elements + numUsed++) ElementType(std::forward<Elements>(toAdd))), 0)... });
}
template <typename T = ElementType>
typename std::enable_if<std::is_move_assignable<T>::value, void>::type
moveAssignElement(ElementType* destination, ElementType&& source)
{
*destination = std::move(source);
}
template <typename T = ElementType>
typename std::enable_if<!std::is_move_assignable<T>::value, void>::type
moveAssignElement(ElementType* destination, ElementType&& source)
{
destination->~ElementType();
new (destination) ElementType(std::move(source));
}
void checkSourceIsNotAMember(const ElementType& element)
{
// when you pass a reference to an existing element into a method like add() which
// may need to reallocate the array to make more space, the incoming reference may
// be deleted indirectly during the reallocation operation! To work around this,
// make a local copy of the item you're trying to add (and maybe use std::move to
// move it into the add() method to avoid any extra overhead)
jassert(std::addressof(element) < begin() || end() <= std::addressof(element));
ignoreUnused(element);
}
HeapBlock<ElementType> elements;
int numAllocated = 0, numUsed = 0;
template <class OtherElementType, class OtherCriticalSection>
friend class ArrayBase;
JUCE_DECLARE_NON_COPYABLE(ArrayBase)
};
} // namespace juce
/*** End of inlined file: juce_ArrayBase.h ***/
/*** Start of inlined file: juce_Array.h ***/
namespace juce
{
/**
Holds a resizable array of primitive or copy-by-value objects.
Examples of arrays are: Array<int>, Array<Rectangle> or Array<MyClass*>
The Array class can be used to hold simple, non-polymorphic objects as well as primitive types - to
do so, the class must fulfill these requirements:
- it must have a copy constructor and assignment operator
- it must be able to be relocated in memory by a memcpy without this causing any problems - so
objects whose functionality relies on external pointers or references to themselves can not be used.
You can of course have an array of pointers to any kind of object, e.g. Array<MyClass*>, but if
you do this, the array doesn't take any ownership of the objects - see the OwnedArray class or the
ReferenceCountedArray class for more powerful ways of holding lists of objects.
For holding lists of strings, you can use Array\<String\>, but it's usually better to use the
specialised class StringArray, which provides more useful functions.
To make all the array's methods thread-safe, pass in "CriticalSection" as the templated
TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection.
@see OwnedArray, ReferenceCountedArray, StringArray, CriticalSection
@tags{Core}
*/
template <typename ElementType,
typename TypeOfCriticalSectionToUse = DummyCriticalSection,
int minimumAllocatedSize = 0>
class Array
{
private:
using ParameterType = typename TypeHelpers::ParameterType<ElementType>::type;
public:
/** Creates an empty array. */
Array() = default;
/** Creates a copy of another array.
@param other the array to copy
*/
Array(const Array& other)
{
const ScopedLockType lock(other.getLock());
values.addArray(other.values.begin(), other.values.size());
}
Array(Array&& other) noexcept
: values(std::move(other.values))
{
}
/** Initalises from a null-terminated raw array of values.
@param data the data to copy from
*/
template <typename TypeToCreateFrom>
explicit Array(const TypeToCreateFrom* data)
{
while (*values != TypeToCreateFrom())
add(*data++);
}
/** Initalises from a raw array of values.
@param data the data to copy from
@param numValues the number of values in the array
*/
template <typename TypeToCreateFrom>
Array(const TypeToCreateFrom* data, int numValues)
{
values.addArray(data, numValues);
}
/** Initalises an Array of size 1 containing a single element. */
Array(const ElementType& singleElementToAdd)
{
add(singleElementToAdd);
}
/** Initalises an Array of size 1 containing a single element. */
Array(ElementType&& singleElementToAdd)
{
add(std::move(singleElementToAdd));
}
/** Initalises an Array from a list of items. */
template <typename... OtherElements>
Array(const ElementType& firstNewElement, OtherElements&&... otherElements)
{
values.add(firstNewElement, std::forward<OtherElements>(otherElements)...);
}
/** Initalises an Array from a list of items. */
template <typename... OtherElements>
Array(ElementType&& firstNewElement, OtherElements&&... otherElements)
{
values.add(std::move(firstNewElement), std::forward<OtherElements>(otherElements)...);
}
template <typename TypeToCreateFrom>
Array(const std::initializer_list<TypeToCreateFrom>& items)
{
addArray(items);
}
/** Destructor. */
~Array() = default;
/** Copies another array.
@param other the array to copy
*/
Array& operator= (const Array& other)
{
if (this != &other)
{
auto otherCopy(other);
swapWith(otherCopy);
}
return *this;
}
Array& operator= (Array&& other) noexcept
{
const ScopedLockType lock(getLock());
values = std::move(other.values);
return *this;
}
/** Compares this array to another one.
Two arrays are considered equal if they both contain the same set of
elements, in the same order.
@param other the other array to compare with
*/
template <class OtherArrayType>
bool operator== (const OtherArrayType& other) const
{
const ScopedLockType lock(getLock());
const typename OtherArrayType::ScopedLockType lock2(other.getLock());
return values == other;
}
/** Compares this array to another one.
Two arrays are considered equal if they both contain the same set of
elements, in the same order.
@param other the other array to compare with
*/
template <class OtherArrayType>
bool operator!= (const OtherArrayType& other) const
{
return !operator== (other);
}
/** Removes all elements from the array.
This will remove all the elements, and free any storage that the array is
using. To clear the array without freeing the storage, use the clearQuick()
method instead.
@see clearQuick
*/
void clear()
{
const ScopedLockType lock(getLock());
clearQuick();
values.setAllocatedSize(0);
}
/** Removes all elements from the array without freeing the array's allocated storage.
@see clear
*/
void clearQuick()
{
const ScopedLockType lock(getLock());
values.clear();
}
/** Fills the Array with the provided value. */
void fill(const ParameterType& newValue) noexcept
{
const ScopedLockType lock(getLock());
for (auto& e : *this)
e = newValue;
}
/** Returns the current number of elements in the array. */
inline int size() const noexcept
{
const ScopedLockType lock(getLock());
return values.size();
}
/** Returns true if the array is empty, false otherwise. */
inline bool isEmpty() const noexcept
{
return size() == 0;
}
/** Returns one of the elements in the array.
If the index passed in is beyond the range of valid elements, this
will return a default value.
If you're certain that the index will always be a valid element, you
can call getUnchecked() instead, which is faster.
@param index the index of the element being requested (0 is the first element in the array)
@see getUnchecked, getFirst, getLast
*/
ElementType operator[] (int index) const
{
const ScopedLockType lock(getLock());
return values.getValueWithDefault(index);
}
/** Returns one of the elements in the array, without checking the index passed in.
Unlike the operator[] method, this will try to return an element without
checking that the index is within the bounds of the array, so should only
be used when you're confident that it will always be a valid index.
@param index the index of the element being requested (0 is the first element in the array)
@see operator[], getFirst, getLast
*/
inline ElementType getUnchecked(int index) const
{
const ScopedLockType lock(getLock());
return values[index];
}
/** Returns a direct reference to one of the elements in the array, without checking the index passed in.
This is like getUnchecked, but returns a direct reference to the element, so that
you can alter it directly. Obviously this can be dangerous, so only use it when
absolutely necessary.
@param index the index of the element being requested (0 is the first element in the array)
@see operator[], getFirst, getLast
*/
inline ElementType& getReference(int index) noexcept
{
const ScopedLockType lock(getLock());
return values[index];
}
/** Returns a direct reference to one of the elements in the array, without checking the index passed in.
This is like getUnchecked, but returns a direct reference to the element. Obviously
this can be dangerous, so only use it when absolutely necessary.
@param index the index of the element being requested (0 is the first element in the array)
@see operator[], getFirst, getLast
*/
inline const ElementType& getReference(int index) const noexcept
{
const ScopedLockType lock(getLock());
return values[index];
}
/** Returns the first element in the array, or a default value if the array is empty.
@see operator[], getUnchecked, getLast
*/
inline ElementType getFirst() const noexcept
{
const ScopedLockType lock(getLock());
return values.getFirst();
}
/** Returns the last element in the array, or a default value if the array is empty.
@see operator[], getUnchecked, getFirst
*/
inline ElementType getLast() const noexcept
{
const ScopedLockType lock(getLock());
return values.getLast();
}
/** Returns a pointer to the actual array data.
This pointer will only be valid until the next time a non-const method
is called on the array.
*/
inline ElementType* getRawDataPointer() noexcept
{
return values.begin();
}
/** Returns a pointer to the actual array data.
This pointer will only be valid until the next time a non-const method
is called on the array.
*/
inline const ElementType* getRawDataPointer() const noexcept
{
return values.begin();
}
/** Returns a pointer to the first element in the array.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline ElementType* begin() noexcept
{
return values.begin();
}
/** Returns a pointer to the first element in the array.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline const ElementType* begin() const noexcept
{
return values.begin();
}
/** Returns a pointer to the element which follows the last element in the array.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline ElementType* end() noexcept
{
return values.end();
}
/** Returns a pointer to the element which follows the last element in the array.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline const ElementType* end() const noexcept
{
return values.end();
}
/** Returns a pointer to the first element in the array.
This method is provided for compatibility with the standard C++ containers.
*/
inline ElementType* data() noexcept
{
return begin();
}
/** Returns a pointer to the first element in the array.
This method is provided for compatibility with the standard C++ containers.
*/
inline const ElementType* data() const noexcept
{
return begin();
}
/** Finds the index of the first element which matches the value passed in.
This will search the array for the given object, and return the index
of its first occurrence. If the object isn't found, the method will return -1.
@param elementToLookFor the value or object to look for
@returns the index of the object, or -1 if it's not found
*/
int indexOf(ParameterType elementToLookFor) const
{
const ScopedLockType lock(getLock());
auto e = values.begin();
auto endPtr = values.end();
for (; e != endPtr; ++e)
if (elementToLookFor == *e)
return static_cast<int> (e - values.begin());
return -1;
}
/** Returns true if the array contains at least one occurrence of an object.
@param elementToLookFor the value or object to look for
@returns true if the item is found
*/
bool contains(ParameterType elementToLookFor) const
{
const ScopedLockType lock(getLock());
auto e = values.begin();
auto endPtr = values.end();
for (; e != endPtr; ++e)
if (elementToLookFor == *e)
return true;
return false;
}
/** Appends a new element at the end of the array.
@param newElement the new object to add to the array
@see set, insert, addIfNotAlreadyThere, addSorted, addUsingDefaultSort, addArray
*/
void add(const ElementType& newElement)
{
const ScopedLockType lock(getLock());
values.add(newElement);
}
/** Appends a new element at the end of the array.
@param newElement the new object to add to the array
@see set, insert, addIfNotAlreadyThere, addSorted, addUsingDefaultSort, addArray
*/
void add(ElementType&& newElement)
{
const ScopedLockType lock(getLock());
values.add(std::move(newElement));
}
/** Appends multiple new elements at the end of the array. */
template <typename... OtherElements>
void add(const ElementType& firstNewElement, OtherElements&&... otherElements)
{
const ScopedLockType lock(getLock());
values.add(firstNewElement, std::forward<OtherElements>(otherElements)...);
}
/** Appends multiple new elements at the end of the array. */
template <typename... OtherElements>
void add(ElementType&& firstNewElement, OtherElements&&... otherElements)
{
const ScopedLockType lock(getLock());
values.add(std::move(firstNewElement), std::forward<OtherElements>(otherElements)...);
}
/** Inserts a new element into the array at a given position.
If the index is less than 0 or greater than the size of the array, the
element will be added to the end of the array.
Otherwise, it will be inserted into the array, moving all the later elements
along to make room.
@param indexToInsertAt the index at which the new element should be
inserted (pass in -1 to add it to the end)
@param newElement the new object to add to the array
@see add, addSorted, addUsingDefaultSort, set
*/
void insert(int indexToInsertAt, ParameterType newElement)
{
const ScopedLockType lock(getLock());
values.insert(indexToInsertAt, newElement, 1);
}
/** Inserts multiple copies of an element into the array at a given position.
If the index is less than 0 or greater than the size of the array, the
element will be added to the end of the array.
Otherwise, it will be inserted into the array, moving all the later elements
along to make room.
@param indexToInsertAt the index at which the new element should be inserted
@param newElement the new object to add to the array
@param numberOfTimesToInsertIt how many copies of the value to insert
@see insert, add, addSorted, set
*/
void insertMultiple(int indexToInsertAt, ParameterType newElement,
int numberOfTimesToInsertIt)
{
if (numberOfTimesToInsertIt > 0)
{
const ScopedLockType lock(getLock());
values.insert(indexToInsertAt, newElement, numberOfTimesToInsertIt);
}
}
/** Inserts an array of values into this array at a given position.
If the index is less than 0 or greater than the size of the array, the
new elements will be added to the end of the array.
Otherwise, they will be inserted into the array, moving all the later elements
along to make room.
@param indexToInsertAt the index at which the first new element should be inserted
@param newElements the new values to add to the array
@param numberOfElements how many items are in the array
@see insert, add, addSorted, set
*/
void insertArray(int indexToInsertAt,
const ElementType* newElements,
int numberOfElements)
{
if (numberOfElements > 0)
{
const ScopedLockType lock(getLock());
values.insertArray(indexToInsertAt, newElements, numberOfElements);
}
}
/** Appends a new element at the end of the array as long as the array doesn't
already contain it.
If the array already contains an element that matches the one passed in, nothing
will be done.
@param newElement the new object to add to the array
@return true if the element was added to the array; false otherwise.
*/
bool addIfNotAlreadyThere(ParameterType newElement)
{
const ScopedLockType lock(getLock());
if (contains(newElement))
return false;
add(newElement);
return true;
}
/** Replaces an element with a new value.
If the index is less than zero, this method does nothing.
If the index is beyond the end of the array, the item is added to the end of the array.
@param indexToChange the index whose value you want to change
@param newValue the new value to set for this index.
@see add, insert
*/
void set(int indexToChange, ParameterType newValue)
{
if (indexToChange >= 0)
{
const ScopedLockType lock(getLock());
if (indexToChange < values.size())
values[indexToChange] = newValue;
else
values.add(newValue);
}
else
{
jassertfalse;
}
}
/** Replaces an element with a new value without doing any bounds-checking.
This just sets a value directly in the array's internal storage, so you'd
better make sure it's in range!
@param indexToChange the index whose value you want to change
@param newValue the new value to set for this index.
@see set, getUnchecked
*/
void setUnchecked(int indexToChange, ParameterType newValue)
{
const ScopedLockType lock(getLock());
jassert(isPositiveAndBelow(indexToChange, values.size()));
values[indexToChange] = newValue;
}
/** Adds elements from an array to the end of this array.
@param elementsToAdd an array of some kind of object from which elements
can be constructed.
@param numElementsToAdd how many elements are in this other array
@see add
*/
template <typename Type>
void addArray(const Type* elementsToAdd, int numElementsToAdd)
{
const ScopedLockType lock(getLock());
if (numElementsToAdd > 0)
values.addArray(elementsToAdd, numElementsToAdd);
}
template <typename TypeToCreateFrom>
void addArray(const std::initializer_list<TypeToCreateFrom>& items)
{
const ScopedLockType lock(getLock());
values.addArray(items);
}
/** Adds elements from a null-terminated array of pointers to the end of this array.
@param elementsToAdd an array of pointers to some kind of object from which elements
can be constructed. This array must be terminated by a nullptr
@see addArray
*/
template <typename Type>
void addNullTerminatedArray(const Type* const* elementsToAdd)
{
int num = 0;
for (auto e = elementsToAdd; *e != nullptr; ++e)
++num;
addArray(elementsToAdd, num);
}
/** This swaps the contents of this array with those of another array.
If you need to exchange two arrays, this is vastly quicker than using copy-by-value
because it just swaps their internal pointers.
*/
template <class OtherArrayType>
void swapWith(OtherArrayType& otherArray) noexcept
{
const ScopedLockType lock1(getLock());
const typename OtherArrayType::ScopedLockType lock2(otherArray.getLock());
values.swapWith(otherArray.values);
}
/** Adds elements from another array to the end of this array.
@param arrayToAddFrom the array from which to copy the elements
@see add
*/
template <class OtherArrayType>
void addArray(const OtherArrayType& arrayToAddFrom)
{
const typename OtherArrayType::ScopedLockType lock1(arrayToAddFrom.getLock());
const ScopedLockType lock2(getLock());
values.addArray(arrayToAddFrom);
}
/** Adds elements from another array to the end of this array.
@param arrayToAddFrom the array from which to copy the elements
@param startIndex the first element of the other array to start copying from
@param numElementsToAdd how many elements to add from the other array. If this
value is negative or greater than the number of available elements,
all available elements will be copied.
@see add
*/
template <class OtherArrayType>
typename std::enable_if<!std::is_pointer<OtherArrayType>::value, void>::type
addArray(const OtherArrayType& arrayToAddFrom,
int startIndex,
int numElementsToAdd = -1)
{
const typename OtherArrayType::ScopedLockType lock1(arrayToAddFrom.getLock());
const ScopedLockType lock2(getLock());
values.addArray(arrayToAddFrom, startIndex, numElementsToAdd);
}
/** This will enlarge or shrink the array to the given number of elements, by adding
or removing items from its end.
If the array is smaller than the given target size, empty elements will be appended
until its size is as specified. If its size is larger than the target, items will be
removed from its end to shorten it.
*/
void resize(int targetNumItems)
{
jassert(targetNumItems >= 0);
auto numToAdd = targetNumItems - values.size();
if (numToAdd > 0)
insertMultiple(values.size(), ElementType(), numToAdd);
else if (numToAdd < 0)
removeRange(targetNumItems, -numToAdd);
}
/** Inserts a new element into the array, assuming that the array is sorted.
This will use a comparator to find the position at which the new element
should go. If the array isn't sorted, the behaviour of this
method will be unpredictable.
@param comparator the comparator to use to compare the elements - see the sort()
method for details about the form this object should take
@param newElement the new element to insert to the array
@returns the index at which the new item was added
@see addUsingDefaultSort, add, sort
*/
template <class ElementComparator>
int addSorted(ElementComparator& comparator, ParameterType newElement)
{
const ScopedLockType lock(getLock());
auto index = findInsertIndexInSortedArray(comparator, values.begin(), newElement, 0, values.size());
insert(index, newElement);
return index;
}
/** Inserts a new element into the array, assuming that the array is sorted.
This will use the DefaultElementComparator class for sorting, so your ElementType
must be suitable for use with that class. If the array isn't sorted, the behaviour of this
method will be unpredictable.
@param newElement the new element to insert to the array
@see addSorted, sort
*/
void addUsingDefaultSort(ParameterType newElement)
{
DefaultElementComparator <ElementType> comparator;
addSorted(comparator, newElement);
}
/** Finds the index of an element in the array, assuming that the array is sorted.
This will use a comparator to do a binary-chop to find the index of the given
element, if it exists. If the array isn't sorted, the behaviour of this
method will be unpredictable.
@param comparator the comparator to use to compare the elements - see the sort()
method for details about the form this object should take
@param elementToLookFor the element to search for
@returns the index of the element, or -1 if it's not found
@see addSorted, sort
*/
template <typename ElementComparator, typename TargetValueType>
int indexOfSorted(ElementComparator& comparator, TargetValueType elementToLookFor) const
{
ignoreUnused(comparator); // if you pass in an object with a static compareElements() method, this
// avoids getting warning messages about the parameter being unused
const ScopedLockType lock(getLock());
for (int s = 0, e = values.size();;)
{
if (s >= e)
return -1;
if (comparator.compareElements(elementToLookFor, values[s]) == 0)
return s;
auto halfway = (s + e) / 2;
if (halfway == s)
return -1;
if (comparator.compareElements(elementToLookFor, values[halfway]) >= 0)
s = halfway;
else
e = halfway;
}
}
/** Removes an element from the array.
This will remove the element at a given index, and move back
all the subsequent elements to close the gap.
If the index passed in is out-of-range, nothing will happen.
@param indexToRemove the index of the element to remove
@see removeAndReturn, removeFirstMatchingValue, removeAllInstancesOf, removeRange
*/
void remove(int indexToRemove)
{
const ScopedLockType lock(getLock());
if (isPositiveAndBelow(indexToRemove, values.size()))
removeInternal(indexToRemove);
}
/** Removes an element from the array.
This will remove the element at a given index, and move back
all the subsequent elements to close the gap.
If the index passed in is out-of-range, nothing will happen.
@param indexToRemove the index of the element to remove
@returns the element that has been removed
@see removeFirstMatchingValue, removeAllInstancesOf, removeRange
*/
ElementType removeAndReturn(int indexToRemove)
{
const ScopedLockType lock(getLock());
if (isPositiveAndBelow(indexToRemove, values.size()))
{
ElementType removed(values[indexToRemove]);
removeInternal(indexToRemove);
return removed;
}
return ElementType();
}
/** Removes an element from the array.
This will remove the element pointed to by the given iterator,
and move back all the subsequent elements to close the gap.
If the iterator passed in does not point to an element within the
array, behaviour is undefined.
@param elementToRemove a pointer to the element to remove
@see removeFirstMatchingValue, removeAllInstancesOf, removeRange, removeIf
*/
void remove(const ElementType* elementToRemove)
{
jassert(elementToRemove != nullptr);
const ScopedLockType lock(getLock());
jassert(values.begin() != nullptr);
auto indexToRemove = (int)(elementToRemove - values.begin());
if (!isPositiveAndBelow(indexToRemove, values.size()))
{
jassertfalse;
return;
}
removeInternal(indexToRemove);
}
/** Removes an item from the array.
This will remove the first occurrence of the given element from the array.
If the item isn't found, no action is taken.
@param valueToRemove the object to try to remove
@see remove, removeRange, removeIf
*/
void removeFirstMatchingValue(ParameterType valueToRemove)
{
const ScopedLockType lock(getLock());
auto* e = values.begin();
for (int i = 0; i < values.size(); ++i)
{
if (valueToRemove == e[i])
{
removeInternal(i);
break;
}
}
}
/** Removes items from the array.
This will remove all occurrences of the given element from the array.
If no such items are found, no action is taken.
@param valueToRemove the object to try to remove
@return how many objects were removed.
@see remove, removeRange, removeIf
*/
int removeAllInstancesOf(ParameterType valueToRemove)
{
int numRemoved = 0;
const ScopedLockType lock(getLock());
for (int i = values.size(); --i >= 0;)
{
if (valueToRemove == values[i])
{
removeInternal(i);
++numRemoved;
}
}
return numRemoved;
}
/** Removes items from the array.
This will remove all objects from the array that match a condition.
If no such items are found, no action is taken.
@param predicate the condition when to remove an item. Must be a callable
type that takes an ElementType and returns a bool
@return how many objects were removed.
@see remove, removeRange, removeAllInstancesOf
*/
template <typename PredicateType>
int removeIf(PredicateType&& predicate)
{
int numRemoved = 0;
const ScopedLockType lock(getLock());
for (int i = values.size(); --i >= 0;)
{
if (predicate(values[i]))
{
removeInternal(i);
++numRemoved;
}
}
return numRemoved;
}
/** Removes a range of elements from the array.
This will remove a set of elements, starting from the given index,
and move subsequent elements down to close the gap.
If the range extends beyond the bounds of the array, it will
be safely clipped to the size of the array.
@param startIndex the index of the first element to remove
@param numberToRemove how many elements should be removed
@see remove, removeFirstMatchingValue, removeAllInstancesOf, removeIf
*/
void removeRange(int startIndex, int numberToRemove)
{
const ScopedLockType lock(getLock());
auto endIndex = jlimit(0, values.size(), startIndex + numberToRemove);
startIndex = jlimit(0, values.size(), startIndex);
numberToRemove = endIndex - startIndex;
if (numberToRemove > 0)
{
values.removeElements(startIndex, numberToRemove);
minimiseStorageAfterRemoval();
}
}
/** Removes the last n elements from the array.
@param howManyToRemove how many elements to remove from the end of the array
@see remove, removeFirstMatchingValue, removeAllInstancesOf, removeRange
*/
void removeLast(int howManyToRemove = 1)
{
jassert(howManyToRemove >= 0);
if (howManyToRemove > 0)
{
const ScopedLockType lock(getLock());
if (howManyToRemove > values.size())
howManyToRemove = values.size();
values.removeElements(values.size() - howManyToRemove, howManyToRemove);
minimiseStorageAfterRemoval();
}
}
/** Removes any elements which are also in another array.
@param otherArray the other array in which to look for elements to remove
@see removeValuesNotIn, remove, removeFirstMatchingValue, removeAllInstancesOf, removeRange
*/
template <class OtherArrayType>
void removeValuesIn(const OtherArrayType& otherArray)
{
const typename OtherArrayType::ScopedLockType lock1(otherArray.getLock());
const ScopedLockType lock2(getLock());
if (this == &otherArray)
{
clear();
}
else
{
if (otherArray.size() > 0)
{
for (int i = values.size(); --i >= 0;)
if (otherArray.contains(values[i]))
removeInternal(i);
}
}
}
/** Removes any elements which are not found in another array.
Only elements which occur in this other array will be retained.
@param otherArray the array in which to look for elements NOT to remove
@see removeValuesIn, remove, removeFirstMatchingValue, removeAllInstancesOf, removeRange
*/
template <class OtherArrayType>
void removeValuesNotIn(const OtherArrayType& otherArray)
{
const typename OtherArrayType::ScopedLockType lock1(otherArray.getLock());
const ScopedLockType lock2(getLock());
if (this != &otherArray)
{
if (otherArray.size() <= 0)
{
clear();
}
else
{
for (int i = values.size(); --i >= 0;)
if (!otherArray.contains(values[i]))
removeInternal(i);
}
}
}
/** Swaps over two elements in the array.
This swaps over the elements found at the two indexes passed in.
If either index is out-of-range, this method will do nothing.
@param index1 index of one of the elements to swap
@param index2 index of the other element to swap
*/
void swap(int index1, int index2)
{
const ScopedLockType lock(getLock());
values.swap(index1, index2);
}
/** Moves one of the values to a different position.
This will move the value to a specified index, shuffling along
any intervening elements as required.
So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling
move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }.
@param currentIndex the index of the value to be moved. If this isn't a
valid index, then nothing will be done
@param newIndex the index at which you'd like this value to end up. If this
is less than zero, the value will be moved to the end
of the array
*/
void move(int currentIndex, int newIndex) noexcept
{
if (currentIndex != newIndex)
{
const ScopedLockType lock(getLock());
values.move(currentIndex, newIndex);
}
}
/** Reduces the amount of storage being used by the array.
Arrays typically allocate slightly more storage than they need, and after
removing elements, they may have quite a lot of unused space allocated.
This method will reduce the amount of allocated storage to a minimum.
*/
void minimiseStorageOverheads()
{
const ScopedLockType lock(getLock());
values.shrinkToNoMoreThan(values.size());
}
/** Increases the array's internal storage to hold a minimum number of elements.
Calling this before adding a large known number of elements means that
the array won't have to keep dynamically resizing itself as the elements
are added, and it'll therefore be more efficient.
*/
void ensureStorageAllocated(int minNumElements)
{
const ScopedLockType lock(getLock());
values.ensureAllocatedSize(minNumElements);
}
/** Sorts the array using a default comparison operation.
If the type of your elements isn't supported by the DefaultElementComparator class
then you may need to use the other version of sort, which takes a custom comparator.
*/
void sort()
{
DefaultElementComparator<ElementType> comparator;
sort(comparator);
}
/** Sorts the elements in the array.
This will use a comparator object to sort the elements into order. The object
passed must have a method of the form:
@code
int compareElements (ElementType first, ElementType second);
@endcode
..and this method must return:
- a value of < 0 if the first comes before the second
- a value of 0 if the two objects are equivalent
- a value of > 0 if the second comes before the first
To improve performance, the compareElements() method can be declared as static or const.
@param comparator the comparator to use for comparing elements.
@param retainOrderOfEquivalentItems if this is true, then items
which the comparator says are equivalent will be
kept in the order in which they currently appear
in the array. This is slower to perform, but may
be important in some cases. If it's false, a faster
algorithm is used, but equivalent elements may be
rearranged.
@see addSorted, indexOfSorted, sortArray
*/
template <class ElementComparator>
void sort(ElementComparator& comparator,
bool retainOrderOfEquivalentItems = false)
{
const ScopedLockType lock(getLock());
ignoreUnused(comparator); // if you pass in an object with a static compareElements() method, this
// avoids getting warning messages about the parameter being unused
sortArray(comparator, values.begin(), 0, size() - 1, retainOrderOfEquivalentItems);
}
/** Returns the CriticalSection that locks this array.
To lock, you can call getLock().enter() and getLock().exit(), or preferably use
an object of ScopedLockType as an RAII lock for it.
*/
inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return values; }
/** Returns the type of scoped lock to use for locking this array */
using ScopedLockType = typename TypeOfCriticalSectionToUse::ScopedLockType;
#ifndef DOXYGEN
// Note that the swapWithArray method has been replaced by a more flexible templated version,
// and renamed "swapWith" to be more consistent with the names used in other classes.
JUCE_DEPRECATED_WITH_BODY(void swapWithArray(Array& other) noexcept, { swapWith(other); })
#endif
private:
ArrayBase<ElementType, TypeOfCriticalSectionToUse> values;
void removeInternal(int indexToRemove)
{
values.removeElements(indexToRemove, 1);
minimiseStorageAfterRemoval();
}
void minimiseStorageAfterRemoval()
{
if (values.capacity() > jmax(minimumAllocatedSize, values.size() * 2))
values.shrinkToNoMoreThan(jmax(values.size(), jmax(minimumAllocatedSize, 64 / (int)sizeof(ElementType))));
}
};
} // namespace juce
/*** End of inlined file: juce_Array.h ***/
/*** Start of inlined file: juce_LinkedListPointer.h ***/
namespace juce
{
/**
Helps to manipulate singly-linked lists of objects.
For objects that are designed to contain a pointer to the subsequent item in the
list, this class contains methods to deal with the list. To use it, the ObjectType
class that it points to must contain a LinkedListPointer called nextListItem, e.g.
@code
struct MyObject
{
int x, y, z;
// A linkable object must contain a member with this name and type, which must be
// accessible by the LinkedListPointer class. (This doesn't mean it has to be public -
// you could make your class a friend of a LinkedListPointer<MyObject> instead).
LinkedListPointer<MyObject> nextListItem;
};
LinkedListPointer<MyObject> myList;
myList.append (new MyObject());
myList.append (new MyObject());
int numItems = myList.size(); // returns 2
MyObject* lastInList = myList.getLast();
@endcode
@tags{Core}
*/
template <class ObjectType>
class LinkedListPointer
{
public:
/** Creates a null pointer to an empty list. */
LinkedListPointer() noexcept
: item(nullptr)
{
}
/** Creates a pointer to a list whose head is the item provided. */
explicit LinkedListPointer(ObjectType* const headItem) noexcept
: item(headItem)
{
}
/** Sets this pointer to point to a new list. */
LinkedListPointer& operator= (ObjectType* const newItem) noexcept
{
item = newItem;
return *this;
}
LinkedListPointer(LinkedListPointer&& other) noexcept
: item(other.item)
{
other.item = nullptr;
}
LinkedListPointer& operator= (LinkedListPointer&& other) noexcept
{
jassert(this != &other); // hopefully the compiler should make this situation impossible!
item = other.item;
other.item = nullptr;
return *this;
}
/** Returns the item which this pointer points to. */
inline operator ObjectType* () const noexcept
{
return item;
}
/** Returns the item which this pointer points to. */
inline ObjectType* get() const noexcept
{
return item;
}
/** Returns the last item in the list which this pointer points to.
This will iterate the list and return the last item found. Obviously the speed
of this operation will be proportional to the size of the list. If the list is
empty the return value will be this object.
If you're planning on appending a number of items to your list, it's much more
efficient to use the Appender class than to repeatedly call getLast() to find the end.
*/
LinkedListPointer& getLast() noexcept
{
auto* l = this;
while (l->item != nullptr)
l = &(l->item->nextListItem);
return *l;
}
/** Returns the number of items in the list.
Obviously with a simple linked list, getting the size involves iterating the list, so
this can be a lengthy operation - be careful when using this method in your code.
*/
int size() const noexcept
{
int total = 0;
for (auto* i = item; i != nullptr; i = i->nextListItem)
++total;
return total;
}
/** Returns the item at a given index in the list.
Since the only way to find an item is to iterate the list, this operation can obviously
be slow, depending on its size, so you should be careful when using this in algorithms.
*/
LinkedListPointer& operator[] (int index) noexcept
{
auto* l = this;
while (--index >= 0 && l->item != nullptr)
l = &(l->item->nextListItem);
return *l;
}
/** Returns the item at a given index in the list.
Since the only way to find an item is to iterate the list, this operation can obviously
be slow, depending on its size, so you should be careful when using this in algorithms.
*/
const LinkedListPointer& operator[] (int index) const noexcept
{
auto* l = this;
while (--index >= 0 && l->item != nullptr)
l = &(l->item->nextListItem);
return *l;
}
/** Returns true if the list contains the given item. */
bool contains(const ObjectType* const itemToLookFor) const noexcept
{
for (auto* i = item; i != nullptr; i = i->nextListItem)
if (itemToLookFor == i)
return true;
return false;
}
/** Inserts an item into the list, placing it before the item that this pointer
currently points to.
*/
void insertNext(ObjectType* const newItem)
{
jassert(newItem != nullptr);
jassert(newItem->nextListItem == nullptr);
newItem->nextListItem = item;
item = newItem;
}
/** Inserts an item at a numeric index in the list.
Obviously this will involve iterating the list to find the item at the given index,
so be careful about the impact this may have on execution time.
*/
void insertAtIndex(int index, ObjectType* newItem)
{
jassert(newItem != nullptr);
auto* l = this;
while (index != 0 && l->item != nullptr)
{
l = &(l->item->nextListItem);
--index;
}
l->insertNext(newItem);
}
/** Replaces the object that this pointer points to, appending the rest of the list to
the new object, and returning the old one.
*/
ObjectType* replaceNext(ObjectType* const newItem) noexcept
{
jassert(newItem != nullptr);
jassert(newItem->nextListItem == nullptr);
auto oldItem = item;
item = newItem;
item->nextListItem = oldItem->nextListItem.item;
oldItem->nextListItem.item = nullptr;
return oldItem;
}
/** Adds an item to the end of the list.
This operation involves iterating the whole list, so can be slow - if you need to
append a number of items to your list, it's much more efficient to use the Appender
class than to repeatedly call append().
*/
void append(ObjectType* const newItem)
{
getLast().item = newItem;
}
/** Creates copies of all the items in another list and adds them to this one.
This will use the ObjectType's copy constructor to try to create copies of each
item in the other list, and appends them to this list.
*/
void addCopyOfList(const LinkedListPointer& other)
{
auto* insertPoint = this;
for (auto* i = other.item; i != nullptr; i = i->nextListItem)
{
insertPoint->insertNext(new ObjectType(*i));
insertPoint = &(insertPoint->item->nextListItem);
}
}
/** Removes the head item from the list.
This won't delete the object that is removed, but returns it, so the caller can
delete it if necessary.
*/
ObjectType* removeNext() noexcept
{
auto oldItem = item;
if (oldItem != nullptr)
{
item = oldItem->nextListItem;
oldItem->nextListItem.item = nullptr;
}
return oldItem;
}
/** Removes a specific item from the list.
Note that this will not delete the item, it simply unlinks it from the list.
*/
void remove(ObjectType* const itemToRemove)
{
if (auto* l = findPointerTo(itemToRemove))
l->removeNext();
}
/** Iterates the list, calling the delete operator on all of its elements and
leaving this pointer empty.
*/
void deleteAll()
{
while (item != nullptr)
{
auto oldItem = item;
item = oldItem->nextListItem;
delete oldItem;
}
}
/** Finds a pointer to a given item.
If the item is found in the list, this returns the pointer that points to it. If
the item isn't found, this returns null.
*/
LinkedListPointer* findPointerTo(ObjectType* const itemToLookFor) noexcept
{
auto* l = this;
while (l->item != nullptr)
{
if (l->item == itemToLookFor)
return l;
l = &(l->item->nextListItem);
}
return nullptr;
}
/** Copies the items in the list to an array.
The destArray must contain enough elements to hold the entire list - no checks are
made for this!
*/
void copyToArray(ObjectType** destArray) const noexcept
{
jassert(destArray != nullptr);
for (auto* i = item; i != nullptr; i = i->nextListItem)
*destArray++ = i;
}
/** Swaps this pointer with another one */
void swapWith(LinkedListPointer& other) noexcept
{
std::swap(item, other.item);
}
/**
Allows efficient repeated insertions into a list.
You can create an Appender object which points to the last element in your
list, and then repeatedly call Appender::append() to add items to the end
of the list in O(1) time.
*/
class Appender
{
public:
/** Creates an appender which will add items to the given list.
*/
Appender(LinkedListPointer& endOfListPointer) noexcept
: endOfList(&endOfListPointer)
{
// This can only be used to add to the end of a list.
jassert(endOfListPointer.item == nullptr);
}
/** Appends an item to the list. */
void append(ObjectType* const newItem) noexcept
{
*endOfList = newItem;
endOfList = &(newItem->nextListItem);
}
private:
LinkedListPointer* endOfList;
JUCE_DECLARE_NON_COPYABLE(Appender)
};
private:
ObjectType* item;
JUCE_DECLARE_NON_COPYABLE(LinkedListPointer)
};
} // namespace juce
/*** End of inlined file: juce_LinkedListPointer.h ***/
/*** Start of inlined file: juce_ListenerList.h ***/
namespace juce
{
/**
Holds a set of objects and can invoke a member function callback on each object
in the set with a single call.
Use a ListenerList to manage a set of objects which need a callback, and you
can invoke a member function by simply calling call() or callChecked().
E.g.
@code
class MyListenerType
{
public:
void myCallbackMethod (int foo, bool bar);
};
ListenerList<MyListenerType> listeners;
listeners.add (someCallbackObjects...);
// This will invoke myCallbackMethod (1234, true) on each of the objects
// in the list...
listeners.call ([] (MyListenerType& l) { l.myCallbackMethod (1234, true); });
@endcode
If you add or remove listeners from the list during one of the callbacks - i.e. while
it's in the middle of iterating the listeners, then it's guaranteed that no listeners
will be mistakenly called after they've been removed, but it may mean that some of the
listeners could be called more than once, or not at all, depending on the list's order.
Sometimes, there's a chance that invoking one of the callbacks might result in the
list itself being deleted while it's still iterating - to survive this situation, you can
use callChecked() instead of call(), passing it a local object to act as a "BailOutChecker".
The BailOutChecker must implement a method of the form "bool shouldBailOut()", and
the list will check this after each callback to determine whether it should abort the
operation. For an example of a bail-out checker, see the Component::BailOutChecker class,
which can be used to check when a Component has been deleted. See also
ListenerList::DummyBailOutChecker, which is a dummy checker that always returns false.
@tags{Core}
*/
template <class ListenerClass,
class ArrayType = Array<ListenerClass*>>
class ListenerList
{
public:
/** Creates an empty list. */
ListenerList() = default;
/** Destructor. */
~ListenerList() = default;
/** Adds a listener to the list.
A listener can only be added once, so if the listener is already in the list,
this method has no effect.
@see remove
*/
void add(ListenerClass* listenerToAdd)
{
if (listenerToAdd != nullptr)
listeners.addIfNotAlreadyThere(listenerToAdd);
else
jassertfalse; // Listeners can't be null pointers!
}
/** Removes a listener from the list.
If the listener wasn't in the list, this has no effect.
*/
void remove(ListenerClass* listenerToRemove)
{
jassert(listenerToRemove != nullptr); // Listeners can't be null pointers!
listeners.removeFirstMatchingValue(listenerToRemove);
}
/** Returns the number of registered listeners. */
int size() const noexcept { return listeners.size(); }
/** Returns true if no listeners are registered, false otherwise. */
bool isEmpty() const noexcept { return listeners.isEmpty(); }
/** Clears the list. */
void clear() { listeners.clear(); }
/** Returns true if the specified listener has been added to the list. */
bool contains(ListenerClass* listener) const noexcept { return listeners.contains(listener); }
/** Returns the raw array of listeners. */
const ArrayType& getListeners() const noexcept { return listeners; }
/** Calls a member function on each listener in the list, with multiple parameters. */
template <typename Callback>
void call(Callback&& callback)
{
typename ArrayType::ScopedLockType lock(listeners.getLock());
for (Iterator<DummyBailOutChecker, ThisType> iter(*this); iter.next();)
callback(*iter.getListener());
}
/** Calls a member function with 1 parameter, on all but the specified listener in the list.
This can be useful if the caller is also a listener and needs to exclude itself.
*/
template <typename Callback>
void callExcluding(ListenerClass* listenerToExclude, Callback&& callback)
{
typename ArrayType::ScopedLockType lock(listeners.getLock());
for (Iterator<DummyBailOutChecker, ThisType> iter(*this); iter.next();)
{
auto* l = iter.getListener();
if (l != listenerToExclude)
callback(*l);
}
}
/** Calls a member function on each listener in the list, with 1 parameter and a bail-out-checker.
See the class description for info about writing a bail-out checker.
*/
template <typename Callback, typename BailOutCheckerType>
void callChecked(const BailOutCheckerType& bailOutChecker, Callback&& callback)
{
typename ArrayType::ScopedLockType lock(listeners.getLock());
for (Iterator<BailOutCheckerType, ThisType> iter(*this); iter.next(bailOutChecker);)
callback(*iter.getListener());
}
/** Calls a member function, with 1 parameter, on all but the specified listener in the list
with a bail-out-checker. This can be useful if the caller is also a listener and needs to
exclude itself. See the class description for info about writing a bail-out checker.
*/
template <typename Callback, typename BailOutCheckerType>
void callCheckedExcluding(ListenerClass* listenerToExclude,
const BailOutCheckerType& bailOutChecker,
Callback&& callback)
{
typename ArrayType::ScopedLockType lock(listeners.getLock());
for (Iterator<BailOutCheckerType, ThisType> iter(*this); iter.next(bailOutChecker);)
{
auto* l = iter.getListener();
if (l != listenerToExclude)
callback(*l);
}
}
/** A dummy bail-out checker that always returns false.
See the ListenerList notes for more info about bail-out checkers.
*/
struct DummyBailOutChecker
{
bool shouldBailOut() const noexcept { return false; }
};
using ThisType = ListenerList<ListenerClass, ArrayType>;
using ListenerType = ListenerClass;
/** Iterates the listeners in a ListenerList. */
template <class BailOutCheckerType, class ListType>
struct Iterator
{
Iterator(const ListType& listToIterate) noexcept
: list(listToIterate), index(listToIterate.size())
{}
~Iterator() = default;
bool next() noexcept
{
if (index <= 0)
return false;
auto listSize = list.size();
if (--index < listSize)
return true;
index = listSize - 1;
return index >= 0;
}
bool next(const BailOutCheckerType& bailOutChecker) noexcept
{
return (!bailOutChecker.shouldBailOut()) && next();
}
typename ListType::ListenerType* getListener() const noexcept
{
return list.getListeners().getUnchecked(index);
}
private:
const ListType& list;
int index;
JUCE_DECLARE_NON_COPYABLE(Iterator)
};
#ifndef DOXYGEN
// There are now lambda-based call functions that can be used to replace these old method-based versions.
// We'll eventually deprecate these old ones, so please begin moving your code to use lambdas!
void call(void (ListenerClass::* callbackFunction) ())
{
call([=](ListenerClass& l) { (l.*callbackFunction)(); });
}
void callExcluding(ListenerClass* listenerToExclude, void (ListenerClass::* callbackFunction) ())
{
callExcluding(listenerToExclude, [=](ListenerClass& l) { (l.*callbackFunction)(); });
}
template <class BailOutCheckerType>
void callChecked(const BailOutCheckerType& bailOutChecker, void (ListenerClass::* callbackFunction) ())
{
callChecked(bailOutChecker, [=](ListenerClass& l) { (l.*callbackFunction)(); });
}
template <class BailOutCheckerType>
void callCheckedExcluding(ListenerClass* listenerToExclude,
const BailOutCheckerType& bailOutChecker,
void (ListenerClass::* callbackFunction) ())
{
callCheckedExcluding(listenerToExclude, bailOutChecker, [=](ListenerClass& l) { (l.*callbackFunction)(); });
}
template <typename... MethodArgs, typename... Args>
void call(void (ListenerClass::* callbackFunction) (MethodArgs...), Args&&... args)
{
typename ArrayType::ScopedLockType lock(listeners.getLock());
for (Iterator<DummyBailOutChecker, ThisType> iter(*this); iter.next();)
(iter.getListener()->*callbackFunction) (static_cast<typename TypeHelpers::ParameterType<Args>::type> (args)...);
}
template <typename... MethodArgs, typename... Args>
void callExcluding(ListenerClass* listenerToExclude,
void (ListenerClass::* callbackFunction) (MethodArgs...),
Args&&... args)
{
typename ArrayType::ScopedLockType lock(listeners.getLock());
for (Iterator<DummyBailOutChecker, ThisType> iter(*this); iter.next();)
if (iter.getListener() != listenerToExclude)
(iter.getListener()->*callbackFunction) (static_cast<typename TypeHelpers::ParameterType<Args>::type> (args)...);
}
template <typename BailOutCheckerType, typename... MethodArgs, typename... Args>
void callChecked(const BailOutCheckerType& bailOutChecker,
void (ListenerClass::* callbackFunction) (MethodArgs...),
Args&&... args)
{
typename ArrayType::ScopedLockType lock(listeners.getLock());
for (Iterator<BailOutCheckerType, ThisType> iter(*this); iter.next(bailOutChecker);)
(iter.getListener()->*callbackFunction) (static_cast<typename TypeHelpers::ParameterType<Args>::type> (args)...);
}
template <typename BailOutCheckerType, typename... MethodArgs, typename... Args>
void callCheckedExcluding(ListenerClass* listenerToExclude,
const BailOutCheckerType& bailOutChecker,
void (ListenerClass::* callbackFunction) (MethodArgs...),
Args&&... args)
{
typename ArrayType::ScopedLockType lock(listeners.getLock());
for (Iterator<BailOutCheckerType, ThisType> iter(*this); iter.next(bailOutChecker);)
if (iter.getListener() != listenerToExclude)
(iter.getListener()->*callbackFunction) (static_cast<typename TypeHelpers::ParameterType<Args>::type> (args)...);
}
#endif
private:
ArrayType listeners;
JUCE_DECLARE_NON_COPYABLE(ListenerList)
};
} // namespace juce
/*** End of inlined file: juce_ListenerList.h ***/
/*** Start of inlined file: juce_OwnedArray.h ***/
namespace juce
{
/** An array designed for holding objects.
This holds a list of pointers to objects, and will automatically
delete the objects when they are removed from the array, or when the
array is itself deleted.
Declare it in the form: OwnedArray<MyObjectClass>
..and then add new objects, e.g. myOwnedArray.add (new MyObjectClass());
After adding objects, they are 'owned' by the array and will be deleted when
removed or replaced.
To make all the array's methods thread-safe, pass in "CriticalSection" as the templated
TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection.
@see Array, ReferenceCountedArray, StringArray, CriticalSection
@tags{Core}
*/
template <class ObjectClass,
class TypeOfCriticalSectionToUse = DummyCriticalSection>
class OwnedArray
{
public:
/** Creates an empty array. */
OwnedArray() = default;
/** Deletes the array and also deletes any objects inside it.
To get rid of the array without deleting its objects, use its
clear (false) method before deleting it.
*/
~OwnedArray()
{
deleteAllObjects();
}
/** Move constructor. */
OwnedArray(OwnedArray&& other) noexcept
: values(std::move(other.values))
{
}
/** Creates an array from a list of objects. */
OwnedArray(const std::initializer_list<ObjectClass*>& items)
{
addArray(items);
}
/** Move assignment operator. */
OwnedArray& operator= (OwnedArray&& other) noexcept
{
const ScopedLockType lock(getLock());
deleteAllObjects();
values = std::move(other.values);
return *this;
}
/** Converting move constructor. */
template <class OtherObjectClass, class OtherCriticalSection>
OwnedArray(OwnedArray<OtherObjectClass, OtherCriticalSection>&& other) noexcept
: values(std::move(other.values))
{
}
/** Converting move assignment operator. */
template <class OtherObjectClass, class OtherCriticalSection>
OwnedArray& operator= (OwnedArray<OtherObjectClass, OtherCriticalSection>&& other) noexcept
{
const ScopedLockType lock(getLock());
deleteAllObjects();
values = std::move(other.values);
return *this;
}
/** Clears the array, optionally deleting the objects inside it first. */
void clear(bool deleteObjects = true)
{
const ScopedLockType lock(getLock());
clearQuick(deleteObjects);
values.setAllocatedSize(0);
}
/** Clears the array, optionally deleting the objects inside it first. */
void clearQuick(bool deleteObjects)
{
const ScopedLockType lock(getLock());
if (deleteObjects)
deleteAllObjects();
else
values.clear();
}
/** Returns the number of items currently in the array.
@see operator[]
*/
inline int size() const noexcept
{
return values.size();
}
/** Returns true if the array is empty, false otherwise. */
inline bool isEmpty() const noexcept
{
return size() == 0;
}
/** Returns a pointer to the object at this index in the array.
If the index is out-of-range, this will return a null pointer, (and
it could be null anyway, because it's ok for the array to hold null
pointers as well as objects).
@see getUnchecked
*/
inline ObjectClass* operator[] (int index) const noexcept
{
const ScopedLockType lock(getLock());
return values.getValueWithDefault(index);
}
/** Returns a pointer to the object at this index in the array, without checking whether the index is in-range.
This is a faster and less safe version of operator[] which doesn't check the index passed in, so
it can be used when you're sure the index is always going to be legal.
*/
inline ObjectClass* getUnchecked(int index) const noexcept
{
const ScopedLockType lock(getLock());
return values[index];
}
/** Returns a pointer to the first object in the array.
This will return a null pointer if the array's empty.
@see getLast
*/
inline ObjectClass* getFirst() const noexcept
{
const ScopedLockType lock(getLock());
return values.getFirst();
}
/** Returns a pointer to the last object in the array.
This will return a null pointer if the array's empty.
@see getFirst
*/
inline ObjectClass* getLast() const noexcept
{
const ScopedLockType lock(getLock());
return values.getLast();
}
/** Returns a pointer to the actual array data.
This pointer will only be valid until the next time a non-const method
is called on the array.
*/
inline ObjectClass** getRawDataPointer() noexcept
{
return values.begin();
}
/** Returns a pointer to the first element in the array.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline ObjectClass** begin() noexcept
{
return values.begin();
}
/** Returns a pointer to the first element in the array.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline ObjectClass* const* begin() const noexcept
{
return values.begin();
}
/** Returns a pointer to the element which follows the last element in the array.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline ObjectClass** end() noexcept
{
return values.end();
}
/** Returns a pointer to the element which follows the last element in the array.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline ObjectClass* const* end() const noexcept
{
return values.end();
}
/** Returns a pointer to the first element in the array.
This method is provided for compatibility with the standard C++ containers.
*/
inline ObjectClass** data() noexcept
{
return begin();
}
/** Returns a pointer to the first element in the array.
This method is provided for compatibility with the standard C++ containers.
*/
inline ObjectClass* const* data() const noexcept
{
return begin();
}
/** Finds the index of an object which might be in the array.
@param objectToLookFor the object to look for
@returns the index at which the object was found, or -1 if it's not found
*/
int indexOf(const ObjectClass* objectToLookFor) const noexcept
{
const ScopedLockType lock(getLock());
auto* e = values.begin();
for (; e != values.end(); ++e)
if (objectToLookFor == *e)
return static_cast<int> (e - values.begin());
return -1;
}
/** Returns true if the array contains a specified object.
@param objectToLookFor the object to look for
@returns true if the object is in the array
*/
bool contains(const ObjectClass* objectToLookFor) const noexcept
{
const ScopedLockType lock(getLock());
auto* e = values.begin();
for (; e != values.end(); ++e)
if (objectToLookFor == *e)
return true;
return false;
}
/** Appends a new object to the end of the array.
Note that this object will be deleted by the OwnedArray when it is removed,
so be careful not to delete it somewhere else.
Also be careful not to add the same object to the array more than once,
as this will obviously cause deletion of dangling pointers.
@param newObject the new object to add to the array
@returns the new object that was added
@see set, insert, addSorted
*/
ObjectClass* add(ObjectClass* newObject)
{
const ScopedLockType lock(getLock());
values.add(newObject);
return newObject;
}
/** Appends a new object to the end of the array.
Note that this object will be deleted by the OwnedArray when it is removed,
so be careful not to delete it somewhere else.
Also be careful not to add the same object to the array more than once,
as this will obviously cause deletion of dangling pointers.
@param newObject the new object to add to the array
@returns the new object that was added
@see set, insert, addSorted
*/
ObjectClass* add(std::unique_ptr<ObjectClass> newObject)
{
return add(newObject.release());
}
/** Inserts a new object into the array at the given index.
Note that this object will be deleted by the OwnedArray when it is removed,
so be careful not to delete it somewhere else.
If the index is less than 0 or greater than the size of the array, the
element will be added to the end of the array.
Otherwise, it will be inserted into the array, moving all the later elements
along to make room.
Be careful not to add the same object to the array more than once,
as this will obviously cause deletion of dangling pointers.
@param indexToInsertAt the index at which the new element should be inserted
@param newObject the new object to add to the array
@returns the new object that was added
@see add, addSorted, set
*/
ObjectClass* insert(int indexToInsertAt, ObjectClass* newObject)
{
const ScopedLockType lock(getLock());
values.insert(indexToInsertAt, newObject, 1);
return newObject;
}
/** Inserts a new object into the array at the given index.
Note that this object will be deleted by the OwnedArray when it is removed,
so be careful not to delete it somewhere else.
If the index is less than 0 or greater than the size of the array, the
element will be added to the end of the array.
Otherwise, it will be inserted into the array, moving all the later elements
along to make room.
Be careful not to add the same object to the array more than once,
as this will obviously cause deletion of dangling pointers.
@param indexToInsertAt the index at which the new element should be inserted
@param newObject the new object to add to the array
@returns the new object that was added
@see add, addSorted, set
*/
ObjectClass* insert(int indexToInsertAt, std::unique_ptr<ObjectClass> newObject)
{
return insert(indexToInsertAt, newObject.release());
}
/** Inserts an array of values into this array at a given position.
If the index is less than 0 or greater than the size of the array, the
new elements will be added to the end of the array.
Otherwise, they will be inserted into the array, moving all the later elements
along to make room.
@param indexToInsertAt the index at which the first new element should be inserted
@param newObjects the new values to add to the array
@param numberOfElements how many items are in the array
@see insert, add, addSorted, set
*/
void insertArray(int indexToInsertAt,
ObjectClass* const* newObjects,
int numberOfElements)
{
if (numberOfElements > 0)
{
const ScopedLockType lock(getLock());
values.insertArray(indexToInsertAt, newObjects, numberOfElements);
}
}
/** Replaces an object in the array with a different one.
If the index is less than zero, this method does nothing.
If the index is beyond the end of the array, the new object is added to the end of the array.
Be careful not to add the same object to the array more than once,
as this will obviously cause deletion of dangling pointers.
@param indexToChange the index whose value you want to change
@param newObject the new value to set for this index.
@param deleteOldElement whether to delete the object that's being replaced with the new one
@see add, insert, remove
*/
ObjectClass* set(int indexToChange, ObjectClass* newObject, bool deleteOldElement = true)
{
if (indexToChange >= 0)
{
std::unique_ptr<ObjectClass> toDelete;
{
const ScopedLockType lock(getLock());
if (indexToChange < values.size())
{
if (deleteOldElement)
{
toDelete.reset(values[indexToChange]);
if (toDelete.get() == newObject)
toDelete.release();
}
values[indexToChange] = newObject;
}
else
{
values.add(newObject);
}
}
}
else
{
jassertfalse; // you're trying to set an object at a negative index, which doesn't have
// any effect - but since the object is not being added, it may be leaking..
}
return newObject;
}
/** Replaces an object in the array with a different one.
If the index is less than zero, this method does nothing.
If the index is beyond the end of the array, the new object is added to the end of the array.
Be careful not to add the same object to the array more than once,
as this will obviously cause deletion of dangling pointers.
@param indexToChange the index whose value you want to change
@param newObject the new value to set for this index.
@param deleteOldElement whether to delete the object that's being replaced with the new one
@see add, insert, remove
*/
ObjectClass* set(int indexToChange, std::unique_ptr<ObjectClass> newObject, bool deleteOldElement = true)
{
return set(indexToChange, newObject.release(), deleteOldElement);
}
/** Adds elements from another array to the end of this array.
@param arrayToAddFrom the array from which to copy the elements
@param startIndex the first element of the other array to start copying from
@param numElementsToAdd how many elements to add from the other array. If this
value is negative or greater than the number of available elements,
all available elements will be copied.
@see add
*/
template <class OtherArrayType>
void addArray(const OtherArrayType& arrayToAddFrom,
int startIndex = 0,
int numElementsToAdd = -1)
{
const typename OtherArrayType::ScopedLockType lock1(arrayToAddFrom.getLock());
const ScopedLockType lock2(getLock());
values.addArray(arrayToAddFrom, startIndex, numElementsToAdd);
}
/** Adds elements from another array to the end of this array. */
template <typename OtherArrayType>
void addArray(const std::initializer_list<OtherArrayType>& items)
{
const ScopedLockType lock(getLock());
values.addArray(items);
}
/** Adds copies of the elements in another array to the end of this array.
The other array must be either an OwnedArray of a compatible type of object, or an Array
containing pointers to the same kind of object. The objects involved must provide
a copy constructor, and this will be used to create new copies of each element, and
add them to this array.
@param arrayToAddFrom the array from which to copy the elements
@param startIndex the first element of the other array to start copying from
@param numElementsToAdd how many elements to add from the other array. If this
value is negative or greater than the number of available elements,
all available elements will be copied.
@see add
*/
template <class OtherArrayType>
void addCopiesOf(const OtherArrayType& arrayToAddFrom,
int startIndex = 0,
int numElementsToAdd = -1)
{
const typename OtherArrayType::ScopedLockType lock1(arrayToAddFrom.getLock());
const ScopedLockType lock2(getLock());
if (startIndex < 0)
{
jassertfalse;
startIndex = 0;
}
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size())
numElementsToAdd = arrayToAddFrom.size() - startIndex;
jassert(numElementsToAdd >= 0);
values.ensureAllocatedSize(values.size() + numElementsToAdd);
while (--numElementsToAdd >= 0)
values.add(createCopyIfNotNull(arrayToAddFrom.getUnchecked(startIndex++)));
}
/** Inserts a new object into the array assuming that the array is sorted.
This will use a comparator to find the position at which the new object
should go. If the array isn't sorted, the behaviour of this
method will be unpredictable.
@param comparator the comparator to use to compare the elements - see the sort method
for details about this object's structure
@param newObject the new object to insert to the array
@returns the index at which the new object was added
@see add, sort, indexOfSorted
*/
template <class ElementComparator>
int addSorted(ElementComparator& comparator, ObjectClass* newObject) noexcept
{
// If you pass in an object with a static compareElements() method, this
// avoids getting warning messages about the parameter being unused
ignoreUnused(comparator);
const ScopedLockType lock(getLock());
auto index = findInsertIndexInSortedArray(comparator, values.begin(), newObject, 0, values.size());
insert(index, newObject);
return index;
}
/** Finds the index of an object in the array, assuming that the array is sorted.
This will use a comparator to do a binary-chop to find the index of the given
element, if it exists. If the array isn't sorted, the behaviour of this
method will be unpredictable.
@param comparator the comparator to use to compare the elements - see the sort()
method for details about the form this object should take
@param objectToLookFor the object to search for
@returns the index of the element, or -1 if it's not found
@see addSorted, sort
*/
template <typename ElementComparator>
int indexOfSorted(ElementComparator& comparator, const ObjectClass* objectToLookFor) const noexcept
{
// If you pass in an object with a static compareElements() method, this
// avoids getting warning messages about the parameter being unused
ignoreUnused(comparator);
const ScopedLockType lock(getLock());
int s = 0, e = values.size();
while (s < e)
{
if (comparator.compareElements(objectToLookFor, values[s]) == 0)
return s;
auto halfway = (s + e) / 2;
if (halfway == s)
break;
if (comparator.compareElements(objectToLookFor, values[halfway]) >= 0)
s = halfway;
else
e = halfway;
}
return -1;
}
/** Removes an object from the array.
This will remove the object at a given index (optionally also
deleting it) and move back all the subsequent objects to close the gap.
If the index passed in is out-of-range, nothing will happen.
@param indexToRemove the index of the element to remove
@param deleteObject whether to delete the object that is removed
@see removeObject, removeRange
*/
void remove(int indexToRemove, bool deleteObject = true)
{
std::unique_ptr<ObjectClass> toDelete;
{
const ScopedLockType lock(getLock());
if (isPositiveAndBelow(indexToRemove, values.size()))
{
auto** e = values.begin() + indexToRemove;
if (deleteObject)
toDelete.reset(*e);
values.removeElements(indexToRemove, 1);
}
}
if ((values.size() << 1) < values.capacity())
minimiseStorageOverheads();
}
/** Removes and returns an object from the array without deleting it.
This will remove the object at a given index and return it, moving back all
the subsequent objects to close the gap. If the index passed in is out-of-range,
nothing will happen.
@param indexToRemove the index of the element to remove
@see remove, removeObject, removeRange
*/
ObjectClass* removeAndReturn(int indexToRemove)
{
ObjectClass* removedItem = nullptr;
const ScopedLockType lock(getLock());
if (isPositiveAndBelow(indexToRemove, values.size()))
{
removedItem = values[indexToRemove];
values.removeElements(indexToRemove, 1);
if ((values.size() << 1) < values.capacity())
minimiseStorageOverheads();
}
return removedItem;
}
/** Removes a specified object from the array.
If the item isn't found, no action is taken.
@param objectToRemove the object to try to remove
@param deleteObject whether to delete the object (if it's found)
@see remove, removeRange
*/
void removeObject(const ObjectClass* objectToRemove, bool deleteObject = true)
{
const ScopedLockType lock(getLock());
for (int i = 0; i < values.size(); ++i)
{
if (objectToRemove == values[i])
{
remove(i, deleteObject);
break;
}
}
}
/** Removes a range of objects from the array.
This will remove a set of objects, starting from the given index,
and move any subsequent elements down to close the gap.
If the range extends beyond the bounds of the array, it will
be safely clipped to the size of the array.
@param startIndex the index of the first object to remove
@param numberToRemove how many objects should be removed
@param deleteObjects whether to delete the objects that get removed
@see remove, removeObject
*/
void removeRange(int startIndex, int numberToRemove, bool deleteObjects = true)
{
const ScopedLockType lock(getLock());
auto endIndex = jlimit(0, values.size(), startIndex + numberToRemove);
startIndex = jlimit(0, values.size(), startIndex);
numberToRemove = endIndex - startIndex;
if (numberToRemove > 0)
{
Array<ObjectClass*> objectsToDelete;
if (deleteObjects)
objectsToDelete.addArray(values.begin() + startIndex, numberToRemove);
values.removeElements(startIndex, numberToRemove);
for (auto& o : objectsToDelete)
ContainerDeletePolicy<ObjectClass>::destroy(o);
if ((values.size() << 1) < values.capacity())
minimiseStorageOverheads();
}
}
/** Removes the last n objects from the array.
@param howManyToRemove how many objects to remove from the end of the array
@param deleteObjects whether to also delete the objects that are removed
@see remove, removeObject, removeRange
*/
void removeLast(int howManyToRemove = 1,
bool deleteObjects = true)
{
const ScopedLockType lock(getLock());
if (howManyToRemove >= values.size())
clear(deleteObjects);
else
removeRange(values.size() - howManyToRemove, howManyToRemove, deleteObjects);
}
/** Swaps a pair of objects in the array.
If either of the indexes passed in is out-of-range, nothing will happen,
otherwise the two objects at these positions will be exchanged.
*/
void swap(int index1, int index2) noexcept
{
const ScopedLockType lock(getLock());
values.swap(index1, index2);
}
/** Moves one of the objects to a different position.
This will move the object to a specified index, shuffling along
any intervening elements as required.
So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling
move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }.
@param currentIndex the index of the object to be moved. If this isn't a
valid index, then nothing will be done
@param newIndex the index at which you'd like this object to end up. If this
is less than zero, it will be moved to the end of the array
*/
void move(int currentIndex, int newIndex) noexcept
{
if (currentIndex != newIndex)
{
const ScopedLockType lock(getLock());
values.move(currentIndex, newIndex);
}
}
/** This swaps the contents of this array with those of another array.
If you need to exchange two arrays, this is vastly quicker than using copy-by-value
because it just swaps their internal pointers.
*/
template <class OtherArrayType>
void swapWith(OtherArrayType& otherArray) noexcept
{
const ScopedLockType lock1(getLock());
const typename OtherArrayType::ScopedLockType lock2(otherArray.getLock());
values.swapWith(otherArray.values);
}
/** Reduces the amount of storage being used by the array.
Arrays typically allocate slightly more storage than they need, and after
removing elements, they may have quite a lot of unused space allocated.
This method will reduce the amount of allocated storage to a minimum.
*/
void minimiseStorageOverheads() noexcept
{
const ScopedLockType lock(getLock());
values.shrinkToNoMoreThan(values.size());
}
/** Increases the array's internal storage to hold a minimum number of elements.
Calling this before adding a large known number of elements means that
the array won't have to keep dynamically resizing itself as the elements
are added, and it'll therefore be more efficient.
*/
void ensureStorageAllocated(int minNumElements) noexcept
{
const ScopedLockType lock(getLock());
values.ensureAllocatedSize(minNumElements);
}
/** Sorts the elements in the array.
This will use a comparator object to sort the elements into order. The object
passed must have a method of the form:
@code
int compareElements (ElementType* first, ElementType* second);
@endcode
..and this method must return:
- a value of < 0 if the first comes before the second
- a value of 0 if the two objects are equivalent
- a value of > 0 if the second comes before the first
To improve performance, the compareElements() method can be declared as static or const.
@param comparator the comparator to use for comparing elements.
@param retainOrderOfEquivalentItems if this is true, then items
which the comparator says are equivalent will be
kept in the order in which they currently appear
in the array. This is slower to perform, but may
be important in some cases. If it's false, a faster
algorithm is used, but equivalent elements may be
rearranged.
@see sortArray, indexOfSorted
*/
template <class ElementComparator>
void sort(ElementComparator& comparator,
bool retainOrderOfEquivalentItems = false) noexcept
{
// If you pass in an object with a static compareElements() method, this
// avoids getting warning messages about the parameter being unused
ignoreUnused(comparator);
const ScopedLockType lock(getLock());
if (size() > 1)
sortArray(comparator, values.begin(), 0, size() - 1, retainOrderOfEquivalentItems);
}
/** Returns the CriticalSection that locks this array.
To lock, you can call getLock().enter() and getLock().exit(), or preferably use
an object of ScopedLockType as an RAII lock for it.
*/
inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return values; }
/** Returns the type of scoped lock to use for locking this array */
using ScopedLockType = typename TypeOfCriticalSectionToUse::ScopedLockType;
#ifndef DOXYGEN
// Note that the swapWithArray method has been replaced by a more flexible templated version,
// and renamed "swapWith" to be more consistent with the names used in other classes.
JUCE_DEPRECATED_WITH_BODY(void swapWithArray(OwnedArray& other) noexcept, { swapWith(other); })
#endif
private:
ArrayBase <ObjectClass*, TypeOfCriticalSectionToUse> values;
void deleteAllObjects()
{
auto i = values.size();
while (--i >= 0)
{
auto* e = values[i];
values.removeElements(i, 1);
ContainerDeletePolicy<ObjectClass>::destroy(e);
}
}
template <class OtherObjectClass, class OtherCriticalSection>
friend class OwnedArray;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(OwnedArray)
};
} // namespace juce
/*** End of inlined file: juce_OwnedArray.h ***/
/*** Start of inlined file: juce_ReferenceCountedArray.h ***/
namespace juce
{
/**
Holds a list of objects derived from ReferenceCountedObject, or which implement basic
reference-count handling methods.
The template parameter specifies the class of the object you want to point to - the easiest
way to make a class reference-countable is to simply make it inherit from ReferenceCountedObject
or SingleThreadedReferenceCountedObject, but if you need to, you can roll your own reference-countable
class by implementing a set of methods called incReferenceCount(), decReferenceCount(), and
decReferenceCountWithoutDeleting(). See ReferenceCountedObject for examples of how these methods
should behave.
A ReferenceCountedArray holds objects derived from ReferenceCountedObject,
and takes care of incrementing and decrementing their ref counts when they
are added and removed from the array.
To make all the array's methods thread-safe, pass in "CriticalSection" as the templated
TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection.
@see Array, OwnedArray, StringArray
@tags{Core}
*/
template <class ObjectClass, class TypeOfCriticalSectionToUse = DummyCriticalSection>
class ReferenceCountedArray
{
public:
using ObjectClassPtr = ReferenceCountedObjectPtr<ObjectClass>;
/** Creates an empty array.
@see ReferenceCountedObject, Array, OwnedArray
*/
ReferenceCountedArray() = default;
/** Creates a copy of another array */
ReferenceCountedArray(const ReferenceCountedArray& other) noexcept
{
const ScopedLockType lock(other.getLock());
values.addArray(other.begin(), other.size());
for (auto* o : *this)
if (o != nullptr)
o->incReferenceCount();
}
/** Moves from another array */
ReferenceCountedArray(ReferenceCountedArray&& other) noexcept
: values(std::move(other.values))
{
}
/** Creates a copy of another array */
template <class OtherObjectClass, class OtherCriticalSection>
ReferenceCountedArray(const ReferenceCountedArray<OtherObjectClass, OtherCriticalSection>& other) noexcept
{
const typename ReferenceCountedArray<OtherObjectClass, OtherCriticalSection>::ScopedLockType lock(other.getLock());
values.addArray(other.begin(), other.size());
for (auto* o : *this)
if (o != nullptr)
o->incReferenceCount();
}
/** Copies another array into this one.
Any existing objects in this array will first be released.
*/
ReferenceCountedArray& operator= (const ReferenceCountedArray& other) noexcept
{
releaseAllObjects();
auto otherCopy = other;
swapWith(otherCopy);
return *this;
}
/** Copies another array into this one.
Any existing objects in this array will first be released.
*/
template <class OtherObjectClass>
ReferenceCountedArray& operator= (const ReferenceCountedArray<OtherObjectClass, TypeOfCriticalSectionToUse>& other) noexcept
{
auto otherCopy = other;
swapWith(otherCopy);
return *this;
}
/** Moves from another array */
ReferenceCountedArray& operator= (ReferenceCountedArray&& other) noexcept
{
releaseAllObjects();
values = std::move(other.values);
return *this;
}
/** Destructor.
Any objects in the array will be released, and may be deleted if not referenced from elsewhere.
*/
~ReferenceCountedArray()
{
releaseAllObjects();
}
/** Removes all objects from the array.
Any objects in the array whose reference counts drop to zero will be deleted.
*/
void clear()
{
const ScopedLockType lock(getLock());
clearQuick();
values.setAllocatedSize(0);
}
/** Removes all objects from the array without freeing the array's allocated storage.
Any objects in the array that whose reference counts drop to zero will be deleted.
@see clear
*/
void clearQuick()
{
const ScopedLockType lock(getLock());
releaseAllObjects();
}
/** Returns the current number of objects in the array. */
inline int size() const noexcept
{
return values.size();
}
/** Returns true if the array is empty, false otherwise. */
inline bool isEmpty() const noexcept
{
return size() == 0;
}
/** Returns a pointer to the object at this index in the array.
If the index is out-of-range, this will return a null pointer, (and
it could be null anyway, because it's ok for the array to hold null
pointers as well as objects).
@see getUnchecked
*/
inline ObjectClassPtr operator[] (int index) const noexcept
{
return ObjectClassPtr(getObjectPointer(index));
}
/** Returns a pointer to the object at this index in the array, without checking
whether the index is in-range.
This is a faster and less safe version of operator[] which doesn't check the index passed in, so
it can be used when you're sure the index is always going to be legal.
*/
inline ObjectClassPtr getUnchecked(int index) const noexcept
{
return ObjectClassPtr(getObjectPointerUnchecked(index));
}
/** Returns a raw pointer to the object at this index in the array.
If the index is out-of-range, this will return a null pointer, (and
it could be null anyway, because it's ok for the array to hold null
pointers as well as objects).
@see getUnchecked
*/
inline ObjectClass* getObjectPointer(int index) const noexcept
{
const ScopedLockType lock(getLock());
return values.getValueWithDefault(index);
}
/** Returns a raw pointer to the object at this index in the array, without checking
whether the index is in-range.
*/
inline ObjectClass* getObjectPointerUnchecked(int index) const noexcept
{
const ScopedLockType lock(getLock());
return values[index];
}
/** Returns a pointer to the first object in the array.
This will return a null pointer if the array's empty.
@see getLast
*/
inline ObjectClassPtr getFirst() const noexcept
{
const ScopedLockType lock(getLock());
return values.getFirst();
}
/** Returns a pointer to the last object in the array.
This will return a null pointer if the array's empty.
@see getFirst
*/
inline ObjectClassPtr getLast() const noexcept
{
const ScopedLockType lock(getLock());
return values.getLast();
}
/** Returns a pointer to the actual array data.
This pointer will only be valid until the next time a non-const method
is called on the array.
*/
inline ObjectClass** getRawDataPointer() const noexcept
{
return values.begin();
}
/** Returns a pointer to the first element in the array.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline ObjectClass** begin() noexcept
{
return values.begin();
}
/** Returns a pointer to the first element in the array.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline ObjectClass* const* begin() const noexcept
{
return values.begin();
}
/** Returns a pointer to the element which follows the last element in the array.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline ObjectClass** end() noexcept
{
return values.end();
}
/** Returns a pointer to the element which follows the last element in the array.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline ObjectClass* const* end() const noexcept
{
return values.end();
}
/** Returns a pointer to the first element in the array.
This method is provided for compatibility with the standard C++ containers.
*/
inline ObjectClass** data() noexcept
{
return begin();
}
/** Returns a pointer to the first element in the array.
This method is provided for compatibility with the standard C++ containers.
*/
inline ObjectClass* const* data() const noexcept
{
return begin();
}
/** Finds the index of the first occurrence of an object in the array.
@param objectToLookFor the object to look for
@returns the index at which the object was found, or -1 if it's not found
*/
int indexOf(const ObjectClass* objectToLookFor) const noexcept
{
const ScopedLockType lock(getLock());
auto* e = values.begin();
auto* endPointer = values.end();
while (e != endPointer)
{
if (objectToLookFor == *e)
return static_cast<int> (e - values.begin());
++e;
}
return -1;
}
/** Finds the index of the first occurrence of an object in the array.
@param objectToLookFor the object to look for
@returns the index at which the object was found, or -1 if it's not found
*/
int indexOf(const ObjectClassPtr& objectToLookFor) const noexcept { return indexOf(objectToLookFor.get()); }
/** Returns true if the array contains a specified object.
@param objectToLookFor the object to look for
@returns true if the object is in the array
*/
bool contains(const ObjectClass* objectToLookFor) const noexcept
{
const ScopedLockType lock(getLock());
auto* e = values.begin();
auto* endPointer = values.end();
while (e != endPointer)
{
if (objectToLookFor == *e)
return true;
++e;
}
return false;
}
/** Returns true if the array contains a specified object.
@param objectToLookFor the object to look for
@returns true if the object is in the array
*/
bool contains(const ObjectClassPtr& objectToLookFor) const noexcept { return contains(objectToLookFor.get()); }
/** Appends a new object to the end of the array.
This will increase the new object's reference count.
@param newObject the new object to add to the array
@see set, insert, addIfNotAlreadyThere, addSorted, addArray
*/
ObjectClass* add(ObjectClass* newObject)
{
const ScopedLockType lock(getLock());
values.add(newObject);
if (newObject != nullptr)
newObject->incReferenceCount();
return newObject;
}
/** Appends a new object to the end of the array.
This will increase the new object's reference count.
@param newObject the new object to add to the array
@see set, insert, addIfNotAlreadyThere, addSorted, addArray
*/
ObjectClass* add(const ObjectClassPtr& newObject) { return add(newObject.get()); }
/** Inserts a new object into the array at the given index.
If the index is less than 0 or greater than the size of the array, the
element will be added to the end of the array.
Otherwise, it will be inserted into the array, moving all the later elements
along to make room.
This will increase the new object's reference count.
@param indexToInsertAt the index at which the new element should be inserted
@param newObject the new object to add to the array
@see add, addSorted, addIfNotAlreadyThere, set
*/
ObjectClass* insert(int indexToInsertAt, ObjectClass* newObject)
{
values.insert(indexToInsertAt, newObject, 1);
if (newObject != nullptr)
newObject->incReferenceCount();
return newObject;
}
/** Inserts a new object into the array at the given index.
If the index is less than 0 or greater than the size of the array, the
element will be added to the end of the array.
Otherwise, it will be inserted into the array, moving all the later elements
along to make room.
This will increase the new object's reference count.
@param indexToInsertAt the index at which the new element should be inserted
@param newObject the new object to add to the array
@see add, addSorted, addIfNotAlreadyThere, set
*/
ObjectClass* insert(int indexToInsertAt, const ObjectClassPtr& newObject) { return insert(indexToInsertAt, newObject.get()); }
/** Appends a new object at the end of the array as long as the array doesn't
already contain it.
If the array already contains a matching object, nothing will be done.
@param newObject the new object to add to the array
@returns true if the object has been added, false otherwise
*/
bool addIfNotAlreadyThere(ObjectClass* newObject)
{
const ScopedLockType lock(getLock());
if (contains(newObject))
return false;
add(newObject);
return true;
}
/** Appends a new object at the end of the array as long as the array doesn't
already contain it.
If the array already contains a matching object, nothing will be done.
@param newObject the new object to add to the array
@returns true if the object has been added, false otherwise
*/
bool addIfNotAlreadyThere(const ObjectClassPtr& newObject) { return addIfNotAlreadyThere(newObject.get()); }
/** Replaces an object in the array with a different one.
If the index is less than zero, this method does nothing.
If the index is beyond the end of the array, the new object is added to the end of the array.
The object being added has its reference count increased, and if it's replacing
another object, then that one has its reference count decreased, and may be deleted.
@param indexToChange the index whose value you want to change
@param newObject the new value to set for this index.
@see add, insert, remove
*/
void set(int indexToChange, ObjectClass* newObject)
{
if (indexToChange >= 0)
{
const ScopedLockType lock(getLock());
if (newObject != nullptr)
newObject->incReferenceCount();
if (indexToChange < values.size())
{
auto* e = values[indexToChange];
values[indexToChange] = newObject;
releaseObject(e);
}
else
{
values.add(newObject);
}
}
}
/** Replaces an object in the array with a different one.
If the index is less than zero, this method does nothing.
If the index is beyond the end of the array, the new object is added to the end of the array.
The object being added has its reference count increased, and if it's replacing
another object, then that one has its reference count decreased, and may be deleted.
@param indexToChange the index whose value you want to change
@param newObject the new value to set for this index.
@see add, insert, remove
*/
void set(int indexToChange, const ObjectClassPtr& newObject) { set(indexToChange, newObject.get()); }
/** Adds elements from another array to the end of this array.
@param arrayToAddFrom the array from which to copy the elements
@param startIndex the first element of the other array to start copying from
@param numElementsToAdd how many elements to add from the other array. If this
value is negative or greater than the number of available elements,
all available elements will be copied.
@see add
*/
void addArray(const ReferenceCountedArray& arrayToAddFrom,
int startIndex = 0,
int numElementsToAdd = -1) noexcept
{
const ScopedLockType lock1(arrayToAddFrom.getLock());
{
const ScopedLockType lock2(getLock());
auto numElementsAdded = values.addArray(arrayToAddFrom.values, startIndex, numElementsToAdd);
auto** e = values.end();
for (int i = 0; i < numElementsAdded; ++i)
(*(--e))->incReferenceCount();
}
}
/** Inserts a new object into the array assuming that the array is sorted.
This will use a comparator to find the position at which the new object
should go. If the array isn't sorted, the behaviour of this
method will be unpredictable.
@param comparator the comparator object to use to compare the elements - see the
sort() method for details about this object's form
@param newObject the new object to insert to the array
@returns the index at which the new object was added
@see add, sort
*/
template <class ElementComparator>
int addSorted(ElementComparator& comparator, ObjectClass* newObject) noexcept
{
const ScopedLockType lock(getLock());
auto index = findInsertIndexInSortedArray(comparator, values.begin(), newObject, 0, values.size());
insert(index, newObject);
return index;
}
/** Inserts or replaces an object in the array, assuming it is sorted.
This is similar to addSorted, but if a matching element already exists, then it will be
replaced by the new one, rather than the new one being added as well.
*/
template <class ElementComparator>
void addOrReplaceSorted(ElementComparator& comparator, ObjectClass* newObject) noexcept
{
const ScopedLockType lock(getLock());
auto index = findInsertIndexInSortedArray(comparator, values.begin(), newObject, 0, values.size());
if (index > 0 && comparator.compareElements(newObject, values[index - 1]) == 0)
set(index - 1, newObject); // replace an existing object that matches
else
insert(index, newObject); // no match, so insert the new one
}
/** Finds the index of an object in the array, assuming that the array is sorted.
This will use a comparator to do a binary-chop to find the index of the given
element, if it exists. If the array isn't sorted, the behaviour of this
method will be unpredictable.
@param comparator the comparator to use to compare the elements - see the sort()
method for details about the form this object should take
@param objectToLookFor the object to search for
@returns the index of the element, or -1 if it's not found
@see addSorted, sort
*/
template <class ElementComparator>
int indexOfSorted(ElementComparator& comparator,
const ObjectClass* objectToLookFor) const noexcept
{
ignoreUnused(comparator);
const ScopedLockType lock(getLock());
int s = 0, e = values.size();
while (s < e)
{
if (comparator.compareElements(objectToLookFor, values[s]) == 0)
return s;
auto halfway = (s + e) / 2;
if (halfway == s)
break;
if (comparator.compareElements(objectToLookFor, values[halfway]) >= 0)
s = halfway;
else
e = halfway;
}
return -1;
}
/** Removes an object from the array.
This will remove the object at a given index and move back all the
subsequent objects to close the gap.
If the index passed in is out-of-range, nothing will happen.
The object that is removed will have its reference count decreased,
and may be deleted if not referenced from elsewhere.
@param indexToRemove the index of the element to remove
@see removeObject, removeRange
*/
void remove(int indexToRemove)
{
const ScopedLockType lock(getLock());
if (isPositiveAndBelow(indexToRemove, values.size()))
{
auto* e = *(values.begin() + indexToRemove);
values.removeElements(indexToRemove, 1);
releaseObject(e);
if ((values.size() << 1) < values.capacity())
minimiseStorageOverheads();
}
}
/** Removes and returns an object from the array.
This will remove the object at a given index and return it, moving back all
the subsequent objects to close the gap. If the index passed in is out-of-range,
nothing will happen and a null pointer will be returned.
@param indexToRemove the index of the element to remove
@see remove, removeObject, removeRange
*/
ObjectClassPtr removeAndReturn(int indexToRemove)
{
ObjectClassPtr removedItem;
const ScopedLockType lock(getLock());
if (isPositiveAndBelow(indexToRemove, values.size()))
{
auto* e = *(values.begin() + indexToRemove);
removedItem = e;
values.removeElements(indexToRemove, 1);
releaseObject(e);
if ((values.size() << 1) < values.capacity())
minimiseStorageOverheads();
}
return removedItem;
}
/** Removes the first occurrence of a specified object from the array.
If the item isn't found, no action is taken. If it is found, it is
removed and has its reference count decreased.
@param objectToRemove the object to try to remove
@see remove, removeRange
*/
void removeObject(ObjectClass* objectToRemove)
{
const ScopedLockType lock(getLock());
remove(indexOf(objectToRemove));
}
/** Removes the first occurrence of a specified object from the array.
If the item isn't found, no action is taken. If it is found, it is
removed and has its reference count decreased.
@param objectToRemove the object to try to remove
@see remove, removeRange
*/
void removeObject(const ObjectClassPtr& objectToRemove) { removeObject(objectToRemove.get()); }
/** Removes a range of objects from the array.
This will remove a set of objects, starting from the given index,
and move any subsequent elements down to close the gap.
If the range extends beyond the bounds of the array, it will
be safely clipped to the size of the array.
The objects that are removed will have their reference counts decreased,
and may be deleted if not referenced from elsewhere.
@param startIndex the index of the first object to remove
@param numberToRemove how many objects should be removed
@see remove, removeObject
*/
void removeRange(int startIndex,
int numberToRemove)
{
const ScopedLockType lock(getLock());
startIndex = jlimit(0, values.size(), startIndex);
auto endIndex = jlimit(0, values.size(), startIndex + numberToRemove);
numberToRemove = endIndex - startIndex;
if (numberToRemove > 0)
{
Array<ObjectClass*> objectsToRemove;
objectsToRemove.addArray(values.begin() + startIndex, numberToRemove);
values.removeElements(startIndex, numberToRemove);
for (auto& o : objectsToRemove)
releaseObject(o);
if ((values.size() << 1) < values.capacity())
minimiseStorageOverheads();
}
}
/** Removes the last n objects from the array.
The objects that are removed will have their reference counts decreased,
and may be deleted if not referenced from elsewhere.
@param howManyToRemove how many objects to remove from the end of the array
@see remove, removeObject, removeRange
*/
void removeLast(int howManyToRemove = 1)
{
const ScopedLockType lock(getLock());
if (howManyToRemove > values.size())
howManyToRemove = values.size();
while (--howManyToRemove >= 0)
remove(values.size() - 1);
}
/** Swaps a pair of objects in the array.
If either of the indexes passed in is out-of-range, nothing will happen,
otherwise the two objects at these positions will be exchanged.
*/
void swap(int index1, int index2) noexcept
{
const ScopedLockType lock(getLock());
if (isPositiveAndBelow(index1, values.size())
&& isPositiveAndBelow(index2, values.size()))
{
std::swap(values[index1], values[index2]);
}
}
/** Moves one of the objects to a different position.
This will move the object to a specified index, shuffling along
any intervening elements as required.
So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling
move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }.
@param currentIndex the index of the object to be moved. If this isn't a
valid index, then nothing will be done
@param newIndex the index at which you'd like this object to end up. If this
is less than zero, it will be moved to the end of the array
*/
void move(int currentIndex, int newIndex) noexcept
{
if (currentIndex != newIndex)
{
const ScopedLockType lock(getLock());
values.move(currentIndex, newIndex);
}
}
/** This swaps the contents of this array with those of another array.
If you need to exchange two arrays, this is vastly quicker than using copy-by-value
because it just swaps their internal pointers.
*/
template <class OtherArrayType>
void swapWith(OtherArrayType& otherArray) noexcept
{
const ScopedLockType lock1(getLock());
const typename OtherArrayType::ScopedLockType lock2(otherArray.getLock());
values.swapWith(otherArray.values);
}
/** Compares this array to another one.
@returns true only if the other array contains the same objects in the same order
*/
bool operator== (const ReferenceCountedArray& other) const noexcept
{
const ScopedLockType lock2(other.getLock());
const ScopedLockType lock1(getLock());
return values == other.values;
}
/** Compares this array to another one.
@see operator==
*/
bool operator!= (const ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& other) const noexcept
{
return !operator== (other);
}
/** Sorts the elements in the array.
This will use a comparator object to sort the elements into order. The object
passed must have a method of the form:
@code
int compareElements (ElementType first, ElementType second);
@endcode
..and this method must return:
- a value of < 0 if the first comes before the second
- a value of 0 if the two objects are equivalent
- a value of > 0 if the second comes before the first
To improve performance, the compareElements() method can be declared as static or const.
@param comparator the comparator to use for comparing elements.
@param retainOrderOfEquivalentItems if this is true, then items
which the comparator says are equivalent will be
kept in the order in which they currently appear
in the array. This is slower to perform, but may
be important in some cases. If it's false, a faster
algorithm is used, but equivalent elements may be
rearranged.
@see sortArray
*/
template <class ElementComparator>
void sort(ElementComparator& comparator,
bool retainOrderOfEquivalentItems = false) noexcept
{
// If you pass in an object with a static compareElements() method, this
// avoids getting warning messages about the parameter being unused
ignoreUnused(comparator);
const ScopedLockType lock(getLock());
sortArray(comparator, values.begin(), 0, values.size() - 1, retainOrderOfEquivalentItems);
}
/** Reduces the amount of storage being used by the array.
Arrays typically allocate slightly more storage than they need, and after
removing elements, they may have quite a lot of unused space allocated.
This method will reduce the amount of allocated storage to a minimum.
*/
void minimiseStorageOverheads() noexcept
{
const ScopedLockType lock(getLock());
values.shrinkToNoMoreThan(values.size());
}
/** Increases the array's internal storage to hold a minimum number of elements.
Calling this before adding a large known number of elements means that
the array won't have to keep dynamically resizing itself as the elements
are added, and it'll therefore be more efficient.
*/
void ensureStorageAllocated(const int minNumElements)
{
const ScopedLockType lock(getLock());
values.ensureAllocatedSize(minNumElements);
}
/** Returns the CriticalSection that locks this array.
To lock, you can call getLock().enter() and getLock().exit(), or preferably use
an object of ScopedLockType as an RAII lock for it.
*/
inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return values; }
/** Returns the type of scoped lock to use for locking this array */
using ScopedLockType = typename TypeOfCriticalSectionToUse::ScopedLockType;
#ifndef DOXYGEN
// Note that the swapWithArray method has been replaced by a more flexible templated version,
// and renamed "swapWith" to be more consistent with the names used in other classes.
JUCE_DEPRECATED_WITH_BODY(void swapWithArray(ReferenceCountedArray& other) noexcept, { swapWith(other); })
#endif
private:
ArrayBase<ObjectClass*, TypeOfCriticalSectionToUse> values;
void releaseAllObjects()
{
auto i = values.size();
while (--i >= 0)
{
auto* e = values[i];
values.removeElements(i, 1);
releaseObject(e);
}
}
static void releaseObject(ObjectClass* o)
{
if (o != nullptr && o->decReferenceCountWithoutDeleting())
ContainerDeletePolicy<ObjectClass>::destroy(o);
}
};
} // namespace juce
/*** End of inlined file: juce_ReferenceCountedArray.h ***/
/*** Start of inlined file: juce_ScopedValueSetter.h ***/
namespace juce
{
/**
Helper class providing an RAII-based mechanism for temporarily setting and
then re-setting a value.
E.g. @code
int x = 1;
{
ScopedValueSetter setter (x, 2);
// x is now 2
}
// x is now 1 again
{
ScopedValueSetter setter (x, 3, 4);
// x is now 3
}
// x is now 4
@endcode
@tags{Core}
*/
template <typename ValueType>
class ScopedValueSetter
{
public:
/** Creates a ScopedValueSetter that will immediately change the specified value to the
given new value, and will then reset it to its original value when this object is deleted.
*/
ScopedValueSetter(ValueType& valueToSet,
ValueType newValue)
: value(valueToSet),
originalValue(valueToSet)
{
valueToSet = newValue;
}
/** Creates a ScopedValueSetter that will immediately change the specified value to the
given new value, and will then reset it to be valueWhenDeleted when this object is deleted.
*/
ScopedValueSetter(ValueType& valueToSet,
ValueType newValue,
ValueType valueWhenDeleted)
: value(valueToSet),
originalValue(valueWhenDeleted)
{
valueToSet = newValue;
}
~ScopedValueSetter()
{
value = originalValue;
}
private:
ValueType& value;
const ValueType originalValue;
JUCE_DECLARE_NON_COPYABLE(ScopedValueSetter)
};
} // namespace juce
/*** End of inlined file: juce_ScopedValueSetter.h ***/
/*** Start of inlined file: juce_SortedSet.h ***/
namespace juce
{
JUCE_BEGIN_IGNORE_WARNINGS_MSVC(4512)
/**
Holds a set of unique primitive objects, such as ints or doubles.
A set can only hold one item with a given value, so if for example it's a
set of integers, attempting to add the same integer twice will do nothing
the second time.
Internally, the list of items is kept sorted (which means that whatever
kind of primitive type is used must support the ==, <, >, <= and >= operators
to determine the order), and searching the set for known values is very fast
because it uses a binary-chop method.
Note that if you're using a class or struct as the element type, it must be
capable of being copied or moved with a straightforward memcpy, rather than
needing construction and destruction code.
To make all the set's methods thread-safe, pass in "CriticalSection" as the templated
TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection.
@see Array, OwnedArray, ReferenceCountedArray, StringArray, CriticalSection
@tags{Core}
*/
template <class ElementType, class TypeOfCriticalSectionToUse = DummyCriticalSection>
class SortedSet
{
public:
/** Creates an empty set. */
SortedSet() = default;
/** Creates a copy of another set. */
SortedSet(const SortedSet&) = default;
/** Creates a copy of another set. */
SortedSet(SortedSet&&) noexcept = default;
/** Makes a copy of another set. */
SortedSet& operator= (const SortedSet&) = default;
/** Makes a copy of another set. */
SortedSet& operator= (SortedSet&&) noexcept = default;
/** Destructor. */
~SortedSet() = default;
/** Compares this set to another one.
Two sets are considered equal if they both contain the same set of elements.
@param other the other set to compare with
*/
bool operator== (const SortedSet<ElementType>& other) const noexcept
{
return data == other.data;
}
/** Compares this set to another one.
Two sets are considered equal if they both contain the same set of elements.
@param other the other set to compare with
*/
bool operator!= (const SortedSet<ElementType>& other) const noexcept
{
return !operator== (other);
}
/** Removes all elements from the set.
This will remove all the elements, and free any storage that the set is
using. To clear it without freeing the storage, use the clearQuick()
method instead.
@see clearQuick
*/
void clear() noexcept
{
data.clear();
}
/** Removes all elements from the set without freeing the array's allocated storage.
@see clear
*/
void clearQuick() noexcept
{
data.clearQuick();
}
/** Returns the current number of elements in the set. */
inline int size() const noexcept
{
return data.size();
}
/** Returns true if the set is empty, false otherwise. */
inline bool isEmpty() const noexcept
{
return size() == 0;
}
/** Returns one of the elements in the set.
If the index passed in is beyond the range of valid elements, this
will return zero.
If you're certain that the index will always be a valid element, you
can call getUnchecked() instead, which is faster.
@param index the index of the element being requested (0 is the first element in the set)
@see getUnchecked, getFirst, getLast
*/
inline ElementType operator[] (const int index) const noexcept
{
return data[index];
}
/** Returns one of the elements in the set, without checking the index passed in.
Unlike the operator[] method, this will try to return an element without
checking that the index is within the bounds of the set, so should only
be used when you're confident that it will always be a valid index.
@param index the index of the element being requested (0 is the first element in the set)
@see operator[], getFirst, getLast
*/
inline ElementType getUnchecked(const int index) const noexcept
{
return data.getUnchecked(index);
}
/** Returns a direct reference to one of the elements in the set, without checking the index passed in.
This is like getUnchecked, but returns a direct reference to the element, so that
you can alter it directly. Obviously this can be dangerous, so only use it when
absolutely necessary.
@param index the index of the element being requested (0 is the first element in the array)
*/
inline ElementType& getReference(const int index) noexcept
{
return data.getReference(index);
}
/** Returns a direct reference to one of the elements in the set, without checking the index passed in.
@param index the index of the element being requested (0 is the first element in the array)
*/
inline const ElementType& getReference(const int index) const noexcept
{
return data.getReference(index);
}
/** Returns the first element in the set, or 0 if the set is empty.
@see operator[], getUnchecked, getLast
*/
inline ElementType getFirst() const noexcept
{
return data.getFirst();
}
/** Returns the last element in the set, or 0 if the set is empty.
@see operator[], getUnchecked, getFirst
*/
inline ElementType getLast() const noexcept
{
return data.getLast();
}
/** Returns a pointer to the first element in the set.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline const ElementType* begin() const noexcept
{
return data.begin();
}
/** Returns a pointer to the element which follows the last element in the set.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline const ElementType* end() const noexcept
{
return data.end();
}
/** Finds the index of the first element which matches the value passed in.
This will search the set for the given object, and return the index
of its first occurrence. If the object isn't found, the method will return -1.
@param elementToLookFor the value or object to look for
@returns the index of the object, or -1 if it's not found
*/
int indexOf(const ElementType& elementToLookFor) const noexcept
{
const ScopedLockType lock(data.getLock());
int s = 0;
int e = data.size();
for (;;)
{
if (s >= e)
return -1;
if (elementToLookFor == data.getReference(s))
return s;
auto halfway = (s + e) / 2;
if (halfway == s)
return -1;
if (elementToLookFor < data.getReference(halfway))
e = halfway;
else
s = halfway;
}
}
/** Returns true if the set contains at least one occurrence of an object.
@param elementToLookFor the value or object to look for
@returns true if the item is found
*/
bool contains(const ElementType& elementToLookFor) const noexcept
{
return indexOf(elementToLookFor) >= 0;
}
/** Adds a new element to the set, (as long as it's not already in there).
Note that if a matching element already exists, the new value will be assigned
to the existing one using operator=, so that if there are any differences between
the objects which were not recognised by the object's operator==, then the
set will always contain a copy of the most recently added one.
@param newElement the new object to add to the set
@returns true if the value was added, or false if it already existed
@see set, insert, addIfNotAlreadyThere, addSorted, addSet, addArray
*/
bool add(const ElementType& newElement) noexcept
{
const ScopedLockType lock(getLock());
int s = 0;
int e = data.size();
while (s < e)
{
auto& elem = data.getReference(s);
if (newElement == elem)
{
elem = newElement; // force an update in case operator== permits differences.
return false;
}
auto halfway = (s + e) / 2;
bool isBeforeHalfway = (newElement < data.getReference(halfway));
if (halfway == s)
{
if (!isBeforeHalfway)
++s;
break;
}
if (isBeforeHalfway)
e = halfway;
else
s = halfway;
}
data.insert(s, newElement);
return true;
}
/** Adds elements from an array to this set.
@param elementsToAdd the array of elements to add
@param numElementsToAdd how many elements are in this other array
@see add
*/
void addArray(const ElementType* elementsToAdd,
int numElementsToAdd) noexcept
{
const ScopedLockType lock(getLock());
while (--numElementsToAdd >= 0)
add(*elementsToAdd++);
}
/** Adds elements from another set to this one.
@param setToAddFrom the set from which to copy the elements
@param startIndex the first element of the other set to start copying from
@param numElementsToAdd how many elements to add from the other set. If this
value is negative or greater than the number of available elements,
all available elements will be copied.
@see add
*/
template <class OtherSetType>
void addSet(const OtherSetType& setToAddFrom,
int startIndex = 0,
int numElementsToAdd = -1) noexcept
{
const typename OtherSetType::ScopedLockType lock1(setToAddFrom.getLock());
const ScopedLockType lock2(getLock());
jassert(this != &setToAddFrom);
if (this != &setToAddFrom)
{
if (startIndex < 0)
{
jassertfalse;
startIndex = 0;
}
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > setToAddFrom.size())
numElementsToAdd = setToAddFrom.size() - startIndex;
if (numElementsToAdd > 0)
addArray(&setToAddFrom.data.getReference(startIndex), numElementsToAdd);
}
}
/** Removes an element from the set.
This will remove the element at a given index.
If the index passed in is out-of-range, nothing will happen.
@param indexToRemove the index of the element to remove
@returns the element that has been removed
@see removeValue, removeRange
*/
ElementType remove(const int indexToRemove) noexcept
{
return data.removeAndReturn(indexToRemove);
}
/** Removes an item from the set.
This will remove the given element from the set, if it's there.
@param valueToRemove the object to try to remove
@see remove, removeRange
*/
void removeValue(const ElementType& valueToRemove) noexcept
{
const ScopedLockType lock(getLock());
data.remove(indexOf(valueToRemove));
}
/** Removes any elements which are also in another set.
@param otherSet the other set in which to look for elements to remove
@see removeValuesNotIn, remove, removeValue, removeRange
*/
template <class OtherSetType>
void removeValuesIn(const OtherSetType& otherSet) noexcept
{
const typename OtherSetType::ScopedLockType lock1(otherSet.getLock());
const ScopedLockType lock2(getLock());
if (this == &otherSet)
{
clear();
}
else if (!otherSet.isEmpty())
{
for (int i = data.size(); --i >= 0;)
if (otherSet.contains(data.getReference(i)))
remove(i);
}
}
/** Removes any elements which are not found in another set.
Only elements which occur in this other set will be retained.
@param otherSet the set in which to look for elements NOT to remove
@see removeValuesIn, remove, removeValue, removeRange
*/
template <class OtherSetType>
void removeValuesNotIn(const OtherSetType& otherSet) noexcept
{
const typename OtherSetType::ScopedLockType lock1(otherSet.getLock());
const ScopedLockType lock2(getLock());
if (this != &otherSet)
{
if (otherSet.isEmpty())
{
clear();
}
else
{
for (int i = data.size(); --i >= 0;)
if (!otherSet.contains(data.getReference(i)))
remove(i);
}
}
}
/** This swaps the contents of this array with those of another array.
If you need to exchange two arrays, this is vastly quicker than using copy-by-value
because it just swaps their internal pointers.
*/
template <class OtherSetType>
void swapWith(OtherSetType& otherSet) noexcept
{
data.swapWith(otherSet.data);
}
/** Reduces the amount of storage being used by the set.
Sets typically allocate slightly more storage than they need, and after
removing elements, they may have quite a lot of unused space allocated.
This method will reduce the amount of allocated storage to a minimum.
*/
void minimiseStorageOverheads() noexcept
{
data.minimiseStorageOverheads();
}
/** Increases the set's internal storage to hold a minimum number of elements.
Calling this before adding a large known number of elements means that
the set won't have to keep dynamically resizing itself as the elements
are added, and it'll therefore be more efficient.
*/
void ensureStorageAllocated(const int minNumElements)
{
data.ensureStorageAllocated(minNumElements);
}
/** Returns the CriticalSection that locks this array.
To lock, you can call getLock().enter() and getLock().exit(), or preferably use
an object of ScopedLockType as an RAII lock for it.
*/
inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return data.getLock(); }
/** Returns the type of scoped lock to use for locking this array */
using ScopedLockType = typename TypeOfCriticalSectionToUse::ScopedLockType;
private:
Array<ElementType, TypeOfCriticalSectionToUse> data;
};
JUCE_END_IGNORE_WARNINGS_MSVC
} // namespace juce
/*** End of inlined file: juce_SortedSet.h ***/
/*** Start of inlined file: juce_SparseSet.h ***/
namespace juce
{
/**
Holds a set of primitive values, storing them as a set of ranges.
This container acts like an array, but can efficiently hold large contiguous
ranges of values. It's quite a specialised class, mostly useful for things
like keeping the set of selected rows in a listbox.
The type used as a template parameter must be an integer type, such as int, short,
int64, etc.
@tags{Core}
*/
template <class Type>
class SparseSet
{
public:
SparseSet() = default;
SparseSet(const SparseSet&) = default;
SparseSet& operator= (const SparseSet&) = default;
SparseSet(SparseSet&& other) noexcept : ranges(std::move(other.ranges)) {}
SparseSet& operator= (SparseSet&& other) noexcept { ranges = std::move(other.ranges); return *this; }
/** Clears the set. */
void clear() { ranges.clear(); }
/** Checks whether the set is empty.
This is much quicker than using (size() == 0).
*/
bool isEmpty() const noexcept { return ranges.isEmpty(); }
/** Returns the number of values in the set.
Because of the way the data is stored, this method can take longer if there
are a lot of items in the set. Use isEmpty() for a quick test of whether there
are any items.
*/
Type size() const noexcept
{
Type total = {};
for (auto& r : ranges)
total += r.getLength();
return total;
}
/** Returns one of the values in the set.
@param index the index of the value to retrieve, in the range 0 to (size() - 1).
@returns the value at this index, or 0 if it's out-of-range
*/
Type operator[] (Type index) const noexcept
{
Type total = {};
for (auto& r : ranges)
{
auto end = total + r.getLength();
if (index < end)
return r.getStart() + (index - total);
total = end;
}
return {};
}
/** Checks whether a particular value is in the set. */
bool contains(Type valueToLookFor) const noexcept
{
for (auto& r : ranges)
{
if (r.getStart() > valueToLookFor)
break;
if (r.getEnd() > valueToLookFor)
return true;
}
return false;
}
/** Returns the number of contiguous blocks of values.
@see getRange
*/
int getNumRanges() const noexcept { return ranges.size(); }
/** Returns one of the contiguous ranges of values stored.
@param rangeIndex the index of the range to look up, between 0
and (getNumRanges() - 1)
@see getTotalRange
*/
Range<Type> getRange(int rangeIndex) const noexcept { return ranges[rangeIndex]; }
/** Returns the range between the lowest and highest values in the set.
@see getRange
*/
Range<Type> getTotalRange() const noexcept
{
if (ranges.isEmpty())
return {};
return { ranges.getFirst().getStart(),
ranges.getLast().getEnd() };
}
/** Adds a range of contiguous values to the set.
e.g. addRange (Range \<int\> (10, 14)) will add (10, 11, 12, 13) to the set.
*/
void addRange(Range<Type> range)
{
if (!range.isEmpty())
{
removeRange(range);
ranges.add(range);
std::sort(ranges.begin(), ranges.end(),
[](Range<Type> a, Range<Type> b) { return a.getStart() < b.getStart(); });
simplify();
}
}
/** Removes a range of values from the set.
e.g. removeRange (Range\<int\> (10, 14)) will remove (10, 11, 12, 13) from the set.
*/
void removeRange(Range<Type> rangeToRemove)
{
if (getTotalRange().intersects(rangeToRemove) && !rangeToRemove.isEmpty())
{
for (int i = ranges.size(); --i >= 0;)
{
auto& r = ranges.getReference(i);
if (r.getEnd() <= rangeToRemove.getStart())
break;
if (r.getStart() >= rangeToRemove.getEnd())
continue;
if (rangeToRemove.contains(r))
{
ranges.remove(i);
}
else if (r.contains(rangeToRemove))
{
auto r1 = r.withEnd(rangeToRemove.getStart());
auto r2 = r.withStart(rangeToRemove.getEnd());
// this should be covered in if (rangeToRemove.contains (r))
jassert(!r1.isEmpty() || !r2.isEmpty());
r = r1;
if (r.isEmpty())
r = r2;
if (!r1.isEmpty() && !r2.isEmpty())
ranges.insert(i + 1, r2);
}
else if (rangeToRemove.getEnd() > r.getEnd())
{
r.setEnd(rangeToRemove.getStart());
}
else
{
r.setStart(rangeToRemove.getEnd());
}
}
}
}
/** Does an XOR of the values in a given range. */
void invertRange(Range<Type> range)
{
SparseSet newItems;
newItems.addRange(range);
for (auto& r : ranges)
newItems.removeRange(r);
removeRange(range);
for (auto& r : newItems.ranges)
addRange(r);
}
/** Checks whether any part of a given range overlaps any part of this set. */
bool overlapsRange(Range<Type> range) const noexcept
{
if (!range.isEmpty())
for (auto& r : ranges)
if (r.intersects(range))
return true;
return false;
}
/** Checks whether the whole of a given range is contained within this one. */
bool containsRange(Range<Type> range) const noexcept
{
if (!range.isEmpty())
for (auto& r : ranges)
if (r.contains(range))
return true;
return false;
}
/** Returns the set as a list of ranges, which you may want to iterate over. */
const Array<Range<Type>>& getRanges() const noexcept { return ranges; }
bool operator== (const SparseSet& other) const noexcept { return ranges == other.ranges; }
bool operator!= (const SparseSet& other) const noexcept { return ranges != other.ranges; }
private:
Array<Range<Type>> ranges;
void simplify()
{
for (int i = ranges.size(); --i > 0;)
{
auto& r1 = ranges.getReference(i - 1);
auto& r2 = ranges.getReference(i);
if (r1.getEnd() == r2.getStart())
{
r1.setEnd(r2.getEnd());
ranges.remove(i);
}
}
}
};
} // namespace juce
/*** End of inlined file: juce_SparseSet.h ***/
/*** Start of inlined file: juce_AbstractFifo.h ***/
namespace juce
{
/**
Encapsulates the logic required to implement a lock-free FIFO.
This class handles the logic needed when building a single-reader, single-writer FIFO.
It doesn't actually hold any data itself, but your FIFO class can use one of these to manage
its position and status when reading or writing to it.
To use it, you can call prepareToWrite() to determine the position within your own buffer that
an incoming block of data should be stored, and prepareToRead() to find out when the next
outgoing block should be read from.
e.g.
@code
struct MyFifo
{
void addToFifo (const int* someData, int numItems)
{
int start1, size1, start2, size2;
abstractFifo.prepareToWrite (numItems, start1, size1, start2, size2);
if (size1 > 0)
copySomeData (myBuffer + start1, someData, size1);
if (size2 > 0)
copySomeData (myBuffer + start2, someData + size1, size2);
abstractFifo.finishedWrite (size1 + size2);
}
void readFromFifo (int* someData, int numItems)
{
int start1, size1, start2, size2;
abstractFifo.prepareToRead (numItems, start1, size1, start2, size2);
if (size1 > 0)
copySomeData (someData, myBuffer + start1, size1);
if (size2 > 0)
copySomeData (someData + size1, myBuffer + start2, size2);
abstractFifo.finishedRead (size1 + size2);
}
AbstractFifo abstractFifo { 1024 };
int myBuffer[1024];
};
@endcode
@tags{Core}
*/
class JUCE_API AbstractFifo
{
public:
/** Creates a FIFO to manage a buffer with the specified capacity. */
AbstractFifo(int capacity) noexcept;
/** Destructor */
~AbstractFifo();
/** Returns the total size of the buffer being managed. */
int getTotalSize() const noexcept;
/** Returns the number of items that can currently be added to the buffer without it overflowing. */
int getFreeSpace() const noexcept;
/** Returns the number of items that can currently be read from the buffer. */
int getNumReady() const noexcept;
/** Clears the buffer positions, so that it appears empty. */
void reset() noexcept;
/** Changes the buffer's total size.
Note that this isn't thread-safe, so don't call it if there's any danger that it
might overlap with a call to any other method in this class!
*/
void setTotalSize(int newSize) noexcept;
/** Returns the location within the buffer at which an incoming block of data should be written.
Because the section of data that you want to add to the buffer may overlap the end
and wrap around to the start, two blocks within your buffer are returned, and you
should copy your data into the first one, with any remaining data spilling over into
the second.
If the number of items you ask for is too large to fit within the buffer's free space, then
blockSize1 + blockSize2 may add up to a lower value than numToWrite. If this happens, you
may decide to keep waiting and re-trying the method until there's enough space available.
After calling this method, if you choose to write your data into the blocks returned, you
must call finishedWrite() to tell the FIFO how much data you actually added.
e.g.
@code
void addToFifo (const int* someData, int numItems)
{
int start1, size1, start2, size2;
prepareToWrite (numItems, start1, size1, start2, size2);
if (size1 > 0)
copySomeData (myBuffer + start1, someData, size1);
if (size2 > 0)
copySomeData (myBuffer + start2, someData + size1, size2);
finishedWrite (size1 + size2);
}
@endcode
@param numToWrite indicates how many items you'd like to add to the buffer
@param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written
@param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1
@param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into
the first block should be written
@param blockSize2 on exit, this indicates how many items can be written to the block starting at startIndex2
@see finishedWrite
*/
void prepareToWrite(int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept;
/** Called after writing from the FIFO, to indicate that this many items have been added.
@see prepareToWrite
*/
void finishedWrite(int numWritten) noexcept;
/** Returns the location within the buffer from which the next block of data should be read.
Because the section of data that you want to read from the buffer may overlap the end
and wrap around to the start, two blocks within your buffer are returned, and you
should read from both of them.
If the number of items you ask for is greater than the amount of data available, then
blockSize1 + blockSize2 may add up to a lower value than numWanted. If this happens, you
may decide to keep waiting and re-trying the method until there's enough data available.
After calling this method, if you choose to read the data, you must call finishedRead() to
tell the FIFO how much data you have consumed.
e.g.
@code
void readFromFifo (int* someData, int numItems)
{
int start1, size1, start2, size2;
prepareToRead (numSamples, start1, size1, start2, size2);
if (size1 > 0)
copySomeData (someData, myBuffer + start1, size1);
if (size2 > 0)
copySomeData (someData + size1, myBuffer + start2, size2);
finishedRead (size1 + size2);
}
@endcode
@param numWanted indicates how many items you'd like to add to the buffer
@param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written
@param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1
@param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into
the first block should be written
@param blockSize2 on exit, this indicates how many items can be written to the block starting at startIndex2
@see finishedRead
*/
void prepareToRead(int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept;
/** Called after reading from the FIFO, to indicate that this many items have now been consumed.
@see prepareToRead
*/
void finishedRead(int numRead) noexcept;
private:
enum class ReadOrWrite
{
read,
write
};
public:
/** Class for a scoped reader/writer */
template <ReadOrWrite mode>
class ScopedReadWrite final
{
public:
/** Construct an unassigned reader/writer. Doesn't do anything upon destruction. */
ScopedReadWrite() = default;
/** Construct a reader/writer and immediately call prepareRead/prepareWrite
on the abstractFifo which was passed in.
This object will hold a pointer back to the fifo, so make sure that
the fifo outlives this object.
*/
ScopedReadWrite(AbstractFifo& f, int num) noexcept : fifo(&f)
{
prepare(*fifo, num);
}
ScopedReadWrite(const ScopedReadWrite&) = delete;
ScopedReadWrite(ScopedReadWrite&&) noexcept;
ScopedReadWrite& operator= (const ScopedReadWrite&) = delete;
ScopedReadWrite& operator= (ScopedReadWrite&&) noexcept;
/** Calls finishedRead or finishedWrite if this is a non-null scoped
reader/writer.
*/
~ScopedReadWrite() noexcept
{
if (fifo != nullptr)
finish(*fifo, blockSize1 + blockSize2);
}
/** Calls the passed function with each index that was deemed valid
for the current read/write operation.
*/
template <typename FunctionToApply>
void forEach(FunctionToApply&& func) const
{
for (auto i = startIndex1, e = startIndex1 + blockSize1; i != e; ++i) func(i);
for (auto i = startIndex2, e = startIndex2 + blockSize2; i != e; ++i) func(i);
}
int startIndex1, blockSize1, startIndex2, blockSize2;
private:
void prepare(AbstractFifo&, int) noexcept;
static void finish(AbstractFifo&, int) noexcept;
void swap(ScopedReadWrite&) noexcept;
AbstractFifo* fifo = nullptr;
};
using ScopedRead = ScopedReadWrite<ReadOrWrite::read>;
using ScopedWrite = ScopedReadWrite<ReadOrWrite::write>;
/** Replaces prepareToRead/finishedRead with a single function.
This function returns an object which contains the start indices and
block sizes, and also automatically finishes the read operation when
it goes out of scope.
@code
{
auto readHandle = fifo.read (4);
for (auto i = 0; i != readHandle.blockSize1; ++i)
{
// read the item at index readHandle.startIndex1 + i
}
for (auto i = 0; i != readHandle.blockSize2; ++i)
{
// read the item at index readHandle.startIndex2 + i
}
} // readHandle goes out of scope here, finishing the read operation
@endcode
*/
ScopedRead read(int numToRead) noexcept;
/** Replaces prepareToWrite/finishedWrite with a single function.
This function returns an object which contains the start indices and
block sizes, and also automatically finishes the write operation when
it goes out of scope.
@code
{
auto writeHandle = fifo.write (5);
for (auto i = 0; i != writeHandle.blockSize1; ++i)
{
// write the item at index writeHandle.startIndex1 + i
}
for (auto i = 0; i != writeHandle.blockSize2; ++i)
{
// write the item at index writeHandle.startIndex2 + i
}
} // writeHandle goes out of scope here, finishing the write operation
@endcode
*/
ScopedWrite write(int numToWrite) noexcept;
private:
int bufferSize;
Atomic<int> validStart, validEnd;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(AbstractFifo)
};
template <>
inline void AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::read>::finish(AbstractFifo& f, int num) noexcept
{
f.finishedRead(num);
}
template <>
inline void AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::write>::finish(AbstractFifo& f, int num) noexcept
{
f.finishedWrite(num);
}
template <>
inline void AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::read>::prepare(AbstractFifo& f, int num) noexcept
{
f.prepareToRead(num, startIndex1, blockSize1, startIndex2, blockSize2);
}
template <>
inline void AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::write>::prepare(AbstractFifo& f, int num) noexcept
{
f.prepareToWrite(num, startIndex1, blockSize1, startIndex2, blockSize2);
}
} // namespace juce
/*** End of inlined file: juce_AbstractFifo.h ***/
/*** Start of inlined file: juce_NewLine.h ***/
namespace juce
{
/** This class is used for represent a new-line character sequence.
To write a new-line to a stream, you can use the predefined 'newLine' variable, e.g.
@code
myOutputStream << "Hello World" << newLine << newLine;
@endcode
The exact character sequence that will be used for the new-line can be set and
retrieved with OutputStream::setNewLineString() and OutputStream::getNewLineString().
@tags{Core}
*/
class JUCE_API NewLine
{
public:
/** Returns the default new-line sequence that the library uses.
@see OutputStream::setNewLineString()
*/
static const char* getDefault() noexcept { return "\r\n"; }
/** Returns the default new-line sequence that the library uses.
@see getDefault()
*/
operator String() const { return getDefault(); }
/** Returns the default new-line sequence that the library uses.
@see OutputStream::setNewLineString()
*/
operator StringRef() const noexcept { return getDefault(); }
};
/** A predefined object representing a new-line, which can be written to a string or stream.
To write a new-line to a stream, you can use the predefined 'newLine' variable like this:
@code
myOutputStream << "Hello World" << newLine << newLine;
@endcode
*/
extern NewLine newLine;
/** Writes a new-line sequence to a string.
You can use the predefined object 'newLine' to invoke this, e.g.
@code
myString << "Hello World" << newLine << newLine;
@endcode
*/
inline String& operator<< (String& string1, const NewLine&) { return string1 += NewLine::getDefault(); }
inline String& operator+= (String& s1, const NewLine&) { return s1 += NewLine::getDefault(); }
inline String operator+ (const NewLine&, const NewLine&) { return String(NewLine::getDefault()) + NewLine::getDefault(); }
inline String operator+ (String s1, const NewLine&) { return s1 += NewLine::getDefault(); }
inline String operator+ (const NewLine&, const char* s2) { return String(NewLine::getDefault()) + s2; }
} // namespace juce
/*** End of inlined file: juce_NewLine.h ***/
/*** Start of inlined file: juce_StringPool.h ***/
namespace juce
{
/**
A StringPool holds a set of shared strings, which reduces storage overheads and improves
comparison speed when dealing with many duplicate strings.
When you add a string to a pool using getPooledString, it'll return a character
array containing the same string. This array is owned by the pool, and the same array
is returned every time a matching string is asked for. This means that it's trivial to
compare two pooled strings for equality, as you can simply compare their pointers. It
also cuts down on storage if you're using many copies of the same string.
@tags{Core}
*/
class JUCE_API StringPool
{
public:
/** Creates an empty pool. */
StringPool() noexcept;
/** Destructor */
~StringPool();
/** Returns a pointer to a shared copy of the string that is passed in.
The pool will always return the same String object when asked for a string that matches it.
*/
String getPooledString(const String& original);
/** Returns a pointer to a copy of the string that is passed in.
The pool will always return the same String object when asked for a string that matches it.
*/
String getPooledString(const char* original);
/** Returns a pointer to a shared copy of the string that is passed in.
The pool will always return the same String object when asked for a string that matches it.
*/
String getPooledString(StringRef original);
/** Returns a pointer to a copy of the string that is passed in.
The pool will always return the same String object when asked for a string that matches it.
*/
String getPooledString(String::CharPointerType start, String::CharPointerType end);
/** Scans the pool, and removes any strings that are unreferenced.
You don't generally need to call this - it'll be called automatically when the pool grows
large enough to warrant it.
*/
void garbageCollect();
/** Returns a shared global pool which is used for things like Identifiers, XML parsing. */
static StringPool& getGlobalPool() noexcept;
private:
Array<String> strings;
CriticalSection lock;
uint32 lastGarbageCollectionTime;
void garbageCollectIfNeeded();
JUCE_DECLARE_NON_COPYABLE(StringPool)
};
} // namespace juce
/*** End of inlined file: juce_StringPool.h ***/
/*** Start of inlined file: juce_Identifier.h ***/
namespace juce
{
/**
Represents a string identifier, designed for accessing properties by name.
Comparing two Identifier objects is very fast (an O(1) operation), but creating
them can be slower than just using a String directly, so the optimal way to use them
is to keep some static Identifier objects for the things you use often.
@see NamedValueSet, ValueTree
@tags{Core}
*/
class JUCE_API Identifier final
{
public:
/** Creates a null identifier. */
Identifier() noexcept;
/** Creates an identifier with a specified name.
Because this name may need to be used in contexts such as script variables or XML
tags, it must only contain ascii letters and digits, or the underscore character.
*/
Identifier(const char* name);
/** Creates an identifier with a specified name.
Because this name may need to be used in contexts such as script variables or XML
tags, it must only contain ascii letters and digits, or the underscore character.
*/
Identifier(const String& name);
/** Creates an identifier with a specified name.
Because this name may need to be used in contexts such as script variables or XML
tags, it must only contain ascii letters and digits, or the underscore character.
*/
Identifier(String::CharPointerType nameStart, String::CharPointerType nameEnd);
/** Creates a copy of another identifier. */
Identifier(const Identifier& other) noexcept;
/** Creates a copy of another identifier. */
Identifier& operator= (const Identifier& other) noexcept;
/** Creates a copy of another identifier. */
Identifier(Identifier&& other) noexcept;
/** Creates a copy of another identifier. */
Identifier& operator= (Identifier&& other) noexcept;
/** Destructor */
~Identifier() noexcept;
/** Compares two identifiers. This is a very fast operation. */
inline bool operator== (const Identifier& other) const noexcept { return name.getCharPointer() == other.name.getCharPointer(); }
/** Compares two identifiers. This is a very fast operation. */
inline bool operator!= (const Identifier& other) const noexcept { return name.getCharPointer() != other.name.getCharPointer(); }
/** Compares the identifier with a string. */
inline bool operator== (StringRef other) const noexcept { return name == other; }
/** Compares the identifier with a string. */
inline bool operator!= (StringRef other) const noexcept { return name != other; }
/** Compares the identifier with a string. */
inline bool operator< (StringRef other) const noexcept { return name < other; }
/** Compares the identifier with a string. */
inline bool operator<= (StringRef other) const noexcept { return name <= other; }
/** Compares the identifier with a string. */
inline bool operator> (StringRef other) const noexcept { return name > other; }
/** Compares the identifier with a string. */
inline bool operator>= (StringRef other) const noexcept { return name >= other; }
/** Returns this identifier as a string. */
const String& toString() const noexcept { return name; }
/** Returns this identifier's raw string pointer. */
operator String::CharPointerType() const noexcept { return name.getCharPointer(); }
/** Returns this identifier's raw string pointer. */
String::CharPointerType getCharPointer() const noexcept { return name.getCharPointer(); }
/** Returns this identifier as a StringRef. */
operator StringRef() const noexcept { return name; }
/** Returns true if this Identifier is not null */
bool isValid() const noexcept { return name.isNotEmpty(); }
/** Returns true if this Identifier is null */
bool isNull() const noexcept { return name.isEmpty(); }
/** A null identifier. */
static Identifier null;
/** Checks a given string for characters that might not be valid in an Identifier.
Since Identifiers are used as a script variables and XML attributes, they should only contain
alphanumeric characters, underscores, or the '-' and ':' characters.
*/
static bool isValidIdentifier(const String& possibleIdentifier) noexcept;
private:
String name;
};
} // namespace juce
/*** End of inlined file: juce_Identifier.h ***/
/*** Start of inlined file: juce_StringArray.h ***/
namespace juce
{
/**
A special array for holding a list of strings.
@see String, StringPairArray
@tags{Core}
*/
class JUCE_API StringArray
{
public:
/** Creates an empty string array */
StringArray() noexcept;
/** Creates a copy of another string array */
StringArray(const StringArray&);
/** Move constructor */
StringArray(StringArray&&) noexcept;
/** Creates an array containing a single string. */
StringArray(const String& firstValue);
/** Creates an array containing a list of strings. */
template <typename... OtherElements>
StringArray(StringRef firstValue, OtherElements&&... otherValues)
: strings(firstValue, std::forward<OtherElements>(otherValues)...) {}
/** Creates an array containing a list of strings. */
StringArray(const std::initializer_list<const char*>& strings);
/** Creates a StringArray by moving from an Array<String> */
StringArray(Array<String>&&) noexcept;
/** Creates a StringArray from an array of objects which can be implicitly converted to Strings. */
template <typename Type>
StringArray(const Array<Type>& stringArray)
{
addArray(stringArray.begin(), stringArray.end());
}
/** Creates an array from a raw array of strings.
@param strings an array of strings to add
@param numberOfStrings how many items there are in the array
*/
StringArray(const String* strings, int numberOfStrings);
/** Creates a copy of an array of string literals.
@param strings an array of strings to add. Null pointers in the array will be
treated as empty strings
@param numberOfStrings how many items there are in the array
*/
StringArray(const char* const* strings, int numberOfStrings);
/** Creates a copy of a null-terminated array of string literals.
Each item from the array passed-in is added, until it encounters a null pointer,
at which point it stops.
*/
explicit StringArray(const char* const* strings);
/** Creates a copy of a null-terminated array of string literals.
Each item from the array passed-in is added, until it encounters a null pointer,
at which point it stops.
*/
explicit StringArray(const wchar_t* const* strings);
/** Creates a copy of an array of string literals.
@param strings an array of strings to add. Null pointers in the array will be
treated as empty strings
@param numberOfStrings how many items there are in the array
*/
StringArray(const wchar_t* const* strings, int numberOfStrings);
/** Destructor. */
~StringArray();
/** Copies the contents of another string array into this one */
StringArray& operator= (const StringArray&);
/** Move assignment operator */
StringArray& operator= (StringArray&&) noexcept;
/** Copies a StringArray from an array of objects which can be implicitly converted to Strings. */
template <typename Type>
StringArray& operator= (const Array<Type>& stringArray)
{
addArray(stringArray.begin(), stringArray.end());
return *this;
}
/** Swaps the contents of this and another StringArray. */
void swapWith(StringArray&) noexcept;
/** Compares two arrays.
Comparisons are case-sensitive.
@returns true only if the other array contains exactly the same strings in the same order
*/
bool operator== (const StringArray&) const noexcept;
/** Compares two arrays.
Comparisons are case-sensitive.
@returns false if the other array contains exactly the same strings in the same order
*/
bool operator!= (const StringArray&) const noexcept;
/** Returns the number of strings in the array */
inline int size() const noexcept { return strings.size(); }
/** Returns true if the array is empty, false otherwise. */
inline bool isEmpty() const noexcept { return size() == 0; }
/** Returns one of the strings from the array.
If the index is out-of-range, an empty string is returned.
Obviously the reference returned shouldn't be stored for later use, as the
string it refers to may disappear when the array changes.
*/
const String& operator[] (int index) const noexcept;
/** Returns a reference to one of the strings in the array.
This lets you modify a string in-place in the array, but you must be sure that
the index is in-range.
*/
String& getReference(int index) noexcept;
/** Returns a reference to one of the strings in the array.
This lets you modify a string in-place in the array, but you must be sure that
the index is in-range.
*/
const String& getReference(int index) const noexcept;
/** Returns a pointer to the first String in the array.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline String* begin() noexcept { return strings.begin(); }
/** Returns a pointer to the first String in the array.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline const String* begin() const noexcept { return strings.begin(); }
/** Returns a pointer to the String which follows the last element in the array.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline String* end() noexcept { return strings.end(); }
/** Returns a pointer to the String which follows the last element in the array.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline const String* end() const noexcept { return strings.end(); }
/** Searches for a string in the array.
The comparison will be case-insensitive if the ignoreCase parameter is true.
@returns true if the string is found inside the array
*/
bool contains(StringRef stringToLookFor,
bool ignoreCase = false) const;
/** Searches for a string in the array.
The comparison will be case-insensitive if the ignoreCase parameter is true.
@param stringToLookFor the string to try to find
@param ignoreCase whether the comparison should be case-insensitive
@param startIndex the first index to start searching from
@returns the index of the first occurrence of the string in this array,
or -1 if it isn't found.
*/
int indexOf(StringRef stringToLookFor,
bool ignoreCase = false,
int startIndex = 0) const;
/** Appends a string at the end of the array. */
void add(String stringToAdd);
/** Inserts a string into the array.
This will insert a string into the array at the given index, moving
up the other elements to make room for it.
If the index is less than zero or greater than the size of the array,
the new string will be added to the end of the array.
*/
void insert(int index, String stringToAdd);
/** Adds a string to the array as long as it's not already in there.
The search can optionally be case-insensitive.
@return true if the string has been added, false otherwise.
*/
bool addIfNotAlreadyThere(const String& stringToAdd, bool ignoreCase = false);
/** Replaces one of the strings in the array with another one.
If the index is higher than the array's size, the new string will be
added to the end of the array; if it's less than zero nothing happens.
*/
void set(int index, String newString);
/** Appends some strings from another array to the end of this one.
@param other the array to add
@param startIndex the first element of the other array to add
@param numElementsToAdd the maximum number of elements to add (if this is
less than zero, they are all added)
*/
void addArray(const StringArray& other,
int startIndex = 0,
int numElementsToAdd = -1);
/** Adds items from a range of start/end iterators of some kind of objects which
can be implicitly converted to Strings.
*/
template <typename Iterator>
void addArray(Iterator&& start, Iterator&& end)
{
ensureStorageAllocated(size() + (int) static_cast<size_t> (end - start));
while (start != end)
strings.add(*start++);
}
/** Merges the strings from another array into this one.
This will not add a string that already exists.
@param other the array to add
@param ignoreCase ignore case when merging
*/
void mergeArray(const StringArray& other,
bool ignoreCase = false);
/** Breaks up a string into tokens and adds them to this array.
This will tokenise the given string using whitespace characters as the
token delimiters, and will add these tokens to the end of the array.
@returns the number of tokens added
@see fromTokens
*/
int addTokens(StringRef stringToTokenise, bool preserveQuotedStrings);
/** Breaks up a string into tokens and adds them to this array.
This will tokenise the given string (using the string passed in to define the
token delimiters), and will add these tokens to the end of the array.
@param stringToTokenise the string to tokenise
@param breakCharacters a string of characters, any of which will be considered
to be a token delimiter.
@param quoteCharacters if this string isn't empty, it defines a set of characters
which are treated as quotes. Any text occurring
between quotes is not broken up into tokens.
@returns the number of tokens added
@see fromTokens
*/
int addTokens(StringRef stringToTokenise,
StringRef breakCharacters,
StringRef quoteCharacters);
/** Breaks up a string into lines and adds them to this array.
This breaks a string down into lines separated by \\n or \\r\\n, and adds each line
to the array. Line-break characters are omitted from the strings that are added to
the array.
*/
int addLines(StringRef stringToBreakUp);
/** Returns an array containing the tokens in a given string.
This will tokenise the given string using whitespace characters as the
token delimiters, and return the parsed tokens as an array.
@see addTokens
*/
static StringArray fromTokens(StringRef stringToTokenise,
bool preserveQuotedStrings);
/** Returns an array containing the tokens in a given string.
This will tokenise the given string using the breakCharacters string to define
the token delimiters, and will return the parsed tokens as an array.
@param stringToTokenise the string to tokenise
@param breakCharacters a string of characters, any of which will be considered
to be a token delimiter.
@param quoteCharacters if this string isn't empty, it defines a set of characters
which are treated as quotes. Any text occurring
between quotes is not broken up into tokens.
@see addTokens
*/
static StringArray fromTokens(StringRef stringToTokenise,
StringRef breakCharacters,
StringRef quoteCharacters);
/** Returns an array containing the lines in a given string.
This breaks a string down into lines separated by \\n or \\r\\n, and returns an
array containing these lines. Line-break characters are omitted from the strings that
are added to the array.
*/
static StringArray fromLines(StringRef stringToBreakUp);
/** Removes all elements from the array. */
void clear();
/** Removes all elements from the array without freeing the array's allocated storage.
@see clear
*/
void clearQuick();
/** Removes a string from the array.
If the index is out-of-range, no action will be taken.
*/
void remove(int index);
/** Finds a string in the array and removes it.
This will remove all occurrences of the given string from the array.
The comparison may be case-insensitive depending on the ignoreCase parameter.
*/
void removeString(StringRef stringToRemove,
bool ignoreCase = false);
/** Removes a range of elements from the array.
This will remove a set of elements, starting from the given index,
and move subsequent elements down to close the gap.
If the range extends beyond the bounds of the array, it will
be safely clipped to the size of the array.
@param startIndex the index of the first element to remove
@param numberToRemove how many elements should be removed
*/
void removeRange(int startIndex, int numberToRemove);
/** Removes any duplicated elements from the array.
If any string appears in the array more than once, only the first occurrence of
it will be retained.
@param ignoreCase whether to use a case-insensitive comparison
*/
void removeDuplicates(bool ignoreCase);
/** Removes empty strings from the array.
@param removeWhitespaceStrings if true, strings that only contain whitespace
characters will also be removed
*/
void removeEmptyStrings(bool removeWhitespaceStrings = true);
/** Moves one of the strings to a different position.
This will move the string to a specified index, shuffling along
any intervening elements as required.
So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling
move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }.
@param currentIndex the index of the value to be moved. If this isn't a
valid index, then nothing will be done
@param newIndex the index at which you'd like this value to end up. If this
is less than zero, the value will be moved to the end
of the array
*/
void move(int currentIndex, int newIndex) noexcept;
/** Deletes any whitespace characters from the starts and ends of all the strings. */
void trim();
/** Adds numbers to the strings in the array, to make each string unique.
This will add numbers to the ends of groups of similar strings.
e.g. if there are two "moose" strings, they will become "moose (1)" and "moose (2)"
@param ignoreCaseWhenComparing whether the comparison used is case-insensitive
@param appendNumberToFirstInstance whether the first of a group of similar strings
also has a number appended to it.
@param preNumberString when adding a number, this string is added before the number.
If you pass nullptr, a default string will be used, which adds
brackets around the number.
@param postNumberString this string is appended after any numbers that are added.
If you pass nullptr, a default string will be used, which adds
brackets around the number.
*/
void appendNumbersToDuplicates(bool ignoreCaseWhenComparing,
bool appendNumberToFirstInstance,
CharPointer_UTF8 preNumberString = CharPointer_UTF8(nullptr),
CharPointer_UTF8 postNumberString = CharPointer_UTF8(nullptr));
/** Joins the strings in the array together into one string.
This will join a range of elements from the array into a string, separating
them with a given string.
e.g. joinIntoString (",") will turn an array of "a" "b" and "c" into "a,b,c".
@param separatorString the string to insert between all the strings
@param startIndex the first element to join
@param numberOfElements how many elements to join together. If this is less
than zero, all available elements will be used.
*/
String joinIntoString(StringRef separatorString,
int startIndex = 0,
int numberOfElements = -1) const;
/** Sorts the array into alphabetical order.
@param ignoreCase if true, the comparisons used will not be case-sensitive.
*/
void sort(bool ignoreCase);
/** Sorts the array using extra language-aware rules to do a better job of comparing
words containing spaces and numbers.
@see String::compareNatural()
*/
void sortNatural();
/** Increases the array's internal storage to hold a minimum number of elements.
Calling this before adding a large known number of elements means that
the array won't have to keep dynamically resizing itself as the elements
are added, and it'll therefore be more efficient.
*/
void ensureStorageAllocated(int minNumElements);
/** Reduces the amount of storage being used by the array.
Arrays typically allocate slightly more storage than they need, and after
removing elements, they may have quite a lot of unused space allocated.
This method will reduce the amount of allocated storage to a minimum.
*/
void minimiseStorageOverheads();
/** This is the array holding the actual strings. This is public to allow direct access
to array methods that may not already be provided by the StringArray class.
*/
Array<String> strings;
private:
JUCE_LEAK_DETECTOR(StringArray)
};
} // namespace juce
/*** End of inlined file: juce_StringArray.h ***/
/*** Start of inlined file: juce_SystemStats.h ***/
namespace juce
{
/**
Contains methods for finding out about the current hardware and OS configuration.
@tags{Core}
*/
class JUCE_API SystemStats final
{
public:
/** Returns the current version of JUCE,
See also the JUCE_VERSION, JUCE_MAJOR_VERSION and JUCE_MINOR_VERSION macros.
*/
static String getJUCEVersion();
/** The set of possible results of the getOperatingSystemType() method. */
enum OperatingSystemType
{
UnknownOS = 0,
MacOSX = 0x0100, /**< To test whether any version of OSX is running,
you can use the expression ((getOperatingSystemType() & MacOSX) != 0). */
Windows = 0x0200, /**< To test whether any version of Windows is running,
you can use the expression ((getOperatingSystemType() & Windows) != 0). */
Linux = 0x0400,
Android = 0x0800,
iOS = 0x1000,
WASM = 0x2000,
MacOSX_10_7 = MacOSX | 7,
MacOSX_10_8 = MacOSX | 8,
MacOSX_10_9 = MacOSX | 9,
MacOSX_10_10 = MacOSX | 10,
MacOSX_10_11 = MacOSX | 11,
MacOSX_10_12 = MacOSX | 12,
MacOSX_10_13 = MacOSX | 13,
MacOSX_10_14 = MacOSX | 14,
MacOSX_10_15 = MacOSX | 15,
MacOS_11 = MacOSX | 16,
Win2000 = Windows | 1,
WinXP = Windows | 2,
WinVista = Windows | 3,
Windows7 = Windows | 4,
Windows8_0 = Windows | 5,
Windows8_1 = Windows | 6,
Windows10 = Windows | 7
};
/** Returns the type of operating system we're running on.
@returns one of the values from the OperatingSystemType enum.
@see getOperatingSystemName
*/
static OperatingSystemType getOperatingSystemType();
/** Returns the name of the type of operating system we're running on.
@returns a string describing the OS type.
@see getOperatingSystemType
*/
static String getOperatingSystemName();
/** Returns true if the OS is 64-bit, or false for a 32-bit OS. */
static bool isOperatingSystem64Bit();
/** Returns an environment variable.
If the named value isn't set, this will return the defaultValue string instead.
*/
static String getEnvironmentVariable(const String& name, const String& defaultValue);
/** Returns the current user's name, if available.
@see getFullUserName()
*/
static String getLogonName();
/** Returns the current user's full name, if available.
On some OSes, this may just return the same value as getLogonName().
@see getLogonName()
*/
static String getFullUserName();
/** Returns the host-name of the computer. */
static String getComputerName();
/** Returns the language of the user's locale.
The return value is a 2 or 3 letter language code (ISO 639-1 or ISO 639-2)
*/
static String getUserLanguage();
/** Returns the region of the user's locale.
The return value is a 2 letter country code (ISO 3166-1 alpha-2).
*/
static String getUserRegion();
/** Returns the user's display language.
The return value is a 2 or 3 letter language code (ISO 639-1 or ISO 639-2).
Note that depending on the OS and region, this may also be followed by a dash
and a sub-region code, e.g "en-GB"
*/
static String getDisplayLanguage();
/** This will attempt to return some kind of string describing the device.
If no description is available, it'll just return an empty string. You may
want to use this for things like determining the type of phone/iPad, etc.
*/
static String getDeviceDescription();
/** This will attempt to return the manufacturer of the device.
If no description is available, it'll just return an empty string.
*/
static String getDeviceManufacturer();
/** This method calculates some IDs to uniquely identify the device.
The first choice for an ID is a filesystem ID for the user's home folder or
windows directory. If that fails then this function returns the MAC addresses.
*/
static StringArray getDeviceIdentifiers();
// CPU and memory information..
/** Returns the number of logical CPU cores. */
static int getNumCpus() noexcept;
/** Returns the number of physical CPU cores. */
static int getNumPhysicalCpus() noexcept;
/** Returns the approximate CPU speed.
@returns the speed in megahertz, e.g. 1500, 2500, 32000 (depending on
what year you're reading this...)
*/
static int getCpuSpeedInMegahertz();
/** Returns a string to indicate the CPU vendor.
Might not be known on some systems.
*/
static String getCpuVendor();
/** Attempts to return a string describing the CPU model.
May not be available on some systems.
*/
static String getCpuModel();
static bool hasMMX() noexcept; /**< Returns true if Intel MMX instructions are available. */
static bool has3DNow() noexcept; /**< Returns true if AMD 3DNOW instructions are available. */
static bool hasFMA3() noexcept; /**< Returns true if AMD FMA3 instructions are available. */
static bool hasFMA4() noexcept; /**< Returns true if AMD FMA4 instructions are available. */
static bool hasSSE() noexcept; /**< Returns true if Intel SSE instructions are available. */
static bool hasSSE2() noexcept; /**< Returns true if Intel SSE2 instructions are available. */
static bool hasSSE3() noexcept; /**< Returns true if Intel SSE3 instructions are available. */
static bool hasSSSE3() noexcept; /**< Returns true if Intel SSSE3 instructions are available. */
static bool hasSSE41() noexcept; /**< Returns true if Intel SSE4.1 instructions are available. */
static bool hasSSE42() noexcept; /**< Returns true if Intel SSE4.2 instructions are available. */
static bool hasAVX() noexcept; /**< Returns true if Intel AVX instructions are available. */
static bool hasAVX2() noexcept; /**< Returns true if Intel AVX2 instructions are available. */
static bool hasAVX512F() noexcept; /**< Returns true if Intel AVX-512 Foundation instructions are available. */
static bool hasAVX512BW() noexcept; /**< Returns true if Intel AVX-512 Byte and Word instructions are available. */
static bool hasAVX512CD() noexcept; /**< Returns true if Intel AVX-512 Conflict Detection instructions are available. */
static bool hasAVX512DQ() noexcept; /**< Returns true if Intel AVX-512 Doubleword and Quadword instructions are available. */
static bool hasAVX512ER() noexcept; /**< Returns true if Intel AVX-512 Exponential and Reciprocal instructions are available. */
static bool hasAVX512IFMA() noexcept; /**< Returns true if Intel AVX-512 Integer Fused Multiply-Add instructions are available. */
static bool hasAVX512PF() noexcept; /**< Returns true if Intel AVX-512 Prefetch instructions are available. */
static bool hasAVX512VBMI() noexcept; /**< Returns true if Intel AVX-512 Vector Bit Manipulation instructions are available. */
static bool hasAVX512VL() noexcept; /**< Returns true if Intel AVX-512 Vector Length instructions are available. */
static bool hasAVX512VPOPCNTDQ() noexcept; /**< Returns true if Intel AVX-512 Vector Population Count Double and Quad-word instructions are available. */
static bool hasNeon() noexcept; /**< Returns true if ARM NEON instructions are available. */
/** Finds out how much RAM is in the machine.
@returns the approximate number of megabytes of memory, or zero if
something goes wrong when finding out.
*/
static int getMemorySizeInMegabytes();
/** Returns the system page-size.
This is only used by programmers with beards.
*/
static int getPageSize();
/** Returns a backtrace of the current call-stack.
The usefulness of the result will depend on the level of debug symbols
that are available in the executable.
*/
static String getStackBacktrace();
/** A function type for use in setApplicationCrashHandler().
When called, its void* argument will contain platform-specific data about the crash.
*/
using CrashHandlerFunction = void(*)(void*);
/** Sets up a global callback function that will be called if the application
executes some kind of illegal instruction.
You may want to call getStackBacktrace() in your handler function, to find out
where the problem happened and log it, etc.
*/
static void setApplicationCrashHandler(CrashHandlerFunction);
/** Returns true if this code is running inside an app extension sandbox.
This function will always return false on windows, linux and android.
*/
static bool isRunningInAppExtensionSandbox() noexcept;
// This method was spelt wrong! Please change your code to use getCpuSpeedInMegahertz() instead
JUCE_DEPRECATED_WITH_BODY(static int getCpuSpeedInMegaherz(), { return getCpuSpeedInMegahertz(); })
private:
SystemStats() = delete; // uses only static methods
JUCE_DECLARE_NON_COPYABLE(SystemStats)
};
} // namespace juce
/*** End of inlined file: juce_SystemStats.h ***/
/*** Start of inlined file: juce_HeavyweightLeakedObjectDetector.h ***/
namespace juce
{
/**
This class is a useful way of tracking down hard to find memory leaks when the
regular LeakedObjectDetector isn't enough.
As well as firing when any instances of the OwnerClass type are leaked, it will
print out a stack trace showing where the leaked object was created. This is obviously
quite a heavyweight task so, unlike the LeakedObjectDetector which should be always
be added to your classes, you should only use this object temporarily when you are
debugging and remove it when finished.
To use it, use the JUCE_HEAVYWEIGHT_LEAK_DETECTOR macro as a simple way to put
one in your class declaration.
@tags{Core}
*/
template <class OwnerClass>
class HeavyweightLeakedObjectDetector
{
public:
HeavyweightLeakedObjectDetector() noexcept { getBacktraceMap()[this] = SystemStats::getStackBacktrace(); }
HeavyweightLeakedObjectDetector(const HeavyweightLeakedObjectDetector&) noexcept { getBacktraceMap()[this] = SystemStats::getStackBacktrace(); }
~HeavyweightLeakedObjectDetector() { getBacktraceMap().erase(this); }
private:
typedef std::map<HeavyweightLeakedObjectDetector<OwnerClass>*, String> BacktraceMap;
struct BacktraceMapHolder
{
BacktraceMapHolder() = default;
~BacktraceMapHolder()
{
if (map.size() > 0)
{
DBG("*** Leaked objects detected: " << map.size() << " instance(s) of class " << getLeakedObjectClassName());
DBG(getFormattedBacktracesString());
/** If you hit this, then you've leaked one or more objects of the type specified by
the 'OwnerClass' template parameter - the name and stack trace of its creation should
have been printed by the lines above.
If you're leaking, it's probably because you're using old-fashioned, non-RAII techniques for
your object management. Tut, tut. Always, always use std::unique_ptrs, OwnedArrays,
ReferenceCountedObjects, etc, and avoid the 'delete' operator at all costs!
*/
jassertfalse;
}
}
String getFormattedBacktracesString() const
{
String str;
int counter = 1;
for (auto& bt : map)
{
str << "\nBacktrace " << String(counter++) << "\n"
<< "-----------------------------------------------------------------" << "\n"
<< bt.second;
}
return str;
}
BacktraceMap map;
};
static BacktraceMap& getBacktraceMap()
{
static BacktraceMapHolder holder;
return holder.map;
}
static const char* getLeakedObjectClassName()
{
return OwnerClass::getLeakedObjectClassName();
}
};
#if DOXYGEN || ! defined (JUCE_HEAVYWEIGHT_LEAK_DETECTOR)
#if (DOXYGEN || JUCE_CHECK_MEMORY_LEAKS)
/** This macro lets you embed a heavyweight leak-detecting object inside a class.
To use it, simply declare a JUCE_HEAVYWEIGHT_LEAK_DETECTOR (YourClassName) inside a private section
of the class declaration. E.g.
@code
class MyClass
{
public:
MyClass();
void blahBlah();
private:
JUCE_HEAVYWEIGHT_LEAK_DETECTOR (MyClass)
};
@endcode
NB: you should only use this when you really need to track down a tricky memory leak, and
should never leave one of these inside a class!
@see HeavyweightLeakedObjectDetector, JUCE_LEAK_DETECTOR, LeakedObjectDetector
*/
#define JUCE_HEAVYWEIGHT_LEAK_DETECTOR(OwnerClass) \
friend class juce::HeavyweightLeakedObjectDetector<OwnerClass>; \
static const char* getLeakedObjectClassName() noexcept { return #OwnerClass; } \
juce::HeavyweightLeakedObjectDetector<OwnerClass> JUCE_JOIN_MACRO (leakDetector, __LINE__);
#else
#define JUCE_HEAVYWEIGHT_LEAK_DETECTOR(OwnerClass)
#endif
#endif
} // namespace juce
/*** End of inlined file: juce_HeavyweightLeakedObjectDetector.h ***/
/*** Start of inlined file: juce_StringPairArray.h ***/
namespace juce
{
/**
A container for holding a set of strings which are keyed by another string.
@see StringArray
@tags{Core}
*/
class JUCE_API StringPairArray
{
public:
/** Creates an empty array */
StringPairArray(bool ignoreCaseWhenComparingKeys = true);
/** Creates a copy of another array */
StringPairArray(const StringPairArray& other);
/** Destructor. */
~StringPairArray();
/** Copies the contents of another string array into this one */
StringPairArray& operator= (const StringPairArray& other);
/** Compares two arrays.
Comparisons are case-sensitive.
@returns true only if the other array contains exactly the same strings with the same keys
*/
bool operator== (const StringPairArray& other) const;
/** Compares two arrays.
Comparisons are case-sensitive.
@returns false if the other array contains exactly the same strings with the same keys
*/
bool operator!= (const StringPairArray& other) const;
/** Finds the value corresponding to a key string.
If no such key is found, this will just return an empty string. To check whether
a given key actually exists (because it might actually be paired with an empty string), use
the getAllKeys() method to obtain a list.
Obviously the reference returned shouldn't be stored for later use, as the
string it refers to may disappear when the array changes.
@see getValue
*/
const String& operator[] (StringRef key) const;
/** Finds the value corresponding to a key string.
If no such key is found, this will just return the value provided as a default.
@see operator[]
*/
String getValue(StringRef, const String& defaultReturnValue) const;
/** Returns true if the given key exists. */
bool containsKey(StringRef key) const noexcept;
/** Returns a list of all keys in the array. */
const StringArray& getAllKeys() const noexcept { return keys; }
/** Returns a list of all values in the array. */
const StringArray& getAllValues() const noexcept { return values; }
/** Returns the number of strings in the array */
inline int size() const noexcept { return keys.size(); }
/** Adds or amends a key/value pair.
If a value already exists with this key, its value will be overwritten,
otherwise the key/value pair will be added to the array.
*/
void set(const String& key, const String& value);
/** Adds the items from another array to this one.
This is equivalent to using set() to add each of the pairs from the other array.
*/
void addArray(const StringPairArray& other);
/** Removes all elements from the array. */
void clear();
/** Removes a string from the array based on its key.
If the key isn't found, nothing will happen.
*/
void remove(StringRef key);
/** Removes a string from the array based on its index.
If the index is out-of-range, no action will be taken.
*/
void remove(int index);
/** Indicates whether to use a case-insensitive search when looking up a key string.
*/
void setIgnoresCase(bool shouldIgnoreCase);
/** Indicates whether a case-insensitive search is used when looking up a key string.
*/
bool getIgnoresCase() const noexcept;
/** Returns a descriptive string containing the items.
This is handy for dumping the contents of an array.
*/
String getDescription() const;
/** Reduces the amount of storage being used by the array.
Arrays typically allocate slightly more storage than they need, and after
removing elements, they may have quite a lot of unused space allocated.
This method will reduce the amount of allocated storage to a minimum.
*/
void minimiseStorageOverheads();
/** Adds the contents of a map to this StringPairArray. */
void addMap(const std::map<String, String>& mapToAdd);
private:
StringArray keys, values;
bool ignoreCase;
JUCE_LEAK_DETECTOR(StringPairArray)
};
} // namespace juce
/*** End of inlined file: juce_StringPairArray.h ***/
/*** Start of inlined file: juce_TextDiff.h ***/
namespace juce
{
/**
Calculates and applies a sequence of changes to convert one text string into
another.
Once created, the TextDiff object contains an array of change objects, where
each change can be either an insertion or a deletion. When applied in order
to the original string, these changes will convert it to the target string.
@tags{Core}
*/
class JUCE_API TextDiff
{
public:
/** Creates a set of diffs for converting the original string into the target. */
TextDiff(const String& original,
const String& target);
/** Applies this sequence of changes to the original string, producing the
target string that was specified when generating them.
Obviously it only makes sense to call this function with the string that
was originally passed to the constructor. Any other input will produce an
undefined result.
*/
String appliedTo(String text) const;
/** Describes a change, which can be either an insertion or deletion. */
struct Change
{
String insertedText; /**< If this change is a deletion, this string will be empty; otherwise,
it'll be the text that should be inserted at the index specified by start. */
int start; /**< Specifies the character index in a string at which text should be inserted or deleted. */
int length; /**< If this change is a deletion, this specifies the number of characters to delete. For an
insertion, this is the length of the new text being inserted. */
/** Returns true if this change is a deletion, or false for an insertion. */
bool isDeletion() const noexcept;
/** Returns the result of applying this change to a string. */
String appliedTo(const String& original) const noexcept;
};
/** The list of changes required to perform the transformation.
Applying each of these, in order, to the original string will produce the target.
*/
Array<Change> changes;
};
} // namespace juce
/*** End of inlined file: juce_TextDiff.h ***/
/*** Start of inlined file: juce_LocalisedStrings.h ***/
namespace juce
{
/**
Used to convert strings to localised foreign-language versions.
This is basically a look-up table of strings and their translated equivalents.
It can be loaded from a text file, so that you can supply a set of localised
versions of strings that you use in your app.
To use it in your code, simply call the translate() method on each string that
might have foreign versions, and if none is found, the method will just return
the original string.
The translation file should start with some lines specifying a description of
the language it contains, and also a list of ISO country codes where it might
be appropriate to use the file. After that, each line of the file should contain
a pair of quoted strings with an '=' sign.
E.g. for a french translation, the file might be:
@code
language: French
countries: fr be mc ch lu
"hello" = "bonjour"
"goodbye" = "au revoir"
@endcode
If the strings need to contain a quote character, they can use '\"' instead, and
if the first non-whitespace character on a line isn't a quote, then it's ignored,
(you can use this to add comments).
Note that this is a singleton class, so don't create or destroy the object directly.
There's also a TRANS(text) macro defined to make it easy to use the this.
E.g. @code
printSomething (TRANS("hello"));
@endcode
This macro is used in the JUCE classes themselves, so your application has a chance to
intercept and translate any internal JUCE text strings that might be shown. (You can easily
get a list of all the messages by searching for the TRANS() macro in the JUCE source
code).
@tags{Core}
*/
class JUCE_API LocalisedStrings
{
public:
/** Creates a set of translations from the text of a translation file.
When you create one of these, you can call setCurrentMappings() to make it
the set of mappings that the system's using.
*/
LocalisedStrings(const String& fileContents, bool ignoreCaseOfKeys);
/** Creates a set of translations from a file.
When you create one of these, you can call setCurrentMappings() to make it
the set of mappings that the system's using.
*/
LocalisedStrings(const File& fileToLoad, bool ignoreCaseOfKeys);
LocalisedStrings(const LocalisedStrings&);
LocalisedStrings& operator= (const LocalisedStrings&);
/** Destructor. */
~LocalisedStrings();
/** Selects the current set of mappings to be used by the system.
The object you pass in will be automatically deleted when no longer needed, so
don't keep a pointer to it. You can also pass in nullptr to remove the current
mappings.
See also the TRANS() macro, which uses the current set to do its translation.
@see translateWithCurrentMappings
*/
static void setCurrentMappings(LocalisedStrings* newTranslations);
/** Returns the currently selected set of mappings.
This is the object that was last passed to setCurrentMappings(). It may
be nullptr if none has been created.
*/
static LocalisedStrings* getCurrentMappings();
/** Tries to translate a string using the currently selected set of mappings.
If no mapping has been set, or if the mapping doesn't contain a translation
for the string, this will just return the original string.
See also the TRANS() macro, which uses this method to do its translation.
@see setCurrentMappings, getCurrentMappings
*/
static String translateWithCurrentMappings(const String& text);
/** Tries to translate a string using the currently selected set of mappings.
If no mapping has been set, or if the mapping doesn't contain a translation
for the string, this will just return the original string.
See also the TRANS() macro, which uses this method to do its translation.
@see setCurrentMappings, getCurrentMappings
*/
static String translateWithCurrentMappings(const char* text);
/** Attempts to look up a string and return its localised version.
If the string isn't found in the list, the original string will be returned.
*/
String translate(const String& text) const;
/** Attempts to look up a string and return its localised version.
If the string isn't found in the list, the resultIfNotFound string will be returned.
*/
String translate(const String& text, const String& resultIfNotFound) const;
/** Returns the name of the language specified in the translation file.
This is specified in the file using a line starting with "language:", e.g.
@code
language: german
@endcode
*/
String getLanguageName() const { return languageName; }
/** Returns the list of suitable country codes listed in the translation file.
These is specified in the file using a line starting with "countries:", e.g.
@code
countries: fr be mc ch lu
@endcode
The country codes are supposed to be 2-character ISO compliant codes.
*/
const StringArray& getCountryCodes() const { return countryCodes; }
/** Provides access to the actual list of mappings. */
const StringPairArray& getMappings() const { return translations; }
/** Adds and merges another set of translations into this set.
Note that the language name and country codes of the new LocalisedStrings
object must match that of this object - an assertion will be thrown if they
don't match.
Any existing values will have their mappings overwritten by the new ones.
*/
void addStrings(const LocalisedStrings&);
/** Gives this object a set of strings to use as a fallback if a string isn't found.
The object that is passed-in will be owned and deleted by this object
when no longer needed. It can be nullptr to clear the existing fallback object.
*/
void setFallback(LocalisedStrings* fallbackStrings);
private:
String languageName;
StringArray countryCodes;
StringPairArray translations;
std::unique_ptr<LocalisedStrings> fallback;
void loadFromText(const String&, bool ignoreCase);
JUCE_LEAK_DETECTOR(LocalisedStrings)
};
#ifndef TRANS
/** Uses the LocalisedStrings class to translate the given string literal.
This macro is provided for backwards-compatibility, and just calls the translate()
function. In new code, it's recommended that you just call translate() directly
instead, and avoid using macros.
@see translate(), LocalisedStrings
*/
#define TRANS(stringLiteral) juce::translate (stringLiteral)
#endif
/** A dummy version of the TRANS macro, used to indicate a string literal that should be
added to the translation file by source-code scanner tools.
Wrapping a string literal in this macro has no effect, but by using it around strings
that your app needs to translate at a later stage, it lets automatic code-scanning tools
find this string and add it to the list of strings that need translation.
*/
#define NEEDS_TRANS(stringLiteral) (stringLiteral)
/** Uses the LocalisedStrings class to translate the given string literal.
@see LocalisedStrings
*/
JUCE_API String translate(const String& stringLiteral);
/** Uses the LocalisedStrings class to translate the given string literal.
@see LocalisedStrings
*/
JUCE_API String translate(const char* stringLiteral);
/** Uses the LocalisedStrings class to translate the given string literal.
@see LocalisedStrings
*/
JUCE_API String translate(CharPointer_UTF8 stringLiteral);
/** Uses the LocalisedStrings class to translate the given string literal.
@see LocalisedStrings
*/
JUCE_API String translate(const String& stringLiteral, const String& resultIfNotFound);
} // namespace juce
/*** End of inlined file: juce_LocalisedStrings.h ***/
/*** Start of inlined file: juce_Base64.h ***/
namespace juce
{
/**
Contains some static methods for converting between binary and the
standard base-64 encoding format.
@tags{Core}
*/
struct JUCE_API Base64
{
/** Converts a binary block of data into a base-64 string.
This will write the resulting string data to the given stream.
If a write error occurs with the stream, the method will terminate and return false.
*/
static bool convertToBase64(OutputStream& base64Result, const void* sourceData, size_t sourceDataSize);
/** Converts a base-64 string back to its binary representation.
This will write the decoded binary data to the given stream.
If the string is not valid base-64, the method will terminate and return false.
*/
static bool convertFromBase64(OutputStream& binaryOutput, StringRef base64TextInput);
/** Converts a block of binary data to a base-64 string. */
static String toBase64(const void* sourceData, size_t sourceDataSize);
/** Converts a string's UTF-8 representation to a base-64 string. */
static String toBase64(const String& textToEncode);
};
} // namespace juce
/*** End of inlined file: juce_Base64.h ***/
/*** Start of inlined file: juce_Result.h ***/
namespace juce
{
/**
Represents the 'success' or 'failure' of an operation, and holds an associated
error message to describe the error when there's a failure.
E.g.
@code
Result myOperation()
{
if (doSomeKindOfFoobar())
return Result::ok();
else
return Result::fail ("foobar didn't work!");
}
const Result result (myOperation());
if (result.wasOk())
{
...it's all good...
}
else
{
warnUserAboutFailure ("The foobar operation failed! Error message was: "
+ result.getErrorMessage());
}
@endcode
@tags{Core}
*/
class JUCE_API Result
{
public:
/** Creates and returns a 'successful' result. */
static Result ok() noexcept { return Result(); }
/** Creates a 'failure' result.
If you pass a blank error message in here, a default "Unknown Error" message
will be used instead.
*/
static Result fail(const String& errorMessage) noexcept;
/** Returns true if this result indicates a success. */
bool wasOk() const noexcept;
/** Returns true if this result indicates a failure.
You can use getErrorMessage() to retrieve the error message associated
with the failure.
*/
bool failed() const noexcept;
/** Returns true if this result indicates a success.
This is equivalent to calling wasOk().
*/
operator bool() const noexcept;
/** Returns true if this result indicates a failure.
This is equivalent to calling failed().
*/
bool operator!() const noexcept;
/** Returns the error message that was set when this result was created.
For a successful result, this will be an empty string;
*/
const String& getErrorMessage() const noexcept;
Result(const Result&);
Result& operator= (const Result&);
Result(Result&&) noexcept;
Result& operator= (Result&&) noexcept;
bool operator== (const Result& other) const noexcept;
bool operator!= (const Result& other) const noexcept;
private:
String errorMessage;
// The default constructor is not for public use!
// Instead, use Result::ok() or Result::fail()
Result() noexcept;
explicit Result(const String&) noexcept;
// These casts are private to prevent people trying to use the Result object in numeric contexts
operator int() const;
operator void* () const;
};
} // namespace juce
/*** End of inlined file: juce_Result.h ***/
/*** Start of inlined file: juce_Uuid.h ***/
namespace juce
{
/**
A universally unique 128-bit identifier.
This class generates very random unique numbers. It's vanishingly unlikely
that two identical UUIDs would ever be created by chance. The values are
formatted to meet the RFC 4122 version 4 standard.
The class includes methods for saving the ID as a string or as raw binary data.
@tags{Core}
*/
class JUCE_API Uuid
{
public:
/** Creates a new unique ID, compliant with RFC 4122 version 4. */
Uuid();
/** Destructor. */
~Uuid() noexcept;
/** Creates a copy of another UUID. */
Uuid(const Uuid&) noexcept;
/** Copies another UUID. */
Uuid& operator= (const Uuid&) noexcept;
/** Returns true if the ID is zero. */
bool isNull() const noexcept;
/** Returns a null Uuid object. */
static Uuid null() noexcept;
bool operator== (const Uuid&) const noexcept;
bool operator!= (const Uuid&) const noexcept;
bool operator< (const Uuid&) const noexcept;
bool operator> (const Uuid&) const noexcept;
bool operator<= (const Uuid&) const noexcept;
bool operator>= (const Uuid&) const noexcept;
/** Returns a stringified version of this UUID.
A Uuid object can later be reconstructed from this string using operator= or
the constructor that takes a string parameter.
@returns a 32 character hex string.
*/
String toString() const;
/** Returns a stringified version of this UUID, separating it into sections with dashes.
@returns a string in the format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
*/
String toDashedString() const;
/** Creates an ID from an encoded string version.
@see toString
*/
Uuid(const String& uuidString);
/** Copies from a stringified UUID.
The string passed in should be one that was created with the toString() method.
*/
Uuid& operator= (const String& uuidString);
/** Returns the time-low section of the UUID. */
uint32 getTimeLow() const noexcept;
/** Returns the time-mid section of the UUID. */
uint16 getTimeMid() const noexcept;
/** Returns the time-high-and-version section of the UUID. */
uint16 getTimeHighAndVersion() const noexcept;
/** Returns the clock-seq-and-reserved section of the UUID. */
uint8 getClockSeqAndReserved() const noexcept;
/** Returns the clock-seq-low section of the UUID. */
uint8 getClockSeqLow() const noexcept;
/** Returns the node section of the UUID. */
uint64 getNode() const noexcept;
/** Returns a hash of the UUID. */
uint64 hash() const noexcept;
/** Returns a pointer to the internal binary representation of the ID.
This is an array of 16 bytes. To reconstruct a Uuid from its data, use
the constructor or operator= method that takes an array of uint8s.
*/
const uint8* getRawData() const noexcept { return uuid; }
/** Creates a UUID from a 16-byte array.
@see getRawData
*/
Uuid(const uint8* rawData) noexcept;
/** Sets this UUID from 16-bytes of raw data. */
Uuid& operator= (const uint8* rawData) noexcept;
private:
uint8 uuid[16];
String getHexRegion(int, int) const;
int compare(Uuid) const noexcept;
JUCE_LEAK_DETECTOR(Uuid)
};
} // namespace juce
#if ! DOXYGEN
namespace std
{
template <> struct hash<juce::Uuid>
{
size_t operator() (const juce::Uuid& u) const noexcept { return (size_t)u.hash(); }
};
}
#endif
/*** End of inlined file: juce_Uuid.h ***/
/*** Start of inlined file: juce_ConsoleApplication.h ***/
namespace juce
{
/**
Holds a list of command-line arguments, and provides useful methods for searching
and operating on them.
You can create an ArgumentList manually, or give it some argv/argc values from a
main() function to parse.
@see ConsoleApplication
@tags{Core}
*/
struct ArgumentList
{
/** Creates an argument list for a given executable. */
ArgumentList(String executable, StringArray arguments);
/** Parses a standard argv/argc pair to create an argument list. */
ArgumentList(int argc, char* argv[]);
/** Tokenises a string containing all the arguments to create an argument list. */
ArgumentList(const String& executable, const String& arguments);
ArgumentList(const ArgumentList&) = default;
ArgumentList& operator= (const ArgumentList&) = default;
/**
One of the arguments in an ArgumentList.
@tags{Core}
*/
struct Argument
{
/** The original text of this argument. */
String text;
/** Resolves this argument as an absolute File, using the current working
directory as a base for resolving relative paths, and stripping quotes, etc.
*/
File resolveAsFile() const;
/** Resolves this argument as an absolute File, using the current working
directory as a base for resolving relative paths, and also doing a check to
make sure the file exists.
If the file doesn't exist, this will call fail() with a suitable error.
@see resolveAsFile, resolveAsExistingFolder
*/
File resolveAsExistingFile() const;
/** Resolves a user-supplied folder name into an absolute File, using the current working
directory as a base for resolving relative paths, and also doing a check to make
sure the folder exists.
If the folder doesn't exist, this will call fail() with a suitable error.
@see resolveAsFile, resolveAsExistingFile
*/
File resolveAsExistingFolder() const;
/** Returns true if this argument starts with a double dash. */
bool isLongOption() const;
/** Returns true if this argument starts with a single dash. */
bool isShortOption() const;
/** Returns true if this argument starts with a double dash, followed by the given string. */
bool isLongOption(const String& optionRoot) const;
/** If this argument is a long option with a value, this returns the value.
e.g. for "--foo=bar", this would return 'bar'.
*/
String getLongOptionValue() const;
/** Returns true if this argument starts with a single dash and then contains the given character somewhere inside it. */
bool isShortOption(char shortOptionCharacter) const;
/** Returns true if this argument starts with one or more dashes. */
bool isOption() const;
/** Compares this argument against a string.
The string may be a pipe-separated list of options, e.g. "--help|-h"
*/
bool operator== (StringRef stringToCompare) const;
/** Compares this argument against a string.
The string may be a pipe-separated list of options, e.g. "--help|-h"
*/
bool operator!= (StringRef stringToCompare) const;
};
/** Returns the number of arguments in the list. */
int size() const;
/** Returns one of the arguments */
Argument operator[] (int index) const;
/** Throws an error unless there are at least the given number of arguments. */
void checkMinNumArguments(int expectedMinNumberOfArgs) const;
/** Returns true if the given string matches one of the arguments.
The option can also be a list of different versions separated by pipes, e.g. "--help|-h"
@see removeOptionIfFound
*/
bool containsOption(StringRef option) const;
/** Returns true if the given string matches one of the arguments, and also removes the
argument from the list if found.
The option can also be a list of different versions separated by pipes, e.g. "--help|-h"
@see containsOption
*/
bool removeOptionIfFound(StringRef option);
/** Returns the index of the given string if it matches one of the arguments, or -1 if it doesn't.
The option can also be a list of different versions separated by pipes, e.g. "--help|-h"
*/
int indexOfOption(StringRef option) const;
/** Throws an error unless the given option is found in the argument list. */
void failIfOptionIsMissing(StringRef option) const;
/** Looks for a given argument and returns either its assigned value (for long options) or the
string that follows it (for short options).
The option can also be a list of different versions separated by pipes, e.g. "--help|-h"
If it finds a long option, it will look for an assignment with a '=' sign, e.g. "--file=foo.txt",
and will return the string following the '='. If there's no '=', it will return an empty string.
If it finds a short option, it will attempt to return the argument that follows it, unless
it's another option.
If the argument isn't found, this returns an empty string.
*/
String getValueForOption(StringRef option) const;
/** Looks for a given argument and returns either its assigned value (for long options) or the
string that follows it (for short options).
This works like getValueForOption() but also removes the option argument (and any value arguments)
from the list if they are found.
*/
String removeValueForOption(StringRef option);
/** Looks for the value of argument using getValueForOption() and tries to parse that value as a file.
If the option isn't found, or if the value can't be parsed as a filename, it will throw an error.
*/
File getFileForOption(StringRef option) const;
/** Looks for the value of argument using getValueForOption() and tries to parse that value as a file.
This works like getFileForOption() but also removes the option argument (and any value arguments)
from the list if they are found.
*/
File getFileForOptionAndRemove(StringRef option);
/** Looks for a file argument using getFileForOption() and fails with a suitable error if
the file doesn't exist.
*/
File getExistingFileForOption(StringRef option) const;
/** Looks for a file argument using getFileForOption() and fails with a suitable error if
the file doesn't exist.
This works like getExistingFileForOption() but also removes the option argument (and any
value arguments) from the list if they are found.
*/
File getExistingFileForOptionAndRemove(StringRef option);
/** Looks for a filename argument using getFileForOption() and fails with a suitable error if
the file isn't a folder that exists.
*/
File getExistingFolderForOption(StringRef option) const;
/** Looks for a filename argument using getFileForOption() and fails with a suitable error if
the file isn't a folder that exists.
This works like getExistingFolderForOption() but also removes the option argument (and any
value arguments) from the list if they are found.
*/
File getExistingFolderForOptionAndRemove(StringRef option);
/** The name or path of the executable that was invoked, as it was specified on the command-line. */
String executableName;
/** The list of arguments (not including the name of the executable that was invoked). */
Array<Argument> arguments;
};
/**
Represents a the set of commands that a console app can perform, and provides
helper functions for performing them.
When using these helper classes to implement a console app, you probably want to
do something along these lines:
@code
int main (int argc, char* argv[])
{
ConsoleApplication app;
app.addHelpCommand ("--help|-h", "Usage:", true);
app.addVersionCommand ("--version|-v", "MyApp version 1.2.3");
app.addCommand ({ "--foo",
"--foo filename",
"Performs a foo operation on the given file",
[] (const auto& args) { doFoo (args); }});
return app.findAndRunCommand (argc, argv);
}
@endcode
@see ArgumentList
@tags{Core}
*/
struct ConsoleApplication
{
/**
Represents a command that can be executed if its command-line arguments are matched.
@see ConsoleApplication::addCommand(), ConsoleApplication::findAndRunCommand()
@tags{Core}
*/
struct Command
{
/** The option string that must appear in the argument list for this command to be invoked.
This can also be a list of different versions separated by pipes, e.g. "--help|-h"
*/
String commandOption;
/** A description of the command-line arguments needed for this command, which will be
printed as part of the help text.
*/
String argumentDescription;
/** A short (one line) description of this command, which can be printed by
ConsoleApplication::printCommandList().
*/
String shortDescription;
/** A longer description of this command, for use in extended help. */
String longDescription;
/** The actual command that should be invoked to perform this action. */
std::function<void(const ArgumentList&)> command;
};
/** Adds a command to the list. */
void addCommand(Command);
/** Adds a command to the list, and marks it as one which is invoked if no other
command matches.
*/
void addDefaultCommand(Command);
/** Adds a command that will print the given text in response to the "--version" option. */
void addVersionCommand(String versionArgument, String versionText);
/** Adds a help command to the list.
This command will print the user-supplied message that's passed in here as an
argument, followed by a list of all the registered commands.
*/
void addHelpCommand(String helpArgument, String helpMessage, bool makeDefaultCommand);
/** Prints out the list of commands and their short descriptions in a format that's
suitable for use as help.
*/
void printCommandList(const ArgumentList&) const;
/** Prints out a longer description of a particular command, based on its
longDescription member.
*/
void printCommandDetails(const ArgumentList&, const Command&) const;
/** Throws a failure exception to cause a command-line app to terminate.
This is intended to be called from code in a Command, so that the
exception will be automatically caught and turned into a printed error message
and a return code which will be returned from main().
@see ConsoleApplication::invokeCatchingFailures()
*/
static void fail(String errorMessage, int returnCode = 1);
/** Invokes a function, catching any fail() calls that it might trigger, and handling
them by printing their error message and returning their error code.
@see ConsoleApplication::fail()
*/
static int invokeCatchingFailures(std::function<int()>&& functionToCall);
/** Looks for the first command in the list which matches the given arguments, and
tries to invoke it.
If no command is found, and if there is no default command to run, it fails with
a suitable error message.
If the command calls the fail() function, this will throw an exception that gets
automatically caught and handled, and this method will return the error code that
was passed into the fail() call.
If optionMustBeFirstArg is true, then only the first argument will be looked at
when searching the available commands - this lets you do 'git' style commands where
the executable name is followed by a verb.
*/
int findAndRunCommand(const ArgumentList&,
bool optionMustBeFirstArg = false) const;
/** Creates an ArgumentList object from the argc and argv variablrs, and invokes
findAndRunCommand() using it.
*/
int findAndRunCommand(int argc, char* argv[]) const;
/** Looks for the first command in the list which matches the given arguments.
If none is found, this returns either the default command (if one is set)
or nullptr.
If optionMustBeFirstArg is true, then only the first argument will be looked at
when searching the available commands - this lets you do 'git' style commands where
the executable name is followed by a verb.
*/
const Command* findCommand(const ArgumentList&, bool optionMustBeFirstArg) const;
/** Gives read-only access to the list of registered commands. */
const std::vector<Command>& getCommands() const;
private:
std::vector<Command> commands;
int commandIfNoOthersRecognised = -1;
};
} // namespace juce
/*** End of inlined file: juce_ConsoleApplication.h ***/
/*** Start of inlined file: juce_Variant.h ***/
namespace juce
{
/**
A variant class, that can be used to hold a range of primitive values.
A var object can hold a range of simple primitive values, strings, or
any kind of ReferenceCountedObject. The var class is intended to act like
the kind of values used in dynamic scripting languages.
You can save/load var objects either in a small, proprietary binary format
using writeToStream()/readFromStream(), or as JSON by using the JSON class.
@see JSON, DynamicObject
@tags{Core}
*/
class JUCE_API var
{
public:
/** This structure is passed to a NativeFunction callback, and contains invocation
details about the function's arguments and context.
*/
struct JUCE_API NativeFunctionArgs
{
NativeFunctionArgs(const var& thisObject, const var* args, int numArgs) noexcept;
const var& thisObject;
const var* arguments;
int numArguments;
};
using NativeFunction = std::function<var(const NativeFunctionArgs&)>;
/** Creates a void variant. */
var() noexcept;
/** Destructor. */
~var() noexcept;
var(const var& valueToCopy);
var(int value) noexcept;
var(int64 value) noexcept;
var(bool value) noexcept;
var(double value) noexcept;
var(const char* value);
var(const wchar_t* value);
var(const String& value);
var(const Array<var>& value);
var(const StringArray& value);
var(ReferenceCountedObject* object);
var(NativeFunction method) noexcept;
var(const void* binaryData, size_t dataSize);
var(const MemoryBlock& binaryData);
var& operator= (const var& valueToCopy);
var& operator= (int value);
var& operator= (int64 value);
var& operator= (bool value);
var& operator= (double value);
var& operator= (const char* value);
var& operator= (const wchar_t* value);
var& operator= (const String& value);
var& operator= (const MemoryBlock& value);
var& operator= (const Array<var>& value);
var& operator= (ReferenceCountedObject* object);
var& operator= (NativeFunction method);
var(var&&) noexcept;
var(String&&);
var(MemoryBlock&&);
var(Array<var>&&);
var& operator= (var&&) noexcept;
var& operator= (String&&);
void swapWith(var& other) noexcept;
/** Returns a var object that can be used where you need the javascript "undefined" value. */
static var undefined() noexcept;
operator int() const noexcept;
operator int64() const noexcept;
operator bool() const noexcept;
operator float() const noexcept;
operator double() const noexcept;
operator String() const;
String toString() const;
/** If this variant holds an array, this provides access to it.
NOTE: Beware when you use this - the array pointer is only valid for the lifetime
of the variant that returned it, so be very careful not to call this method on temporary
var objects that are the return-value of a function, and which may go out of scope before
you use the array!
*/
Array<var>* getArray() const noexcept;
/** If this variant holds a memory block, this provides access to it.
NOTE: Beware when you use this - the MemoryBlock pointer is only valid for the lifetime
of the variant that returned it, so be very careful not to call this method on temporary
var objects that are the return-value of a function, and which may go out of scope before
you use the MemoryBlock!
*/
MemoryBlock* getBinaryData() const noexcept;
ReferenceCountedObject* getObject() const noexcept;
DynamicObject* getDynamicObject() const noexcept;
bool isVoid() const noexcept;
bool isUndefined() const noexcept;
bool isInt() const noexcept;
bool isInt64() const noexcept;
bool isBool() const noexcept;
bool isDouble() const noexcept;
bool isString() const noexcept;
bool isObject() const noexcept;
bool isArray() const noexcept;
bool isBinaryData() const noexcept;
bool isMethod() const noexcept;
/** Returns true if this var has the same value as the one supplied.
Note that this ignores the type, so a string var "123" and an integer var with the
value 123 are considered to be equal.
@see equalsWithSameType
*/
bool equals(const var& other) const noexcept;
/** Returns true if this var has the same value and type as the one supplied.
This differs from equals() because e.g. "123" and 123 will be considered different.
@see equals
*/
bool equalsWithSameType(const var& other) const noexcept;
/** Returns true if this var has the same type as the one supplied. */
bool hasSameTypeAs(const var& other) const noexcept;
/** Returns a deep copy of this object.
For simple types this just returns a copy, but if the object contains any arrays
or DynamicObjects, they will be cloned (recursively).
*/
var clone() const noexcept;
/** If the var is an array, this returns the number of elements.
If the var isn't actually an array, this will return 0.
*/
int size() const;
/** If the var is an array, this can be used to return one of its elements.
To call this method, you must make sure that the var is actually an array, and
that the index is a valid number. If these conditions aren't met, behaviour is
undefined.
For more control over the array's contents, you can call getArray() and manipulate
it directly as an Array\<var\>.
*/
const var& operator[] (int arrayIndex) const;
/** If the var is an array, this can be used to return one of its elements.
To call this method, you must make sure that the var is actually an array, and
that the index is a valid number. If these conditions aren't met, behaviour is
undefined.
For more control over the array's contents, you can call getArray() and manipulate
it directly as an Array\<var\>.
*/
var& operator[] (int arrayIndex);
/** Appends an element to the var, converting it to an array if it isn't already one.
If the var isn't an array, it will be converted to one, and if its value was non-void,
this value will be kept as the first element of the new array. The parameter value
will then be appended to it.
For more control over the array's contents, you can call getArray() and manipulate
it directly as an Array\<var\>.
*/
void append(const var& valueToAppend);
/** Inserts an element to the var, converting it to an array if it isn't already one.
If the var isn't an array, it will be converted to one, and if its value was non-void,
this value will be kept as the first element of the new array. The parameter value
will then be inserted into it.
For more control over the array's contents, you can call getArray() and manipulate
it directly as an Array\<var\>.
*/
void insert(int index, const var& value);
/** If the var is an array, this removes one of its elements.
If the index is out-of-range or the var isn't an array, nothing will be done.
For more control over the array's contents, you can call getArray() and manipulate
it directly as an Array\<var\>.
*/
void remove(int index);
/** Treating the var as an array, this resizes it to contain the specified number of elements.
If the var isn't an array, it will be converted to one, and if its value was non-void,
this value will be kept as the first element of the new array before resizing.
For more control over the array's contents, you can call getArray() and manipulate
it directly as an Array\<var\>.
*/
void resize(int numArrayElementsWanted);
/** If the var is an array, this searches it for the first occurrence of the specified value,
and returns its index.
If the var isn't an array, or if the value isn't found, this returns -1.
*/
int indexOf(const var& value) const;
/** If this variant is an object, this returns one of its properties. */
const var& operator[] (const Identifier& propertyName) const;
/** If this variant is an object, this returns one of its properties. */
const var& operator[] (const char* propertyName) const;
/** If this variant is an object, this returns one of its properties, or a default
fallback value if the property is not set. */
var getProperty(const Identifier& propertyName, const var& defaultReturnValue) const;
/** Returns true if this variant is an object and if it has the given property. */
bool hasProperty(const Identifier& propertyName) const noexcept;
/** Invokes a named method call with no arguments. */
var call(const Identifier& method) const;
/** Invokes a named method call with one argument. */
var call(const Identifier& method, const var& arg1) const;
/** Invokes a named method call with 2 arguments. */
var call(const Identifier& method, const var& arg1, const var& arg2) const;
/** Invokes a named method call with 3 arguments. */
var call(const Identifier& method, const var& arg1, const var& arg2, const var& arg3);
/** Invokes a named method call with 4 arguments. */
var call(const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const;
/** Invokes a named method call with 5 arguments. */
var call(const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const;
/** Invokes a named method call with a list of arguments. */
var invoke(const Identifier& method, const var* arguments, int numArguments) const;
/** If this object is a method, this returns the function pointer. */
NativeFunction getNativeFunction() const;
/** Writes a binary representation of this value to a stream.
The data can be read back later using readFromStream().
@see JSON
*/
void writeToStream(OutputStream& output) const;
/** Reads back a stored binary representation of a value.
The data in the stream must have been written using writeToStream(), or this
will have unpredictable results.
@see JSON
*/
static var readFromStream(InputStream& input);
/* This was a static empty var object, but is now deprecated as it's too easy to accidentally
use it indirectly during a static constructor, leading to hard-to-find order-of-initialisation
problems.
@deprecated If you need a default-constructed var, just use var() or {}.
The only time you might miss having var::null available might be if you need to return an
empty var from a function by reference, but if you need to do that, it's easy enough to use
a function-local static var and return that, avoiding any order-of-initialisation issues.
*/
JUCE_DEPRECATED_STATIC(static const var null;)
private:
struct VariantType;
struct Instance;
union ValueUnion
{
int intValue;
int64 int64Value;
bool boolValue;
double doubleValue;
char stringValue[sizeof(String)];
ReferenceCountedObject* objectValue;
MemoryBlock* binaryValue;
NativeFunction* methodValue;
};
friend bool canCompare(const var&, const var&);
const VariantType* type;
ValueUnion value;
Array<var>* convertToArray();
var(const VariantType&) noexcept;
// This is needed to prevent the wrong constructor/operator being called
var(const ReferenceCountedObject*) = delete;
var& operator= (const ReferenceCountedObject*) = delete;
var(const void*) = delete;
var& operator= (const void*) = delete;
};
/** Compares the values of two var objects, using the var::equals() comparison. */
JUCE_API bool operator== (const var&, const var&);
/** Compares the values of two var objects, using the var::equals() comparison. */
JUCE_API bool operator!= (const var&, const var&);
/** Compares the values of two var objects, using the var::equals() comparison. */
JUCE_API bool operator< (const var&, const var&);
/** Compares the values of two var objects, using the var::equals() comparison. */
JUCE_API bool operator<= (const var&, const var&);
/** Compares the values of two var objects, using the var::equals() comparison. */
JUCE_API bool operator> (const var&, const var&);
/** Compares the values of two var objects, using the var::equals() comparison. */
JUCE_API bool operator>= (const var&, const var&);
JUCE_API bool operator== (const var&, const String&);
JUCE_API bool operator!= (const var&, const String&);
JUCE_API bool operator== (const var&, const char*);
JUCE_API bool operator!= (const var&, const char*);
/** This template-overloaded class can be used to convert between var and custom types.
@tags{Core}
*/
template <typename Type>
struct VariantConverter
{
static Type fromVar(const var& v) { return static_cast<Type> (v); }
static var toVar(const Type& t) { return t; }
};
#ifndef DOXYGEN
template <>
struct VariantConverter<String>
{
static String fromVar(const var& v) { return v.toString(); }
static var toVar(const String& s) { return s; }
};
#endif
} // namespace juce
/*** End of inlined file: juce_Variant.h ***/
/*** Start of inlined file: juce_NamedValueSet.h ***/
namespace juce
{
/** Holds a set of named var objects.
This can be used as a basic structure to hold a set of var object, which can
be retrieved by using their identifier.
@tags{Core}
*/
class JUCE_API NamedValueSet
{
public:
/** Structure for a named var object */
struct JUCE_API NamedValue
{
NamedValue() noexcept;
~NamedValue() noexcept;
NamedValue(const Identifier& name, const var& value);
NamedValue(const Identifier& name, var&& value) noexcept;
NamedValue(Identifier&& name, var&& value) noexcept;
NamedValue(const NamedValue&);
NamedValue(NamedValue&&) noexcept;
NamedValue& operator= (NamedValue&&) noexcept;
bool operator== (const NamedValue&) const noexcept;
bool operator!= (const NamedValue&) const noexcept;
Identifier name;
var value;
};
/** Creates an empty set. */
NamedValueSet() noexcept;
NamedValueSet(const NamedValueSet&);
NamedValueSet(NamedValueSet&&) noexcept;
NamedValueSet& operator= (const NamedValueSet&);
NamedValueSet& operator= (NamedValueSet&&) noexcept;
/** Creates a NamedValueSet from a list of names and properties. */
NamedValueSet(std::initializer_list<NamedValue>);
/** Destructor. */
~NamedValueSet() noexcept;
/** Two NamedValueSets are considered equal if they contain all the same key/value
pairs, regardless of the order.
*/
bool operator== (const NamedValueSet&) const noexcept;
bool operator!= (const NamedValueSet&) const noexcept;
const NamedValueSet::NamedValue* begin() const noexcept { return values.begin(); }
const NamedValueSet::NamedValue* end() const noexcept { return values.end(); }
/** Returns the total number of values that the set contains. */
int size() const noexcept;
/** Returns true if the set is empty. */
bool isEmpty() const noexcept;
/** Returns the value of a named item.
If the name isn't found, this will return a void variant.
*/
const var& operator[] (const Identifier& name) const noexcept;
/** Tries to return the named value, but if no such value is found, this will
instead return the supplied default value.
*/
var getWithDefault(const Identifier& name, const var& defaultReturnValue) const;
/** Changes or adds a named value.
@returns true if a value was changed or added; false if the
value was already set the value passed-in.
*/
bool set(const Identifier& name, const var& newValue);
/** Changes or adds a named value.
@returns true if a value was changed or added; false if the
value was already set the value passed-in.
*/
bool set(const Identifier& name, var&& newValue);
/** Returns true if the set contains an item with the specified name. */
bool contains(const Identifier& name) const noexcept;
/** Removes a value from the set.
@returns true if a value was removed; false if there was no value
with the name that was given.
*/
bool remove(const Identifier& name);
/** Returns the name of the value at a given index.
The index must be between 0 and size() - 1.
*/
Identifier getName(int index) const noexcept;
/** Returns a pointer to the var that holds a named value, or null if there is
no value with this name.
Do not use this method unless you really need access to the internal var object
for some reason - for normal reading and writing always prefer operator[]() and set().
Also note that the pointer returned may become invalid as soon as any subsequent
methods are called on the NamedValueSet.
*/
var* getVarPointer(const Identifier& name) noexcept;
/** Returns a pointer to the var that holds a named value, or null if there is
no value with this name.
Do not use this method unless you really need access to the internal var object
for some reason - for normal reading and writing always prefer operator[]() and set().
Also note that the pointer returned may become invalid as soon as any subsequent
methods are called on the NamedValueSet.
*/
const var* getVarPointer(const Identifier& name) const noexcept;
/** Returns the value of the item at a given index.
The index must be between 0 and size() - 1.
*/
const var& getValueAt(int index) const noexcept;
/** Returns the value of the item at a given index.
The index must be between 0 and size() - 1, or this will return a nullptr
Also note that the pointer returned may become invalid as soon as any subsequent
methods are called on the NamedValueSet.
*/
var* getVarPointerAt(int index) noexcept;
/** Returns the value of the item at a given index.
The index must be between 0 and size() - 1, or this will return a nullptr
Also note that the pointer returned may become invalid as soon as any subsequent
methods are called on the NamedValueSet.
*/
const var* getVarPointerAt(int index) const noexcept;
/** Returns the index of the given name, or -1 if it's not found. */
int indexOf(const Identifier& name) const noexcept;
/** Removes all values. */
void clear();
/** Sets properties to the values of all of an XML element's attributes. */
void setFromXmlAttributes(const XmlElement& xml);
/** Sets attributes in an XML element corresponding to each of this object's
properties.
*/
void copyToXmlAttributes(XmlElement& xml) const;
private:
Array<NamedValue> values;
};
} // namespace juce
/*** End of inlined file: juce_NamedValueSet.h ***/
/*** Start of inlined file: juce_DynamicObject.h ***/
namespace juce
{
/**
Represents a dynamically implemented object.
This class is primarily intended for wrapping scripting language objects,
but could be used for other purposes.
An instance of a DynamicObject can be used to store named properties, and
by subclassing hasMethod() and invokeMethod(), you can give your object
methods.
@tags{Core}
*/
class JUCE_API DynamicObject : public ReferenceCountedObject
{
public:
DynamicObject();
DynamicObject(const DynamicObject&);
~DynamicObject() override;
using Ptr = ReferenceCountedObjectPtr<DynamicObject>;
/** Returns true if the object has a property with this name.
Note that if the property is actually a method, this will return false.
*/
virtual bool hasProperty(const Identifier& propertyName) const;
/** Returns a named property.
This returns var() if no such property exists.
*/
virtual const var& getProperty(const Identifier& propertyName) const;
/** Sets a named property. */
virtual void setProperty(const Identifier& propertyName, const var& newValue);
/** Removes a named property. */
virtual void removeProperty(const Identifier& propertyName);
/** Checks whether this object has the specified method.
The default implementation of this just checks whether there's a property
with this name that's actually a method, but this can be overridden for
building objects with dynamic invocation.
*/
virtual bool hasMethod(const Identifier& methodName) const;
/** Invokes a named method on this object.
The default implementation looks up the named property, and if it's a method
call, then it invokes it.
This method is virtual to allow more dynamic invocation to used for objects
where the methods may not already be set as properties.
*/
virtual var invokeMethod(Identifier methodName,
const var::NativeFunctionArgs& args);
/** Adds a method to the class.
This is basically the same as calling setProperty (methodName, (var::NativeFunction) myFunction), but
helps to avoid accidentally invoking the wrong type of var constructor. It also makes
the code easier to read.
*/
void setMethod(Identifier methodName, var::NativeFunction function);
/** Removes all properties and methods from the object. */
void clear();
/** Returns the NamedValueSet that holds the object's properties. */
NamedValueSet& getProperties() noexcept { return properties; }
/** Calls var::clone() on all the properties that this object contains. */
void cloneAllProperties();
/** Returns a clone of this object.
The default implementation of this method just returns a new DynamicObject
with a (deep) copy of all of its properties. Subclasses can override this to
implement their own custom copy routines.
*/
virtual Ptr clone();
/** Writes this object to a text stream in JSON format.
This method is used by JSON::toString and JSON::writeToStream, and you should
never need to call it directly, but it's virtual so that custom object types
can stringify themselves appropriately.
*/
virtual void writeAsJSON(OutputStream&, int indentLevel, bool allOnOneLine, int maximumDecimalPlaces);
private:
NamedValueSet properties;
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE
// This method has been deprecated - use var::invoke instead
virtual void invokeMethod(const Identifier&, const var*, int) {}
#endif
JUCE_LEAK_DETECTOR(DynamicObject)
};
} // namespace juce
/*** End of inlined file: juce_DynamicObject.h ***/
/*** Start of inlined file: juce_HashMap.h ***/
namespace juce
{
/**
A simple class to generate hash functions for some primitive types, intended for
use with the HashMap class.
@see HashMap
@tags{Core}
*/
struct DefaultHashFunctions
{
/** Generates a simple hash from an unsigned int. */
static int generateHash(uint32 key, int upperLimit) noexcept { return (int)(key % (uint32)upperLimit); }
/** Generates a simple hash from an integer. */
static int generateHash(int32 key, int upperLimit) noexcept { return generateHash((uint32)key, upperLimit); }
/** Generates a simple hash from a uint64. */
static int generateHash(uint64 key, int upperLimit) noexcept { return (int)(key % (uint64)upperLimit); }
/** Generates a simple hash from an int64. */
static int generateHash(int64 key, int upperLimit) noexcept { return generateHash((uint64)key, upperLimit); }
/** Generates a simple hash from a string. */
static int generateHash(const String& key, int upperLimit) noexcept { return generateHash((uint32)key.hashCode(), upperLimit); }
/** Generates a simple hash from a variant. */
static int generateHash(const var& key, int upperLimit) noexcept { return generateHash(key.toString(), upperLimit); }
/** Generates a simple hash from a void ptr. */
static int generateHash(const void* key, int upperLimit) noexcept { return generateHash((uint64)(pointer_sized_uint)key, upperLimit); }
/** Generates a simple hash from a UUID. */
static int generateHash(const Uuid& key, int upperLimit) noexcept { return generateHash(key.hash(), upperLimit); }
};
/**
Holds a set of mappings between some key/value pairs.
The types of the key and value objects are set as template parameters.
You can also specify a class to supply a hash function that converts a key value
into an hashed integer. This class must have the form:
@code
struct MyHashGenerator
{
int generateHash (MyKeyType key, int upperLimit) const
{
// The function must return a value 0 <= x < upperLimit
return someFunctionOfMyKeyType (key) % upperLimit;
}
};
@endcode
Like the Array class, the key and value types are expected to be copy-by-value
types, so if you define them to be pointer types, this class won't delete the
objects that they point to.
If you don't supply a class for the HashFunctionType template parameter, the
default one provides some simple mappings for strings and ints.
@code
HashMap<int, String> hash;
hash.set (1, "item1");
hash.set (2, "item2");
DBG (hash [1]); // prints "item1"
DBG (hash [2]); // prints "item2"
// This iterates the map, printing all of its key -> value pairs..
for (HashMap<int, String>::Iterator i (hash); i.next();)
DBG (i.getKey() << " -> " << i.getValue());
@endcode
@tparam HashFunctionType The class of hash function, which must be copy-constructible.
@see CriticalSection, DefaultHashFunctions, NamedValueSet, SortedSet
@tags{Core}
*/
template <typename KeyType,
typename ValueType,
class HashFunctionType = DefaultHashFunctions,
class TypeOfCriticalSectionToUse = DummyCriticalSection>
class HashMap
{
private:
using KeyTypeParameter = typename TypeHelpers::ParameterType<KeyType>::type;
using ValueTypeParameter = typename TypeHelpers::ParameterType<ValueType>::type;
public:
/** Creates an empty hash-map.
@param numberOfSlots Specifies the number of hash entries the map will use. This will be
the "upperLimit" parameter that is passed to your generateHash()
function. The number of hash slots will grow automatically if necessary,
or it can be remapped manually using remapTable().
@param hashFunction An instance of HashFunctionType, which will be copied and
stored to use with the HashMap. This parameter can be omitted
if HashFunctionType has a default constructor.
*/
explicit HashMap(int numberOfSlots = defaultHashTableSize,
HashFunctionType hashFunction = HashFunctionType())
: hashFunctionToUse(hashFunction)
{
hashSlots.insertMultiple(0, nullptr, numberOfSlots);
}
/** Destructor. */
~HashMap()
{
clear();
}
/** Removes all values from the map.
Note that this will clear the content, but won't affect the number of slots (see
remapTable and getNumSlots).
*/
void clear()
{
const ScopedLockType sl(getLock());
for (auto i = hashSlots.size(); --i >= 0;)
{
auto* h = hashSlots.getUnchecked(i);
while (h != nullptr)
{
const std::unique_ptr<HashEntry> deleter(h);
h = h->nextEntry;
}
hashSlots.set(i, nullptr);
}
totalNumItems = 0;
}
/** Returns the current number of items in the map. */
inline int size() const noexcept
{
return totalNumItems;
}
/** Returns the value corresponding to a given key.
If the map doesn't contain the key, a default instance of the value type is returned.
@param keyToLookFor the key of the item being requested
*/
inline ValueType operator[] (KeyTypeParameter keyToLookFor) const
{
const ScopedLockType sl(getLock());
if (auto* entry = getEntry(getSlot(keyToLookFor), keyToLookFor))
return entry->value;
return ValueType();
}
/** Returns a reference to the value corresponding to a given key.
If the map doesn't contain the key, a default instance of the value type is
added to the map and a reference to this is returned.
@param keyToLookFor the key of the item being requested
*/
inline ValueType& getReference(KeyTypeParameter keyToLookFor)
{
const ScopedLockType sl(getLock());
auto hashIndex = generateHashFor(keyToLookFor, getNumSlots());
auto* firstEntry = hashSlots.getUnchecked(hashIndex);
if (auto* entry = getEntry(firstEntry, keyToLookFor))
return entry->value;
auto* entry = new HashEntry(keyToLookFor, ValueType(), firstEntry);
hashSlots.set(hashIndex, entry);
++totalNumItems;
if (totalNumItems > (getNumSlots() * 3) / 2)
remapTable(getNumSlots() * 2);
return entry->value;
}
/** Returns true if the map contains an item with the specified key. */
bool contains(KeyTypeParameter keyToLookFor) const
{
const ScopedLockType sl(getLock());
return (getEntry(getSlot(keyToLookFor), keyToLookFor) != nullptr);
}
/** Returns true if the hash contains at least one occurrence of a given value. */
bool containsValue(ValueTypeParameter valueToLookFor) const
{
const ScopedLockType sl(getLock());
for (auto i = getNumSlots(); --i >= 0;)
for (auto* entry = hashSlots.getUnchecked(i); entry != nullptr; entry = entry->nextEntry)
if (entry->value == valueToLookFor)
return true;
return false;
}
/** Adds or replaces an element in the hash-map.
If there's already an item with the given key, this will replace its value. Otherwise, a new item
will be added to the map.
*/
void set(KeyTypeParameter newKey, ValueTypeParameter newValue) { getReference(newKey) = newValue; }
/** Removes an item with the given key. */
void remove(KeyTypeParameter keyToRemove)
{
const ScopedLockType sl(getLock());
auto hashIndex = generateHashFor(keyToRemove, getNumSlots());
auto* entry = hashSlots.getUnchecked(hashIndex);
HashEntry* previous = nullptr;
while (entry != nullptr)
{
if (entry->key == keyToRemove)
{
const std::unique_ptr<HashEntry> deleter(entry);
entry = entry->nextEntry;
if (previous != nullptr)
previous->nextEntry = entry;
else
hashSlots.set(hashIndex, entry);
--totalNumItems;
}
else
{
previous = entry;
entry = entry->nextEntry;
}
}
}
/** Removes all items with the given value. */
void removeValue(ValueTypeParameter valueToRemove)
{
const ScopedLockType sl(getLock());
for (auto i = getNumSlots(); --i >= 0;)
{
auto* entry = hashSlots.getUnchecked(i);
HashEntry* previous = nullptr;
while (entry != nullptr)
{
if (entry->value == valueToRemove)
{
const std::unique_ptr<HashEntry> deleter(entry);
entry = entry->nextEntry;
if (previous != nullptr)
previous->nextEntry = entry;
else
hashSlots.set(i, entry);
--totalNumItems;
}
else
{
previous = entry;
entry = entry->nextEntry;
}
}
}
}
/** Remaps the hash-map to use a different number of slots for its hash function.
Each slot corresponds to a single hash-code, and each one can contain multiple items.
@see getNumSlots()
*/
void remapTable(int newNumberOfSlots)
{
const ScopedLockType sl(getLock());
Array<HashEntry*> newSlots;
newSlots.insertMultiple(0, nullptr, newNumberOfSlots);
for (auto i = getNumSlots(); --i >= 0;)
{
HashEntry* nextEntry = nullptr;
for (auto* entry = hashSlots.getUnchecked(i); entry != nullptr; entry = nextEntry)
{
auto hashIndex = generateHashFor(entry->key, newNumberOfSlots);
nextEntry = entry->nextEntry;
entry->nextEntry = newSlots.getUnchecked(hashIndex);
newSlots.set(hashIndex, entry);
}
}
hashSlots.swapWith(newSlots);
}
/** Returns the number of slots which are available for hashing.
Each slot corresponds to a single hash-code, and each one can contain multiple items.
@see getNumSlots()
*/
inline int getNumSlots() const noexcept
{
return hashSlots.size();
}
/** Efficiently swaps the contents of two hash-maps. */
template <class OtherHashMapType>
void swapWith(OtherHashMapType& otherHashMap) noexcept
{
const ScopedLockType lock1(getLock());
const typename OtherHashMapType::ScopedLockType lock2(otherHashMap.getLock());
hashSlots.swapWith(otherHashMap.hashSlots);
std::swap(totalNumItems, otherHashMap.totalNumItems);
}
/** Returns the CriticalSection that locks this structure.
To lock, you can call getLock().enter() and getLock().exit(), or preferably use
an object of ScopedLockType as an RAII lock for it.
*/
inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return lock; }
/** Returns the type of scoped lock to use for locking this array */
using ScopedLockType = typename TypeOfCriticalSectionToUse::ScopedLockType;
private:
class HashEntry
{
public:
HashEntry(KeyTypeParameter k, ValueTypeParameter val, HashEntry* const next)
: key(k), value(val), nextEntry(next)
{}
const KeyType key;
ValueType value;
HashEntry* nextEntry;
JUCE_DECLARE_NON_COPYABLE(HashEntry)
};
public:
/** Iterates over the items in a HashMap.
To use it, repeatedly call next() until it returns false, e.g.
@code
HashMap <String, String> myMap;
HashMap<String, String>::Iterator i (myMap);
while (i.next())
{
DBG (i.getKey() << " -> " << i.getValue());
}
@endcode
The order in which items are iterated bears no resemblance to the order in which
they were originally added!
Obviously as soon as you call any non-const methods on the original hash-map, any
iterators that were created beforehand will cease to be valid, and should not be used.
@see HashMap
*/
struct Iterator
{
Iterator(const HashMap& hashMapToIterate) noexcept
: hashMap(hashMapToIterate), entry(nullptr), index(0)
{}
Iterator(const Iterator& other) noexcept
: hashMap(other.hashMap), entry(other.entry), index(other.index)
{}
/** Moves to the next item, if one is available.
When this returns true, you can get the item's key and value using getKey() and
getValue(). If it returns false, the iteration has finished and you should stop.
*/
bool next() noexcept
{
if (entry != nullptr)
entry = entry->nextEntry;
while (entry == nullptr)
{
if (index >= hashMap.getNumSlots())
return false;
entry = hashMap.hashSlots.getUnchecked(index++);
}
return true;
}
/** Returns the current item's key.
This should only be called when a call to next() has just returned true.
*/
KeyType getKey() const
{
return entry != nullptr ? entry->key : KeyType();
}
/** Returns the current item's value.
This should only be called when a call to next() has just returned true.
*/
ValueType getValue() const
{
return entry != nullptr ? entry->value : ValueType();
}
/** Resets the iterator to its starting position. */
void reset() noexcept
{
entry = nullptr;
index = 0;
}
Iterator& operator++() noexcept { next(); return *this; }
ValueType operator*() const { return getValue(); }
bool operator!= (const Iterator& other) const noexcept { return entry != other.entry || index != other.index; }
void resetToEnd() noexcept { index = hashMap.getNumSlots(); }
private:
const HashMap& hashMap;
HashEntry* entry;
int index;
// using the copy constructor is ok, but you cannot assign iterators
Iterator& operator= (const Iterator&) = delete;
JUCE_LEAK_DETECTOR(Iterator)
};
/** Returns a start iterator for the values in this tree. */
Iterator begin() const noexcept { Iterator i(*this); i.next(); return i; }
/** Returns an end iterator for the values in this tree. */
Iterator end() const noexcept { Iterator i(*this); i.resetToEnd(); return i; }
private:
enum { defaultHashTableSize = 101 };
friend struct Iterator;
HashFunctionType hashFunctionToUse;
Array<HashEntry*> hashSlots;
int totalNumItems = 0;
TypeOfCriticalSectionToUse lock;
int generateHashFor(KeyTypeParameter key, int numSlots) const
{
const int hash = hashFunctionToUse.generateHash(key, numSlots);
jassert(isPositiveAndBelow(hash, numSlots)); // your hash function is generating out-of-range numbers!
return hash;
}
static HashEntry* getEntry(HashEntry* firstEntry, KeyType keyToLookFor) noexcept
{
for (auto* entry = firstEntry; entry != nullptr; entry = entry->nextEntry)
if (entry->key == keyToLookFor)
return entry;
return nullptr;
}
inline HashEntry* getSlot(KeyType key) const noexcept { return hashSlots.getUnchecked(generateHashFor(key, getNumSlots())); }
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(HashMap)
};
} // namespace juce
/*** End of inlined file: juce_HashMap.h ***/
/*** Start of inlined file: juce_RelativeTime.h ***/
namespace juce
{
/** A relative measure of time.
The time is stored as a number of seconds, at double-precision floating
point accuracy, and may be positive or negative.
If you need an absolute time, (i.e. a date + time), see the Time class.
@tags{Core}
*/
class JUCE_API RelativeTime
{
public:
/** Creates a RelativeTime.
@param seconds the number of seconds, which may be +ve or -ve.
@see milliseconds, minutes, hours, days, weeks
*/
explicit RelativeTime(double seconds = 0.0) noexcept;
/** Copies another relative time. */
RelativeTime(const RelativeTime& other) noexcept;
/** Copies another relative time. */
RelativeTime& operator= (const RelativeTime& other) noexcept;
/** Destructor. */
~RelativeTime() noexcept;
/** Creates a new RelativeTime object representing a number of milliseconds.
@see seconds, minutes, hours, days, weeks
*/
static RelativeTime milliseconds(int milliseconds) noexcept;
/** Creates a new RelativeTime object representing a number of milliseconds.
@see seconds, minutes, hours, days, weeks
*/
static RelativeTime milliseconds(int64 milliseconds) noexcept;
/** Creates a new RelativeTime object representing a number of seconds.
@see milliseconds, minutes, hours, days, weeks
*/
static RelativeTime seconds(double seconds) noexcept;
/** Creates a new RelativeTime object representing a number of minutes.
@see milliseconds, hours, days, weeks
*/
static RelativeTime minutes(double numberOfMinutes) noexcept;
/** Creates a new RelativeTime object representing a number of hours.
@see milliseconds, minutes, days, weeks
*/
static RelativeTime hours(double numberOfHours) noexcept;
/** Creates a new RelativeTime object representing a number of days.
@see milliseconds, minutes, hours, weeks
*/
static RelativeTime days(double numberOfDays) noexcept;
/** Creates a new RelativeTime object representing a number of weeks.
@see milliseconds, minutes, hours, days
*/
static RelativeTime weeks(double numberOfWeeks) noexcept;
/** Returns the number of milliseconds this time represents.
@see milliseconds, inSeconds, inMinutes, inHours, inDays, inWeeks
*/
int64 inMilliseconds() const noexcept;
/** Returns the number of seconds this time represents.
@see inMilliseconds, inMinutes, inHours, inDays, inWeeks
*/
double inSeconds() const noexcept { return numSeconds; }
/** Returns the number of minutes this time represents.
@see inMilliseconds, inSeconds, inHours, inDays, inWeeks
*/
double inMinutes() const noexcept;
/** Returns the number of hours this time represents.
@see inMilliseconds, inSeconds, inMinutes, inDays, inWeeks
*/
double inHours() const noexcept;
/** Returns the number of days this time represents.
@see inMilliseconds, inSeconds, inMinutes, inHours, inWeeks
*/
double inDays() const noexcept;
/** Returns the number of weeks this time represents.
@see inMilliseconds, inSeconds, inMinutes, inHours, inDays
*/
double inWeeks() const noexcept;
/** Returns a readable textual description of the time.
The exact format of the string returned will depend on
the magnitude of the time - e.g.
"1 min 4 secs", "1 hr 45 mins", "2 weeks 5 days", "140 ms"
so that only the two most significant units are printed.
The returnValueForZeroTime value is the result that is returned if the
length is zero. Depending on your application you might want to use this
to return something more relevant like "empty" or "0 secs", etc.
@see inMilliseconds, inSeconds, inMinutes, inHours, inDays, inWeeks
*/
String getDescription(const String& returnValueForZeroTime = "0") const;
/** This returns a string that roughly describes how long ago this time was, which
can be handy for showing ages of files, etc.
This will only attempt to be accurate to within the nearest order of magnitude
so returns strings such as "5 years", "2 weeks", "< 1 minute", "< 1 sec" etc.
*/
String getApproximateDescription() const;
/** Adds another RelativeTime to this one. */
RelativeTime operator+= (RelativeTime timeToAdd) noexcept;
/** Subtracts another RelativeTime from this one. */
RelativeTime operator-= (RelativeTime timeToSubtract) noexcept;
/** Adds a number of seconds to this time. */
RelativeTime operator+= (double secondsToAdd) noexcept;
/** Subtracts a number of seconds from this time. */
RelativeTime operator-= (double secondsToSubtract) noexcept;
private:
double numSeconds;
};
/** Compares two RelativeTimes. */
JUCE_API bool JUCE_CALLTYPE operator== (RelativeTime t1, RelativeTime t2) noexcept;
/** Compares two RelativeTimes. */
JUCE_API bool JUCE_CALLTYPE operator!= (RelativeTime t1, RelativeTime t2) noexcept;
/** Compares two RelativeTimes. */
JUCE_API bool JUCE_CALLTYPE operator> (RelativeTime t1, RelativeTime t2) noexcept;
/** Compares two RelativeTimes. */
JUCE_API bool JUCE_CALLTYPE operator< (RelativeTime t1, RelativeTime t2) noexcept;
/** Compares two RelativeTimes. */
JUCE_API bool JUCE_CALLTYPE operator>= (RelativeTime t1, RelativeTime t2) noexcept;
/** Compares two RelativeTimes. */
JUCE_API bool JUCE_CALLTYPE operator<= (RelativeTime t1, RelativeTime t2) noexcept;
/** Adds two RelativeTimes together. */
JUCE_API RelativeTime JUCE_CALLTYPE operator+ (RelativeTime t1, RelativeTime t2) noexcept;
/** Subtracts two RelativeTimes. */
JUCE_API RelativeTime JUCE_CALLTYPE operator- (RelativeTime t1, RelativeTime t2) noexcept;
} // namespace juce
/*** End of inlined file: juce_RelativeTime.h ***/
/*** Start of inlined file: juce_Time.h ***/
namespace juce
{
/**
Holds an absolute date and time.
Internally, the time is stored at millisecond precision.
@see RelativeTime
@tags{Core}
*/
class JUCE_API Time
{
public:
/** Creates a Time object.
This default constructor creates a time of midnight Jan 1st 1970 UTC, (which is
represented internally as 0ms).
To create a time object representing the current time, use getCurrentTime().
@see getCurrentTime
*/
Time() = default;
/** Creates a time based on a number of milliseconds.
To create a time object set to the current time, use getCurrentTime().
@param millisecondsSinceEpoch the number of milliseconds since the unix
'epoch' (midnight Jan 1st 1970 UTC).
@see getCurrentTime, currentTimeMillis
*/
explicit Time(int64 millisecondsSinceEpoch) noexcept;
/** Creates a time from a set of date components.
@param year the year, in 4-digit format, e.g. 2004
@param month the month, in the range 0 to 11
@param day the day of the month, in the range 1 to 31
@param hours hours in 24-hour clock format, 0 to 23
@param minutes minutes 0 to 59
@param seconds seconds 0 to 59
@param milliseconds milliseconds 0 to 999
@param useLocalTime if true, assume input is in this machine's local timezone
if false, assume input is in UTC.
*/
Time(int year,
int month,
int day,
int hours,
int minutes,
int seconds = 0,
int milliseconds = 0,
bool useLocalTime = true) noexcept;
Time(const Time&) = default;
~Time() = default;
Time& operator= (const Time&) = default;
/** Returns a Time object that is set to the current system time.
This may not be monotonic, as the system time can change at any moment.
You should therefore not use this method for measuring time intervals.
@see currentTimeMillis
*/
static Time JUCE_CALLTYPE getCurrentTime() noexcept;
/** Returns the time as a number of milliseconds.
@returns the number of milliseconds this Time object represents, since
midnight Jan 1st 1970 UTC.
@see getMilliseconds
*/
int64 toMilliseconds() const noexcept { return millisSinceEpoch; }
/** Returns the year (in this machine's local timezone).
A 4-digit format is used, e.g. 2004.
*/
int getYear() const noexcept;
/** Returns the number of the month (in this machine's local timezone).
The value returned is in the range 0 to 11.
@see getMonthName
*/
int getMonth() const noexcept;
/** Returns the name of the month (in this machine's local timezone).
@param threeLetterVersion if true, it'll be a 3-letter abbreviation, e.g. "Jan"; if false
it'll return the long form, e.g. "January"
@see getMonth
*/
String getMonthName(bool threeLetterVersion) const;
/** Returns the day of the month (in this machine's local timezone).
The value returned is in the range 1 to 31.
*/
int getDayOfMonth() const noexcept;
/** Returns the number of the day of the week (in this machine's local timezone).
The value returned is in the range 0 to 6 (0 = sunday, 1 = monday, etc).
*/
int getDayOfWeek() const noexcept;
/** Returns the number of the day of the year (in this machine's local timezone).
The value returned is in the range 0 to 365.
*/
int getDayOfYear() const noexcept;
/** Returns the name of the weekday (in this machine's local timezone).
@param threeLetterVersion if true, it'll return a 3-letter abbreviation, e.g. "Tue"; if
false, it'll return the full version, e.g. "Tuesday".
*/
String getWeekdayName(bool threeLetterVersion) const;
/** Returns the number of hours since midnight (in this machine's local timezone).
This is in 24-hour clock format, in the range 0 to 23.
@see getHoursInAmPmFormat, isAfternoon
*/
int getHours() const noexcept;
/** Returns true if the time is in the afternoon (in this machine's local timezone).
@returns true for "PM", false for "AM".
@see getHoursInAmPmFormat, getHours
*/
bool isAfternoon() const noexcept;
/** Returns the hours in 12-hour clock format (in this machine's local timezone).
This will return a value 1 to 12 - use isAfternoon() to find out
whether this is in the afternoon or morning.
@see getHours, isAfternoon
*/
int getHoursInAmPmFormat() const noexcept;
/** Returns the number of minutes, 0 to 59 (in this machine's local timezone). */
int getMinutes() const noexcept;
/** Returns the number of seconds, 0 to 59. */
int getSeconds() const noexcept;
/** Returns the number of milliseconds, 0 to 999.
Unlike toMilliseconds(), this just returns the position within the
current second rather than the total number since the epoch.
@see toMilliseconds
*/
int getMilliseconds() const noexcept;
/** Returns true if the local timezone uses a daylight saving correction. */
bool isDaylightSavingTime() const noexcept;
/** Returns a 3-character string to indicate the local timezone. */
String getTimeZone() const;
/** Returns the local timezone offset from UTC in seconds. */
int getUTCOffsetSeconds() const noexcept;
/** Returns a string to indicate the offset of the local timezone from UTC.
@returns "+XX:XX", "-XX:XX" or "Z"
@param includeDividerCharacters whether to include or omit the ":" divider in the string
*/
String getUTCOffsetString(bool includeDividerCharacters) const;
/** Returns a string version of this date and time, using this machine's local timezone.
For a more powerful way of formatting the date and time, see the formatted() method.
@param includeDate whether to include the date in the string
@param includeTime whether to include the time in the string
@param includeSeconds if the time is being included, this provides an option not to include
the seconds in it
@param use24HourClock if the time is being included, sets whether to use am/pm or 24
hour notation.
@see formatted
*/
String toString(bool includeDate,
bool includeTime,
bool includeSeconds = true,
bool use24HourClock = false) const;
/** Converts this date/time to a string with a user-defined format.
This uses the C strftime() function to format this time as a string. To save you
looking it up, these are the escape codes that strftime uses (other codes might
work on some platforms and not others, but these are the common ones):
- %a is replaced by the locale's abbreviated weekday name.
- %A is replaced by the locale's full weekday name.
- %b is replaced by the locale's abbreviated month name.
- %B is replaced by the locale's full month name.
- %c is replaced by the locale's appropriate date and time representation.
- %d is replaced by the day of the month as a decimal number [01,31].
- %H is replaced by the hour (24-hour clock) as a decimal number [00,23].
- %I is replaced by the hour (12-hour clock) as a decimal number [01,12].
- %j is replaced by the day of the year as a decimal number [001,366].
- %m is replaced by the month as a decimal number [01,12].
- %M is replaced by the minute as a decimal number [00,59].
- %p is replaced by the locale's equivalent of either a.m. or p.m.
- %S is replaced by the second as a decimal number [00,60].
- %U is replaced by the week number of the year (Sunday as the first day of the week) as a decimal number [00,53].
- %w is replaced by the weekday as a decimal number [0,6], with 0 representing Sunday.
- %W is replaced by the week number of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Monday are considered to be in week 0.
- %x is replaced by the locale's appropriate date representation.
- %X is replaced by the locale's appropriate time representation.
- %y is replaced by the year without century as a decimal number [00,99].
- %Y is replaced by the year with century as a decimal number.
- %Z is replaced by the timezone name or abbreviation, or by no bytes if no timezone information exists.
- %% is replaced by %.
@see toString
*/
String formatted(const String& format) const;
/** Returns a fully described string of this date and time in ISO-8601 format
(using the local timezone).
@param includeDividerCharacters whether to include or omit the "-" and ":"
dividers in the string
*/
String toISO8601(bool includeDividerCharacters) const;
/** Parses an ISO-8601 string and returns it as a Time. */
static Time fromISO8601(StringRef iso8601);
/** Adds a RelativeTime to this time. */
Time& operator+= (RelativeTime delta) noexcept;
/** Subtracts a RelativeTime from this time. */
Time& operator-= (RelativeTime delta) noexcept;
/** Tries to set the computer's clock.
@returns true if this succeeds, although depending on the system, the
application might not have sufficient privileges to do this.
*/
bool setSystemTimeToThisTime() const;
/** Returns the name of a day of the week.
@param dayNumber the day, 0 to 6 (0 = sunday, 1 = monday, etc)
@param threeLetterVersion if true, it'll return a 3-letter abbreviation, e.g. "Tue"; if
false, it'll return the full version, e.g. "Tuesday".
*/
static String getWeekdayName(int dayNumber, bool threeLetterVersion);
/** Returns the name of one of the months.
@param monthNumber the month, 0 to 11
@param threeLetterVersion if true, it'll be a 3-letter abbreviation, e.g. "Jan"; if false
it'll return the long form, e.g. "January"
*/
static String getMonthName(int monthNumber, bool threeLetterVersion);
// Static methods for getting system timers directly..
/** Returns the current system time.
Returns the number of milliseconds since midnight Jan 1st 1970 UTC.
Should be accurate to within a few millisecs, depending on platform,
hardware, etc.
*/
static int64 currentTimeMillis() noexcept;
/** Returns the number of millisecs since a fixed event (usually system startup).
This returns a monotonically increasing value which is unaffected by changes to the
system clock. It should be accurate to within a few millisecs, depending on platform,
hardware, etc.
Being a 32-bit return value, it will of course wrap back to 0 after 2^32 seconds of
uptime, so be careful to take that into account. If you need a 64-bit time, you can
use currentTimeMillis() instead.
@see getApproximateMillisecondCounter
*/
static uint32 getMillisecondCounter() noexcept;
/** Returns the number of millisecs since a fixed event (usually system startup).
This has the same function as getMillisecondCounter(), but returns a more accurate
value, using a higher-resolution timer if one is available.
@see getMillisecondCounter
*/
static double getMillisecondCounterHiRes() noexcept;
/** Waits until the getMillisecondCounter() reaches a given value.
This will make the thread sleep as efficiently as it can while it's waiting.
*/
static void waitForMillisecondCounter(uint32 targetTime) noexcept;
/** Less-accurate but faster version of getMillisecondCounter().
This will return the last value that getMillisecondCounter() returned, so doesn't
need to make a system call, but is less accurate - it shouldn't be more than
100ms away from the correct time, though, so is still accurate enough for a
lot of purposes.
@see getMillisecondCounter
*/
static uint32 getApproximateMillisecondCounter() noexcept;
// High-resolution timers..
/** Returns the current high-resolution counter's tick-count.
This is a similar idea to getMillisecondCounter(), but with a higher
resolution.
@see getHighResolutionTicksPerSecond, highResolutionTicksToSeconds,
secondsToHighResolutionTicks
*/
static int64 getHighResolutionTicks() noexcept;
/** Returns the resolution of the high-resolution counter in ticks per second.
@see getHighResolutionTicks, highResolutionTicksToSeconds,
secondsToHighResolutionTicks
*/
static int64 getHighResolutionTicksPerSecond() noexcept;
/** Converts a number of high-resolution ticks into seconds.
@see getHighResolutionTicks, getHighResolutionTicksPerSecond,
secondsToHighResolutionTicks
*/
static double highResolutionTicksToSeconds(int64 ticks) noexcept;
/** Converts a number seconds into high-resolution ticks.
@see getHighResolutionTicks, getHighResolutionTicksPerSecond,
highResolutionTicksToSeconds
*/
static int64 secondsToHighResolutionTicks(double seconds) noexcept;
/** Returns a Time based on the value of the __DATE__ macro when this module was compiled */
static Time getCompilationDate();
private:
int64 millisSinceEpoch = 0;
};
/** Adds a RelativeTime to a Time. */
JUCE_API Time operator+ (Time time, RelativeTime delta) noexcept;
/** Adds a RelativeTime to a Time. */
JUCE_API Time operator+ (RelativeTime delta, Time time) noexcept;
/** Subtracts a RelativeTime from a Time. */
JUCE_API Time operator- (Time time, RelativeTime delta) noexcept;
/** Returns the relative time difference between two times. */
JUCE_API const RelativeTime operator- (Time time1, Time time2) noexcept;
/** Compares two Time objects. */
JUCE_API bool operator== (Time time1, Time time2) noexcept;
/** Compares two Time objects. */
JUCE_API bool operator!= (Time time1, Time time2) noexcept;
/** Compares two Time objects. */
JUCE_API bool operator< (Time time1, Time time2) noexcept;
/** Compares two Time objects. */
JUCE_API bool operator<= (Time time1, Time time2) noexcept;
/** Compares two Time objects. */
JUCE_API bool operator> (Time time1, Time time2) noexcept;
/** Compares two Time objects. */
JUCE_API bool operator>= (Time time1, Time time2) noexcept;
} // namespace juce
/*** End of inlined file: juce_Time.h ***/
/*** Start of inlined file: juce_InputStream.h ***/
namespace juce
{
/** The base class for streams that read data.
Input and output streams are used throughout the library - subclasses can override
some or all of the virtual functions to implement their behaviour.
@see OutputStream, MemoryInputStream, BufferedInputStream, FileInputStream
@tags{Core}
*/
class JUCE_API InputStream
{
public:
/** Destructor. */
virtual ~InputStream() = default;
/** Returns the total number of bytes available for reading in this stream.
Note that this is the number of bytes available from the start of the
stream, not from the current position.
If the size of the stream isn't actually known, this will return -1.
@see getNumBytesRemaining
*/
virtual int64 getTotalLength() = 0;
/** Returns the number of bytes available for reading, or a negative value if
the remaining length is not known.
@see getTotalLength
*/
int64 getNumBytesRemaining();
/** Returns true if the stream has no more data to read. */
virtual bool isExhausted() = 0;
/** Reads some data from the stream into a memory buffer.
This is the only read method that subclasses actually need to implement, as the
InputStream base class implements the other read methods in terms of this one (although
it's often more efficient for subclasses to implement them directly).
@param destBuffer the destination buffer for the data. This must not be null.
@param maxBytesToRead the maximum number of bytes to read - make sure the
memory block passed in is big enough to contain this
many bytes. This value must not be negative.
@returns the actual number of bytes that were read, which may be less than
maxBytesToRead if the stream is exhausted before it gets that far
*/
virtual int read(void* destBuffer, int maxBytesToRead) = 0;
ssize_t read(void* destBuffer, size_t maxBytesToRead);
/** Reads a byte from the stream.
If the stream is exhausted, this will return zero.
@see OutputStream::writeByte
*/
virtual char readByte();
/** Reads a boolean from the stream.
The bool is encoded as a single byte - non-zero for true, 0 for false.
If the stream is exhausted, this will return false.
@see OutputStream::writeBool
*/
virtual bool readBool();
/** Reads two bytes from the stream as a little-endian 16-bit value.
If the next two bytes read are byte1 and byte2, this returns (byte1 | (byte2 << 8)).
If the stream is exhausted partway through reading the bytes, this will return zero.
@see OutputStream::writeShort, readShortBigEndian
*/
virtual short readShort();
/** Reads two bytes from the stream as a little-endian 16-bit value.
If the next two bytes read are byte1 and byte2, this returns (byte2 | (byte1 << 8)).
If the stream is exhausted partway through reading the bytes, this will return zero.
@see OutputStream::writeShortBigEndian, readShort
*/
virtual short readShortBigEndian();
/** Reads four bytes from the stream as a little-endian 32-bit value.
If the next four bytes are byte1 to byte4, this returns
(byte1 | (byte2 << 8) | (byte3 << 16) | (byte4 << 24)).
If the stream is exhausted partway through reading the bytes, this will return zero.
@see OutputStream::writeInt, readIntBigEndian
*/
virtual int readInt();
/** Reads four bytes from the stream as a big-endian 32-bit value.
If the next four bytes are byte1 to byte4, this returns
(byte4 | (byte3 << 8) | (byte2 << 16) | (byte1 << 24)).
If the stream is exhausted partway through reading the bytes, this will return zero.
@see OutputStream::writeIntBigEndian, readInt
*/
virtual int readIntBigEndian();
/** Reads eight bytes from the stream as a little-endian 64-bit value.
If the next eight bytes are byte1 to byte8, this returns
(byte1 | (byte2 << 8) | (byte3 << 16) | (byte4 << 24) | (byte5 << 32) | (byte6 << 40) | (byte7 << 48) | (byte8 << 56)).
If the stream is exhausted partway through reading the bytes, this will return zero.
@see OutputStream::writeInt64, readInt64BigEndian
*/
virtual int64 readInt64();
/** Reads eight bytes from the stream as a big-endian 64-bit value.
If the next eight bytes are byte1 to byte8, this returns
(byte8 | (byte7 << 8) | (byte6 << 16) | (byte5 << 24) | (byte4 << 32) | (byte3 << 40) | (byte2 << 48) | (byte1 << 56)).
If the stream is exhausted partway through reading the bytes, this will return zero.
@see OutputStream::writeInt64BigEndian, readInt64
*/
virtual int64 readInt64BigEndian();
/** Reads four bytes as a 32-bit floating point value.
The raw 32-bit encoding of the float is read from the stream as a little-endian int.
If the stream is exhausted partway through reading the bytes, this will return zero.
@see OutputStream::writeFloat, readDouble
*/
virtual float readFloat();
/** Reads four bytes as a 32-bit floating point value.
The raw 32-bit encoding of the float is read from the stream as a big-endian int.
If the stream is exhausted partway through reading the bytes, this will return zero.
@see OutputStream::writeFloatBigEndian, readDoubleBigEndian
*/
virtual float readFloatBigEndian();
/** Reads eight bytes as a 64-bit floating point value.
The raw 64-bit encoding of the double is read from the stream as a little-endian int64.
If the stream is exhausted partway through reading the bytes, this will return zero.
@see OutputStream::writeDouble, readFloat
*/
virtual double readDouble();
/** Reads eight bytes as a 64-bit floating point value.
The raw 64-bit encoding of the double is read from the stream as a big-endian int64.
If the stream is exhausted partway through reading the bytes, this will return zero.
@see OutputStream::writeDoubleBigEndian, readFloatBigEndian
*/
virtual double readDoubleBigEndian();
/** Reads an encoded 32-bit number from the stream using a space-saving compressed format.
For small values, this is more space-efficient than using readInt() and OutputStream::writeInt()
The format used is: number of significant bytes + up to 4 bytes in little-endian order.
@see OutputStream::writeCompressedInt()
*/
virtual int readCompressedInt();
/** Reads a UTF-8 string from the stream, up to the next linefeed or carriage return.
This will read up to the next "\n" or "\r\n" or end-of-stream.
After this call, the stream's position will be left pointing to the next character
following the line-feed, but the linefeeds aren't included in the string that
is returned.
*/
virtual String readNextLine();
/** Reads a zero-terminated UTF-8 string from the stream.
This will read characters from the stream until it hits a null character
or end-of-stream.
@see OutputStream::writeString, readEntireStreamAsString
*/
virtual String readString();
/** Tries to read the whole stream and turn it into a string.
This will read from the stream's current position until the end-of-stream.
It can read from UTF-8 data, or UTF-16 if it detects suitable header-bytes.
*/
virtual String readEntireStreamAsString();
/** Reads from the stream and appends the data to a MemoryBlock.
@param destBlock the block to append the data onto
@param maxNumBytesToRead if this is a positive value, it sets a limit to the number
of bytes that will be read - if it's negative, data
will be read until the stream is exhausted.
@returns the number of bytes that were added to the memory block
*/
virtual size_t readIntoMemoryBlock(MemoryBlock& destBlock,
ssize_t maxNumBytesToRead = -1);
/** Returns the offset of the next byte that will be read from the stream.
@see setPosition
*/
virtual int64 getPosition() = 0;
/** Tries to move the current read position of the stream.
The position is an absolute number of bytes from the stream's start.
Some streams might not be able to do this, in which case they should do
nothing and return false. Others might be able to manage it by resetting
themselves and skipping to the correct position, although this is
obviously a bit slow.
@returns true if the stream manages to reposition itself correctly
@see getPosition
*/
virtual bool setPosition(int64 newPosition) = 0;
/** Reads and discards a number of bytes from the stream.
Some input streams might implement this more efficiently, but the base
class will just keep reading data until the requisite number of bytes
have been done. For large skips it may be quicker to call setPosition()
with the required position.
*/
virtual void skipNextBytes(int64 numBytesToSkip);
protected:
InputStream() = default;
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(InputStream)
};
} // namespace juce
/*** End of inlined file: juce_InputStream.h ***/
/*** Start of inlined file: juce_OutputStream.h ***/
namespace juce
{
/**
The base class for streams that write data to some kind of destination.
Input and output streams are used throughout the library - subclasses can override
some or all of the virtual functions to implement their behaviour.
@see InputStream, MemoryOutputStream, FileOutputStream
@tags{Core}
*/
class JUCE_API OutputStream
{
protected:
OutputStream();
public:
/** Destructor.
Some subclasses might want to do things like call flush() during their
destructors.
*/
virtual ~OutputStream();
/** If the stream is using a buffer, this will ensure it gets written
out to the destination. */
virtual void flush() = 0;
/** Tries to move the stream's output position.
Not all streams will be able to seek to a new position - this will return
false if it fails to work.
@see getPosition
*/
virtual bool setPosition(int64 newPosition) = 0;
/** Returns the stream's current position.
@see setPosition
*/
virtual int64 getPosition() = 0;
/** Writes a block of data to the stream.
When creating a subclass of OutputStream, this is the only write method
that needs to be overloaded - the base class has methods for writing other
types of data which use this to do the work.
@param dataToWrite the target buffer to receive the data. This must not be null.
@param numberOfBytes the number of bytes to write.
@returns false if the write operation fails for some reason
*/
virtual bool write(const void* dataToWrite,
size_t numberOfBytes) = 0;
/** Writes a single byte to the stream.
@returns false if the write operation fails for some reason
@see InputStream::readByte
*/
virtual bool writeByte(char byte);
/** Writes a boolean to the stream as a single byte.
This is encoded as a binary byte (not as text) with a value of 1 or 0.
@returns false if the write operation fails for some reason
@see InputStream::readBool
*/
virtual bool writeBool(bool boolValue);
/** Writes a 16-bit integer to the stream in a little-endian byte order.
This will write two bytes to the stream: (value & 0xff), then (value >> 8).
@returns false if the write operation fails for some reason
@see InputStream::readShort
*/
virtual bool writeShort(short value);
/** Writes a 16-bit integer to the stream in a big-endian byte order.
This will write two bytes to the stream: (value >> 8), then (value & 0xff).
@returns false if the write operation fails for some reason
@see InputStream::readShortBigEndian
*/
virtual bool writeShortBigEndian(short value);
/** Writes a 32-bit integer to the stream in a little-endian byte order.
@returns false if the write operation fails for some reason
@see InputStream::readInt
*/
virtual bool writeInt(int value);
/** Writes a 32-bit integer to the stream in a big-endian byte order.
@returns false if the write operation fails for some reason
@see InputStream::readIntBigEndian
*/
virtual bool writeIntBigEndian(int value);
/** Writes a 64-bit integer to the stream in a little-endian byte order.
@returns false if the write operation fails for some reason
@see InputStream::readInt64
*/
virtual bool writeInt64(int64 value);
/** Writes a 64-bit integer to the stream in a big-endian byte order.
@returns false if the write operation fails for some reason
@see InputStream::readInt64BigEndian
*/
virtual bool writeInt64BigEndian(int64 value);
/** Writes a 32-bit floating point value to the stream in a binary format.
The binary 32-bit encoding of the float is written as a little-endian int.
@returns false if the write operation fails for some reason
@see InputStream::readFloat
*/
virtual bool writeFloat(float value);
/** Writes a 32-bit floating point value to the stream in a binary format.
The binary 32-bit encoding of the float is written as a big-endian int.
@returns false if the write operation fails for some reason
@see InputStream::readFloatBigEndian
*/
virtual bool writeFloatBigEndian(float value);
/** Writes a 64-bit floating point value to the stream in a binary format.
The eight raw bytes of the double value are written out as a little-endian 64-bit int.
@returns false if the write operation fails for some reason
@see InputStream::readDouble
*/
virtual bool writeDouble(double value);
/** Writes a 64-bit floating point value to the stream in a binary format.
The eight raw bytes of the double value are written out as a big-endian 64-bit int.
@see InputStream::readDoubleBigEndian
@returns false if the write operation fails for some reason
*/
virtual bool writeDoubleBigEndian(double value);
/** Writes a byte to the output stream a given number of times.
@returns false if the write operation fails for some reason
*/
virtual bool writeRepeatedByte(uint8 byte, size_t numTimesToRepeat);
/** Writes a condensed binary encoding of a 32-bit integer.
If you're storing a lot of integers which are unlikely to have very large values,
this can save a lot of space, because values under 0xff will only take up 2 bytes,
under 0xffff only 3 bytes, etc.
The format used is: number of significant bytes + up to 4 bytes in little-endian order.
@returns false if the write operation fails for some reason
@see InputStream::readCompressedInt
*/
virtual bool writeCompressedInt(int value);
/** Stores a string in the stream in a binary format.
This isn't the method to use if you're trying to append text to the end of a
text-file! It's intended for storing a string so that it can be retrieved later
by InputStream::readString().
It writes the string to the stream as UTF8, including the null termination character.
For appending text to a file, instead use writeText, or operator<<
@returns false if the write operation fails for some reason
@see InputStream::readString, writeText, operator<<
*/
virtual bool writeString(const String& text);
/** Writes a string of text to the stream.
It can either write the text as UTF-8 or UTF-16, and can also add the UTF-16 byte-order-mark
bytes (0xff, 0xfe) to indicate the endianness (these should only be used at the start
of a file).
If lineEndings is nullptr, then line endings in the text won't be modified. If you
pass "\\n" or "\\r\\n" then this function will replace any existing line feeds.
@returns false if the write operation fails for some reason
*/
virtual bool writeText(const String& text,
bool asUTF16,
bool writeUTF16ByteOrderMark,
const char* lineEndings);
/** Reads data from an input stream and writes it to this stream.
@param source the stream to read from
@param maxNumBytesToWrite the number of bytes to read from the stream (if this is
less than zero, it will keep reading until the input
is exhausted)
@returns the number of bytes written
*/
virtual int64 writeFromInputStream(InputStream& source, int64 maxNumBytesToWrite);
/** Sets the string to write to the stream when a new line is written.
By default this will be set the value of NewLine::getDefault().
*/
void setNewLineString(const String& newLineString);
/** Returns the current new-line string that was set by setNewLineString(). */
const String& getNewLineString() const noexcept { return newLineString; }
private:
String newLineString;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(OutputStream)
};
/** Writes a number to a stream as 8-bit characters in the default system encoding. */
JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, int number);
/** Writes a number to a stream as 8-bit characters in the default system encoding. */
JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, int64 number);
/** Writes a number to a stream as 8-bit characters in the default system encoding. */
JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, double number);
/** Writes a character to a stream. */
JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, char character);
/** Writes a null-terminated text string to a stream. */
JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const char* text);
/** Writes a block of data from a MemoryBlock to a stream. */
JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const MemoryBlock& data);
/** Writes the contents of a file to a stream. */
JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const File& fileToRead);
/** Writes the complete contents of an input stream to an output stream. */
JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, InputStream& streamToRead);
/** Writes a new-line to a stream.
You can use the predefined symbol 'newLine' to invoke this, e.g.
@code
myOutputStream << "Hello World" << newLine << newLine;
@endcode
@see OutputStream::setNewLineString
*/
JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const NewLine&);
} // namespace juce
/*** End of inlined file: juce_OutputStream.h ***/
/*** Start of inlined file: juce_BufferedInputStream.h ***/
namespace juce
{
/** Wraps another input stream, and reads from it using an intermediate buffer
If you're using an input stream such as a file input stream, and making lots of
small read accesses to it, it's probably sensible to wrap it in one of these,
so that the source stream gets accessed in larger chunk sizes, meaning less
work for the underlying stream.
@tags{Core}
*/
class JUCE_API BufferedInputStream : public InputStream
{
public:
/** Creates a BufferedInputStream from an input source.
@param sourceStream the source stream to read from
@param bufferSize the size of reservoir to use to buffer the source
@param deleteSourceWhenDestroyed whether the sourceStream that is passed in should be
deleted by this object when it is itself deleted.
*/
BufferedInputStream(InputStream* sourceStream,
int bufferSize,
bool deleteSourceWhenDestroyed);
/** Creates a BufferedInputStream from an input source.
@param sourceStream the source stream to read from - the source stream must not
be deleted until this object has been destroyed.
@param bufferSize the size of reservoir to use to buffer the source
*/
BufferedInputStream(InputStream& sourceStream, int bufferSize);
/** Destructor.
This may also delete the source stream, if that option was chosen when the
buffered stream was created.
*/
~BufferedInputStream() override;
/** Returns the next byte that would be read by a call to readByte() */
char peekByte();
int64 getTotalLength() override;
int64 getPosition() override;
bool setPosition(int64 newPosition) override;
int read(void* destBuffer, int maxBytesToRead) override;
String readString() override;
bool isExhausted() override;
private:
OptionalScopedPointer<InputStream> source;
int bufferSize;
int64 position, lastReadPos = 0, bufferStart, bufferOverlap = 128;
HeapBlock<char> buffer;
bool ensureBuffered();
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(BufferedInputStream)
};
} // namespace juce
/*** End of inlined file: juce_BufferedInputStream.h ***/
/*** Start of inlined file: juce_MemoryInputStream.h ***/
namespace juce
{
/**
Allows a block of data to be accessed as a stream.
This can either be used to refer to a shared block of memory, or can make its
own internal copy of the data when the MemoryInputStream is created.
@tags{Core}
*/
class JUCE_API MemoryInputStream : public InputStream
{
public:
/** Creates a MemoryInputStream.
@param sourceData the block of data to use as the stream's source
@param sourceDataSize the number of bytes in the source data block
@param keepInternalCopyOfData if false, the stream will just keep a pointer to
the source data, so this data shouldn't be changed
for the lifetime of the stream; if this parameter is
true, the stream will make its own copy of the
data and use that.
*/
MemoryInputStream(const void* sourceData,
size_t sourceDataSize,
bool keepInternalCopyOfData);
/** Creates a MemoryInputStream.
@param data a block of data to use as the stream's source
@param keepInternalCopyOfData if false, the stream will just keep a reference to
the source data, so this data shouldn't be changed
for the lifetime of the stream; if this parameter is
true, the stream will make its own copy of the
data and use that.
*/
MemoryInputStream(const MemoryBlock& data,
bool keepInternalCopyOfData);
/** Creates a stream by moving from a MemoryBlock. */
MemoryInputStream(MemoryBlock&& blockToTake);
/** Destructor. */
~MemoryInputStream() override;
/** Returns a pointer to the source data block from which this stream is reading. */
const void* getData() const noexcept { return data; }
/** Returns the number of bytes of source data in the block from which this stream is reading. */
size_t getDataSize() const noexcept { return dataSize; }
int64 getPosition() override;
bool setPosition(int64) override;
int64 getTotalLength() override;
bool isExhausted() override;
int read(void* destBuffer, int maxBytesToRead) override;
void skipNextBytes(int64 numBytesToSkip) override;
private:
const void* data;
size_t dataSize, position = 0;
MemoryBlock internalCopy;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MemoryInputStream)
};
} // namespace juce
/*** End of inlined file: juce_MemoryInputStream.h ***/
/*** Start of inlined file: juce_MemoryOutputStream.h ***/
namespace juce
{
/**
Writes data to an internal memory buffer, which grows as required.
The data that was written into the stream can then be accessed later as
a contiguous block of memory.
@tags{Core}
*/
class JUCE_API MemoryOutputStream : public OutputStream
{
public:
/** Creates an empty memory stream, ready to be written into.
@param initialSize the initial amount of capacity to allocate for writing into
*/
MemoryOutputStream(size_t initialSize = 256);
/** Creates a memory stream for writing into into a pre-existing MemoryBlock object.
Note that the destination block will always be larger than the amount of data
that has been written to the stream, because the MemoryOutputStream keeps some
spare capacity at its end. To trim the block's size down to fit the actual
data, call flush(), or delete the MemoryOutputStream.
@param memoryBlockToWriteTo the block into which new data will be written.
@param appendToExistingBlockContent if this is true, the contents of the block will be
kept, and new data will be appended to it. If false,
the block will be cleared before use
*/
MemoryOutputStream(MemoryBlock& memoryBlockToWriteTo,
bool appendToExistingBlockContent);
/** Creates a MemoryOutputStream that will write into a user-supplied, fixed-size
block of memory.
When using this mode, the stream will write directly into this memory area until
it's full, at which point write operations will fail.
*/
MemoryOutputStream(void* destBuffer, size_t destBufferSize);
/** Destructor.
This will free any data that was written to it.
*/
~MemoryOutputStream() override;
/** Returns a pointer to the data that has been written to the stream.
@see getDataSize
*/
const void* getData() const noexcept;
/** Returns the number of bytes of data that have been written to the stream.
@see getData
*/
size_t getDataSize() const noexcept { return size; }
/** Resets the stream, clearing any data that has been written to it so far. */
void reset() noexcept;
/** Increases the internal storage capacity to be able to contain at least the specified
amount of data without needing to be resized.
*/
void preallocate(size_t bytesToPreallocate);
/** Appends the utf-8 bytes for a unicode character */
bool appendUTF8Char(juce_wchar character);
/** Returns a String created from the (UTF8) data that has been written to the stream. */
String toUTF8() const;
/** Attempts to detect the encoding of the data and convert it to a string.
@see String::createStringFromData
*/
String toString() const;
/** Returns a copy of the stream's data as a memory block. */
MemoryBlock getMemoryBlock() const;
/** If the stream is writing to a user-supplied MemoryBlock, this will trim any excess
capacity off the block, so that its length matches the amount of actual data that
has been written so far.
*/
void flush() override;
bool write(const void*, size_t) override;
int64 getPosition() override { return (int64)position; }
bool setPosition(int64) override;
int64 writeFromInputStream(InputStream&, int64 maxNumBytesToWrite) override;
bool writeRepeatedByte(uint8 byte, size_t numTimesToRepeat) override;
private:
MemoryBlock* const blockToUse = nullptr;
MemoryBlock internalBlock;
void* externalData = nullptr;
size_t position = 0, size = 0, availableSize = 0;
void trimExternalBlockSize();
char* prepareToWrite(size_t);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MemoryOutputStream)
};
/** Copies all the data that has been written to a MemoryOutputStream into another stream. */
OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const MemoryOutputStream& streamToRead);
} // namespace juce
/*** End of inlined file: juce_MemoryOutputStream.h ***/
/*** Start of inlined file: juce_SubregionStream.h ***/
namespace juce
{
/** Wraps another input stream, and reads from a specific part of it.
This lets you take a subsection of a stream and present it as an entire
stream in its own right.
@tags{Core}
*/
class JUCE_API SubregionStream : public InputStream
{
public:
/** Creates a SubregionStream from an input source.
@param sourceStream the source stream to read from
@param startPositionInSourceStream this is the position in the source stream that
corresponds to position 0 in this stream
@param lengthOfSourceStream this specifies the maximum number of bytes
from the source stream that will be passed through
by this stream. When the position of this stream
exceeds lengthOfSourceStream, it will cause an end-of-stream.
If the length passed in here is greater than the length
of the source stream (as returned by getTotalLength()),
then the smaller value will be used.
Passing a negative value for this parameter means it
will keep reading until the source's end-of-stream.
@param deleteSourceWhenDestroyed whether the sourceStream that is passed in should be
deleted by this object when it is itself deleted.
*/
SubregionStream(InputStream* sourceStream,
int64 startPositionInSourceStream,
int64 lengthOfSourceStream,
bool deleteSourceWhenDestroyed);
/** Destructor.
This may also delete the source stream, if that option was chosen when the
buffered stream was created.
*/
~SubregionStream() override;
int64 getTotalLength() override;
int64 getPosition() override;
bool setPosition(int64 newPosition) override;
int read(void* destBuffer, int maxBytesToRead) override;
bool isExhausted() override;
private:
OptionalScopedPointer<InputStream> source;
const int64 startPositionInSourceStream, lengthOfSourceStream;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SubregionStream)
};
} // namespace juce
/*** End of inlined file: juce_SubregionStream.h ***/
/*** Start of inlined file: juce_InputSource.h ***/
namespace juce
{
/**
A lightweight object that can create a stream to read some kind of resource.
This may be used to refer to a file, or some other kind of source, allowing a
caller to create an input stream that can read from it when required.
@see FileInputSource
@tags{Core}
*/
class JUCE_API InputSource
{
public:
InputSource() = default;
/** Destructor. */
virtual ~InputSource() = default;
/** Returns a new InputStream to read this item.
@returns an inputstream that the caller will delete, or nullptr if
the filename isn't found.
*/
virtual InputStream* createInputStream() = 0;
/** Returns a new InputStream to read an item, relative.
@param relatedItemPath the relative pathname of the resource that is required
@returns an inputstream that the caller will delete, or nullptr if
the item isn't found.
*/
virtual InputStream* createInputStreamFor(const String& relatedItemPath) = 0;
/** Returns a hash code that uniquely represents this item.
*/
virtual int64 hashCode() const = 0;
private:
JUCE_LEAK_DETECTOR(InputSource)
};
} // namespace juce
/*** End of inlined file: juce_InputSource.h ***/
/*** Start of inlined file: juce_File.h ***/
#if ! DOXYGEN && (JUCE_MAC || JUCE_IOS)
#if __LP64__
using OSType = unsigned int;
#else
using OSType = unsigned long;
#endif
#endif
namespace juce
{
/**
Represents a local file or directory.
This class encapsulates the absolute pathname of a file or directory, and
has methods for finding out about the file and changing its properties.
To read or write to the file, there are methods for returning an input or
output stream.
@see FileInputStream, FileOutputStream
@tags{Core}
*/
class JUCE_API File final
{
public:
/** Creates an (invalid) file object.
The file is initially set to an empty path, so getFullPathName() will return
an empty string.
You can use its operator= method to point it at a proper file.
*/
File() = default;
/** Creates a file from an absolute path.
If the path supplied is a relative path, it is taken to be relative
to the current working directory (see File::getCurrentWorkingDirectory()),
but this isn't a recommended way of creating a file, because you
never know what the CWD is going to be.
On the Mac/Linux, the path can include "~" notation for referring to
user home directories.
*/
File(const String& absolutePath);
/** Creates a copy of another file object. */
File(const File&);
/** Destructor. */
~File() = default;
/** Sets the file based on an absolute pathname.
If the path supplied is a relative path, it is taken to be relative
to the current working directory (see File::getCurrentWorkingDirectory()),
but this isn't a recommended way of creating a file, because you
never know what the CWD is going to be.
On the Mac/Linux, the path can include "~" notation for referring to
user home directories.
*/
File& operator= (const String& newAbsolutePath);
/** Copies from another file object. */
File& operator= (const File& otherFile);
/** Move constructor */
File(File&&) noexcept;
/** Move assignment operator */
File& operator= (File&&) noexcept;
/** Checks whether the file actually exists.
@returns true if the file exists, either as a file or a directory.
@see existsAsFile, isDirectory
*/
bool exists() const;
/** Checks whether the file exists and is a file rather than a directory.
@returns true only if this is a real file, false if it's a directory
or doesn't exist
@see exists, isDirectory
*/
bool existsAsFile() const;
/** Checks whether the file is a directory that exists.
@returns true only if the file is a directory which actually exists, so
false if it's a file or doesn't exist at all
@see exists, existsAsFile
*/
bool isDirectory() const;
/** Checks whether the path of this file represents the root of a file system,
irrespective of its existence.
This will return true for "C:", "D:", etc on Windows and "/" on other
platforms.
*/
bool isRoot() const;
/** Returns the size of the file in bytes.
@returns the number of bytes in the file, or 0 if it doesn't exist.
*/
int64 getSize() const;
/** Utility function to convert a file size in bytes to a neat string description.
So for example 100 would return "100 bytes", 2000 would return "2 KB",
2000000 would produce "2 MB", etc.
*/
static String descriptionOfSizeInBytes(int64 bytes);
/** Returns the complete, absolute path of this file.
This includes the filename and all its parent folders. On Windows it'll
also include the drive letter prefix; on Mac or Linux it'll be a complete
path starting from the root folder.
If you just want the file's name, you should use getFileName() or
getFileNameWithoutExtension().
@see getFileName, getRelativePathFrom
*/
const String& getFullPathName() const noexcept { return fullPath; }
/** Returns the last section of the pathname.
Returns just the final part of the path - e.g. if the whole path
is "/moose/fish/foo.txt" this will return "foo.txt".
For a directory, it returns the final part of the path - e.g. for the
directory "/moose/fish" it'll return "fish".
If the filename begins with a dot, it'll return the whole filename, e.g. for
"/moose/.fish", it'll return ".fish"
@see getFullPathName, getFileNameWithoutExtension
*/
String getFileName() const;
/** Creates a relative path that refers to a file relatively to a given directory.
e.g. File ("/moose/foo.txt").getRelativePathFrom (File ("/moose/fish/haddock"))
would return "../../foo.txt".
If it's not possible to navigate from one file to the other, an absolute
path is returned. If the paths are invalid, an empty string may also be
returned.
@param directoryToBeRelativeTo the directory which the resultant string will
be relative to. If this is actually a file rather than
a directory, its parent directory will be used instead.
If it doesn't exist, it's assumed to be a directory.
@see getChildFile, isAbsolutePath
*/
String getRelativePathFrom(const File& directoryToBeRelativeTo) const;
/** Returns the file's extension.
Returns the file extension of this file, also including the dot.
e.g. "/moose/fish/foo.txt" would return ".txt"
@see hasFileExtension, withFileExtension, getFileNameWithoutExtension
*/
String getFileExtension() const;
/** Checks whether the file has a given extension.
@param extensionToTest the extension to look for - it doesn't matter whether or
not this string has a dot at the start, so ".wav" and "wav"
will have the same effect. To compare with multiple extensions, this
parameter can contain multiple strings, separated by semi-colons -
so, for example: hasFileExtension (".jpeg;png;gif") would return
true if the file has any of those three extensions.
@see getFileExtension, withFileExtension, getFileNameWithoutExtension
*/
bool hasFileExtension(StringRef extensionToTest) const;
/** Returns a version of this file with a different file extension.
e.g. File ("/moose/fish/foo.txt").withFileExtension ("html") returns "/moose/fish/foo.html"
@param newExtension the new extension, either with or without a dot at the start (this
doesn't make any difference). To get remove a file's extension altogether,
pass an empty string into this function.
@see getFileName, getFileExtension, hasFileExtension, getFileNameWithoutExtension
*/
File withFileExtension(StringRef newExtension) const;
/** Returns the last part of the filename, without its file extension.
e.g. for "/moose/fish/foo.txt" this will return "foo".
@see getFileName, getFileExtension, hasFileExtension, withFileExtension
*/
String getFileNameWithoutExtension() const;
/** Returns a 32-bit hash-code that identifies this file.
This is based on the filename. Obviously it's possible, although unlikely, that
two files will have the same hash-code.
*/
int hashCode() const;
/** Returns a 64-bit hash-code that identifies this file.
This is based on the filename. Obviously it's possible, although unlikely, that
two files will have the same hash-code.
*/
int64 hashCode64() const;
/** Returns a file that represents a relative (or absolute) sub-path of the current one.
This will find a child file or directory of the current object.
e.g.
File ("/moose/fish").getChildFile ("foo.txt") will produce "/moose/fish/foo.txt".
File ("/moose/fish").getChildFile ("haddock/foo.txt") will produce "/moose/fish/haddock/foo.txt".
File ("/moose/fish").getChildFile ("../foo.txt") will produce "/moose/foo.txt".
If the string is actually an absolute path, it will be treated as such, e.g.
File ("/moose/fish").getChildFile ("/foo.txt") will produce "/foo.txt"
@see getSiblingFile, getParentDirectory, getRelativePathFrom, isAChildOf
*/
File getChildFile(StringRef relativeOrAbsolutePath) const;
/** Returns a file which is in the same directory as this one.
This is equivalent to getParentDirectory().getChildFile (name).
@see getChildFile, getParentDirectory
*/
File getSiblingFile(StringRef siblingFileName) const;
/** Returns the directory that contains this file or directory.
e.g. for "/moose/fish/foo.txt" this will return "/moose/fish".
If you are already at the root directory ("/" or "C:") then this method will
return the root directory.
*/
File getParentDirectory() const;
/** Checks whether a file is somewhere inside a directory.
Returns true if this file is somewhere inside a subdirectory of the directory
that is passed in. Neither file actually has to exist, because the function
just checks the paths for similarities.
e.g. File ("/moose/fish/foo.txt").isAChildOf ("/moose") is true.
File ("/moose/fish/foo.txt").isAChildOf ("/moose/fish") is also true.
*/
bool isAChildOf(const File& potentialParentDirectory) const;
/** Chooses a filename relative to this one that doesn't already exist.
If this file is a directory, this will return a child file of this
directory that doesn't exist, by adding numbers to a prefix and suffix until
it finds one that isn't already there.
If the prefix + the suffix doesn't exist, it won't bother adding a number.
e.g. File ("/moose/fish").getNonexistentChildFile ("foo", ".txt", true) might
return "/moose/fish/foo(2).txt" if there's already a file called "foo.txt".
@param prefix the string to use for the filename before the number
@param suffix the string to add to the filename after the number
@param putNumbersInBrackets if true, this will create filenames in the
format "prefix(number)suffix", if false, it will leave the
brackets out.
*/
File getNonexistentChildFile(const String& prefix,
const String& suffix,
bool putNumbersInBrackets = true) const;
/** Chooses a filename for a sibling file to this one that doesn't already exist.
If this file doesn't exist, this will just return itself, otherwise it
will return an appropriate sibling that doesn't exist, e.g. if a file
"/moose/fish/foo.txt" exists, this might return "/moose/fish/foo(2).txt".
@param putNumbersInBrackets whether to add brackets around the numbers that
get appended to the new filename.
*/
File getNonexistentSibling(bool putNumbersInBrackets = true) const;
/** Compares the pathnames for two files. */
bool operator== (const File&) const;
/** Compares the pathnames for two files. */
bool operator!= (const File&) const;
/** Compares the pathnames for two files. */
bool operator< (const File&) const;
/** Compares the pathnames for two files. */
bool operator> (const File&) const;
/** Checks whether a file can be created or written to.
@returns true if it's possible to create and write to this file. If the file
doesn't already exist, this will check its parent directory to
see if writing is allowed.
@see setReadOnly
*/
bool hasWriteAccess() const;
/** Changes the write-permission of a file or directory.
@param shouldBeReadOnly whether to add or remove write-permission
@param applyRecursively if the file is a directory and this is true, it will
recurse through all the subfolders changing the permissions
of all files
@returns true if it manages to change the file's permissions.
@see hasWriteAccess
*/
bool setReadOnly(bool shouldBeReadOnly,
bool applyRecursively = false) const;
/** Changes the execute-permissions of a file.
@param shouldBeExecutable whether to add or remove execute-permission
@returns true if it manages to change the file's permissions.
*/
bool setExecutePermission(bool shouldBeExecutable) const;
/** Returns true if this file is a hidden or system file.
The criteria for deciding whether a file is hidden are platform-dependent.
*/
bool isHidden() const;
/** Returns a unique identifier for the file, if one is available.
Depending on the OS and file-system, this may be a unix inode number or
a win32 file identifier, or 0 if it fails to find one. The number will
be unique on the filesystem, but not globally.
*/
uint64 getFileIdentifier() const;
/** Returns the last modification time of this file.
@returns the time, or an invalid time if the file doesn't exist.
@see setLastModificationTime, getLastAccessTime, getCreationTime
*/
Time getLastModificationTime() const;
/** Returns the last time this file was accessed.
@returns the time, or an invalid time if the file doesn't exist.
@see setLastAccessTime, getLastModificationTime, getCreationTime
*/
Time getLastAccessTime() const;
/** Returns the time that this file was created.
@returns the time, or an invalid time if the file doesn't exist.
@see getLastModificationTime, getLastAccessTime
*/
Time getCreationTime() const;
/** Changes the modification time for this file.
@param newTime the time to apply to the file
@returns true if it manages to change the file's time.
@see getLastModificationTime, setLastAccessTime, setCreationTime
*/
bool setLastModificationTime(Time newTime) const;
/** Changes the last-access time for this file.
@param newTime the time to apply to the file
@returns true if it manages to change the file's time.
@see getLastAccessTime, setLastModificationTime, setCreationTime
*/
bool setLastAccessTime(Time newTime) const;
/** Changes the creation date for this file.
@param newTime the time to apply to the file
@returns true if it manages to change the file's time.
@see getCreationTime, setLastModificationTime, setLastAccessTime
*/
bool setCreationTime(Time newTime) const;
/** If possible, this will try to create a version string for the given file.
The OS may be able to look at the file and give a version for it - e.g. with
executables, bundles, dlls, etc. If no version is available, this will
return an empty string.
*/
String getVersion() const;
/** Creates an empty file if it doesn't already exist.
If the file that this object refers to doesn't exist, this will create a file
of zero size.
If it already exists or is a directory, this method will do nothing.
If the parent directories of the File do not exist then this method will
recursively create the parent directories.
@returns a result to indicate whether the file was created successfully,
or an error message if it failed.
@see createDirectory
*/
Result create() const;
/** Creates a new directory for this filename.
This will try to create the file as a directory, and will also create
any parent directories it needs in order to complete the operation.
@returns a result to indicate whether the directory was created successfully, or
an error message if it failed.
@see create
*/
Result createDirectory() const;
/** Deletes a file.
If this file is actually a directory, it may not be deleted correctly if it
contains files. See deleteRecursively() as a better way of deleting directories.
If this file is a symlink, then the symlink will be deleted and not the target
of the symlink.
@returns true if the file has been successfully deleted (or if it didn't exist to
begin with).
@see deleteRecursively
*/
bool deleteFile() const;
/** Deletes a file or directory and all its subdirectories.
If this file is a directory, this will try to delete it and all its subfolders. If
it's just a file, it will just try to delete the file.
@param followSymlinks If true, then any symlink pointing to a directory will also
recursively delete the contents of that directory
@returns true if the file and all its subfolders have been successfully
deleted (or if it didn't exist to begin with).
@see deleteFile
*/
bool deleteRecursively(bool followSymlinks = false) const;
/** Moves this file or folder to the trash.
@returns true if the operation succeeded. It could fail if the trash is full, or
if the file is write-protected, so you should check the return value
and act appropriately.
*/
bool moveToTrash() const;
/** Moves or renames a file.
Tries to move a file to a different location.
If the target file already exists, this will attempt to delete it first, and
will fail if this can't be done.
Note that the destination file isn't the directory to put it in, it's the actual
filename that you want the new file to have.
Also note that on some OSes (e.g. Windows), moving files between different
volumes may not be possible.
@returns true if the operation succeeds
*/
bool moveFileTo(const File& targetLocation) const;
/** Copies a file.
Tries to copy a file to a different location.
If the target file already exists, this will attempt to delete it first, and
will fail if this can't be done.
@returns true if the operation succeeds
*/
bool copyFileTo(const File& targetLocation) const;
/** Replaces a file.
Replace the file in the given location, assuming the replaced files identity.
Depending on the file system this will preserve file attributes such as
creation date, short file name, etc.
If replacement succeeds the original file is deleted.
@returns true if the operation succeeds
*/
bool replaceFileIn(const File& targetLocation) const;
/** Copies a directory.
Tries to copy an entire directory, recursively.
If this file isn't a directory or if any target files can't be created, this
will return false.
@param newDirectory the directory that this one should be copied to. Note that this
is the name of the actual directory to create, not the directory
into which the new one should be placed, so there must be enough
write privileges to create it if it doesn't exist. Any files inside
it will be overwritten by similarly named ones that are copied.
*/
bool copyDirectoryTo(const File& newDirectory) const;
/** Used in file searching, to specify whether to return files, directories, or both.
*/
enum TypesOfFileToFind
{
findDirectories = 1, /**< Use this flag to indicate that you want to find directories. */
findFiles = 2, /**< Use this flag to indicate that you want to find files. */
findFilesAndDirectories = 3, /**< Use this flag to indicate that you want to find both files and directories. */
ignoreHiddenFiles = 4 /**< Add this flag to avoid returning any hidden files in the results. */
};
/** Searches this directory for files matching a wildcard pattern.
Assuming that this file is a directory, this method will search it
for either files or subdirectories whose names match a filename pattern.
Note that the order in which files are returned is completely undefined!
@param whatToLookFor a value from the TypesOfFileToFind enum, specifying whether to
return files, directories, or both. If the ignoreHiddenFiles flag
is also added to this value, hidden files won't be returned
@param searchRecursively if true, all subdirectories will be recursed into to do
an exhaustive search
@param wildCardPattern the filename pattern to search for, e.g. "*.txt"
@returns the set of files that were found
@see getNumberOfChildFiles, RangedDirectoryIterator
*/
Array<File> findChildFiles(int whatToLookFor,
bool searchRecursively,
const String& wildCardPattern = "*") const;
/** Searches inside a directory for files matching a wildcard pattern.
Note that there's a newer, better version of this method which returns the results
array, and in almost all cases, you should use that one instead! This one is kept around
mainly for legacy code to use.
*/
int findChildFiles(Array<File>& results, int whatToLookFor,
bool searchRecursively, const String& wildCardPattern = "*") const;
/** Searches inside a directory and counts how many files match a wildcard pattern.
Assuming that this file is a directory, this method will search it
for either files or subdirectories whose names match a filename pattern,
and will return the number of matches found.
This isn't a recursive call, and will only search this directory, not
its children.
@param whatToLookFor a value from the TypesOfFileToFind enum, specifying whether to
count files, directories, or both. If the ignoreHiddenFiles flag
is also added to this value, hidden files won't be counted
@param wildCardPattern the filename pattern to search for, e.g. "*.txt"
@returns the number of matches found
@see findChildFiles, RangedDirectoryIterator
*/
int getNumberOfChildFiles(int whatToLookFor,
const String& wildCardPattern = "*") const;
/** Returns true if this file is a directory that contains one or more subdirectories.
@see isDirectory, findChildFiles
*/
bool containsSubDirectories() const;
/** Creates a stream to read from this file.
Note that this is an old method, and actually it's usually best to avoid it and
instead use an RAII pattern with an FileInputStream directly, e.g.
@code
FileInputStream input (fileToOpen);
if (input.openedOk())
{
input.read (etc...
}
@endcode
@returns a stream that will read from this file (initially positioned at the
start of the file), or nullptr if the file can't be opened for some reason
@see createOutputStream, loadFileAsData
*/
std::unique_ptr<FileInputStream> createInputStream() const;
/** Creates a stream to write to this file.
Note that this is an old method, and actually it's usually best to avoid it and
instead use an RAII pattern with an FileOutputStream directly, e.g.
@code
FileOutputStream output (fileToOpen);
if (output.openedOk())
{
output.read etc...
}
@endcode
If the file exists, the stream that is returned will be positioned ready for
writing at the end of the file. If you want to write to the start of the file,
replacing the existing content, then you can do the following:
@code
FileOutputStream output (fileToOverwrite);
if (output.openedOk())
{
output.setPosition (0);
output.truncate();
...
}
@endcode
@returns a stream that will write to this file (initially positioned at the
end of the file), or nullptr if the file can't be opened for some reason
@see createInputStream, appendData, appendText
*/
std::unique_ptr<FileOutputStream> createOutputStream(size_t bufferSize = 0x8000) const;
/** Loads a file's contents into memory as a block of binary data.
Of course, trying to load a very large file into memory will blow up, so
it's better to check first.
@param result the data block to which the file's contents should be appended - note
that if the memory block might already contain some data, you
might want to clear it first
@returns true if the file could all be read into memory
*/
bool loadFileAsData(MemoryBlock& result) const;
/** Reads a file into memory as a string.
Attempts to load the entire file as a zero-terminated string.
This makes use of InputStream::readEntireStreamAsString, which can
read either UTF-16 or UTF-8 file formats.
*/
String loadFileAsString() const;
/** Reads the contents of this file as text and splits it into lines, which are
appended to the given StringArray.
*/
void readLines(StringArray& destLines) const;
/** Appends a block of binary data to the end of the file.
This will try to write the given buffer to the end of the file.
@returns false if it can't write to the file for some reason
*/
bool appendData(const void* dataToAppend,
size_t numberOfBytes) const;
/** Replaces this file's contents with a given block of data.
This will delete the file and replace it with the given data.
A nice feature of this method is that it's safe - instead of deleting
the file first and then re-writing it, it creates a new temporary file,
writes the data to that, and then moves the new file to replace the existing
file. This means that if the power gets pulled out or something crashes,
you're a lot less likely to end up with a corrupted or unfinished file..
Returns true if the operation succeeds, or false if it fails.
@see appendText
*/
bool replaceWithData(const void* dataToWrite,
size_t numberOfBytes) const;
/** Appends a string to the end of the file.
This will try to append a text string to the file, as either 16-bit unicode
or 8-bit characters in the default system encoding.
It can also write the 'ff fe' unicode header bytes before the text to indicate
the endianness of the file.
If lineEndings is nullptr, then line endings in the text won't be modified. If you
pass "\\n" or "\\r\\n" then this function will replace any existing line feeds.
@see replaceWithText
*/
bool appendText(const String& textToAppend,
bool asUnicode = false,
bool writeUnicodeHeaderBytes = false,
const char* lineEndings = "\r\n") const;
/** Replaces this file's contents with a given text string.
This will delete the file and replace it with the given text.
A nice feature of this method is that it's safe - instead of deleting
the file first and then re-writing it, it creates a new temporary file,
writes the text to that, and then moves the new file to replace the existing
file. This means that if the power gets pulled out or something crashes,
you're a lot less likely to end up with an empty file..
For an explanation of the parameters here, see the appendText() method.
Returns true if the operation succeeds, or false if it fails.
@see appendText
*/
bool replaceWithText(const String& textToWrite,
bool asUnicode = false,
bool writeUnicodeHeaderBytes = false,
const char* lineEndings = "\r\n") const;
/** Attempts to scan the contents of this file and compare it to another file, returning
true if this is possible and they match byte-for-byte.
*/
bool hasIdenticalContentTo(const File& other) const;
/** Creates a set of files to represent each file root.
e.g. on Windows this will create files for "c:\", "d:\" etc according
to which ones are available. On the Mac/Linux, this will probably
just add a single entry for "/".
*/
static void findFileSystemRoots(Array<File>& results);
/** Finds the name of the drive on which this file lives.
@returns the volume label of the drive, or an empty string if this isn't possible
*/
String getVolumeLabel() const;
/** Returns the serial number of the volume on which this file lives.
@returns the serial number, or zero if there's a problem doing this
*/
int getVolumeSerialNumber() const;
/** Returns the number of bytes free on the drive that this file lives on.
@returns the number of bytes free, or 0 if there's a problem finding this out
@see getVolumeTotalSize
*/
int64 getBytesFreeOnVolume() const;
/** Returns the total size of the drive that contains this file.
@returns the total number of bytes that the volume can hold
@see getBytesFreeOnVolume
*/
int64 getVolumeTotalSize() const;
/** Returns true if this file is on a CD or DVD drive. */
bool isOnCDRomDrive() const;
/** Returns true if this file is on a hard disk.
This will fail if it's a network drive, but will still be true for
removable hard-disks.
*/
bool isOnHardDisk() const;
/** Returns true if this file is on a removable disk drive.
This might be a usb-drive, a CD-rom, or maybe a network drive.
*/
bool isOnRemovableDrive() const;
/** Launches the file as a process.
- if the file is executable, this will run it.
- if it's a document of some kind, it will launch the document with its
default viewer application.
- if it's a folder, it will be opened in Explorer, Finder, or equivalent.
@see revealToUser
*/
bool startAsProcess(const String& parameters = String()) const;
/** Opens Finder, Explorer, or whatever the OS uses, to show the user this file's location.
@see startAsProcess
*/
void revealToUser() const;
/** A set of types of location that can be passed to the getSpecialLocation() method.
*/
enum SpecialLocationType
{
/** The user's home folder. This is the same as using File ("~"). */
userHomeDirectory,
/** The user's default documents folder. On Windows, this might be the user's
"My Documents" folder. On the Mac it'll be their "Documents" folder. Linux
doesn't tend to have one of these, so it might just return their home folder.
*/
userDocumentsDirectory,
/** The folder that contains the user's desktop objects. */
userDesktopDirectory,
/** The most likely place where a user might store their music files. */
userMusicDirectory,
/** The most likely place where a user might store their movie files. */
userMoviesDirectory,
/** The most likely place where a user might store their picture files. */
userPicturesDirectory,
/** The folder in which applications store their persistent user-specific settings.
On Windows, this might be "\Documents and Settings\username\Application Data".
On the Mac, it might be "~/Library". If you're going to store your settings in here,
always create your own sub-folder to put them in, to avoid making a mess.
On GNU/Linux it is "~/.config".
*/
userApplicationDataDirectory,
/** An equivalent of the userApplicationDataDirectory folder that is shared by all users
of the computer, rather than just the current user.
On the Mac it'll be "/Library", on Windows, it could be something like
"\Documents and Settings\All Users\Application Data".
On GNU/Linux it is "/opt".
Depending on the setup, this folder may be read-only.
*/
commonApplicationDataDirectory,
/** A place to put documents which are shared by all users of the machine.
On Windows this may be somewhere like "C:\Users\Public\Documents", on OSX it
will be something like "/Users/Shared". Other OSes may have no such concept
though, so be careful.
*/
commonDocumentsDirectory,
/** The folder that should be used for temporary files.
Always delete them when you're finished, to keep the user's computer tidy!
*/
tempDirectory,
/** Returns this application's executable file.
If running as a plug-in or DLL, this will (where possible) be the DLL rather than the
host app.
On the mac this will return the unix binary, not the package folder - see
currentApplicationFile for that.
See also invokedExecutableFile, which is similar, but if the exe was launched from a
file link, invokedExecutableFile will return the name of the link.
*/
currentExecutableFile,
/** Returns this application's location.
If running as a plug-in or DLL, this will (where possible) be the DLL rather than the
host app.
On the mac this will return the package folder (if it's in one), not the unix binary
that's inside it - compare with currentExecutableFile.
*/
currentApplicationFile,
/** Returns the file that was invoked to launch this executable.
This may differ from currentExecutableFile if the app was started from e.g. a link - this
will return the name of the link that was used, whereas currentExecutableFile will return
the actual location of the target executable.
*/
invokedExecutableFile,
/** In a plugin, this will return the path of the host executable. */
hostApplicationPath,
#if JUCE_WINDOWS || DOXYGEN
/** On a Windows machine, returns the location of the Windows/System32 folder. */
windowsSystemDirectory,
#endif
/** The directory in which applications normally get installed.
So on windows, this would be something like "C:\Program Files", on the
Mac "/Applications", or "/usr" on linux.
*/
globalApplicationsDirectory,
#if JUCE_WINDOWS || DOXYGEN
/** On a Windows machine, returns the directory in which 32 bit applications
normally get installed. On a 64 bit machine this would be something like
"C:\Program Files (x86)", whereas for 32 bit machines this would match
globalApplicationsDirectory and be something like "C:\Program Files".
@see globalApplicationsDirectory
*/
globalApplicationsDirectoryX86
#endif
};
/** Finds the location of a special type of file or directory, such as a home folder or
documents folder.
@see SpecialLocationType
*/
static File JUCE_CALLTYPE getSpecialLocation(const SpecialLocationType type);
/** Returns a temporary file in the system's temp directory.
This will try to return the name of a non-existent temp file.
To get the temp folder, you can use getSpecialLocation (File::tempDirectory).
*/
static File createTempFile(StringRef fileNameEnding);
/** Returns the current working directory.
@see setAsCurrentWorkingDirectory
*/
static File getCurrentWorkingDirectory();
/** Sets the current working directory to be this file.
For this to work the file must point to a valid directory.
@returns true if the current directory has been changed.
@see getCurrentWorkingDirectory
*/
bool setAsCurrentWorkingDirectory() const;
/** The system-specific file separator character.
On Windows, this will be '\', on Mac/Linux, it'll be '/'
*/
static juce_wchar getSeparatorChar();
/** The system-specific file separator character, as a string.
On Windows, this will be '\', on Mac/Linux, it'll be '/'
*/
static StringRef getSeparatorString();
/** Returns a version of a filename with any illegal characters removed.
This will return a copy of the given string after removing characters
that are not allowed in a legal filename, and possibly shortening the
string if it's too long.
Because this will remove slashes, don't use it on an absolute pathname - use
createLegalPathName() for that.
@see createLegalPathName
*/
static String createLegalFileName(const String& fileNameToFix);
/** Returns a version of a path with any illegal characters removed.
Similar to createLegalFileName(), but this won't remove slashes, so can
be used on a complete pathname.
@see createLegalFileName
*/
static String createLegalPathName(const String& pathNameToFix);
/** Indicates whether filenames are case-sensitive on the current operating system. */
static bool areFileNamesCaseSensitive();
/** Returns true if the string seems to be a fully-specified absolute path. */
static bool isAbsolutePath(StringRef path);
/** Creates a file that simply contains this string, without doing the sanity-checking
that the normal constructors do.
Best to avoid this unless you really know what you're doing.
*/
static File createFileWithoutCheckingPath(const String& absolutePath) noexcept;
/** Adds a separator character to the end of a path if it doesn't already have one. */
static String addTrailingSeparator(const String& path);
/** Tries to create a symbolic link and returns a boolean to indicate success */
bool createSymbolicLink(const File& linkFileToCreate, bool overwriteExisting) const;
/** Returns true if this file is a link or alias that can be followed using getLinkedTarget(). */
bool isSymbolicLink() const;
/** If this file is a link or alias, this returns the file that it points to.
If the file isn't actually link, it'll just return itself.
*/
File getLinkedTarget() const;
/** Create a symbolic link to a native path and return a boolean to indicate success.
Use this method if you want to create a link to a relative path or a special native
file path (such as a device file on Windows).
*/
static bool createSymbolicLink(const File& linkFileToCreate,
const String& nativePathOfTarget,
bool overwriteExisting);
/** This returns the native path that the symbolic link points to. The returned path
is a native path of the current OS and can be a relative, absolute or special path. */
String getNativeLinkedTarget() const;
#if JUCE_WINDOWS || DOXYGEN
/** Windows ONLY - Creates a win32 .LNK shortcut file that links to this file. */
bool createShortcut(const String& description, const File& linkFileToCreate) const;
/** Windows ONLY - Returns true if this is a win32 .LNK file. */
bool isShortcut() const;
#else
#endif
#if JUCE_MAC || JUCE_IOS || DOXYGEN
/** OSX ONLY - Finds the OSType of a file from the its resources. */
OSType getMacOSType() const;
/** OSX ONLY - Returns true if this file is actually a bundle. */
bool isBundle() const;
#endif
#if JUCE_MAC || DOXYGEN
/** OSX ONLY - Adds this file to the OSX dock */
void addToDock() const;
#endif
/** Comparator for files */
struct NaturalFileComparator
{
NaturalFileComparator(bool shouldPutFoldersFirst) noexcept : foldersFirst(shouldPutFoldersFirst) {}
int compareElements(const File& firstFile, const File& secondFile) const
{
if (foldersFirst && (firstFile.isDirectory() != secondFile.isDirectory()))
return firstFile.isDirectory() ? -1 : 1;
#if NAMES_ARE_CASE_SENSITIVE
return firstFile.getFullPathName().compareNatural(secondFile.getFullPathName(), true);
#else
return firstFile.getFullPathName().compareNatural(secondFile.getFullPathName(), false);
#endif
}
bool foldersFirst;
};
/* These static objects are deprecated because it's too easy to accidentally use them indirectly
during a static constructor, which leads to very obscure order-of-initialisation bugs.
Use File::getSeparatorChar() and File::getSeparatorString(), and instead of File::nonexistent,
just use File() or {}.
*/
JUCE_DEPRECATED_STATIC(static const juce_wchar separator;)
JUCE_DEPRECATED_STATIC(static const StringRef separatorString;)
JUCE_DEPRECATED_STATIC(static const File nonexistent;)
private:
String fullPath;
static String parseAbsolutePath(const String&);
String getPathUpToLastSlash() const;
Result createDirectoryInternal(const String&) const;
bool copyInternal(const File&) const;
bool moveInternal(const File&) const;
bool replaceInternal(const File&) const;
bool setFileTimesInternal(int64 m, int64 a, int64 c) const;
void getFileTimesInternal(int64& m, int64& a, int64& c) const;
bool setFileReadOnlyInternal(bool) const;
bool setFileExecutableInternal(bool) const;
};
} // namespace juce
/*** End of inlined file: juce_File.h ***/
/*** Start of inlined file: juce_DirectoryIterator.h ***/
namespace juce
{
/**
This class is now deprecated in favour of RangedDirectoryIterator.
Searches through the files in a directory, returning each file that is found.
A DirectoryIterator will search through a directory and its subdirectories using
a wildcard filepattern match.
If you may be scanning a large number of files, it's usually smarter to use this
class than File::findChildFiles() because it allows you to stop at any time, rather
than having to wait for the entire scan to finish before getting the results.
Please note that the order in which files are returned is completely undefined!
They'll arrive in whatever order the underlying OS calls provide them, which will
depend on the filesystem and other factors. If you need a sorted list, you'll need
to manually sort them using your preferred comparator after collecting the list.
It also provides an estimate of its progress, using a (highly inaccurate!) algorithm.
@tags{Core}
@see RangedDirectoryIterator
*/
class JUCE_API DirectoryIterator final
{
public:
/** This class is now deprecated in favour of RangedDirectoryIterator.
Creates a DirectoryIterator for a given directory.
After creating one of these, call its next() method to get the
first file - e.g. @code
DirectoryIterator iter (File ("/animals/mooses"), true, "*.moose");
while (iter.next())
{
File theFileItFound (iter.getFile());
... etc
}
@endcode
@see RangedDirectoryIterator
*/
JUCE_DEPRECATED(DirectoryIterator(const File& directory,
bool isRecursive,
const String& wildCard = "*",
int whatToLookFor = File::findFiles));
/** Destructor. */
~DirectoryIterator();
/** Moves the iterator along to the next file.
@returns true if a file was found (you can then use getFile() to see what it was) - or
false if there are no more matching files.
*/
bool next();
/** Moves the iterator along to the next file, and returns various properties of that file.
If you need to find out details about the file, it's more efficient to call this method than
to call the normal next() method and then find out the details afterwards.
All the parameters are optional, so pass null pointers for any items that you're not
interested in.
@returns true if a file was found (you can then use getFile() to see what it was) - or
false if there are no more matching files. If it returns false, then none of the
parameters will be filled-in.
*/
bool next(bool* isDirectory,
bool* isHidden,
int64* fileSize,
Time* modTime,
Time* creationTime,
bool* isReadOnly);
/** Returns the file that the iterator is currently pointing at.
The result of this call is only valid after a call to next() has returned true.
*/
const File& getFile() const;
/** Returns a guess of how far through the search the iterator has got.
@returns a value 0.0 to 1.0 to show the progress, although this won't be
very accurate.
*/
float getEstimatedProgress() const;
private:
struct NativeIterator
{
NativeIterator(const File& directory, const String& wildCard);
~NativeIterator();
bool next(String& filenameFound,
bool* isDirectory, bool* isHidden, int64* fileSize,
Time* modTime, Time* creationTime, bool* isReadOnly);
class Pimpl;
std::unique_ptr<Pimpl> pimpl;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NativeIterator)
};
StringArray wildCards;
NativeIterator fileFinder;
String wildCard, path;
int index = -1;
mutable int totalNumFiles = -1;
const int whatToLookFor;
const bool isRecursive;
bool hasBeenAdvanced = false;
std::unique_ptr<DirectoryIterator> subIterator;
File currentFile;
static StringArray parseWildcards(const String& pattern);
static bool fileMatches(const StringArray& wildCards, const String& filename);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DirectoryIterator)
};
} // namespace juce
/*** End of inlined file: juce_DirectoryIterator.h ***/
/*** Start of inlined file: juce_RangedDirectoryIterator.h ***/
namespace juce
{
/**
Describes the attributes of a file or folder.
@tags{Core}
*/
class DirectoryEntry final
{
public:
/** The path to a file or folder. */
File getFile() const { return file; }
/** The time at which the item was last modified. */
Time getModificationTime() const { return modTime; }
/** The time at which the item was created. */
Time getCreationTime() const { return creationTime; }
/** The size of the item. */
int64 getFileSize() const { return fileSize; }
/** True if the item is a directory, false otherwise. */
bool isDirectory() const { return directory; }
/** True if the item is hidden, false otherwise. */
bool isHidden() const { return hidden; }
/** True if the item is read-only, false otherwise. */
bool isReadOnly() const { return readOnly; }
/** The estimated proportion of the range that has been visited
by the iterator, from 0.0 to 1.0.
*/
float getEstimatedProgress() const;
private:
std::weak_ptr<DirectoryIterator> iterator;
File file;
Time modTime;
Time creationTime;
int64 fileSize = 0;
bool directory = false;
bool hidden = false;
bool readOnly = false;
friend class RangedDirectoryIterator;
};
/** A convenience operator so that the expression `*it++` works correctly when
`it` is an instance of RangedDirectoryIterator.
*/
inline const DirectoryEntry& operator* (const DirectoryEntry& e) noexcept { return e; }
/**
Allows iterating over files and folders using C++11 range-for syntax.
In the following example, we recursively find all hidden files in a
specific directory.
@code
std::vector<File> hiddenFiles;
for (DirectoryEntry entry : RangedDirectoryIterator (File ("/path/to/folder"), isRecursive))
if (entry.isHidden())
hiddenFiles.push_back (entry.getFile());
@endcode
@tags{Core}
*/
class RangedDirectoryIterator final
{
public:
using difference_type = std::ptrdiff_t;
using value_type = DirectoryEntry;
using reference = DirectoryEntry;
using pointer = void;
using iterator_category = std::input_iterator_tag;
/** The default-constructed iterator acts as the 'end' sentinel. */
RangedDirectoryIterator() = default;
/** Creates a RangedDirectoryIterator for a given directory.
The resulting iterator can be used directly in a 'range-for' expression.
@param directory the directory to search in
@param isRecursive whether all the subdirectories should also be searched
@param wildCard the file pattern to match. This may contain multiple patterns
separated by a semi-colon or comma, e.g. "*.jpg;*.png"
@param whatToLookFor a value from the File::TypesOfFileToFind enum, specifying
whether to look for files, directories, or both.
*/
RangedDirectoryIterator(const File& directory,
bool isRecursive,
const String& wildCard = "*",
int whatToLookFor = File::findFiles);
/** Returns true if both iterators are in their end/sentinel state,
otherwise returns false.
*/
bool operator== (const RangedDirectoryIterator& other) const noexcept
{
return iterator == nullptr && other.iterator == nullptr;
}
/** Returns the inverse of operator== */
bool operator!= (const RangedDirectoryIterator& other) const noexcept
{
return !operator== (other);
}
/** Return an object containing metadata about the file or folder to
which the iterator is currently pointing.
*/
const DirectoryEntry& operator* () const noexcept { return entry; }
const DirectoryEntry* operator->() const noexcept { return &entry; }
/** Moves the iterator along to the next file. */
RangedDirectoryIterator& operator++()
{
increment();
return *this;
}
/** Moves the iterator along to the next file.
@returns an object containing metadata about the file or folder to
to which the iterator was previously pointing.
*/
DirectoryEntry operator++ (int)
{
auto result = *(*this);
++(*this);
return result;
}
private:
bool next();
void increment();
std::shared_ptr<DirectoryIterator> iterator;
DirectoryEntry entry;
};
/** Returns the iterator that was passed in.
Provided for range-for compatibility.
*/
inline RangedDirectoryIterator begin(const RangedDirectoryIterator& it) { return it; }
/** Returns a default-constructed sentinel value.
Provided for range-for compatibility.
*/
inline RangedDirectoryIterator end(const RangedDirectoryIterator&) { return {}; }
} // namespace juce
/*** End of inlined file: juce_RangedDirectoryIterator.h ***/
/*** Start of inlined file: juce_FileInputStream.h ***/
namespace juce
{
/**
An input stream that reads from a local file.
@see InputStream, FileOutputStream, File::createInputStream
@tags{Core}
*/
class JUCE_API FileInputStream : public InputStream
{
public:
/** Creates a FileInputStream to read from the given file.
After creating a FileInputStream, you should use openedOk() or failedToOpen()
to make sure that it's OK before trying to read from it! If it failed, you
can call getStatus() to get more error information.
*/
explicit FileInputStream(const File& fileToRead);
/** Destructor. */
~FileInputStream() override;
/** Returns the file that this stream is reading from. */
const File& getFile() const noexcept { return file; }
/** Returns the status of the file stream.
The result will be ok if the file opened successfully. If an error occurs while
opening or reading from the file, this will contain an error message.
*/
const Result& getStatus() const noexcept { return status; }
/** Returns true if the stream couldn't be opened for some reason.
@see getResult()
*/
bool failedToOpen() const noexcept { return status.failed(); }
/** Returns true if the stream opened without problems.
@see getResult()
*/
bool openedOk() const noexcept { return status.wasOk(); }
int64 getTotalLength() override;
int read(void*, int) override;
bool isExhausted() override;
int64 getPosition() override;
bool setPosition(int64) override;
private:
const File file;
void* fileHandle = nullptr;
int64 currentPosition = 0;
Result status{ Result::ok() };
void openHandle();
size_t readInternal(void*, size_t);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(FileInputStream)
};
} // namespace juce
/*** End of inlined file: juce_FileInputStream.h ***/
/*** Start of inlined file: juce_FileOutputStream.h ***/
namespace juce
{
/**
An output stream that writes into a local file.
@see OutputStream, FileInputStream, File::createOutputStream
@tags{Core}
*/
class JUCE_API FileOutputStream : public OutputStream
{
public:
/** Creates a FileOutputStream.
If the file doesn't exist, it will first be created. If the file can't be
created or opened (for example, because the parent directory of the file
does not exist), the failedToOpen() method will return true.
If the file already exists when opened, the stream's write-position will
be set to the end of the file. To overwrite an existing file, you can truncate
it like this:
@code
FileOutputStream stream (file);
if (stream.openedOk())
{
stream.setPosition (0);
stream.truncate();
...
}
@endcode
Destroying a FileOutputStream object does not force the operating system
to write the buffered data to disk immediately. If this is required you
should call flush() before triggering the destructor.
@see TemporaryFile
*/
FileOutputStream(const File& fileToWriteTo,
size_t bufferSizeToUse = 16384);
/** Destructor. */
~FileOutputStream() override;
/** Returns the file that this stream is writing to.
*/
const File& getFile() const { return file; }
/** Returns the status of the file stream.
The result will be ok if the file opened successfully. If an error occurs while
opening or writing to the file, this will contain an error message.
*/
const Result& getStatus() const noexcept { return status; }
/** Returns true if the stream couldn't be opened for some reason.
@see getResult()
*/
bool failedToOpen() const noexcept { return status.failed(); }
/** Returns true if the stream opened without problems.
@see getResult()
*/
bool openedOk() const noexcept { return status.wasOk(); }
/** Attempts to truncate the file to the current write position.
To truncate a file to a specific size, first use setPosition() to seek to the
appropriate location, and then call this method.
*/
Result truncate();
void flush() override;
int64 getPosition() override;
bool setPosition(int64) override;
bool write(const void*, size_t) override;
bool writeRepeatedByte(uint8 byte, size_t numTimesToRepeat) override;
private:
File file;
void* fileHandle = nullptr;
Result status{ Result::ok() };
int64 currentPosition = 0;
size_t bufferSize, bytesInBuffer = 0;
HeapBlock<char> buffer;
void openHandle();
void closeHandle();
void flushInternal();
bool flushBuffer();
int64 setPositionInternal(int64);
ssize_t writeInternal(const void*, size_t);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(FileOutputStream)
};
} // namespace juce
/*** End of inlined file: juce_FileOutputStream.h ***/
/*** Start of inlined file: juce_FileSearchPath.h ***/
namespace juce
{
/**
Represents a set of folders that make up a search path.
@see File
@tags{Core}
*/
class JUCE_API FileSearchPath
{
public:
/** Creates an empty search path. */
FileSearchPath();
/** Creates a search path from a string of pathnames.
The path can be semicolon- or comma-separated, e.g.
"/foo/bar;/foo/moose;/fish/moose"
The separate folders are tokenised and added to the search path.
*/
FileSearchPath(const String& path);
/** Creates a copy of another search path. */
FileSearchPath(const FileSearchPath&);
/** Copies another search path. */
FileSearchPath& operator= (const FileSearchPath&);
/** Destructor. */
~FileSearchPath();
/** Uses a string containing a list of pathnames to re-initialise this list.
This search path is cleared and the semicolon- or comma-separated folders
in this string are added instead. e.g. "/foo/bar;/foo/moose;/fish/moose"
*/
FileSearchPath& operator= (const String& path);
/** Returns the number of folders in this search path.
@see operator[]
*/
int getNumPaths() const;
/** Returns one of the folders in this search path.
The file returned isn't guaranteed to actually be a valid directory.
@see getNumPaths
*/
File operator[] (int index) const;
/** Returns the search path as a semicolon-separated list of directories. */
String toString() const;
/** Adds a new directory to the search path.
The new directory is added to the end of the list if the insertIndex parameter is
less than zero, otherwise it is inserted at the given index.
*/
void add(const File& directoryToAdd,
int insertIndex = -1);
/** Adds a new directory to the search path if it's not already in there.
@return true if the directory has been added, false otherwise.
*/
bool addIfNotAlreadyThere(const File& directoryToAdd);
/** Removes a directory from the search path. */
void remove(int indexToRemove);
/** Merges another search path into this one.
This will remove any duplicate directories.
*/
void addPath(const FileSearchPath&);
/** Removes any directories that are actually subdirectories of one of the other directories in the search path.
If the search is intended to be recursive, there's no point having nested folders in the search
path, because they'll just get searched twice and you'll get duplicate results.
e.g. if the path is "c:\abc\de;c:\abc", this method will simplify it to "c:\abc"
*/
void removeRedundantPaths();
/** Removes any directories that don't actually exist. */
void removeNonExistentPaths();
/** Searches the path for a wildcard.
This will search all the directories in the search path in order and return
an array of the files that were found.
@param whatToLookFor a value from the File::TypesOfFileToFind enum, specifying whether to
return files, directories, or both.
@param searchRecursively whether to recursively search the subdirectories too
@param wildCardPattern a pattern to match against the filenames
@returns the number of files added to the array
@see File::findChildFiles
*/
Array<File> findChildFiles(int whatToLookFor,
bool searchRecursively,
const String& wildCardPattern = "*") const;
/** Searches the path for a wildcard.
Note that there's a newer, better version of this method which returns the results
array, and in almost all cases, you should use that one instead! This one is kept around
mainly for legacy code to use.
*/
int findChildFiles(Array<File>& results,
int whatToLookFor,
bool searchRecursively,
const String& wildCardPattern = "*") const;
/** Finds out whether a file is inside one of the path's directories.
This will return true if the specified file is a child of one of the
directories specified by this path. Note that this doesn't actually do any
searching or check that the files exist - it just looks at the pathnames
to work out whether the file would be inside a directory.
@param fileToCheck the file to look for
@param checkRecursively if true, then this will return true if the file is inside a
subfolder of one of the path's directories (at any depth). If false
it will only return true if the file is actually a direct child
of one of the directories.
@see File::isAChildOf
*/
bool isFileInPath(const File& fileToCheck,
bool checkRecursively) const;
private:
StringArray directories;
void init(const String&);
JUCE_LEAK_DETECTOR(FileSearchPath)
};
} // namespace juce
/*** End of inlined file: juce_FileSearchPath.h ***/
/*** Start of inlined file: juce_MemoryMappedFile.h ***/
namespace juce
{
/**
Maps a file into virtual memory for easy reading and/or writing.
@tags{Core}
*/
class JUCE_API MemoryMappedFile
{
public:
/** The read/write flags used when opening a memory mapped file. */
enum AccessMode
{
readOnly, /**< Indicates that the memory can only be read. */
readWrite /**< Indicates that the memory can be read and written to - changes that are
made will be flushed back to disk at the whim of the OS. */
};
/** Opens a file and maps it to an area of virtual memory.
The file should already exist, and should already be the size that you want to work with
when you call this. If the file is resized after being opened, the behaviour is undefined.
If the file exists and the operation succeeds, the getData() and getSize() methods will
return the location and size of the data that can be read or written. Note that the entire
file is not read into memory immediately - the OS simply creates a virtual mapping, which
will lazily pull the data into memory when blocks are accessed.
If the file can't be opened for some reason, the getData() method will return a null pointer.
If exclusive is false then other apps can also open the same memory mapped file and use this
mapping as an effective way of communicating. If exclusive is true then the mapped file will
be opened exclusively - preventing other apps to access the file which may improve the
performance of accessing the file.
*/
MemoryMappedFile(const File& file, AccessMode mode, bool exclusive = false);
/** Opens a section of a file and maps it to an area of virtual memory.
The file should already exist, and should already be the size that you want to work with
when you call this. If the file is resized after being opened, the behaviour is undefined.
If the file exists and the operation succeeds, the getData() and getSize() methods will
return the location and size of the data that can be read or written. Note that the entire
file is not read into memory immediately - the OS simply creates a virtual mapping, which
will lazily pull the data into memory when blocks are accessed.
If the file can't be opened for some reason, the getData() method will return a null pointer.
NOTE: The start of the actual range used may be rounded-down to a multiple of the OS's page-size,
so do not assume that the mapped memory will begin at exactly the position you requested - always
use getRange() to check the actual range that is being used.
*/
MemoryMappedFile(const File& file,
const Range<int64>& fileRange,
AccessMode mode,
bool exclusive = false);
/** Destructor. */
~MemoryMappedFile();
/** Returns the address at which this file has been mapped, or a null pointer if
the file couldn't be successfully mapped.
*/
void* getData() const noexcept { return address; }
/** Returns the number of bytes of data that are available for reading or writing.
This will normally be the size of the file.
*/
size_t getSize() const noexcept { return (size_t)range.getLength(); }
/** Returns the section of the file at which the mapped memory represents. */
Range<int64> getRange() const noexcept { return range; }
private:
void* address = nullptr;
Range<int64> range;
#if JUCE_WINDOWS
void* fileHandle = nullptr;
#else
int fileHandle = 0;
#endif
void openInternal(const File&, AccessMode, bool);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MemoryMappedFile)
};
} // namespace juce
/*** End of inlined file: juce_MemoryMappedFile.h ***/
/*** Start of inlined file: juce_TemporaryFile.h ***/
namespace juce
{
/**
Manages a temporary file, which will be deleted when this object is deleted.
This object is intended to be used as a stack based object, using its scope
to make sure the temporary file isn't left lying around.
For example:
@code
{
File myTargetFile ("~/myfile.txt");
// this will choose a file called something like "~/myfile_temp239348.txt"
// which definitely doesn't exist at the time the constructor is called.
TemporaryFile temp (myTargetFile);
// create a stream to the temporary file, and write some data to it...
if (auto out = std::unique_ptr<FileOutputStream> (temp.getFile().createOutputStream()))
{
out->write ( ...etc )
out.reset(); // (deletes the stream)
// ..now we've finished writing, this will rename the temp file to
// make it replace the target file we specified above.
bool succeeded = temp.overwriteTargetFileWithTemporary();
}
// ..and even if something went wrong and our overwrite failed,
// as the TemporaryFile object goes out of scope here, it'll make sure
// that the temp file gets deleted.
}
@endcode
@see File, FileOutputStream
@tags{Core}
*/
class JUCE_API TemporaryFile
{
public:
enum OptionFlags
{
useHiddenFile = 1, /**< Indicates that the temporary file should be hidden -
i.e. its name should start with a dot. */
putNumbersInBrackets = 2 /**< Indicates that when numbers are appended to make sure
the file is unique, they should go in brackets rather
than just being appended (see File::getNonexistentSibling() )*/
};
/** Creates a randomly-named temporary file in the default temp directory.
@param suffix a file suffix to use for the file
@param optionFlags a combination of the values listed in the OptionFlags enum
The file will not be created until you write to it. And remember that when
this object is deleted, the file will also be deleted!
*/
TemporaryFile(const String& suffix = String(),
int optionFlags = 0);
/** Creates a temporary file in the same directory as a specified file.
This is useful if you have a file that you want to overwrite, but don't
want to harm the original file if the write operation fails. You can
use this to create a temporary file next to the target file, then
write to the temporary file, and finally use overwriteTargetFileWithTemporary()
to replace the target file with the one you've just written.
This class won't create any files until you actually write to them. And remember
that when this object is deleted, the temporary file will also be deleted!
@param targetFile the file that you intend to overwrite - the temporary
file will be created in the same directory as this
@param optionFlags a combination of the values listed in the OptionFlags enum
*/
TemporaryFile(const File& targetFile,
int optionFlags = 0);
/** Creates a temporary file using an explicit filename.
The other constructors are a better choice than this one, unless for some reason
you need to explicitly specify the temporary file you want to use.
@param targetFile the file that you intend to overwrite
@param temporaryFile the temporary file to be used
*/
TemporaryFile(const File& targetFile,
const File& temporaryFile);
/** Destructor.
When this object is deleted it will make sure that its temporary file is
also deleted! If the operation fails, it'll throw an assertion in debug
mode.
*/
~TemporaryFile();
/** Returns the temporary file. */
const File& getFile() const noexcept { return temporaryFile; }
/** Returns the target file that was specified in the constructor. */
const File& getTargetFile() const noexcept { return targetFile; }
/** Tries to move the temporary file to overwrite the target file that was
specified in the constructor.
If you used the constructor that specified a target file, this will attempt
to replace that file with the temporary one.
Before calling this, make sure:
- that you've actually written to the temporary file
- that you've closed any open streams that you were using to write to it
- and that you don't have any streams open to the target file, which would
prevent it being overwritten
If the file move succeeds, this returns true, and the temporary file will
have disappeared. If it fails, the temporary file will probably still exist,
but will be deleted when this object is destroyed.
*/
bool overwriteTargetFileWithTemporary() const;
/** Attempts to delete the temporary file, if it exists.
@returns true if the file is successfully deleted (or if it didn't exist).
*/
bool deleteTemporaryFile() const;
private:
const File temporaryFile, targetFile;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(TemporaryFile)
};
} // namespace juce
/*** End of inlined file: juce_TemporaryFile.h ***/
/*** Start of inlined file: juce_FileFilter.h ***/
namespace juce
{
/**
Interface for deciding which files are suitable for something.
For example, this is used by DirectoryContentsList to select which files
go into the list.
@see WildcardFileFilter, DirectoryContentsList, FileListComponent, FileBrowserComponent
@tags{Core}
*/
class JUCE_API FileFilter
{
public:
/** Creates a filter with the given description.
The description can be returned later with the getDescription() method.
*/
FileFilter(const String& filterDescription);
/** Destructor. */
virtual ~FileFilter();
/** Returns the description that the filter was created with. */
const String& getDescription() const noexcept;
/** Should return true if this file is suitable for inclusion in whatever context
the object is being used.
*/
virtual bool isFileSuitable(const File& file) const = 0;
/** Should return true if this directory is suitable for inclusion in whatever context
the object is being used.
*/
virtual bool isDirectorySuitable(const File& file) const = 0;
protected:
String description;
};
} // namespace juce
/*** End of inlined file: juce_FileFilter.h ***/
/*** Start of inlined file: juce_WildcardFileFilter.h ***/
namespace juce
{
/**
A type of FileFilter that works by wildcard pattern matching.
This filter only allows files that match one of the specified patterns, but
allows all directories through.
@see FileFilter, DirectoryContentsList, FileListComponent, FileBrowserComponent
@tags{Core}
*/
class JUCE_API WildcardFileFilter : public FileFilter
{
public:
/**
Creates a wildcard filter for one or more patterns.
The wildcardPatterns parameter is a comma or semicolon-delimited set of
patterns, e.g. "*.wav;*.aiff" would look for files ending in either .wav
or .aiff.
Passing an empty string as a pattern will fail to match anything, so by leaving
either the file or directory pattern parameter empty means you can control
whether files or directories are found.
The description is a name to show the user in a list of possible patterns, so
for the wav/aiff example, your description might be "audio files".
*/
WildcardFileFilter(const String& fileWildcardPatterns,
const String& directoryWildcardPatterns,
const String& filterDescription);
/** Destructor. */
~WildcardFileFilter() override;
/** Returns true if the filename matches one of the patterns specified. */
bool isFileSuitable(const File& file) const override;
/** This always returns true. */
bool isDirectorySuitable(const File& file) const override;
private:
StringArray fileWildcards, directoryWildcards;
JUCE_LEAK_DETECTOR(WildcardFileFilter)
};
} // namespace juce
/*** End of inlined file: juce_WildcardFileFilter.h ***/
/*** Start of inlined file: juce_FileInputSource.h ***/
namespace juce
{
/**
A type of InputSource that represents a normal file.
@see InputSource
@tags{Core}
*/
class JUCE_API FileInputSource : public InputSource
{
public:
/** Creates a FileInputSource for a file.
If the useFileTimeInHashGeneration parameter is true, then this object's
hashCode() method will incorporate the file time into its hash code; if
false, only the file name will be used for the hash.
*/
FileInputSource(const File& file, bool useFileTimeInHashGeneration = false);
/** Destructor. */
~FileInputSource() override;
InputStream* createInputStream() override;
InputStream* createInputStreamFor(const String& relatedItemPath) override;
int64 hashCode() const override;
private:
const File file;
bool useFileTimeInHashGeneration;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(FileInputSource)
};
}
/*** End of inlined file: juce_FileInputSource.h ***/
/*** Start of inlined file: juce_FileLogger.h ***/
namespace juce
{
/**
A simple implementation of a Logger that writes to a file.
@see Logger
@tags{Core}
*/
class JUCE_API FileLogger : public Logger
{
public:
/** Creates a FileLogger for a given file.
@param fileToWriteTo the file that to use - new messages will be appended
to the file. If the file doesn't exist, it will be created,
along with any parent directories that are needed.
@param welcomeMessage when opened, the logger will write a header to the log, along
with the current date and time, and this welcome message
@param maxInitialFileSizeBytes if this is zero or greater, then if the file already exists
but is larger than this number of bytes, then the start of the
file will be truncated to keep the size down. This prevents a log
file getting ridiculously large over time. The file will be truncated
at a new-line boundary. If this value is less than zero, no size limit
will be imposed; if it's zero, the file will always be deleted. Note that
the size is only checked once when this object is created - any logging
that is done later will be appended without any checking
*/
FileLogger(const File& fileToWriteTo,
const String& welcomeMessage,
const int64 maxInitialFileSizeBytes = 128 * 1024);
/** Destructor. */
~FileLogger() override;
/** Returns the file that this logger is writing to. */
const File& getLogFile() const noexcept { return logFile; }
/** Helper function to create a log file in the correct place for this platform.
The method might return nullptr if the file can't be created for some reason.
@param logFileSubDirectoryName the name of the subdirectory to create inside the logs folder (as
returned by getSystemLogFileFolder). It's best to use something
like the name of your application here.
@param logFileName the name of the file to create, e.g. "MyAppLog.txt".
@param welcomeMessage a message that will be written to the log when it's opened.
@param maxInitialFileSizeBytes (see the FileLogger constructor for more info on this)
*/
static FileLogger* createDefaultAppLogger(const String& logFileSubDirectoryName,
const String& logFileName,
const String& welcomeMessage,
const int64 maxInitialFileSizeBytes = 128 * 1024);
/** Helper function to create a log file in the correct place for this platform.
The filename used is based on the root and suffix strings provided, along with a
time and date string, meaning that a new, empty log file will be always be created
rather than appending to an existing one.
The method might return nullptr if the file can't be created for some reason.
@param logFileSubDirectoryName the name of the subdirectory to create inside the logs folder (as
returned by getSystemLogFileFolder). It's best to use something
like the name of your application here.
@param logFileNameRoot the start of the filename to use, e.g. "MyAppLog_". This will have
a timestamp and the logFileNameSuffix appended to it
@param logFileNameSuffix the file suffix to use, e.g. ".txt"
@param welcomeMessage a message that will be written to the log when it's opened.
*/
static FileLogger* createDateStampedLogger(const String& logFileSubDirectoryName,
const String& logFileNameRoot,
const String& logFileNameSuffix,
const String& welcomeMessage);
/** Returns an OS-specific folder where log-files should be stored.
On Windows this will return a logger with a path such as:
c:\\Documents and Settings\\username\\Application Data\\[logFileSubDirectoryName]\\[logFileName]
On the Mac it'll create something like:
~/Library/Logs/[logFileSubDirectoryName]/[logFileName]
@see createDefaultAppLogger
*/
static File getSystemLogFileFolder();
// (implementation of the Logger virtual method)
void logMessage(const String&) override;
/** This is a utility function which removes lines from the start of a text
file to make sure that its total size is below the given size.
*/
static void trimFileSize(const File& file, int64 maxFileSize);
private:
File logFile;
CriticalSection logLock;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(FileLogger)
};
} // namespace juce
/*** End of inlined file: juce_FileLogger.h ***/
/*** Start of inlined file: juce_JSON.h ***/
namespace juce
{
/**
Contains static methods for converting JSON-formatted text to and from var objects.
The var class is structurally compatible with JSON-formatted data, so these
functions allow you to parse JSON into a var object, and to convert a var
object to JSON-formatted text.
@see var
@tags{Core}
*/
class JUCE_API JSON
{
public:
/** Parses a string of JSON-formatted text, and returns a result code containing
any parse errors.
This will return the parsed structure in the parsedResult parameter, and will
return a Result object to indicate whether parsing was successful, and if not,
it will contain an error message.
If you're not interested in the error message, you can use one of the other
shortcut parse methods, which simply return a var() if the parsing fails.
Note that this will only parse valid JSON, which means that the item given must
be either an object or an array definition. If you want to also be able to parse
any kind of primitive JSON object, use the fromString() method.
*/
static Result parse(const String& text, var& parsedResult);
/** Attempts to parse some JSON-formatted text, and returns the result as a var object.
If the parsing fails, this simply returns var() - if you need to find out more
detail about the parse error, use the alternative parse() method which returns a Result.
Note that this will only parse valid JSON, which means that the item given must
be either an object or an array definition. If you want to also be able to parse
any kind of primitive JSON object, use the fromString() method.
*/
static var parse(const String& text);
/** Attempts to parse some JSON-formatted text from a file, and returns the result
as a var object.
Note that this is just a short-cut for reading the entire file into a string and
parsing the result.
If the parsing fails, this simply returns var() - if you need to find out more
detail about the parse error, use the alternative parse() method which returns a Result.
*/
static var parse(const File& file);
/** Attempts to parse some JSON-formatted text from a stream, and returns the result
as a var object.
Note that this is just a short-cut for reading the entire stream into a string and
parsing the result.
If the parsing fails, this simply returns var() - if you need to find out more
detail about the parse error, use the alternative parse() method which returns a Result.
*/
static var parse(InputStream& input);
/** Returns a string which contains a JSON-formatted representation of the var object.
If allOnOneLine is true, the result will be compacted into a single line of text
with no carriage-returns. If false, it will be laid-out in a more human-readable format.
The maximumDecimalPlaces parameter determines the precision of floating point numbers
in scientific notation.
@see writeToStream
*/
static String toString(const var& objectToFormat,
bool allOnOneLine = false,
int maximumDecimalPlaces = 15);
/** Parses a string that was created with the toString() method.
This is slightly different to the parse() methods because they will reject primitive
values and only accept array or object definitions, whereas this method will handle
either.
*/
static var fromString(StringRef);
/** Writes a JSON-formatted representation of the var object to the given stream.
If allOnOneLine is true, the result will be compacted into a single line of text
with no carriage-returns. If false, it will be laid-out in a more human-readable format.
The maximumDecimalPlaces parameter determines the precision of floating point numbers
in scientific notation.
@see toString
*/
static void writeToStream(OutputStream& output,
const var& objectToFormat,
bool allOnOneLine = false,
int maximumDecimalPlaces = 15);
/** Returns a version of a string with any extended characters escaped. */
static String escapeString(StringRef);
/** Parses a quoted string-literal in JSON format, returning the un-escaped result in the
result parameter, and an error message in case the content was illegal.
This advances the text parameter, leaving it positioned after the closing quote.
*/
static Result parseQuotedString(String::CharPointerType& text, var& result);
private:
JSON() = delete; // This class can't be instantiated - just use its static methods.
};
} // namespace juce
/*** End of inlined file: juce_JSON.h ***/
/*** Start of inlined file: juce_Javascript.h ***/
namespace juce
{
/**
A simple javascript interpreter!
It's not fully standards-compliant, and won't be as fast as the fancy JIT-compiled
engines that you get in browsers, but this is an extremely compact, low-overhead javascript
interpreter, which is integrated with the juce var and DynamicObject classes. If you need
a few simple bits of scripting in your app, and want to be able to easily let the JS
work with native objects defined as DynamicObject subclasses, then this might do the job.
To use, simply create an instance of this class and call execute() to run your code.
Variables that the script sets can be retrieved with evaluate(), and if you need to provide
native objects for the script to use, you can add them with registerNativeObject().
One caveat: Because the values and objects that the engine works with are DynamicObject
and var objects, they use reference-counting rather than garbage-collection, so if your
script creates complex connections between objects, you run the risk of creating cyclic
dependencies and hence leaking.
@tags{Core}
*/
class JUCE_API JavascriptEngine final
{
public:
/** Creates an instance of the engine.
This creates a root namespace and defines some basic Object, String, Array
and Math library methods.
*/
JavascriptEngine();
/** Destructor. */
~JavascriptEngine();
/** Attempts to parse and run a block of javascript code.
If there's a parse or execution error, the error description is returned in
the result.
You can specify a maximum time for which the program is allowed to run, and
it'll return with an error message if this time is exceeded.
*/
Result execute(const String& javascriptCode);
/** Attempts to parse and run a javascript expression, and returns the result.
If there's a syntax error, or the expression can't be evaluated, the return value
will be var::undefined(). The errorMessage parameter gives you a way to find out
any parsing errors.
You can specify a maximum time for which the program is allowed to run, and
it'll return with an error message if this time is exceeded.
*/
var evaluate(const String& javascriptCode,
Result* errorMessage = nullptr);
/** Calls a function in the root namespace, and returns the result.
The function arguments are passed in the same format as used by native
methods in the var class.
*/
var callFunction(const Identifier& function,
const var::NativeFunctionArgs& args,
Result* errorMessage = nullptr);
/** Calls a function object in the namespace of a dynamic object, and returns the result.
The function arguments are passed in the same format as used by native
methods in the var class.
*/
var callFunctionObject(DynamicObject* objectScope,
const var& functionObject,
const var::NativeFunctionArgs& args,
Result* errorMessage = nullptr);
/** Adds a native object to the root namespace.
The object passed-in is reference-counted, and will be retained by the
engine until the engine is deleted. The name must be a simple JS identifier,
without any dots.
*/
void registerNativeObject(const Identifier& objectName, DynamicObject* object);
/** This value indicates how long a call to one of the evaluate methods is permitted
to run before timing-out and failing.
The default value is a number of seconds, but you can change this to whatever value
suits your application.
*/
RelativeTime maximumExecutionTime;
/** When called from another thread, causes the interpreter to time-out as soon as possible */
void stop() noexcept;
/** Provides access to the set of properties of the root namespace object. */
const NamedValueSet& getRootObjectProperties() const noexcept;
private:
JUCE_PUBLIC_IN_DLL_BUILD(struct RootObject)
const ReferenceCountedObjectPtr<RootObject> root;
void prepareTimeout() const noexcept;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(JavascriptEngine)
};
} // namespace juce
/*** End of inlined file: juce_Javascript.h ***/
/*** Start of inlined file: juce_BigInteger.h ***/
namespace juce
{
/**
An arbitrarily large integer class.
A BigInteger can be used in a similar way to a normal integer, but has no size
limit (except for memory and performance constraints).
Negative values are possible, but the value isn't stored as 2s-complement, so
be careful if you use negative values and look at the values of individual bits.
@tags{Core}
*/
class JUCE_API BigInteger
{
public:
/** Creates an empty BigInteger */
BigInteger();
/** Creates a BigInteger containing an integer value in its low bits.
The low 32 bits of the number are initialised with this value.
*/
BigInteger(uint32 value);
/** Creates a BigInteger containing an integer value in its low bits.
The low 32 bits of the number are initialised with the absolute value
passed in, and its sign is set to reflect the sign of the number.
*/
BigInteger(int32 value);
/** Creates a BigInteger containing an integer value in its low bits.
The low 64 bits of the number are initialised with the absolute value
passed in, and its sign is set to reflect the sign of the number.
*/
BigInteger(int64 value);
/** Creates a copy of another BigInteger. */
BigInteger(const BigInteger&);
/** Move constructor */
BigInteger(BigInteger&&) noexcept;
/** Move assignment operator */
BigInteger& operator= (BigInteger&&) noexcept;
/** Destructor. */
~BigInteger();
/** Copies another BigInteger onto this one. */
BigInteger& operator= (const BigInteger&);
/** Swaps the internal contents of this with another object. */
void swapWith(BigInteger&) noexcept;
/** Returns the value of a specified bit in the number.
If the index is out-of-range, the result will be false.
*/
bool operator[] (int bit) const noexcept;
/** Returns true if no bits are set. */
bool isZero() const noexcept;
/** Returns true if the value is 1. */
bool isOne() const noexcept;
/** Attempts to get the lowest 32 bits of the value as an integer.
If the value is bigger than the integer limits, this will return only the lower bits.
*/
int toInteger() const noexcept;
/** Attempts to get the lowest 64 bits of the value as an integer.
If the value is bigger than the integer limits, this will return only the lower bits.
*/
int64 toInt64() const noexcept;
/** Resets the value to 0. */
void clear() noexcept;
/** Clears a particular bit in the number. */
void clearBit(int bitNumber) noexcept;
/** Sets a specified bit to 1. */
void setBit(int bitNumber);
/** Sets or clears a specified bit. */
void setBit(int bitNumber, bool shouldBeSet);
/** Sets a range of bits to be either on or off.
@param startBit the first bit to change
@param numBits the number of bits to change
@param shouldBeSet whether to turn these bits on or off
*/
void setRange(int startBit, int numBits, bool shouldBeSet);
/** Inserts a bit an a given position, shifting up any bits above it. */
void insertBit(int bitNumber, bool shouldBeSet);
/** Returns a range of bits as a new BigInteger.
e.g. getBitRangeAsInt (0, 64) would return the lowest 64 bits.
@see getBitRangeAsInt
*/
BigInteger getBitRange(int startBit, int numBits) const;
/** Returns a range of bits as an integer value.
e.g. getBitRangeAsInt (0, 32) would return the lowest 32 bits.
Asking for more than 32 bits isn't allowed (obviously) - for that, use
getBitRange().
*/
uint32 getBitRangeAsInt(int startBit, int numBits) const noexcept;
/** Sets a range of bits to an integer value.
Copies the given integer onto a range of bits, starting at startBit,
and using up to numBits of the available bits.
*/
void setBitRangeAsInt(int startBit, int numBits, uint32 valueToSet);
/** Shifts a section of bits left or right.
@param howManyBitsLeft how far to move the bits (+ve numbers shift it left, -ve numbers shift it right).
@param startBit the first bit to affect - if this is > 0, only bits above that index will be affected.
*/
void shiftBits(int howManyBitsLeft, int startBit);
/** Returns the total number of set bits in the value. */
int countNumberOfSetBits() const noexcept;
/** Looks for the index of the next set bit after a given starting point.
This searches from startIndex (inclusive) upwards for the first set bit,
and returns its index. If no set bits are found, it returns -1.
*/
int findNextSetBit(int startIndex) const noexcept;
/** Looks for the index of the next clear bit after a given starting point.
This searches from startIndex (inclusive) upwards for the first clear bit,
and returns its index.
*/
int findNextClearBit(int startIndex) const noexcept;
/** Returns the index of the highest set bit in the number.
If the value is zero, this will return -1.
*/
int getHighestBit() const noexcept;
/** Returns true if the value is less than zero.
@see setNegative, negate
*/
bool isNegative() const noexcept;
/** Changes the sign of the number to be positive or negative.
@see isNegative, negate
*/
void setNegative(bool shouldBeNegative) noexcept;
/** Inverts the sign of the number.
@see isNegative, setNegative
*/
void negate() noexcept;
// All the standard arithmetic ops...
BigInteger& operator+= (const BigInteger&);
BigInteger& operator-= (const BigInteger&);
BigInteger& operator*= (const BigInteger&);
BigInteger& operator/= (const BigInteger&);
BigInteger& operator|= (const BigInteger&);
BigInteger& operator&= (const BigInteger&);
BigInteger& operator^= (const BigInteger&);
BigInteger& operator%= (const BigInteger&);
BigInteger& operator<<= (int numBitsToShift);
BigInteger& operator>>= (int numBitsToShift);
BigInteger& operator++();
BigInteger& operator--();
BigInteger operator++ (int);
BigInteger operator-- (int);
BigInteger operator-() const;
BigInteger operator+ (const BigInteger&) const;
BigInteger operator- (const BigInteger&) const;
BigInteger operator* (const BigInteger&) const;
BigInteger operator/ (const BigInteger&) const;
BigInteger operator| (const BigInteger&) const;
BigInteger operator& (const BigInteger&) const;
BigInteger operator^ (const BigInteger&) const;
BigInteger operator% (const BigInteger&) const;
BigInteger operator<< (int numBitsToShift) const;
BigInteger operator>> (int numBitsToShift) const;
bool operator== (const BigInteger&) const noexcept;
bool operator!= (const BigInteger&) const noexcept;
bool operator< (const BigInteger&) const noexcept;
bool operator<= (const BigInteger&) const noexcept;
bool operator> (const BigInteger&) const noexcept;
bool operator>= (const BigInteger&) const noexcept;
/** Does a signed comparison of two BigIntegers.
Return values are:
- 0 if the numbers are the same
- < 0 if this number is smaller than the other
- > 0 if this number is bigger than the other
*/
int compare(const BigInteger& other) const noexcept;
/** Compares the magnitudes of two BigIntegers, ignoring their signs.
Return values are:
- 0 if the numbers are the same
- < 0 if this number is smaller than the other
- > 0 if this number is bigger than the other
*/
int compareAbsolute(const BigInteger& other) const noexcept;
/** Divides this value by another one and returns the remainder.
This number is divided by other, leaving the quotient in this number,
with the remainder being copied to the other BigInteger passed in.
*/
void divideBy(const BigInteger& divisor, BigInteger& remainder);
/** Returns the largest value that will divide both this value and the argument. */
BigInteger findGreatestCommonDivisor(BigInteger other) const;
/** Performs a combined exponent and modulo operation.
This BigInteger's value becomes (this ^ exponent) % modulus.
*/
void exponentModulo(const BigInteger& exponent, const BigInteger& modulus);
/** Performs an inverse modulo on the value.
i.e. the result is (this ^ -1) mod (modulus).
*/
void inverseModulo(const BigInteger& modulus);
/** Performs the Montgomery Multiplication with modulo.
This object is left containing the result value: ((this * other) * R1) % modulus.
To get this result, we need modulus, modulusp and k such as R = 2^k, with
modulus * modulusp - R * R1 = GCD(modulus, R) = 1
*/
void montgomeryMultiplication(const BigInteger& other, const BigInteger& modulus,
const BigInteger& modulusp, int k);
/** Performs the Extended Euclidean algorithm.
This method will set the xOut and yOut arguments such that (a * xOut) - (b * yOut) = GCD (a, b).
On return, this object is left containing the value of the GCD.
*/
void extendedEuclidean(const BigInteger& a, const BigInteger& b,
BigInteger& xOut, BigInteger& yOut);
/** Converts the number to a string.
Specify a base such as 2 (binary), 8 (octal), 10 (decimal), 16 (hex).
If minimumNumCharacters is greater than 0, the returned string will be
padded with leading zeros to reach at least that length.
*/
String toString(int base, int minimumNumCharacters = 1) const;
/** Reads the numeric value from a string.
Specify a base such as 2 (binary), 8 (octal), 10 (decimal), 16 (hex).
Any invalid characters will be ignored.
*/
void parseString(StringRef text, int base);
/** Turns the number into a block of binary data.
The data is arranged as little-endian, so the first byte of data is the low 8 bits
of the number, and so on.
@see loadFromMemoryBlock
*/
MemoryBlock toMemoryBlock() const;
/** Converts a block of raw data into a number.
The data is arranged as little-endian, so the first byte of data is the low 8 bits
of the number, and so on.
@see toMemoryBlock
*/
void loadFromMemoryBlock(const MemoryBlock& data);
private:
enum { numPreallocatedInts = 4 };
HeapBlock<uint32> heapAllocation;
uint32 preallocated[numPreallocatedInts];
size_t allocatedSize;
int highestBit = -1;
bool negative = false;
uint32* getValues() const noexcept;
uint32* ensureSize(size_t);
void shiftLeft(int bits, int startBit);
void shiftRight(int bits, int startBit);
JUCE_LEAK_DETECTOR(BigInteger)
};
/** Writes a BigInteger to an OutputStream as a UTF8 decimal string. */
OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const BigInteger& value);
} // namespace juce
/*** End of inlined file: juce_BigInteger.h ***/
/*** Start of inlined file: juce_Expression.h ***/
namespace juce
{
/**
A class for dynamically evaluating simple numeric expressions.
This class can parse a simple C-style string expression involving floating point
numbers, named symbols and functions. The basic arithmetic operations of +, -, *, /
are supported, as well as parentheses, and any alphanumeric identifiers are
assumed to be named symbols which will be resolved when the expression is
evaluated.
Expressions which use identifiers and functions require a subclass of
Expression::Scope to be supplied when evaluating them, and this object
is expected to be able to resolve the symbol names and perform the functions that
are used.
@tags{Core}
*/
class JUCE_API Expression
{
public:
/** Creates a simple expression with a value of 0. */
Expression();
/** Destructor. */
~Expression();
/** Creates a copy of an expression. */
Expression(const Expression&);
/** Copies another expression. */
Expression& operator= (const Expression&);
/** Move constructor */
Expression(Expression&&) noexcept;
/** Move assignment operator */
Expression& operator= (Expression&&) noexcept;
/** Creates a simple expression with a specified constant value. */
explicit Expression(double constant);
/** Attempts to create an expression by parsing a string.
Any errors are returned in the parseError argument provided.
*/
Expression(const String& stringToParse, String& parseError);
/** Returns a string version of the expression. */
String toString() const;
/** Returns an expression which is an addition operation of two existing expressions. */
Expression operator+ (const Expression&) const;
/** Returns an expression which is a subtraction operation of two existing expressions. */
Expression operator- (const Expression&) const;
/** Returns an expression which is a multiplication operation of two existing expressions. */
Expression operator* (const Expression&) const;
/** Returns an expression which is a division operation of two existing expressions. */
Expression operator/ (const Expression&) const;
/** Returns an expression which performs a negation operation on an existing expression. */
Expression operator-() const;
/** Returns an Expression which is an identifier reference. */
static Expression symbol(const String& symbol);
/** Returns an Expression which is a function call. */
static Expression function(const String& functionName, const Array<Expression>& parameters);
/** Returns an Expression which parses a string from a character pointer, and updates the pointer
to indicate where it finished.
The pointer is incremented so that on return, it indicates the character that follows
the end of the expression that was parsed.
If there's a syntax error in parsing, the parseError argument will be set
to a description of the problem.
*/
static Expression parse(String::CharPointerType& stringToParse, String& parseError);
/** When evaluating an Expression object, this class is used to resolve symbols and
perform functions that the expression uses.
*/
class JUCE_API Scope
{
public:
Scope();
virtual ~Scope();
/** Returns some kind of globally unique ID that identifies this scope. */
virtual String getScopeUID() const;
/** Returns the value of a symbol.
If the symbol is unknown, this can throw an Expression::EvaluationError exception.
The member value is set to the part of the symbol that followed the dot, if there is
one, e.g. for "foo.bar", symbol = "foo" and member = "bar".
@throws Expression::EvaluationError
*/
virtual Expression getSymbolValue(const String& symbol) const;
/** Executes a named function.
If the function name is unknown, this can throw an Expression::EvaluationError exception.
@throws Expression::EvaluationError
*/
virtual double evaluateFunction(const String& functionName,
const double* parameters, int numParameters) const;
/** Used as a callback by the Scope::visitRelativeScope() method.
You should never create an instance of this class yourself, it's used by the
expression evaluation code.
*/
class Visitor
{
public:
virtual ~Visitor() = default;
virtual void visit(const Scope&) = 0;
};
/** Creates a Scope object for a named scope, and then calls a visitor
to do some kind of processing with this new scope.
If the name is valid, this method must create a suitable (temporary) Scope
object to represent it, and must call the Visitor::visit() method with this
new scope.
*/
virtual void visitRelativeScope(const String& scopeName, Visitor& visitor) const;
};
/** Evaluates this expression, without using a Scope.
Without a Scope, no symbols can be used, and only basic functions such as sin, cos, tan,
min, max are available.
To find out about any errors during evaluation, use the other version of this method which
takes a String parameter.
*/
double evaluate() const;
/** Evaluates this expression, providing a scope that should be able to evaluate any symbols
or functions that it uses.
To find out about any errors during evaluation, use the other version of this method which
takes a String parameter.
*/
double evaluate(const Scope& scope) const;
/** Evaluates this expression, providing a scope that should be able to evaluate any symbols
or functions that it uses.
*/
double evaluate(const Scope& scope, String& evaluationError) const;
/** Attempts to return an expression which is a copy of this one, but with a constant adjusted
to make the expression resolve to a target value.
E.g. if the expression is "x + 10" and x is 5, then asking for a target value of 8 will return
the expression "x + 3". Obviously some expressions can't be reversed in this way, in which
case they might just be adjusted by adding a constant to the original expression.
@throws Expression::EvaluationError
*/
Expression adjustedToGiveNewResult(double targetValue, const Scope& scope) const;
/** Represents a symbol that is used in an Expression. */
struct Symbol
{
Symbol(const String& scopeUID, const String& symbolName);
bool operator== (const Symbol&) const noexcept;
bool operator!= (const Symbol&) const noexcept;
String scopeUID; /**< The unique ID of the Scope that contains this symbol. */
String symbolName; /**< The name of the symbol. */
};
/** Returns a copy of this expression in which all instances of a given symbol have been renamed. */
Expression withRenamedSymbol(const Symbol& oldSymbol, const String& newName, const Scope& scope) const;
/** Returns true if this expression makes use of the specified symbol.
If a suitable scope is supplied, the search will dereference and recursively check
all symbols, so that it can be determined whether this expression relies on the given
symbol at any level in its evaluation. If the scope parameter is null, this just checks
whether the expression contains any direct references to the symbol.
@throws Expression::EvaluationError
*/
bool referencesSymbol(const Symbol& symbol, const Scope& scope) const;
/** Returns true if this expression contains any symbols. */
bool usesAnySymbols() const;
/** Returns a list of all symbols that may be needed to resolve this expression in the given scope. */
void findReferencedSymbols(Array<Symbol>& results, const Scope& scope) const;
/** Expression type.
@see Expression::getType()
*/
enum Type
{
constantType,
functionType,
operatorType,
symbolType
};
/** Returns the type of this expression. */
Type getType() const noexcept;
/** If this expression is a symbol, function or operator, this returns its identifier. */
String getSymbolOrFunction() const;
/** Returns the number of inputs to this expression.
@see getInput
*/
int getNumInputs() const;
/** Retrieves one of the inputs to this expression.
@see getNumInputs
*/
Expression getInput(int index) const;
private:
class Term;
struct Helpers;
ReferenceCountedObjectPtr<Term> term;
explicit Expression(Term*);
};
} // namespace juce
/*** End of inlined file: juce_Expression.h ***/
/*** Start of inlined file: juce_Random.h ***/
namespace juce
{
/**
A random number generator.
You can create a Random object and use it to generate a sequence of random numbers.
@tags{Core}
*/
class JUCE_API Random final
{
public:
/** Creates a Random object based on a seed value.
For a given seed value, the subsequent numbers generated by this object
will be predictable, so a good idea is to set this value based
on the time, e.g.
new Random (Time::currentTimeMillis())
*/
explicit Random(int64 seedValue) noexcept;
/** Creates a Random object using a random seed value.
Internally, this calls setSeedRandomly() to randomise the seed.
*/
Random();
/** Destructor. */
~Random() noexcept;
/** Returns the next random 32 bit integer.
@returns a random integer from the full range 0x80000000 to 0x7fffffff
*/
int nextInt() noexcept;
/** Returns the next random number, limited to a given range.
The maxValue parameter may not be negative, or zero.
@returns a random integer between 0 (inclusive) and maxValue (exclusive).
*/
int nextInt(int maxValue) noexcept;
/** Returns the next random number, limited to a given range.
@returns a random integer between the range start (inclusive) and its end (exclusive).
*/
int nextInt(Range<int> range) noexcept;
/** Returns the next 64-bit random number.
@returns a random integer from the full range 0x8000000000000000 to 0x7fffffffffffffff
*/
int64 nextInt64() noexcept;
/** Returns the next random floating-point number.
@returns a random value in the range 0 (inclusive) to 1.0 (exclusive)
*/
float nextFloat() noexcept;
/** Returns the next random floating-point number.
@returns a random value in the range 0 (inclusive) to 1.0 (exclusive)
*/
double nextDouble() noexcept;
/** Returns the next random boolean value. */
bool nextBool() noexcept;
/** Returns a BigInteger containing a random number.
@returns a random value in the range 0 to (maximumValue - 1).
*/
BigInteger nextLargeNumber(const BigInteger& maximumValue);
/** Fills a block of memory with random values. */
void fillBitsRandomly(void* bufferToFill, size_t sizeInBytes);
/** Sets a range of bits in a BigInteger to random values. */
void fillBitsRandomly(BigInteger& arrayToChange, int startBit, int numBits);
/** Resets this Random object to a given seed value. */
void setSeed(int64 newSeed) noexcept;
/** Returns the RNG's current seed. */
int64 getSeed() const noexcept { return seed; }
/** Merges this object's seed with another value.
This sets the seed to be a value created by combining the current seed and this
new value.
*/
void combineSeed(int64 seedValue) noexcept;
/** Reseeds this generator using a value generated from various semi-random system
properties like the current time, etc.
Because this function convolves the time with the last seed value, calling
it repeatedly will increase the randomness of the final result.
*/
void setSeedRandomly();
/** The overhead of creating a new Random object is fairly small, but if you want to avoid
it, you can call this method to get a global shared Random object.
It's not thread-safe though, so threads should use their own Random object, otherwise
you run the risk of your random numbers becoming.. erm.. randomly corrupted..
*/
static Random& getSystemRandom() noexcept;
private:
int64 seed;
JUCE_LEAK_DETECTOR(Random)
};
} // namespace juce
/*** End of inlined file: juce_Random.h ***/
/*** Start of inlined file: juce_RuntimePermissions.h ***/
namespace juce
{
/**
Class to handle app runtime permissions for certain functionality on some platforms.
The use of this class is currently only required if the app should run on
Android API level 23 and higher.
On lower API levels, the permissions are specified in the app manifest. On iOS,
runtime permission requests are handled automatically by the Apple APIs and not
manually in the app code. On Windows, OS X, and Linux, runtime permissions are not
used at all. In all these cases, request() will simply call through to the
callback with no overhead and pass true (making it safe to use on all platforms).
For example, to enable audio recording on Android in your cross-platform app,
you could modify your code as follows:
Old code:
audioDeviceManager.initialise (2, 2, nullptr, true, String(), nullptr);
New code:
RuntimePermissions::request (
RuntimePermissions::audioRecording,
[this] (bool wasGranted)
{
if (! wasGranted)
{
// e.g. display an error or initialise with 0 input channels
return;
}
audioDeviceManager.initialise (2, 2, nullptr, true, String(), nullptr);
}
);
@tags{Core}
*/
class JUCE_API RuntimePermissions
{
public:
enum PermissionID
{
/** Permission to access the microphone (required on Android).
You need to request this, for example, to initialise an AudioDeviceManager with
a non-zero number of input channels, and to open the default audio input device.
*/
recordAudio = 1,
/** Permission to scan for and pair to Bluetooth MIDI devices (required on Android).
You need to request this before calling BluetoothMidiDevicePairingDialogue::open(),
otherwise no devices will be found.
*/
bluetoothMidi = 2,
/** Permission to read from external storage such as SD cards */
readExternalStorage = 3,
/** Permission to write to external storage such as SD cards */
writeExternalStorage = 4,
/** Permission to use camera */
camera = 5
};
/** Function type of runtime permission request callbacks. */
using Callback = std::function<void(bool)>;
/** Call this method to request a runtime permission.
@param permission The PermissionID of the permission you want to request.
@param callback The callback to be called after the request has been granted
or denied; the argument passed will be true if the permission
has been granted and false otherwise.
If no runtime request is required or possible to obtain the permission, the
callback will be called immediately. The argument passed in will be true
if the permission is granted or no permission is required on this platform,
and false otherwise.
If a runtime request is required to obtain the permission, the callback
will be called asynchronously after the OS has granted or denied the requested
permission (typically by displaying a dialog box to the user and waiting until
the user has responded).
*/
static void request(PermissionID permission, Callback callback);
/** Returns whether a runtime request is required to obtain the permission
on the current platform.
*/
static bool isRequired(PermissionID permission);
/** Returns true if the app has been already granted this permission, either
via a previous runtime request or otherwise, or no permission is necessary.
Note that this can be false even if isRequired returns false. In this case,
the permission can not be obtained at all at runtime.
*/
static bool isGranted(PermissionID permission);
};
} // namespace juce
/*** End of inlined file: juce_RuntimePermissions.h ***/
/*** Start of inlined file: juce_WindowsRegistry.h ***/
namespace juce
{
#if JUCE_WINDOWS || DOXYGEN
/**
Contains some static helper functions for manipulating the MS Windows registry
(Only available on Windows, of course!)
@tags{Core}
*/
class JUCE_API WindowsRegistry
{
public:
/** These values can be used to specify whether the 32- or 64-bit registry should be used.
When running on a 32-bit OS, there is no 64-bit registry, so the mode will be ignored.
*/
enum WoW64Mode
{
/** Default handling: 32-bit apps will use the 32-bit registry, and 64-bit apps
will use the 64-bit registry. */
WoW64_Default = 0,
/** Always use the 64-bit registry store. (KEY_WOW64_64KEY). */
WoW64_64bit = 0x100,
/** Always use the 32-bit registry store. (KEY_WOW64_32KEY). */
WoW64_32bit = 0x200
};
/** Returns a string from the registry.
The path is a string for the entire path of a value in the registry,
e.g. "HKEY_CURRENT_USER\Software\foo\bar"
*/
static String JUCE_CALLTYPE getValue(const String& regValuePath,
const String& defaultValue = String(),
WoW64Mode mode = WoW64_Default);
/** Reads a binary block from the registry.
The path is a string for the entire path of a value in the registry,
e.g. "HKEY_CURRENT_USER\Software\foo\bar"
@returns a DWORD indicating the type of the key.
*/
static uint32 JUCE_CALLTYPE getBinaryValue(const String& regValuePath, MemoryBlock& resultData, WoW64Mode mode = WoW64_Default);
/** Sets a registry value as a string.
This will take care of creating any groups needed to get to the given registry value.
*/
static bool JUCE_CALLTYPE setValue(const String& regValuePath, const String& value, WoW64Mode mode = WoW64_Default);
/** Sets a registry value as a DWORD.
This will take care of creating any groups needed to get to the given registry value.
*/
static bool JUCE_CALLTYPE setValue(const String& regValuePath, uint32 value, WoW64Mode mode = WoW64_Default);
/** Sets a registry value as a QWORD.
This will take care of creating any groups needed to get to the given registry value.
*/
static bool JUCE_CALLTYPE setValue(const String& regValuePath, uint64 value, WoW64Mode mode = WoW64_Default);
/** Sets a registry value as a binary block.
This will take care of creating any groups needed to get to the given registry value.
*/
static bool JUCE_CALLTYPE setValue(const String& regValuePath, const MemoryBlock& value, WoW64Mode mode = WoW64_Default);
/** Returns true if the given value exists in the registry. */
static bool JUCE_CALLTYPE valueExists(const String& regValuePath, WoW64Mode mode = WoW64_Default);
/** Returns true if the given key exists in the registry. */
static bool JUCE_CALLTYPE keyExists(const String& regKeyPath, WoW64Mode mode = WoW64_Default);
/** Deletes a registry value. */
static bool JUCE_CALLTYPE deleteValue(const String& regValuePath, WoW64Mode mode = WoW64_Default);
/** Deletes a registry key (which is registry-talk for 'folder'). */
static bool JUCE_CALLTYPE deleteKey(const String& regKeyPath, WoW64Mode mode = WoW64_Default);
/** Creates a file association in the registry.
This lets you set the executable that should be launched by a given file extension.
@param fileExtension the file extension to associate, including the
initial dot, e.g. ".txt"
@param symbolicDescription a space-free short token to identify the file type
@param fullDescription a human-readable description of the file type
@param targetExecutable the executable that should be launched
@param iconResourceNumber the icon that gets displayed for the file type will be
found by looking up this resource number in the
executable. Pass 0 here to not use an icon
@param registerForCurrentUserOnly if false, this will try to register the association
for all users (you might not have permission to do this
unless running in an installer). If true, it will register the
association in HKEY_CURRENT_USER.
@param mode the WoW64 mode to use for choosing the database
*/
static bool JUCE_CALLTYPE registerFileAssociation(const String& fileExtension,
const String& symbolicDescription,
const String& fullDescription,
const File& targetExecutable,
int iconResourceNumber,
bool registerForCurrentUserOnly,
WoW64Mode mode = WoW64_Default);
// DEPRECATED: use the other methods with a WoW64Mode parameter of WoW64_64bit instead.
JUCE_DEPRECATED(static String getValueWow64(const String&, const String& defaultValue = String()));
JUCE_DEPRECATED(static bool valueExistsWow64(const String&));
JUCE_DEPRECATED(static bool keyExistsWow64(const String&));
private:
WindowsRegistry() = delete;
JUCE_DECLARE_NON_COPYABLE(WindowsRegistry)
};
#endif
} // namespace juce
/*** End of inlined file: juce_WindowsRegistry.h ***/
/*** Start of inlined file: juce_ChildProcess.h ***/
namespace juce
{
/**
Launches and monitors a child process.
This class lets you launch an executable, and read its output. You can also
use it to check whether the child process has finished.
@tags{Core}
*/
class JUCE_API ChildProcess
{
public:
/** Creates a process object.
To actually launch the process, use start().
*/
ChildProcess();
/** Destructor.
Note that deleting this object won't terminate the child process.
*/
~ChildProcess();
/** These flags are used by the start() methods. */
enum StreamFlags
{
wantStdOut = 1,
wantStdErr = 2
};
/** Attempts to launch a child process command.
The command should be the name of the executable file, followed by any arguments
that are required.
If the process has already been launched, this will launch it again. If a problem
occurs, the method will return false.
The streamFlags is a combinations of values to indicate which of the child's output
streams should be read and returned by readProcessOutput().
*/
bool start(const String& command, int streamFlags = wantStdOut | wantStdErr);
/** Attempts to launch a child process command.
The first argument should be the name of the executable file, followed by any other
arguments that are needed.
If the process has already been launched, this will launch it again. If a problem
occurs, the method will return false.
The streamFlags is a combinations of values to indicate which of the child's output
streams should be read and returned by readProcessOutput().
*/
bool start(const StringArray& arguments, int streamFlags = wantStdOut | wantStdErr);
/** Returns true if the child process is alive. */
bool isRunning() const;
/** Attempts to read some output from the child process.
This will attempt to read up to the given number of bytes of data from the
process. It returns the number of bytes that were actually read.
*/
int readProcessOutput(void* destBuffer, int numBytesToRead);
/** Blocks until the process has finished, and then returns its complete output
as a string.
*/
String readAllProcessOutput();
/** Blocks until the process is no longer running. */
bool waitForProcessToFinish(int timeoutMs) const;
/** If the process has finished, this returns its exit code. */
uint32 getExitCode() const;
/** Attempts to kill the child process.
Returns true if it succeeded. Trying to read from the process after calling this may
result in undefined behaviour.
*/
bool kill();
private:
class ActiveProcess;
std::unique_ptr<ActiveProcess> activeProcess;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ChildProcess)
};
} // namespace juce
/*** End of inlined file: juce_ChildProcess.h ***/
/*** Start of inlined file: juce_DynamicLibrary.h ***/
namespace juce
{
/**
Handles the opening and closing of DLLs.
This class can be used to open a DLL and get some function pointers from it.
Since the DLL is freed when this object is deleted, it's handy for managing
library lifetimes using RAII.
@tags{Core}
*/
class JUCE_API DynamicLibrary
{
public:
/** Creates an unopened DynamicLibrary object.
Call open() to actually open one.
*/
DynamicLibrary() = default;
/**
*/
DynamicLibrary(const String& name) { open(name); }
/** Move constructor */
DynamicLibrary(DynamicLibrary&& other) noexcept
{
std::swap(handle, other.handle);
}
/** Destructor.
If a library is currently open, it will be closed when this object is destroyed.
*/
~DynamicLibrary() { close(); }
/** Opens a DLL.
The name and the method by which it gets found is of course platform-specific, and
may or may not include a path, depending on the OS.
If a library is already open when this method is called, it will first close the library
before attempting to load the new one.
@returns true if the library was successfully found and opened.
*/
bool open(const String& name);
/** Releases the currently-open DLL, or has no effect if none was open. */
void close();
/** Tries to find a named function in the currently-open DLL, and returns a pointer to it.
If no library is open, or if the function isn't found, this will return a null pointer.
*/
void* getFunction(const String& functionName) noexcept;
/** Returns the platform-specific native library handle.
You'll need to cast this to whatever is appropriate for the OS that's in use.
*/
void* getNativeHandle() const noexcept { return handle; }
private:
void* handle = nullptr;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DynamicLibrary)
};
} // namespace juce
/*** End of inlined file: juce_DynamicLibrary.h ***/
/*** Start of inlined file: juce_HighResolutionTimer.h ***/
namespace juce
{
/**
A high-resolution periodic timer.
This provides accurately-timed regular callbacks. Unlike the normal Timer
class, this one uses a dedicated thread, not the message thread, so is
far more stable and precise.
You should only use this class in situations where you really need accuracy,
because unlike the normal Timer class, which is very lightweight and cheap
to start/stop, the HighResolutionTimer will use far more resources, and
starting/stopping it may involve launching and killing threads.
@see Timer
@tags{Core}
*/
class JUCE_API HighResolutionTimer
{
protected:
/** Creates a HighResolutionTimer.
When created, the timer is stopped, so use startTimer() to get it going.
*/
HighResolutionTimer();
public:
/** Destructor. */
virtual ~HighResolutionTimer();
/** The user-defined callback routine that actually gets called periodically.
This will be called on a dedicated timer thread, so make sure your
implementation is thread-safe!
It's perfectly ok to call startTimer() or stopTimer() from within this
callback to change the subsequent intervals.
*/
virtual void hiResTimerCallback() = 0;
/** Starts the timer and sets the length of interval required.
If the timer is already started, this will reset its counter, so the
time between calling this method and the next timer callback will not be
less than the interval length passed in.
@param intervalInMilliseconds the interval to use (any values less than 1 will be
rounded up to 1)
*/
void startTimer(int intervalInMilliseconds);
/** Stops the timer.
This method may block while it waits for pending callbacks to complete. Once it
returns, no more callbacks will be made. If it is called from the timer's own thread,
it will cancel the timer after the current callback returns.
*/
void stopTimer();
/** Checks if the timer has been started.
@returns true if the timer is running.
*/
bool isTimerRunning() const noexcept;
/** Returns the timer's interval.
@returns the timer's interval in milliseconds if it's running, or 0 if it's not.
*/
int getTimerInterval() const noexcept;
private:
struct Pimpl;
std::unique_ptr<Pimpl> pimpl;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(HighResolutionTimer)
};
} // namespace juce
/*** End of inlined file: juce_HighResolutionTimer.h ***/
/*** Start of inlined file: juce_InterProcessLock.h ***/
namespace juce
{
/**
Acts as a critical section which processes can use to block each other.
@see CriticalSection
@tags{Core}
*/
class JUCE_API InterProcessLock
{
public:
/** Creates a lock object.
@param name a name that processes will use to identify this lock object
*/
explicit InterProcessLock(const String& name);
/** Destructor.
This will also release the lock if it's currently held by this process.
*/
~InterProcessLock();
/** Attempts to lock the critical section.
@param timeOutMillisecs how many milliseconds to wait if the lock is already
held by another process - a value of 0 will return
immediately, negative values will wait forever
@returns true if the lock could be gained within the timeout period, or
false if the timeout expired.
*/
bool enter(int timeOutMillisecs = -1);
/** Releases the lock if it's currently held by this process. */
void exit();
/**
Automatically locks and unlocks an InterProcessLock object.
This works like a ScopedLock, but using an InterprocessLock rather than
a CriticalSection.
@see ScopedLock
*/
class ScopedLockType
{
public:
/** Creates a scoped lock.
As soon as it is created, this will lock the InterProcessLock, and
when the ScopedLockType object is deleted, the InterProcessLock will
be unlocked.
Note that since an InterprocessLock can fail due to errors, you should check
isLocked() to make sure that the lock was successful before using it.
Make sure this object is created and deleted by the same thread,
otherwise there are no guarantees what will happen! Best just to use it
as a local stack object, rather than creating one with the new() operator.
*/
explicit ScopedLockType(InterProcessLock& l) : ipLock(l) { lockWasSuccessful = l.enter(); }
/** Destructor.
The InterProcessLock will be unlocked when the destructor is called.
Make sure this object is created and deleted by the same thread,
otherwise there are no guarantees what will happen!
*/
inline ~ScopedLockType() { ipLock.exit(); }
/** Returns true if the InterProcessLock was successfully locked. */
bool isLocked() const noexcept { return lockWasSuccessful; }
private:
InterProcessLock& ipLock;
bool lockWasSuccessful;
JUCE_DECLARE_NON_COPYABLE(ScopedLockType)
};
private:
class Pimpl;
std::unique_ptr<Pimpl> pimpl;
CriticalSection lock;
String name;
JUCE_DECLARE_NON_COPYABLE(InterProcessLock)
};
} // namespace juce
/*** End of inlined file: juce_InterProcessLock.h ***/
/*** Start of inlined file: juce_Process.h ***/
namespace juce
{
/** Represents the current executable's process.
This contains methods for controlling the current application at the
process-level.
@see Thread, JUCEApplicationBase
@tags{Core}
*/
class JUCE_API Process
{
public:
enum ProcessPriority
{
LowPriority = 0,
NormalPriority = 1,
HighPriority = 2,
RealtimePriority = 3
};
/** Changes the current process's priority.
@param priority the process priority, where
0=low, 1=normal, 2=high, 3=realtime
*/
static void JUCE_CALLTYPE setPriority(const ProcessPriority priority);
/** Kills the current process immediately.
This is an emergency process terminator that kills the application
immediately - it's intended only for use only when something goes
horribly wrong.
@see JUCEApplicationBase::quit
*/
static void JUCE_CALLTYPE terminate();
/** Returns true if this application process is the one that the user is
currently using.
*/
static bool JUCE_CALLTYPE isForegroundProcess();
/** Attempts to make the current process the active one.
(This is not possible on some platforms).
*/
static void JUCE_CALLTYPE makeForegroundProcess();
/** Hides the application (on an OS that supports this, e.g. OSX, iOS, Android) */
static void JUCE_CALLTYPE hide();
/** Raises the current process's privilege level.
Does nothing if this isn't supported by the current OS, or if process
privilege level is fixed.
*/
static void JUCE_CALLTYPE raisePrivilege();
/** Lowers the current process's privilege level.
Does nothing if this isn't supported by the current OS, or if process
privilege level is fixed.
*/
static void JUCE_CALLTYPE lowerPrivilege();
/** Returns true if this process is being hosted by a debugger. */
static bool JUCE_CALLTYPE isRunningUnderDebugger() noexcept;
/** Tries to launch the OS's default reader application for a given file or URL. */
static bool JUCE_CALLTYPE openDocument(const String& documentURL, const String& parameters);
/** Tries to launch the OS's default email application to let the user create a message. */
static bool JUCE_CALLTYPE openEmailWithAttachments(const String& targetEmailAddress,
const String& emailSubject,
const String& bodyText,
const StringArray& filesToAttach);
#if JUCE_WINDOWS || DOXYGEN
/** WINDOWS ONLY - This returns the HINSTANCE of the current module.
The return type is a void* to avoid being dependent on windows.h - just cast
it to a HINSTANCE to use it.
In a normal JUCE application, this will be automatically set to the module
handle of the executable.
If you've built a DLL and plan to use any JUCE messaging or windowing classes,
you'll need to make sure you call the setCurrentModuleInstanceHandle()
to provide the correct module handle in your DllMain() function, because
the system relies on the correct instance handle when opening windows.
*/
static void* JUCE_CALLTYPE getCurrentModuleInstanceHandle() noexcept;
/** WINDOWS ONLY - Sets a new module handle to be used by the library.
The parameter type is a void* to avoid being dependent on windows.h, but it actually
expects a HINSTANCE value.
@see getCurrentModuleInstanceHandle()
*/
static void JUCE_CALLTYPE setCurrentModuleInstanceHandle(void* newHandle) noexcept;
#endif
#if (JUCE_MAC && JUCE_MODULE_AVAILABLE_juce_gui_basics) || DOXYGEN
/** OSX ONLY - Shows or hides the OSX dock icon for this app. */
static void setDockIconVisible(bool isVisible);
#endif
#if JUCE_MAC || JUCE_LINUX || JUCE_BSD || DOXYGEN
/** UNIX ONLY - Attempts to use setrlimit to change the maximum number of file
handles that the app can open. Pass 0 or less as the parameter to mean
'infinite'. Returns true if it succeeds.
*/
static bool setMaxNumberOfFileHandles(int maxNumberOfFiles) noexcept;
#endif
private:
Process();
JUCE_DECLARE_NON_COPYABLE(Process)
};
} // namespace juce
/*** End of inlined file: juce_Process.h ***/
/*** Start of inlined file: juce_SpinLock.h ***/
namespace juce
{
/**
A simple spin-lock class that can be used as a simple, low-overhead mutex for
uncontended situations.
Note that unlike a CriticalSection, this type of lock is not re-entrant, and may
be less efficient when used in a highly contended situation, but it's very small and
requires almost no initialisation.
It's most appropriate for simple situations where you're only going to hold the
lock for a very brief time.
@see CriticalSection
@tags{Core}
*/
class JUCE_API SpinLock
{
public:
inline SpinLock() = default;
inline ~SpinLock() = default;
/** Acquires the lock.
This will block until the lock has been successfully acquired by this thread.
Note that a SpinLock is NOT re-entrant, and is not smart enough to know whether the
caller thread already has the lock - so if a thread tries to acquire a lock that it
already holds, this method will never return!
It's strongly recommended that you never call this method directly - instead use the
ScopedLockType class to manage the locking using an RAII pattern instead.
*/
void enter() const noexcept;
/** Attempts to acquire the lock, returning true if this was successful. */
inline bool tryEnter() const noexcept
{
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment